diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:14 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:14 -0800 |
| commit | f72d5de56a522ac3be03873bdde26f23a5eeeb3c (patch) | |
| tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /dx/src | |
| parent | 31e30105703263782efd450d356cd67ea01af3b7 (diff) | |
| download | android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.tar.gz android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.tar.bz2 android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.zip | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'dx/src')
372 files changed, 0 insertions, 73100 deletions
diff --git a/dx/src/Android.mk b/dx/src/Android.mk deleted file mode 100644 index ef3d32d14..000000000 --- a/dx/src/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2006 The Android Open Source Project -# -LOCAL_PATH := $(call my-dir) - - -# dx java library -# ============================================================ -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-subdir-java-files) -LOCAL_JAR_MANIFEST := ../etc/manifest.txt - -LOCAL_MODULE:= dx - -include $(BUILD_HOST_JAVA_LIBRARY) - -INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE) - -# the documentation -# ============================================================ -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-subdir-java-files) $(call all-subdir-html-files) - -LOCAL_MODULE:= dx -LOCAL_DROIDDOC_OPTIONS := -hidden -LOCAL_MODULE_CLASS := JAVA_LIBRARIES -LOCAL_IS_HOST_MODULE := true - -include $(BUILD_DROIDDOC) - diff --git a/dx/src/com/android/dx/Version.java b/dx/src/com/android/dx/Version.java deleted file mode 100644 index 02dc7b248..000000000 --- a/dx/src/com/android/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.android.dx; - -/** - * Version number for dx. - */ -public class Version { - /** non-null; version string */ - public static final String VERSION = "1.2"; -} diff --git a/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java b/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java deleted file mode 100644 index 12e1f74ba..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java +++ /dev/null @@ -1,67 +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.android.dx.cf.attrib; - -import com.android.dx.rop.cst.Constant; - -/** - * Attribute class for <code>AnnotationDefault</code> attributes. - */ -public final class AttAnnotationDefault extends BaseAttribute { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "AnnotationDefault"; - - /** non-null; the annotation default value */ - private final Constant value; - - /** >= 0; attribute data length in the original classfile (not - * including the attribute header) */ - private final int byteLength; - - /** - * Constructs an instance. - * - * @param value non-null; the annotation default value - * @param byteLength >= 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} */ - public int byteLength() { - // Add six for the standard attribute header. - return byteLength + 6; - } - - /** - * Gets the annotation default value. - * - * @return non-null; the value - */ - public Constant getValue() { - return value; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttCode.java b/dx/src/com/android/dx/cf/attrib/AttCode.java deleted file mode 100644 index f00da2fde..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttCode.java +++ /dev/null @@ -1,145 +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.android.dx.cf.attrib; - -import com.android.dx.cf.code.ByteCatchList; -import com.android.dx.cf.code.BytecodeArray; -import com.android.dx.cf.iface.AttributeList; -import com.android.dx.util.MutabilityException; - -/** - * Attribute class for standard <code>Code</code> attributes. - */ -public final class AttCode extends BaseAttribute { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "Code"; - - /** >= 0; the stack size */ - private final int maxStack; - - /** >= 0; the number of locals */ - private final int maxLocals; - - /** non-null; array containing the bytecode per se */ - private final BytecodeArray code; - - /** non-null; the exception table */ - private final ByteCatchList catches; - - /** non-null; the associated list of attributes */ - private final AttributeList attributes; - - /** - * Constructs an instance. - * - * @param maxStack >= 0; the stack size - * @param maxLocals >= 0; the number of locals - * @param code non-null; array containing the bytecode per se - * @param catches non-null; the exception table - * @param attributes 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; - } - - public int byteLength() { - return 10 + code.byteLength() + catches.byteLength() + - attributes.byteLength(); - } - - /** - * Gets the maximum stack size. - * - * @return >= 0; the maximum stack size - */ - public int getMaxStack() { - return maxStack; - } - - /** - * Gets the number of locals. - * - * @return >= 0; the number of locals - */ - public int getMaxLocals() { - return maxLocals; - } - - /** - * Gets the bytecode array. - * - * @return non-null; the bytecode array - */ - public BytecodeArray getCode() { - return code; - } - - /** - * Gets the exception table. - * - * @return non-null; the exception table - */ - public ByteCatchList getCatches() { - return catches; - } - - /** - * Gets the associated attribute list. - * - * @return non-null; the attribute list - */ - public AttributeList getAttributes() { - return attributes; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttConstantValue.java b/dx/src/com/android/dx/cf/attrib/AttConstantValue.java deleted file mode 100644 index a84da4342..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttConstantValue.java +++ /dev/null @@ -1,77 +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.android.dx.cf.attrib; - -import com.android.dx.rop.cst.CstDouble; -import com.android.dx.rop.cst.CstFloat; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstLong; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.TypedConstant; - -/** - * Attribute class for standard <code>ConstantValue</code> attributes. - */ -public final class AttConstantValue extends BaseAttribute { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "ConstantValue"; - - /** non-null; the constant value */ - private final TypedConstant constantValue; - - /** - * Constructs an instance. - * - * @param constantValue non-null; the constant value, which must - * be an instance of one of: <code>CstString</code>, - * <code>CstInteger</code>, <code>CstLong</code>, - * <code>CstFloat</code>, or <code>CstDouble</code> - */ - 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} */ - public int byteLength() { - return 8; - } - - /** - * Gets the constant value of this instance. The returned value - * is an instance of one of: <code>CstString</code>, - * <code>CstInteger</code>, <code>CstLong</code>, - * <code>CstFloat</code>, or <code>CstDouble</code>. - * - * @return non-null; the constant value - */ - public TypedConstant getConstantValue() { - return constantValue; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttDeprecated.java b/dx/src/com/android/dx/cf/attrib/AttDeprecated.java deleted file mode 100644 index cd1dd2463..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttDeprecated.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.android.dx.cf.attrib; - -/** - * Attribute class for standard <code>Deprecated</code> attributes. - */ -public final class AttDeprecated extends BaseAttribute { - /** 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} */ - public int byteLength() { - return 6; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java b/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java deleted file mode 100644 index 7cccad703..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.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.android.dx.cf.attrib; - -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; - -/** - * Attribute class for standards-track <code>EnclosingMethod</code> - * attributes. - */ -public final class AttEnclosingMethod extends BaseAttribute { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "EnclosingMethod"; - - /** non-null; the innermost enclosing class */ - private final CstType type; - - /** null-ok; the name-and-type of the innermost enclosing method, if any */ - private final CstNat method; - - /** - * Constructs an instance. - * - * @param type non-null; the innermost enclosing class - * @param method 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} */ - public int byteLength() { - return 10; - } - - /** - * Gets the innermost enclosing class. - * - * @return non-null; the innermost enclosing class - */ - public CstType getEnclosingClass() { - return type; - } - - /** - * Gets the name-and-type of the innermost enclosing method, if - * any. - * - * @return null-ok; the name-and-type of the innermost enclosing - * method, if any - */ - public CstNat getMethod() { - return method; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttExceptions.java b/dx/src/com/android/dx/cf/attrib/AttExceptions.java deleted file mode 100644 index 59e624ef8..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttExceptions.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.android.dx.cf.attrib; - -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.MutabilityException; - -/** - * Attribute class for standard <code>Exceptions</code> attributes. - */ -public final class AttExceptions extends BaseAttribute { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "Exceptions"; - - /** non-null; list of exception classes */ - private final TypeList exceptions; - - /** - * Constructs an instance. - * - * @param exceptions non-null; list of classes, presumed but not - * verified to be subclasses of <code>Throwable</code> - */ - 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} */ - 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</code>. - * - * @return non-null; the list of classes - */ - public TypeList getExceptions() { - return exceptions; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java b/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java deleted file mode 100644 index df305395b..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttInnerClasses.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.android.dx.cf.attrib; - -import com.android.dx.util.MutabilityException; - -/** - * Attribute class for standard <code>InnerClasses</code> attributes. - */ -public final class AttInnerClasses extends BaseAttribute { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "InnerClasses"; - - /** non-null; list of inner class entries */ - private final InnerClassList innerClasses; - - /** - * Constructs an instance. - * - * @param innerClasses 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} */ - public int byteLength() { - return 8 + innerClasses.size() * 8; - } - - /** - * Gets the list of "inner class" entries associated with this instance. - * - * @return non-null; the list - */ - public InnerClassList getInnerClasses() { - return innerClasses; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java b/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java deleted file mode 100644 index c5e65e80d..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.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.android.dx.cf.attrib; - -import com.android.dx.cf.code.LineNumberList; -import com.android.dx.util.MutabilityException; - -/** - * Attribute class for standard <code>LineNumberTable</code> attributes. - */ -public final class AttLineNumberTable extends BaseAttribute { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "LineNumberTable"; - - /** non-null; list of line number entries */ - private final LineNumberList lineNumbers; - - /** - * Constructs an instance. - * - * @param lineNumbers 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} */ - public int byteLength() { - return 8 + 4 * lineNumbers.size(); - } - - /** - * Gets the list of "line number" entries associated with this instance. - * - * @return non-null; the list - */ - public LineNumberList getLineNumbers() { - return lineNumbers; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java deleted file mode 100644 index 893f25477..000000000 --- a/dx/src/com/android/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.android.dx.cf.attrib; - -import com.android.dx.cf.code.LocalVariableList; - -/** - * Attribute class for standard <code>LocalVariableTable</code> attributes. - */ -public final class AttLocalVariableTable extends BaseLocalVariables { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "LocalVariableTable"; - - /** - * Constructs an instance. - * - * @param localVariables non-null; list of local variable entries - */ - public AttLocalVariableTable(LocalVariableList localVariables) { - super(ATTRIBUTE_NAME, localVariables); - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java deleted file mode 100644 index 7037b7401..000000000 --- a/dx/src/com/android/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.android.dx.cf.attrib; - -import com.android.dx.cf.code.LocalVariableList; - -/** - * Attribute class for standard <code>LocalVariableTypeTable</code> attributes. - */ -public final class AttLocalVariableTypeTable extends BaseLocalVariables { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "LocalVariableTypeTable"; - - /** - * Constructs an instance. - * - * @param localVariables non-null; list of local variable entries - */ - public AttLocalVariableTypeTable(LocalVariableList localVariables) { - super(ATTRIBUTE_NAME, localVariables); - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java deleted file mode 100644 index 583ab17be..000000000 --- a/dx/src/com/android/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.android.dx.cf.attrib; - -import com.android.dx.rop.annotation.Annotations; - -/** - * Attribute class for standard <code>RuntimeInvisibleAnnotations</code> - * attributes. - */ -public final class AttRuntimeInvisibleAnnotations extends BaseAnnotations { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "RuntimeInvisibleAnnotations"; - - /** - * Constructs an instance. - * - * @param annotations non-null; the list of annotations - * @param byteLength >= 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/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java deleted file mode 100644 index 08865e153..000000000 --- a/dx/src/com/android/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.android.dx.cf.attrib; - -import com.android.dx.rop.annotation.AnnotationsList; - -/** - * Attribute class for standard - * <code>RuntimeInvisibleParameterAnnotations</code> attributes. - */ -public final class AttRuntimeInvisibleParameterAnnotations - extends BaseParameterAnnotations { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = - "RuntimeInvisibleParameterAnnotations"; - - /** - * Constructs an instance. - * - * @param parameterAnnotations non-null; the parameter annotations - * @param byteLength >= 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/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java deleted file mode 100644 index c61acb5c2..000000000 --- a/dx/src/com/android/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.android.dx.cf.attrib; - -import com.android.dx.rop.annotation.Annotations; - -/** - * Attribute class for standard <code>RuntimeVisibleAnnotations</code> - * attributes. - */ -public final class AttRuntimeVisibleAnnotations extends BaseAnnotations { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "RuntimeVisibleAnnotations"; - - /** - * Constructs an instance. - * - * @param annotations non-null; the list of annotations - * @param byteLength >= 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/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java deleted file mode 100644 index dfe57b2b6..000000000 --- a/dx/src/com/android/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.android.dx.cf.attrib; - -import com.android.dx.rop.annotation.AnnotationsList; - -/** - * Attribute class for standard <code>RuntimeVisibleParameterAnnotations</code> - * attributes. - */ -public final class AttRuntimeVisibleParameterAnnotations - extends BaseParameterAnnotations { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = - "RuntimeVisibleParameterAnnotations"; - - /** - * Constructs an instance. - * - * @param annotations non-null; the parameter annotations - * @param byteLength >= 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/dx/src/com/android/dx/cf/attrib/AttSignature.java b/dx/src/com/android/dx/cf/attrib/AttSignature.java deleted file mode 100644 index 97edbbdd0..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttSignature.java +++ /dev/null @@ -1,59 +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.android.dx.cf.attrib; - -import com.android.dx.rop.cst.CstUtf8; - -/** - * Attribute class for standards-track <code>Signature</code> attributes. - */ -public final class AttSignature extends BaseAttribute { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "Signature"; - - /** non-null; the signature string */ - private final CstUtf8 signature; - - /** - * Constructs an instance. - * - * @param signature non-null; the signature string - */ - public AttSignature(CstUtf8 signature) { - super(ATTRIBUTE_NAME); - - if (signature == null) { - throw new NullPointerException("signature == null"); - } - - this.signature = signature; - } - - /** {@inheritDoc} */ - public int byteLength() { - return 8; - } - - /** - * Gets the signature string. - * - * @return non-null; the signature string - */ - public CstUtf8 getSignature() { - return signature; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttSourceFile.java b/dx/src/com/android/dx/cf/attrib/AttSourceFile.java deleted file mode 100644 index f0872178f..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttSourceFile.java +++ /dev/null @@ -1,59 +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.android.dx.cf.attrib; - -import com.android.dx.rop.cst.CstUtf8; - -/** - * Attribute class for standard <code>SourceFile</code> attributes. - */ -public final class AttSourceFile extends BaseAttribute { - /** non-null; attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "SourceFile"; - - /** non-null; name of the source file */ - private final CstUtf8 sourceFile; - - /** - * Constructs an instance. - * - * @param sourceFile non-null; the name of the source file - */ - public AttSourceFile(CstUtf8 sourceFile) { - super(ATTRIBUTE_NAME); - - if (sourceFile == null) { - throw new NullPointerException("sourceFile == null"); - } - - this.sourceFile = sourceFile; - } - - /** {@inheritDoc} */ - public int byteLength() { - return 8; - } - - /** - * Gets the source file name of this instance. - * - * @return non-null; the source file - */ - public CstUtf8 getSourceFile() { - return sourceFile; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/AttSynthetic.java b/dx/src/com/android/dx/cf/attrib/AttSynthetic.java deleted file mode 100644 index daa9b0c23..000000000 --- a/dx/src/com/android/dx/cf/attrib/AttSynthetic.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.android.dx.cf.attrib; - -/** - * Attribute class for standard <code>Synthetic</code> attributes. - */ -public final class AttSynthetic extends BaseAttribute { - /** 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} */ - public int byteLength() { - return 6; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java b/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java deleted file mode 100644 index 0163e2cb4..000000000 --- a/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java +++ /dev/null @@ -1,72 +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.android.dx.cf.attrib; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.util.MutabilityException; - -/** - * Base class for annotations attributes. - */ -public abstract class BaseAnnotations extends BaseAttribute { - /** non-null; list of annotations */ - private final Annotations annotations; - - /** >= 0; attribute data length in the original classfile (not - * including the attribute header) */ - private final int byteLength; - - /** - * Constructs an instance. - * - * @param attributeName non-null; the name of the attribute - * @param annotations non-null; the list of annotations - * @param byteLength >= 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} */ - public final int byteLength() { - // Add six for the standard attribute header. - return byteLength + 6; - } - - /** - * Gets the list of annotations associated with this instance. - * - * @return non-null; the list - */ - public final Annotations getAnnotations() { - return annotations; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/BaseAttribute.java b/dx/src/com/android/dx/cf/attrib/BaseAttribute.java deleted file mode 100644 index ef1c6ac0d..000000000 --- a/dx/src/com/android/dx/cf/attrib/BaseAttribute.java +++ /dev/null @@ -1,46 +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.android.dx.cf.attrib; - -import com.android.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 { - /** non-null; attribute name */ - private final String name; - - /** - * Constructs an instance. - * - * @param name non-null; attribute name - */ - public BaseAttribute(String name) { - if (name == null) { - throw new NullPointerException("name == null"); - } - - this.name = name; - } - - /** {@inheritDoc} */ - public String getName() { - return name; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java b/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java deleted file mode 100644 index a39e72438..000000000 --- a/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.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.android.dx.cf.attrib; - -import com.android.dx.cf.code.LocalVariableList; -import com.android.dx.util.MutabilityException; - -/** - * Base attribute class for standard <code>LocalVariableTable</code> - * and <code>LocalVariableTypeTable</code> attributes. - */ -public abstract class BaseLocalVariables extends BaseAttribute { - /** non-null; list of local variable entries */ - private final LocalVariableList localVariables; - - /** - * Constructs an instance. - * - * @param name non-null; attribute name - * @param localVariables 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} */ - public final int byteLength() { - return 8 + localVariables.size() * 10; - } - - /** - * Gets the list of "local variable" entries associated with this instance. - * - * @return non-null; the list - */ - public final LocalVariableList getLocalVariables() { - return localVariables; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java deleted file mode 100644 index a927e3d5f..000000000 --- a/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.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.android.dx.cf.attrib; - -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.util.MutabilityException; - -/** - * Base class for parameter annotation list attributes. - */ -public abstract class BaseParameterAnnotations extends BaseAttribute { - /** non-null; list of annotations */ - private final AnnotationsList parameterAnnotations; - - /** >= 0; attribute data length in the original classfile (not - * including the attribute header) */ - private final int byteLength; - - /** - * Constructs an instance. - * - * @param attributeName non-null; the name of the attribute - * @param parameterAnnotations non-null; the annotations - * @param byteLength >= 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} */ - 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 non-null; the list - */ - public final AnnotationsList getParameterAnnotations() { - return parameterAnnotations; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/InnerClassList.java b/dx/src/com/android/dx/cf/attrib/InnerClassList.java deleted file mode 100644 index 3585f1db8..000000000 --- a/dx/src/com/android/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.android.dx.cf.attrib; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.FixedSizeList; - -/** - * List of "inner class" entries, which are the contents of - * <code>InnerClasses</code> 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 >= 0; which item - * @return null-ok; the indicated item - */ - public Item get(int n) { - return (Item) get0(n); - } - - /** - * Sets the item at the given index. - * - * @param n >= 0, < size(); which class - * @param innerClass non-null; class this item refers to - * @param outerClass null-ok; outer class that this class is a - * member of, if any - * @param innerName 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, - CstUtf8 innerName, int accessFlags) { - set0(n, new Item(innerClass, outerClass, innerName, accessFlags)); - } - - /** - * Item in an inner classes list. - */ - public static class Item { - /** non-null; class this item refers to */ - private final CstType innerClass; - - /** null-ok; outer class that this class is a member of, if any */ - private final CstType outerClass; - - /** null-ok; original simple name of this class, if not anonymous */ - private final CstUtf8 innerName; - - /** original declared access flags */ - private final int accessFlags; - - /** - * Constructs an instance. - * - * @param innerClass non-null; class this item refers to - * @param outerClass null-ok; outer class that this class is a - * member of, if any - * @param innerName null-ok; original simple name of this - * class, if not anonymous - * @param accessFlags original declared access flags - */ - public Item(CstType innerClass, CstType outerClass, - CstUtf8 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 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 null-ok; the class - */ - public CstType getOuterClass() { - return outerClass; - } - - /** - * Gets the original name of this item's class, if not anonymous. - * - * @return null-ok; the name - */ - public CstUtf8 getInnerName() { - return innerName; - } - - /** - * Gets the original declared access flags. - * - * @return the access flags - */ - public int getAccessFlags() { - return accessFlags; - } - } -} diff --git a/dx/src/com/android/dx/cf/attrib/RawAttribute.java b/dx/src/com/android/dx/cf/attrib/RawAttribute.java deleted file mode 100644 index b89926d8a..000000000 --- a/dx/src/com/android/dx/cf/attrib/RawAttribute.java +++ /dev/null @@ -1,91 +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.android.dx.cf.attrib; - -import com.android.dx.rop.cst.ConstantPool; -import com.android.dx.util.ByteArray; - -/** - * Raw attribute, for holding onto attributes that are unrecognized. - */ -public final class RawAttribute extends BaseAttribute { - /** non-null; attribute data */ - private final ByteArray data; - - /** - * null-ok; constant pool to use for resolution of cpis in {@link - * #data} - */ - private final ConstantPool pool; - - /** - * Constructs an instance. - * - * @param name non-null; attribute name - * @param data non-null; attribute data - * @param pool 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 non-null; attribute name - * @param data non-null; array containing the attribute data - * @param offset offset in <code>data</code> to the attribute data - * @param length length of the attribute data, in bytes - * @param pool 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 non-null; the data - */ - public ByteArray getData() { - return data; - } - - /** {@inheritDoc} */ - 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 null-ok; the constant pool - */ - public ConstantPool getPool() { - return pool; - } -} diff --git a/dx/src/com/android/dx/cf/attrib/package.html b/dx/src/com/android/dx/cf/attrib/package.html deleted file mode 100644 index 8125079a4..000000000 --- a/dx/src/com/android/dx/cf/attrib/package.html +++ /dev/null @@ -1,11 +0,0 @@ -<body> -<p>Implementation of containers and utilities for all the standard Java -attribute types.</p> - -<p><b>PACKAGES USED:</b> -<ul> -<li><code>com.android.dx.cf.iface</code></li> -<li><code>com.android.dx.rop.pool</code></li> -<li><code>com.android.dx.util</code></li> -</ul> -</body> diff --git a/dx/src/com/android/dx/cf/code/BaseMachine.java b/dx/src/com/android/dx/cf/code/BaseMachine.java deleted file mode 100644 index 430e48be7..000000000 --- a/dx/src/com/android/dx/cf/code/BaseMachine.java +++ /dev/null @@ -1,545 +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.android.dx.cf.code; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.LocalItem; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import java.util.ArrayList; - -/** - * Base implementation of {@link Machine}. - * - * <p><b>Note:</b> For the most part, the documentation for this class - * ignores the distinction between {@link Type} and {@link - * TypeBearer}.</p> - */ -public abstract class BaseMachine implements Machine { - /* non-null; the prototype for the associated method */ - private final Prototype prototype; - - /** non-null; primary arguments */ - private TypeBearer[] args; - - /** >= 0; number of primary arguments */ - private int argCount; - - /** null-ok; type of the operation, if salient */ - private Type auxType; - - /** auxiliary <code>int</code> argument */ - private int auxInt; - - /** null-ok; auxiliary constant argument */ - private Constant auxCst; - - /** auxiliary branch target argument */ - private int auxTarget; - - /** null-ok; auxiliary switch cases argument */ - private SwitchList auxCases; - - /** null-ok; auxiliary initial value list for newarray */ - private ArrayList<Constant> auxInitValues; - - /** >= -1; last local accessed */ - private int localIndex; - - /** null-ok; local target spec, if salient and calculated */ - private RegisterSpec localTarget; - - /** non-null; results */ - private TypeBearer[] results; - - /** - * >= -1; count of the results, or <code>-1</code> if no results - * have been set - */ - private int resultCount; - - /** - * Constructs an instance. - * - * @param prototype 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} */ - public Prototype getPrototype() { - return prototype; - } - - /** {@inheritDoc} */ - public final void clearArgs() { - argCount = 0; - auxType = null; - auxInt = 0; - auxCst = null; - auxTarget = 0; - auxCases = null; - auxInitValues = null; - localIndex = -1; - localTarget = null; - resultCount = -1; - } - - /** {@inheritDoc} */ - 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} */ - 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()); - } - } - } - - 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} */ - 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} */ - 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 " + type2.toHuman() + - " but found " + args[2].getType().toHuman()); - } - } - - /** {@inheritDoc} */ - public final void localArg(Frame frame, int idx) { - clearArgs(); - args[0] = frame.getLocals().get(idx); - argCount = 1; - localIndex = idx; - } - - /** {@inheritDoc} */ - public final void auxType(Type type) { - auxType = type; - } - - /** {@inheritDoc} */ - public final void auxIntArg(int value) { - auxInt = value; - } - - /** {@inheritDoc} */ - public final void auxCstArg(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - auxCst = cst; - } - - /** {@inheritDoc} */ - public final void auxTargetArg(int target) { - auxTarget = target; - } - - /** {@inheritDoc} */ - public final void auxSwitchArg(SwitchList cases) { - if (cases == null) { - throw new NullPointerException("cases == null"); - } - - auxCases = cases; - } - - /** {@inheritDoc} */ - public final void auxInitValues(ArrayList<Constant> initValues) { - auxInitValues = initValues; - } - - /** {@inheritDoc} */ - public final void localTarget(int idx, Type type, LocalItem local) { - localTarget = RegisterSpec.makeLocalOptional(idx, type, local); - } - - /** - * Gets the number of primary arguments. - * - * @return >= 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 >= 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</code>th primary argument. - * - * @param n >= 0, < argCount(); which argument - * @return 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 null-ok; the salient type - */ - protected final Type getAuxType() { - return auxType; - } - - /** - * Gets the <code>int</code> auxiliary argument. - * - * @return the argument value - */ - protected final int getAuxInt() { - return auxInt; - } - - /** - * Gets the constant auxiliary argument. - * - * @return 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 null-ok; the argument value - */ - protected final SwitchList getAuxCases() { - return auxCases; - } - - /** - * Gets the init values auxiliary argument. - * - * @return null-ok; the argument value - */ - protected final ArrayList<Constant> getInitValues() { - return auxInitValues; - } - /** - * Gets the last local index accessed. - * - * @return >= -1; the salient local index or <code>-1</code> if none - * was set since the last time {@link #clearArgs} was called - */ - protected final int getLocalIndex() { - return localIndex; - } - - /** - * 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}. - * - * @return null-ok; the salient register spec or <code>null</code> if no - * local target was set since the last time {@link #clearArgs} was - * called - */ - protected final RegisterSpec getLocalTarget() { - 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) { - 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. - * - * <p><b>Note:</b> If there is more than one result value, the - * others may be added by using {@link #addResult}.</p> - * - * @param result 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 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 >= 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 >= 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</code>th result value. - * - * @param n >= 0, < resultCount(); which result - * @return 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 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()); - } else { - ExecutionStack stack = frame.getStack(); - for (int i = 0; i < resultCount; i++) { - stack.push(results[i]); - } - } - } - - /** - * Throws an exception that indicates a mismatch in local variable - * types. - * - * @param found non-null; the encountered type - * @param local 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/dx/src/com/android/dx/cf/code/BasicBlocker.java b/dx/src/com/android/dx/cf/code/BasicBlocker.java deleted file mode 100644 index 82e4a08d0..000000000 --- a/dx/src/com/android/dx/cf/code/BasicBlocker.java +++ /dev/null @@ -1,449 +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.android.dx.cf.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstMemberRef; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.util.Bits; -import com.android.dx.util.IntList; -import java.util.ArrayList; - -/** - * Utility that identifies basic blocks in bytecode. - */ -public final class BasicBlocker implements BytecodeArray.Visitor { - /** non-null; method being converted */ - private final ConcreteMethod method; - - /** non-null; work set; bits indicate offsets in need of examination */ - private final int[] workSet; - - /** - * 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; - - /** - * 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; - - /** - * non-null, sparse; for each instruction offset to a branch of - * some sort, the list of targets for that instruction - */ - private final IntList[] targetLists; - - /** - * 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 non-null; method to convert - * @return 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 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} */ - public void visitInvalid(int opcode, int offset, int length) { - visitCommon(offset, length, true); - } - - /** {@inheritDoc} */ - 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} */ - 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} */ - 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)) { - /* - * 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} */ - 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} */ - 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} */ - public void visitNewarray(int offset, int length, CstType type, - ArrayList<Constant> intVals) { - visitCommon(offset, length, true); - visitThrowing(offset, length, true); - } - - /** - * Extracts the list of basic blocks from the bit sets. - * - * @return non-null; the list of basic blocks - */ - private ByteBlockList getBlockList() { - ByteCatchList catches = method.getCatches(); - 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</code> 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</code> 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</code> 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} - */ - public void setPreviousOffset(int offset) { - previousOffset = offset; - } - - /** - * {@inheritDoc} - */ - public int getPreviousOffset() { - return previousOffset; - } -} diff --git a/dx/src/com/android/dx/cf/code/ByteBlock.java b/dx/src/com/android/dx/cf/code/ByteBlock.java deleted file mode 100644 index 065c5221c..000000000 --- a/dx/src/com/android/dx/cf/code/ByteBlock.java +++ /dev/null @@ -1,145 +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.android.dx.cf.code; - -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; -import com.android.dx.util.LabeledItem; - -/** - * Representation of a basic block in a bytecode array. - */ -public final class ByteBlock implements LabeledItem { - /** >= 0; label for this block */ - private final int label; - - /** >= 0; bytecode offset (inclusive) of the start of the block */ - private final int start; - - /** > start; bytecode offset (exclusive) of the end of the block */ - private final int end; - - /** non-null; list of successors that this block may branch to */ - private final IntList successors; - - /** non-null; list of exceptions caught and their handler targets */ - private final ByteCatchList catches; - - /** - * Constructs an instance. - * - * @param label >= 0; target label for this block - * @param start >= 0; bytecode offset (inclusive) of the start - * of the block - * @param end > start; bytecode offset (exclusive) of the end - * of the block - * @param successors non-null; list of successors that this block may - * branch to - * @param catches 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 >= 0; the label - */ - public int getLabel() { - return label; - } - - /** - * Gets the bytecode offset (inclusive) of the start of this block. - * - * @return >= 0; the start offset - */ - public int getStart() { - return start; - } - - /** - * Gets the bytecode offset (exclusive) of the end of this block. - * - * @return > getStart(); the end offset - */ - public int getEnd() { - return end; - } - - /** - * Gets the list of successors that this block may branch to - * non-exceptionally. - * - * @return non-null; the successor list - */ - public IntList getSuccessors() { - return successors; - } - - /** - * Gets the list of exceptions caught and their handler targets. - * - * @return non-null; the catch list - */ - public ByteCatchList getCatches() { - return catches; - } -} diff --git a/dx/src/com/android/dx/cf/code/ByteBlockList.java b/dx/src/com/android/dx/cf/code/ByteBlockList.java deleted file mode 100644 index 9d27b7fd9..000000000 --- a/dx/src/com/android/dx/cf/code/ByteBlockList.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.android.dx.cf.code; - -import com.android.dx.util.FixedSizeList; -import com.android.dx.util.Hex; -import com.android.dx.util.LabeledList; - -/** - * List of {@link ByteBlock} instances. - */ -public final class ByteBlockList extends LabeledList { - - /** - * Constructs an instance. - * - * @param size >= 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</code>. - * - * @param n >= 0, < size(); which element - * @return 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 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 >= 0, < size(); which element - * @param bb null-ok; the value to store - */ - public void set(int n, ByteBlock bb) { - super.set(n, bb); - } -} diff --git a/dx/src/com/android/dx/cf/code/ByteCatchList.java b/dx/src/com/android/dx/cf/code/ByteCatchList.java deleted file mode 100644 index 375831e55..000000000 --- a/dx/src/com/android/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.android.dx.cf.code; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.FixedSizeList; -import com.android.dx.util.IntList; - -/** - * List of catch entries, that is, the elements of an "exception table," - * which is part of a standard <code>Code</code> attribute. - */ -public final class ByteCatchList extends FixedSizeList { - /** 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</code> attribute. The returned value includes the - * two bytes for <code>exception_table_length</code>. - * - * @return >= 2; the total length, in bytes - */ - public int byteLength() { - return 2 + size() * 8; - } - - /** - * Gets the indicated item. - * - * @param n >= 0; which item - * @return null-ok; the indicated item - */ - public Item get(int n) { - return (Item) get0(n); - } - - /** - * Sets the item at the given index. - * - * @param n >= 0, < size(); which entry to set - * @param item 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 >= 0, < size(); which entry to set - * @param startPc >= 0; the start pc (inclusive) of the handler's range - * @param endPc >= startPc; the end pc (exclusive) of the - * handler's range - * @param handlerPc >= 0; the pc of the exception handler - * @param exceptionClass null-ok; the exception class or - * <code>null</code> 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 non-null; list of exception handlers active at - * <code>pc</code> - */ - 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 <i>not</i> 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</code> which represents a catch-all. - * - * @param item non-null; item with the exception type to look for - * @param arr non-null; array to search in - * @param count non-null; maximum number of elements in the array to check - * @return <code>true</code> iff the exception type is <i>not</i> 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</code> address appended if appropriate. The - * result is automatically made immutable. - * - * @param noException >= -1; the no-exception address to append, or - * <code>-1</code> not to append anything - * @return non-null; list of exception targets, with - * <code>noException</code> 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 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 { - /** >= 0; the start pc (inclusive) of the handler's range */ - private final int startPc; - - /** >= startPc; the end pc (exclusive) of the handler's range */ - private final int endPc; - - /** >= 0; the pc of the exception handler */ - private final int handlerPc; - - /** null-ok; the exception class or <code>null</code> to catch all - * exceptions with this handler */ - private final CstType exceptionClass; - - /** - * Constructs an instance. - * - * @param startPc >= 0; the start pc (inclusive) of the - * handler's range - * @param endPc >= startPc; the end pc (exclusive) of the - * handler's range - * @param handlerPc >= 0; the pc of the exception handler - * @param exceptionClass null-ok; the exception class or - * <code>null</code> 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 >= 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 >= startPc; the end pc (exclusive) of the - * handler's range. - */ - public int getEndPc() { - return endPc; - } - - /** - * Gets the pc of the exception handler. - * - * @return >= 0; the pc of the exception handler - */ - public int getHandlerPc() { - return handlerPc; - } - - /** - * Gets the class of exception handled. - * - * @return 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</code> iff this item covers <code>pc</code> - */ - public boolean covers(int pc) { - return (pc >= startPc) && (pc < endPc); - } - } -} diff --git a/dx/src/com/android/dx/cf/code/ByteOps.java b/dx/src/com/android/dx/cf/code/ByteOps.java deleted file mode 100644 index 4c420f6f6..000000000 --- a/dx/src/com/android/dx/cf/code/ByteOps.java +++ /dev/null @@ -1,649 +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.android.dx.cf.code; - -import com.android.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 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</code> */ - public static final int FMT_NO_ARGS = 1; - - /** "0": <code>op</code>; implies <code>max_locals >= 1</code> */ - public static final int FMT_NO_ARGS_LOCALS_1 = 2; - - /** "1": <code>op</code>; implies <code>max_locals >= 2</code> */ - public static final int FMT_NO_ARGS_LOCALS_2 = 3; - - /** "2": <code>op</code>; implies <code>max_locals >= 3</code> */ - public static final int FMT_NO_ARGS_LOCALS_3 = 4; - - /** "3": <code>op</code>; implies <code>max_locals >= 4</code> */ - public static final int FMT_NO_ARGS_LOCALS_4 = 5; - - /** "4": <code>op</code>; implies <code>max_locals >= 5</code> */ - public static final int FMT_NO_ARGS_LOCALS_5 = 6; - - /** "b": <code>op target target</code> */ - public static final int FMT_BRANCH = 7; - - /** "c": <code>op target target target target</code> */ - public static final int FMT_WIDE_BRANCH = 8; - - /** "p": <code>op #cpi #cpi</code>; constant restricted as specified */ - public static final int FMT_CPI = 9; - - /** - * "l": <code>op local</code>; category-1 local; implies - * <code>max_locals</code> is at least two more than the given - * local number - */ - public static final int FMT_LOCAL_1 = 10; - - /** - * "m": <code>op local</code>; category-2 local; implies - * <code>max_locals</code> is at least two more than the given - * local number - */ - public static final int FMT_LOCAL_2 = 11; - - /** - * "y": <code>op #byte</code> (<code>bipush</code> and - * <code>newarray</code>) - */ - public static final int FMT_LITERAL_BYTE = 12; - - /** "I": <code>invokeinterface cpi cpi count 0</code> */ - public static final int FMT_INVOKEINTERFACE = 13; - - /** "L": <code>ldc #cpi</code>; constant restricted as specified */ - public static final int FMT_LDC = 14; - - /** "S": <code>sipush #byte #byte</code> */ - public static final int FMT_SIPUSH = 15; - - /** "T": <code>tableswitch ...</code> */ - public static final int FMT_TABLESWITCH = 16; - - /** "U": <code>lookupswitch ...</code> */ - public static final int FMT_LOOKUPSWITCH = 17; - - /** "M": <code>multianewarray cpi cpi dims</code> */ - public static final int FMT_MULTIANEWARRAY = 18; - - /** "W": <code>wide ...</code> */ - 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</code> */ - public static final int CPOK_Integer = 0x20; - - /** "F": flag bit for valid cp type for <code>Float</code> */ - public static final int CPOK_Float = 0x40; - - /** "J": flag bit for valid cp type for <code>Long</code> */ - public static final int CPOK_Long = 0x80; - - /** "D": flag bit for valid cp type for <code>Double</code> */ - public static final int CPOK_Double = 0x100; - - /** "c": flag bit for valid cp type for <code>Class</code> */ - public static final int CPOK_Class = 0x200; - - /** "s": flag bit for valid cp type for <code>String</code> */ - public static final int CPOK_String = 0x400; - - /** "f": flag bit for valid cp type for <code>Fieldref</code> */ - public static final int CPOK_Fieldref = 0x800; - - /** "m": flag bit for valid cp type for <code>Methodref</code> */ - public static final int CPOK_Methodref = 0x1000; - - /** "i": flag bit for valid cp type for <code>InterfaceMethodref</code> */ - public static final int CPOK_InterfaceMethodref = 0x2000; - - /** - * non-null; map from opcodes to format or'ed with allowed constant - * pool types - */ - private static final int[] OPCODE_INFO = new int[256]; - - /** non-null; map from opcodes to their names */ - private static final String[] OPCODE_NAMES = new String[256]; - - /** 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 >= 0, <= 255; the opcode - * @return 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 >= 0, <= 255; the opcode - * @return its format and allowed cp types - */ - public static int opInfo(int opcode) { - return OPCODE_INFO[opcode]; - } -} diff --git a/dx/src/com/android/dx/cf/code/BytecodeArray.java b/dx/src/com/android/dx/cf/code/BytecodeArray.java deleted file mode 100644 index 71ba029f6..000000000 --- a/dx/src/com/android/dx/cf/code/BytecodeArray.java +++ /dev/null @@ -1,1393 +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.android.dx.cf.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.ConstantPool; -import com.android.dx.rop.cst.CstDouble; -import com.android.dx.rop.cst.CstFloat; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstKnownNull; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.rop.cst.CstLong; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.util.Bits; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; -import java.util.ArrayList; - -/** - * Bytecode array, which is part of a standard <code>Code</code> attribute. - */ -public final class BytecodeArray { - /** convenient no-op implementation of {@link Visitor} */ - public static final Visitor EMPTY_VISITOR = new BaseVisitor(); - - /** non-null; underlying bytes */ - private final ByteArray bytes; - - /** non-null; constant pool to use when resolving constant pool indices */ - private final ConstantPool pool; - - /** - * Constructs an instance. - * - * @param bytes non-null; underlying bytes - * @param pool 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 non-null; the byte array - */ - public ByteArray getBytes() { - return bytes; - } - - /** - * Gets the size of the bytecode array, per se. - * - * @return >= 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</code> attribute. The returned value includes the - * array size plus four bytes for <code>code_length</code>. - * - * @return >= 4; the total length, in bytes - */ - public int byteLength() { - return 4 + bytes.size(); - } - - /** - * Parses each instruction in the array, in order. - * - * @param visitor 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 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 non-null; the work set to process - * @param visitor 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. - * - * <p>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:</p> - * - * <ul> - * <li>The opcodes to push literal constants of primitive types all become - * <code>ldc</code>. - * E.g., <code>fconst_0</code>, <code>sipush</code>, and - * <code>lconst_0</code> qualify for this treatment.</li> - * <li><code>aconst_null</code> becomes <code>ldc</code> of a - * "known null."</li> - * <li>Shorthand local variable accessors become the corresponding - * longhand. E.g. <code>aload_2</code> becomes <code>aload</code>.</li> - * <li><code>goto_w</code> and <code>jsr_w</code> become <code>goto</code> - * and <code>jsr</code> (respectively).</li> - * <li><code>ldc_w</code> becomes <code>ldc</code>.</li> - * <li><code>tableswitch</code> becomes <code>lookupswitch</code>. - * <li>Arithmetic, array, and value-returning ops are collapsed - * to the <code>int</code> variant opcode, with the <code>type</code> - * argument set to indicate the actual type. E.g., - * <code>fadd</code> becomes <code>iadd</code>, but - * <code>type</code> is passed as <code>Type.FLOAT</code> in that - * case. Similarly, <code>areturn</code> becomes - * <code>ireturn</code>. (However, <code>return</code> remains - * unchanged.</li> - * <li>Local variable access ops are collapsed to the <code>int</code> - * variant opcode, with the <code>type</code> argument set to indicate - * the actual type. E.g., <code>aload</code> becomes <code>iload</code>, - * but <code>type</code> is passed as <code>Type.OBJECT</code> in - * that case.</li> - * <li>Numeric conversion ops (<code>i2l</code>, etc.) are left alone - * to avoid too much confustion, but their <code>type</code> is - * the pushed type. E.g., <code>i2b</code> gets type - * <code>Type.INT</code>, and <code>f2d</code> gets type - * <code>Type.DOUBLE</code>. Other unaltered opcodes also get - * their pushed type. E.g., <code>arraylength</code> gets type - * <code>Type.INT</code>.</li> - * </ul> - * - * @param offset >= 0, < bytes.size(); offset to the start of the - * instruction - * @param visitor 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: { - 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: { - 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.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</code>. - * - * @param offset the offset to the <code>tableswitch</code> opcode itself - * @param visitor 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</code>. - * - * @param offset the offset to the <code>lookupswitch</code> opcode itself - * @param visitor 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</code>. - * - * @param offset the offset to the <code>newarray</code> opcode itself - * @param visitor 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<Constant> initVals = new ArrayList<Constant>(); - - 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</code>. - * - * @param offset the offset to the <code>wide</code> opcode itself - * @param visitor 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 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 non-null; the type of the accessed value - * @param value additional literal integer argument, if salient (i.e., - * for <code>iinc</code>) - */ - 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</code>, the argument is the count of - * dimensions. In the case of <code>invokeinterface</code>, - * 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</code>, the <code>value</code> field always - * holds the raw value (for convenience of clients). - * - * <p><b>Note:</b> In order to avoid giving it a barely-useful - * visitor all its own, <code>newarray</code> also uses this - * form, passing <code>value</code> as the array type code and - * <code>cst</code> as a {@link CstType} instance - * corresponding to the array type.</p> - * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length length of the instruction, in bytes - * @param cst 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 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 cst non-null; the type of the array - * @param initVals non-null; list of bytecode offsets for init values - */ - public void visitNewarray(int offset, int length, CstType type, - ArrayList<Constant> 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} */ - public void visitInvalid(int opcode, int offset, int length) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitNoArgs(int opcode, int offset, int length, - Type type) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitLocal(int opcode, int offset, int length, - int idx, Type type, int value) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitConstant(int opcode, int offset, int length, - Constant cst, int value) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitBranch(int opcode, int offset, int length, - int target) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitSwitch(int opcode, int offset, int length, - SwitchList cases, int padding) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitNewarray(int offset, int length, CstType type, - ArrayList<Constant> initValues) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void setPreviousOffset(int offset) { - previousOffset = offset; - } - - /** {@inheritDoc} */ - public int getPreviousOffset() { - return previousOffset; - } - } - - /** - * Base implementation of {@link Visitor}, which has empty method - * bodies for all methods. - */ - class ConstantParserVisitor extends BaseVisitor { - Constant cst; - int length; - int value; - - /** Empty constructor */ - ConstantParserVisitor() { - } - - private void clear() { - length = 0; - } - - /** {@inheritDoc} */ - public void visitInvalid(int opcode, int offset, int length) { - clear(); - } - - /** {@inheritDoc} */ - public void visitNoArgs(int opcode, int offset, int length, - Type type) { - clear(); - } - - /** {@inheritDoc} */ - public void visitLocal(int opcode, int offset, int length, - int idx, Type type, int value) { - clear(); - } - - /** {@inheritDoc} */ - public void visitConstant(int opcode, int offset, int length, - Constant cst, int value) { - this.cst = cst; - this.length = length; - this.value = value; - } - - /** {@inheritDoc} */ - public void visitBranch(int opcode, int offset, int length, - int target) { - clear(); - } - - /** {@inheritDoc} */ - public void visitSwitch(int opcode, int offset, int length, - SwitchList cases, int padding) { - clear(); - } - - /** {@inheritDoc} */ - public void visitNewarray(int offset, int length, CstType type, - ArrayList<Constant> initVals) { - clear(); - } - - /** {@inheritDoc} */ - public void setPreviousOffset(int offset) { - // Intentionally left empty - } - - /** {@inheritDoc} */ - public int getPreviousOffset() { - // Intentionally left empty - return -1; - } - } -} diff --git a/dx/src/com/android/dx/cf/code/ConcreteMethod.java b/dx/src/com/android/dx/cf/code/ConcreteMethod.java deleted file mode 100644 index 47f698dc2..000000000 --- a/dx/src/com/android/dx/cf/code/ConcreteMethod.java +++ /dev/null @@ -1,254 +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.android.dx.cf.code; - -import com.android.dx.cf.attrib.AttCode; -import com.android.dx.cf.attrib.AttLineNumberTable; -import com.android.dx.cf.attrib.AttLocalVariableTable; -import com.android.dx.cf.attrib.AttLocalVariableTypeTable; -import com.android.dx.cf.attrib.AttSourceFile; -import com.android.dx.cf.iface.AttributeList; -import com.android.dx.cf.iface.ClassFile; -import com.android.dx.cf.iface.Method; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.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</code> attribute. - */ -public final class ConcreteMethod implements Method { - /** non-null; method being wrapped */ - private final Method method; - - /** - * null-ok; the class's <code>SourceFile</code> attribute value, - * if any - */ - private final CstUtf8 sourceFile; - - /** - * whether the class that this method is part of is defined with - * <code>ACC_SUPER</code> - */ - private final boolean accSuper; - - /** non-null; the code attribute */ - private final AttCode attCode; - - /** non-null; line number list */ - private final LineNumberList lineNumbers; - - /** non-null; local variable list */ - private final LocalVariableList localVariables; - - /** - * Constructs an instance. - * - * @param method non-null; the method to be based on - * @param cf 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 cf, boolean keepLines, - boolean keepLocals) { - this.method = method; - this.accSuper = (cf.getAccessFlags() & AccessFlags.ACC_SUPER) != 0; - this.sourceFile = cf.getSourceFile(); - - 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 lineNumbers = LineNumberList.EMPTY; - if (keepLines) { - for (AttLineNumberTable lnt = (AttLineNumberTable) - codeAttribs.findFirst(AttLineNumberTable.ATTRIBUTE_NAME); - lnt != null; - lnt = (AttLineNumberTable) codeAttribs.findNext(lnt)) { - lineNumbers = LineNumberList.concat(lineNumbers, - lnt.getLineNumbers()); - } - } - this.lineNumbers = lineNumbers; - - LocalVariableList localVariables = 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)) { - localVariables = - LocalVariableList.concat(localVariables, - 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) { - localVariables = - LocalVariableList.mergeDescriptorsAndSignatures( - localVariables, typeList); - } - } - this.localVariables = localVariables; - } - - /** {@inheritDoc} */ - public CstNat getNat() { - return method.getNat(); - } - - /** {@inheritDoc} */ - public CstUtf8 getName() { - return method.getName(); - } - - /** {@inheritDoc} */ - public CstUtf8 getDescriptor() { - return method.getDescriptor(); - } - - /** {@inheritDoc} */ - public int getAccessFlags() { - return method.getAccessFlags(); - } - - /** {@inheritDoc} */ - public AttributeList getAttributes() { - return method.getAttributes(); - } - - /** {@inheritDoc} */ - public CstType getDefiningClass() { - return method.getDefiningClass(); - } - - /** {@inheritDoc} */ - public Prototype getEffectiveDescriptor() { - return method.getEffectiveDescriptor(); - } - - /** - * Gets whether the class that this method is part of is defined with - * <code>ACC_SUPER</code>. - * - * @return the <code>ACC_SUPER</code> value - */ - public boolean getAccSuper() { - return accSuper; - } - - /** - * Gets the maximum stack size. - * - * @return >= 0; the maximum stack size - */ - public int getMaxStack() { - return attCode.getMaxStack(); - } - - /** - * Gets the number of locals. - * - * @return >= 0; the number of locals - */ - public int getMaxLocals() { - return attCode.getMaxLocals(); - } - - /** - * Gets the bytecode array. - * - * @return non-null; the bytecode array - */ - public BytecodeArray getCode() { - return attCode.getCode(); - } - - /** - * Gets the exception table. - * - * @return non-null; the exception table - */ - public ByteCatchList getCatches() { - return attCode.getCatches(); - } - - /** - * Gets the line number list. - * - * @return non-null; the line number list - */ - public LineNumberList getLineNumbers() { - return lineNumbers; - } - - /** - * Gets the local variable list. - * - * @return non-null; the local variable list - */ - public LocalVariableList getLocalVariables() { - return localVariables; - } - - /** - * Returns a {@link SourcePosition} instance corresponding to the - * given bytecode offset. - * - * @param offset >= 0; the bytecode offset - * @return non-null; an appropriate instance - */ - public SourcePosition makeSourcePosistion(int offset) { - return new SourcePosition(sourceFile, offset, - lineNumbers.pcToLine(offset)); - } -} diff --git a/dx/src/com/android/dx/cf/code/ExecutionStack.java b/dx/src/com/android/dx/cf/code/ExecutionStack.java deleted file mode 100644 index 1a2b565dd..000000000 --- a/dx/src/com/android/dx/cf/code/ExecutionStack.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.android.dx.cf.code; - -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.util.ExceptionWithContext; -import com.android.dx.util.Hex; -import com.android.dx.util.MutabilityControl; - -/** - * Representation of a Java method execution stack. - * - * <p><b>Note:</b> For the most part, the documentation for this class - * ignores the distinction between {@link Type} and {@link - * TypeBearer}.</p> - */ -public final class ExecutionStack extends MutabilityControl { - /** non-null; array of stack contents */ - private final TypeBearer[] stack; - - /** - * >= 0; stack pointer (points one past the end) / current stack - * size - */ - private int stackPtr; - - /** - * Constructs an instance. - * - * @param maxStack >= 0; the maximum size of the stack for this - * instance - */ - public ExecutionStack(int maxStack) { - super(maxStack != 0); - stack = new TypeBearer[maxStack]; - stackPtr = 0; - } - - /** - * Makes and returns a mutable copy of this instance. - * - * @return non-null; the copy - */ - public ExecutionStack copy() { - ExecutionStack result = new ExecutionStack(stack.length); - - System.arraycopy(stack, 0, result.stack, 0, stack.length); - result.stackPtr = stackPtr; - - return result; - } - - /** - * Annotates (adds context to) the given exception with information - * about this instance. - * - * @param ex 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 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 >= 0; the max stack size - */ - public int getMaxStack() { - return stack.length; - } - - /** - * Gets the current stack size. - * - * @return >= 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; - } - - stackPtr = 0; - } - - /** - * Pushes a value of the given type onto the stack. - * - * @param type 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++; - } - - /** - * Peeks at the <code>n</code>th element down from the top of the stack. - * <code>n == 0</code> means to peek at the top of the stack. Note that - * this will return <code>null</code> if the indicated element is the - * deeper half of a category-2 value. - * - * @param n >= 0; which element to peek at - * @return null-ok; the type of value stored at that element - * @throws SimException thrown if <code>n >= size()</code> - */ - 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</code>th element down from the top of the - * stack, returning the type per se, as opposed to the - * <i>type-bearer</i>. This method is just a convenient shorthand - * for <code>peek(n).getType()</code>. - * - * @see #peek - */ - public Type peekType(int n) { - return peek(n).getType(); - } - - /** - * Pops the top element off of the stack. - * - * @return 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; - 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 >= 0; which element to change, where <code>0</code> is - * the top element of the stack - * @param type non-null; type of the new value - * @throws SimException thrown if <code>n >= size()</code> 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 non-null; a stack to merge with - * @return 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()</code> except that <code>null</code> is converted - * to <code>"<invalid>"</code>. - * - * @param type null-ok; the stack element - * @return non-null; the string form - */ - private static String stackElementString(TypeBearer type) { - if (type == null) { - return "<invalid>"; - } - - return type.toString(); - } - - /** - * Throws a properly-formatted exception. - * - * @param msg non-null; useful message - * @return never (keeps compiler happy) - */ - private static TypeBearer throwSimException(String msg) { - throw new SimException("stack: " + msg); - } -} diff --git a/dx/src/com/android/dx/cf/code/Frame.java b/dx/src/com/android/dx/cf/code/Frame.java deleted file mode 100644 index a74d142ee..000000000 --- a/dx/src/com/android/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.android.dx.cf.code; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.util.ExceptionWithContext; -import com.android.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 { - /** non-null; the locals */ - private final LocalsArray locals; - - /** non-null; the stack */ - private final ExecutionStack stack; - - /** null-ok; stack of labels of subroutines that this block is nested in */ - private final IntList subroutines; - - /** - * Constructs an instance. - * - * @param locals non-null; the locals array to use - * @param stack non-null; the execution stack to use - */ - private Frame(LocalsArray locals, ExecutionStack stack) { - this(locals, stack, IntList.EMPTY); - } - - /** - * Constructs an instance. - * - * @param locals non-null; the locals array to use - * @param stack non-null; the execution stack to use - * @param subroutines 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</code>s) and - * the stack starts out empty. - * - * @param maxLocals >= 0; the maximum number of locals this instance - * can refer to - * @param maxStack >= 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 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 non-null; type to replace - */ - public void makeInitialized(Type type) { - locals.makeInitialized(type); - stack.makeInitialized(type); - } - - /** - * Gets the locals array for this instance. - * - * @return non-null; the locals array - */ - public LocalsArray getLocals() { - return locals; - } - - /** - * Gets the execution stack for this instance. - * - * @return 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 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 >=0; The label of the returning subroutine's - * start block - * @param subLabel >=0; A calling label of a subroutine - * @return 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 non-null; another frame - * @return 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 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 non-null; LocalsArray from before a merge - * @param subroutines non-null; a label list of subroutine start blocks - * representing the subroutine nesting of the block being merged into. - * @return 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</code>. Only called on the frame at the first - * block of a subroutine. - * - * @param other non-null; another frame - * @param subLabel label of subroutine start block - * @param predLabel label of calling block - * @return 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 >=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 non-null; the exception to annotate - */ - public void annotate(ExceptionWithContext ex) { - locals.annotate(ex); - stack.annotate(ex); - } -} diff --git a/dx/src/com/android/dx/cf/code/LineNumberList.java b/dx/src/com/android/dx/cf/code/LineNumberList.java deleted file mode 100644 index 35875b0a7..000000000 --- a/dx/src/com/android/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.android.dx.cf.code; - -import com.android.dx.util.FixedSizeList; - -/** - * List of "line number" entries, which are the contents of - * <code>LineNumberTable</code> attributes. - */ -public final class LineNumberList extends FixedSizeList { - /** 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 non-null; first instance - * @param list2 non-null; second instance - * @return 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 >= 0; which item - * @return null-ok; the indicated item - */ - public Item get(int n) { - return (Item) get0(n); - } - - /** - * Sets the item at the given index. - * - * @param n >= 0, < size(); which element - * @param item 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 >= 0, < size(); which element - * @param startPc >= 0; start pc of this item - * @param lineNumber >= 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 >= 0; the address to look up - * @return >= -1; the associated line number, or <code>-1</code> 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 { - /** >= 0; start pc of this item */ - private final int startPc; - - /** >= 0; corresponding line number */ - private final int lineNumber; - - /** - * Constructs an instance. - * - * @param startPc >= 0; start pc of this item - * @param lineNumber >= 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/dx/src/com/android/dx/cf/code/LocalVariableList.java b/dx/src/com/android/dx/cf/code/LocalVariableList.java deleted file mode 100644 index 10876036b..000000000 --- a/dx/src/com/android/dx/cf/code/LocalVariableList.java +++ /dev/null @@ -1,374 +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.android.dx.cf.code; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.code.LocalItem; -import com.android.dx.util.FixedSizeList; - -/** - * List of "local variable" entries, which are the contents of - * <code>LocalVariableTable</code> and <code>LocalVariableTypeTable</code> - * attributes, as well as combinations of the two. - */ -public final class LocalVariableList extends FixedSizeList { - /** 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 non-null; first instance - * @param list2 non-null; second instance - * @return 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 non-null; list with descriptors - * @param signatureList non-null; list with signatures - * @return non-null; the merged result - */ - public static LocalVariableList mergeDescriptorsAndSignatures( - LocalVariableList descriptorList, - LocalVariableList signatureList) { - int signatureSize = signatureList.size(); - 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) { - CstUtf8 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 >= 0; which item - * @return null-ok; the indicated item - */ - public Item get(int n) { - return (Item) get0(n); - } - - /** - * Sets the item at the given index. - * - * @param n >= 0, < size(); which element - * @param item 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. - * - * <p><b>Note:</b> At least one of <code>descriptor</code> or - * <code>signature</code> must be passed as non-null.</p> - * - * @param n >= 0, < size(); which element - * @param startPc >= 0; the start pc of this variable's scope - * @param length >= 0; the length (in bytecodes) of this variable's - * scope - * @param name non-null; the variable's name - * @param descriptor null-ok; the variable's type descriptor - * @param signature null-ok; the variable's type signature - * @param index >= 0; the variable's local index - */ - public void set(int n, int startPc, int length, CstUtf8 name, - CstUtf8 descriptor, CstUtf8 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.android.dx.cf.code.LocalVariableList.Item} - * in all respects but the type descriptor and signature, if any. - * - * @param item non-null; local variable information to match - * @return null-ok; the corresponding local variable information stored - * in this instance, or <code>null</code> 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. <b>Note:</b> In standard classfiles, a - * variable's start point is listed as the address of the instruction - * <i>just past</i> the one that sets the variable. - * - * @param pc >= 0; the address to look up - * @param index >= 0; the local variable index - * @return null-ok; the associated local variable information, or - * <code>null</code> 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 { - /** >= 0; the start pc of this variable's scope */ - private final int startPc; - - /** >= 0; the length (in bytecodes) of this variable's scope */ - private final int length; - - /** non-null; the variable's name */ - private final CstUtf8 name; - - /** null-ok; the variable's type descriptor */ - private final CstUtf8 descriptor; - - /** null-ok; the variable's type signature */ - private final CstUtf8 signature; - - /** >= 0; the variable's local index */ - private final int index; - - /** - * Constructs an instance. - * - * <p><b>Note:</b> At least one of <code>descriptor</code> or - * <code>signature</code> must be passed as non-null.</p> - * - * @param startPc >= 0; the start pc of this variable's scope - * @param length >= 0; the length (in bytecodes) of this variable's - * scope - * @param name non-null; the variable's name - * @param descriptor null-ok; the variable's type descriptor - * @param signature null-ok; the variable's type signature - * @param index >= 0; the variable's local index - */ - public Item(int startPc, int length, CstUtf8 name, - CstUtf8 descriptor, CstUtf8 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 >= 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 >= 0; the length (in bytecodes) of this variable's scope - */ - public int getLength() { - return length; - } - - /** - * Gets the variable's type descriptor. - * - * @return null-ok; the variable's type descriptor - */ - public CstUtf8 getDescriptor() { - return descriptor; - } - - /** - * Gets the variable's LocalItem, a (name, signature) tuple - * - * @return 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 null-ok; the variable's type signature - */ - private CstUtf8 getSignature() { - return signature; - } - - /** - * Gets the variable's local index. - * - * @return >= 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())</code>. - * - * @return 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 non-null; the new signature - * @return non-null; an appropriately-constructed instance - */ - public Item withSignature(CstUtf8 newSignature) { - return new Item(startPc, length, name, descriptor, newSignature, - index); - } - - /** - * Gets whether this instance matches (describes) the given - * address and index. - * - * @param pc >= 0; the address in question - * @param index >= 0; the local variable index in question - * @return <code>true</code> iff this instance matches <code>pc</code> - * and <code>index</code> - */ - 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 non-null; the instance to compare to - * @return <code>true</code> 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/dx/src/com/android/dx/cf/code/LocalsArray.java b/dx/src/com/android/dx/cf/code/LocalsArray.java deleted file mode 100644 index 1c324ca07..000000000 --- a/dx/src/com/android/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.android.dx.cf.code; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.util.ExceptionWithContext; -import com.android.dx.util.Hex; -import com.android.dx.util.MutabilityControl; -import com.android.dx.util.ToHuman; - -/** - * Representation of an array of local variables, with Java semantics. - * - * <p><b>Note:</b> For the most part, the documentation for this class - * ignores the distinction between {@link Type} and {@link - * TypeBearer}.</p> - */ -public abstract class LocalsArray extends MutabilityControl implements ToHuman { - - /** - * Constructs an instance, explicitly indicating the mutability. - * - * @param mutable <code>true</code> if this instance is mutable - */ - protected LocalsArray(boolean mutable) { - super(mutable); - } - - /** - * Makes and returns a mutable copy of this instance. - * - * @return non-null; the copy - */ - public abstract LocalsArray copy(); - - /** - * Annotates (adds context to) the given exception with information - * about this instance. - * - * @param ex 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 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 - * <code>getMaxLocals()</code> and (b) the next index gets invalidated - * by the operation. In case of either category, if the <i>previous</i> - * local contains a category-2 value, then it too is invalidated by - * this operation. - * - * @param idx >= 0, < getMaxLocals(); which local - * @param type non-null; new type for the local at <code>idx</code> - */ - 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)</code>. - * - * @param spec 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 >= 0, < getMaxLocals(); which local - */ - public abstract void invalidate(int idx); - - /** - * Gets the type stored at the given local index, or <code>null</code> - * if the given local is uninitialized / invalid. - * - * @param idx >= 0, < getMaxLocals(); which local - * @return 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 >= 0, < getMaxLocals(); which local - * @return non-null; the type of value stored in that local - * @throws SimException thrown if <code>idx</code> 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 >= 0, < getMaxLocals(); which local - * @return non-null; the type of value stored in that local - * @throws SimException thrown if <code>idx</code> 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 >= 0, < getMaxLocals(); which local - * @return non-null; the type of value stored in that local - * @throws SimException thrown if <code>idx</code> 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</code>. If the merged result is - * the same as this instance, then this is returned (not a copy). - * - * @param other non-null; another LocalsArray - * @return non-null; the merge result, a new instance or this - */ - public abstract LocalsArray merge(LocalsArray other); - - /** - * Merges this instance with a <code>LocalsSet</code> from a subroutine - * caller. To be used when merging in the first block of a subroutine. - * - * @param other other non-null; another LocalsArray. The final locals - * state of a subroutine caller. - * @param predLabel the label of the subroutine caller block. - * @return 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</code> instance, then return - * <code>this</code>, otherwise return <code>LocalsArraySet</code>'s - * primary. - * - * @return locals for this execution context. - */ - protected abstract OneLocalsArray getPrimary(); - -} diff --git a/dx/src/com/android/dx/cf/code/LocalsArraySet.java b/dx/src/com/android/dx/cf/code/LocalsArraySet.java deleted file mode 100644 index 9e24da9b9..000000000 --- a/dx/src/com/android/dx/cf/code/LocalsArraySet.java +++ /dev/null @@ -1,462 +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.android.dx.cf.code; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.util.ExceptionWithContext; -import com.android.dx.util.Hex; -import com.android.dx.util.MutabilityControl; - -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. - * - * <p><b>Note:</b> For the most part, the documentation for this class - * ignores the distinction between {@link com.android.dx.rop.type.Type} and {@link - * com.android.dx.rop.type.TypeBearer}.</p> - */ -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<LocalsArray> secondaries; - - /** - * Constructs an instance. The locals array initially consists of - * all-uninitialized values (represented as <code>null</code>s). - * - * @param maxLocals >= 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 non-null; primary locals to use - * @param secondaries non-null; secondaries set, indexed by subroutine - * caller label. - */ - public LocalsArraySet(OneLocalsArray primary, - ArrayList<LocalsArray> secondaries) { - super(primary.getMaxLocals() > 0); - - this.primary = primary; - this.secondaries = secondaries; - } - - /** - * Constructs an instance which is a copy of another. - * - * @param toCopy 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*/ - 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</code> instance. - * - * @param other non-null; to merge - * @return non-null; this instance if merge was a no-op, or - * new merged instance. - */ - private LocalsArraySet mergeWithSet(LocalsArraySet other) { - OneLocalsArray newPrimary; - ArrayList<LocalsArray> 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</code> instance. - * - * @param other non-null; to merge - * @return non-null; this instance if merge was a no-op, or - * new merged instance. - */ - private LocalsArraySet mergeWithOne(OneLocalsArray other) { - OneLocalsArray newPrimary; - ArrayList<LocalsArray> 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</code> instance for a specified subroutine - * caller label, or null if label has no locals associated with it. - * - * @param label >=0 subroutine caller label - * @return 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<LocalsArray> 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 >= 0; A calling label of a subroutine - * @return 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/dx/src/com/android/dx/cf/code/Machine.java b/dx/src/com/android/dx/cf/code/Machine.java deleted file mode 100644 index 517a10d6a..000000000 --- a/dx/src/com/android/dx/cf/code/Machine.java +++ /dev/null @@ -1,208 +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.android.dx.cf.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.code.LocalItem; -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 <i>effective</i> prototype includes an initial - * <code>this</code> argument for instance methods. - * - * @return 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 non-null; frame to operate on - * @param count >= 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</code> (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 non-null; frame to operate on - * @param prototype 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 non-null; frame to operate on - * @param type 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 non-null; frame to operate on - * @param type1 non-null; type of the first argument - * @param type2 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 non-null; frame to operate on - * @param type1 non-null; type of the first argument - * @param type2 non-null; type of the second argument - * @param type3 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 non-null; frame to operate on - * @param idx >= 0; the local variable index - */ - public void localArg(Frame frame, int idx); - - /** - * 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</code> are collapsed to the <code>int</code> - * variant. (See {@link BytecodeArray#parseInstruction} for - * details.) - * - * @param type 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</code>, with the given value. - * - * <p><b>Note:</b> Perhaps unintuitively, the stack manipulation - * ops (e.g., <code>dup</code> and <code>swap</code>) 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</code> sets this to <code>0x12312</code>, and the - * other form of that op sets this to - * <code>0x121</code>.</p> - * - * <p><b>Also Note:</b> For <code>switch*</code> instructions, this is - * used to indicate the padding value (which is only useful for - * verification).</p> - * - * @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. - * - * <p><b>Note:</b> Some opcodes use both <code>int</code> and - * constant auxiliary arguments.</p> - * - * @param cst 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*</code> table. - * - * <p><b>Note:</b> This is generally used in conjunction with - * {@link #auxIntArg} (which holds the padding).</p> - * - * @param cases 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 non-null; the list of constant values to initialize - * the array - */ - public void auxInitValues(ArrayList<Constant> initValues); - - /** - * Indicates that the target of this operation is the given local. - * - * @param idx >= 0; the local variable index - * @param type non-null; the type of the local - * @param local 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 non-null; frame to operate on - * @param offset >= 0; byte offset in the method to the opcode being - * run - * @param opcode >= 0; the opcode to run - */ - public void run(Frame frame, int offset, int opcode); -} diff --git a/dx/src/com/android/dx/cf/code/Merger.java b/dx/src/com/android/dx/cf/code/Merger.java deleted file mode 100644 index adeaab225..000000000 --- a/dx/src/com/android/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.android.dx.cf.code; - -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.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 non-null; a locals array - * @param locals2 non-null; another locals array - * @return 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 non-null; a stack - * @param stack2 non-null; another stack - * @return 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 non-null; a frame type - * @param ft2 non-null; another frame type - * @return 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</code> is the supertype of all reference - * types and all arrays are assignable to - * <code>Serializable</code> and <code>Cloneable</code>. - * - * @param supertypeBearer non-null; the supertype - * @param subtypeBearer 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/dx/src/com/android/dx/cf/code/OneLocalsArray.java b/dx/src/com/android/dx/cf/code/OneLocalsArray.java deleted file mode 100644 index 3a590a105..000000000 --- a/dx/src/com/android/dx/cf/code/OneLocalsArray.java +++ /dev/null @@ -1,246 +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.android.dx.cf.code; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.util.ExceptionWithContext; -import com.android.dx.util.Hex; -import com.android.dx.util.MutabilityControl; - -/** - * Representation of an array of local variables, with Java semantics. - * - * <p><b>Note:</b> For the most part, the documentation for this class - * ignores the distinction between {@link com.android.dx.rop.type.Type} and {@link - * com.android.dx.rop.type.TypeBearer}.</p> - */ -public class OneLocalsArray extends LocalsArray { - /** non-null; actual array */ - private final TypeBearer[] locals; - - /** - * Constructs an instance. The locals array initially consists of - * all-uninitialized values (represented as <code>null</code>s). - * - * @param maxLocals >= 0; the maximum number of locals this instance - * can refer to - */ - public OneLocalsArray(int maxLocals) { - super(maxLocals != 0); - locals = new TypeBearer[maxLocals]; - } - - /** @inheritDoc */ - public OneLocalsArray copy() { - OneLocalsArray result = new OneLocalsArray(locals.length); - - System.arraycopy(locals, 0, result.locals, 0, locals.length); - - return result; - } - - /** @inheritDoc */ - public void annotate(ExceptionWithContext ex) { - for (int i = 0; i < locals.length; i++) { - TypeBearer type = locals[i]; - String s = (type == null) ? "<invalid>" : type.toString(); - ex.addContext("locals[" + Hex.u2(i) + "]: " + s); - } - } - - /** {@inheritDoc*/ - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < locals.length; i++) { - TypeBearer type = locals[i]; - String s = (type == null) ? "<invalid>" : type.toString(); - sb.append("locals[" + Hex.u2(i) + "]: " + s + "\n"); - } - - return sb.toString(); - } - - /** @inheritDoc */ - 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 */ - public int getMaxLocals() { - return locals.length; - } - - /** @inheritDoc */ - 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 */ - public void set(RegisterSpec spec) { - set(spec.getReg(), spec); - } - - /** @inheritDoc */ - public void invalidate(int idx) { - throwIfImmutable(); - locals[idx] = null; - } - - /** @inheritDoc */ - public TypeBearer getOrNull(int idx) { - return locals[idx]; - } - - /** @inheritDoc */ - public TypeBearer get(int idx) { - TypeBearer result = locals[idx]; - - if (result == null) { - return throwSimException(idx, "invalid"); - } - - return result; - } - - /** @inheritDoc */ - 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 */ - 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 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/dx/src/com/android/dx/cf/code/ReturnAddress.java b/dx/src/com/android/dx/cf/code/ReturnAddress.java deleted file mode 100644 index c69253c95..000000000 --- a/dx/src/com/android/dx/cf/code/ReturnAddress.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.android.dx.cf.code; - -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.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 <i>start address</i> of the subroutine - * being returned from, not the address being returned <i>to</i>, so that's - * what instances of this class hang onto. - */ -public final class ReturnAddress implements TypeBearer { - /** >= 0; the start address of the subroutine being returned from */ - private final int subroutineAddress; - - /** - * Constructs an instance. - * - * @param subroutineAddress >= 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 ("<addr:" + Hex.u2(subroutineAddress) + ">"); - } - - /** {@inheritDoc} */ - public String toHuman() { - return toString(); - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.RETURN_ADDRESS; - } - - /** {@inheritDoc} */ - public TypeBearer getFrameType() { - return this; - } - - /** {@inheritDoc} */ - public int getBasicType() { - return Type.RETURN_ADDRESS.getBasicType(); - } - - /** {@inheritDoc} */ - public int getBasicFrameType() { - return Type.RETURN_ADDRESS.getBasicFrameType(); - } - - /** {@inheritDoc} */ - 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 >= 0; the subroutine address - */ - public int getSubroutineAddress() { - return subroutineAddress; - } -} diff --git a/dx/src/com/android/dx/cf/code/Ropper.java b/dx/src/com/android/dx/cf/code/Ropper.java deleted file mode 100644 index f3eecab53..000000000 --- a/dx/src/com/android/dx/cf/code/Ropper.java +++ /dev/null @@ -1,1667 +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.android.dx.cf.code; - -import com.android.dx.rop.code.*; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.Bits; -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.HashMap; - -/** - * 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; - - /** non-null; method being converted */ - private final ConcreteMethod method; - - /** 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; - - /** non-null; simulation machine to use */ - private final RopperMachine machine; - - /** non-null; simulator to use */ - private final Simulator sim; - - /** - * non-null; sparse array mapping block labels to initial frame contents, - * if known - */ - private final Frame[] startFrames; - - /** non-null; output block list in-progress */ - private final ArrayList<BasicBlock> result; - - /** - * non-null; list of subroutine-nest labels - * (See {@link Frame#getSubroutines} associated with each result block. - * Parallel to {@link Ropper#result}. - */ - private final ArrayList<IntList> resultSubroutines; - - /** - * non-null; for each block (by label) that is used as an exception - * handler, the type of exception it catches - */ - private final Type[] catchTypes; - - /** - * whether an exception-handler block for a synchronized method was - * ever required - */ - private boolean synchNeedsExceptionHandler; - - /** non-null; list of subroutines indexed by label of start address */ - private final Subroutine subroutines[]; - - /** true if <code>subroutines</code> is non-empty */ - private boolean hasSubroutines; - - /** - * 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 >= 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</code> as appropriate. To be called with - * the frame of a subroutine ret block. - * - * @param frame non-null; frame from ret block to merge - * @param workSet non-null; workset to update - */ - void mergeToSuccessors(Frame frame, int[] workSet) { - int sz = callerBlocks.size(); - - 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 non-null; method to convert - * @param advice non-null; translation advice to use - * @return non-null; the converted instance - */ - public static RopMethod convert(ConcreteMethod method, - TranslationAdvice advice) { - try { - Ropper r = new Ropper(method, advice); - 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 non-null; method to convert - * @param advice non-null; translation advice to use - */ - private Ropper(ConcreteMethod method, TranslationAdvice advice) { - 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); - this.sim = new Simulator(machine, method); - 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<BasicBlock>(blocks.size() * 2 + 10); - this.resultSubroutines = new ArrayList<IntList>(blocks.size() * 2 + 10); - - this.catchTypes = new Type[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()); - } - - /** - * Gets the first (lowest) register number to use as the temporary - * area when unwinding stack manipulation ops. - * - * @return >= 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 exception handler setup block corresponding - * to the given label. - * - * @param label >= 0; the original label - * @return >= 0; the corresponding exception handler setup label - */ - private int getExceptionSetupLabel(int label) { - return maxLabel + label; - } - - /** - * 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 < 0; the special label constant - * @return >= 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. We multiply maxLabel by 2 since 0..maxLabel - * (exclusive) are the original blocks and - * maxLabel..(maxLabel*2) are reserved for exception handler - * setup blocks (see getExceptionSetupLabel(), above). - */ - return (maxLabel * 2) + ~label; - } - - /** - * Gets the minimum label for unreserved use. - * - * @return >= 0; the minimum label - */ - private int getMinimumUnreservedLabel() { - /* - * The labels below ((maxLabel * 2) + SPECIAL_LABEL_COUNT) are - * reserved for particular uses. - */ - - return (maxLabel * 2) + SPECIAL_LABEL_COUNT; - } - - /** - * Gets an arbitrary unreserved and available label. - * - * @return >= 0; the label - */ - 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 >= 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 non-null; the register spec - */ - private RegisterSpec getSynchReg() { - /* - * We use the register that is just past the deepest possible - * stack element. 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. - */ - return RegisterSpec.make(getNormalRegCount(), Type.OBJECT); - } - - /** - * Searches {@link #result} for a block with the given label. Return its - * index if found, or return <code>-1</code> if there is no such block. - * - * @param label the label to look for - * @return >= -1; the index for the block with the given label or - * <code>-1</code> 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. Return it if - * found, or throw an exception if there is no such block. - * - * @param label the label to look for - * @return 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 non-null; the block to add - * @param subroutines 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 non-null; the block to add or replace - * @param subroutines non-null; subroutine label list as described in - * {@link Frame#getSubroutines} - * @return <code>true</code> if the block was replaced or - * <code>false</code> 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 non-null; the block to add or replace - * @param subroutines non-null; subroutine label list as described in - * {@link Frame#getSubroutines} - * @return <code>true</code> if the block was replaced or - * <code>false</code> 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 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 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 non-null; block to process - * @param frame non-null; start frame for the block - * @param workSet 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<Insn> 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, by setting it if - * the given handler has yet to be encountered, or by - * conservatively unioning if it has. - */ - Type already = catchTypes[targ]; - if (already == null) { - catchTypes[targ] = exceptionClass.getClassType(); - } else if (already != exceptionClass.getClassType()) { - catchTypes[targ] = Type.OBJECT; - } - - /* - * The synthesized exception setup block will have the - * label getExceptionSetupLabel(targ). - */ - newSucc.add(getExceptionSetupLabel(targ)); - } - - 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 >= 0; label to work on - * @param pred predecessor label. Must be >= 0 when - * <code>label</code> is a subroutine start block and calledSubroutine - * is non-null. Otherwise, may be -1. - * @param calledSubroutine null-ok; a Subroutine instance if - * <code>label</code> is the first block in a subroutine. - * @param frame non-null; new frame for the labelled block - * @param workSet 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</code> - * 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 = catchTypes.length; - for (int i = 0; i < len; i++) { - Type one = catchTypes[i]; - if (one != null) { - Insn proto = labelToBlock(i).getFirstInsn(); - SourcePosition pos = proto.getPosition(); - InsnList il = new InsnList(2); - - Insn insn = new PlainInsn(Rops.opMoveException(one), - pos, - RegisterSpec.make(maxLocals, one), - 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(getExceptionSetupLabel(i), - il, - IntList.makeImmutable(i), - i); - addBlock(bb, startFrames[i].getSubroutines()); - } - } - } - - /** - * Checks to see if the basic block is a subroutine caller block. - * - * @param bb 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() { - 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<IntList> labelToSubroutines - = new ArrayList<IntList>(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() { - - 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++; - } - } - - /** - * Inlines a subroutine. Start by calling - * <code>inlineSubroutineCalledFrom</code>. - */ - private class SubroutineInliner { - /** - * maps original label to the label - * that will be used by the inlined version - */ - private final HashMap<Integer, Integer> 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<IntList> labelToSubroutines; - - SubroutineInliner(final LabelAllocator labelAllocator, - ArrayList<IntList> labelToSubroutines) { - origLabelToCopiedLabel = new HashMap<Integer, Integer>(); - - workList = new BitSet(maxLabel); - - this.labelAllocator = labelAllocator; - this.labelToSubroutines = labelToSubroutines; - } - - /** - * Inlines a subroutine. - * - * @param b block where 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 >=0 a basic block label - * @param subroutineStart >=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.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<code> that is returned from by a ret in - * a given block. - * @param label A block that originally contained a ret instruction - * @return null-ok; Subroutine or 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 move-return-address instructions, returning a new InsnList - * if necessary. The move-return-address insns are dead code after - * subroutines have been inlined. - * - * @param insns InsnList that may contain move-return-address insns - * @return InsnList with 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 jsr - * targets. Worker for 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/dx/src/com/android/dx/cf/code/RopperMachine.java b/dx/src/com/android/dx/cf/code/RopperMachine.java deleted file mode 100644 index 6d05b382e..000000000 --- a/dx/src/com/android/dx/cf/code/RopperMachine.java +++ /dev/null @@ -1,936 +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.android.dx.cf.code; - -import com.android.dx.rop.code.FillArrayDataInsn; -import com.android.dx.rop.code.Insn; -import com.android.dx.rop.code.PlainCstInsn; -import com.android.dx.rop.code.PlainInsn; -import com.android.dx.rop.code.RegOps; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.Rop; -import com.android.dx.rop.code.Rops; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.code.SwitchInsn; -import com.android.dx.rop.code.ThrowingCstInsn; -import com.android.dx.rop.code.ThrowingInsn; -import com.android.dx.rop.code.TranslationAdvice; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.IntList; - -import java.util.ArrayList; - -/** - * Machine implementation for use by {@link Ropper}. - */ -/*package*/ final class RopperMachine extends ValueAwareMachine { - /** non-null; array reflection class */ - private static final CstType ARRAY_REFLECT_TYPE = - new CstType(Type.internClassName("java/lang/reflect/Array")); - - /** - * non-null; method constant for use in converting - * <code>multianewarray</code> instructions - */ - private static final CstMethodRef MULTIANEWARRAY_METHOD = - new CstMethodRef(ARRAY_REFLECT_TYPE, - new CstNat(new CstUtf8("newInstance"), - new CstUtf8("(Ljava/lang/Class;[I)" + - "Ljava/lang/Object;"))); - - /** non-null; {@link Ropper} controlling this instance */ - private final Ropper ropper; - - /** non-null; method being converted */ - private final ConcreteMethod method; - - /** non-null; translation advice */ - private final TranslationAdvice advice; - - /** max locals of the method */ - private final int maxLocals; - - /** non-null; instructions for the rop basic block in-progress */ - private final ArrayList<Insn> insns; - - /** 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</code> */ - private boolean returns; - - /** primary successor index */ - private int primarySuccessorIndex; - - /** >= 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; - - /** - * null-ok; the appropriate <code>return</code> op or <code>null</code> - * if it is not yet known - */ - private Rop returnOp; - - /** - * null-ok; the source position for the return block or <code>null</code> - * if it is not yet known - */ - private SourcePosition returnPosition; - - /** - * Constructs an instance. - * - * @param ropper non-null; ropper controlling this instance - * @param method non-null; method being converted - * @param advice non-null; translation advice to use - */ - public RopperMachine(Ropper ropper, ConcreteMethod method, - TranslationAdvice advice) { - super(method.getEffectiveDescriptor()); - - if (ropper == null) { - throw new NullPointerException("ropper == null"); - } - - if (advice == null) { - throw new NullPointerException("advice == null"); - } - - this.ropper = ropper; - this.method = method; - this.advice = advice; - this.maxLocals = method.getMaxLocals(); - this.insns = new ArrayList<Insn>(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 non-null; the instructions array - */ - public ArrayList<Insn> getInsns() { - return insns; - } - - /** - * Gets the return opcode encountered, if any. - * - * @return null-ok; the return opcode - */ - public Rop getReturnOp() { - return returnOp; - } - - /** - * Gets the return position, if known. - * - * @return 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</code>, 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</code> has been used - */ - public boolean wereCatchesUsed() { - return catchesUsed; - } - - /** - * Gets whether the block just processed ended with a - * <code>return</code>. - * - * @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</code> if there are successors but no primary - * successor. This may return something other than - * <code>-1</code> in the case of an instruction with no - * successors at all (primary or otherwise). - * - * @return >= -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 >= 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 true if a RET has ben encountered since the last call to - * startBlock() - */ - public boolean hasRet() { - return returnAddress != null; - } - - /** - * @return null-ok; return address of a ret instruction if encountered - * since last call to startBlock(). 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(); - 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) ? 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++; - - moveResult = new PlainInsn( - Rops.opMoveResult(((CstMethodRef) cst).getPrototype() - .getReturnType()), 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 lastType = sources.get(1).getTypeBearer(); - - if (lastType.isConstant() - && advice.hasConstantOperation(rop, - sources.get(0), sources.get(1))) { - /* - * 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(); - rop = Rops.ropFor(ropOpcode, destType, sources, cst); - } - } - - SwitchList cases = getAuxCases(); - ArrayList<Constant> 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) { - 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 >= 0; the stack pointer after the instruction's - * arguments have been popped - * @return 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 non-null; the opcode to use - * @param pos 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 >= 0; the Java opcode - * @param cst null-ok; the constant argument, if any - * @return >= 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: { - 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. - */ - CstMethodRef ref = (CstMethodRef) cst; - if (ref.isInstanceInit() || - (ref.getDefiningClass() == method.getDefiningClass()) || - !method.getAccSuper()) { - return RegOps.INVOKE_DIRECT; - } - return RegOps.INVOKE_SUPER; - } - case ByteOps.INVOKESTATIC: { - return RegOps.INVOKE_STATIC; - } - case ByteOps.INVOKEINTERFACE: { - return RegOps.INVOKE_INTERFACE; - } - 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"); - } -} diff --git a/dx/src/com/android/dx/cf/code/SimException.java b/dx/src/com/android/dx/cf/code/SimException.java deleted file mode 100644 index 220f2818a..000000000 --- a/dx/src/com/android/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.android.dx.cf.code; - -import com.android.dx.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/dx/src/com/android/dx/cf/code/Simulator.java b/dx/src/com/android/dx/cf/code/Simulator.java deleted file mode 100644 index 3c90ee593..000000000 --- a/dx/src/com/android/dx/cf/code/Simulator.java +++ /dev/null @@ -1,701 +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.android.dx.cf.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstInterfaceMethodRef; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.rop.code.LocalItem; -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; - -import java.util.List; -import java.util.ArrayList; - -/** - * Class which knows how to simulate the effects of executing bytecode. - * - * <p><b>Note:</b> This class is not thread-safe. If multiple threads - * need to use a single instance, they must synchronize access explicitly - * between themselves.</p> - */ -public class Simulator { - /** 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."; - - /** non-null; machine to use when simulating */ - private final Machine machine; - - /** non-null; array of bytecode */ - private final BytecodeArray code; - - /** non-null; local variable information */ - private final LocalVariableList localVariables; - - /** non-null; visitor instance to use */ - private final SimVisitor visitor; - - /** - * Constructs an instance. - * - * @param machine non-null; machine to use when simulating - * @param method non-null; method data to use - */ - public Simulator(Machine machine, ConcreteMethod method) { - if (machine == null) { - throw new NullPointerException("machine == null"); - } - - if (method == null) { - throw new NullPointerException("method == null"); - } - - this.machine = machine; - this.code = method.getCode(); - this.localVariables = method.getLocalVariables(); - this.visitor = new SimVisitor(); - } - - /** - * Simulates the effect of executing the given basic block. This modifies - * the passed-in frame to represent the end result. - * - * @param bb non-null; the basic block - * @param frame 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 >= 0; offset of the instruction to simulate - * @param frame 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"); - } - - /** - * Bytecode visitor used during simulation. - */ - private class SimVisitor implements BytecodeArray.Visitor { - /** - * non-null; machine instance to use (just to avoid excessive - * cross-object field access) - */ - private final Machine machine; - - /** - * 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 non-null; the frame - */ - public void setFrame(Frame frame) { - if (frame == null) { - throw new NullPointerException("frame == null"); - } - - this.frame = frame; - } - - /** {@inheritDoc} */ - public void visitInvalid(int opcode, int offset, int length) { - throw new SimException("invalid opcode " + Hex.u1(opcode)); - } - - /** {@inheritDoc} */ - 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()) { - throw new SimException("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: { - /* - * Change the type (which is to be pushed) to - * reflect the actual component type of the array - * being popped. - */ - Type requireType = type.getArrayType(); - type = frame.getStack().peekType(1); - if (type == Type.KNOWN_NULL) { - /* - * The type is a known-null: Just treat the - * popped type as whatever is expected. In - * reality, unless this frame is revisited - * (due to a branch merge), execution will - * result in the throwing of a - * NullPointerException, but claiming the - * expected type at here should be good enough - * for the purposes at this level. - */ - type = requireType; - } - type = type.getComponentType(); - machine.popArgs(frame, requireType, 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: { - Type arrayType = type.getArrayType(); - machine.popArgs(frame, arrayType, 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 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)) { - throw new SimException("return type mismatch: prototype " + - "indicates " + returnType.toHuman() + - ", but encountered type " + encountered.toHuman()); - } - } - - /** {@inheritDoc} */ - 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()) { - BaseMachine.throwLocalMismatch(type, localType); - return; - } - } else { - localType = type; - } - - switch (opcode) { - case ByteOps.ILOAD: - case ByteOps.RET: { - machine.localArg(frame, idx); - 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} */ - 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: { - /* - * Convert the interface method ref into a normal - * method ref. - */ - cst = ((CstInterfaceMethodRef) cst).toMethodRef(); - // and fall through... - } - case ByteOps.INVOKEVIRTUAL: - case ByteOps.INVOKESPECIAL: { - /* - * Get the instance prototype, and use it to direct - * the machine. - */ - Prototype prototype = - ((CstMethodRef) cst).getPrototype(false); - machine.popArgs(frame, prototype); - break; - } - case ByteOps.INVOKESTATIC: { - /* - * Get the static prototype, and use it to direct - * the machine. - */ - Prototype prototype = - ((CstMethodRef) cst).getPrototype(true); - machine.popArgs(frame, prototype); - 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; - } - default: { - machine.clearArgs(); - break; - } - } - - machine.auxIntArg(value); - machine.auxCstArg(cst); - machine.run(frame, offset, opcode); - } - - /** {@inheritDoc} */ - 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} */ - 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} */ - public void visitNewarray(int offset, int length, CstType type, - ArrayList<Constant> initValues) { - machine.popArgs(frame, Type.INT); - machine.auxInitValues(initValues); - machine.auxCstArg(type); - machine.run(frame, offset, ByteOps.NEWARRAY); - } - - /** {@inheritDoc} */ - public void setPreviousOffset(int offset) { - previousOffset = offset; - } - - /** {@inheritDoc} */ - public int getPreviousOffset() { - return previousOffset; - } - } -} diff --git a/dx/src/com/android/dx/cf/code/SwitchList.java b/dx/src/com/android/dx/cf/code/SwitchList.java deleted file mode 100644 index dc04137fb..000000000 --- a/dx/src/com/android/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.android.dx.cf.code; - -import com.android.dx.util.IntList; -import com.android.dx.util.MutabilityControl; - -/** - * List of (value, target) mappings representing the choices of a - * <code>tableswitch</code> or <code>lookupswitch</code> instruction. It - * also holds the default target for the switch. - */ -public final class SwitchList extends MutabilityControl { - /** non-null; list of test values */ - private final IntList values; - - /** - * 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 >= 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 >= 0; the list size - */ - public int size() { - return size; - } - - /** - * Gets the indicated test value. - * - * @param n >= 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()</code> - * returns the default target. - * - * @param n >= 0, <= size(); which index - * @return >= 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())</code>. - * - * @return >= 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 non-null; the target list - */ - public IntList getTargets() { - return targets; - } - - /** - * Gets the list of all case values. - * - * @return 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 >= 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 >= 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/dx/src/com/android/dx/cf/code/ValueAwareMachine.java b/dx/src/com/android/dx/cf/code/ValueAwareMachine.java deleted file mode 100644 index 4062c3b94..000000000 --- a/dx/src/com/android/dx/cf/code/ValueAwareMachine.java +++ /dev/null @@ -1,198 +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.android.dx.cf.code; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.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 non-null; the prototype for the associated method - */ - public ValueAwareMachine(Prototype prototype) { - super(prototype); - } - - /** {@inheritDoc} */ - 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.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/dx/src/com/android/dx/cf/code/package.html b/dx/src/com/android/dx/cf/code/package.html deleted file mode 100644 index abd4e9bec..000000000 --- a/dx/src/com/android/dx/cf/code/package.html +++ /dev/null @@ -1,10 +0,0 @@ -<body> -<p>Implementation of classes having to do with Java simulation, such as -is needed for verification or stack-to-register conversion.</p> - -<p><b>PACKAGES USED:</b> -<ul> -<li><code>com.android.dx.rop.pool</code></li> -<li><code>com.android.dx.util</code></li> -</ul> -</body> diff --git a/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java b/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java deleted file mode 100644 index 953981c90..000000000 --- a/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java +++ /dev/null @@ -1,335 +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.android.dx.cf.cst; - -import com.android.dx.cf.iface.ParseException; -import com.android.dx.cf.iface.ParseObserver; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstDouble; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstFloat; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstInterfaceMethodRef; -import com.android.dx.rop.cst.CstLong; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.cst.StdConstantPool; -import com.android.dx.rop.type.Type; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; - -import static com.android.dx.cf.cst.ConstantTags.*; - -/** - * Parser for a constant pool embedded in a class file. - */ -public final class ConstantPoolParser { - /** non-null; the bytes of the constant pool */ - private final ByteArray bytes; - - /** non-null; actual parsed constant pool contents */ - private final StdConstantPool pool; - - /** non-null; byte offsets to each cst */ - private final int[] offsets; - - /** - * -1 || >= 10; the end offset of this constant pool in the - * <code>byte[]</code> which it came from or <code>-1</code> if not - * yet parsed - */ - private int endOffset; - - /** null-ok; parse observer, if any */ - private ParseObserver observer; - - /** - * Constructs an instance. - * - * @param bytes 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 null-ok; the observer - */ - public void setObserver(ParseObserver observer) { - this.observer = observer; - } - - /** - * Gets the end offset of this constant pool in the <code>byte[]</code> - * which it came from. - * - * @return >= 10; the end offset - */ - public int getEndOffset() { - parseIfNecessary(); - return endOffset; - } - - /** - * Gets the actual constant pool. - * - * @return 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); - } - - for (int i = 1; i < offsets.length; i++) { - int offset = offsets[i]; - if ((offset != 0) && (pool.getOrNull(i) == null)) { - parse0(i); - } - } - - 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; - } - } - observer.parsed(bytes, offset, nextOffset - offset, - Hex.u2(i) + ": " + cst.toString()); - } - - 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); - 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; - } - default: { - ParseException ex = - new ParseException("unknown tag byte: " + Hex.u1(tag)); - 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 non-null; the parsed constant - */ - private Constant parse0(int idx) { - 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); - 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); - CstUtf8 name = (CstUtf8) parse0(nameIndex); - cst = new CstType(Type.internClassName(name.getString())); - break; - } - case CONSTANT_String: { - int stringIndex = bytes.getUnsignedShort(at + 1); - CstUtf8 string = (CstUtf8) parse0(stringIndex); - cst = new CstString(string); - break; - } - case CONSTANT_Fieldref: { - int classIndex = bytes.getUnsignedShort(at + 1); - CstType type = (CstType) parse0(classIndex); - int natIndex = bytes.getUnsignedShort(at + 3); - CstNat nat = (CstNat) parse0(natIndex); - cst = new CstFieldRef(type, nat); - break; - } - case CONSTANT_Methodref: { - int classIndex = bytes.getUnsignedShort(at + 1); - CstType type = (CstType) parse0(classIndex); - int natIndex = bytes.getUnsignedShort(at + 3); - CstNat nat = (CstNat) parse0(natIndex); - cst = new CstMethodRef(type, nat); - break; - } - case CONSTANT_InterfaceMethodref: { - int classIndex = bytes.getUnsignedShort(at + 1); - CstType type = (CstType) parse0(classIndex); - int natIndex = bytes.getUnsignedShort(at + 3); - CstNat nat = (CstNat) parse0(natIndex); - cst = new CstInterfaceMethodRef(type, nat); - break; - } - case CONSTANT_NameAndType: { - int nameIndex = bytes.getUnsignedShort(at + 1); - CstUtf8 name = (CstUtf8) parse0(nameIndex); - int descriptorIndex = bytes.getUnsignedShort(at + 3); - CstUtf8 descriptor = (CstUtf8) parse0(descriptorIndex); - cst = new CstNat(name, descriptor); - break; - } - } - } 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 non-null; the parsed value - */ - private CstUtf8 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 CstUtf8(ubytes); - } catch (IllegalArgumentException ex) { - // Translate the exception - throw new ParseException(ex); - } - } -} diff --git a/dx/src/com/android/dx/cf/cst/ConstantTags.java b/dx/src/com/android/dx/cf/cst/ConstantTags.java deleted file mode 100644 index 64bc8d874..000000000 --- a/dx/src/com/android/dx/cf/cst/ConstantTags.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.android.dx.cf.cst; - -/** - * Tags for constant pool constants. - */ -public interface ConstantTags { - /** tag for a <code>CONSTANT_Utf8_info</code> */ - int CONSTANT_Utf8 = 1; - - /** tag for a <code>CONSTANT_Integer_info</code> */ - int CONSTANT_Integer = 3; - - /** tag for a <code>CONSTANT_Float_info</code> */ - int CONSTANT_Float = 4; - - /** tag for a <code>CONSTANT_Long_info</code> */ - int CONSTANT_Long = 5; - - /** tag for a <code>CONSTANT_Double_info</code> */ - int CONSTANT_Double = 6; - - /** tag for a <code>CONSTANT_Class_info</code> */ - int CONSTANT_Class = 7; - - /** tag for a <code>CONSTANT_String_info</code> */ - int CONSTANT_String = 8; - - /** tag for a <code>CONSTANT_Fieldref_info</code> */ - int CONSTANT_Fieldref = 9; - - /** tag for a <code>CONSTANT_Methodref_info</code> */ - int CONSTANT_Methodref = 10; - - /** tag for a <code>CONSTANT_InterfaceMethodref_info</code> */ - int CONSTANT_InterfaceMethodref = 11; - - /** tag for a <code>CONSTANT_NameAndType_info</code> */ - int CONSTANT_NameAndType = 12; -} diff --git a/dx/src/com/android/dx/cf/direct/AnnotationParser.java b/dx/src/com/android/dx/cf/direct/AnnotationParser.java deleted file mode 100644 index 5d800869b..000000000 --- a/dx/src/com/android/dx/cf/direct/AnnotationParser.java +++ /dev/null @@ -1,474 +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.android.dx.cf.direct; - -import com.android.dx.cf.iface.ParseException; -import com.android.dx.cf.iface.ParseObserver; -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.AnnotationVisibility; -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.ConstantPool; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstBoolean; -import com.android.dx.rop.cst.CstByte; -import com.android.dx.rop.cst.CstChar; -import com.android.dx.rop.cst.CstDouble; -import com.android.dx.rop.cst.CstEnumRef; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstFloat; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstLong; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstShort; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Type; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; - -import java.io.IOException; - -/** - * Parser for annotations. - */ -public final class AnnotationParser { - /** non-null; class file being parsed */ - private final DirectClassFile cf; - - /** non-null; constant pool to use */ - private final ConstantPool pool; - - /** non-null; bytes of the attribute data */ - private final ByteArray bytes; - - /** null-ok; parse observer, if any */ - private final ParseObserver observer; - - /** non-null; input stream to parse from */ - private final ByteArray.MyDataInputStream input; - - /** - * non-null; cursor for use when informing the observer of what - * was parsed - */ - private int parseCursor; - - /** - * Constructs an instance. - * - * @param cf non-null; class file to parse from - * @param offset >= 0; offset into the class file data to parse at - * @param length >= 0; number of bytes left in the attribute data - * @param observer 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</code>) attribute. - * - * @return 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 non-null; visibility of the parsed annotations - * @return 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 non-null; visibility of the parsed annotations - * @return 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 non-null; visibility of the parsed annotations - * @return 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 non-null; visibility of the parsed annotations - * @return 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 non-null; visibility of the parsed annotation - * @return non-null; the parsed annotation - */ - private Annotation parseAnnotation(AnnotationVisibility visibility) - throws IOException { - requireLength(4); - - int typeIndex = input.readUnsignedShort(); - int numElements = input.readUnsignedShort(); - CstUtf8 typeUtf8 = (CstUtf8) pool.get(typeIndex); - CstType type = new CstType(Type.intern(typeUtf8.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 non-null; the parsed element - */ - private NameValuePair parseElement() throws IOException { - requireLength(5); - - int elementNameIndex = input.readUnsignedShort(); - CstUtf8 elementName = (CstUtf8) 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 non-null; the parsed value - */ - private Constant parseValue() throws IOException { - int tag = input.readUnsignedByte(); - - if (observer != null) { - CstUtf8 humanTag = new CstUtf8(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(); - CstUtf8 value = (CstUtf8) pool.get(classInfoIndex); - Type type = Type.internReturnType(value.getString()); - - if (observer != null) { - parsed(2, "class_info: " + type.toHuman()); - } - - return new CstType(type); - } - case 's': { - CstString value = new CstString((CstUtf8) parseConstant()); - return value; - } - case 'e': { - requireLength(4); - - int typeNameIndex = input.readUnsignedShort(); - int constNameIndex = input.readUnsignedShort(); - CstUtf8 typeName = (CstUtf8) pool.get(typeNameIndex); - CstUtf8 constName = (CstUtf8) 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 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 CstUtf8) - ? ((CstUtf8) 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 >= 0; number of bytes parsed - * @param message 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()</code>. - * - * @param indent the amount to change the indent by - */ - private void changeIndent(int indent) { - observer.changeIndent(indent); - } -} diff --git a/dx/src/com/android/dx/cf/direct/AttributeFactory.java b/dx/src/com/android/dx/cf/direct/AttributeFactory.java deleted file mode 100644 index 420d74175..000000000 --- a/dx/src/com/android/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.android.dx.cf.direct; - -import com.android.dx.cf.attrib.RawAttribute; -import com.android.dx.cf.iface.Attribute; -import com.android.dx.cf.iface.ParseException; -import com.android.dx.cf.iface.ParseObserver; -import com.android.dx.rop.cst.ConstantPool; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.ByteArray; -import com.android.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 non-null; class file to parse from - * @param context context to parse in; one of the <code>CTX_*</code> - * constants - * @param offset offset into <code>dcf</code>'s <code>bytes</code> - * to start parsing at - * @param observer null-ok; parse observer to report to, if any - * @return 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"); - } - - CstUtf8 name = null; - - try { - ByteArray bytes = cf.getBytes(); - ConstantPool pool = cf.getConstantPool(); - int nameIdx = bytes.getUnsignedShort(offset); - int length = bytes.getInt(offset + 2); - - name = (CstUtf8) 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 non-null; class file to parse from - * @param context context to parse in; one of the <code>CTX_*</code> - * constants - * @param name non-null; the attribute name - * @param offset offset into <code>bytes</code> 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 null-ok; parse observer to report to, if any - * @return 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/dx/src/com/android/dx/cf/direct/AttributeListParser.java b/dx/src/com/android/dx/cf/direct/AttributeListParser.java deleted file mode 100644 index 765226565..000000000 --- a/dx/src/com/android/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.android.dx.cf.direct; - -import com.android.dx.cf.iface.Attribute; -import com.android.dx.cf.iface.ParseException; -import com.android.dx.cf.iface.ParseObserver; -import com.android.dx.cf.iface.StdAttributeList; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; - -/** - * Parser for lists of attributes. - */ -final /*package*/ class AttributeListParser { - /** 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; - - /** non-null; attribute factory to use */ - private final AttributeFactory attributeFactory; - - /** non-null; list of parsed attributes */ - private final StdAttributeList list; - - /** >= -1; the end offset of this list in the byte array of the - * classfile, or <code>-1</code> if not yet parsed */ - private int endOffset; - - /** null-ok; parse observer, if any */ - private ParseObserver observer; - - /** - * Constructs an instance. - * - * @param cf non-null; class file to parse from - * @param context attribute parsing context (see {@link AttributeFactory}) - * @param offset offset in <code>bytes</code> to the start of the list - * @param attributeFactory 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 null-ok; the observer - */ - public void setObserver(ParseObserver observer) { - this.observer = observer; - } - - /** - * Gets the end offset of this constant pool in the <code>byte[]</code> - * which it came from. - * - * @return >= 0; the end offset - */ - public int getEndOffset() { - parseIfNecessary(); - return endOffset; - } - - /** - * Gets the parsed list. - * - * @return 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/dx/src/com/android/dx/cf/direct/ClassPathOpener.java b/dx/src/com/android/dx/cf/direct/ClassPathOpener.java deleted file mode 100644 index d30234990..000000000 --- a/dx/src/com/android/dx/cf/direct/ClassPathOpener.java +++ /dev/null @@ -1,251 +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.android.dx.cf.direct; - -import com.android.dx.util.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.util.zip.ZipFile; -import java.util.zip.ZipEntry; -import java.util.Arrays; -import java.util.Comparator; -import java.util.ArrayList; -import java.util.Collections; - -/** - * 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 { - - /** non-null; pathname to start with */ - private final String pathname; - /** 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; - - /** - * Callback interface for <code>ClassOpener</code>. - */ - public interface Consumer { - - /** - * Provides the file name and byte array for a class path element. - * - * @param name non-null; filename of element. May not be a valid - * filesystem path. - * - * @param bytes non-null; file data - * @return true on success. Result is or'd with all other results - * from <code>processFileBytes</code> and returned to the caller - * of <code>process()</code>. - */ - boolean processFileBytes(String name, byte[] bytes); - - /** - * Informs consumer that an exception occurred while processing - * this path element. Processing will continue if possible. - * - * @param ex non-null; exception - */ - void onException(Exception ex); - - /** - * Informs consumer that processing of an archive file has begun. - * - * @param file non-null; archive file being processed - */ - void onProcessArchiveStart(File file); - } - - /** - * Constructs an instance. - * - * @param pathname 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 non-null; callback interface - */ - public ClassPathOpener(String pathname, boolean sort, Consumer consumer) { - this.pathname = pathname; - this.sort = sort; - this.consumer = consumer; - } - - /** - * Processes a path element. - * - * @return the OR of all return values - * from <code>Consumer.processFileBytes()</code>. - */ - public boolean process() { - File file = new File(pathname); - - return processOne(file, true); - } - - /** - * Processes one file. - * - * @param file 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); - } - - byte[] bytes = FileUtils.readFile(file); - return consumer.processFileBytes(path, bytes); - } 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 non-null; first class name - * @param b non-null; second class name - * @return <code>compareTo()</code>-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 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<File>() { - 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>, - * <code>.jar</code>, or <code>.apk</code>). - * - * @param file 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); - ByteArrayOutputStream baos = new ByteArrayOutputStream(40000); - byte[] buf = new byte[20000]; - boolean any = false; - - ArrayList<? extends java.util.zip.ZipEntry> entriesList - = Collections.list(zip.entries()); - - if (sort) { - Collections.sort(entriesList, new Comparator<ZipEntry>() { - public int compare (ZipEntry a, ZipEntry b) { - return compareClassNames(a.getName(), b.getName()); - } - }); - } - - consumer.onProcessArchiveStart(file); - - for (ZipEntry one: entriesList) { - - if (one.isDirectory()) { - continue; - } - - String path = one.getName(); - InputStream in = zip.getInputStream(one); - - baos.reset(); - for (;;) { - int amt = in.read(buf); - if (amt < 0) { - break; - } - - baos.write(buf, 0, amt); - } - - in.close(); - - byte[] bytes = baos.toByteArray(); - any |= consumer.processFileBytes(path, bytes); - } - - zip.close(); - return any; - } -} diff --git a/dx/src/com/android/dx/cf/direct/CodeObserver.java b/dx/src/com/android/dx/cf/direct/CodeObserver.java deleted file mode 100644 index 950147fdb..000000000 --- a/dx/src/com/android/dx/cf/direct/CodeObserver.java +++ /dev/null @@ -1,306 +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.android.dx.cf.direct; - -import com.android.dx.cf.code.ByteOps; -import com.android.dx.cf.code.BytecodeArray; -import com.android.dx.cf.code.SwitchList; -import com.android.dx.cf.iface.ParseObserver; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstDouble; -import com.android.dx.rop.cst.CstFloat; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstKnownNull; -import com.android.dx.rop.cst.CstLong; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; - -import java.util.List; -import java.util.ArrayList; - -/** - * Bytecode visitor to use when "observing" bytecode getting parsed. - */ -public class CodeObserver implements BytecodeArray.Visitor { - /** non-null; actual array of bytecode */ - private final ByteArray bytes; - - /** non-null; observer to inform of parsing */ - private final ParseObserver observer; - - /** - * Constructs an instance. - * - * @param bytes non-null; actual array of bytecode - * @param observer 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} */ - public void visitInvalid(int opcode, int offset, int length) { - observer.parsed(bytes, offset, length, header(offset)); - } - - /** {@inheritDoc} */ - public void visitNoArgs(int opcode, int offset, int length, Type type) { - observer.parsed(bytes, offset, length, header(offset)); - } - - /** {@inheritDoc} */ - 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} */ - 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} */ - 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} */ - public void visitSwitch(int opcode, int offset, int length, - SwitchList cases, int padding) { - int sz = cases.size(); - StringBuffer sb = new StringBuffer(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} */ - public void visitNewarray(int offset, int length, CstType cst, - ArrayList<Constant> intVals) { - String commentOrSpace = (length == 1) ? " // " : " "; - String typeName = cst.getClassType().getComponentType().toHuman(); - - observer.parsed(bytes, offset, length, - header(offset) + commentOrSpace + typeName); - } - - /** {@inheritDoc} */ - public void setPreviousOffset(int offset) { - // Do nothing - } - - /** {@inheritDoc} */ - 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 {code #visitConstant} where the constant is an - * <code>int</code>. - * - * @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 {code #visitConstant} where the constant is a - * <code>long</code>. - * - * @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 {code #visitConstant} where the constant is a - * <code>float</code>. - * - * @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 {code #visitConstant} where the constant is a - * <code>double</code>. - * - * @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/dx/src/com/android/dx/cf/direct/DirectClassFile.java b/dx/src/com/android/dx/cf/direct/DirectClassFile.java deleted file mode 100644 index e4751a4cc..000000000 --- a/dx/src/com/android/dx/cf/direct/DirectClassFile.java +++ /dev/null @@ -1,633 +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.android.dx.cf.direct; - -import com.android.dx.cf.attrib.AttSourceFile; -import com.android.dx.cf.cst.ConstantPoolParser; -import com.android.dx.cf.iface.Attribute; -import com.android.dx.cf.iface.AttributeList; -import com.android.dx.cf.iface.ClassFile; -import com.android.dx.cf.iface.FieldList; -import com.android.dx.cf.iface.MethodList; -import com.android.dx.cf.iface.ParseException; -import com.android.dx.cf.iface.ParseObserver; -import com.android.dx.cf.iface.StdAttributeList; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.ConstantPool; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.cst.StdConstantPool; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; - -/** - * Class file with info taken from a <code>byte[]</code> 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</code> file major version - * - * The class file definition (vmspec/2nd-edition) says: - * - * "Implementations of version 1.2 of the - * Java 2 platform can support class file - * formats of versions in the range 45.0 - * through 46.0 inclusive." - * - * The class files generated by the build are currently - * (as of 11/2006) reporting version 49.0 (0x31.0x00), - * however, so we use that as our upper bound. - * - * 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</code> file major version */ - private static final int CLASS_FILE_MAX_MAJOR_VERSION = 50; - - /** maximum <code>.class</code> file minor version */ - private static final int CLASS_FILE_MAX_MINOR_VERSION = 0; - - /** - * non-null; the file path for the class, excluding any base directory - * specification - */ - private final String filePath; - - /** non-null; the bytes of the file */ - private final ByteArray bytes; - - /** - * whether to be strict about parsing; if - * <code>false</code>, 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; - - /** - * null-ok; the constant pool; only ever <code>null</code> - * before the constant pool is successfully parsed - */ - private StdConstantPool pool; - - /** - * the class file field <code>access_flags</code>; will be <code>-1</code> - * before the file is successfully parsed - */ - private int accessFlags; - - /** - * null-ok; the class file field <code>this_class</code>, - * interpreted as a type constant; only ever <code>null</code> - * before the file is successfully parsed - */ - private CstType thisClass; - - /** - * null-ok; the class file field <code>super_class</code>, interpreted - * as a type constant if non-zero - */ - private CstType superClass; - - /** - * null-ok; the class file field <code>interfaces</code>; only - * ever <code>null</code> before the file is successfully - * parsed - */ - private TypeList interfaces; - - /** - * null-ok; the class file field <code>fields</code>; only ever - * <code>null</code> before the file is successfully parsed - */ - private FieldList fields; - - /** - * null-ok; the class file field <code>methods</code>; only ever - * <code>null</code> before the file is successfully parsed - */ - private MethodList methods; - - /** - * null-ok; the class file field <code>attributes</code>; only - * ever <code>null</code> before the file is successfully - * parsed - */ - private StdAttributeList attributes; - - /** null-ok; attribute factory, if any */ - private AttributeFactory attributeFactory; - - /** null-ok; parse observer, if any */ - private ParseObserver observer; - - /** - * Returns the string form of an object or <code>"(none)"</code> - * (rather than <code>"null"</code>) for <code>null</code>. - * - * @param obj null-ok; the object to stringify - * @return 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 non-null; the bytes of the file - * @param filePath non-null; the file path for the class, - * excluding any base directory specification - * @param strictParse whether to be strict about parsing; if - * <code>false</code>, 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 non-null; the bytes of the file - * @param filePath non-null; the file path for the class, - * excluding any base directory specification - * @param strictParse whether to be strict about parsing; if - * <code>false</code>, 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 null-ok; the observer - */ - public void setObserver(ParseObserver observer) { - this.observer = observer; - } - - /** - * Sets the attribute factory to use. - * - * @param attributeFactory non-null; the attribute factory - */ - public void setAttributeFactory(AttributeFactory attributeFactory) { - if (attributeFactory == null) { - throw new NullPointerException("attributeFactory == null"); - } - - this.attributeFactory = attributeFactory; - } - - /** - * Gets the {@link ByteArray} that this instance's data comes from. - * - * @return non-null; the bytes - */ - public ByteArray getBytes() { - return bytes; - } - - /** {@inheritDoc} */ - public int getMagic() { - parseToInterfacesIfNecessary(); - return getMagic0(); - } - - /** {@inheritDoc} */ - public int getMinorVersion() { - parseToInterfacesIfNecessary(); - return getMinorVersion0(); - } - - /** {@inheritDoc} */ - public int getMajorVersion() { - parseToInterfacesIfNecessary(); - return getMajorVersion0(); - } - - /** {@inheritDoc} */ - public int getAccessFlags() { - parseToInterfacesIfNecessary(); - return accessFlags; - } - - /** {@inheritDoc} */ - public CstType getThisClass() { - parseToInterfacesIfNecessary(); - return thisClass; - } - - /** {@inheritDoc} */ - public CstType getSuperclass() { - parseToInterfacesIfNecessary(); - return superClass; - } - - /** {@inheritDoc} */ - public ConstantPool getConstantPool() { - parseToInterfacesIfNecessary(); - return pool; - } - - /** {@inheritDoc} */ - public TypeList getInterfaces() { - parseToInterfacesIfNecessary(); - return interfaces; - } - - /** {@inheritDoc} */ - public FieldList getFields() { - parseToEndIfNecessary(); - return fields; - } - - /** {@inheritDoc} */ - public MethodList getMethods() { - parseToEndIfNecessary(); - return methods; - } - - /** {@inheritDoc} */ - public AttributeList getAttributes() { - parseToEndIfNecessary(); - return attributes; - } - - /** {@inheritDoc} */ - public CstUtf8 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</code>. - * - * @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 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</code>, 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</code>, 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</code>, 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/version are within - * range. - * - * @param magic the value of a classfile "magic" field - * @param minorVersion the value of a classfile "minor_version" field - * @param majorVersion the value of a classfile "major_version" field - * @return true iff the parameters are valid and within range - */ - private boolean isGoodVersion(int magic, 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 (magic == CLASS_FILE_MAGIC && 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 (!isGoodVersion(getMagic0(), getMinorVersion0(), - getMajorVersion0())) { - throw new ParseException("bad class file magic (" + - Hex.u4(getMagic0()) + - ") or version (" + - Hex.u2(getMajorVersion0()) + "." + - Hex.u2(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</code>. - */ - private static class DcfTypeList implements TypeList { - /** non-null; array containing the data */ - private final ByteArray bytes; - - /** number of elements in the list (not number of bytes) */ - private final int size; - - /** non-null; the constant pool */ - private final StdConstantPool pool; - - /** - * Constructs an instance. - * - * @param bytes 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 non-null; the constant pool to use - * @param observer 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} */ - public boolean isMutable() { - return false; - } - - /** {@inheritDoc} */ - public int size() { - return size; - } - - /** {@inheritDoc} */ - public int getWordCount() { - // It is the same as size because all elements are classes. - return size; - } - - /** {@inheritDoc} */ - public Type getType(int n) { - int idx = bytes.getUnsignedShort(n * 2); - return ((CstType) pool.get(idx)).getClassType(); - } - - /** {@inheritDoc} */ - public TypeList withAddedType(Type type) { - throw new UnsupportedOperationException("unsupported"); - } - } -} diff --git a/dx/src/com/android/dx/cf/direct/FieldListParser.java b/dx/src/com/android/dx/cf/direct/FieldListParser.java deleted file mode 100644 index 06dcc4127..000000000 --- a/dx/src/com/android/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.android.dx.cf.direct; - -import com.android.dx.cf.iface.AttributeList; -import com.android.dx.cf.iface.Member; -import com.android.dx.cf.iface.StdField; -import com.android.dx.cf.iface.StdFieldList; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; - -/** - * Parser for lists of fields in a class file. - */ -final /*package*/ class FieldListParser extends MemberListParser { - /** non-null; list in progress */ - private final StdFieldList fields; - - /** - * Constructs an instance. - * - * @param cf non-null; the class file to parse from - * @param definer non-null; class being defined - * @param offset offset in <code>bytes</code> to the start of the list - * @param attributeFactory 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 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/dx/src/com/android/dx/cf/direct/MemberListParser.java b/dx/src/com/android/dx/cf/direct/MemberListParser.java deleted file mode 100644 index 3c0bfa837..000000000 --- a/dx/src/com/android/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.android.dx.cf.direct; - -import com.android.dx.cf.iface.AttributeList; -import com.android.dx.cf.iface.Member; -import com.android.dx.cf.iface.ParseException; -import com.android.dx.cf.iface.ParseObserver; -import com.android.dx.cf.iface.StdAttributeList; -import com.android.dx.rop.cst.ConstantPool; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; - -/** - * Parser for lists of class file members (that is, fields and methods). - */ -abstract /*package*/ class MemberListParser { - /** non-null; the class file to parse from */ - private final DirectClassFile cf; - - /** 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; - - /** non-null; attribute factory to use */ - private final AttributeFactory attributeFactory; - - /** >= -1; the end offset of this list in the byte array of the - * classfile, or <code>-1</code> if not yet parsed */ - private int endOffset; - - /** null-ok; parse observer, if any */ - private ParseObserver observer; - - /** - * Constructs an instance. - * - * @param cf non-null; the class file to parse from - * @param definer non-null; class being defined - * @param offset offset in <code>bytes</code> to the start of the list - * @param attributeFactory 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[]</code> - * which it came from. - * - * @return >= 0; the end offset - */ - public int getEndOffset() { - parseIfNecessary(); - return endOffset; - } - - /** - * Sets the parse observer for this instance. - * - * @param observer 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 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 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 non-null; the string form - */ - protected abstract String humanAccessFlags(int accessFlags); - - /** - * Gets the <code>CTX_*</code> constant to use when parsing attributes. - * Subclasses must override this method. - * - * @return 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</code> - * @param nat the interpreted name and type (based on the two - * <code>*_index</code> fields) - * @param attributes list of parsed attributes - * @return 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); - CstUtf8 name = (CstUtf8) pool.get(nameIdx); - CstUtf8 desc = (CstUtf8) 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/dx/src/com/android/dx/cf/direct/MethodListParser.java b/dx/src/com/android/dx/cf/direct/MethodListParser.java deleted file mode 100644 index 9ca8ba6b8..000000000 --- a/dx/src/com/android/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.android.dx.cf.direct; - -import com.android.dx.cf.iface.AttributeList; -import com.android.dx.cf.iface.Member; -import com.android.dx.cf.iface.StdMethod; -import com.android.dx.cf.iface.StdMethodList; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; - -/** - * Parser for lists of methods in a class file. - */ -final /*package*/ class MethodListParser extends MemberListParser { - /** non-null; list in progress */ - final private StdMethodList methods; - - /** - * Constructs an instance. - * - * @param cf non-null; the class file to parse from - * @param definer non-null; class being defined - * @param offset offset in <code>bytes</code> to the start of the list - * @param attributeFactory 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 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/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java b/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java deleted file mode 100644 index ab0e2f7fd..000000000 --- a/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java +++ /dev/null @@ -1,764 +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.android.dx.cf.direct; - -import com.android.dx.cf.attrib.AttAnnotationDefault; -import com.android.dx.cf.attrib.AttCode; -import com.android.dx.cf.attrib.AttConstantValue; -import com.android.dx.cf.attrib.AttDeprecated; -import com.android.dx.cf.attrib.AttEnclosingMethod; -import com.android.dx.cf.attrib.AttExceptions; -import com.android.dx.cf.attrib.AttInnerClasses; -import com.android.dx.cf.attrib.AttLineNumberTable; -import com.android.dx.cf.attrib.AttLocalVariableTable; -import com.android.dx.cf.attrib.AttLocalVariableTypeTable; -import com.android.dx.cf.attrib.AttRuntimeInvisibleAnnotations; -import com.android.dx.cf.attrib.AttRuntimeInvisibleParameterAnnotations; -import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations; -import com.android.dx.cf.attrib.AttRuntimeVisibleParameterAnnotations; -import com.android.dx.cf.attrib.AttSignature; -import com.android.dx.cf.attrib.AttSourceFile; -import com.android.dx.cf.attrib.AttSynthetic; -import com.android.dx.cf.attrib.InnerClassList; -import com.android.dx.cf.code.ByteCatchList; -import com.android.dx.cf.code.BytecodeArray; -import com.android.dx.cf.code.LineNumberList; -import com.android.dx.cf.code.LocalVariableList; -import com.android.dx.cf.iface.Attribute; -import com.android.dx.cf.iface.ParseException; -import com.android.dx.cf.iface.ParseObserver; -import com.android.dx.cf.iface.StdAttributeList; -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.AnnotationVisibility; -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.ConstantPool; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.cst.TypedConstant; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.ByteArray; -import com.android.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 { - /** 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 == 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 == 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</code> 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>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) ? "<any>" : - 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</code> 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</code> 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</code> 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</code> 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</code> 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); - CstUtf8 name = (CstUtf8) 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</code> 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</code> 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</code> 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</code> - * or a <code>LocalVariableTypeTable</code>. - * - * @param bytes non-null; bytes to parse, which should <i>only</i> - * contain the table data (no header) - * @param pool non-null; constant pool to use - * @param count >= 0; the number of entries - * @param typeTable <code>true</code> iff this is for a type table - * @return 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(); - CstUtf8 name = (CstUtf8) pool.get(nameIdx); - CstUtf8 type = (CstUtf8) pool.get(typeIdx); - CstUtf8 descriptor = null; - CstUtf8 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</code> 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</code> 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</code> 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</code> 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</code> 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); - CstUtf8 cst = (CstUtf8) pool.get(idx); - Attribute result = new AttSignature(cst); - - if (observer != null) { - observer.parsed(bytes, offset, 2, "signature: " + cst); - } - - return result; - } - - /** - * Parses a <code>SourceFile</code> 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); - CstUtf8 cst = (CstUtf8) pool.get(idx); - Attribute result = new AttSourceFile(cst); - - if (observer != null) { - observer.parsed(bytes, offset, 2, "source: " + cst); - } - - return result; - } - - /** - * Parses a <code>Synthetic</code> 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)); - } -} diff --git a/dx/src/com/android/dx/cf/direct/package.html b/dx/src/com/android/dx/cf/direct/package.html deleted file mode 100644 index 2a4619843..000000000 --- a/dx/src/com/android/dx/cf/direct/package.html +++ /dev/null @@ -1,12 +0,0 @@ -<body> -<p>Implementation of <code>cf.iface.*</code> based on a direct representation -of class files as <code>byte[]</code>s.</p> - -<p><b>PACKAGES USED:</b> -<ul> -<li><code>com.android.dx.cf.attrib</code></li> -<li><code>com.android.dx.cf.iface</code></li> -<li><code>com.android.dx.rop.pool</code></li> -<li><code>com.android.dx.util</code></li> -</ul> -</body> diff --git a/dx/src/com/android/dx/cf/iface/Attribute.java b/dx/src/com/android/dx/cf/iface/Attribute.java deleted file mode 100644 index f28f51e24..000000000 --- a/dx/src/com/android/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.android.dx.cf.iface; - -/** - * Interface representing attributes of class files (directly or indirectly). - */ -public interface Attribute { - /** - * Get the name of the attribute. - * - * @return 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</code>. - * - * @return >= 6; the total length, in bytes - */ - public int byteLength(); -} diff --git a/dx/src/com/android/dx/cf/iface/AttributeList.java b/dx/src/com/android/dx/cf/iface/AttributeList.java deleted file mode 100644 index a72965abd..000000000 --- a/dx/src/com/android/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.android.dx.cf.iface; - -/** - * Interface for lists of attributes. - */ -public interface AttributeList { - /** - * Get whether this instance is mutable. Note that the - * <code>AttributeList</code> 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</code> 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</code>th attribute. - * - * @param n <code>n >= 0, n < size()</code>; which attribute - * @return 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</code> length indicator. - * - * @return >= 2; the total length, in bytes - */ - public int byteLength(); - - /** - * Get the first attribute in the list with the given name, if any. - * - * @param name non-null; attribute name - * @return null-ok; first attribute in the list with the given name, - * or <code>null</code> 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 non-null; attribute to start looking after - * @return null-ok; next attribute after <code>attrib</code> with the - * same name as <code>attrib</code> - */ - public Attribute findNext(Attribute attrib); -} diff --git a/dx/src/com/android/dx/cf/iface/ClassFile.java b/dx/src/com/android/dx/cf/iface/ClassFile.java deleted file mode 100644 index 36a5f7415..000000000 --- a/dx/src/com/android/dx/cf/iface/ClassFile.java +++ /dev/null @@ -1,123 +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.android.dx.cf.iface; - -import com.android.dx.rop.cst.ConstantPool; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.TypeList; - -/** - * Interface for things which purport to be class files or reasonable - * facsimiles thereof. - * - * <p><b>Note:</b> The fields referred to in this documentation are of the - * <code>ClassFile</code> structure defined in vmspec-2 sec4.1. - */ -public interface ClassFile { - /** - * Gets the field <code>magic</code>. - * - * @return the value in question - */ - public int getMagic(); - - /** - * Gets the field <code>minor_version</code>. - * - * @return the value in question - */ - public int getMinorVersion(); - - /** - * Gets the field <code>major_version</code>. - * - * @return the value in question - */ - public int getMajorVersion(); - - /** - * Gets the field <code>access_flags</code>. - * - * @return the value in question - */ - public int getAccessFlags(); - - /** - * Gets the field <code>this_class</code>, interpreted as a type constant. - * - * @return non-null; the value in question - */ - public CstType getThisClass(); - - /** - * Gets the field <code>super_class</code>, interpreted as a type constant - * if non-zero. - * - * @return null-ok; the value in question - */ - public CstType getSuperclass(); - - /** - * Gets the field <code>constant_pool</code> (along with - * <code>constant_pool_count</code>). - * - * @return non-null; the constant pool - */ - public ConstantPool getConstantPool(); - - /** - * Gets the field <code>interfaces<code> (along with - * interfaces_count</code>). - * - * @return non-null; the list of interfaces - */ - public TypeList getInterfaces(); - - /** - * Gets the field <code>fields</code> (along with - * <code>fields_count</code>). - * - * @return non-null; the list of fields - */ - public FieldList getFields(); - - /** - * Gets the field <code>methods</code> (along with - * <code>methods_count</code>). - * - * @return non-null; the list of fields - */ - public MethodList getMethods(); - - /** - * Gets the field <code>attributes</code> (along with - * <code>attributes_count</code>). - * - * @return non-null; the list of attributes - */ - public AttributeList getAttributes(); - - /** - * Gets the name out of the <code>SourceFile</code> attribute of this - * file, if any. This is a convenient shorthand for scrounging around - * the class's attributes. - * - * @return non-null; the constant pool - */ - public CstUtf8 getSourceFile(); -} diff --git a/dx/src/com/android/dx/cf/iface/Field.java b/dx/src/com/android/dx/cf/iface/Field.java deleted file mode 100644 index d1694fc32..000000000 --- a/dx/src/com/android/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.android.dx.cf.iface; - -import com.android.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</code> for a <code>static final</code> field which - * includes a <code>ConstantValue</code> attribute. - * - * @return null-ok; the constant value, or <code>null</code> if this - * field isn't a constant - */ - public TypedConstant getConstantValue(); -} diff --git a/dx/src/com/android/dx/cf/iface/FieldList.java b/dx/src/com/android/dx/cf/iface/FieldList.java deleted file mode 100644 index 80a794fdb..000000000 --- a/dx/src/com/android/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.android.dx.cf.iface; - -/** - * Interface for lists of fields. - */ -public interface FieldList -{ - /** - * Get whether this instance is mutable. Note that the - * <code>FieldList</code> 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</code> 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</code>th field. - * - * @param n <code>n >= 0, n < size()</code>; which field - * @return non-null; the field in question - */ - public Field get(int n); -} diff --git a/dx/src/com/android/dx/cf/iface/Member.java b/dx/src/com/android/dx/cf/iface/Member.java deleted file mode 100644 index b305e09b6..000000000 --- a/dx/src/com/android/dx/cf/iface/Member.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.android.dx.cf.iface; - -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; - -/** - * Interface representing members of class files (that is, fields and methods). - */ -public interface Member { - /** - * Get the defining class. - * - * @return non-null; the defining class - */ - public CstType getDefiningClass(); - - /** - * Get the field <code>access_flags</code>. - * - * @return the access flags - */ - public int getAccessFlags(); - - /** - * Get the field <code>name_index</code> of the member. This is - * just a convenient shorthand for <code>getNat().getName()</code>. - * - * @return non-null; the name - */ - public CstUtf8 getName(); - - /** - * Get the field <code>descriptor_index</code> of the member. This is - * just a convenient shorthand for <code>getNat().getDescriptor()</code>. - * - * @return non-null; the descriptor - */ - public CstUtf8 getDescriptor(); - - /** - * Get the name and type associated with this member. This is a - * combination of the fields <code>name_index</code> and - * <code>descriptor_index</code> in the original classfile, interpreted - * via the constant pool. - * - * @return non-null; the name and type - */ - public CstNat getNat(); - - /** - * Get the field <code>attributes</code> (along with - * <code>attributes_count</code>). - * - * @return non-null; the constant pool - */ - public AttributeList getAttributes(); -} diff --git a/dx/src/com/android/dx/cf/iface/Method.java b/dx/src/com/android/dx/cf/iface/Method.java deleted file mode 100644 index 424400a2b..000000000 --- a/dx/src/com/android/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.android.dx.cf.iface; - -import com.android.dx.rop.type.Prototype; - -/** - * Interface representing methods of class files. - */ -public interface Method - extends Member -{ - /** - * Get the <i>effective</i> method descriptor, which includes, if - * necessary, a first <code>this</code> parameter. - * - * @return non-null; the effective method descriptor - */ - public Prototype getEffectiveDescriptor(); -} diff --git a/dx/src/com/android/dx/cf/iface/MethodList.java b/dx/src/com/android/dx/cf/iface/MethodList.java deleted file mode 100644 index a7a395cbe..000000000 --- a/dx/src/com/android/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.android.dx.cf.iface; - -/** - * Interface for lists of methods. - */ -public interface MethodList { - /** - * Get whether this instance is mutable. Note that the - * <code>MethodList</code> 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</code> 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</code>th method. - * - * @param n <code>n >= 0, n < size()</code>; which method - * @return non-null; the method in question - */ - public Method get(int n); -} diff --git a/dx/src/com/android/dx/cf/iface/ParseException.java b/dx/src/com/android/dx/cf/iface/ParseException.java deleted file mode 100644 index 18a9d0e24..000000000 --- a/dx/src/com/android/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.android.dx.cf.iface; - -import com.android.dx.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/dx/src/com/android/dx/cf/iface/ParseObserver.java b/dx/src/com/android/dx/cf/iface/ParseObserver.java deleted file mode 100644 index 2ad3493c6..000000000 --- a/dx/src/com/android/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.android.dx.cf.iface; - -import com.android.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 non-null; the source that is being parsed - * @param offset offset into <code>bytes</code> for the start of the - * member - * @param name non-null; name of the member - * @param descriptor 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 non-null; the source that was parsed - * @param offset offset into <code>bytes</code> for the end of the - * member - * @param name non-null; name of the member - * @param descriptor non-null; descriptor of the member - * @param member 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 non-null; the source that was parsed - * @param offset offset into <code>bytes</code> for what was parsed - * @param len number of bytes parsed - * @param human non-null; human form for what was parsed - */ - public void parsed(ByteArray bytes, int offset, int len, String human); -} diff --git a/dx/src/com/android/dx/cf/iface/StdAttributeList.java b/dx/src/com/android/dx/cf/iface/StdAttributeList.java deleted file mode 100644 index c29bb08d0..000000000 --- a/dx/src/com/android/dx/cf/iface/StdAttributeList.java +++ /dev/null @@ -1,104 +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.android.dx.cf.iface; - -import com.android.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</code>. - * - * @param size the size of the list - */ - public StdAttributeList(int size) { - super(size); - } - - /** {@inheritDoc} */ - public Attribute get(int n) { - return (Attribute) get0(n); - } - - /** {@inheritDoc} */ - 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} */ - 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} */ - 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 >= 0, < size(); which attribute - * @param attribute null-ok; the attribute object - */ - public void set(int n, Attribute attribute) { - set0(n, attribute); - } -} diff --git a/dx/src/com/android/dx/cf/iface/StdField.java b/dx/src/com/android/dx/cf/iface/StdField.java deleted file mode 100644 index 3551aee69..000000000 --- a/dx/src/com/android/dx/cf/iface/StdField.java +++ /dev/null @@ -1,54 +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.android.dx.cf.iface; - -import com.android.dx.cf.attrib.AttConstantValue; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; -import com.android.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 non-null; the defining class - * @param accessFlags access flags - * @param nat non-null; member name and type (descriptor) - * @param attributes non-null; list of associated attributes - */ - public StdField(CstType definingClass, int accessFlags, CstNat nat, - AttributeList attributes) { - super(definingClass, accessFlags, nat, attributes); - } - - /** {@inheritDoc} */ - 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/dx/src/com/android/dx/cf/iface/StdFieldList.java b/dx/src/com/android/dx/cf/iface/StdFieldList.java deleted file mode 100644 index 0f8654b20..000000000 --- a/dx/src/com/android/dx/cf/iface/StdFieldList.java +++ /dev/null @@ -1,49 +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.android.dx.cf.iface; - -import com.android.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</code>. - * - * @param size the size of the list - */ - public StdFieldList(int size) { - super(size); - } - - /** {@inheritDoc} */ - public Field get(int n) { - return (Field) get0(n); - } - - /** - * Sets the field at the given index. - * - * @param n >= 0, < size(); which field - * @param field null-ok; the field object - */ - public void set(int n, Field field) { - set0(n, field); - } -} diff --git a/dx/src/com/android/dx/cf/iface/StdMember.java b/dx/src/com/android/dx/cf/iface/StdMember.java deleted file mode 100644 index eaf949ef0..000000000 --- a/dx/src/com/android/dx/cf/iface/StdMember.java +++ /dev/null @@ -1,110 +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.android.dx.cf.iface; - -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; - -/** - * Standard implementation of {@link Member}, which directly stores - * all the associated data. - */ -public abstract class StdMember implements Member { - /** non-null; the defining class */ - private final CstType definingClass; - - /** access flags */ - private final int accessFlags; - - /** non-null; member name and type */ - private final CstNat nat; - - /** non-null; list of associated attributes */ - private final AttributeList attributes; - - /** - * Constructs an instance. - * - * @param definingClass non-null; the defining class - * @param accessFlags access flags - * @param nat non-null; member name and type (descriptor) - * @param attributes 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() { - StringBuffer sb = new StringBuffer(100); - - sb.append(getClass().getName()); - sb.append('{'); - sb.append(nat.toHuman()); - sb.append('}'); - - return sb.toString(); - } - - /** {@inheritDoc} */ - public final CstType getDefiningClass() { - return definingClass; - } - - /** {@inheritDoc} */ - public final int getAccessFlags() { - return accessFlags; - } - - /** {@inheritDoc} */ - public final CstNat getNat() { - return nat; - } - - /** {@inheritDoc} */ - public final CstUtf8 getName() { - return nat.getName(); - } - - /** {@inheritDoc} */ - public final CstUtf8 getDescriptor() { - return nat.getDescriptor(); - } - - /** {@inheritDoc} */ - public final AttributeList getAttributes() { - return attributes; - } -} diff --git a/dx/src/com/android/dx/cf/iface/StdMethod.java b/dx/src/com/android/dx/cf/iface/StdMethod.java deleted file mode 100644 index a4acbaa7f..000000000 --- a/dx/src/com/android/dx/cf/iface/StdMethod.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.android.dx.cf.iface; - -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Prototype; - -/** - * Standard implementation of {@link Method}, which directly stores - * all the associated data. - */ -public final class StdMethod extends StdMember implements Method { - /** non-null; the effective method descriptor */ - private final Prototype effectiveDescriptor; - - /** - * Constructs an instance. - * - * @param definingClass non-null; the defining class - * @param accessFlags access flags - * @param nat non-null; member name and type (descriptor) - * @param attributes 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} */ - public Prototype getEffectiveDescriptor() { - return effectiveDescriptor; - } -} diff --git a/dx/src/com/android/dx/cf/iface/StdMethodList.java b/dx/src/com/android/dx/cf/iface/StdMethodList.java deleted file mode 100644 index ef0ff3153..000000000 --- a/dx/src/com/android/dx/cf/iface/StdMethodList.java +++ /dev/null @@ -1,49 +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.android.dx.cf.iface; - -import com.android.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</code>. - * - * @param size the size of the list - */ - public StdMethodList(int size) { - super(size); - } - - /** {@inheritDoc} */ - public Method get(int n) { - return (Method) get0(n); - } - - /** - * Sets the method at the given index. - * - * @param n >= 0, < size(); which method - * @param method null-ok; the method object - */ - public void set(int n, Method method) { - set0(n, method); - } -} diff --git a/dx/src/com/android/dx/cf/iface/package.html b/dx/src/com/android/dx/cf/iface/package.html deleted file mode 100644 index c7345527d..000000000 --- a/dx/src/com/android/dx/cf/iface/package.html +++ /dev/null @@ -1,10 +0,0 @@ -<body> -<p>Interfaces and base classes for dealing with class files. This package -doesn't have any parsing but does have basic container implementations.</p> - -<p><b>PACKAGES USED:</b> -<ul> -<li><code>com.android.dx.rop.pool</code></li> -<li><code>com.android.dx.util</code></li> -</ul> -</body> diff --git a/dx/src/com/android/dx/command/DxConsole.java b/dx/src/com/android/dx/command/DxConsole.java deleted file mode 100644 index 982e6593c..000000000 --- a/dx/src/com/android/dx/command/DxConsole.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.android.dx.command; - -import java.io.PrintStream; - -/** - * Provides standard and error PrintStream object to output information.<br> - * By default the PrintStream objects link to <code>System.out</code> and - * <code>System.err</code> but they can be changed to link to other - * PrintStream. - */ -public class DxConsole { - /** - * Standard output stream. Links to <code>System.out</code> by default. - */ - public static PrintStream out = System.out; - - /** - * Error output stream. Links to <code>System.err</code> by default. - */ - public static PrintStream err = System.err; -} diff --git a/dx/src/com/android/dx/command/Main.java b/dx/src/com/android/dx/command/Main.java deleted file mode 100644 index 17f5db386..000000000 --- a/dx/src/com/android/dx/command/Main.java +++ /dev/null @@ -1,170 +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.android.dx.command; - -import com.android.dx.Version; - -import junit.textui.TestRunner; - -/** - * Main class for dx. It recognizes enough options to be able to dispatch - * to the right "actual" main. - */ -public class Main { - private static String USAGE_MESSAGE = - "usage:\n" + - " dx --dex [--debug] [--verbose] [--positions=<style>] " + - "[--no-locals]\n" + - " [--no-optimize] [--statistics] [--[no-]optimize-list=<file>] " + - "[--no-strict]\n" + - " [--keep-classes] [--output=<file>] [--dump-to=<file>] " + - "[--dump-width=<n>]\n" + - " [--dump-method=<name>[*]] [--verbose-dump] [--no-files] " + - "[--core-library]\n" + - " [<file>.class | <file>.{zip,jar,apk} | <directory>] ...\n" + - " Convert a set of classfiles into a dex file, optionally " + - "embedded in a\n" + - " jar/zip. Output name must end with one of: .dex .jar " + - ".zip .apk. Positions\n" + - " options: none, important, lines.\n" + - " dx --annotool --annotation=<class> [--element=<element types>]\n" + - " [--print=<print types>]\n" + - " dx --dump [--debug] [--strict] [--bytes] [--basic-blocks | " + - "--rop-blocks]\n" + - " [--width=<n>] [<file>.class | <file>.txt] ...\n" + - " Dump classfiles in a human-oriented format.\n" + - " dx --junit [-wait] <TestClass>\n" + - " Run the indicated unit test.\n" + - " dx -J<option> ... <arguments, in one of the above " + - "forms>\n" + - " Pass VM-specific options to the virtual machine that " + - "runs dx.\n" + - " dx --version\n" + - " Print the version of this tool (" + Version.VERSION + - ").\n" + - " dx --help\n" + - " Print this message."; - - /** - * This class is uninstantiable. - */ - private Main() { - // This space intentionally left blank. - } - - /** - * Run! - */ - public static void main(String[] args) { - boolean gotCmd = false; - boolean showUsage = false; - - try { - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - if (arg.equals("--") || !arg.startsWith("--")) { - gotCmd = false; - showUsage = true; - break; - } - - gotCmd = true; - if (arg.equals("--dex")) { - com.android.dx.command.dexer.Main.main(without(args, i)); - break; - } else if (arg.equals("--dump")) { - com.android.dx.command.dump.Main.main(without(args, i)); - break; - } else if (arg.equals("--annotool")) { - com.android.dx.command.annotool.Main.main( - without(args, i)); - break; - } else if (arg.equals("--junit")) { - TestRunner.main(without(args, i)); - break; - } else if (arg.equals("--version")) { - version(); - break; - } else if (arg.equals("--help")) { - showUsage = true; - break; - } else { - gotCmd = false; - } - } - } catch (UsageException ex) { - showUsage = true; - } catch (RuntimeException ex) { - System.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:"); - ex.printStackTrace(); - System.exit(2); - } catch (Throwable ex) { - System.err.println("\nUNEXPECTED TOP-LEVEL ERROR:"); - ex.printStackTrace(); - if ((ex instanceof NoClassDefFoundError) - || (ex instanceof NoSuchMethodError)) { - System.err.println( - "Note: You may be using an incompatible " + - "virtual machine or class library.\n" + - "(This program is known to be incompatible " + - "with recent releases of GCJ.)"); - } - System.exit(3); - } - - if (!gotCmd) { - System.err.println("error: no command specified"); - showUsage = true; - } - - if (showUsage) { - usage(); - System.exit(1); - } - } - - /** - * Prints the version message. - */ - private static void version() { - System.err.println("dx version " + Version.VERSION); - System.exit(0); - } - - /** - * Prints the usage message. - */ - private static void usage() { - System.err.println(USAGE_MESSAGE); - } - - /** - * Returns a copy of the given args array, but without the indicated - * element. - * - * @param orig non-null; original array - * @param n which element to omit - * @return non-null; new array - */ - private static String[] without(String[] orig, int n) { - int len = orig.length - 1; - String[] newa = new String[len]; - System.arraycopy(orig, 0, newa, 0, n); - System.arraycopy(orig, n + 1, newa, n, len - n); - return newa; - } -} diff --git a/dx/src/com/android/dx/command/UsageException.java b/dx/src/com/android/dx/command/UsageException.java deleted file mode 100644 index 6809bf45e..000000000 --- a/dx/src/com/android/dx/command/UsageException.java +++ /dev/null @@ -1,25 +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.android.dx.command; - -/** - * Simple exception class used to communicate that the command-line tool - * should print the usage message. - */ -public class UsageException extends RuntimeException { - // This space intentionally left blank. -} diff --git a/dx/src/com/android/dx/command/annotool/AnnotationLister.java b/dx/src/com/android/dx/command/annotool/AnnotationLister.java deleted file mode 100644 index 78f5d64d2..000000000 --- a/dx/src/com/android/dx/command/annotool/AnnotationLister.java +++ /dev/null @@ -1,283 +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.android.dx.command.annotool; - -import com.android.dx.cf.direct.ClassPathOpener; -import com.android.dx.cf.direct.DirectClassFile; -import com.android.dx.cf.direct.StdAttributeFactory; -import com.android.dx.cf.iface.AttributeList; -import com.android.dx.cf.iface.Attribute; -import com.android.dx.cf.attrib.AttRuntimeInvisibleAnnotations; -import com.android.dx.cf.attrib.BaseAnnotations; -import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations; -import com.android.dx.util.ByteArray; -import com.android.dx.rop.annotation.Annotation; - -import java.io.File; -import java.lang.annotation.ElementType; -import java.util.HashSet; - -/** - * Greps annotations on a set of class files and prints matching elements - * to stdout. What counts as a match and what should be printed is controlled - * by the <code>Main.Arguments</code> instance. - */ -class AnnotationLister { - - /** - * The string name of the pseudo-class that - * contains package-wide annotations - */ - private static final String PACKAGE_INFO = "package-info"; - - /** current match configuration */ - private final Main.Arguments args; - - /** Set of classes whose inner classes should be considered matched */ - HashSet<String> matchInnerClassesOf = new HashSet<String>(); - - /** set of packages whose classes should be considered matched */ - HashSet<String> matchPackages = new HashSet<String>(); - - AnnotationLister (Main.Arguments args) { - this.args = args; - } - - /** Processes based on configuration specified in constructor. */ - void process() { - for (String path: args.files) { - ClassPathOpener opener; - - opener = new ClassPathOpener(path, true, - new ClassPathOpener.Consumer() { - public boolean processFileBytes(String name, byte[] bytes) { - if (!name.endsWith(".class")) { - return true; - } - - ByteArray ba = new ByteArray(bytes); - DirectClassFile cf - = new DirectClassFile(ba, name, true); - - cf.setAttributeFactory(StdAttributeFactory.THE_ONE); - AttributeList attributes = cf.getAttributes(); - Attribute att; - - String cfClassName - = cf.getThisClass().getClassType().getClassName(); - - if (cfClassName.endsWith(PACKAGE_INFO)) { - att = attributes.findFirst( - AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME); - - for (;att != null; att = attributes.findNext(att)) { - BaseAnnotations ann = (BaseAnnotations)att; - visitPackageAnnotation(cf, ann); - } - - att = attributes.findFirst( - AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME); - - for (;att != null; att = attributes.findNext(att)) { - BaseAnnotations ann = (BaseAnnotations)att; - visitPackageAnnotation(cf, ann); - } - } else if (isMatchingInnerClass(cfClassName) - || isMatchingPackage(cfClassName)) { - printMatch(cf); - } else { - att = attributes.findFirst( - AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME); - - for (;att != null; att = attributes.findNext(att)) { - BaseAnnotations ann = (BaseAnnotations)att; - visitClassAnnotation(cf, ann); - } - - att = attributes.findFirst( - AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME); - - for (;att != null; att = attributes.findNext(att)) { - BaseAnnotations ann = (BaseAnnotations)att; - visitClassAnnotation(cf, ann); - } - } - - return true; - } - - public void onException(Exception ex) { - throw new RuntimeException(ex); - } - - public void onProcessArchiveStart(File file) { - - } - - }); - - opener.process(); - } - } - - /** - * Inspects a class annotation. - * - * @param cf non-null; class file - * @param ann non-null; annotation - */ - private void visitClassAnnotation(DirectClassFile cf, - BaseAnnotations ann) { - - if (!args.eTypes.contains(ElementType.TYPE)) { - return; - } - - for (Annotation anAnn: ann.getAnnotations().getAnnotations()) { - String annClassName - = anAnn.getType().getClassType().getClassName(); - if (args.aclass.equals(annClassName)) { - printMatch(cf); - } - } - } - - /** - * Inspects a package annotation - * - * @param cf non-null; class file of "package-info" pseudo-class - * @param ann non-null; annotation - */ - private void visitPackageAnnotation( - DirectClassFile cf, BaseAnnotations ann) { - - if (!args.eTypes.contains(ElementType.PACKAGE)) { - return; - } - - String packageName = cf.getThisClass().getClassType().getClassName(); - - int slashIndex = packageName.lastIndexOf('/'); - - if (slashIndex == -1) { - packageName = ""; - } else { - packageName - = packageName.substring(0, slashIndex); - } - - - for (Annotation anAnn: ann.getAnnotations().getAnnotations()) { - String annClassName - = anAnn.getType().getClassType().getClassName(); - if (args.aclass.equals(annClassName)) { - printMatchPackage(packageName); - } - } - } - - - /** - * Prints, or schedules for printing, elements related to a - * matching package. - * - * @param packageName non-null; name of package - */ - private void printMatchPackage(String packageName) { - for(Main.PrintType pt: args.printTypes) { - switch (pt) { - case CLASS: - case INNERCLASS: - case METHOD: - matchPackages.add(packageName); - break; - case PACKAGE: - System.out.println(packageName.replace('/','.')); - break; - } - } - } - - /** - * Prints, or schedules for printing, elements related to a matching - * class. - * - * @param cf non-null; matching class - */ - private void printMatch(DirectClassFile cf) { - for(Main.PrintType pt: args.printTypes) { - switch (pt) { - case CLASS: - String classname; - classname = cf.getThisClass().getClassType().getClassName(); - classname = classname.replace('/','.'); - System.out.println(classname); - break; - case INNERCLASS: - matchInnerClassesOf.add( - cf.getThisClass().getClassType().getClassName()); - break; - case METHOD: - //TODO - break; - case PACKAGE: - break; - } - } - } - - /** - * Checks to see if a specified class name should be considered a match - * due to previous matches. - * - * @param s non-null; class name - * @return true if this class should be considered a match - */ - private boolean isMatchingInnerClass(String s) { - int i; - - while (0 < (i = s.lastIndexOf('$'))) { - s = s.substring(0, i); - if (matchInnerClassesOf.contains(s)) { - return true; - } - } - - return false; - } - - /** - * Checks to see if a specified package should be considered a match due - * to previous matches. - * - * @param s non-null; package name - * @return true if this package should be considered a match - */ - private boolean isMatchingPackage(String s) { - int slashIndex = s.lastIndexOf('/'); - - String packageName; - if (slashIndex == -1) { - packageName = ""; - } else { - packageName - = s.substring(0, slashIndex); - } - - return matchPackages.contains(packageName); - } -} diff --git a/dx/src/com/android/dx/command/annotool/Main.java b/dx/src/com/android/dx/command/annotool/Main.java deleted file mode 100644 index 4f1d9a40b..000000000 --- a/dx/src/com/android/dx/command/annotool/Main.java +++ /dev/null @@ -1,159 +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.android.dx.command.annotool; - -import com.android.dx.cf.direct.ClassPathOpener; -import com.android.dx.cf.direct.DirectClassFile; -import com.android.dx.cf.direct.StdAttributeFactory; -import com.android.dx.cf.iface.AttributeList; -import com.android.dx.cf.iface.Attribute; -import com.android.dx.cf.attrib.AttRuntimeInvisibleAnnotations; -import com.android.dx.cf.attrib.BaseAnnotations; -import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations; -import com.android.dx.util.ByteArray; -import com.android.dx.rop.annotation.Annotation; - -import java.io.File; -import java.lang.annotation.ElementType; -import java.util.EnumSet; -import java.util.Arrays; - - -public class Main { - - private static class InvalidArgumentException extends Exception { - InvalidArgumentException() { - super(); - } - - InvalidArgumentException(String s) { - super(s); - } - } - - enum PrintType { - CLASS, - INNERCLASS, - METHOD, - PACKAGE - } - - - static class Arguments { - /** - * from --annotation, dot-seperated classname - * of annotation to look for - */ - String aclass; - - /** from --eTypes */ - EnumSet<ElementType> eTypes = EnumSet.noneOf(ElementType.class); - - /** from --print */ - EnumSet<PrintType> printTypes = EnumSet.noneOf(PrintType.class); - - /** remaining positional arguments */ - String[] files; - - Arguments() { - } - - void parse (String[] argArray) throws InvalidArgumentException { - for (int i = 0; i < argArray.length; i++) { - String arg = argArray[i]; - - if (arg.startsWith("--annotation=")) { - String argParam = arg.substring(arg.indexOf('=') + 1); - if (aclass != null) { - throw new InvalidArgumentException( - "--annotation can only be specified once."); - } - aclass = argParam.replace('.','/'); - } else if (arg.startsWith("--element=")) { - String argParam = arg.substring(arg.indexOf('=') + 1); - - try { - for (String p: argParam.split(",")) { - eTypes.add(ElementType.valueOf(p.toUpperCase())); - } - } catch (IllegalArgumentException ex) { - throw new InvalidArgumentException("invalid --element"); - } - } else if (arg.startsWith("--print=")) { - String argParam = arg.substring(arg.indexOf('=') + 1); - - try { - for (String p: argParam.split(",")) { - printTypes.add(PrintType.valueOf(p.toUpperCase())); - } - } catch (IllegalArgumentException ex) { - throw new InvalidArgumentException("invalid --print"); - } - } else { - files = new String[argArray.length - i]; - System.arraycopy(argArray, i, files, 0, files.length); - break; - } - } - - if (aclass == null) { - throw new InvalidArgumentException( - "--annotation must be specified"); - } - - if (printTypes.isEmpty()) { - printTypes.add(PrintType.CLASS); - } - - if (eTypes.isEmpty()) { - eTypes.add(ElementType.TYPE); - } - - EnumSet<ElementType> set = eTypes.clone(); - - set.remove(ElementType.TYPE); - set.remove(ElementType.PACKAGE); - if (!set.isEmpty()) { - throw new InvalidArgumentException( - "only --element parameters 'type' and 'package' " - + "supported"); - } - } - } - - /** - * This class is uninstantiable. - */ - private Main() { - // This space intentionally left blank. - } - - public static void main(String[] argArray) { - - final Arguments args = new Arguments(); - - try { - args.parse(argArray); - } catch (InvalidArgumentException ex) { - System.err.println(ex.getMessage()); - - throw new RuntimeException("usage"); - } - - new AnnotationLister(args).process(); - } -} diff --git a/dx/src/com/android/dx/command/dexer/Main.java b/dx/src/com/android/dx/command/dexer/Main.java deleted file mode 100644 index 19f67b443..000000000 --- a/dx/src/com/android/dx/command/dexer/Main.java +++ /dev/null @@ -1,905 +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.android.dx.command.dexer; - -import com.android.dx.Version; -import com.android.dx.cf.iface.ParseException; -import com.android.dx.cf.direct.ClassPathOpener; -import com.android.dx.command.DxConsole; -import com.android.dx.command.UsageException; -import com.android.dx.dex.cf.CfOptions; -import com.android.dx.dex.cf.CfTranslator; -import com.android.dx.dex.cf.CodeStatistics; -import com.android.dx.dex.code.PositionList; -import com.android.dx.dex.file.ClassDefItem; -import com.android.dx.dex.file.DexFile; -import com.android.dx.dex.file.EncodedMethod; -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstUtf8; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Map; -import java.util.TreeMap; -import java.util.jar.Attributes; -import java.util.jar.JarEntry; -import java.util.jar.JarOutputStream; -import java.util.jar.Manifest; - -/** - * Main class for the class file translator. - */ -public class Main { - /** - * non-null; name for the <code>.dex</code> file that goes into - * <code>.jar</code> files - */ - private static final String DEX_IN_JAR_NAME = "classes.dex"; - - /** - * non-null; name of the standard manifest file in <code>.jar</code> - * files - */ - private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; - - /** - * non-null; attribute name for the (quasi-standard?) - * <code>Created-By</code> attribute - */ - private static final Attributes.Name CREATED_BY = - new Attributes.Name("Created-By"); - - /** - * non-null; list of <code>javax</code> subpackages that are considered - * to be "core". <b>Note:</b>: This list must be sorted, since it - * is binary-searched. - */ - private static final String[] JAVAX_CORE = { - "accessibility", "crypto", "imageio", "management", "naming", "net", - "print", "rmi", "security", "sound", "sql", "swing", "transaction", - "xml" - }; - - /** number of warnings during processing */ - private static int warnings = 0; - - /** number of errors during processing */ - private static int errors = 0; - - /** non-null; parsed command-line arguments */ - private static Arguments args; - - /** non-null; output file in-progress */ - private static DexFile outputDex; - - /** - * null-ok; map of resources to include in the output, or - * <code>null</code> if resources are being ignored - */ - private static TreeMap<String, byte[]> outputResources; - - /** - * This class is uninstantiable. - */ - private Main() { - // This space intentionally left blank. - } - - /** - * Run and exit if something unexpected happened. - * @param argArray the command line arguments - */ - public static void main(String[] argArray) { - Arguments arguments = new Arguments(); - arguments.parse(argArray); - - int result = run(arguments); - if (result != 0) { - System.exit(result); - } - } - - /** - * Run and return a result code. - * @param arguments the data + parameters for the conversion - * @return 0 if success > 0 otherwise. - */ - public static int run(Arguments arguments) { - // Reset the error/warning count to start fresh. - warnings = 0; - errors = 0; - - args = arguments; - args.makeCfOptions(); - - if (!processAllFiles()) { - return 1; - } - - byte[] outArray = writeDex(); - - if (outArray == null) { - return 2; - } - - if (args.jarOutput) { - // Effectively free up the (often massive) DexFile memory. - outputDex = null; - - if (!createJar(args.outName, outArray)) { - return 3; - } - } - - return 0; - } - - /** - * Constructs the output {@link DexFile}, fill it in with all the - * specified classes, and populate the resources map if required. - * - * @return whether processing was successful - */ - private static boolean processAllFiles() { - outputDex = new DexFile(); - - if (args.jarOutput) { - outputResources = new TreeMap<String, byte[]>(); - } - - if (args.dumpWidth != 0) { - outputDex.setDumpWidth(args.dumpWidth); - } - - boolean any = false; - String[] fileNames = args.fileNames; - - try { - for (int i = 0; i < fileNames.length; i++) { - any |= processOne(fileNames[i]); - } - } catch (StopProcessing ex) { - /* - * Ignore it and just let the warning/error reporting do - * their things. - */ - } - - if (warnings != 0) { - DxConsole.err.println(warnings + " warning" + - ((warnings == 1) ? "" : "s")); - } - - if (errors != 0) { - DxConsole.err.println(errors + " error" + - ((errors == 1) ? "" : "s") + "; aborting"); - return false; - } - - if (!(any || args.emptyOk)) { - DxConsole.err.println("no classfiles specified"); - return false; - } - - if (args.optimize && args.statistics) { - CodeStatistics.dumpStatistics(DxConsole.out); - } - - return true; - } - - /** - * Processes one pathname element. - * - * @param pathname non-null; the pathname to process. May be the path of - * a class file, a jar file, or a directory containing class files. - * @return whether any processing actually happened - */ - private static boolean processOne(String pathname) { - ClassPathOpener opener; - - opener = new ClassPathOpener(pathname, false, - new ClassPathOpener.Consumer() { - public boolean processFileBytes(String name, byte[] bytes) { - return Main.processFileBytes(name, bytes); - } - public void onException(Exception ex) { - if (ex instanceof StopProcessing) { - throw (StopProcessing) ex; - } - DxConsole.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:"); - ex.printStackTrace(DxConsole.err); - errors++; - } - public void onProcessArchiveStart(File file) { - if (args.verbose) { - DxConsole.out.println("processing archive " + file + "..."); - } - } - }); - - return opener.process(); - } - - /** - * Processes one file, which may be either a class or a resource. - * - * @param name non-null; name of the file - * @param bytes non-null; contents of the file - * @return whether processing was successful - */ - private static boolean processFileBytes(String name, byte[] bytes) { - boolean isClass = name.endsWith(".class"); - boolean keepResources = (outputResources != null); - - if (!isClass && !keepResources) { - if (args.verbose) { - DxConsole.out.println("ignored resource " + name); - } - return false; - } - - if (args.verbose) { - DxConsole.out.println("processing " + name + "..."); - } - - String fixedName = fixPath(name); - - if (isClass) { - if (keepResources && args.keepClassesInJar) { - outputResources.put(fixedName, bytes); - } - return processClass(fixedName, bytes); - } else { - outputResources.put(fixedName, bytes); - return true; - } - } - - /** - * Processes one classfile. - * - * @param name non-null; name of the file, clipped such that it - * <i>should</i> correspond to the name of the class it contains - * @param bytes non-null; contents of the file - * @return whether processing was successful - */ - private static boolean processClass(String name, byte[] bytes) { - if (! args.coreLibrary) { - checkClassName(name); - } - - try { - ClassDefItem clazz = - CfTranslator.translate(name, bytes, args.cfOptions); - outputDex.add(clazz); - return true; - } catch (ParseException ex) { - DxConsole.err.println("\ntrouble processing:"); - if (args.debug) { - ex.printStackTrace(DxConsole.err); - } else { - ex.printContext(DxConsole.err); - } - } - - warnings++; - return false; - } - - /** - * Check the class name to make sure it's not a "core library" - * class. If there is a problem, this updates the error count and - * throws an exception to stop processing. - * - * @param name non-null; the fully-qualified internal-form class name - */ - private static void checkClassName(String name) { - boolean bogus = false; - - if (name.startsWith("java/")) { - bogus = true; - } else if (name.startsWith("javax/")) { - int slashAt = name.indexOf('/', 6); - if (slashAt == -1) { - // Top-level javax classes are verboten. - bogus = true; - } else { - String pkg = name.substring(6, slashAt); - bogus = (Arrays.binarySearch(JAVAX_CORE, pkg) >= 0); - } - } - - if (! bogus) { - return; - } - - /* - * The user is probably trying to include an entire desktop - * core library in a misguided attempt to get their application - * working. Try to help them understand what's happening. - */ - - DxConsole.err.println("\ntrouble processing \"" + name + "\":"); - DxConsole.err.println("\n" + - "Attempt to include a core VM class in something other " + - "than a core library.\n" + - "It is likely that you have attempted to include the " + - "core library from a desktop\n" + - "virtual machine into an application, which will most " + - "assuredly not work. If\n" + - "you really intend to build a core library -- which is "+ - "only appropriate as\n" + - "part of creating a full virtual machine binary, as " + - "opposed to compiling an\n" + - "application -- then use the \"--core-library\" option " + - "to suppress this error\n" + - "message. If you go ahead and use \"--core-library\" " + - "but are in fact building\n" + - "an application, then please be aware that your build " + - "will still fail at some\n" + - "point; you will simply be denied the pleasure of " + - "reading this helpful error\n" + - "message."); - errors++; - throw new StopProcessing(); - } - - /** - * Converts {@link #outputDex} into a <code>byte[]</code>, write - * it out to the proper file (if any), and also do whatever human-oriented - * dumping is required. - * - * @return null-ok; the converted <code>byte[]</code> or <code>null</code> - * if there was a problem - */ - private static byte[] writeDex() { - byte[] outArray = null; - - try { - OutputStream out = null; - OutputStream humanOutRaw = null; - OutputStreamWriter humanOut = null; - try { - if (args.humanOutName != null) { - humanOutRaw = openOutput(args.humanOutName); - humanOut = new OutputStreamWriter(humanOutRaw); - } - - if (args.methodToDump != null) { - /* - * Simply dump the requested method. Note: The call - * to toDex() is required just to get the underlying - * structures ready. - */ - outputDex.toDex(null, false); - dumpMethod(outputDex, args.methodToDump, humanOut); - } else { - /* - * This is the usual case: Create an output .dex file, - * and write it, dump it, etc. - */ - outArray = outputDex.toDex(humanOut, args.verboseDump); - - if ((args.outName != null) && !args.jarOutput) { - out = openOutput(args.outName); - out.write(outArray); - } - } - - if (args.statistics) { - DxConsole.out.println(outputDex.getStatistics().toHuman()); - } - } finally { - if (humanOut != null) { - humanOut.flush(); - } - closeOutput(out); - closeOutput(humanOutRaw); - } - } catch (Exception ex) { - if (args.debug) { - DxConsole.err.println("\ntrouble writing output:"); - ex.printStackTrace(DxConsole.err); - } else { - DxConsole.err.println("\ntrouble writing output: " + - ex.getMessage()); - } - return null; - } - - return outArray; - } - - /** - * Creates a jar file from the resources and given dex file array. - * - * @param fileName non-null; name of the file - * @param dexArray non-null; array containing the dex file to include - * @return whether the creation was successful - */ - private static boolean createJar(String fileName, byte[] dexArray) { - /* - * Make or modify the manifest (as appropriate), put the dex - * array into the resources map, and then process the entire - * resources map in a uniform manner. - */ - - try { - Manifest manifest = makeManifest(); - OutputStream out = openOutput(fileName); - JarOutputStream jarOut = new JarOutputStream(out, manifest); - - outputResources.put(DEX_IN_JAR_NAME, dexArray); - - try { - for (Map.Entry<String, byte[]> e : - outputResources.entrySet()) { - String name = e.getKey(); - byte[] contents = e.getValue(); - JarEntry entry = new JarEntry(name); - - if (args.verbose) { - DxConsole.out.println("writing " + name + "; size " + - contents.length + "..."); - } - - entry.setSize(contents.length); - jarOut.putNextEntry(entry); - jarOut.write(contents); - jarOut.closeEntry(); - } - } finally { - jarOut.finish(); - jarOut.flush(); - closeOutput(out); - } - } catch (Exception ex) { - if (args.debug) { - DxConsole.err.println("\ntrouble writing output:"); - ex.printStackTrace(DxConsole.err); - } else { - DxConsole.err.println("\ntrouble writing output: " + - ex.getMessage()); - } - return false; - } - - return true; - } - - /** - * Creates and returns the manifest to use for the output. This may - * modify {@link #outputResources} (removing the pre-existing manifest). - * - * @return non-null; the manifest - */ - private static Manifest makeManifest() throws IOException { - byte[] manifestBytes = outputResources.get(MANIFEST_NAME); - Manifest manifest; - Attributes attribs; - - if (manifestBytes == null) { - // We need to construct an entirely new manifest. - manifest = new Manifest(); - attribs = manifest.getMainAttributes(); - attribs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); - } else { - manifest = new Manifest(new ByteArrayInputStream(manifestBytes)); - attribs = manifest.getMainAttributes(); - outputResources.remove(MANIFEST_NAME); - } - - String createdBy = attribs.getValue(CREATED_BY); - if (createdBy == null) { - createdBy = ""; - } else { - createdBy += " + "; - } - createdBy += "dx " + Version.VERSION; - - attribs.put(CREATED_BY, createdBy); - attribs.putValue("Dex-Location", DEX_IN_JAR_NAME); - - return manifest; - } - - /** - * Opens and returns the named file for writing, treating "-" specially. - * - * @param name non-null; the file name - * @return non-null; the opened file - */ - private static OutputStream openOutput(String name) throws IOException { - if (name.equals("-") || - name.startsWith("-.")) { - return System.out; - } - - return new FileOutputStream(name); - } - - /** - * Flushes and closes the given output stream, except if it happens to be - * {@link System#out} in which case this method does the flush but not - * the close. This method will also silently do nothing if given a - * <code>null</code> argument. - * - * @param stream null-ok; what to close - */ - private static void closeOutput(OutputStream stream) throws IOException { - if (stream == null) { - return; - } - - stream.flush(); - - if (stream != System.out) { - stream.close(); - } - } - - /** - * Returns the "fixed" version of a given file path, suitable for - * use as a path within a <code>.jar</code> file and for checking - * against a classfile-internal "this class" name. This looks for - * the last instance of the substring <code>"/./"</code> within - * the path, and if it finds it, it takes the portion after to be - * the fixed path. If that isn't found but the path starts with - * <code>"./"</code>, then that prefix is removed and the rest is - * return. If neither of these is the case, this method returns - * its argument. - * - * @param path non-null; the path to "fix" - * @return non-null; the fixed version (which might be the same as - * the given <code>path</code>) - */ - private static String fixPath(String path) { - /* - * If the path separator is \ (like on windows), we convert the - * path to a standard '/' separated path. - */ - if (File.separatorChar == '\\') { - path = path.replace('\\', '/'); - } - - int index = path.lastIndexOf("/./"); - - if (index != -1) { - return path.substring(index + 3); - } - - if (path.startsWith("./")) { - return path.substring(2); - } - - return path; - } - - /** - * Dumps any method with the given name in the given file. - * - * @param dex non-null; the dex file - * @param fqName non-null; the fully-qualified name of the method(s) - * @param out non-null; where to dump to - */ - private static void dumpMethod(DexFile dex, String fqName, - OutputStreamWriter out) { - boolean wildcard = fqName.endsWith("*"); - int lastDot = fqName.lastIndexOf('.'); - - if ((lastDot <= 0) || (lastDot == (fqName.length() - 1))) { - DxConsole.err.println("bogus fully-qualified method name: " + - fqName); - return; - } - - String className = fqName.substring(0, lastDot).replace('.', '/'); - String methodName = fqName.substring(lastDot + 1); - ClassDefItem clazz = dex.getClassOrNull(className); - - if (clazz == null) { - DxConsole.err.println("no such class: " + className); - return; - } - - if (wildcard) { - methodName = methodName.substring(0, methodName.length() - 1); - } - - ArrayList<EncodedMethod> allMeths = clazz.getMethods(); - TreeMap<CstNat, EncodedMethod> meths = - new TreeMap<CstNat, EncodedMethod>(); - - /* - * Figure out which methods to include in the output, and get them - * all sorted, so that the printout code is robust with respect to - * changes in the underlying order. - */ - for (EncodedMethod meth : allMeths) { - String methName = meth.getName().getString(); - if ((wildcard && methName.startsWith(methodName)) || - (!wildcard && methName.equals(methodName))) { - meths.put(meth.getRef().getNat(), meth); - } - } - - if (meths.size() == 0) { - DxConsole.err.println("no such method: " + fqName); - return; - } - - PrintWriter pw = new PrintWriter(out); - - for (EncodedMethod meth : meths.values()) { - // TODO: Better stuff goes here, perhaps. - meth.debugPrint(pw, args.verboseDump); - - /* - * The (default) source file is an attribute of the class, but - * it's useful to see it in method dumps. - */ - CstUtf8 sourceFile = clazz.getSourceFile(); - if (sourceFile != null) { - pw.println(" source file: " + sourceFile.toQuoted()); - } - - Annotations methodAnnotations = - clazz.getMethodAnnotations(meth.getRef()); - AnnotationsList parameterAnnotations = - clazz.getParameterAnnotations(meth.getRef()); - - if (methodAnnotations != null) { - pw.println(" method annotations:"); - for (Annotation a : methodAnnotations.getAnnotations()) { - pw.println(" " + a); - } - } - - if (parameterAnnotations != null) { - pw.println(" parameter annotations:"); - int sz = parameterAnnotations.size(); - for (int i = 0; i < sz; i++) { - pw.println(" parameter " + i); - Annotations annotations = parameterAnnotations.get(i); - for (Annotation a : annotations.getAnnotations()) { - pw.println(" " + a); - } - } - } - } - - pw.flush(); - } - - /** - * Exception class used to halt processing prematurely. - */ - private static class StopProcessing extends RuntimeException { - // This space intentionally left blank. - } - - /** - * Command-line argument parser and access. - */ - public static class Arguments { - /** whether to run in debug mode */ - public boolean debug = false; - - /** whether to emit high-level verbose human-oriented output */ - public boolean verbose = false; - - /** whether to emit verbose human-oriented output in the dump file */ - public boolean verboseDump = false; - - /** whether we are constructing a core library */ - public boolean coreLibrary = false; - - /** null-ok; particular method to dump */ - public String methodToDump = null; - - /** max width for columnar output */ - public int dumpWidth = 0; - - /** null-ok; output file name for binary file */ - public String outName = null; - - /** null-ok; output file name for human-oriented dump */ - public String humanOutName = null; - - /** whether strict file-name-vs-class-name checking should be done */ - public boolean strictNameCheck = true; - - /** - * whether it is okay for there to be no <code>.class</code> files - * to process - */ - public boolean emptyOk = false; - - /** - * whether the binary output is to be a <code>.jar</code> file - * instead of a plain <code>.dex</code> - */ - public boolean jarOutput = false; - - /** - * when writing a <code>.jar</code> file, whether to still - * keep the <code>.class</code> files - */ - public boolean keepClassesInJar = false; - - /** how much source position info to preserve */ - public int positionInfo = PositionList.LINES; - - /** whether to keep local variable information */ - public boolean localInfo = true; - - /** non-null after {@link #parse}; file name arguments */ - public String[] fileNames; - - /** whether to do SSA/register optimization */ - public boolean optimize = true; - - /** Filename containg list of methods to optimize */ - public String optimizeListFile = null; - - /** Filename containing list of methods to NOT optimize */ - public String dontOptimizeListFile = null; - - /** Whether to print statistics to stdout at end of compile cycle */ - public boolean statistics; - - /** Options for dex.cf.* */ - public CfOptions cfOptions; - - /** - * Parses the given command-line arguments. - * - * @param args non-null; the arguments - */ - public void parse(String[] args) { - int at = 0; - - for (/*at*/; at < args.length; at++) { - String arg = args[at]; - if (arg.equals("--") || !arg.startsWith("--")) { - break; - } else if (arg.equals("--debug")) { - debug = true; - } else if (arg.equals("--verbose")) { - verbose = true; - } else if (arg.equals("--verbose-dump")) { - verboseDump = true; - } else if (arg.equals("--no-files")) { - emptyOk = true; - } else if (arg.equals("--no-optimize")) { - optimize = false; - } else if (arg.equals("--no-strict")) { - strictNameCheck = false; - } else if (arg.equals("--core-library")) { - coreLibrary = true; - } else if (arg.equals("--statistics")) { - statistics = true; - } else if (arg.startsWith("--optimize-list=")) { - if (dontOptimizeListFile != null) { - System.err.println("--optimize-list and " - + "--no-optimize-list are incompatible."); - throw new UsageException(); - } - optimize = true; - optimizeListFile = arg.substring(arg.indexOf('=') + 1); - } else if (arg.startsWith("--no-optimize-list=")) { - if (dontOptimizeListFile != null) { - System.err.println("--optimize-list and " - + "--no-optimize-list are incompatible."); - throw new UsageException(); - } - optimize = true; - dontOptimizeListFile = arg.substring(arg.indexOf('=') + 1); - } else if (arg.equals("--keep-classes")) { - keepClassesInJar = true; - } else if (arg.startsWith("--output=")) { - outName = arg.substring(arg.indexOf('=') + 1); - if (outName.endsWith(".zip") || - outName.endsWith(".jar") || - outName.endsWith(".apk")) { - jarOutput = true; - } else if (outName.endsWith(".dex") || - outName.equals("-")) { - jarOutput = false; - } else { - System.err.println("unknown output extension: " + - outName); - throw new UsageException(); - } - } else if (arg.startsWith("--dump-to=")) { - humanOutName = arg.substring(arg.indexOf('=') + 1); - } else if (arg.startsWith("--dump-width=")) { - arg = arg.substring(arg.indexOf('=') + 1); - dumpWidth = Integer.parseInt(arg); - } else if (arg.startsWith("--dump-method=")) { - methodToDump = arg.substring(arg.indexOf('=') + 1); - jarOutput = false; - } else if (arg.startsWith("--positions=")) { - String pstr = arg.substring(arg.indexOf('=') + 1).intern(); - if (pstr == "none") { - positionInfo = PositionList.NONE; - } else if (pstr == "important") { - positionInfo = PositionList.IMPORTANT; - } else if (pstr == "lines") { - positionInfo = PositionList.LINES; - } else { - System.err.println("unknown positions option: " + - pstr); - throw new UsageException(); - } - } else if (arg.equals("--no-locals")) { - localInfo = false; - } else { - System.err.println("unknown option: " + arg); - throw new UsageException(); - } - } - - int fileCount = args.length - at; - fileNames = new String[fileCount]; - System.arraycopy(args, at, fileNames, 0, fileCount); - - if (fileCount == 0) { - if (!emptyOk) { - System.err.println("no input files specified"); - throw new UsageException(); - } - } else if (emptyOk) { - System.out.println("ignoring input files"); - at = args.length; - } - - if ((humanOutName == null) && (methodToDump != null)) { - humanOutName = "-"; - } - - makeCfOptions(); - } - - /** - * Copies relevent arguments over into a CfOptions instance. - */ - private void makeCfOptions() { - cfOptions = new CfOptions(); - - cfOptions.positionInfo = positionInfo; - cfOptions.localInfo = localInfo; - cfOptions.strictNameCheck = strictNameCheck; - cfOptions.optimize = optimize; - cfOptions.optimizeListFile = optimizeListFile; - cfOptions.dontOptimizeListFile = dontOptimizeListFile; - cfOptions.statistics = statistics; - cfOptions.warn = DxConsole.err; - } - } -} diff --git a/dx/src/com/android/dx/command/dump/Args.java b/dx/src/com/android/dx/command/dump/Args.java deleted file mode 100644 index 042fae2e1..000000000 --- a/dx/src/com/android/dx/command/dump/Args.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.android.dx.command.dump; - -/** - * contains command line parsedArgs values - */ -class Args { - /** whether to run in debug mode */ - boolean debug = false; - - /** whether to dump raw bytes where salient */ - boolean rawBytes = false; - - /** whether to dump information about basic blocks */ - boolean basicBlocks = false; - - /** whether to dump regiserized blocks */ - boolean ropBlocks = false; - - /** whether to dump SSA-form blocks */ - boolean ssaBlocks = false; - - /** Step in SSA processing to stop at, or null for all */ - String ssaStep = null; - - /** whether to run SSA optimizations */ - boolean optimize = false; - - /** whether to be strict about parsing classfiles*/ - boolean strictParse = false; - - /** max width for columnar output */ - int width = 0; - - /** whether to dump flow-graph in "dot" format */ - boolean dotDump = false; - - /** if non-null, an explicit method to dump */ - String method; - -} diff --git a/dx/src/com/android/dx/command/dump/BaseDumper.java b/dx/src/com/android/dx/command/dump/BaseDumper.java deleted file mode 100644 index f4a8dee1d..000000000 --- a/dx/src/com/android/dx/command/dump/BaseDumper.java +++ /dev/null @@ -1,299 +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.android.dx.command.dump; - -import com.android.dx.cf.code.ConcreteMethod; -import com.android.dx.cf.iface.Member; -import com.android.dx.cf.iface.ParseObserver; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; -import com.android.dx.util.IndentingWriter; -import com.android.dx.util.TwoColumnOutput; - -import java.io.IOException; -import java.io.PrintStream; -import java.io.StringWriter; - -/** - * Base class for the various human-friendly dumpers. - */ -public abstract class BaseDumper - implements ParseObserver { - /** non-null; array of data being dumped */ - private final byte[] bytes; - - /** whether or not to include the raw bytes (in a column on the left) */ - private final boolean rawBytes; - - /** non-null; where to dump to */ - private final PrintStream out; - - /** width of the output in columns */ - private final int width; - - /** - * non-null; the file path for the class, excluding any base directory - * specification - */ - private final String filePath; - - /** whether to be strict about parsing */ - private final boolean strictParse; - - /** number of bytes per line in hex dumps */ - private final int hexCols; - - /** the current level of indentation */ - private int indent; - - /** non-null; the current column separator string */ - private String separator; - - /** the offset of the next byte to dump */ - private int at; - - /** commandline parsedArgs */ - protected Args args; - - /** - * Constructs an instance. - * - * @param bytes non-null; bytes of the (alleged) class file - * on the left) - * @param out non-null; where to dump to - * passed in as <= 0 - * @param filePath the file path for the class, excluding any base - * directory specification - */ - public BaseDumper(byte[] bytes, PrintStream out, - String filePath, Args args) { - this.bytes = bytes; - this.rawBytes = args.rawBytes; - this.out = out; - this.width = (args.width <= 0) ? 79 : args.width; - this.filePath = filePath; - this.strictParse = args.strictParse; - this.indent = 0; - this.separator = rawBytes ? "|" : ""; - this.at = 0; - this.args = args; - - int hexCols = (((width - 5) / 15) + 1) & ~1; - if (hexCols < 6) { - hexCols = 6; - } else if (hexCols > 10) { - hexCols = 10; - } - this.hexCols = hexCols; - } - - /** - * Computes the total width, in register-units, of the parameters for - * this method. - * @param meth method to process - * @return width in register-units - */ - static int computeParamWidth(ConcreteMethod meth, boolean isStatic) { - return meth.getEffectiveDescriptor().getParameterTypes().getWordCount(); - } - - /** {@inheritDoc} */ - public void changeIndent(int indentDelta) { - indent += indentDelta; - - separator = rawBytes ? "|" : ""; - for (int i = 0; i < indent; i++) { - separator += " "; - } - } - - /** {@inheritDoc} */ - public void parsed(ByteArray bytes, int offset, int len, String human) { - offset = bytes.underlyingOffset(offset, getBytes()); - - boolean rawBytes = getRawBytes(); - - if (offset < at) { - println("<dump skipped backwards to " + Hex.u4(offset) + ">"); - at = offset; - } else if (offset > at) { - String hex = rawBytes ? hexDump(at, offset - at) : ""; - print(twoColumns(hex, "<skipped to " + Hex.u4(offset) + ">")); - at = offset; - } - - String hex = rawBytes ? hexDump(offset, len) : ""; - print(twoColumns(hex, human)); - at += len; - } - - /** {@inheritDoc} */ - public void startParsingMember(ByteArray bytes, int offset, String name, - String descriptor) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void endParsingMember(ByteArray bytes, int offset, String name, - String descriptor, Member member) { - // This space intentionally left blank. - } - - /** - * Gets the current dump cursor (that is, the offset of the expected - * next byte to dump). - * - * @return >= 0; the dump cursor - */ - protected final int getAt() { - return at; - } - - /** - * Sets the dump cursor to the indicated offset in the given array. - * - * @param arr non-null; array in question - * @param offset >= 0; offset into the array - */ - protected final void setAt(ByteArray arr, int offset) { - at = arr.underlyingOffset(offset, bytes); - } - - /** - * Gets the array of <code>byte</code>s to process. - * - * @return non-null; the bytes - */ - protected final byte[] getBytes() { - return bytes; - } - - /** - * Gets the filesystem/jar path of the file being dumped. - * - * @return non-null; the path - */ - protected final String getFilePath() { - return filePath; - } - - /** - * Gets whether to be strict about parsing. - * - * @return whether to be strict about parsing - */ - protected final boolean getStrictParse() { - return strictParse; - } - - /** - * Prints the given string to this instance's output stream. - * - * @param s null-ok; string to print - */ - protected final void print(String s) { - out.print(s); - } - - /** - * Prints the given string to this instance's output stream, followed - * by a newline. - * - * @param s null-ok; string to print - */ - protected final void println(String s) { - out.println(s); - } - - /** - * Gets whether this dump is to include raw bytes. - * - * @return the raw bytes flag - */ - protected final boolean getRawBytes() { - return rawBytes; - } - - /** - * Gets the width of the first column of output. This is <code>0</code> - * unless raw bytes are being included in the output. - * - * @return >= 0; the width of the first column - */ - protected final int getWidth1() { - if (rawBytes) { - return 5 + (hexCols * 2) + (hexCols / 2); - } - - return 0; - } - - /** - * Gets the width of the second column of output. - * - * @return >= 0; the width of the second column - */ - protected final int getWidth2() { - int w1 = rawBytes ? (getWidth1() + 1) : 0; - return width - w1 - (indent * 2); - } - - /** - * Constructs a hex data dump of the given portion of {@link #bytes}. - * - * @param offset offset to start dumping at - * @param len length to dump - * @return non-null; the dump - */ - protected final String hexDump(int offset, int len) { - return Hex.dump(bytes, offset, len, offset, hexCols, 4); - } - - /** - * Combines a pair of strings as two columns, or if this is one-column - * output, format the otherwise-second column. - * - * @param s1 non-null; the first column's string - * @param s2 non-null; the second column's string - * @return non-null; the combined output - */ - protected final String twoColumns(String s1, String s2) { - int w1 = getWidth1(); - int w2 = getWidth2(); - - try { - if (w1 == 0) { - int len2 = s2.length(); - StringWriter sw = new StringWriter(len2 * 2); - IndentingWriter iw = new IndentingWriter(sw, w2, separator); - - iw.write(s2); - if ((len2 == 0) || (s2.charAt(len2 - 1) != '\n')) { - iw.write('\n'); - } - iw.flush(); - - return sw.toString(); - } else { - return TwoColumnOutput.toString(s1, w1, separator, s2, w2); - } - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } -} diff --git a/dx/src/com/android/dx/command/dump/BlockDumper.java b/dx/src/com/android/dx/command/dump/BlockDumper.java deleted file mode 100644 index 0be2fb402..000000000 --- a/dx/src/com/android/dx/command/dump/BlockDumper.java +++ /dev/null @@ -1,360 +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.android.dx.command.dump; - -import com.android.dx.cf.attrib.AttCode; -import com.android.dx.cf.code.BasicBlocker; -import com.android.dx.cf.code.ByteBlock; -import com.android.dx.cf.code.ByteBlockList; -import com.android.dx.cf.code.ByteCatchList; -import com.android.dx.cf.code.BytecodeArray; -import com.android.dx.cf.code.ConcreteMethod; -import com.android.dx.cf.code.Ropper; -import com.android.dx.cf.direct.CodeObserver; -import com.android.dx.cf.direct.DirectClassFile; -import com.android.dx.cf.direct.StdAttributeFactory; -import com.android.dx.cf.iface.Member; -import com.android.dx.cf.iface.Method; -import com.android.dx.rop.code.BasicBlock; -import com.android.dx.rop.code.BasicBlockList; -import com.android.dx.rop.code.Insn; -import com.android.dx.rop.code.InsnList; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.DexTranslationAdvice; -import com.android.dx.rop.code.TranslationAdvice; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.CstType; -import com.android.dx.ssa.Optimizer; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; - -import java.io.PrintStream; - -/** - * Utility to dump basic block info from methods in a human-friendly form. - */ -public class BlockDumper - extends BaseDumper { - /** whether or not to registerize (make rop blocks) */ - private boolean rop; - - /** - * null-ok; the class file object being constructed; becomes non-null - * during {@link #dump} - */ - protected DirectClassFile classFile; - - /** null-ok; most recently parsed code attribute */ - private AttCode codeAtt; - - /** whether or not to suppress dumping */ - protected boolean suppressDump; - - /** whether this is the first method being dumped */ - private boolean first; - - /** whether or not to run the ssa optimziations */ - private boolean optimize; - - /** - * Dumps the given array, interpreting it as a class file and dumping - * methods with indications of block-level stuff. - * - * @param bytes non-null; bytes of the (alleged) class file - * @param out non-null; where to dump to - * passed in as <= 0 - * @param filePath the file path for the class, excluding any base - * directory specification - * @param rop whether or not to registerize (make rop blocks) - * @param args commandline parsedArgs - */ - public static void dump(byte[] bytes, PrintStream out, - String filePath, boolean rop, Args args) { - BlockDumper bd = - new BlockDumper(bytes, out, filePath, - rop, args); - bd.dump(); - } - - /** - * Constructs an instance. This class is not publicly instantiable. - * Use {@link #dump}. - */ - BlockDumper(byte[] bytes, PrintStream out, - String filePath, - boolean rop, Args args) { - super(bytes, out, filePath, args); - - this.rop = rop; - this.classFile = null; - this.codeAtt = null; - this.suppressDump = true; - this.first = true; - this.optimize = args.optimize; - } - - /** - * Does the dumping. - */ - public void dump() { - byte[] bytes = getBytes(); - ByteArray ba = new ByteArray(bytes); - - /* - * First, parse the file completely, so we can safely refer to - * attributes, etc. - */ - classFile = new DirectClassFile(ba, getFilePath(), getStrictParse()); - classFile.setAttributeFactory(StdAttributeFactory.THE_ONE); - classFile.getMagic(); // Force parsing to happen. - - // Next, reparse it and observe the process. - DirectClassFile liveCf = - new DirectClassFile(ba, getFilePath(), getStrictParse()); - liveCf.setAttributeFactory(StdAttributeFactory.THE_ONE); - liveCf.setObserver(this); - liveCf.getMagic(); // Force parsing to happen. - } - - /** {@inheritDoc} */ - @Override - public void changeIndent(int indentDelta) { - if (!suppressDump) { - super.changeIndent(indentDelta); - } - } - - /** {@inheritDoc} */ - @Override - public void parsed(ByteArray bytes, int offset, int len, String human) { - if (!suppressDump) { - super.parsed(bytes, offset, len, human); - } - } - - /** - * @param name method name - * @return true if this method should be dumped - */ - protected boolean shouldDumpMethod(String name) { - return args.method == null || args.method.equals(name); - } - - /** {@inheritDoc} */ - @Override - public void startParsingMember(ByteArray bytes, int offset, String name, - String descriptor) { - if (descriptor.indexOf('(') < 0) { - // It's a field, not a method - return; - } - - if (!shouldDumpMethod(name)) { - return; - } - - // Reset the dump cursor to the start of the method. - setAt(bytes, offset); - - suppressDump = false; - - if (first) { - first = false; - } else { - parsed(bytes, offset, 0, "\n"); - } - - parsed(bytes, offset, 0, "method " + name + " " + descriptor); - suppressDump = true; - } - - /** {@inheritDoc} */ - @Override - public void endParsingMember(ByteArray bytes, int offset, String name, - String descriptor, Member member) { - if (!(member instanceof Method)) { - return; - } - - if (!shouldDumpMethod(name)) { - return; - } - - ConcreteMethod meth = new ConcreteMethod((Method) member, classFile, - true, true); - - if (rop) { - ropDump(meth); - } else { - regularDump(meth); - } - } - - /** - * Does a regular basic block dump. - * - * @param meth non-null; method data to dump - */ - private void regularDump(ConcreteMethod meth) { - BytecodeArray code = meth.getCode(); - ByteArray bytes = code.getBytes(); - ByteBlockList list = BasicBlocker.identifyBlocks(meth); - int sz = list.size(); - CodeObserver codeObserver = new CodeObserver(bytes, BlockDumper.this); - - // Reset the dump cursor to the start of the bytecode - setAt(bytes, 0); - - suppressDump = false; - - int byteAt = 0; - for (int i = 0; i < sz; i++) { - ByteBlock bb = list.get(i); - int start = bb.getStart(); - int end = bb.getEnd(); - - if (byteAt < start) { - parsed(bytes, byteAt, start - byteAt, - "dead code " + Hex.u2(byteAt) + ".." + Hex.u2(start)); - } - - parsed(bytes, start, 0, - "block " + Hex.u2(bb.getLabel()) + ": " + - Hex.u2(start) + ".." + Hex.u2(end)); - changeIndent(1); - - int len; - for (int j = start; j < end; j += len) { - len = code.parseInstruction(j, codeObserver); - codeObserver.setPreviousOffset(j); - } - - IntList successors = bb.getSuccessors(); - int ssz = successors.size(); - if (ssz == 0) { - parsed(bytes, end, 0, "returns"); - } else { - for (int j = 0; j < ssz; j++) { - int succ = successors.get(j); - parsed(bytes, end, 0, "next " + Hex.u2(succ)); - } - } - - ByteCatchList catches = bb.getCatches(); - int csz = catches.size(); - for (int j = 0; j < csz; j++) { - ByteCatchList.Item one = catches.get(j); - CstType exceptionClass = one.getExceptionClass(); - parsed(bytes, end, 0, - "catch " + - ((exceptionClass == CstType.OBJECT) ? "<any>" : - exceptionClass.toHuman()) + " -> " + - Hex.u2(one.getHandlerPc())); - } - - changeIndent(-1); - byteAt = end; - } - - int end = bytes.size(); - if (byteAt < end) { - parsed(bytes, byteAt, end - byteAt, - "dead code " + Hex.u2(byteAt) + ".." + Hex.u2(end)); - } - - suppressDump = true; - } - - /** - * Does a registerizing dump. - * - * @param meth non-null; method data to dump - */ - private void ropDump(ConcreteMethod meth) { - BytecodeArray code = meth.getCode(); - ByteArray bytes = code.getBytes(); - - TranslationAdvice advice = DexTranslationAdvice.THE_ONE; - - RopMethod rmeth = - Ropper.convert(meth, advice); - StringBuffer sb = new StringBuffer(2000); - - if (optimize) { - boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags()); - - int paramWidth = computeParamWidth(meth, isStatic); - rmeth = Optimizer.optimize(rmeth, paramWidth, isStatic, true, - advice); - } - - BasicBlockList blocks = rmeth.getBlocks(); - - sb.append("first " + Hex.u2(rmeth.getFirstLabel()) + "\n"); - - int sz = blocks.size(); - for (int i = 0; i < sz; i++) { - BasicBlock bb = blocks.get(i); - int label = bb.getLabel(); - sb.append("block "); - sb.append(Hex.u2(label)); - sb.append("\n"); - - IntList preds = rmeth.labelToPredecessors(label); - int psz = preds.size(); - for (int j = 0; j < psz; j++) { - sb.append(" pred "); - sb.append(Hex.u2(preds.get(j))); - sb.append("\n"); - } - - InsnList il = bb.getInsns(); - int ilsz = il.size(); - for (int j = 0; j < ilsz; j++) { - Insn one = il.get(j); - sb.append(" "); - sb.append(il.get(j).toHuman()); - sb.append("\n"); - } - - IntList successors = bb.getSuccessors(); - int ssz = successors.size(); - if (ssz == 0) { - sb.append(" returns\n"); - } else { - int primary = bb.getPrimarySuccessor(); - for (int j = 0; j < ssz; j++) { - int succ = successors.get(j); - sb.append(" next "); - sb.append(Hex.u2(succ)); - - if ((ssz != 1) && (succ == primary)) { - sb.append(" *"); - } - - sb.append("\n"); - } - } - } - - suppressDump = false; - setAt(bytes, 0); - parsed(bytes, 0, bytes.size(), sb.toString()); - suppressDump = true; - } -} diff --git a/dx/src/com/android/dx/command/dump/ClassDumper.java b/dx/src/com/android/dx/command/dump/ClassDumper.java deleted file mode 100644 index 10dacf374..000000000 --- a/dx/src/com/android/dx/command/dump/ClassDumper.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.android.dx.command.dump; - -import com.android.dx.cf.direct.DirectClassFile; -import com.android.dx.cf.direct.StdAttributeFactory; -import com.android.dx.util.ByteArray; - -import java.io.PrintStream; - -/** - * Utility to dump the contents of class files in a human-friendly form. - */ -public final class ClassDumper - extends BaseDumper { - /** - * Dumps the given array, interpreting it as a class file. - * - * @param bytes non-null; bytes of the (alleged) class file - * @param out non-null; where to dump to - * passed in as <= 0 - * @param filePath the file path for the class, excluding any base - * directory specification - * @param args bag of commandline arguments - */ - public static void dump(byte[] bytes, PrintStream out, - String filePath, Args args) { - ClassDumper cd = - new ClassDumper(bytes, out, filePath, args); - cd.dump(); - } - - /** - * Constructs an instance. This class is not publicly instantiable. - * Use {@link #dump}. - */ - private ClassDumper(byte[] bytes, PrintStream out, - String filePath, Args args) { - super(bytes, out, filePath, args); - } - - /** - * Does the dumping. - */ - public void dump() { - byte[] bytes = getBytes(); - ByteArray ba = new ByteArray(bytes); - DirectClassFile cf = - new DirectClassFile(ba, getFilePath(), getStrictParse()); - - cf.setAttributeFactory(StdAttributeFactory.THE_ONE); - cf.setObserver(this); - cf.getMagic(); // Force parsing to happen. - - int at = getAt(); - if (at != bytes.length) { - parsed(ba, at, bytes.length - at, "<extra data at end of file>"); - } - } -} diff --git a/dx/src/com/android/dx/command/dump/DotDumper.java b/dx/src/com/android/dx/command/dump/DotDumper.java deleted file mode 100644 index 87c529816..000000000 --- a/dx/src/com/android/dx/command/dump/DotDumper.java +++ /dev/null @@ -1,170 +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.android.dx.command.dump; - -import com.android.dx.cf.code.ConcreteMethod; -import com.android.dx.cf.code.Ropper; -import com.android.dx.cf.direct.DirectClassFile; -import com.android.dx.cf.direct.StdAttributeFactory; -import com.android.dx.cf.iface.Member; -import com.android.dx.cf.iface.Method; -import com.android.dx.cf.iface.ParseObserver; -import com.android.dx.rop.code.BasicBlock; -import com.android.dx.rop.code.BasicBlockList; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.DexTranslationAdvice; -import com.android.dx.rop.code.TranslationAdvice; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.ssa.Optimizer; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; - -/** - * Dumps the pred/succ graph of methods into a format compatible - * with the popular graph utility "dot". - */ -public class DotDumper implements ParseObserver { - - DirectClassFile classFile; - - byte[] bytes; - String filePath; - boolean strictParse; - boolean optimize; - Args args; - - static void dump (byte[] bytes, String filePath, Args args) { - new DotDumper(bytes, filePath, args).run(); - } - - DotDumper(byte[] bytes, String filePath, Args args) { - this.bytes = bytes; - this.filePath = filePath; - this.strictParse = args.strictParse; - this.optimize = args.optimize; - this.args = args; - } - - - private void run() { - ByteArray ba = new ByteArray(bytes); - - /* - * First, parse the file completely, so we can safely refer to - * attributes, etc. - */ - classFile = new DirectClassFile(ba, filePath, strictParse); - classFile.setAttributeFactory(StdAttributeFactory.THE_ONE); - classFile.getMagic(); // Force parsing to happen. - - // Next, reparse it and observe the process. - DirectClassFile liveCf = - new DirectClassFile(ba, filePath, strictParse); - liveCf.setAttributeFactory(StdAttributeFactory.THE_ONE); - liveCf.setObserver(this); - liveCf.getMagic(); // Force parsing to happen. - } - - /** - * @param name method name - * @return true if this method should be dumped - */ - protected boolean shouldDumpMethod(String name) { - return args.method == null || args.method.equals(name); - } - - public void changeIndent(int indentDelta) { - - } - - public void parsed(ByteArray bytes, int offset, int len, String human) { - - } - - /** {@inheritDoc} */ - public void startParsingMember(ByteArray bytes, int offset, String name, - String descriptor) { - - } - - public void endParsingMember(ByteArray bytes, int offset, String name, - String descriptor, Member member) { - if (!(member instanceof Method)) { - return; - } - - if (!shouldDumpMethod(name)) { - return; - } - - ConcreteMethod meth = new ConcreteMethod((Method) member, classFile, - true, true); - - TranslationAdvice advice = DexTranslationAdvice.THE_ONE; - RopMethod rmeth = - Ropper.convert(meth, advice); - - if (optimize) { - boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags()); - rmeth = Optimizer.optimize(rmeth, - BaseDumper.computeParamWidth(meth, isStatic), isStatic, - true, advice); - } - - System.out.println("digraph " + name + "{"); - - System.out.println("\tfirst -> n" - + Hex.u2(rmeth.getFirstLabel()) + ";"); - - BasicBlockList blocks = rmeth.getBlocks(); - - int sz = blocks.size(); - for (int i = 0; i < sz; i++) { - BasicBlock bb = blocks.get(i); - int label = bb.getLabel(); - IntList successors = bb.getSuccessors(); - - if (successors.size() == 0) { - System.out.println("\tn" + Hex.u2(label) + " -> returns;"); - } else if (successors.size() == 1) { - System.out.println("\tn" + Hex.u2(label) + " -> n" - + Hex.u2(successors.get(0)) + ";"); - } else { - System.out.print("\tn" + Hex.u2(label) + " -> {"); - for (int j = 0; j < successors.size(); j++ ) { - int successor = successors.get(j); - - if (successor != bb.getPrimarySuccessor()) { - System.out.print(" n" + Hex.u2(successor) + " "); - } - - } - System.out.println("};"); - - System.out.println("\tn" + Hex.u2(label) + " -> n" - + Hex.u2(bb.getPrimarySuccessor()) - + " [label=\"primary\"];"); - - - } - } - - System.out.println("}"); - - } -} diff --git a/dx/src/com/android/dx/command/dump/Main.java b/dx/src/com/android/dx/command/dump/Main.java deleted file mode 100644 index 1ea26bc94..000000000 --- a/dx/src/com/android/dx/command/dump/Main.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.android.dx.command.dump; - -import com.android.dx.cf.iface.ParseException; -import com.android.dx.util.FileUtils; -import com.android.dx.util.HexParser; - -import java.io.UnsupportedEncodingException; - -/** - * Main class for the class file dumper. - */ -public class Main { - - static Args parsedArgs = new Args(); - - /** - * This class is uninstantiable. - */ - private Main() { - // This space intentionally left blank. - } - - /** - * Run! - */ - public static void main(String[] args) { - int at = 0; - - for (/*at*/; at < args.length; at++) { - String arg = args[at]; - if (arg.equals("--") || !arg.startsWith("--")) { - break; - } else if (arg.equals("--bytes")) { - parsedArgs.rawBytes = true; - } else if (arg.equals("--basic-blocks")) { - parsedArgs.basicBlocks = true; - } else if (arg.equals("--rop-blocks")) { - parsedArgs.ropBlocks = true; - } else if (arg.equals("--optimize")) { - parsedArgs.optimize = true; - } else if (arg.equals("--ssa-blocks")) { - parsedArgs.ssaBlocks = true; - } else if (arg.startsWith("--ssa-step=")) { - parsedArgs.ssaStep = arg.substring(arg.indexOf('=') + 1); - } else if (arg.equals("--debug")) { - parsedArgs.debug = true; - } else if (arg.equals("--dot")) { - parsedArgs.dotDump = true; - } else if (arg.equals("--strict")) { - parsedArgs.strictParse = true; - } else if (arg.startsWith("--width=")) { - arg = arg.substring(arg.indexOf('=') + 1); - parsedArgs.width = Integer.parseInt(arg); - } else if (arg.startsWith("--method=")) { - arg = arg.substring(arg.indexOf('=') + 1); - parsedArgs.method = arg; - } else { - System.err.println("unknown option: " + arg); - throw new RuntimeException("usage"); - } - } - - if (at == args.length) { - System.err.println("no input files specified"); - throw new RuntimeException("usage"); - } - - for (/*at*/; at < args.length; at++) { - try { - String name = args[at]; - System.out.println("reading " + name + "..."); - byte[] bytes = FileUtils.readFile(name); - if (!name.endsWith(".class")) { - String src; - try { - src = new String(bytes, "utf-8"); - } catch (UnsupportedEncodingException ex) { - throw new RuntimeException("shouldn't happen", ex); - } - bytes = HexParser.parse(src); - } - processOne(name, bytes); - } catch (ParseException ex) { - System.err.println("\ntrouble parsing:"); - if (parsedArgs.debug) { - ex.printStackTrace(); - } else { - ex.printContext(System.err); - } - } - } - } - - /** - * Processes one file. - * - * @param name non-null; name of the file - * @param bytes non-null; contents of the file - */ - private static void processOne(String name, byte[] bytes) { - if (parsedArgs.dotDump) { - DotDumper.dump(bytes, name, parsedArgs); - } else if (parsedArgs.basicBlocks) { - BlockDumper.dump(bytes, System.out, name, false, parsedArgs); - } else if (parsedArgs.ropBlocks) { - BlockDumper.dump(bytes, System.out, name, true, parsedArgs); - } else if (parsedArgs.ssaBlocks) { - // --optimize ignored with --ssa-blocks - parsedArgs.optimize = false; - SsaDumper.dump(bytes, System.out, name, parsedArgs); - } else { - ClassDumper.dump(bytes, System.out, name, parsedArgs); - } - } -} diff --git a/dx/src/com/android/dx/command/dump/SsaDumper.java b/dx/src/com/android/dx/command/dump/SsaDumper.java deleted file mode 100644 index 95442a174..000000000 --- a/dx/src/com/android/dx/command/dump/SsaDumper.java +++ /dev/null @@ -1,160 +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.android.dx.command.dump; - -import com.android.dx.cf.code.ConcreteMethod; -import com.android.dx.cf.code.Ropper; -import com.android.dx.cf.iface.Member; -import com.android.dx.cf.iface.Method; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.TranslationAdvice; -import com.android.dx.rop.code.DexTranslationAdvice; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.ssa.DeadCodeRemover; -import com.android.dx.ssa.PhiTypeResolver; -import com.android.dx.ssa.SsaBasicBlock; -import com.android.dx.ssa.SsaConverter; -import com.android.dx.ssa.SsaInsn; -import com.android.dx.ssa.SsaMethod; -import com.android.dx.ssa.Optimizer; -import com.android.dx.ssa.ConstCollector; -import com.android.dx.ssa.SCCP; -import com.android.dx.ssa.LiteralOpUpgrader; -import com.android.dx.ssa.back.SsaToRop; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; - -import java.io.PrintStream; -import java.util.BitSet; -import java.util.EnumSet; - -public class SsaDumper extends BlockDumper { - - public static void dump(byte[] bytes, PrintStream out, - String filePath, Args args) { - - SsaDumper sd = - new SsaDumper(bytes, out, filePath, args); - sd.dump(); - } - - SsaDumper(byte[] bytes, PrintStream out, String filePath, Args args) { - - super(bytes, out, filePath, true, args); - - } - - /** {@inheritDoc} */ - @Override - public void endParsingMember(ByteArray bytes, int offset, String name, - String descriptor, Member member) { - if (!(member instanceof Method)) { - return; - } - - if (!shouldDumpMethod(name)) { - return; - } - - ConcreteMethod meth = new ConcreteMethod((Method) member, classFile, - true, true); - - TranslationAdvice advice = DexTranslationAdvice.THE_ONE; - - RopMethod rmeth = Ropper.convert(meth, advice); - - SsaMethod ssaMeth = null; - - boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags()); - int paramWidth = computeParamWidth(meth, isStatic); - if (args.ssaStep == null) { - ssaMeth = Optimizer.debugNoRegisterAllocation(rmeth, - paramWidth, isStatic, true, advice, - EnumSet.allOf(Optimizer.OptionalStep.class)); - } else if ("edge-split".equals(args.ssaStep)) { - ssaMeth = Optimizer.debugEdgeSplit(rmeth, paramWidth, - isStatic, true, advice); - } else if ("phi-placement".equals(args.ssaStep)) { - ssaMeth = Optimizer.debugPhiPlacement( - rmeth, paramWidth, isStatic, true, advice); - } else if ("renaming".equals(args.ssaStep)) { - ssaMeth = Optimizer.debugRenaming( - rmeth, paramWidth, isStatic, true, advice); - } else if ("dead-code".equals(args.ssaStep)) { - ssaMeth = Optimizer.debugDeadCodeRemover( - rmeth, paramWidth, isStatic,true, advice); - } - - StringBuffer sb = new StringBuffer(2000); - - sb.append("first "); - sb.append(Hex.u2( - ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex()))); - sb.append('\n'); - - for (SsaBasicBlock block : ssaMeth.getBlocks()) { - sb.append("block ") - .append(Hex.u2(block.getRopLabel())).append('\n'); - - BitSet preds = block.getPredecessors(); - - for(int i=preds.nextSetBit(0); i>=0; i=preds.nextSetBit(i+1)) { - sb.append (" pred "); - sb.append (Hex.u2(ssaMeth.blockIndexToRopLabel(i))); - sb.append('\n'); - } - - sb.append (" live in:" + block.getLiveInRegs()); - sb.append ("\n"); - - for (SsaInsn insn: block.getInsns()) { - sb.append(" "); - sb.append(insn.toHuman()); - sb.append('\n'); - } - - if (block.getSuccessors().cardinality() == 0) { - sb.append (" returns\n"); - } else { - int primary = block.getPrimarySuccessorRopLabel(); - - IntList succLabelList = block.getRopLabelSuccessorList(); - - int szSuccLabels = succLabelList.size(); - - for (int i = 0; i < szSuccLabels; i++) { - sb.append (" next "); - sb.append (Hex.u2(succLabelList.get(i))); - - if (szSuccLabels != 1 && primary == succLabelList.get(i)) { - sb.append (" *"); - } - sb.append('\n'); - } - } - - sb.append (" live out:" + block.getLiveOutRegs()); - sb.append ("\n"); - } - - suppressDump = false; - setAt(bytes, 0); - parsed(bytes, 0, bytes.size(), sb.toString()); - suppressDump = true; - } -} diff --git a/dx/src/com/android/dx/dex/cf/AttributeTranslator.java b/dx/src/com/android/dx/dex/cf/AttributeTranslator.java deleted file mode 100644 index dab15c9a0..000000000 --- a/dx/src/com/android/dx/dex/cf/AttributeTranslator.java +++ /dev/null @@ -1,416 +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.android.dx.dex.cf; - -import com.android.dx.cf.attrib.AttAnnotationDefault; -import com.android.dx.cf.attrib.AttEnclosingMethod; -import com.android.dx.cf.attrib.AttExceptions; -import com.android.dx.cf.attrib.AttInnerClasses; -import com.android.dx.cf.attrib.AttRuntimeInvisibleAnnotations; -import com.android.dx.cf.attrib.AttRuntimeInvisibleParameterAnnotations; -import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations; -import com.android.dx.cf.attrib.AttRuntimeVisibleParameterAnnotations; -import com.android.dx.cf.attrib.AttSignature; -import com.android.dx.cf.attrib.InnerClassList; -import com.android.dx.cf.direct.DirectClassFile; -import com.android.dx.cf.direct.StdAttributeFactory; -import com.android.dx.cf.iface.AttributeList; -import com.android.dx.cf.iface.Method; -import com.android.dx.cf.iface.MethodList; -import com.android.dx.dex.file.AnnotationUtils; -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.AnnotationVisibility; -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.Warning; - -import java.util.ArrayList; - -/** - * Utility methods that translate various classfile attributes - * into forms suitable for use in creating <code>dex</code> files. - */ -/*package*/ class AttributeTranslator { - /** - * This class is uninstantiable. - */ - private AttributeTranslator() { - // This space intentionally left blank. - } - - /** - * Gets the list of thrown exceptions for a given method. - * - * @param method non-null; the method in question - * @return non-null; the list of thrown exceptions - */ - public static TypeList getExceptions(Method method) { - AttributeList attribs = method.getAttributes(); - AttExceptions exceptions = (AttExceptions) - attribs.findFirst(AttExceptions.ATTRIBUTE_NAME); - - if (exceptions == null) { - return StdTypeList.EMPTY; - } - - return exceptions.getExceptions(); - } - - /** - * Gets the annotations out of a given {@link AttributeList}. This - * combines both visible and invisible annotations into a single - * result set and also adds in a system annotation for the - * <code>Signature</code> attribute if present. - * - * @param attribs non-null; the attributes list to search in - * @return non-null; the set of annotations, which may be empty - */ - public static Annotations getAnnotations(AttributeList attribs) { - Annotations result = getAnnotations0(attribs); - Annotation signature = getSignature(attribs); - - if (signature != null) { - result = Annotations.combine(result, signature); - } - - return result; - } - - /** - * Gets the annotations out of a given class, similar to {@link - * #getAnnotations}, also including annotations for translations - * of class-level attributes <code>EnclosingMethod</code> and - * <code>InnerClasses</code>, if present. Additionally, if the - * class is an annotation class, then this also includes a - * representation of all the <code>AnnotationDefault</code> - * values. - * - * @param cf non-null; the class in question - * @param args non-null; the high-level options - * @return non-null; the set of annotations, which may be empty - */ - public static Annotations getClassAnnotations(DirectClassFile cf, - CfOptions args) { - CstType thisClass = cf.getThisClass(); - AttributeList attribs = cf.getAttributes(); - Annotations result = getAnnotations(attribs); - Annotation enclosingMethod = translateEnclosingMethod(attribs); - - try { - Annotations innerClassAnnotations = - translateInnerClasses(thisClass, attribs, - enclosingMethod == null); - if (innerClassAnnotations != null) { - result = Annotations.combine(result, innerClassAnnotations); - } - } catch (Warning warn) { - args.warn.println("warning: " + warn.getMessage()); - } - - if (enclosingMethod != null) { - result = Annotations.combine(result, enclosingMethod); - } - - if (AccessFlags.isAnnotation(cf.getAccessFlags())) { - Annotation annotationDefault = - translateAnnotationDefaults(cf); - if (annotationDefault != null) { - result = Annotations.combine(result, annotationDefault); - } - } - - return result; - } - - /** - * Gets the annotations out of a given method, similar to {@link - * #getAnnotations}, also including an annotation for the translation - * of the method-specific attribute <code>Exceptions</code>. - * - * @param method non-null; the method in question - * @return non-null; the set of annotations, which may be empty - */ - public static Annotations getMethodAnnotations(Method method) { - Annotations result = getAnnotations(method.getAttributes()); - TypeList exceptions = getExceptions(method); - - if (exceptions.size() != 0) { - Annotation throwsAnnotation = - AnnotationUtils.makeThrows(exceptions); - result = Annotations.combine(result, throwsAnnotation); - } - - return result; - } - - /** - * Helper method for {@link #getAnnotations} which just gets the - * existing annotations, per se. - * - * @param attribs non-null; the attributes list to search in - * @return non-null; the set of annotations, which may be empty - */ - private static Annotations getAnnotations0(AttributeList attribs) { - AttRuntimeVisibleAnnotations visible = - (AttRuntimeVisibleAnnotations) - attribs.findFirst(AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME); - AttRuntimeInvisibleAnnotations invisible = - (AttRuntimeInvisibleAnnotations) - attribs.findFirst(AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME); - - if (visible == null) { - if (invisible == null) { - return Annotations.EMPTY; - } - return invisible.getAnnotations(); - } - - if (invisible == null) { - return visible.getAnnotations(); - } - - // Both are non-null, so combine them. - - return Annotations.combine(visible.getAnnotations(), - invisible.getAnnotations()); - } - - /** - * Gets the <code>Signature</code> attribute out of a given - * {@link AttributeList}, if any, translating it to an annotation. - * - * @param attribs non-null; the attributes list to search in - * @return null-ok; the converted <code>Signature</code> annotation, - * if there was an attribute to translate - */ - private static Annotation getSignature(AttributeList attribs) { - AttSignature signature = (AttSignature) - attribs.findFirst(AttSignature.ATTRIBUTE_NAME); - - if (signature == null) { - return null; - } - - return AnnotationUtils.makeSignature(signature.getSignature()); - } - - /** - * Gets the <code>EnclosingMethod</code> attribute out of a given - * {@link AttributeList}, if any, translating it to an annotation. - * If the class really has an enclosing method, this returns an - * <code>EnclosingMethod</code> annotation; if not, this returns - * an <code>EnclosingClass</code> annotation. - * - * @param attribs non-null; the attributes list to search in - * @return null-ok; the converted <code>EnclosingMethod</code> or - * <code>EnclosingClass</code> annotation, if there was an - * attribute to translate - */ - private static Annotation translateEnclosingMethod(AttributeList attribs) { - AttEnclosingMethod enclosingMethod = (AttEnclosingMethod) - attribs.findFirst(AttEnclosingMethod.ATTRIBUTE_NAME); - - if (enclosingMethod == null) { - return null; - } - - CstType enclosingClass = enclosingMethod.getEnclosingClass(); - CstNat nat = enclosingMethod.getMethod(); - - if (nat == null) { - /* - * Dalvik doesn't use EnclosingMethod annotations unless - * there really is an enclosing method. Anonymous classes - * are unambiguously identified by having an InnerClass - * annotation with an empty name along with an appropriate - * EnclosingClass. - */ - return AnnotationUtils.makeEnclosingClass(enclosingClass); - } - - return AnnotationUtils.makeEnclosingMethod( - new CstMethodRef(enclosingClass, nat)); - } - - /** - * Gets the <code>InnerClasses</code> attribute out of a given - * {@link AttributeList}, if any, translating it to one or more of an - * <code>InnerClass</code>, <code>EnclosingClass</code>, or - * <code>MemberClasses</code> annotation. - * - * @param thisClass non-null; type representing the class being processed - * @param attribs non-null; the attributes list to search in - * @param needEnclosingClass whether to include an - * <code>EnclosingClass</code> annotation - * @return null-ok; the converted list of annotations, if there - * was an attribute to translate - */ - private static Annotations translateInnerClasses(CstType thisClass, - AttributeList attribs, boolean needEnclosingClass) { - AttInnerClasses innerClasses = (AttInnerClasses) - attribs.findFirst(AttInnerClasses.ATTRIBUTE_NAME); - - if (innerClasses == null) { - return null; - } - - /* - * Search the list for the element representing the current class - * as well as for any named member classes. - */ - - InnerClassList list = innerClasses.getInnerClasses(); - int size = list.size(); - InnerClassList.Item foundThisClass = null; - ArrayList<Type> membersList = new ArrayList<Type>(); - - for (int i = 0; i < size; i++) { - InnerClassList.Item item = list.get(i); - CstType innerClass = item.getInnerClass(); - if (innerClass.equals(thisClass)) { - foundThisClass = item; - } else if (thisClass.equals(item.getOuterClass())) { - membersList.add(innerClass.getClassType()); - } - } - - int membersSize = membersList.size(); - - if ((foundThisClass == null) && (membersSize == 0)) { - return null; - } - - Annotations result = new Annotations(); - - if (foundThisClass != null) { - result.add(AnnotationUtils.makeInnerClass( - foundThisClass.getInnerName(), - foundThisClass.getAccessFlags())); - if (needEnclosingClass) { - CstType outer = foundThisClass.getOuterClass(); - if (outer == null) { - throw new Warning( - "Ignoring InnerClasses attribute for an " + - "anonymous inner class that doesn't come with " + - "an associated EnclosingMethod attribute. " + - "(This class was probably produced by a broken " + - "compiler.)"); - } - result.add(AnnotationUtils.makeEnclosingClass( - foundThisClass.getOuterClass())); - } - } - - if (membersSize != 0) { - StdTypeList typeList = new StdTypeList(membersSize); - for (int i = 0; i < membersSize; i++) { - typeList.set(i, membersList.get(i)); - } - typeList.setImmutable(); - result.add(AnnotationUtils.makeMemberClasses(typeList)); - } - - result.setImmutable(); - return result; - } - - /** - * Gets the parameter annotations out of a given method. This - * combines both visible and invisible annotations into a single - * result set. - * - * @param method non-null; the method in question - * @return non-null; the list of annotation sets, which may be empty - */ - public static AnnotationsList getParameterAnnotations(Method method) { - AttributeList attribs = method.getAttributes(); - AttRuntimeVisibleParameterAnnotations visible = - (AttRuntimeVisibleParameterAnnotations) - attribs.findFirst( - AttRuntimeVisibleParameterAnnotations.ATTRIBUTE_NAME); - AttRuntimeInvisibleParameterAnnotations invisible = - (AttRuntimeInvisibleParameterAnnotations) - attribs.findFirst( - AttRuntimeInvisibleParameterAnnotations.ATTRIBUTE_NAME); - - if (visible == null) { - if (invisible == null) { - return AnnotationsList.EMPTY; - } - return invisible.getParameterAnnotations(); - } - - if (invisible == null) { - return visible.getParameterAnnotations(); - } - - // Both are non-null, so combine them. - - return AnnotationsList.combine(visible.getParameterAnnotations(), - invisible.getParameterAnnotations()); - } - - /** - * Gets the <code>AnnotationDefault</code> attributes out of a - * given class, if any, reforming them as an - * <code>AnnotationDefault</code> annotation. - * - * @param cf non-null; the class in question - * @return null-ok; an appropriately-constructed - * <code>AnnotationDefault</code> annotation, if there were any - * annotation defaults in the class, or <code>null<code> if not - */ - private static Annotation translateAnnotationDefaults(DirectClassFile cf) { - CstType thisClass = cf.getThisClass(); - MethodList methods = cf.getMethods(); - int sz = methods.size(); - Annotation result = - new Annotation(thisClass, AnnotationVisibility.EMBEDDED); - boolean any = false; - - for (int i = 0; i < sz; i++) { - Method one = methods.get(i); - AttributeList attribs = one.getAttributes(); - AttAnnotationDefault oneDefault = (AttAnnotationDefault) - attribs.findFirst(AttAnnotationDefault.ATTRIBUTE_NAME); - - if (oneDefault != null) { - NameValuePair pair = new NameValuePair( - one.getNat().getName(), - oneDefault.getValue()); - result.add(pair); - any = true; - } - } - - if (! any) { - return null; - } - - result.setImmutable(); - return AnnotationUtils.makeAnnotationDefault(result); - } -} diff --git a/dx/src/com/android/dx/dex/cf/CfOptions.java b/dx/src/com/android/dx/dex/cf/CfOptions.java deleted file mode 100644 index 8726223f1..000000000 --- a/dx/src/com/android/dx/dex/cf/CfOptions.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.android.dx.dex.cf; - -import com.android.dx.dex.code.PositionList; - -import java.io.PrintStream; - -/** - * A class to contain options passed into dex.cf - */ -public class CfOptions { - /** how much source position info to preserve */ - public int positionInfo = PositionList.LINES; - - /** whether to keep local variable information */ - public boolean localInfo = false; - - /** whether strict file-name-vs-class-name checking should be done */ - public boolean strictNameCheck = true; - - /** whether to do SSA/register optimization */ - public boolean optimize = false; - - /** filename containing list of methods to optimize */ - public String optimizeListFile = null; - - /** filename containing list of methods <i>not</i> to optimize */ - public String dontOptimizeListFile = null; - - /** whether to print statistics to stdout at end of compile cycle */ - public boolean statistics; - - /** where to issue warnings to */ - public PrintStream warn = System.err; -} diff --git a/dx/src/com/android/dx/dex/cf/CfTranslator.java b/dx/src/com/android/dx/dex/cf/CfTranslator.java deleted file mode 100644 index c48be53e3..000000000 --- a/dx/src/com/android/dx/dex/cf/CfTranslator.java +++ /dev/null @@ -1,383 +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.android.dx.dex.cf; - -import com.android.dx.cf.code.ConcreteMethod; -import com.android.dx.cf.code.Ropper; -import com.android.dx.cf.direct.DirectClassFile; -import com.android.dx.cf.direct.StdAttributeFactory; -import com.android.dx.cf.iface.Field; -import com.android.dx.cf.iface.FieldList; -import com.android.dx.cf.iface.Method; -import com.android.dx.cf.iface.MethodList; -import com.android.dx.dex.code.DalvCode; -import com.android.dx.dex.code.PositionList; -import com.android.dx.dex.code.RopTranslator; -import com.android.dx.dex.file.ClassDefItem; -import com.android.dx.dex.file.EncodedField; -import com.android.dx.dex.file.EncodedMethod; -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.code.LocalVariableExtractor; -import com.android.dx.rop.code.LocalVariableInfo; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.DexTranslationAdvice; -import com.android.dx.rop.code.TranslationAdvice; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstBoolean; -import com.android.dx.rop.cst.CstByte; -import com.android.dx.rop.cst.CstChar; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstShort; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.cst.TypedConstant; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.ssa.Optimizer; -import com.android.dx.util.ExceptionWithContext; - -/** - * Static method that turns <code>byte[]</code>s containing Java - * classfiles into {@link ClassDefItem} instances. - */ -public class CfTranslator { - /** set to <code>true</code> to enable development-time debugging code */ - private static final boolean DEBUG = false; - - /** - * This class is uninstantiable. - */ - private CfTranslator() { - // This space intentionally left blank. - } - - /** - * Takes a <code>byte[]</code>, interprets it as a Java classfile, and - * translates it into a {@link ClassDefItem}. - * - * @param filePath non-null; the file path for the class, - * excluding any base directory specification - * @param bytes non-null; contents of the file - * @param args command-line arguments - * @return non-null; the translated class - */ - public static ClassDefItem translate(String filePath, byte[] bytes, - CfOptions args) { - try { - return translate0(filePath, bytes, args); - } catch (RuntimeException ex) { - String msg = "...while processing " + filePath; - throw ExceptionWithContext.withContext(ex, msg); - } - } - - /** - * Performs the main act of translation. This method is separated - * from {@link #translate} just to keep things a bit simpler in - * terms of exception handling. - * - * @param filePath non-null; the file path for the class, - * excluding any base directory specification - * @param bytes non-null; contents of the file - * @param args command-line arguments - * @return non-null; the translated class - */ - private static ClassDefItem translate0(String filePath, byte[] bytes, - CfOptions args) { - DirectClassFile cf = - new DirectClassFile(bytes, filePath, args.strictNameCheck); - - cf.setAttributeFactory(StdAttributeFactory.THE_ONE); - cf.getMagic(); - - OptimizerOptions.loadOptimizeLists(args.optimizeListFile, - args.dontOptimizeListFile); - - // Build up a class to output. - - CstType thisClass = cf.getThisClass(); - int classAccessFlags = cf.getAccessFlags() & ~AccessFlags.ACC_SUPER; - CstUtf8 sourceFile = (args.positionInfo == PositionList.NONE) ? null : - cf.getSourceFile(); - ClassDefItem out = - new ClassDefItem(thisClass, classAccessFlags, - cf.getSuperclass(), cf.getInterfaces(), sourceFile); - - Annotations classAnnotations = - AttributeTranslator.getClassAnnotations(cf, args); - if (classAnnotations.size() != 0) { - out.setClassAnnotations(classAnnotations); - } - - processFields(cf, out); - processMethods(cf, args, out); - - return out; - } - - /** - * Processes the fields of the given class. - * - * @param cf non-null; class being translated - * @param out non-null; output class - */ - private static void processFields(DirectClassFile cf, ClassDefItem out) { - CstType thisClass = cf.getThisClass(); - FieldList fields = cf.getFields(); - int sz = fields.size(); - - for (int i = 0; i < sz; i++) { - Field one = fields.get(i); - try { - CstFieldRef field = new CstFieldRef(thisClass, one.getNat()); - int accessFlags = one.getAccessFlags(); - - if (AccessFlags.isStatic(accessFlags)) { - TypedConstant constVal = one.getConstantValue(); - EncodedField fi = new EncodedField(field, accessFlags); - if (constVal != null) { - constVal = coerceConstant(constVal, field.getType()); - } - out.addStaticField(fi, constVal); - } else { - EncodedField fi = new EncodedField(field, accessFlags); - out.addInstanceField(fi); - } - - Annotations annotations = - AttributeTranslator.getAnnotations(one.getAttributes()); - if (annotations.size() != 0) { - out.addFieldAnnotations(field, annotations); - } - } catch (RuntimeException ex) { - String msg = "...while processing " + one.getName().toHuman() + - " " + one.getDescriptor().toHuman(); - throw ExceptionWithContext.withContext(ex, msg); - } - } - } - - /** - * Helper for {@link #processFields}, which translates constants into - * more specific types if necessary. - * - * @param constant non-null; the constant in question - * @param type non-null; the desired type - */ - private static TypedConstant coerceConstant(TypedConstant constant, - Type type) { - Type constantType = constant.getType(); - - if (constantType.equals(type)) { - return constant; - } - - switch (type.getBasicType()) { - case Type.BT_BOOLEAN: { - return CstBoolean.make(((CstInteger) constant).getValue()); - } - case Type.BT_BYTE: { - return CstByte.make(((CstInteger) constant).getValue()); - } - case Type.BT_CHAR: { - return CstChar.make(((CstInteger) constant).getValue()); - } - case Type.BT_SHORT: { - return CstShort.make(((CstInteger) constant).getValue()); - } - default: { - throw new UnsupportedOperationException("can't coerce " + - constant + " to " + type); - } - } - } - - /** - * Processes the methods of the given class. - * - * @param cf non-null; class being translated - * @param args non-null; command-line args - * @param out non-null; output class - */ - private static void processMethods(DirectClassFile cf, - CfOptions args, ClassDefItem out) { - CstType thisClass = cf.getThisClass(); - MethodList methods = cf.getMethods(); - int sz = methods.size(); - - for (int i = 0; i < sz; i++) { - Method one = methods.get(i); - try { - CstMethodRef meth = new CstMethodRef(thisClass, one.getNat()); - int accessFlags = one.getAccessFlags(); - boolean isStatic = AccessFlags.isStatic(accessFlags); - boolean isPrivate = AccessFlags.isPrivate(accessFlags); - boolean isNative = AccessFlags.isNative(accessFlags); - boolean isAbstract = AccessFlags.isAbstract(accessFlags); - boolean isConstructor = meth.isInstanceInit() || - meth.isClassInit(); - DalvCode code; - - if (isNative || isAbstract) { - // There's no code for native or abstract methods. - code = null; - } else { - ConcreteMethod concrete = - new ConcreteMethod(one, cf, - (args.positionInfo != PositionList.NONE), - args.localInfo); - - TranslationAdvice advice; - - advice = DexTranslationAdvice.THE_ONE; - - RopMethod rmeth = Ropper.convert(concrete, advice); - RopMethod nonOptRmeth = null; - int paramSize; - - paramSize = meth.getParameterWordCount(isStatic); - - String canonicalName - = thisClass.getClassType().getDescriptor() - + "." + one.getName().getString(); - - if (args.optimize && - OptimizerOptions.shouldOptimize(canonicalName)) { - if (DEBUG) { - System.err.println("Optimizing " + canonicalName); - } - - nonOptRmeth = rmeth; - rmeth = Optimizer.optimize(rmeth, - paramSize, isStatic, args.localInfo, advice); - - if (DEBUG) { - OptimizerOptions.compareOptimizerStep(nonOptRmeth, - paramSize, isStatic, args, advice, rmeth); - } - - if (args.statistics) { - CodeStatistics.updateRopStatistics( - nonOptRmeth, rmeth); - } - } - - LocalVariableInfo locals = null; - - if (args.localInfo) { - locals = LocalVariableExtractor.extract(rmeth); - } - - code = RopTranslator.translate(rmeth, args.positionInfo, - locals, paramSize); - - if (args.statistics && nonOptRmeth != null) { - updateDexStatistics(args, rmeth, nonOptRmeth, locals, - paramSize, concrete.getCode().size()); - } - } - - // Preserve the synchronized flag as its "declared" variant... - if (AccessFlags.isSynchronized(accessFlags)) { - accessFlags |= AccessFlags.ACC_DECLARED_SYNCHRONIZED; - - /* - * ...but only native methods are actually allowed to be - * synchronized. - */ - if (!isNative) { - accessFlags &= ~AccessFlags.ACC_SYNCHRONIZED; - } - } - - if (isConstructor) { - accessFlags |= AccessFlags.ACC_CONSTRUCTOR; - } - - TypeList exceptions = AttributeTranslator.getExceptions(one); - EncodedMethod mi = - new EncodedMethod(meth, accessFlags, code, exceptions); - - if (meth.isInstanceInit() || meth.isClassInit() || - isStatic || isPrivate) { - out.addDirectMethod(mi); - } else { - out.addVirtualMethod(mi); - } - - Annotations annotations = - AttributeTranslator.getMethodAnnotations(one); - if (annotations.size() != 0) { - out.addMethodAnnotations(meth, annotations); - } - - AnnotationsList list = - AttributeTranslator.getParameterAnnotations(one); - if (list.size() != 0) { - out.addParameterAnnotations(meth, list); - } - } catch (RuntimeException ex) { - String msg = "...while processing " + one.getName().toHuman() + - " " + one.getDescriptor().toHuman(); - throw ExceptionWithContext.withContext(ex, msg); - } - } - } - - /** - * Helper that updates the dex statistics. - */ - private static void updateDexStatistics(CfOptions args, - RopMethod optRmeth, RopMethod nonOptRmeth, - LocalVariableInfo locals, int paramSize, int originalByteCount) { - /* - * Run rop->dex again on optimized vs. non-optimized method to - * collect statistics. We have to totally convert both ways, - * since converting the "real" method getting added to the - * file would corrupt it (by messing with its constant pool - * indices). - */ - - DalvCode optCode = RopTranslator.translate(optRmeth, - args.positionInfo, locals, paramSize); - DalvCode nonOptCode = RopTranslator.translate(nonOptRmeth, - args.positionInfo, locals, paramSize); - - /* - * Fake out the indices, so code.getInsns() can work well enough - * for the current purpose. - */ - - DalvCode.AssignIndicesCallback callback = - new DalvCode.AssignIndicesCallback() { - public int getIndex(Constant cst) { - // Everything is at index 0! - return 0; - } - }; - - optCode.assignIndices(callback); - nonOptCode.assignIndices(callback); - - CodeStatistics.updateDexStatistics(nonOptCode, optCode); - CodeStatistics.updateOriginalByteCount(originalByteCount); - } -} diff --git a/dx/src/com/android/dx/dex/cf/CodeStatistics.java b/dx/src/com/android/dx/dex/cf/CodeStatistics.java deleted file mode 100644 index fa83100bd..000000000 --- a/dx/src/com/android/dx/dex/cf/CodeStatistics.java +++ /dev/null @@ -1,172 +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.android.dx.dex.cf; - -import com.android.dx.dex.code.DalvCode; -import com.android.dx.rop.code.RopMethod; - -import java.io.PrintStream; - -/** - * Static methods and variables for collecting statistics on generated - * code. - */ -public final class CodeStatistics { - /** set to <code>true</code> to enable development-time debugging code */ - private static final boolean DEBUG = false; - - /** - * running sum of the number of registers added/removed in - * SSA form by the optimizer - */ - public static int runningDeltaRegisters = 0; - - /** - * running sum of the number of insns added/removed in - * SSA form by the optimizer - */ - public static int runningDeltaInsns = 0; - - /** running sum of the total number of Rop insns processed */ - public static int runningTotalInsns = 0; - - /** - * running sum of the number of dex-form registers added/removed in - * SSA form by the optimizer. Only valid if args.statistics is true. - */ - public static int dexRunningDeltaRegisters = 0; - - /** - * running sum of the number of dex-form insns (actually code - * units) added/removed in SSA form by the optimizer. Only valid - * if args.statistics is true. - */ - public static int dexRunningDeltaInsns = 0; - - /** - * running sum of the total number of dex insns (actually code - * units) processed - */ - public static int dexRunningTotalInsns = 0; - - /** running sum of original class bytecode bytes */ - public static int runningOriginalBytes = 0; - - /** - * This class is uninstantiable. - */ - private CodeStatistics() { - // This space intentionally left blank. - } - - /** - * Updates the number of original bytecode bytes processed. - * - * @param count >= 0; the number of bytes to add - */ - public static void updateOriginalByteCount(int count) { - runningOriginalBytes += count; - } - - /** - * Updates the dex statistics. - * - * @param nonOptCode non-optimized code block - * @param code optimized code block - */ - public static void updateDexStatistics(DalvCode nonOptCode, - DalvCode code) { - if (DEBUG) { - System.err.println("dex insns (old/new) " - + nonOptCode.getInsns().codeSize() - + "/" + code.getInsns().codeSize() - + " regs (o/n) " - + nonOptCode.getInsns().getRegistersSize() - + "/" + code.getInsns().getRegistersSize() - ); - } - - dexRunningDeltaInsns - += (code.getInsns().codeSize() - - nonOptCode.getInsns().codeSize()); - - dexRunningDeltaRegisters - += (code.getInsns().getRegistersSize() - - nonOptCode.getInsns().getRegistersSize()); - - dexRunningTotalInsns += code.getInsns().codeSize(); - } - - /** - * Updates the ROP statistics. - * - * @param nonOptRmeth non-optimized method - * @param rmeth optimized method - */ - public static void updateRopStatistics(RopMethod nonOptRmeth, - RopMethod rmeth) { - int oldCountInsns - = nonOptRmeth.getBlocks().getEffectiveInstructionCount(); - int oldCountRegs = nonOptRmeth.getBlocks().getRegCount(); - - if (DEBUG) { - System.err.println("insns (old/new): " - + oldCountInsns + "/" - + rmeth.getBlocks().getEffectiveInstructionCount() - + " regs (o/n):" + oldCountRegs - + "/" + rmeth.getBlocks().getRegCount()); - } - - int newCountInsns - = rmeth.getBlocks().getEffectiveInstructionCount(); - - runningDeltaInsns - += (newCountInsns - oldCountInsns); - - runningDeltaRegisters - += (rmeth.getBlocks().getRegCount() - oldCountRegs); - - runningTotalInsns += newCountInsns; - } - - /** - * Prints out the collected statistics. - * - * @param out non-null; where to output to - */ - public static void dumpStatistics(PrintStream out) { - out.printf("Optimizer Delta Rop Insns: %d total: %d " - + "(%.2f%%) Delta Registers: %d\n", - runningDeltaInsns, - runningTotalInsns, - (100.0 * (((float) runningDeltaInsns) - / (runningTotalInsns + Math.abs(runningDeltaInsns)))), - runningDeltaRegisters); - - out.printf("Optimizer Delta Dex Insns: Insns: %d total: %d " - + "(%.2f%%) Delta Registers: %d\n", - dexRunningDeltaInsns, - dexRunningTotalInsns, - (100.0 * (((float) dexRunningDeltaInsns) - / (dexRunningTotalInsns - + Math.abs(dexRunningDeltaInsns)))), - dexRunningDeltaRegisters); - - out.printf("Original bytecode byte count: %d\n", - runningOriginalBytes); - } -} diff --git a/dx/src/com/android/dx/dex/cf/OptimizerOptions.java b/dx/src/com/android/dx/dex/cf/OptimizerOptions.java deleted file mode 100644 index 1dc3f76a4..000000000 --- a/dx/src/com/android/dx/dex/cf/OptimizerOptions.java +++ /dev/null @@ -1,183 +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.android.dx.dex.cf; - -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.TranslationAdvice; -import com.android.dx.ssa.Optimizer; - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.util.EnumSet; -import java.util.HashSet; - -/** - * Settings for optimization of code. - */ -public class OptimizerOptions { - /** - * null-ok; hash set of class name + method names that should be optimized. - * null if this constraint was not specified on the command line - */ - private static HashSet<String> optimizeList; - - /** - * null-ok; hash set of class name + method names that should NOT - * be optimized. null if this constraint was not specified on the - * command line - */ - private static HashSet<String> dontOptimizeList; - - /** true if the above lists have been loaded */ - private static boolean optimizeListsLoaded; - - /** - * This class is uninstantiable. - */ - private OptimizerOptions() { - // This space intentionally left blank. - } - - /** - * Loads the optimize/don't optimize lists from files. - * - * @param optimizeListFile Pathname - * @param dontOptimizeListFile Pathname - */ - public static void loadOptimizeLists(String optimizeListFile, - String dontOptimizeListFile) { - if (optimizeListsLoaded) { - return; - } - - if (optimizeListFile != null && dontOptimizeListFile != null) { - /* - * We shouldn't get this far. The condition should have - * been caught in the arg processor. - */ - throw new RuntimeException("optimize and don't optimize lists " - + " are mutually exclusive."); - } - - if (optimizeListFile != null) { - optimizeList = loadStringsFromFile(optimizeListFile); - } - - if (dontOptimizeListFile != null) { - dontOptimizeList = loadStringsFromFile(dontOptimizeListFile); - } - - optimizeListsLoaded = true; - } - - /** - * Loads a list of newline-separated strings into a new HashSet and returns - * the HashSet. - * - * @param filename filename to process - * @return set of all unique lines in the file - */ - private static HashSet<String> loadStringsFromFile(String filename) { - HashSet<String> result = new HashSet<String>(); - - try { - FileReader fr = new FileReader(filename); - - BufferedReader bfr = new BufferedReader(fr); - - String line; - - while (null != (line = bfr.readLine())) { - result.add(line); - } - } catch (IOException ex) { - // Let the exception percolate up as a RuntimeException. - throw new RuntimeException("Error with optimize list: " + - filename, ex); - } - - return result; - } - - /** - * Compares the output of the optimizer run normally with a run skipping - * some optional steps. Results are printed to stderr. - * - * @param nonOptRmeth non-null; origional rop method - * @param paramSize >= 0 parameter size of method - * @param isStatic true if this method has no 'this' pointer argument. - * @param args non-null; translator arguments - * @param advice non-null; translation advice - * @param rmeth non-null; method with all optimization steps run. - */ - public static void compareOptimizerStep(RopMethod nonOptRmeth, - int paramSize, boolean isStatic, CfOptions args, - TranslationAdvice advice, RopMethod rmeth) { - EnumSet<Optimizer.OptionalStep> steps; - - steps = EnumSet.allOf(Optimizer.OptionalStep.class); - - // This is the step to skip. - steps.remove(Optimizer.OptionalStep.CONST_COLLECTOR); - - RopMethod skipRopMethod - = Optimizer.optimize(nonOptRmeth, - paramSize, isStatic, args.localInfo, advice, steps); - - int normalInsns - = rmeth.getBlocks().getEffectiveInstructionCount(); - int skipInsns - = skipRopMethod.getBlocks().getEffectiveInstructionCount(); - - System.err.printf( - "optimize step regs:(%d/%d/%.2f%%)" - + " insns:(%d/%d/%.2f%%)\n", - rmeth.getBlocks().getRegCount(), - skipRopMethod.getBlocks().getRegCount(), - 100.0 * ((skipRopMethod.getBlocks().getRegCount() - - rmeth.getBlocks().getRegCount()) - / (float) skipRopMethod.getBlocks().getRegCount()), - normalInsns, skipInsns, - 100.0 * ((skipInsns - normalInsns) / (float) skipInsns)); - } - - /** - * Checks whether the specified method should be optimized - * - * @param canonicalMethodName name of method being considered - * @return true if it should be optimized - */ - public static boolean shouldOptimize(String canonicalMethodName) { - // Optimize only what's in the optimize list. - if (optimizeList != null) { - return optimizeList.contains(canonicalMethodName); - } - - /* - * Or don't optimize what's listed here. (The two lists are - * mutually exclusive. - */ - - if (dontOptimizeList != null) { - return !dontOptimizeList.contains(canonicalMethodName); - } - - // If neither list has been specified, then optimize everything. - return true; - } -} diff --git a/dx/src/com/android/dx/dex/cf/package.html b/dx/src/com/android/dx/dex/cf/package.html deleted file mode 100644 index d56e8a759..000000000 --- a/dx/src/com/android/dx/dex/cf/package.html +++ /dev/null @@ -1,15 +0,0 @@ -<body> -<p>Classes for translating Java classfiles into Dalvik classes.</p> - -<p><b>PACKAGES USED:</b> -<ul> -<li><code>com.android.dx.cf.code</code></li> -<li><code>com.android.dx.cf.direct</code></li> -<li><code>com.android.dx.cf.iface</code></li> -<li><code>com.android.dx.dex.code</code></li> -<li><code>com.android.dx.dex.file</code></li> -<li><code>com.android.dx.rop.code</code></li> -<li><code>com.android.dx.rop.cst</code></li> -<li><code>com.android.dx.util</code></li> -</ul> -</body> diff --git a/dx/src/com/android/dx/dex/code/ArrayData.java b/dx/src/com/android/dx/dex/code/ArrayData.java deleted file mode 100644 index 8476a0361..000000000 --- a/dx/src/com/android/dx/dex/code/ArrayData.java +++ /dev/null @@ -1,199 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.cst.*; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.rop.type.Type; -import java.util.ArrayList; - -/** - * Pseudo-instruction which holds fill array data. - */ -public final class ArrayData extends VariableSizeInsn { - /** - * non-null; address representing the instruction that uses this - * instance - */ - private final CodeAddress user; - - /** non-null; initial values to be filled into an array */ - private final ArrayList<Constant> values; - - /** non-null: type of constant that initializes the array */ - private final Constant arrayType; - - /** Width of the init value element */ - private final int elemWidth; - - /** Length of the init list */ - private final int initLength; - - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param position non-null; source position - * @param user non-null; address representing the instruction that - * uses this instance - * @param values non-null; initial values to be filled into an array - */ - public ArrayData(SourcePosition position, CodeAddress user, - ArrayList<Constant> values, - Constant arrayType) { - super(position, RegisterSpecList.EMPTY); - - if (user == null) { - throw new NullPointerException("user == null"); - } - - if (values == null) { - throw new NullPointerException("values == null"); - } - - int sz = values.size(); - - if (sz <= 0) { - throw new IllegalArgumentException("Illegal number of init values"); - } - - this.arrayType = arrayType; - - if (arrayType == CstType.BYTE_ARRAY || - arrayType == CstType.BOOLEAN_ARRAY) { - elemWidth = 1; - } else if (arrayType == CstType.SHORT_ARRAY || - arrayType == CstType.CHAR_ARRAY) { - elemWidth = 2; - } else if (arrayType == CstType.INT_ARRAY || - arrayType == CstType.FLOAT_ARRAY) { - elemWidth = 4; - } else if (arrayType == CstType.LONG_ARRAY || - arrayType == CstType.DOUBLE_ARRAY) { - elemWidth = 8; - } else { - throw new IllegalArgumentException("Unexpected constant type"); - } - this.user = user; - this.values = values; - initLength = values.size(); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - int sz = initLength; - // Note: the unit here is 16-bit - return 4 + ((sz * elemWidth) + 1) / 2; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out) { - int baseAddress = user.getAddress(); - int sz = values.size(); - - out.writeShort(0x300 | DalvOps.NOP); - out.writeShort(elemWidth); - out.writeInt(initLength); - - - // For speed reasons, replicate the for loop in each case - switch (elemWidth) { - case 1: { - for (int i = 0; i < sz; i++) { - Constant cst = values.get(i); - out.writeByte((byte) ((CstLiteral32) cst).getIntBits()); - } - break; - } - case 2: { - for (int i = 0; i < sz; i++) { - Constant cst = values.get(i); - out.writeShort((short) ((CstLiteral32) cst).getIntBits()); - } - break; - } - case 4: { - for (int i = 0; i < sz; i++) { - Constant cst = values.get(i); - out.writeInt(((CstLiteral32) cst).getIntBits()); - } - break; - } - case 8: { - for (int i = 0; i < sz; i++) { - Constant cst = values.get(i); - out.writeLong(((CstLiteral64) cst).getLongBits()); - } - break; - } - default: - break; - } - - // Pad one byte to make the size of data table multiples of 16-bits - if (elemWidth == 1 && (sz % 2 != 0)) { - out.writeByte(0x00); - } - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisters(RegisterSpecList registers) { - return new ArrayData(getPosition(), user, values, arrayType); - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - StringBuffer sb = new StringBuffer(100); - - int sz = values.size(); - for (int i = 0; i < sz; i++) { - sb.append("\n "); - sb.append(i); - sb.append(": "); - sb.append(values.get(i).toHuman()); - } - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - protected String listingString0(boolean noteIndices) { - int baseAddress = user.getAddress(); - StringBuffer sb = new StringBuffer(100); - int sz = values.size(); - - sb.append("array-data // for fill-array-data @ "); - sb.append(Hex.u2(baseAddress)); - - for (int i = 0; i < sz; i++) { - sb.append("\n "); - sb.append(i); - sb.append(": "); - sb.append(values.get(i).toHuman()); - } - - return sb.toString(); - } -} diff --git a/dx/src/com/android/dx/dex/code/BlockAddresses.java b/dx/src/com/android/dx/dex/code/BlockAddresses.java deleted file mode 100644 index 9fea66c62..000000000 --- a/dx/src/com/android/dx/dex/code/BlockAddresses.java +++ /dev/null @@ -1,143 +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.android.dx.dex.code; - -import com.android.dx.rop.code.BasicBlock; -import com.android.dx.rop.code.BasicBlockList; -import com.android.dx.rop.code.Insn; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.SourcePosition; - -/** - * Container for the set of {@link CodeAddress} instances associated with - * the blocks of a particular method. Each block has a corresponding - * start address, end address, and last instruction address. - */ -public final class BlockAddresses { - /** non-null; array containing addresses for the start of each basic - * block (indexed by basic block label) */ - private final CodeAddress[] starts; - - /** non-null; array containing addresses for the final instruction - * of each basic block (indexed by basic block label) */ - private final CodeAddress[] lasts; - - /** non-null; array containing addresses for the end (just past the - * final instruction) of each basic block (indexed by basic block - * label) */ - private final CodeAddress[] ends; - - /** - * Constructs an instance. - * - * @param method non-null; the method to have block addresses for - */ - public BlockAddresses(RopMethod method) { - BasicBlockList blocks = method.getBlocks(); - int maxLabel = blocks.getMaxLabel(); - - this.starts = new CodeAddress[maxLabel]; - this.lasts = new CodeAddress[maxLabel]; - this.ends = new CodeAddress[maxLabel]; - - setupArrays(method); - } - - /** - * Gets the instance for the start of the given block. - * - * @param block non-null; the block in question - * @return non-null; the appropriate instance - */ - public CodeAddress getStart(BasicBlock block) { - return starts[block.getLabel()]; - } - - /** - * Gets the instance for the start of the block with the given label. - * - * @param label non-null; the label of the block in question - * @return non-null; the appropriate instance - */ - public CodeAddress getStart(int label) { - return starts[label]; - } - - /** - * Gets the instance for the final instruction of the given block. - * - * @param block non-null; the block in question - * @return non-null; the appropriate instance - */ - public CodeAddress getLast(BasicBlock block) { - return lasts[block.getLabel()]; - } - - /** - * Gets the instance for the final instruction of the block with - * the given label. - * - * @param label non-null; the label of the block in question - * @return non-null; the appropriate instance - */ - public CodeAddress getLast(int label) { - return lasts[label]; - } - - /** - * Gets the instance for the end (address after the final instruction) - * of the given block. - * - * @param block non-null; the block in question - * @return non-null; the appropriate instance - */ - public CodeAddress getEnd(BasicBlock block) { - return ends[block.getLabel()]; - } - - /** - * Gets the instance for the end (address after the final instruction) - * of the block with the given label. - * - * @param label non-null; the label of the block in question - * @return non-null; the appropriate instance - */ - public CodeAddress getEnd(int label) { - return ends[label]; - } - - /** - * Sets up the address arrays. - */ - private void setupArrays(RopMethod method) { - BasicBlockList blocks = method.getBlocks(); - int sz = blocks.size(); - - for (int i = 0; i < sz; i++) { - BasicBlock one = blocks.get(i); - int label = one.getLabel(); - Insn insn = one.getInsns().get(0); - - starts[label] = new CodeAddress(insn.getPosition()); - - SourcePosition pos = one.getLastInsn().getPosition(); - - lasts[label] = new CodeAddress(pos); - ends[label] = new CodeAddress(pos); - } - } -} diff --git a/dx/src/com/android/dx/dex/code/CatchBuilder.java b/dx/src/com/android/dx/dex/code/CatchBuilder.java deleted file mode 100644 index 8bc963b5b..000000000 --- a/dx/src/com/android/dx/dex/code/CatchBuilder.java +++ /dev/null @@ -1,48 +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.android.dx.dex.code; - -import com.android.dx.rop.type.Type; - -import java.util.HashSet; - -/** - * Interface for the construction of {@link CatchTable} instances. - */ -public interface CatchBuilder { - /** - * Builds and returns the catch table for this instance. - * - * @return non-null; the constructed table - */ - public CatchTable build(); - - /** - * Gets whether this instance has any catches at all (either typed - * or catch-all). - * - * @return whether this instance has any catches at all - */ - public boolean hasAnyCatches(); - - /** - * Gets the set of catch types associated with this instance. - * - * @return non-null; the set of catch types - */ - public HashSet<Type> getCatchTypes(); -} diff --git a/dx/src/com/android/dx/dex/code/CatchHandlerList.java b/dx/src/com/android/dx/dex/code/CatchHandlerList.java deleted file mode 100644 index 862586c8b..000000000 --- a/dx/src/com/android/dx/dex/code/CatchHandlerList.java +++ /dev/null @@ -1,238 +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.android.dx.dex.code; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.util.FixedSizeList; -import com.android.dx.util.Hex; - -/** - * Ordered list of (exception type, handler address) entries. - */ -public final class CatchHandlerList extends FixedSizeList - implements Comparable<CatchHandlerList> { - /** non-null; empty instance */ - public static final CatchHandlerList EMPTY = new CatchHandlerList(0); - - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size >= 0; the size of the list - */ - public CatchHandlerList(int size) { - super(size); - } - - /** - * Gets the element at the given index. 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</code>. - * - * @param n >= 0, < size(); which index - * @return non-null; element at that index - */ - public Entry get(int n) { - return (Entry) get0(n); - } - - /** {@inheritDoc} */ - public String toHuman() { - return toHuman("", ""); - } - - /** - * Get the human form of this instance, prefixed on each line - * with the string. - * - * @param prefix non-null; the prefix for every line - * @param header non-null; the header for the first line (after the - * first prefix) - * @return non-null; the human form - */ - public String toHuman(String prefix, String header) { - StringBuilder sb = new StringBuilder(100); - int size = size(); - - sb.append(prefix); - sb.append(header); - sb.append("catch "); - - for (int i = 0; i < size; i++) { - Entry entry = get(i); - - if (i != 0) { - sb.append(",\n"); - sb.append(prefix); - sb.append(" "); - } - - if ((i == (size - 1)) && catchesAll()) { - sb.append("<any>"); - } else { - sb.append(entry.getExceptionType().toHuman()); - } - - sb.append(" -> "); - sb.append(Hex.u2or4(entry.getHandler())); - } - - return sb.toString(); - } - - /** - * Returns whether or not this instance ends with a "catch-all" - * handler. - * - * @return <code>true</code> if this instance ends with a "catch-all" - * handler or <code>false</code> if not - */ - public boolean catchesAll() { - int size = size(); - - if (size == 0) { - return false; - } - - Entry last = get(size - 1); - return last.getExceptionType().equals(CstType.OBJECT); - } - - /** - * Sets the entry at the given index. - * - * @param n >= 0, < size(); which index - * @param exceptionType non-null; type of exception handled - * @param handler >= 0; exception handler address - */ - public void set(int n, CstType exceptionType, int handler) { - set0(n, new Entry(exceptionType, handler)); - } - - /** - * Sets the entry at the given index. - * - * @param n >= 0, < size(); which index - * @param entry non-null; the entry to set at <code>n</code> - */ - public void set(int n, Entry entry) { - set0(n, entry); - } - - /** {@inheritDoc} */ - public int compareTo(CatchHandlerList other) { - if (this == other) { - // Easy out. - return 0; - } - - int thisSize = size(); - int otherSize = other.size(); - int checkSize = Math.min(thisSize, otherSize); - - for (int i = 0; i < checkSize; i++) { - Entry thisEntry = get(i); - Entry otherEntry = other.get(i); - int compare = thisEntry.compareTo(otherEntry); - if (compare != 0) { - return compare; - } - } - - if (thisSize < otherSize) { - return -1; - } else if (thisSize > otherSize) { - return 1; - } - - return 0; - } - - /** - * Entry in the list. - */ - public static class Entry implements Comparable<Entry> { - /** non-null; type of exception handled */ - private final CstType exceptionType; - - /** >= 0; exception handler address */ - private final int handler; - - /** - * Constructs an instance. - * - * @param exceptionType non-null; type of exception handled - * @param handler >= 0; exception handler address - */ - public Entry(CstType exceptionType, int handler) { - if (handler < 0) { - throw new IllegalArgumentException("handler < 0"); - } - - if (exceptionType == null) { - throw new NullPointerException("exceptionType == null"); - } - - this.handler = handler; - this.exceptionType = exceptionType; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return (handler * 31) + exceptionType.hashCode(); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (other instanceof Entry) { - return (compareTo((Entry) other) == 0); - } - - return false; - } - - /** {@inheritDoc} */ - public int compareTo(Entry other) { - if (handler < other.handler) { - return -1; - } else if (handler > other.handler) { - return 1; - } - - return exceptionType.compareTo(other.exceptionType); - } - - /** - * Gets the exception type handled. - * - * @return non-null; the exception type - */ - public CstType getExceptionType() { - return exceptionType; - } - - /** - * Gets the handler address. - * - * @return >= 0; the handler address - */ - public int getHandler() { - return handler; - } - } -} diff --git a/dx/src/com/android/dx/dex/code/CatchTable.java b/dx/src/com/android/dx/dex/code/CatchTable.java deleted file mode 100644 index 86f9c588b..000000000 --- a/dx/src/com/android/dx/dex/code/CatchTable.java +++ /dev/null @@ -1,192 +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.android.dx.dex.code; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.util.FixedSizeList; - -/** - * Table of catch entries. Each entry includes a range of code - * addresses for which it is valid and an associated {@link - * CatchHandlerList}. - */ -public final class CatchTable extends FixedSizeList - implements Comparable<CatchTable> { - /** non-null; empty instance */ - public static final CatchTable EMPTY = new CatchTable(0); - - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size >= 0; the size of the table - */ - public CatchTable(int size) { - super(size); - } - - /** - * Gets the element at the given index. 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</code>. - * - * @param n >= 0, < size(); which index - * @return non-null; element at that index - */ - public Entry get(int n) { - return (Entry) get0(n); - } - - /** - * Sets the entry at the given index. - * - * @param n >= 0, < size(); which index - * @param entry non-null; the entry to set at <code>n</code> - */ - public void set(int n, Entry entry) { - set0(n, entry); - } - - /** {@inheritDoc} */ - public int compareTo(CatchTable other) { - if (this == other) { - // Easy out. - return 0; - } - - int thisSize = size(); - int otherSize = other.size(); - int checkSize = Math.min(thisSize, otherSize); - - for (int i = 0; i < checkSize; i++) { - Entry thisEntry = get(i); - Entry otherEntry = other.get(i); - int compare = thisEntry.compareTo(otherEntry); - if (compare != 0) { - return compare; - } - } - - if (thisSize < otherSize) { - return -1; - } else if (thisSize > otherSize) { - return 1; - } - - return 0; - } - - /** - * Entry in a catch list. - */ - public static class Entry implements Comparable<Entry> { - /** >= 0; start address */ - private final int start; - - /** > start; end address (exclusive) */ - private final int end; - - /** non-null; list of catch handlers */ - private final CatchHandlerList handlers; - - /** - * Constructs an instance. - * - * @param start >= 0; start address - * @param end > start; end address (exclusive) - * @param handlers non-null; list of catch handlers - */ - public Entry(int start, int end, CatchHandlerList handlers) { - if (start < 0) { - throw new IllegalArgumentException("start < 0"); - } - - if (end <= start) { - throw new IllegalArgumentException("end <= start"); - } - - if (handlers.isMutable()) { - throw new IllegalArgumentException("handlers.isMutable()"); - } - - this.start = start; - this.end = end; - this.handlers = handlers; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int hash = (start * 31) + end; - hash = (hash * 31) + handlers.hashCode(); - return hash; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (other instanceof Entry) { - return (compareTo((Entry) other) == 0); - } - - return false; - } - - /** {@inheritDoc} */ - public int compareTo(Entry other) { - if (start < other.start) { - return -1; - } else if (start > other.start) { - return 1; - } - - if (end < other.end) { - return -1; - } else if (end > other.end) { - return 1; - } - - return handlers.compareTo(other.handlers); - } - - /** - * Gets the start address. - * - * @return >= 0; the start address - */ - public int getStart() { - return start; - } - - /** - * Gets the end address (exclusive). - * - * @return > start; the end address (exclusive) - */ - public int getEnd() { - return end; - } - - /** - * Gets the handlers. - * - * @return non-null; the handlers - */ - public CatchHandlerList getHandlers() { - return handlers; - } - } -} diff --git a/dx/src/com/android/dx/dex/code/CodeAddress.java b/dx/src/com/android/dx/dex/code/CodeAddress.java deleted file mode 100644 index 97309137b..000000000 --- a/dx/src/com/android/dx/dex/code/CodeAddress.java +++ /dev/null @@ -1,57 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; - -/** - * Pseudo-instruction which is used to track an address within a code - * array. Instances are used for such things as branch targets and - * exception handler ranges. Its code size is zero, and so instances - * do not in general directly wind up in any output (either - * human-oriented or binary file). - */ -public final class CodeAddress extends ZeroSizeInsn { - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param position non-null; source position - */ - public CodeAddress(SourcePosition position) { - super(position); - } - - /** {@inheritDoc} */ - @Override - public final DalvInsn withRegisters(RegisterSpecList registers) { - return new CodeAddress(getPosition()); - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - return null; - } - - /** {@inheritDoc} */ - @Override - protected String listingString0(boolean noteIndices) { - return "code-address"; - } -} diff --git a/dx/src/com/android/dx/dex/code/CstInsn.java b/dx/src/com/android/dx/dex/code/CstInsn.java deleted file mode 100644 index 1bc9021ac..000000000 --- a/dx/src/com/android/dx/dex/code/CstInsn.java +++ /dev/null @@ -1,205 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.cst.Constant; - -/** - * Instruction which has a single constant argument in addition - * to all the normal instruction information. - */ -public final class CstInsn extends FixedSizeInsn { - /** non-null; the constant argument for this instruction */ - private final Constant constant; - - /** - * >= -1; the constant pool index for {@link #constant}, or - * <code>-1</code> if not yet set - */ - private int index; - - /** - * >= -1; the constant pool index for the class reference in - * {@link #constant} if any, or <code>-1</code> if not yet set - */ - private int classIndex; - - /** - * Constructs an instance. The output address of this instance is - * initially unknown (<code>-1</code>) as is the constant pool index. - * - * @param opcode the opcode; one of the constants from {@link Dops} - * @param position non-null; source position - * @param registers non-null; register list, including a - * result register if appropriate (that is, registers may be either - * ins or outs) - * @param constant non-null; constant argument - */ - public CstInsn(Dop opcode, SourcePosition position, - RegisterSpecList registers, Constant constant) { - super(opcode, position, registers); - - if (constant == null) { - throw new NullPointerException("constant == null"); - } - - this.constant = constant; - this.index = -1; - this.classIndex = -1; - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withOpcode(Dop opcode) { - CstInsn result = - new CstInsn(opcode, getPosition(), getRegisters(), constant); - - if (index >= 0) { - result.setIndex(index); - } - - if (classIndex >= 0) { - result.setClassIndex(classIndex); - } - - return result; - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisters(RegisterSpecList registers) { - CstInsn result = - new CstInsn(getOpcode(), getPosition(), registers, constant); - - if (index >= 0) { - result.setIndex(index); - } - - if (classIndex >= 0) { - result.setClassIndex(classIndex); - } - - return result; - } - - /** - * Gets the constant argument. - * - * @return non-null; the constant argument - */ - public Constant getConstant() { - return constant; - } - - /** - * Gets the constant's index. It is only valid to call this after - * {@link #setIndex} has been called. - * - * @return >= 0; the constant pool index - */ - public int getIndex() { - if (index < 0) { - throw new RuntimeException("index not yet set for " + constant); - } - - return index; - } - - /** - * Returns whether the constant's index has been set for this instance. - * - * @see #setIndex - * - * @return <code>true</code> iff the index has been set - */ - public boolean hasIndex() { - return (index >= 0); - } - - /** - * Sets the constant's index. It is only valid to call this method once - * per instance. - * - * @param index >= 0; the constant pool index - */ - public void setIndex(int index) { - if (index < 0) { - throw new IllegalArgumentException("index < 0"); - } - - if (this.index >= 0) { - throw new RuntimeException("index already set"); - } - - this.index = index; - } - - /** - * Gets the constant's class index. It is only valid to call this after - * {@link #setClassIndex} has been called. - * - * @return >= 0; the constant's class's constant pool index - */ - public int getClassIndex() { - if (classIndex < 0) { - throw new RuntimeException("class index not yet set"); - } - - return classIndex; - } - - /** - * Returns whether the constant's class index has been set for this - * instance. - * - * @see #setClassIndex - * - * @return <code>true</code> iff the index has been set - */ - public boolean hasClassIndex() { - return (classIndex >= 0); - } - - /** - * Sets the constant's class index. This is the constant pool index - * for the class referred to by this instance's constant. Only - * reference constants have a class, so it is only on instances - * with reference constants that this method should ever be - * called. It is only valid to call this method once per instance. - * - * @param index >= 0; the constant's class's constant pool index - */ - public void setClassIndex(int index) { - if (index < 0) { - throw new IllegalArgumentException("index < 0"); - } - - if (this.classIndex >= 0) { - throw new RuntimeException("class index already set"); - } - - this.classIndex = index; - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - return constant.toHuman(); - } -} diff --git a/dx/src/com/android/dx/dex/code/DalvCode.java b/dx/src/com/android/dx/dex/code/DalvCode.java deleted file mode 100644 index cf6af099b..000000000 --- a/dx/src/com/android/dx/dex/code/DalvCode.java +++ /dev/null @@ -1,232 +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.android.dx.dex.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.type.Type; - -import java.util.HashSet; - -/** - * Container for all the pieces of a concrete method. Each instance - * corresponds to a <code>code</code> structure in a <code>.dex</code> file. - */ -public final class DalvCode { - /** - * how much position info to preserve; one of the static - * constants in {@link PositionList} - */ - private final int positionInfo; - - /** - * null-ok; the instruction list, ready for final processing; - * nulled out in {@link #finishProcessingIfNecessary} - */ - private OutputFinisher unprocessedInsns; - - /** - * non-null; unprocessed catch table; - * nulled out in {@link #finishProcessingIfNecessary} - */ - private CatchBuilder unprocessedCatches; - - /** - * null-ok; catch table; set in - * {@link #finishProcessingIfNecessary} - */ - private CatchTable catches; - - /** - * null-ok; source positions list; set in - * {@link #finishProcessingIfNecessary} - */ - private PositionList positions; - - /** - * null-ok; local variable list; set in - * {@link #finishProcessingIfNecessary} - */ - private LocalList locals; - - /** - * null-ok; the processed instruction list; set in - * {@link #finishProcessingIfNecessary} - */ - private DalvInsnList insns; - - /** - * Constructs an instance. - * - * @param positionInfo how much position info to preserve; one of the - * static constants in {@link PositionList} - * @param unprocessedInsns non-null; the instruction list, ready - * for final processing - * @param unprocessedCatches non-null; unprocessed catch - * (exception handler) table - */ - public DalvCode(int positionInfo, OutputFinisher unprocessedInsns, - CatchBuilder unprocessedCatches) { - if (unprocessedInsns == null) { - throw new NullPointerException("unprocessedInsns == null"); - } - - if (unprocessedCatches == null) { - throw new NullPointerException("unprocessedCatches == null"); - } - - this.positionInfo = positionInfo; - this.unprocessedInsns = unprocessedInsns; - this.unprocessedCatches = unprocessedCatches; - this.catches = null; - this.positions = null; - this.locals = null; - this.insns = null; - } - - /** - * Finish up processing of the method. - */ - private void finishProcessingIfNecessary() { - if (insns != null) { - return; - } - - insns = unprocessedInsns.finishProcessingAndGetList(); - positions = PositionList.make(insns, positionInfo); - locals = LocalList.make(insns); - catches = unprocessedCatches.build(); - - // Let them be gc'ed. - unprocessedInsns = null; - unprocessedCatches = null; - } - - /** - * Assign indices in all instructions that need them, using the - * given callback to perform lookups. This must be called before - * {@link #getInsns}. - * - * @param callback non-null; callback object - */ - public void assignIndices(AssignIndicesCallback callback) { - unprocessedInsns.assignIndices(callback); - } - - /** - * Gets whether this instance has any position data to represent. - * - * @return <code>true</code> iff this instance has any position - * data to represent - */ - public boolean hasPositions() { - return (positionInfo != PositionList.NONE) - && unprocessedInsns.hasAnyPositionInfo(); - } - - /** - * Gets whether this instance has any local variable data to represent. - * - * @return <code>true</code> iff this instance has any local variable - * data to represent - */ - public boolean hasLocals() { - return unprocessedInsns.hasAnyLocalInfo(); - } - - /** - * Gets whether this instance has any catches at all (either typed - * or catch-all). - * - * @return whether this instance has any catches at all - */ - public boolean hasAnyCatches() { - return unprocessedCatches.hasAnyCatches(); - } - - /** - * Gets the set of catch types handled anywhere in the code. - * - * @return non-null; the set of catch types - */ - public HashSet<Type> getCatchTypes() { - return unprocessedCatches.getCatchTypes(); - } - - /** - * Gets the set of all constants referred to by instructions in - * the code. - * - * @return non-null; the set of constants - */ - public HashSet<Constant> getInsnConstants() { - return unprocessedInsns.getAllConstants(); - } - - /** - * Gets the list of instructions. - * - * @return non-null; the instruction list - */ - public DalvInsnList getInsns() { - finishProcessingIfNecessary(); - return insns; - } - - /** - * Gets the catch (exception handler) table. - * - * @return non-null; the catch table - */ - public CatchTable getCatches() { - finishProcessingIfNecessary(); - return catches; - } - - /** - * Gets the source positions list. - * - * @return non-null; the source positions list - */ - public PositionList getPositions() { - finishProcessingIfNecessary(); - return positions; - } - - /** - * Gets the source positions list. - * - * @return non-null; the source positions list - */ - public LocalList getLocals() { - finishProcessingIfNecessary(); - return locals; - } - - /** - * Class used as a callback for {@link #assignIndices}. - */ - public static interface AssignIndicesCallback { - /** - * Gets the index for the given constant. - * - * @param cst non-null; the constant - * @return >= -1; the index or <code>-1</code> if the constant - * shouldn't actually be reified with an index - */ - public int getIndex(Constant cst); - } -} diff --git a/dx/src/com/android/dx/dex/code/DalvInsn.java b/dx/src/com/android/dx/dex/code/DalvInsn.java deleted file mode 100644 index d92219341..000000000 --- a/dx/src/com/android/dx/dex/code/DalvInsn.java +++ /dev/null @@ -1,422 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.TwoColumnOutput; - -/** - * Base class for Dalvik instructions. - */ -public abstract class DalvInsn { - /** - * the actual output address of this instance, if known, or - * <code>-1</code> if not - */ - private int address; - - /** the opcode; one of the constants from {@link Dops} */ - private final Dop opcode; - - /** non-null; source position */ - private final SourcePosition position; - - /** non-null; list of register arguments */ - private final RegisterSpecList registers; - - /** - * Makes a move instruction, appropriate and ideal for the given arguments. - * - * @param position non-null; source position information - * @param dest non-null; destination register - * @param src non-null; source register - * @return non-null; an appropriately-constructed instance - */ - public static SimpleInsn makeMove(SourcePosition position, - RegisterSpec dest, RegisterSpec src) { - boolean category1 = dest.getCategory() == 1; - boolean reference = dest.getType().isReference(); - int destReg = dest.getReg(); - int srcReg = src.getReg(); - Dop opcode; - - if ((srcReg | destReg) < 16) { - opcode = reference ? Dops.MOVE_OBJECT : - (category1 ? Dops.MOVE : Dops.MOVE_WIDE); - } else if (destReg < 256) { - opcode = reference ? Dops.MOVE_OBJECT_FROM16 : - (category1 ? Dops.MOVE_FROM16 : Dops.MOVE_WIDE_FROM16); - } else { - opcode = reference ? Dops.MOVE_OBJECT_16 : - (category1 ? Dops.MOVE_16 : Dops.MOVE_WIDE_16); - } - - return new SimpleInsn(opcode, position, - RegisterSpecList.make(dest, src)); - } - - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * <p><b>Note:</b> In the unlikely event that an instruction takes - * absolutely no registers (e.g., a <code>nop</code> or a - * no-argument no-result static method call), then the given - * register list may be passed as {@link - * RegisterSpecList#EMPTY}.</p> - * - * @param opcode the opcode; one of the constants from {@link Dops} - * @param position non-null; source position - * @param registers non-null; register list, including a - * result register if appropriate (that is, registers may be either - * ins and outs) - */ - public DalvInsn(Dop opcode, SourcePosition position, - RegisterSpecList registers) { - if (opcode == null) { - throw new NullPointerException("opcode == null"); - } - - if (position == null) { - throw new NullPointerException("position == null"); - } - - if (registers == null) { - throw new NullPointerException("registers == null"); - } - - this.address = -1; - this.opcode = opcode; - this.position = position; - this.registers = registers; - } - - /** {@inheritDoc} */ - @Override - public final String toString() { - StringBuffer sb = new StringBuffer(100); - - sb.append(identifierString()); - sb.append(' '); - sb.append(position); - - sb.append(": "); - sb.append(opcode.getName()); - - boolean needComma = false; - if (registers.size() != 0) { - sb.append(registers.toHuman(" ", ", ", null)); - needComma = true; - } - - String extra = argString(); - if (extra != null) { - if (needComma) { - sb.append(','); - } - sb.append(' '); - sb.append(extra); - } - - return sb.toString(); - } - - /** - * Gets whether the address of this instruction is known. - * - * @see #getAddress - * @see #setAddress - */ - public final boolean hasAddress() { - return (address >= 0); - } - - /** - * Gets the output address of this instruction, if it is known. This throws - * a <code>RuntimeException</code> if it has not yet been set. - * - * @see #setAddress - * - * @return >= 0; the output address - */ - public final int getAddress() { - if (address < 0) { - throw new RuntimeException("address not yet known"); - } - - return address; - } - - /** - * Gets the opcode. - * - * @return non-null; the opcode - */ - public final Dop getOpcode() { - return opcode; - } - - /** - * Gets the source position. - * - * @return non-null; the source position - */ - public final SourcePosition getPosition() { - return position; - } - - /** - * Gets the register list for this instruction. - * - * @return non-null; the registers - */ - public final RegisterSpecList getRegisters() { - return registers; - } - - /** - * Returns whether this instance's opcode uses a result register. - * This method is a convenient shorthand for - * <code>getOpcode().hasResult()</code>. - * - * @return <code>true</code> iff this opcode uses a result register - */ - public final boolean hasResult() { - return opcode.hasResult(); - } - - /** - * Gets the minimum distinct registers required for this instruction. - * This assumes that the result (if any) can share registers with the - * sources (if any), that each source register is unique, and that - * (to be explicit here) category-2 values take up two consecutive - * registers. - * - * @return >= 0; the minimum distinct register requirement - */ - public final int getMinimumRegisterRequirement() { - boolean hasResult = hasResult(); - int regSz = registers.size(); - int resultRequirement = hasResult ? registers.get(0).getCategory() : 0; - int sourceRequirement = 0; - - for (int i = hasResult ? 1 : 0; i < regSz; i++) { - sourceRequirement += registers.get(i).getCategory(); - } - - return Math.max(sourceRequirement, resultRequirement); - } - - /** - * Gets the instruction prefix required, if any, to use in a high - * register transformed version of this instance. - * - * @see #hrVersion - * - * @return null-ok; the prefix, if any - */ - public DalvInsn hrPrefix() { - RegisterSpecList regs = registers; - int sz = regs.size(); - - if (hasResult()) { - if (sz == 1) { - return null; - } - regs = regs.withoutFirst(); - } else if (sz == 0) { - return null; - } - - return new HighRegisterPrefix(position, regs); - } - - /** - * Gets the instruction suffix required, if any, to use in a high - * register transformed version of this instance. - * - * @see #hrVersion - * - * @return null-ok; the suffix, if any - */ - public DalvInsn hrSuffix() { - if (hasResult()) { - RegisterSpec r = registers.get(0); - return makeMove(position, r, r.withReg(0)); - } else { - return null; - } - } - - /** - * Gets the instruction that is equivalent to this one, except that - * uses sequential registers starting at <code>0</code> (storing - * the result, if any, in register <code>0</code> as well). The - * sequence of instructions from {@link #hrPrefix} and {@link - * #hrSuffix} (if non-null) surrounding the result of a call to - * this method are the high register transformation of this - * instance, and it is guaranteed that the number of low registers - * used will be the number returned by {@link - * #getMinimumRegisterRequirement}. - * - * @return non-null; the replacement - */ - public DalvInsn hrVersion() { - RegisterSpecList regs = - registers.withSequentialRegisters(0, hasResult()); - return withRegisters(regs); - } - - /** - * Gets the short identifier for this instruction. This is its - * address, if assigned, or its identity hashcode if not. - * - * @return non-null; the identifier - */ - public final String identifierString() { - if (address != -1) { - return String.format("%04x", address); - } - - return Hex.u4(System.identityHashCode(this)); - } - - /** - * Returns the string form of this instance suitable for inclusion in - * a human-oriented listing dump. This method will return <code>null</code> - * if this instance should not appear in a listing. - * - * @param prefix non-null; prefix before the address; each follow-on - * line will be indented to match as well - * @param width >= 0; the width of the output or <code>0</code> for - * unlimited width - * @param noteIndices whether to include an explicit notation of - * constant pool indices - * @return null-ok; the string form or <code>null</code> if this - * instance should not appear in a listing - */ - public final String listingString(String prefix, int width, - boolean noteIndices) { - String insnPerSe = listingString0(noteIndices); - - if (insnPerSe == null) { - return null; - } - - String addr = prefix + identifierString() + ": "; - int w1 = addr.length(); - int w2 = (width == 0) ? insnPerSe.length() : (width - w1); - - return TwoColumnOutput.toString(addr, w1, "", insnPerSe, w2); - } - - /** - * Sets the output address. - * - * @param address >= 0; the output address - */ - public final void setAddress(int address) { - if (address < 0) { - throw new IllegalArgumentException("address < 0"); - } - - this.address = address; - } - - /** - * Gets the address immediately after this instance. This is only - * calculable if this instance's address is known, and it is equal - * to the address plus the length of the instruction format of this - * instance's opcode. - * - * @return >= 0; the next address - */ - public final int getNextAddress() { - return getAddress() + codeSize(); - } - - /** - * Gets the size of this instruction, in 16-bit code units. - * - * @return >= 0; the code size of this instruction - */ - public abstract int codeSize(); - - /** - * Writes this instance to the given output. This method should - * never annotate the output. - * - * @param out non-null; where to write to - */ - public abstract void writeTo(AnnotatedOutput out); - - /** - * Returns an instance that is just like this one, except that its - * opcode is replaced by the one given, and its address is reset. - * - * @param opcode non-null; the new opcode - * @return non-null; an appropriately-constructed instance - */ - public abstract DalvInsn withOpcode(Dop opcode); - - /** - * Returns an instance that is just like this one, except that all - * register references have been offset by the given delta, and its - * address is reset. - * - * @param delta the amount to offset register references by - * @return non-null; an appropriately-constructed instance - */ - public abstract DalvInsn withRegisterOffset(int delta); - - /** - * Returns an instance that is just like this one, except that the - * register list is replaced by the given one, and its address is - * reset. - * - * @param registers non-null; new register list - * @return non-null; an appropriately-constructed instance - */ - public abstract DalvInsn withRegisters(RegisterSpecList registers); - - /** - * Gets the string form for any arguments to this instance. Subclasses - * must override this. - * - * @return null-ok; the string version of any arguments or - * <code>null</code> if there are none - */ - protected abstract String argString(); - - /** - * Helper for {@link #listingString}, which returns the string - * form of this instance suitable for inclusion in a - * human-oriented listing dump, not including the instruction - * address and without respect for any output formatting. This - * method should return <code>null</code> if this instance should - * not appear in a listing. - * - * @param noteIndices whether to include an explicit notation of - * constant pool indices - * @return null-ok; the listing string - */ - protected abstract String listingString0(boolean noteIndices); -} diff --git a/dx/src/com/android/dx/dex/code/DalvInsnList.java b/dx/src/com/android/dx/dex/code/DalvInsnList.java deleted file mode 100644 index 2cd15c6dd..000000000 --- a/dx/src/com/android/dx/dex/code/DalvInsnList.java +++ /dev/null @@ -1,268 +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.android.dx.dex.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstBaseMethodRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; -import com.android.dx.util.FixedSizeList; -import com.android.dx.util.IndentingWriter; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.ArrayList; - -/** - * List of {@link DalvInsn} instances. - */ -public final class DalvInsnList extends FixedSizeList { - - /** - * The amount of register space, in register units, required for this - * code block. This may be greater than the largest observed register+ - * category because the method this code block exists in may - * specify arguments that are unused by the method. - */ - private final int regCount; - - /** - * Constructs and returns an immutable instance whose elements are - * identical to the ones in the given list, in the same order. - * - * @param list non-null; the list to use for elements - * @param regCount count, in register-units, of the number of registers - * this code block requires. - * @return non-null; an appropriately-constructed instance of this - * class - */ - public static DalvInsnList makeImmutable(ArrayList<DalvInsn> list, - int regCount) { - int size = list.size(); - DalvInsnList result = new DalvInsnList(size, regCount); - - for (int i = 0; i < size; i++) { - result.set(i, list.get(i)); - } - - result.setImmutable(); - return result; - } - - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size the size of the list - */ - public DalvInsnList(int size, int regCount) { - super(size); - this.regCount = regCount; - } - - /** - * Gets the element at the given index. 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</code>. - * - * @param n >= 0, < size(); which index - * @return non-null; element at that index - */ - public DalvInsn get(int n) { - return (DalvInsn) get0(n); - } - - /** - * Sets the instruction at the given index. - * - * @param n >= 0, < size(); which index - * @param insn non-null; the instruction to set at <code>n</code> - */ - public void set(int n, DalvInsn insn) { - set0(n, insn); - } - - /** - * Gets the size of this instance, in 16-bit code units. This will only - * return a meaningful result if the instructions in this instance all - * have valid addresses. - * - * @return >= 0; the size - */ - public int codeSize() { - int sz = size(); - - if (sz == 0) { - return 0; - } - - DalvInsn last = get(sz - 1); - return last.getNextAddress(); - } - - /** - * Writes all the instructions in this instance to the given output - * destination. - * - * @param out non-null; where to write to - */ - public void writeTo(AnnotatedOutput out) { - int startCursor = out.getCursor(); - int sz = size(); - - if (out.annotates()) { - boolean verbose = out.isVerbose(); - - for (int i = 0; i < sz; i++) { - DalvInsn insn = (DalvInsn) get0(i); - int codeBytes = insn.codeSize() * 2; - String s; - - if ((codeBytes != 0) || verbose) { - s = insn.listingString(" ", out.getAnnotationWidth(), - true); - } else { - s = null; - } - - if (s != null) { - out.annotate(codeBytes, s); - } else if (codeBytes != 0) { - out.annotate(codeBytes, ""); - } - } - } - - for (int i = 0; i < sz; i++) { - DalvInsn insn = (DalvInsn) get0(i); - try { - insn.writeTo(out); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, - "...while writing " + insn); - } - } - - // Sanity check of the amount written. - int written = (out.getCursor() - startCursor) / 2; - if (written != codeSize()) { - throw new RuntimeException("write length mismatch; expected " + - codeSize() + " but actually wrote " + written); - } - } - - /** - * Gets the minimum required register count implied by this - * instance. This includes any unused parameters that could - * potentially be at the top of the register space. - * @return >= 0; the required registers size - */ - public int getRegistersSize() { - return regCount; - } - - /** - * Gets the size of the outgoing arguments area required by this - * method. This is equal to the largest argument word count of any - * method referred to by this instance. - * - * @return >= 0; the required outgoing arguments size - */ - public int getOutsSize() { - int sz = size(); - int result = 0; - - for (int i = 0; i < sz; i++) { - DalvInsn insn = (DalvInsn) get0(i); - - if (!(insn instanceof CstInsn)) { - continue; - } - - Constant cst = ((CstInsn) insn).getConstant(); - - if (!(cst instanceof CstBaseMethodRef)) { - continue; - } - - boolean isStatic = - (insn.getOpcode().getFamily() == DalvOps.INVOKE_STATIC); - int count = - ((CstBaseMethodRef) cst).getParameterWordCount(isStatic); - - if (count > result) { - result = count; - } - } - - return result; - } - - /** - * Does a human-friendly dump of this instance. - * - * @param out non-null; where to dump - * @param prefix non-null; prefix to attach to each line of output - * @param verbose whether to be verbose; verbose output includes - * lines for zero-size instructions and explicit constant pool indices - */ - public void debugPrint(Writer out, String prefix, boolean verbose) { - IndentingWriter iw = new IndentingWriter(out, 0, prefix); - int sz = size(); - - try { - for (int i = 0; i < sz; i++) { - DalvInsn insn = (DalvInsn) get0(i); - String s; - - if ((insn.codeSize() != 0) || verbose) { - s = insn.listingString("", 0, verbose); - } else { - s = null; - } - - if (s != null) { - iw.write(s); - } - } - - iw.flush(); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - /** - * Does a human-friendly dump of this instance. - * - * @param out non-null; where to dump - * @param prefix non-null; prefix to attach to each line of output - * @param verbose whether to be verbose; verbose output includes - * lines for zero-size instructions - */ - public void debugPrint(OutputStream out, String prefix, boolean verbose) { - Writer w = new OutputStreamWriter(out); - debugPrint(w, prefix, verbose); - - try { - w.flush(); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } -} diff --git a/dx/src/com/android/dx/dex/code/DalvOps.java b/dx/src/com/android/dx/dex/code/DalvOps.java deleted file mode 100644 index 7dc648e5a..000000000 --- a/dx/src/com/android/dx/dex/code/DalvOps.java +++ /dev/null @@ -1,298 +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.android.dx.dex.code; - -/** - * All the Dalvik opcode value constants. See the related spec - * document for the meaning and instruction format of each opcode. - */ -public final class DalvOps { - /** pseudo-opcode used for nonstandard format "instructions" */ - public static final int SPECIAL_FORMAT = -1; - - /** minimum valid opcode value */ - public static final int MIN_VALUE = -1; - - /** maximum valid opcode value */ - public static final int MAX_VALUE = 0xff; - - // BEGIN(opcodes); GENERATED AUTOMATICALLY BY opcode-gen - public static final int NOP = 0x00; - public static final int MOVE = 0x01; - public static final int MOVE_FROM16 = 0x02; - public static final int MOVE_16 = 0x03; - public static final int MOVE_WIDE = 0x04; - public static final int MOVE_WIDE_FROM16 = 0x05; - public static final int MOVE_WIDE_16 = 0x06; - public static final int MOVE_OBJECT = 0x07; - public static final int MOVE_OBJECT_FROM16 = 0x08; - public static final int MOVE_OBJECT_16 = 0x09; - public static final int MOVE_RESULT = 0x0a; - public static final int MOVE_RESULT_WIDE = 0x0b; - public static final int MOVE_RESULT_OBJECT = 0x0c; - public static final int MOVE_EXCEPTION = 0x0d; - public static final int RETURN_VOID = 0x0e; - public static final int RETURN = 0x0f; - public static final int RETURN_WIDE = 0x10; - public static final int RETURN_OBJECT = 0x11; - public static final int CONST_4 = 0x12; - public static final int CONST_16 = 0x13; - public static final int CONST = 0x14; - public static final int CONST_HIGH16 = 0x15; - public static final int CONST_WIDE_16 = 0x16; - public static final int CONST_WIDE_32 = 0x17; - public static final int CONST_WIDE = 0x18; - public static final int CONST_WIDE_HIGH16 = 0x19; - public static final int CONST_STRING = 0x1a; - public static final int CONST_STRING_JUMBO = 0x1b; - public static final int CONST_CLASS = 0x1c; - public static final int MONITOR_ENTER = 0x1d; - public static final int MONITOR_EXIT = 0x1e; - public static final int CHECK_CAST = 0x1f; - public static final int INSTANCE_OF = 0x20; - public static final int ARRAY_LENGTH = 0x21; - public static final int NEW_INSTANCE = 0x22; - public static final int NEW_ARRAY = 0x23; - public static final int FILLED_NEW_ARRAY = 0x24; - public static final int FILLED_NEW_ARRAY_RANGE = 0x25; - public static final int FILL_ARRAY_DATA = 0x26; - public static final int THROW = 0x27; - public static final int GOTO = 0x28; - public static final int GOTO_16 = 0x29; - public static final int GOTO_32 = 0x2a; - public static final int PACKED_SWITCH = 0x2b; - public static final int SPARSE_SWITCH = 0x2c; - public static final int CMPL_FLOAT = 0x2d; - public static final int CMPG_FLOAT = 0x2e; - public static final int CMPL_DOUBLE = 0x2f; - public static final int CMPG_DOUBLE = 0x30; - public static final int CMP_LONG = 0x31; - public static final int IF_EQ = 0x32; - public static final int IF_NE = 0x33; - public static final int IF_LT = 0x34; - public static final int IF_GE = 0x35; - public static final int IF_GT = 0x36; - public static final int IF_LE = 0x37; - public static final int IF_EQZ = 0x38; - public static final int IF_NEZ = 0x39; - public static final int IF_LTZ = 0x3a; - public static final int IF_GEZ = 0x3b; - public static final int IF_GTZ = 0x3c; - public static final int IF_LEZ = 0x3d; - public static final int UNUSED_3E = 0x3e; - public static final int UNUSED_3F = 0x3f; - public static final int UNUSED_40 = 0x40; - public static final int UNUSED_41 = 0x41; - public static final int UNUSED_42 = 0x42; - public static final int UNUSED_43 = 0x43; - public static final int AGET = 0x44; - public static final int AGET_WIDE = 0x45; - public static final int AGET_OBJECT = 0x46; - public static final int AGET_BOOLEAN = 0x47; - public static final int AGET_BYTE = 0x48; - public static final int AGET_CHAR = 0x49; - public static final int AGET_SHORT = 0x4a; - public static final int APUT = 0x4b; - public static final int APUT_WIDE = 0x4c; - public static final int APUT_OBJECT = 0x4d; - public static final int APUT_BOOLEAN = 0x4e; - public static final int APUT_BYTE = 0x4f; - public static final int APUT_CHAR = 0x50; - public static final int APUT_SHORT = 0x51; - public static final int IGET = 0x52; - public static final int IGET_WIDE = 0x53; - public static final int IGET_OBJECT = 0x54; - public static final int IGET_BOOLEAN = 0x55; - public static final int IGET_BYTE = 0x56; - public static final int IGET_CHAR = 0x57; - public static final int IGET_SHORT = 0x58; - public static final int IPUT = 0x59; - public static final int IPUT_WIDE = 0x5a; - public static final int IPUT_OBJECT = 0x5b; - public static final int IPUT_BOOLEAN = 0x5c; - public static final int IPUT_BYTE = 0x5d; - public static final int IPUT_CHAR = 0x5e; - public static final int IPUT_SHORT = 0x5f; - public static final int SGET = 0x60; - public static final int SGET_WIDE = 0x61; - public static final int SGET_OBJECT = 0x62; - public static final int SGET_BOOLEAN = 0x63; - public static final int SGET_BYTE = 0x64; - public static final int SGET_CHAR = 0x65; - public static final int SGET_SHORT = 0x66; - public static final int SPUT = 0x67; - public static final int SPUT_WIDE = 0x68; - public static final int SPUT_OBJECT = 0x69; - public static final int SPUT_BOOLEAN = 0x6a; - public static final int SPUT_BYTE = 0x6b; - public static final int SPUT_CHAR = 0x6c; - public static final int SPUT_SHORT = 0x6d; - public static final int INVOKE_VIRTUAL = 0x6e; - public static final int INVOKE_SUPER = 0x6f; - public static final int INVOKE_DIRECT = 0x70; - public static final int INVOKE_STATIC = 0x71; - public static final int INVOKE_INTERFACE = 0x72; - public static final int UNUSED_73 = 0x73; - public static final int INVOKE_VIRTUAL_RANGE = 0x74; - public static final int INVOKE_SUPER_RANGE = 0x75; - public static final int INVOKE_DIRECT_RANGE = 0x76; - public static final int INVOKE_STATIC_RANGE = 0x77; - public static final int INVOKE_INTERFACE_RANGE = 0x78; - public static final int UNUSED_79 = 0x79; - public static final int UNUSED_7A = 0x7a; - public static final int NEG_INT = 0x7b; - public static final int NOT_INT = 0x7c; - public static final int NEG_LONG = 0x7d; - public static final int NOT_LONG = 0x7e; - public static final int NEG_FLOAT = 0x7f; - public static final int NEG_DOUBLE = 0x80; - public static final int INT_TO_LONG = 0x81; - public static final int INT_TO_FLOAT = 0x82; - public static final int INT_TO_DOUBLE = 0x83; - public static final int LONG_TO_INT = 0x84; - public static final int LONG_TO_FLOAT = 0x85; - public static final int LONG_TO_DOUBLE = 0x86; - public static final int FLOAT_TO_INT = 0x87; - public static final int FLOAT_TO_LONG = 0x88; - public static final int FLOAT_TO_DOUBLE = 0x89; - public static final int DOUBLE_TO_INT = 0x8a; - public static final int DOUBLE_TO_LONG = 0x8b; - public static final int DOUBLE_TO_FLOAT = 0x8c; - public static final int INT_TO_BYTE = 0x8d; - public static final int INT_TO_CHAR = 0x8e; - public static final int INT_TO_SHORT = 0x8f; - public static final int ADD_INT = 0x90; - public static final int SUB_INT = 0x91; - public static final int MUL_INT = 0x92; - public static final int DIV_INT = 0x93; - public static final int REM_INT = 0x94; - public static final int AND_INT = 0x95; - public static final int OR_INT = 0x96; - public static final int XOR_INT = 0x97; - public static final int SHL_INT = 0x98; - public static final int SHR_INT = 0x99; - public static final int USHR_INT = 0x9a; - public static final int ADD_LONG = 0x9b; - public static final int SUB_LONG = 0x9c; - public static final int MUL_LONG = 0x9d; - public static final int DIV_LONG = 0x9e; - public static final int REM_LONG = 0x9f; - public static final int AND_LONG = 0xa0; - public static final int OR_LONG = 0xa1; - public static final int XOR_LONG = 0xa2; - public static final int SHL_LONG = 0xa3; - public static final int SHR_LONG = 0xa4; - public static final int USHR_LONG = 0xa5; - public static final int ADD_FLOAT = 0xa6; - public static final int SUB_FLOAT = 0xa7; - public static final int MUL_FLOAT = 0xa8; - public static final int DIV_FLOAT = 0xa9; - public static final int REM_FLOAT = 0xaa; - public static final int ADD_DOUBLE = 0xab; - public static final int SUB_DOUBLE = 0xac; - public static final int MUL_DOUBLE = 0xad; - public static final int DIV_DOUBLE = 0xae; - public static final int REM_DOUBLE = 0xaf; - public static final int ADD_INT_2ADDR = 0xb0; - public static final int SUB_INT_2ADDR = 0xb1; - public static final int MUL_INT_2ADDR = 0xb2; - public static final int DIV_INT_2ADDR = 0xb3; - public static final int REM_INT_2ADDR = 0xb4; - public static final int AND_INT_2ADDR = 0xb5; - public static final int OR_INT_2ADDR = 0xb6; - public static final int XOR_INT_2ADDR = 0xb7; - public static final int SHL_INT_2ADDR = 0xb8; - public static final int SHR_INT_2ADDR = 0xb9; - public static final int USHR_INT_2ADDR = 0xba; - public static final int ADD_LONG_2ADDR = 0xbb; - public static final int SUB_LONG_2ADDR = 0xbc; - public static final int MUL_LONG_2ADDR = 0xbd; - public static final int DIV_LONG_2ADDR = 0xbe; - public static final int REM_LONG_2ADDR = 0xbf; - public static final int AND_LONG_2ADDR = 0xc0; - public static final int OR_LONG_2ADDR = 0xc1; - public static final int XOR_LONG_2ADDR = 0xc2; - public static final int SHL_LONG_2ADDR = 0xc3; - public static final int SHR_LONG_2ADDR = 0xc4; - public static final int USHR_LONG_2ADDR = 0xc5; - public static final int ADD_FLOAT_2ADDR = 0xc6; - public static final int SUB_FLOAT_2ADDR = 0xc7; - public static final int MUL_FLOAT_2ADDR = 0xc8; - public static final int DIV_FLOAT_2ADDR = 0xc9; - public static final int REM_FLOAT_2ADDR = 0xca; - public static final int ADD_DOUBLE_2ADDR = 0xcb; - public static final int SUB_DOUBLE_2ADDR = 0xcc; - public static final int MUL_DOUBLE_2ADDR = 0xcd; - public static final int DIV_DOUBLE_2ADDR = 0xce; - public static final int REM_DOUBLE_2ADDR = 0xcf; - public static final int ADD_INT_LIT16 = 0xd0; - public static final int RSUB_INT = 0xd1; - public static final int MUL_INT_LIT16 = 0xd2; - public static final int DIV_INT_LIT16 = 0xd3; - public static final int REM_INT_LIT16 = 0xd4; - public static final int AND_INT_LIT16 = 0xd5; - public static final int OR_INT_LIT16 = 0xd6; - public static final int XOR_INT_LIT16 = 0xd7; - public static final int ADD_INT_LIT8 = 0xd8; - public static final int RSUB_INT_LIT8 = 0xd9; - public static final int MUL_INT_LIT8 = 0xda; - public static final int DIV_INT_LIT8 = 0xdb; - public static final int REM_INT_LIT8 = 0xdc; - public static final int AND_INT_LIT8 = 0xdd; - public static final int OR_INT_LIT8 = 0xde; - public static final int XOR_INT_LIT8 = 0xdf; - public static final int SHL_INT_LIT8 = 0xe0; - public static final int SHR_INT_LIT8 = 0xe1; - public static final int USHR_INT_LIT8 = 0xe2; - public static final int UNUSED_E3 = 0xe3; - public static final int UNUSED_E4 = 0xe4; - public static final int UNUSED_E5 = 0xe5; - public static final int UNUSED_E6 = 0xe6; - public static final int UNUSED_E7 = 0xe7; - public static final int UNUSED_E8 = 0xe8; - public static final int UNUSED_E9 = 0xe9; - public static final int UNUSED_EA = 0xea; - public static final int UNUSED_EB = 0xeb; - public static final int UNUSED_EC = 0xec; - public static final int UNUSED_ED = 0xed; - public static final int UNUSED_EE = 0xee; - public static final int UNUSED_EF = 0xef; - public static final int UNUSED_F0 = 0xf0; - public static final int UNUSED_F1 = 0xf1; - public static final int UNUSED_F2 = 0xf2; - public static final int UNUSED_F3 = 0xf3; - public static final int UNUSED_F4 = 0xf4; - public static final int UNUSED_F5 = 0xf5; - public static final int UNUSED_F6 = 0xf6; - public static final int UNUSED_F7 = 0xf7; - public static final int UNUSED_F8 = 0xf8; - public static final int UNUSED_F9 = 0xf9; - public static final int UNUSED_FA = 0xfa; - public static final int UNUSED_FB = 0xfb; - public static final int UNUSED_FC = 0xfc; - public static final int UNUSED_FD = 0xfd; - public static final int UNUSED_FE = 0xfe; - public static final int UNUSED_FF = 0xff; - // END(opcodes) - - /** - * This class is uninstantiable. - */ - private DalvOps() { - // This space intentionally left blank. - } -} diff --git a/dx/src/com/android/dx/dex/code/Dop.java b/dx/src/com/android/dx/dex/code/Dop.java deleted file mode 100644 index 6914fcae6..000000000 --- a/dx/src/com/android/dx/dex/code/Dop.java +++ /dev/null @@ -1,150 +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.android.dx.dex.code; - -/** - * Representation of an opcode. - */ -public final class Dop { - /** DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode value itself */ - private final int opcode; - - /** DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode family */ - private final int family; - - /** non-null; the instruction format */ - private final InsnFormat format; - - /** whether this opcode uses a result register */ - private final boolean hasResult; - - /** non-null; the name */ - private final String name; - - /** - * Constructs an instance. - * - * @param opcode DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode - * value itself - * @param family DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode family - * @param format non-null; the instruction format - * @param hasResult whether the opcode has a result register; if so it - * is always the first register - * @param name non-null; the name - */ - public Dop(int opcode, int family, InsnFormat format, - boolean hasResult, String name) { - if ((opcode < DalvOps.MIN_VALUE) || (opcode > DalvOps.MAX_VALUE)) { - throw new IllegalArgumentException("bogus opcode"); - } - - if ((family < DalvOps.MIN_VALUE) || (family > DalvOps.MAX_VALUE)) { - throw new IllegalArgumentException("bogus family"); - } - - if (format == null) { - throw new NullPointerException("format == null"); - } - - if (name == null) { - throw new NullPointerException("name == null"); - } - - this.opcode = opcode; - this.family = family; - this.format = format; - this.hasResult = hasResult; - this.name = name; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return name; - } - - /** - * Gets the opcode value. - * - * @return DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode value - */ - public int getOpcode() { - return opcode; - } - - /** - * Gets the opcode family. The opcode family is the unmarked (no - * "/...") opcode that has equivalent semantics to this one. - * - * @return DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode family - */ - public int getFamily() { - return family; - } - - /** - * Gets the instruction format. - * - * @return non-null; the instruction format - */ - public InsnFormat getFormat() { - return format; - } - - /** - * Returns whether this opcode uses a result register. - * - * @return <code>true</code> iff this opcode uses a result register - */ - public boolean hasResult() { - return hasResult; - } - - /** - * Gets the opcode name. - * - * @return non-null; the opcode name - */ - public String getName() { - return name; - } - - /** - * Gets the opcode for the opposite test of this instance. This is only - * valid for opcodes which are in fact tests. - * - * @return non-null; the opposite test - */ - public Dop getOppositeTest() { - switch (opcode) { - case DalvOps.IF_EQ: return Dops.IF_NE; - case DalvOps.IF_NE: return Dops.IF_EQ; - case DalvOps.IF_LT: return Dops.IF_GE; - case DalvOps.IF_GE: return Dops.IF_LT; - case DalvOps.IF_GT: return Dops.IF_LE; - case DalvOps.IF_LE: return Dops.IF_GT; - case DalvOps.IF_EQZ: return Dops.IF_NEZ; - case DalvOps.IF_NEZ: return Dops.IF_EQZ; - case DalvOps.IF_LTZ: return Dops.IF_GEZ; - case DalvOps.IF_GEZ: return Dops.IF_LTZ; - case DalvOps.IF_GTZ: return Dops.IF_LEZ; - case DalvOps.IF_LEZ: return Dops.IF_GTZ; - } - - throw new IllegalArgumentException("bogus opcode: " + this); - } -} diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java deleted file mode 100644 index 8923c59bf..000000000 --- a/dx/src/com/android/dx/dex/code/Dops.java +++ /dev/null @@ -1,1231 +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.android.dx.dex.code; - -import com.android.dx.dex.code.form.Form10t; -import com.android.dx.dex.code.form.Form10x; -import com.android.dx.dex.code.form.Form11n; -import com.android.dx.dex.code.form.Form11x; -import com.android.dx.dex.code.form.Form12x; -import com.android.dx.dex.code.form.Form20t; -import com.android.dx.dex.code.form.Form21c; -import com.android.dx.dex.code.form.Form21h; -import com.android.dx.dex.code.form.Form21s; -import com.android.dx.dex.code.form.Form21t; -import com.android.dx.dex.code.form.Form22b; -import com.android.dx.dex.code.form.Form22c; -import com.android.dx.dex.code.form.Form22s; -import com.android.dx.dex.code.form.Form22t; -import com.android.dx.dex.code.form.Form22x; -import com.android.dx.dex.code.form.Form23x; -import com.android.dx.dex.code.form.Form30t; -import com.android.dx.dex.code.form.Form31c; -import com.android.dx.dex.code.form.Form31i; -import com.android.dx.dex.code.form.Form31t; -import com.android.dx.dex.code.form.Form32x; -import com.android.dx.dex.code.form.Form35c; -import com.android.dx.dex.code.form.Form3rc; -import com.android.dx.dex.code.form.Form51l; -import com.android.dx.dex.code.form.SpecialFormat; - -/** - * Standard instances of {@link Dop} and utility methods for getting - * them. - */ -public final class Dops { - /** non-null; array containing all the standard instances */ - private static final Dop[] DOPS; - - /** - * pseudo-opcode used for nonstandard formatted "instructions" - * (which are mostly not actually instructions, though they do - * appear in instruction lists) - */ - public static final Dop SPECIAL_FORMAT = - new Dop(DalvOps.SPECIAL_FORMAT, DalvOps.SPECIAL_FORMAT, - SpecialFormat.THE_ONE, false, "<special>"); - - // BEGIN(dops); GENERATED AUTOMATICALLY BY opcode-gen - public static final Dop NOP = - new Dop(DalvOps.NOP, DalvOps.NOP, - Form10x.THE_ONE, false, "nop"); - - public static final Dop MOVE = - new Dop(DalvOps.MOVE, DalvOps.MOVE, - Form12x.THE_ONE, true, "move"); - - public static final Dop MOVE_FROM16 = - new Dop(DalvOps.MOVE_FROM16, DalvOps.MOVE, - Form22x.THE_ONE, true, "move/from16"); - - public static final Dop MOVE_16 = - new Dop(DalvOps.MOVE_16, DalvOps.MOVE, - Form32x.THE_ONE, true, "move/16"); - - public static final Dop MOVE_WIDE = - new Dop(DalvOps.MOVE_WIDE, DalvOps.MOVE_WIDE, - Form12x.THE_ONE, true, "move-wide"); - - public static final Dop MOVE_WIDE_FROM16 = - new Dop(DalvOps.MOVE_WIDE_FROM16, DalvOps.MOVE_WIDE, - Form22x.THE_ONE, true, "move-wide/from16"); - - public static final Dop MOVE_WIDE_16 = - new Dop(DalvOps.MOVE_WIDE_16, DalvOps.MOVE_WIDE, - Form32x.THE_ONE, true, "move-wide/16"); - - public static final Dop MOVE_OBJECT = - new Dop(DalvOps.MOVE_OBJECT, DalvOps.MOVE_OBJECT, - Form12x.THE_ONE, true, "move-object"); - - public static final Dop MOVE_OBJECT_FROM16 = - new Dop(DalvOps.MOVE_OBJECT_FROM16, DalvOps.MOVE_OBJECT, - Form22x.THE_ONE, true, "move-object/from16"); - - public static final Dop MOVE_OBJECT_16 = - new Dop(DalvOps.MOVE_OBJECT_16, DalvOps.MOVE_OBJECT, - Form32x.THE_ONE, true, "move-object/16"); - - public static final Dop MOVE_RESULT = - new Dop(DalvOps.MOVE_RESULT, DalvOps.MOVE_RESULT, - Form11x.THE_ONE, true, "move-result"); - - public static final Dop MOVE_RESULT_WIDE = - new Dop(DalvOps.MOVE_RESULT_WIDE, DalvOps.MOVE_RESULT_WIDE, - Form11x.THE_ONE, true, "move-result-wide"); - - public static final Dop MOVE_RESULT_OBJECT = - new Dop(DalvOps.MOVE_RESULT_OBJECT, DalvOps.MOVE_RESULT_OBJECT, - Form11x.THE_ONE, true, "move-result-object"); - - public static final Dop MOVE_EXCEPTION = - new Dop(DalvOps.MOVE_EXCEPTION, DalvOps.MOVE_EXCEPTION, - Form11x.THE_ONE, true, "move-exception"); - - public static final Dop RETURN_VOID = - new Dop(DalvOps.RETURN_VOID, DalvOps.RETURN_VOID, - Form10x.THE_ONE, false, "return-void"); - - public static final Dop RETURN = - new Dop(DalvOps.RETURN, DalvOps.RETURN, - Form11x.THE_ONE, false, "return"); - - public static final Dop RETURN_WIDE = - new Dop(DalvOps.RETURN_WIDE, DalvOps.RETURN_WIDE, - Form11x.THE_ONE, false, "return-wide"); - - public static final Dop RETURN_OBJECT = - new Dop(DalvOps.RETURN_OBJECT, DalvOps.RETURN_OBJECT, - Form11x.THE_ONE, false, "return-object"); - - public static final Dop CONST_4 = - new Dop(DalvOps.CONST_4, DalvOps.CONST, - Form11n.THE_ONE, true, "const/4"); - - public static final Dop CONST_16 = - new Dop(DalvOps.CONST_16, DalvOps.CONST, - Form21s.THE_ONE, true, "const/16"); - - public static final Dop CONST = - new Dop(DalvOps.CONST, DalvOps.CONST, - Form31i.THE_ONE, true, "const"); - - public static final Dop CONST_HIGH16 = - new Dop(DalvOps.CONST_HIGH16, DalvOps.CONST, - Form21h.THE_ONE, true, "const/high16"); - - public static final Dop CONST_WIDE_16 = - new Dop(DalvOps.CONST_WIDE_16, DalvOps.CONST_WIDE, - Form21s.THE_ONE, true, "const-wide/16"); - - public static final Dop CONST_WIDE_32 = - new Dop(DalvOps.CONST_WIDE_32, DalvOps.CONST_WIDE, - Form31i.THE_ONE, true, "const-wide/32"); - - public static final Dop CONST_WIDE = - new Dop(DalvOps.CONST_WIDE, DalvOps.CONST_WIDE, - Form51l.THE_ONE, true, "const-wide"); - - public static final Dop CONST_WIDE_HIGH16 = - new Dop(DalvOps.CONST_WIDE_HIGH16, DalvOps.CONST_WIDE, - Form21h.THE_ONE, true, "const-wide/high16"); - - public static final Dop CONST_STRING = - new Dop(DalvOps.CONST_STRING, DalvOps.CONST_STRING, - Form21c.THE_ONE, true, "const-string"); - - public static final Dop CONST_STRING_JUMBO = - new Dop(DalvOps.CONST_STRING_JUMBO, DalvOps.CONST_STRING, - Form31c.THE_ONE, true, "const-string/jumbo"); - - public static final Dop CONST_CLASS = - new Dop(DalvOps.CONST_CLASS, DalvOps.CONST_CLASS, - Form21c.THE_ONE, true, "const-class"); - - public static final Dop MONITOR_ENTER = - new Dop(DalvOps.MONITOR_ENTER, DalvOps.MONITOR_ENTER, - Form11x.THE_ONE, false, "monitor-enter"); - - public static final Dop MONITOR_EXIT = - new Dop(DalvOps.MONITOR_EXIT, DalvOps.MONITOR_EXIT, - Form11x.THE_ONE, false, "monitor-exit"); - - public static final Dop CHECK_CAST = - new Dop(DalvOps.CHECK_CAST, DalvOps.CHECK_CAST, - Form21c.THE_ONE, true, "check-cast"); - - public static final Dop INSTANCE_OF = - new Dop(DalvOps.INSTANCE_OF, DalvOps.INSTANCE_OF, - Form22c.THE_ONE, true, "instance-of"); - - public static final Dop ARRAY_LENGTH = - new Dop(DalvOps.ARRAY_LENGTH, DalvOps.ARRAY_LENGTH, - Form12x.THE_ONE, true, "array-length"); - - public static final Dop NEW_INSTANCE = - new Dop(DalvOps.NEW_INSTANCE, DalvOps.NEW_INSTANCE, - Form21c.THE_ONE, true, "new-instance"); - - public static final Dop NEW_ARRAY = - new Dop(DalvOps.NEW_ARRAY, DalvOps.NEW_ARRAY, - Form22c.THE_ONE, true, "new-array"); - - public static final Dop FILLED_NEW_ARRAY = - new Dop(DalvOps.FILLED_NEW_ARRAY, DalvOps.FILLED_NEW_ARRAY, - Form35c.THE_ONE, false, "filled-new-array"); - - public static final Dop FILLED_NEW_ARRAY_RANGE = - new Dop(DalvOps.FILLED_NEW_ARRAY_RANGE, DalvOps.FILLED_NEW_ARRAY, - Form3rc.THE_ONE, false, "filled-new-array/range"); - - public static final Dop FILL_ARRAY_DATA = - new Dop(DalvOps.FILL_ARRAY_DATA, DalvOps.FILL_ARRAY_DATA, - Form31t.THE_ONE, false, "fill-array-data"); - - public static final Dop THROW = - new Dop(DalvOps.THROW, DalvOps.THROW, - Form11x.THE_ONE, false, "throw"); - - public static final Dop GOTO = - new Dop(DalvOps.GOTO, DalvOps.GOTO, - Form10t.THE_ONE, false, "goto"); - - public static final Dop GOTO_16 = - new Dop(DalvOps.GOTO_16, DalvOps.GOTO, - Form20t.THE_ONE, false, "goto/16"); - - public static final Dop GOTO_32 = - new Dop(DalvOps.GOTO_32, DalvOps.GOTO, - Form30t.THE_ONE, false, "goto/32"); - - public static final Dop PACKED_SWITCH = - new Dop(DalvOps.PACKED_SWITCH, DalvOps.PACKED_SWITCH, - Form31t.THE_ONE, false, "packed-switch"); - - public static final Dop SPARSE_SWITCH = - new Dop(DalvOps.SPARSE_SWITCH, DalvOps.SPARSE_SWITCH, - Form31t.THE_ONE, false, "sparse-switch"); - - public static final Dop CMPL_FLOAT = - new Dop(DalvOps.CMPL_FLOAT, DalvOps.CMPL_FLOAT, - Form23x.THE_ONE, true, "cmpl-float"); - - public static final Dop CMPG_FLOAT = - new Dop(DalvOps.CMPG_FLOAT, DalvOps.CMPG_FLOAT, - Form23x.THE_ONE, true, "cmpg-float"); - - public static final Dop CMPL_DOUBLE = - new Dop(DalvOps.CMPL_DOUBLE, DalvOps.CMPL_DOUBLE, - Form23x.THE_ONE, true, "cmpl-double"); - - public static final Dop CMPG_DOUBLE = - new Dop(DalvOps.CMPG_DOUBLE, DalvOps.CMPG_DOUBLE, - Form23x.THE_ONE, true, "cmpg-double"); - - public static final Dop CMP_LONG = - new Dop(DalvOps.CMP_LONG, DalvOps.CMP_LONG, - Form23x.THE_ONE, true, "cmp-long"); - - public static final Dop IF_EQ = - new Dop(DalvOps.IF_EQ, DalvOps.IF_EQ, - Form22t.THE_ONE, false, "if-eq"); - - public static final Dop IF_NE = - new Dop(DalvOps.IF_NE, DalvOps.IF_NE, - Form22t.THE_ONE, false, "if-ne"); - - public static final Dop IF_LT = - new Dop(DalvOps.IF_LT, DalvOps.IF_LT, - Form22t.THE_ONE, false, "if-lt"); - - public static final Dop IF_GE = - new Dop(DalvOps.IF_GE, DalvOps.IF_GE, - Form22t.THE_ONE, false, "if-ge"); - - public static final Dop IF_GT = - new Dop(DalvOps.IF_GT, DalvOps.IF_GT, - Form22t.THE_ONE, false, "if-gt"); - - public static final Dop IF_LE = - new Dop(DalvOps.IF_LE, DalvOps.IF_LE, - Form22t.THE_ONE, false, "if-le"); - - public static final Dop IF_EQZ = - new Dop(DalvOps.IF_EQZ, DalvOps.IF_EQZ, - Form21t.THE_ONE, false, "if-eqz"); - - public static final Dop IF_NEZ = - new Dop(DalvOps.IF_NEZ, DalvOps.IF_NEZ, - Form21t.THE_ONE, false, "if-nez"); - - public static final Dop IF_LTZ = - new Dop(DalvOps.IF_LTZ, DalvOps.IF_LTZ, - Form21t.THE_ONE, false, "if-ltz"); - - public static final Dop IF_GEZ = - new Dop(DalvOps.IF_GEZ, DalvOps.IF_GEZ, - Form21t.THE_ONE, false, "if-gez"); - - public static final Dop IF_GTZ = - new Dop(DalvOps.IF_GTZ, DalvOps.IF_GTZ, - Form21t.THE_ONE, false, "if-gtz"); - - public static final Dop IF_LEZ = - new Dop(DalvOps.IF_LEZ, DalvOps.IF_LEZ, - Form21t.THE_ONE, false, "if-lez"); - - public static final Dop AGET = - new Dop(DalvOps.AGET, DalvOps.AGET, - Form23x.THE_ONE, true, "aget"); - - public static final Dop AGET_WIDE = - new Dop(DalvOps.AGET_WIDE, DalvOps.AGET_WIDE, - Form23x.THE_ONE, true, "aget-wide"); - - public static final Dop AGET_OBJECT = - new Dop(DalvOps.AGET_OBJECT, DalvOps.AGET_OBJECT, - Form23x.THE_ONE, true, "aget-object"); - - public static final Dop AGET_BOOLEAN = - new Dop(DalvOps.AGET_BOOLEAN, DalvOps.AGET_BOOLEAN, - Form23x.THE_ONE, true, "aget-boolean"); - - public static final Dop AGET_BYTE = - new Dop(DalvOps.AGET_BYTE, DalvOps.AGET_BYTE, - Form23x.THE_ONE, true, "aget-byte"); - - public static final Dop AGET_CHAR = - new Dop(DalvOps.AGET_CHAR, DalvOps.AGET_CHAR, - Form23x.THE_ONE, true, "aget-char"); - - public static final Dop AGET_SHORT = - new Dop(DalvOps.AGET_SHORT, DalvOps.AGET_SHORT, - Form23x.THE_ONE, true, "aget-short"); - - public static final Dop APUT = - new Dop(DalvOps.APUT, DalvOps.APUT, - Form23x.THE_ONE, false, "aput"); - - public static final Dop APUT_WIDE = - new Dop(DalvOps.APUT_WIDE, DalvOps.APUT_WIDE, - Form23x.THE_ONE, false, "aput-wide"); - - public static final Dop APUT_OBJECT = - new Dop(DalvOps.APUT_OBJECT, DalvOps.APUT_OBJECT, - Form23x.THE_ONE, false, "aput-object"); - - public static final Dop APUT_BOOLEAN = - new Dop(DalvOps.APUT_BOOLEAN, DalvOps.APUT_BOOLEAN, - Form23x.THE_ONE, false, "aput-boolean"); - - public static final Dop APUT_BYTE = - new Dop(DalvOps.APUT_BYTE, DalvOps.APUT_BYTE, - Form23x.THE_ONE, false, "aput-byte"); - - public static final Dop APUT_CHAR = - new Dop(DalvOps.APUT_CHAR, DalvOps.APUT_CHAR, - Form23x.THE_ONE, false, "aput-char"); - - public static final Dop APUT_SHORT = - new Dop(DalvOps.APUT_SHORT, DalvOps.APUT_SHORT, - Form23x.THE_ONE, false, "aput-short"); - - public static final Dop IGET = - new Dop(DalvOps.IGET, DalvOps.IGET, - Form22c.THE_ONE, true, "iget"); - - public static final Dop IGET_WIDE = - new Dop(DalvOps.IGET_WIDE, DalvOps.IGET_WIDE, - Form22c.THE_ONE, true, "iget-wide"); - - public static final Dop IGET_OBJECT = - new Dop(DalvOps.IGET_OBJECT, DalvOps.IGET_OBJECT, - Form22c.THE_ONE, true, "iget-object"); - - public static final Dop IGET_BOOLEAN = - new Dop(DalvOps.IGET_BOOLEAN, DalvOps.IGET_BOOLEAN, - Form22c.THE_ONE, true, "iget-boolean"); - - public static final Dop IGET_BYTE = - new Dop(DalvOps.IGET_BYTE, DalvOps.IGET_BYTE, - Form22c.THE_ONE, true, "iget-byte"); - - public static final Dop IGET_CHAR = - new Dop(DalvOps.IGET_CHAR, DalvOps.IGET_CHAR, - Form22c.THE_ONE, true, "iget-char"); - - public static final Dop IGET_SHORT = - new Dop(DalvOps.IGET_SHORT, DalvOps.IGET_SHORT, - Form22c.THE_ONE, true, "iget-short"); - - public static final Dop IPUT = - new Dop(DalvOps.IPUT, DalvOps.IPUT, - Form22c.THE_ONE, false, "iput"); - - public static final Dop IPUT_WIDE = - new Dop(DalvOps.IPUT_WIDE, DalvOps.IPUT_WIDE, - Form22c.THE_ONE, false, "iput-wide"); - - public static final Dop IPUT_OBJECT = - new Dop(DalvOps.IPUT_OBJECT, DalvOps.IPUT_OBJECT, - Form22c.THE_ONE, false, "iput-object"); - - public static final Dop IPUT_BOOLEAN = - new Dop(DalvOps.IPUT_BOOLEAN, DalvOps.IPUT_BOOLEAN, - Form22c.THE_ONE, false, "iput-boolean"); - - public static final Dop IPUT_BYTE = - new Dop(DalvOps.IPUT_BYTE, DalvOps.IPUT_BYTE, - Form22c.THE_ONE, false, "iput-byte"); - - public static final Dop IPUT_CHAR = - new Dop(DalvOps.IPUT_CHAR, DalvOps.IPUT_CHAR, - Form22c.THE_ONE, false, "iput-char"); - - public static final Dop IPUT_SHORT = - new Dop(DalvOps.IPUT_SHORT, DalvOps.IPUT_SHORT, - Form22c.THE_ONE, false, "iput-short"); - - public static final Dop SGET = - new Dop(DalvOps.SGET, DalvOps.SGET, - Form21c.THE_ONE, true, "sget"); - - public static final Dop SGET_WIDE = - new Dop(DalvOps.SGET_WIDE, DalvOps.SGET_WIDE, - Form21c.THE_ONE, true, "sget-wide"); - - public static final Dop SGET_OBJECT = - new Dop(DalvOps.SGET_OBJECT, DalvOps.SGET_OBJECT, - Form21c.THE_ONE, true, "sget-object"); - - public static final Dop SGET_BOOLEAN = - new Dop(DalvOps.SGET_BOOLEAN, DalvOps.SGET_BOOLEAN, - Form21c.THE_ONE, true, "sget-boolean"); - - public static final Dop SGET_BYTE = - new Dop(DalvOps.SGET_BYTE, DalvOps.SGET_BYTE, - Form21c.THE_ONE, true, "sget-byte"); - - public static final Dop SGET_CHAR = - new Dop(DalvOps.SGET_CHAR, DalvOps.SGET_CHAR, - Form21c.THE_ONE, true, "sget-char"); - - public static final Dop SGET_SHORT = - new Dop(DalvOps.SGET_SHORT, DalvOps.SGET_SHORT, - Form21c.THE_ONE, true, "sget-short"); - - public static final Dop SPUT = - new Dop(DalvOps.SPUT, DalvOps.SPUT, - Form21c.THE_ONE, false, "sput"); - - public static final Dop SPUT_WIDE = - new Dop(DalvOps.SPUT_WIDE, DalvOps.SPUT_WIDE, - Form21c.THE_ONE, false, "sput-wide"); - - public static final Dop SPUT_OBJECT = - new Dop(DalvOps.SPUT_OBJECT, DalvOps.SPUT_OBJECT, - Form21c.THE_ONE, false, "sput-object"); - - public static final Dop SPUT_BOOLEAN = - new Dop(DalvOps.SPUT_BOOLEAN, DalvOps.SPUT_BOOLEAN, - Form21c.THE_ONE, false, "sput-boolean"); - - public static final Dop SPUT_BYTE = - new Dop(DalvOps.SPUT_BYTE, DalvOps.SPUT_BYTE, - Form21c.THE_ONE, false, "sput-byte"); - - public static final Dop SPUT_CHAR = - new Dop(DalvOps.SPUT_CHAR, DalvOps.SPUT_CHAR, - Form21c.THE_ONE, false, "sput-char"); - - public static final Dop SPUT_SHORT = - new Dop(DalvOps.SPUT_SHORT, DalvOps.SPUT_SHORT, - Form21c.THE_ONE, false, "sput-short"); - - public static final Dop INVOKE_VIRTUAL = - new Dop(DalvOps.INVOKE_VIRTUAL, DalvOps.INVOKE_VIRTUAL, - Form35c.THE_ONE, false, "invoke-virtual"); - - public static final Dop INVOKE_SUPER = - new Dop(DalvOps.INVOKE_SUPER, DalvOps.INVOKE_SUPER, - Form35c.THE_ONE, false, "invoke-super"); - - public static final Dop INVOKE_DIRECT = - new Dop(DalvOps.INVOKE_DIRECT, DalvOps.INVOKE_DIRECT, - Form35c.THE_ONE, false, "invoke-direct"); - - public static final Dop INVOKE_STATIC = - new Dop(DalvOps.INVOKE_STATIC, DalvOps.INVOKE_STATIC, - Form35c.THE_ONE, false, "invoke-static"); - - public static final Dop INVOKE_INTERFACE = - new Dop(DalvOps.INVOKE_INTERFACE, DalvOps.INVOKE_INTERFACE, - Form35c.THE_ONE, false, "invoke-interface"); - - public static final Dop INVOKE_VIRTUAL_RANGE = - new Dop(DalvOps.INVOKE_VIRTUAL_RANGE, DalvOps.INVOKE_VIRTUAL, - Form3rc.THE_ONE, false, "invoke-virtual/range"); - - public static final Dop INVOKE_SUPER_RANGE = - new Dop(DalvOps.INVOKE_SUPER_RANGE, DalvOps.INVOKE_SUPER, - Form3rc.THE_ONE, false, "invoke-super/range"); - - public static final Dop INVOKE_DIRECT_RANGE = - new Dop(DalvOps.INVOKE_DIRECT_RANGE, DalvOps.INVOKE_DIRECT, - Form3rc.THE_ONE, false, "invoke-direct/range"); - - public static final Dop INVOKE_STATIC_RANGE = - new Dop(DalvOps.INVOKE_STATIC_RANGE, DalvOps.INVOKE_STATIC, - Form3rc.THE_ONE, false, "invoke-static/range"); - - public static final Dop INVOKE_INTERFACE_RANGE = - new Dop(DalvOps.INVOKE_INTERFACE_RANGE, DalvOps.INVOKE_INTERFACE, - Form3rc.THE_ONE, false, "invoke-interface/range"); - - public static final Dop NEG_INT = - new Dop(DalvOps.NEG_INT, DalvOps.NEG_INT, - Form12x.THE_ONE, true, "neg-int"); - - public static final Dop NOT_INT = - new Dop(DalvOps.NOT_INT, DalvOps.NOT_INT, - Form12x.THE_ONE, true, "not-int"); - - public static final Dop NEG_LONG = - new Dop(DalvOps.NEG_LONG, DalvOps.NEG_LONG, - Form12x.THE_ONE, true, "neg-long"); - - public static final Dop NOT_LONG = - new Dop(DalvOps.NOT_LONG, DalvOps.NOT_LONG, - Form12x.THE_ONE, true, "not-long"); - - public static final Dop NEG_FLOAT = - new Dop(DalvOps.NEG_FLOAT, DalvOps.NEG_FLOAT, - Form12x.THE_ONE, true, "neg-float"); - - public static final Dop NEG_DOUBLE = - new Dop(DalvOps.NEG_DOUBLE, DalvOps.NEG_DOUBLE, - Form12x.THE_ONE, true, "neg-double"); - - public static final Dop INT_TO_LONG = - new Dop(DalvOps.INT_TO_LONG, DalvOps.INT_TO_LONG, - Form12x.THE_ONE, true, "int-to-long"); - - public static final Dop INT_TO_FLOAT = - new Dop(DalvOps.INT_TO_FLOAT, DalvOps.INT_TO_FLOAT, - Form12x.THE_ONE, true, "int-to-float"); - - public static final Dop INT_TO_DOUBLE = - new Dop(DalvOps.INT_TO_DOUBLE, DalvOps.INT_TO_DOUBLE, - Form12x.THE_ONE, true, "int-to-double"); - - public static final Dop LONG_TO_INT = - new Dop(DalvOps.LONG_TO_INT, DalvOps.LONG_TO_INT, - Form12x.THE_ONE, true, "long-to-int"); - - public static final Dop LONG_TO_FLOAT = - new Dop(DalvOps.LONG_TO_FLOAT, DalvOps.LONG_TO_FLOAT, - Form12x.THE_ONE, true, "long-to-float"); - - public static final Dop LONG_TO_DOUBLE = - new Dop(DalvOps.LONG_TO_DOUBLE, DalvOps.LONG_TO_DOUBLE, - Form12x.THE_ONE, true, "long-to-double"); - - public static final Dop FLOAT_TO_INT = - new Dop(DalvOps.FLOAT_TO_INT, DalvOps.FLOAT_TO_INT, - Form12x.THE_ONE, true, "float-to-int"); - - public static final Dop FLOAT_TO_LONG = - new Dop(DalvOps.FLOAT_TO_LONG, DalvOps.FLOAT_TO_LONG, - Form12x.THE_ONE, true, "float-to-long"); - - public static final Dop FLOAT_TO_DOUBLE = - new Dop(DalvOps.FLOAT_TO_DOUBLE, DalvOps.FLOAT_TO_DOUBLE, - Form12x.THE_ONE, true, "float-to-double"); - - public static final Dop DOUBLE_TO_INT = - new Dop(DalvOps.DOUBLE_TO_INT, DalvOps.DOUBLE_TO_INT, - Form12x.THE_ONE, true, "double-to-int"); - - public static final Dop DOUBLE_TO_LONG = - new Dop(DalvOps.DOUBLE_TO_LONG, DalvOps.DOUBLE_TO_LONG, - Form12x.THE_ONE, true, "double-to-long"); - - public static final Dop DOUBLE_TO_FLOAT = - new Dop(DalvOps.DOUBLE_TO_FLOAT, DalvOps.DOUBLE_TO_FLOAT, - Form12x.THE_ONE, true, "double-to-float"); - - public static final Dop INT_TO_BYTE = - new Dop(DalvOps.INT_TO_BYTE, DalvOps.INT_TO_BYTE, - Form12x.THE_ONE, true, "int-to-byte"); - - public static final Dop INT_TO_CHAR = - new Dop(DalvOps.INT_TO_CHAR, DalvOps.INT_TO_CHAR, - Form12x.THE_ONE, true, "int-to-char"); - - public static final Dop INT_TO_SHORT = - new Dop(DalvOps.INT_TO_SHORT, DalvOps.INT_TO_SHORT, - Form12x.THE_ONE, true, "int-to-short"); - - public static final Dop ADD_INT = - new Dop(DalvOps.ADD_INT, DalvOps.ADD_INT, - Form23x.THE_ONE, true, "add-int"); - - public static final Dop SUB_INT = - new Dop(DalvOps.SUB_INT, DalvOps.SUB_INT, - Form23x.THE_ONE, true, "sub-int"); - - public static final Dop MUL_INT = - new Dop(DalvOps.MUL_INT, DalvOps.MUL_INT, - Form23x.THE_ONE, true, "mul-int"); - - public static final Dop DIV_INT = - new Dop(DalvOps.DIV_INT, DalvOps.DIV_INT, - Form23x.THE_ONE, true, "div-int"); - - public static final Dop REM_INT = - new Dop(DalvOps.REM_INT, DalvOps.REM_INT, - Form23x.THE_ONE, true, "rem-int"); - - public static final Dop AND_INT = - new Dop(DalvOps.AND_INT, DalvOps.AND_INT, - Form23x.THE_ONE, true, "and-int"); - - public static final Dop OR_INT = - new Dop(DalvOps.OR_INT, DalvOps.OR_INT, - Form23x.THE_ONE, true, "or-int"); - - public static final Dop XOR_INT = - new Dop(DalvOps.XOR_INT, DalvOps.XOR_INT, - Form23x.THE_ONE, true, "xor-int"); - - public static final Dop SHL_INT = - new Dop(DalvOps.SHL_INT, DalvOps.SHL_INT, - Form23x.THE_ONE, true, "shl-int"); - - public static final Dop SHR_INT = - new Dop(DalvOps.SHR_INT, DalvOps.SHR_INT, - Form23x.THE_ONE, true, "shr-int"); - - public static final Dop USHR_INT = - new Dop(DalvOps.USHR_INT, DalvOps.USHR_INT, - Form23x.THE_ONE, true, "ushr-int"); - - public static final Dop ADD_LONG = - new Dop(DalvOps.ADD_LONG, DalvOps.ADD_LONG, - Form23x.THE_ONE, true, "add-long"); - - public static final Dop SUB_LONG = - new Dop(DalvOps.SUB_LONG, DalvOps.SUB_LONG, - Form23x.THE_ONE, true, "sub-long"); - - public static final Dop MUL_LONG = - new Dop(DalvOps.MUL_LONG, DalvOps.MUL_LONG, - Form23x.THE_ONE, true, "mul-long"); - - public static final Dop DIV_LONG = - new Dop(DalvOps.DIV_LONG, DalvOps.DIV_LONG, - Form23x.THE_ONE, true, "div-long"); - - public static final Dop REM_LONG = - new Dop(DalvOps.REM_LONG, DalvOps.REM_LONG, - Form23x.THE_ONE, true, "rem-long"); - - public static final Dop AND_LONG = - new Dop(DalvOps.AND_LONG, DalvOps.AND_LONG, - Form23x.THE_ONE, true, "and-long"); - - public static final Dop OR_LONG = - new Dop(DalvOps.OR_LONG, DalvOps.OR_LONG, - Form23x.THE_ONE, true, "or-long"); - - public static final Dop XOR_LONG = - new Dop(DalvOps.XOR_LONG, DalvOps.XOR_LONG, - Form23x.THE_ONE, true, "xor-long"); - - public static final Dop SHL_LONG = - new Dop(DalvOps.SHL_LONG, DalvOps.SHL_LONG, - Form23x.THE_ONE, true, "shl-long"); - - public static final Dop SHR_LONG = - new Dop(DalvOps.SHR_LONG, DalvOps.SHR_LONG, - Form23x.THE_ONE, true, "shr-long"); - - public static final Dop USHR_LONG = - new Dop(DalvOps.USHR_LONG, DalvOps.USHR_LONG, - Form23x.THE_ONE, true, "ushr-long"); - - public static final Dop ADD_FLOAT = - new Dop(DalvOps.ADD_FLOAT, DalvOps.ADD_FLOAT, - Form23x.THE_ONE, true, "add-float"); - - public static final Dop SUB_FLOAT = - new Dop(DalvOps.SUB_FLOAT, DalvOps.SUB_FLOAT, - Form23x.THE_ONE, true, "sub-float"); - - public static final Dop MUL_FLOAT = - new Dop(DalvOps.MUL_FLOAT, DalvOps.MUL_FLOAT, - Form23x.THE_ONE, true, "mul-float"); - - public static final Dop DIV_FLOAT = - new Dop(DalvOps.DIV_FLOAT, DalvOps.DIV_FLOAT, - Form23x.THE_ONE, true, "div-float"); - - public static final Dop REM_FLOAT = - new Dop(DalvOps.REM_FLOAT, DalvOps.REM_FLOAT, - Form23x.THE_ONE, true, "rem-float"); - - public static final Dop ADD_DOUBLE = - new Dop(DalvOps.ADD_DOUBLE, DalvOps.ADD_DOUBLE, - Form23x.THE_ONE, true, "add-double"); - - public static final Dop SUB_DOUBLE = - new Dop(DalvOps.SUB_DOUBLE, DalvOps.SUB_DOUBLE, - Form23x.THE_ONE, true, "sub-double"); - - public static final Dop MUL_DOUBLE = - new Dop(DalvOps.MUL_DOUBLE, DalvOps.MUL_DOUBLE, - Form23x.THE_ONE, true, "mul-double"); - - public static final Dop DIV_DOUBLE = - new Dop(DalvOps.DIV_DOUBLE, DalvOps.DIV_DOUBLE, - Form23x.THE_ONE, true, "div-double"); - - public static final Dop REM_DOUBLE = - new Dop(DalvOps.REM_DOUBLE, DalvOps.REM_DOUBLE, - Form23x.THE_ONE, true, "rem-double"); - - public static final Dop ADD_INT_2ADDR = - new Dop(DalvOps.ADD_INT_2ADDR, DalvOps.ADD_INT, - Form12x.THE_ONE, true, "add-int/2addr"); - - public static final Dop SUB_INT_2ADDR = - new Dop(DalvOps.SUB_INT_2ADDR, DalvOps.SUB_INT, - Form12x.THE_ONE, true, "sub-int/2addr"); - - public static final Dop MUL_INT_2ADDR = - new Dop(DalvOps.MUL_INT_2ADDR, DalvOps.MUL_INT, - Form12x.THE_ONE, true, "mul-int/2addr"); - - public static final Dop DIV_INT_2ADDR = - new Dop(DalvOps.DIV_INT_2ADDR, DalvOps.DIV_INT, - Form12x.THE_ONE, true, "div-int/2addr"); - - public static final Dop REM_INT_2ADDR = - new Dop(DalvOps.REM_INT_2ADDR, DalvOps.REM_INT, - Form12x.THE_ONE, true, "rem-int/2addr"); - - public static final Dop AND_INT_2ADDR = - new Dop(DalvOps.AND_INT_2ADDR, DalvOps.AND_INT, - Form12x.THE_ONE, true, "and-int/2addr"); - - public static final Dop OR_INT_2ADDR = - new Dop(DalvOps.OR_INT_2ADDR, DalvOps.OR_INT, - Form12x.THE_ONE, true, "or-int/2addr"); - - public static final Dop XOR_INT_2ADDR = - new Dop(DalvOps.XOR_INT_2ADDR, DalvOps.XOR_INT, - Form12x.THE_ONE, true, "xor-int/2addr"); - - public static final Dop SHL_INT_2ADDR = - new Dop(DalvOps.SHL_INT_2ADDR, DalvOps.SHL_INT, - Form12x.THE_ONE, true, "shl-int/2addr"); - - public static final Dop SHR_INT_2ADDR = - new Dop(DalvOps.SHR_INT_2ADDR, DalvOps.SHR_INT, - Form12x.THE_ONE, true, "shr-int/2addr"); - - public static final Dop USHR_INT_2ADDR = - new Dop(DalvOps.USHR_INT_2ADDR, DalvOps.USHR_INT, - Form12x.THE_ONE, true, "ushr-int/2addr"); - - public static final Dop ADD_LONG_2ADDR = - new Dop(DalvOps.ADD_LONG_2ADDR, DalvOps.ADD_LONG, - Form12x.THE_ONE, true, "add-long/2addr"); - - public static final Dop SUB_LONG_2ADDR = - new Dop(DalvOps.SUB_LONG_2ADDR, DalvOps.SUB_LONG, - Form12x.THE_ONE, true, "sub-long/2addr"); - - public static final Dop MUL_LONG_2ADDR = - new Dop(DalvOps.MUL_LONG_2ADDR, DalvOps.MUL_LONG, - Form12x.THE_ONE, true, "mul-long/2addr"); - - public static final Dop DIV_LONG_2ADDR = - new Dop(DalvOps.DIV_LONG_2ADDR, DalvOps.DIV_LONG, - Form12x.THE_ONE, true, "div-long/2addr"); - - public static final Dop REM_LONG_2ADDR = - new Dop(DalvOps.REM_LONG_2ADDR, DalvOps.REM_LONG, - Form12x.THE_ONE, true, "rem-long/2addr"); - - public static final Dop AND_LONG_2ADDR = - new Dop(DalvOps.AND_LONG_2ADDR, DalvOps.AND_LONG, - Form12x.THE_ONE, true, "and-long/2addr"); - - public static final Dop OR_LONG_2ADDR = - new Dop(DalvOps.OR_LONG_2ADDR, DalvOps.OR_LONG, - Form12x.THE_ONE, true, "or-long/2addr"); - - public static final Dop XOR_LONG_2ADDR = - new Dop(DalvOps.XOR_LONG_2ADDR, DalvOps.XOR_LONG, - Form12x.THE_ONE, true, "xor-long/2addr"); - - public static final Dop SHL_LONG_2ADDR = - new Dop(DalvOps.SHL_LONG_2ADDR, DalvOps.SHL_LONG, - Form12x.THE_ONE, true, "shl-long/2addr"); - - public static final Dop SHR_LONG_2ADDR = - new Dop(DalvOps.SHR_LONG_2ADDR, DalvOps.SHR_LONG, - Form12x.THE_ONE, true, "shr-long/2addr"); - - public static final Dop USHR_LONG_2ADDR = - new Dop(DalvOps.USHR_LONG_2ADDR, DalvOps.USHR_LONG, - Form12x.THE_ONE, true, "ushr-long/2addr"); - - public static final Dop ADD_FLOAT_2ADDR = - new Dop(DalvOps.ADD_FLOAT_2ADDR, DalvOps.ADD_FLOAT, - Form12x.THE_ONE, true, "add-float/2addr"); - - public static final Dop SUB_FLOAT_2ADDR = - new Dop(DalvOps.SUB_FLOAT_2ADDR, DalvOps.SUB_FLOAT, - Form12x.THE_ONE, true, "sub-float/2addr"); - - public static final Dop MUL_FLOAT_2ADDR = - new Dop(DalvOps.MUL_FLOAT_2ADDR, DalvOps.MUL_FLOAT, - Form12x.THE_ONE, true, "mul-float/2addr"); - - public static final Dop DIV_FLOAT_2ADDR = - new Dop(DalvOps.DIV_FLOAT_2ADDR, DalvOps.DIV_FLOAT, - Form12x.THE_ONE, true, "div-float/2addr"); - - public static final Dop REM_FLOAT_2ADDR = - new Dop(DalvOps.REM_FLOAT_2ADDR, DalvOps.REM_FLOAT, - Form12x.THE_ONE, true, "rem-float/2addr"); - - public static final Dop ADD_DOUBLE_2ADDR = - new Dop(DalvOps.ADD_DOUBLE_2ADDR, DalvOps.ADD_DOUBLE, - Form12x.THE_ONE, true, "add-double/2addr"); - - public static final Dop SUB_DOUBLE_2ADDR = - new Dop(DalvOps.SUB_DOUBLE_2ADDR, DalvOps.SUB_DOUBLE, - Form12x.THE_ONE, true, "sub-double/2addr"); - - public static final Dop MUL_DOUBLE_2ADDR = - new Dop(DalvOps.MUL_DOUBLE_2ADDR, DalvOps.MUL_DOUBLE, - Form12x.THE_ONE, true, "mul-double/2addr"); - - public static final Dop DIV_DOUBLE_2ADDR = - new Dop(DalvOps.DIV_DOUBLE_2ADDR, DalvOps.DIV_DOUBLE, - Form12x.THE_ONE, true, "div-double/2addr"); - - public static final Dop REM_DOUBLE_2ADDR = - new Dop(DalvOps.REM_DOUBLE_2ADDR, DalvOps.REM_DOUBLE, - Form12x.THE_ONE, true, "rem-double/2addr"); - - public static final Dop ADD_INT_LIT16 = - new Dop(DalvOps.ADD_INT_LIT16, DalvOps.ADD_INT, - Form22s.THE_ONE, true, "add-int/lit16"); - - public static final Dop RSUB_INT = - new Dop(DalvOps.RSUB_INT, DalvOps.RSUB_INT, - Form22s.THE_ONE, true, "rsub-int"); - - public static final Dop MUL_INT_LIT16 = - new Dop(DalvOps.MUL_INT_LIT16, DalvOps.MUL_INT, - Form22s.THE_ONE, true, "mul-int/lit16"); - - public static final Dop DIV_INT_LIT16 = - new Dop(DalvOps.DIV_INT_LIT16, DalvOps.DIV_INT, - Form22s.THE_ONE, true, "div-int/lit16"); - - public static final Dop REM_INT_LIT16 = - new Dop(DalvOps.REM_INT_LIT16, DalvOps.REM_INT, - Form22s.THE_ONE, true, "rem-int/lit16"); - - public static final Dop AND_INT_LIT16 = - new Dop(DalvOps.AND_INT_LIT16, DalvOps.AND_INT, - Form22s.THE_ONE, true, "and-int/lit16"); - - public static final Dop OR_INT_LIT16 = - new Dop(DalvOps.OR_INT_LIT16, DalvOps.OR_INT, - Form22s.THE_ONE, true, "or-int/lit16"); - - public static final Dop XOR_INT_LIT16 = - new Dop(DalvOps.XOR_INT_LIT16, DalvOps.XOR_INT, - Form22s.THE_ONE, true, "xor-int/lit16"); - - public static final Dop ADD_INT_LIT8 = - new Dop(DalvOps.ADD_INT_LIT8, DalvOps.ADD_INT, - Form22b.THE_ONE, true, "add-int/lit8"); - - public static final Dop RSUB_INT_LIT8 = - new Dop(DalvOps.RSUB_INT_LIT8, DalvOps.RSUB_INT, - Form22b.THE_ONE, true, "rsub-int/lit8"); - - public static final Dop MUL_INT_LIT8 = - new Dop(DalvOps.MUL_INT_LIT8, DalvOps.MUL_INT, - Form22b.THE_ONE, true, "mul-int/lit8"); - - public static final Dop DIV_INT_LIT8 = - new Dop(DalvOps.DIV_INT_LIT8, DalvOps.DIV_INT, - Form22b.THE_ONE, true, "div-int/lit8"); - - public static final Dop REM_INT_LIT8 = - new Dop(DalvOps.REM_INT_LIT8, DalvOps.REM_INT, - Form22b.THE_ONE, true, "rem-int/lit8"); - - public static final Dop AND_INT_LIT8 = - new Dop(DalvOps.AND_INT_LIT8, DalvOps.AND_INT, - Form22b.THE_ONE, true, "and-int/lit8"); - - public static final Dop OR_INT_LIT8 = - new Dop(DalvOps.OR_INT_LIT8, DalvOps.OR_INT, - Form22b.THE_ONE, true, "or-int/lit8"); - - public static final Dop XOR_INT_LIT8 = - new Dop(DalvOps.XOR_INT_LIT8, DalvOps.XOR_INT, - Form22b.THE_ONE, true, "xor-int/lit8"); - - public static final Dop SHL_INT_LIT8 = - new Dop(DalvOps.SHL_INT_LIT8, DalvOps.SHL_INT, - Form22b.THE_ONE, true, "shl-int/lit8"); - - public static final Dop SHR_INT_LIT8 = - new Dop(DalvOps.SHR_INT_LIT8, DalvOps.SHR_INT, - Form22b.THE_ONE, true, "shr-int/lit8"); - - public static final Dop USHR_INT_LIT8 = - new Dop(DalvOps.USHR_INT_LIT8, DalvOps.USHR_INT, - Form22b.THE_ONE, true, "ushr-int/lit8"); - - // END(dops) - - // Static initialization. - static { - DOPS = new Dop[DalvOps.MAX_VALUE - DalvOps.MIN_VALUE + 1]; - - set(SPECIAL_FORMAT); - - // BEGIN(dops-init); GENERATED AUTOMATICALLY BY opcode-gen - set(NOP); - set(MOVE); - set(MOVE_FROM16); - set(MOVE_16); - set(MOVE_WIDE); - set(MOVE_WIDE_FROM16); - set(MOVE_WIDE_16); - set(MOVE_OBJECT); - set(MOVE_OBJECT_FROM16); - set(MOVE_OBJECT_16); - set(MOVE_RESULT); - set(MOVE_RESULT_WIDE); - set(MOVE_RESULT_OBJECT); - set(MOVE_EXCEPTION); - set(RETURN_VOID); - set(RETURN); - set(RETURN_WIDE); - set(RETURN_OBJECT); - set(CONST_4); - set(CONST_16); - set(CONST); - set(CONST_HIGH16); - set(CONST_WIDE_16); - set(CONST_WIDE_32); - set(CONST_WIDE); - set(CONST_WIDE_HIGH16); - set(CONST_STRING); - set(CONST_STRING_JUMBO); - set(CONST_CLASS); - set(MONITOR_ENTER); - set(MONITOR_EXIT); - set(CHECK_CAST); - set(INSTANCE_OF); - set(ARRAY_LENGTH); - set(NEW_INSTANCE); - set(NEW_ARRAY); - set(FILLED_NEW_ARRAY); - set(FILLED_NEW_ARRAY_RANGE); - set(FILL_ARRAY_DATA); - set(THROW); - set(GOTO); - set(GOTO_16); - set(GOTO_32); - set(PACKED_SWITCH); - set(SPARSE_SWITCH); - set(CMPL_FLOAT); - set(CMPG_FLOAT); - set(CMPL_DOUBLE); - set(CMPG_DOUBLE); - set(CMP_LONG); - set(IF_EQ); - set(IF_NE); - set(IF_LT); - set(IF_GE); - set(IF_GT); - set(IF_LE); - set(IF_EQZ); - set(IF_NEZ); - set(IF_LTZ); - set(IF_GEZ); - set(IF_GTZ); - set(IF_LEZ); - set(AGET); - set(AGET_WIDE); - set(AGET_OBJECT); - set(AGET_BOOLEAN); - set(AGET_BYTE); - set(AGET_CHAR); - set(AGET_SHORT); - set(APUT); - set(APUT_WIDE); - set(APUT_OBJECT); - set(APUT_BOOLEAN); - set(APUT_BYTE); - set(APUT_CHAR); - set(APUT_SHORT); - set(IGET); - set(IGET_WIDE); - set(IGET_OBJECT); - set(IGET_BOOLEAN); - set(IGET_BYTE); - set(IGET_CHAR); - set(IGET_SHORT); - set(IPUT); - set(IPUT_WIDE); - set(IPUT_OBJECT); - set(IPUT_BOOLEAN); - set(IPUT_BYTE); - set(IPUT_CHAR); - set(IPUT_SHORT); - set(SGET); - set(SGET_WIDE); - set(SGET_OBJECT); - set(SGET_BOOLEAN); - set(SGET_BYTE); - set(SGET_CHAR); - set(SGET_SHORT); - set(SPUT); - set(SPUT_WIDE); - set(SPUT_OBJECT); - set(SPUT_BOOLEAN); - set(SPUT_BYTE); - set(SPUT_CHAR); - set(SPUT_SHORT); - set(INVOKE_VIRTUAL); - set(INVOKE_SUPER); - set(INVOKE_DIRECT); - set(INVOKE_STATIC); - set(INVOKE_INTERFACE); - set(INVOKE_VIRTUAL_RANGE); - set(INVOKE_SUPER_RANGE); - set(INVOKE_DIRECT_RANGE); - set(INVOKE_STATIC_RANGE); - set(INVOKE_INTERFACE_RANGE); - set(NEG_INT); - set(NOT_INT); - set(NEG_LONG); - set(NOT_LONG); - set(NEG_FLOAT); - set(NEG_DOUBLE); - set(INT_TO_LONG); - set(INT_TO_FLOAT); - set(INT_TO_DOUBLE); - set(LONG_TO_INT); - set(LONG_TO_FLOAT); - set(LONG_TO_DOUBLE); - set(FLOAT_TO_INT); - set(FLOAT_TO_LONG); - set(FLOAT_TO_DOUBLE); - set(DOUBLE_TO_INT); - set(DOUBLE_TO_LONG); - set(DOUBLE_TO_FLOAT); - set(INT_TO_BYTE); - set(INT_TO_CHAR); - set(INT_TO_SHORT); - set(ADD_INT); - set(SUB_INT); - set(MUL_INT); - set(DIV_INT); - set(REM_INT); - set(AND_INT); - set(OR_INT); - set(XOR_INT); - set(SHL_INT); - set(SHR_INT); - set(USHR_INT); - set(ADD_LONG); - set(SUB_LONG); - set(MUL_LONG); - set(DIV_LONG); - set(REM_LONG); - set(AND_LONG); - set(OR_LONG); - set(XOR_LONG); - set(SHL_LONG); - set(SHR_LONG); - set(USHR_LONG); - set(ADD_FLOAT); - set(SUB_FLOAT); - set(MUL_FLOAT); - set(DIV_FLOAT); - set(REM_FLOAT); - set(ADD_DOUBLE); - set(SUB_DOUBLE); - set(MUL_DOUBLE); - set(DIV_DOUBLE); - set(REM_DOUBLE); - set(ADD_INT_2ADDR); - set(SUB_INT_2ADDR); - set(MUL_INT_2ADDR); - set(DIV_INT_2ADDR); - set(REM_INT_2ADDR); - set(AND_INT_2ADDR); - set(OR_INT_2ADDR); - set(XOR_INT_2ADDR); - set(SHL_INT_2ADDR); - set(SHR_INT_2ADDR); - set(USHR_INT_2ADDR); - set(ADD_LONG_2ADDR); - set(SUB_LONG_2ADDR); - set(MUL_LONG_2ADDR); - set(DIV_LONG_2ADDR); - set(REM_LONG_2ADDR); - set(AND_LONG_2ADDR); - set(OR_LONG_2ADDR); - set(XOR_LONG_2ADDR); - set(SHL_LONG_2ADDR); - set(SHR_LONG_2ADDR); - set(USHR_LONG_2ADDR); - set(ADD_FLOAT_2ADDR); - set(SUB_FLOAT_2ADDR); - set(MUL_FLOAT_2ADDR); - set(DIV_FLOAT_2ADDR); - set(REM_FLOAT_2ADDR); - set(ADD_DOUBLE_2ADDR); - set(SUB_DOUBLE_2ADDR); - set(MUL_DOUBLE_2ADDR); - set(DIV_DOUBLE_2ADDR); - set(REM_DOUBLE_2ADDR); - set(ADD_INT_LIT16); - set(RSUB_INT); - set(MUL_INT_LIT16); - set(DIV_INT_LIT16); - set(REM_INT_LIT16); - set(AND_INT_LIT16); - set(OR_INT_LIT16); - set(XOR_INT_LIT16); - set(ADD_INT_LIT8); - set(RSUB_INT_LIT8); - set(MUL_INT_LIT8); - set(DIV_INT_LIT8); - set(REM_INT_LIT8); - set(AND_INT_LIT8); - set(OR_INT_LIT8); - set(XOR_INT_LIT8); - set(SHL_INT_LIT8); - set(SHR_INT_LIT8); - set(USHR_INT_LIT8); - // END(dops-init) - } - - /** - * This class is uninstantiable. - */ - private Dops() { - // This space intentionally left blank. - } - - /** - * Gets the {@link Dop} for the given opcode value. - * - * @param opcode DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode value - * @return non-null; the associated opcode instance - */ - public static Dop get(int opcode) { - int idx = opcode - DalvOps.MIN_VALUE; - - try { - Dop result = DOPS[idx]; - if (result != null) { - return result; - } - } catch (ArrayIndexOutOfBoundsException ex) { - // Fall through. - } - - throw new IllegalArgumentException("bogus opcode"); - } - - /** - * Gets the {@link Dop} with the given family/format combination, if - * any. - * - * @param family DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode family - * @param format non-null; the opcode's instruction format - * @return null-ok; the corresponding opcode, or <code>null</code> if - * there is none - */ - public static Dop getOrNull(int family, InsnFormat format) { - if (format == null) { - throw new NullPointerException("format == null"); - } - - int len = DOPS.length; - - // TODO: Linear search is bad. - for (int i = 0; i < len; i++) { - Dop dop = DOPS[i]; - if ((dop != null) && - (dop.getFamily() == family) && - (dop.getFormat() == format)) { - return dop; - } - } - - return null; - } - - /** - * Puts the given opcode into the table of all ops. - * - * @param opcode non-null; the opcode - */ - private static void set(Dop opcode) { - int idx = opcode.getOpcode() - DalvOps.MIN_VALUE; - DOPS[idx] = opcode; - } -} diff --git a/dx/src/com/android/dx/dex/code/FixedSizeInsn.java b/dx/src/com/android/dx/dex/code/FixedSizeInsn.java deleted file mode 100644 index 63c9d2407..000000000 --- a/dx/src/com/android/dx/dex/code/FixedSizeInsn.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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.util.AnnotatedOutput; - -/** - * Base class for instructions which are of a fixed code size and - * which use {@link InsnFormat} methods to write themselves. This - * includes most — but not all — instructions. - */ -public abstract class FixedSizeInsn extends DalvInsn { - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * <p><b>Note:</b> In the unlikely event that an instruction takes - * absolutely no registers (e.g., a <code>nop</code> or a - * no-argument no-result * static method call), then the given - * register list may be passed as {@link - * RegisterSpecList#EMPTY}.</p> - * - * @param opcode the opcode; one of the constants from {@link Dops} - * @param position non-null; source position - * @param registers non-null; register list, including a - * result register if appropriate (that is, registers may be either - * ins or outs) - */ - public FixedSizeInsn(Dop opcode, SourcePosition position, - RegisterSpecList registers) { - super(opcode, position, registers); - } - - /** {@inheritDoc} */ - @Override - public final int codeSize() { - return getOpcode().getFormat().codeSize(); - } - - /** {@inheritDoc} */ - @Override - public final void writeTo(AnnotatedOutput out) { - getOpcode().getFormat().writeTo(out, this); - } - - /** {@inheritDoc} */ - @Override - public final DalvInsn withRegisterOffset(int delta) { - return withRegisters(getRegisters().withOffset(delta)); - } - - /** {@inheritDoc} */ - @Override - protected final String listingString0(boolean noteIndices) { - return getOpcode().getFormat().listingString(this, noteIndices); - } -} diff --git a/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java b/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java deleted file mode 100644 index 458bc893d..000000000 --- a/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java +++ /dev/null @@ -1,147 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.type.Type; -import com.android.dx.util.AnnotatedOutput; - -/** - * Combination instruction which turns into a variable number of - * <code>move*</code> instructions to move a set of registers into - * registers starting at <code>0</code> sequentially. This is used - * in translating an instruction whose register requirements cannot - * be met using a straightforward choice of a single opcode. - */ -public final class HighRegisterPrefix extends VariableSizeInsn { - /** null-ok; cached instructions, if constructed */ - private SimpleInsn[] insns; - - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param position non-null; source position - * @param registers non-null; source registers - */ - public HighRegisterPrefix(SourcePosition position, - RegisterSpecList registers) { - super(position, registers); - - if (registers.size() == 0) { - throw new IllegalArgumentException("registers.size() == 0"); - } - - insns = null; - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - int result = 0; - - calculateInsnsIfNecessary(); - - for (SimpleInsn insn : insns) { - result += insn.codeSize(); - } - - return result; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out) { - calculateInsnsIfNecessary(); - - for (SimpleInsn insn : insns) { - insn.writeTo(out); - } - } - - /** - * Helper for {@link #codeSize} and {@link #writeTo} which sets up - * {@link #insns} if not already done. - */ - private void calculateInsnsIfNecessary() { - if (insns != null) { - return; - } - - RegisterSpecList registers = getRegisters(); - int sz = registers.size(); - - insns = new SimpleInsn[sz]; - - for (int i = 0, outAt = 0; i < sz; i++) { - RegisterSpec src = registers.get(i); - insns[i] = moveInsnFor(src, outAt); - outAt += src.getCategory(); - } - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisters(RegisterSpecList registers) { - return new HighRegisterPrefix(getPosition(), registers); - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - return null; - } - - /** {@inheritDoc} */ - @Override - protected String listingString0(boolean noteIndices) { - RegisterSpecList registers = getRegisters(); - int sz = registers.size(); - StringBuffer sb = new StringBuffer(100); - - for (int i = 0, outAt = 0; i < sz; i++) { - RegisterSpec src = registers.get(i); - SimpleInsn insn = moveInsnFor(src, outAt); - - if (i != 0) { - sb.append('\n'); - } - - sb.append(insn.listingString0(noteIndices)); - - outAt += src.getCategory(); - } - - return sb.toString(); - } - - /** - * Returns the proper move instruction for the given source spec - * and destination index. - * - * @param src non-null; the source register spec - * @param destIndex >= 0; the destination register index - * @return non-null; the appropriate move instruction - */ - private static SimpleInsn moveInsnFor(RegisterSpec src, int destIndex) { - return DalvInsn.makeMove(SourcePosition.NO_INFO, - RegisterSpec.make(destIndex, src.getType()), - src); - } -} diff --git a/dx/src/com/android/dx/dex/code/InsnFormat.java b/dx/src/com/android/dx/dex/code/InsnFormat.java deleted file mode 100644 index ed4137b3f..000000000 --- a/dx/src/com/android/dx/dex/code/InsnFormat.java +++ /dev/null @@ -1,578 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstKnownNull; -import com.android.dx.rop.cst.CstLiteral64; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Base class for all instruction format handlers. Instruction format - * handlers know how to translate {@link DalvInsn} instances into - * streams of code words, as well as human-oriented listing strings - * representing such translations. - */ -public abstract class InsnFormat { - /** - * Returns the string form, suitable for inclusion in a listing - * dump, of the given instruction. The instruction must be of this - * instance's format for proper operation. - * - * @param insn non-null; the instruction - * @param noteIndices whether to include an explicit notation of - * constant pool indices - * @return non-null; the string form - */ - public final String listingString(DalvInsn insn, boolean noteIndices) { - String op = insn.getOpcode().getName(); - String arg = insnArgString(insn); - String comment = insnCommentString(insn, noteIndices); - StringBuilder sb = new StringBuilder(100); - - sb.append(op); - - if (arg.length() != 0) { - sb.append(' '); - sb.append(arg); - } - - if (comment.length() != 0) { - sb.append(" // "); - sb.append(comment); - } - - return sb.toString(); - } - - /** - * Returns the string form of the arguments to the given instruction. - * The instruction must be of this instance's format. If the instruction - * has no arguments, then the result should be <code>""</code>, not - * <code>null</code>. - * - * <p>Subclasses must override this method.</p> - * - * @param insn non-null; the instruction - * @return non-null; the string form - */ - public abstract String insnArgString(DalvInsn insn); - - /** - * Returns the associated comment for the given instruction, if any. - * The instruction must be of this instance's format. If the instruction - * has no comment, then the result should be <code>""</code>, not - * <code>null</code>. - * - * <p>Subclasses must override this method.</p> - * - * @param insn non-null; the instruction - * @param noteIndices whether to include an explicit notation of - * constant pool indices - * @return non-null; the string form - */ - public abstract String insnCommentString(DalvInsn insn, - boolean noteIndices); - - /** - * Gets the code size of instructions that use this format. The - * size is a number of 16-bit code units, not bytes. This should - * throw an exception if this format is of variable size. - * - * @return >= 0; the instruction length in 16-bit code units - */ - public abstract int codeSize(); - - /** - * Returns whether or not the given instruction's arguments will - * fit in this instance's format. This includes such things as - * counting register arguments, checking register ranges, and - * making sure that additional arguments are of appropriate types - * and are in-range. If this format has a branch target but the - * instruction's branch offset is unknown, this method will simply - * not check the offset. - * - * <p>Subclasses must override this method.</p> - * - * @param insn non-null; the instruction to check - * @return <code>true</code> iff the instruction's arguments are - * appropriate for this instance, or <code>false</code> if not - */ - public abstract boolean isCompatible(DalvInsn insn); - - /** - * Returns whether or not the given instruction's branch offset will - * fit in this instance's format. This always returns <code>false</code> - * for formats that don't include a branch offset. - * - * <p>The default implementation of this method always returns - * <code>false</code>. Subclasses must override this method if they - * include branch offsets.</p> - * - * @param insn non-null; the instruction to check - * @return <code>true</code> iff the instruction's branch offset is - * appropriate for this instance, or <code>false</code> if not - */ - public boolean branchFits(TargetInsn insn) { - return false; - } - - /** - * Returns the next instruction format to try to match an instruction - * with, presuming that this instance isn't compatible, if any. - * - * <p>Subclasses must override this method.</p> - * - * @return null-ok; the next format to try, or <code>null</code> if - * there are no suitable alternatives - */ - public abstract InsnFormat nextUp(); - - /** - * Writes the code units for the given instruction to the given - * output destination. The instruction must be of this instance's format. - * - * <p>Subclasses must override this method.</p> - * - * @param out non-null; the output destination to write to - * @param insn non-null; the instruction to write - */ - public abstract void writeTo(AnnotatedOutput out, DalvInsn insn); - - /** - * Helper method to return a register list string. - * - * @param list non-null; the list of registers - * @return non-null; the string form - */ - protected static String regListString(RegisterSpecList list) { - int sz = list.size(); - StringBuffer sb = new StringBuffer(sz * 5 + 2); - - sb.append('{'); - - for (int i = 0; i < sz; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(list.get(i).regString()); - } - - sb.append('}'); - - return sb.toString(); - } - - /** - * Helper method to return a literal bits argument string. - * - * @param value the value - * @return non-null; the string form - */ - protected static String literalBitsString(CstLiteralBits value) { - StringBuffer sb = new StringBuffer(100); - - sb.append('#'); - - if (value instanceof CstKnownNull) { - sb.append("null"); - } else { - sb.append(value.typeName()); - sb.append(' '); - sb.append(value.toHuman()); - } - - return sb.toString(); - } - - /** - * Helper method to return a literal bits comment string. - * - * @param value the value - * @param width the width of the constant, in bits (used for displaying - * the uninterpreted bits; one of: <code>4 8 16 32 64</code> - * @return non-null; the comment - */ - protected static String literalBitsComment(CstLiteralBits value, - int width) { - StringBuffer sb = new StringBuffer(20); - - sb.append("#"); - - long bits; - - if (value instanceof CstLiteral64) { - bits = ((CstLiteral64) value).getLongBits(); - } else { - bits = value.getIntBits(); - } - - switch (width) { - case 4: sb.append(Hex.uNibble((int) bits)); break; - case 8: sb.append(Hex.u1((int) bits)); break; - case 16: sb.append(Hex.u2((int) bits)); break; - case 32: sb.append(Hex.u4((int) bits)); break; - case 64: sb.append(Hex.u8(bits)); break; - default: { - throw new RuntimeException("shouldn't happen"); - } - } - - return sb.toString(); - } - - /** - * Helper method to return a branch address string. - * - * @param insn non-null; the instruction in question - * @return non-null; the string form of the instruction's branch target - */ - protected static String branchString(DalvInsn insn) { - TargetInsn ti = (TargetInsn) insn; - int address = ti.getTargetAddress(); - - return (address == (char) address) ? Hex.u2(address) : Hex.u4(address); - } - - /** - * Helper method to return the comment for a branch. - * - * @param insn non-null; the instruction in question - * @return non-null; the comment - */ - protected static String branchComment(DalvInsn insn) { - TargetInsn ti = (TargetInsn) insn; - int offset = ti.getTargetOffset(); - - return (offset == (short) offset) ? Hex.s2(offset) : Hex.s4(offset); - } - - /** - * Helper method to return a constant string. - * - * @param insn non-null; a constant-bearing instruction - * @return non-null; the string form of the contained constant - */ - protected static String cstString(DalvInsn insn) { - CstInsn ci = (CstInsn) insn; - Constant cst = ci.getConstant(); - - return cst.toHuman(); - } - - /** - * Helper method to return an instruction comment for a constant. - * - * @param insn non-null; a constant-bearing instruction - * @return non-null; comment string representing the constant - */ - protected static String cstComment(DalvInsn insn) { - CstInsn ci = (CstInsn) insn; - - if (! ci.hasIndex()) { - return ""; - } - - StringBuilder sb = new StringBuilder(20); - int index = ci.getIndex(); - - sb.append(ci.getConstant().typeName()); - sb.append('@'); - - if (index < 65536) { - sb.append(Hex.u2(index)); - } else { - sb.append(Hex.u4(index)); - } - - return sb.toString(); - } - - /** - * Helper method to determine if a signed int value fits in a nibble. - * - * @param value the value in question - * @return <code>true</code> iff it's in the range -8..+7 - */ - protected static boolean signedFitsInNibble(int value) { - return (value >= -8) && (value <= 7); - } - - /** - * Helper method to determine if an unsigned int value fits in a nibble. - * - * @param value the value in question - * @return <code>true</code> iff it's in the range 0..0xf - */ - protected static boolean unsignedFitsInNibble(int value) { - return value == (value & 0xf); - } - - /** - * Helper method to determine if a signed int value fits in a byte. - * - * @param value the value in question - * @return <code>true</code> iff it's in the range -0x80..+0x7f - */ - protected static boolean signedFitsInByte(int value) { - return (byte) value == value; - } - - /** - * Helper method to determine if an unsigned int value fits in a byte. - * - * @param value the value in question - * @return <code>true</code> iff it's in the range 0..0xff - */ - protected static boolean unsignedFitsInByte(int value) { - return value == (value & 0xff); - } - - /** - * Helper method to determine if a signed int value fits in a short. - * - * @param value the value in question - * @return <code>true</code> iff it's in the range -0x8000..+0x7fff - */ - protected static boolean signedFitsInShort(int value) { - return (short) value == value; - } - - /** - * Helper method to determine if an unsigned int value fits in a short. - * - * @param value the value in question - * @return <code>true</code> iff it's in the range 0..0xffff - */ - protected static boolean unsignedFitsInShort(int value) { - return value == (value & 0xffff); - } - - /** - * Helper method to determine if a signed int value fits in three bytes. - * - * @param value the value in question - * @return <code>true</code> iff it's in the range -0x800000..+0x7fffff - */ - protected static boolean signedFitsIn3Bytes(int value) { - return value == ((value << 8) >> 8); - } - - /** - * Helper method to extract the callout-argument index from an - * appropriate instruction. - * - * @param insn non-null; the instruction - * @return >= 0; the callout argument index - */ - protected static int argIndex(DalvInsn insn) { - int arg = ((CstInteger) ((CstInsn) insn).getConstant()).getValue(); - - if (arg < 0) { - throw new IllegalArgumentException("bogus insn"); - } - - return arg; - } - - /** - * Helper method to combine an opcode and a second byte of data into - * the appropriate form for emitting into a code buffer. - * - * @param insn non-null; the instruction containing the opcode - * @param arg 0..255; arbitrary other byte value - * @return combined value - */ - protected static short opcodeUnit(DalvInsn insn, int arg) { - if ((arg & 0xff) != arg) { - throw new IllegalArgumentException("arg out of range 0..255"); - } - - int opcode = insn.getOpcode().getOpcode(); - - if ((opcode & 0xff) != opcode) { - throw new IllegalArgumentException("opcode out of range 0..255"); - } - - return (short) (opcode | (arg << 8)); - } - - /** - * Helper method to combine two bytes into a code unit. - * - * @param low 0..255; low byte - * @param high 0..255; high byte - * @return combined value - */ - protected static short codeUnit(int low, int high) { - if ((low & 0xff) != low) { - throw new IllegalArgumentException("low out of range 0..255"); - } - - if ((high & 0xff) != high) { - throw new IllegalArgumentException("high out of range 0..255"); - } - - return (short) (low | (high << 8)); - } - - /** - * Helper method to combine four nibbles into a code unit. - * - * @param n0 0..15; low nibble - * @param n1 0..15; medium-low nibble - * @param n2 0..15; medium-high nibble - * @param n3 0..15; high nibble - * @return combined value - */ - protected static short codeUnit(int n0, int n1, int n2, int n3) { - if ((n0 & 0xf) != n0) { - throw new IllegalArgumentException("n0 out of range 0..15"); - } - - if ((n1 & 0xf) != n1) { - throw new IllegalArgumentException("n1 out of range 0..15"); - } - - if ((n2 & 0xf) != n2) { - throw new IllegalArgumentException("n2 out of range 0..15"); - } - - if ((n3 & 0xf) != n3) { - throw new IllegalArgumentException("n3 out of range 0..15"); - } - - return (short) (n0 | (n1 << 4) | (n2 << 8) | (n3 << 12)); - } - - /** - * Helper method to combine two nibbles into a byte. - * - * @param low 0..15; low nibble - * @param high 0..15; high nibble - * @return 0..255; combined value - */ - protected static int makeByte(int low, int high) { - if ((low & 0xf) != low) { - throw new IllegalArgumentException("low out of range 0..15"); - } - - if ((high & 0xf) != high) { - throw new IllegalArgumentException("high out of range 0..15"); - } - - return low | (high << 4); - } - - /** - * Writes one code unit to the given output destination. - * - * @param out non-null; where to write to - * @param c0 code unit to write - */ - protected static void write(AnnotatedOutput out, short c0) { - out.writeShort(c0); - } - - /** - * Writes two code units to the given output destination. - * - * @param out non-null; where to write to - * @param c0 code unit to write - * @param c1 code unit to write - */ - protected static void write(AnnotatedOutput out, short c0, short c1) { - out.writeShort(c0); - out.writeShort(c1); - } - - /** - * Writes three code units to the given output destination. - * - * @param out non-null; where to write to - * @param c0 code unit to write - * @param c1 code unit to write - * @param c2 code unit to write - */ - protected static void write(AnnotatedOutput out, short c0, short c1, - short c2) { - out.writeShort(c0); - out.writeShort(c1); - out.writeShort(c2); - } - - /** - * Writes four code units to the given output destination. - * - * @param out non-null; where to write to - * @param c0 code unit to write - * @param c1 code unit to write - * @param c2 code unit to write - * @param c3 code unit to write - */ - protected static void write(AnnotatedOutput out, short c0, short c1, - short c2, short c3) { - out.writeShort(c0); - out.writeShort(c1); - out.writeShort(c2); - out.writeShort(c3); - } - - /** - * Writes five code units to the given output destination. - * - * @param out non-null; where to write to - * @param c0 code unit to write - * @param c1 code unit to write - * @param c2 code unit to write - * @param c3 code unit to write - * @param c4 code unit to write - */ - protected static void write(AnnotatedOutput out, short c0, short c1, - short c2, short c3, short c4) { - out.writeShort(c0); - out.writeShort(c1); - out.writeShort(c2); - out.writeShort(c3); - out.writeShort(c4); - } - - /** - * Writes six code units to the given output destination. - * - * @param out non-null; where to write to - * @param c0 code unit to write - * @param c1 code unit to write - * @param c2 code unit to write - * @param c3 code unit to write - * @param c4 code unit to write - * @param c5 code unit to write - */ - protected static void write(AnnotatedOutput out, short c0, short c1, - short c2, short c3, short c4, short c5) { - out.writeShort(c0); - out.writeShort(c1); - out.writeShort(c2); - out.writeShort(c3); - out.writeShort(c4); - out.writeShort(c5); - } -} diff --git a/dx/src/com/android/dx/dex/code/LocalEnd.java b/dx/src/com/android/dx/dex/code/LocalEnd.java deleted file mode 100644 index 87934dbd4..000000000 --- a/dx/src/com/android/dx/dex/code/LocalEnd.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2009 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.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; - -/** - * Pseudo-instruction which is used to explicitly end the mapping of a - * register to a named local variable. That is, an instance of this - * class in an instruction stream indicates that starting with the - * subsequent instruction, the indicated variable is no longer valid. - */ -public final class LocalEnd extends ZeroSizeInsn { - /** - * non-null; register spec representing the local variable ended - * by this instance. <b>Note:</b> The only salient part of the spec - * is the register number; the rest of the info may be useful for - * debugging but shouldn't affect any actual processing - */ - private final RegisterSpec local; - - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param position non-null; source position - * @param local non-null; register spec representing the local - * variable introduced by this instance - */ - public LocalEnd(SourcePosition position, RegisterSpec local) { - super(position); - - if (local == null) { - throw new NullPointerException("local == null"); - } - - this.local = local; - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisterOffset(int delta) { - return new LocalEnd(getPosition(), local.withOffset(delta)); - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisters(RegisterSpecList registers) { - return new LocalEnd(getPosition(), local); - } - - /** - * Gets the register spec representing the local variable ended - * by this instance. - * - * @return non-null; the register spec - */ - public RegisterSpec getLocal() { - return local; - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - return local.toString(); - } - - /** {@inheritDoc} */ - @Override - protected String listingString0(boolean noteIndices) { - return "local-end " + LocalStart.localString(local); - } -} diff --git a/dx/src/com/android/dx/dex/code/LocalList.java b/dx/src/com/android/dx/dex/code/LocalList.java deleted file mode 100644 index d963fca08..000000000 --- a/dx/src/com/android/dx/dex/code/LocalList.java +++ /dev/null @@ -1,402 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecSet; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Type; -import com.android.dx.util.FixedSizeList; - -import java.util.ArrayList; - -/** - * List of local variables. Each local variable entry indicates a - * range of code which it is valid for, a register number, a name, - * and a type. - */ -public final class LocalList extends FixedSizeList { - /** non-null; empty instance */ - public static final LocalList EMPTY = new LocalList(0); - - /** - * Constructs an instance for the given method, based on the given - * block order and intermediate local information. - * - * @param insns non-null; instructions to convert - * @return non-null; the constructed list - */ - public static LocalList make(DalvInsnList insns) { - ArrayList<Entry> result = new ArrayList<Entry>(100); - int codeSize = insns.codeSize(); - int sz = insns.size(); - RegisterSpecSet state = null; - int stateMax = 0; - - for (int i = 0; i < sz; i++) { - DalvInsn insn = insns.get(i); - - if (insn instanceof LocalSnapshot) { - RegisterSpecSet newState = ((LocalSnapshot) insn).getLocals(); - boolean first = (state == null); - - if (first) { - stateMax = newState.getMaxSize(); - } - - for (int j = 0; j < stateMax; j++) { - RegisterSpec oldSpec = first ? null : state.get(j); - RegisterSpec newSpec = newState.get(j); - boolean oldEnds = false; - boolean newStarts = false; - - if (oldSpec == null) { - if (newSpec != null) { - /* - * This is a newly-introduced local, not - * replacing an existing local. - */ - newStarts = true; - } - } else if (newSpec == null) { - /* - * This is a local going out of scope, with no - * replacement. - */ - oldEnds = true; - } else if (!oldSpec.equals(newSpec)) { - /* - * This is a local going out of scope, immediately - * replaced by a different local. - */ - oldEnds = true; - newStarts = true; - } - - if (oldEnds) { - endScope(result, oldSpec, insn.getAddress()); - } - - if (newStarts) { - startScope(result, newSpec, insn.getAddress(), - codeSize); - } - } - - state = newState; - } else if (insn instanceof LocalStart) { - RegisterSpec newSpec = ((LocalStart) insn).getLocal(); - RegisterSpec oldSpec = state.get(newSpec); - - boolean oldEnds = false; - boolean newStarts = false; - - if (oldSpec == null) { - /* - * This is a newly-introduced local, not replacing an - * existing local. - */ - newStarts = true; - } else if (!oldSpec.equals(newSpec)) { - /* - * This is a local going out of scope, immediately - * replaced by a different local. - */ - oldEnds = true; - newStarts = true; - } - - if (newStarts) { - int address = insn.getAddress(); - - if (oldEnds) { - endScope(result, oldSpec, address); - } - - startScope(result, newSpec, address, codeSize); - - if (state.isImmutable()) { - state = state.mutableCopy(); - } - - state.put(newSpec); - } - } - } - - int resultSz = result.size(); - - if (resultSz == 0) { - return EMPTY; - } - - LocalList resultList = new LocalList(resultSz); - - for (int i = 0; i < resultSz; i++) { - resultList.set(i, result.get(i)); - } - - resultList.setImmutable(); - return resultList; - } - - /** - * Helper for {@link #make}, to indicate that the given variable has - * been introduced. - * - * @param result non-null; result in-progress - * @param spec non-null; register spec for the variable in question - * @param startAddress >= 0; address at which the scope starts - * (inclusive) - * @param endAddress > startAddress; initial scope end address - * (exclusive) - */ - private static void startScope(ArrayList<Entry> result, RegisterSpec spec, - int startAddress, int endAddress) { - result.add(new Entry(startAddress, endAddress, spec)); - } - - /** - * Helper for {@link #make}, to indicate that the given variable's - * scope has closed. - * - * @param result non-null; result in-progress - * @param spec non-null; register spec for the variable in question - * @param endAddress >= 0; address at which the scope ends (exclusive) - */ - private static void endScope(ArrayList<Entry> result, RegisterSpec spec, - int endAddress) { - int sz = result.size(); - - for (int i = sz - 1; i >= 0; i--) { - Entry e = result.get(i); - if (e.matches(spec)) { - if (e.getStart() == endAddress) { - /* - * It turns out that the indicated entry doesn't actually - * cover any code. - */ - result.remove(i); - } else { - result.set(i, e.withEnd(endAddress)); - } - return; - } - } - - throw new RuntimeException("unmatched variable: " + spec); - } - - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size >= 0; the size of the list - */ - public LocalList(int size) { - super(size); - } - - /** - * Gets the element at the given index. 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</code>. - * - * @param n >= 0, < size(); which index - * @return non-null; element at that index - */ - public Entry get(int n) { - return (Entry) get0(n); - } - - /** - * Sets the entry at the given index. - * - * @param n >= 0, < size(); which index - * @param start >= 0; start address - * @param end > start; end address (exclusive) - * @param spec non-null; register spec representing the variable - */ - public void set(int n, int start, int end, RegisterSpec spec) { - set0(n, new Entry(start, end, spec)); - } - - /** - * Sets the entry at the given index. - * - * @param n >= 0, < size(); which index - * @param entry non-null; the entry to set at <code>n</code> - */ - public void set(int n, Entry entry) { - set0(n, entry); - } - - /** - * Entry in a local list. - */ - public static class Entry { - /** >= 0; start address */ - private final int start; - - /** > start; end address (exclusive) */ - private final int end; - - /** non-null; register spec representing the variable */ - private final RegisterSpec spec; - - /** non-null; variable type */ - private final CstType type; - - /** - * Constructs an instance. - * - * @param start >= 0; start address - * @param end > start; end address (exclusive) - * @param spec non-null; register spec representing the variable - */ - public Entry(int start, int end, RegisterSpec spec) { - if (start < 0) { - throw new IllegalArgumentException("start < 0"); - } - - if (end <= start) { - throw new IllegalArgumentException("end <= start"); - } - - try { - if (spec.getLocalItem() == null) { - throw new NullPointerException( - "spec.getLocalItem() == null"); - } - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("spec == null"); - } - - this.start = start; - this.end = end; - this.spec = spec; - - if (spec.getType() == Type.KNOWN_NULL) { - /* - * KNOWN_NULL's descriptor is '<null>', which we do - * not want to emit. Everything else is as expected. - */ - this.type = CstType.OBJECT; - } else { - this.type = CstType.intern(spec.getType()); - } - } - - /** - * Gets the start address. - * - * @return >= 0; the start address - */ - public int getStart() { - return start; - } - - /** - * Gets the end address (exclusive). - * - * @return > start; the end address (exclusive) - */ - public int getEnd() { - return end; - } - - /** - * Gets the variable name. - * - * @return null-ok; the variable name - */ - public CstUtf8 getName() { - return spec.getLocalItem().getName(); - } - - /** - * Gets the variable signature. - * - * @return null-ok; the variable signature - */ - public CstUtf8 getSignature() { - return spec.getLocalItem().getSignature(); - } - - /** - * Gets the variable's type. - * - * @return non-null; the type - */ - public CstType getType() { - return type; - } - - /** - * Gets the number of the register holding the variable. - * - * @return >= 0; the number fo the register holding the variable - */ - public int getRegister() { - return spec.getReg(); - } - - /** - * Gets the RegisterSpec of the register holding the variable. - * - * @return non-null; RegisterSpec of the holding register. - */ - public RegisterSpec getRegisterSpec() { - return spec; - } - - /** - * Returns whether or not this instance matches the given spec. - * - * @param spec non-null; the spec in question - * @return <code>true</code> iff this instance matches - * <code>spec</code> - */ - public boolean matches(RegisterSpec spec) { - return spec.equals(this.spec); - } - - /** - * Returns whether or not this instance matches the spec in - * the given instance. - * - * @param other non-null; another entry - * @return <code>true</code> iff this instance's spec matches - * <code>other</code> - */ - public boolean matches(Entry other) { - return other.spec.equals(this.spec); - } - - /** - * Returns an instance just like this one, except with the end - * address altered to be the one given. - * - * @param newEnd > getStart(); the end address of the new instance - * @return non-null; an appropriately-constructed instance - */ - public Entry withEnd(int newEnd) { - return new Entry(start, newEnd, spec); - } - } -} diff --git a/dx/src/com/android/dx/dex/code/LocalSnapshot.java b/dx/src/com/android/dx/dex/code/LocalSnapshot.java deleted file mode 100644 index 19a9baa35..000000000 --- a/dx/src/com/android/dx/dex/code/LocalSnapshot.java +++ /dev/null @@ -1,96 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.RegisterSpecSet; -import com.android.dx.rop.code.SourcePosition; - -/** - * Pseudo-instruction which is used to hold a snapshot of the - * state of local variable name mappings that exists immediately after - * the instance in an instruction array. - */ -public final class LocalSnapshot extends ZeroSizeInsn { - /** non-null; local state associated with this instance */ - private final RegisterSpecSet locals; - - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param position non-null; source position - * @param locals non-null; associated local variable state - */ - public LocalSnapshot(SourcePosition position, RegisterSpecSet locals) { - super(position); - - if (locals == null) { - throw new NullPointerException("locals == null"); - } - - this.locals = locals; - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisterOffset(int delta) { - return new LocalSnapshot(getPosition(), locals.withOffset(delta)); - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisters(RegisterSpecList registers) { - return new LocalSnapshot(getPosition(), locals); - } - - /** - * Gets the local state associated with this instance. - * - * @return non-null; the state - */ - public RegisterSpecSet getLocals() { - return locals; - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - return locals.toString(); - } - - /** {@inheritDoc} */ - @Override - protected String listingString0(boolean noteIndices) { - int sz = locals.size(); - int max = locals.getMaxSize(); - StringBuffer sb = new StringBuffer(100 + sz * 40); - - sb.append("local-snapshot"); - - for (int i = 0; i < max; i++) { - RegisterSpec spec = locals.get(i); - if (spec != null) { - sb.append("\n "); - sb.append(LocalStart.localString(spec)); - } - } - - return sb.toString(); - } -} diff --git a/dx/src/com/android/dx/dex/code/LocalStart.java b/dx/src/com/android/dx/dex/code/LocalStart.java deleted file mode 100644 index 22e20f80d..000000000 --- a/dx/src/com/android/dx/dex/code/LocalStart.java +++ /dev/null @@ -1,98 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; - -/** - * Pseudo-instruction which is used to introduce a new local variable. That - * is, an instance of this class in an instruction stream indicates that - * starting with the subsequent instruction, the indicated variable - * is bound. - */ -public final class LocalStart extends ZeroSizeInsn { - /** - * non-null; register spec representing the local variable introduced - * by this instance - */ - private final RegisterSpec local; - - /** - * Returns the local variable listing string for a single register spec. - * - * @param spec non-null; the spec to convert - * @return non-null; the string form - */ - public static String localString(RegisterSpec spec) { - return spec.regString() + ' ' + spec.getLocalItem().toString() + ": " + - spec.getTypeBearer().toHuman(); - } - - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param position non-null; source position - * @param local non-null; register spec representing the local - * variable introduced by this instance - */ - public LocalStart(SourcePosition position, RegisterSpec local) { - super(position); - - if (local == null) { - throw new NullPointerException("local == null"); - } - - this.local = local; - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisterOffset(int delta) { - return new LocalStart(getPosition(), local.withOffset(delta)); - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisters(RegisterSpecList registers) { - return new LocalStart(getPosition(), local); - } - - /** - * Gets the register spec representing the local variable introduced - * by this instance. - * - * @return non-null; the register spec - */ - public RegisterSpec getLocal() { - return local; - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - return local.toString(); - } - - /** {@inheritDoc} */ - @Override - protected String listingString0(boolean noteIndices) { - return "local-start " + localString(local); - } -} diff --git a/dx/src/com/android/dx/dex/code/OddSpacer.java b/dx/src/com/android/dx/dex/code/OddSpacer.java deleted file mode 100644 index f99df3629..000000000 --- a/dx/src/com/android/dx/dex/code/OddSpacer.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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.util.AnnotatedOutput; - -/** - * Pseudo-instruction which either turns into a <code>nop</code> or - * nothingness, in order to make the subsequent instruction have an - * even address. This is used to align (subsequent) instructions that - * require it. - */ -public final class OddSpacer extends VariableSizeInsn { - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param position non-null; source position - */ - public OddSpacer(SourcePosition position) { - super(position, RegisterSpecList.EMPTY); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return (getAddress() & 1); - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out) { - if (codeSize() != 0) { - out.writeShort(InsnFormat.codeUnit(DalvOps.NOP, 0)); - } - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisters(RegisterSpecList registers) { - return new OddSpacer(getPosition()); - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - return null; - } - - /** {@inheritDoc} */ - @Override - protected String listingString0(boolean noteIndices) { - if (codeSize() == 0) { - return null; - } - - return "nop // spacer"; - } -} diff --git a/dx/src/com/android/dx/dex/code/OutputCollector.java b/dx/src/com/android/dx/dex/code/OutputCollector.java deleted file mode 100644 index 98d8a9cd0..000000000 --- a/dx/src/com/android/dx/dex/code/OutputCollector.java +++ /dev/null @@ -1,118 +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.android.dx.dex.code; - -import java.util.ArrayList; - -/** - * Destination for {@link DalvInsn} instances being output. This class - * receives and collects instructions in two pieces — a primary - * list and a suffix (generally consisting of adjunct data referred to - * by the primary list, such as switch case tables) — which it - * merges and emits back out in the form of a {@link DalvInsnList} - * instance. - */ -public final class OutputCollector { - /** - * non-null; the associated finisher (which holds the instruction - * list in-progress) - */ - private final OutputFinisher finisher; - - /** - * null-ok; suffix for the output, or <code>null</code> if the suffix - * has been appended to the main output (by {@link #appendSuffixToOutput}) - */ - private ArrayList<DalvInsn> suffix; - - /** - * Constructs an instance. - * - * @param initialCapacity >= 0; initial capacity of the output list - * @param suffixInitialCapacity >= 0; initial capacity of the output - * suffix - * @param regCount >= 0; register count for the method - */ - public OutputCollector(int initialCapacity, int suffixInitialCapacity, - int regCount) { - this.finisher = new OutputFinisher(initialCapacity, regCount); - this.suffix = new ArrayList<DalvInsn>(suffixInitialCapacity); - } - - /** - * Adds an instruction to the output. - * - * @param insn non-null; the instruction to add - */ - public void add(DalvInsn insn) { - finisher.add(insn); - } - - /** - * Reverses a branch which is buried a given number of instructions - * backward in the output. It is illegal to call this unless the - * indicated instruction really is a reversible branch. - * - * @param which how many instructions back to find the branch; - * <code>0</code> is the most recently added instruction, - * <code>1</code> is the instruction before that, etc. - * @param newTarget non-null; the new target for the reversed branch - */ - public void reverseBranch(int which, CodeAddress newTarget) { - finisher.reverseBranch(which, newTarget); - } - - /** - * Adds an instruction to the output suffix. - * - * @param insn non-null; the instruction to add - */ - public void addSuffix(DalvInsn insn) { - suffix.add(insn); - } - - /** - * Gets the results of all the calls on this instance, in the form of - * an {@link OutputFinisher}. - * - * @return non-null; the output finisher - * @throws UnsupportedOperationException if this method has - * already been called - */ - public OutputFinisher getFinisher() { - if (suffix == null) { - throw new UnsupportedOperationException("already processed"); - } - - appendSuffixToOutput(); - return finisher; - } - - /** - * Helper for {@link #getFinisher}, which appends the suffix to - * the primary output. - */ - private void appendSuffixToOutput() { - int size = suffix.size(); - - for (int i = 0; i < size; i++) { - finisher.add(suffix.get(i)); - } - - suffix = null; - } -} diff --git a/dx/src/com/android/dx/dex/code/OutputFinisher.java b/dx/src/com/android/dx/dex/code/OutputFinisher.java deleted file mode 100644 index 73eecf82e..000000000 --- a/dx/src/com/android/dx/dex/code/OutputFinisher.java +++ /dev/null @@ -1,737 +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.android.dx.dex.code; - -import com.android.dx.rop.code.LocalItem; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.RegisterSpecSet; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstMemberRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Type; - -import java.util.ArrayList; -import java.util.HashSet; - -/** - * Processor for instruction lists, which takes a "first cut" of - * instruction selection as a basis and produces a "final cut" in the - * form of a {@link DalvInsnList} instance. - */ -public final class OutputFinisher { - /** - * >= 0; register count for the method, not including any extra - * "reserved" registers needed to translate "difficult" instructions - */ - private final int unreservedRegCount; - - /** non-null; the list of instructions, per se */ - private ArrayList<DalvInsn> insns; - - /** whether any instruction has position info */ - private boolean hasAnyPositionInfo; - - /** whether any instruction has local variable info */ - private boolean hasAnyLocalInfo; - - /** - * >= 0; the count of reserved registers (low-numbered - * registers used when expanding instructions that can't be - * represented simply); becomes valid after a call to {@link - * #massageInstructions} - */ - private int reservedCount; - - /** - * Constructs an instance. It initially contains no instructions. - * - * @param regCount >= 0; register count for the method - * @param initialCapacity >= 0; initial capacity of the instructions - * list - */ - public OutputFinisher(int initialCapacity, int regCount) { - this.unreservedRegCount = regCount; - this.insns = new ArrayList<DalvInsn>(initialCapacity); - this.reservedCount = -1; - this.hasAnyPositionInfo = false; - this.hasAnyLocalInfo = false; - } - - /** - * Returns whether any of the instructions added to this instance - * come with position info. - * - * @return whether any of the instructions added to this instance - * come with position info - */ - public boolean hasAnyPositionInfo() { - return hasAnyPositionInfo; - } - - /** - * Returns whether this instance has any local variable information. - * - * @return whether this instance has any local variable information - */ - public boolean hasAnyLocalInfo() { - return hasAnyLocalInfo; - } - - /** - * Helper for {@link #add} which scrutinizes a single - * instruction for local variable information. - * - * @param insn non-null; instruction to scrutinize - * @return <code>true</code> iff the instruction refers to any - * named locals - */ - private static boolean hasLocalInfo(DalvInsn insn) { - if (insn instanceof LocalSnapshot) { - RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals(); - int size = specs.size(); - for (int i = 0; i < size; i++) { - if (hasLocalInfo(specs.get(i))) { - return true; - } - } - } else if (insn instanceof LocalStart) { - RegisterSpec spec = ((LocalStart) insn).getLocal(); - if (hasLocalInfo(spec)) { - return true; - } - } - - return false; - } - - /** - * Helper for {@link #hasAnyLocalInfo} which scrutinizes a single - * register spec. - * - * @param spec non-null; spec to scrutinize - * @return <code>true</code> iff the spec refers to any - * named locals - */ - private static boolean hasLocalInfo(RegisterSpec spec) { - return (spec != null) - && (spec.getLocalItem().getName() != null); - } - - /** - * Returns the set of all constants referred to by instructions added - * to this instance. - * - * @return non-null; the set of constants - */ - public HashSet<Constant> getAllConstants() { - HashSet<Constant> result = new HashSet<Constant>(20); - - for (DalvInsn insn : insns) { - addConstants(result, insn); - } - - return result; - } - - /** - * Helper for {@link #getAllConstants} which adds all the info for - * a single instruction. - * - * @param result non-null; result set to add to - * @param insn non-null; instruction to scrutinize - */ - private static void addConstants(HashSet<Constant> result, - DalvInsn insn) { - if (insn instanceof CstInsn) { - Constant cst = ((CstInsn) insn).getConstant(); - result.add(cst); - } else if (insn instanceof LocalSnapshot) { - RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals(); - int size = specs.size(); - for (int i = 0; i < size; i++) { - addConstants(result, specs.get(i)); - } - } else if (insn instanceof LocalStart) { - RegisterSpec spec = ((LocalStart) insn).getLocal(); - addConstants(result, spec); - } - } - - /** - * Helper for {@link #getAllConstants} which adds all the info for - * a single <code>RegisterSpec</code>. - * - * @param result non-null; result set to add to - * @param spec null-ok; register spec to add - */ - private static void addConstants(HashSet<Constant> result, - RegisterSpec spec) { - if (spec == null) { - return; - } - - LocalItem local = spec.getLocalItem(); - CstUtf8 name = local.getName(); - CstUtf8 signature = local.getSignature(); - Type type = spec.getType(); - - if (type != Type.KNOWN_NULL) { - result.add(CstType.intern(type)); - } - - if (name != null) { - result.add(name); - } - - if (signature != null) { - result.add(signature); - } - } - - /** - * Adds an instruction to the output. - * - * @param insn non-null; the instruction to add - */ - public void add(DalvInsn insn) { - insns.add(insn); - updateInfo(insn); - } - - /** - * Inserts an instruction in the output at the given offset. - * - * @param at >= 0; what index to insert at - * @param insn non-null; the instruction to insert - */ - public void insert(int at, DalvInsn insn) { - insns.add(at, insn); - updateInfo(insn); - } - - /** - * Helper for {@link #add} and {@link #insert}, - * which updates the position and local info flags. - * - * @param insn non-null; an instruction that was just introduced - */ - private void updateInfo(DalvInsn insn) { - if (! hasAnyPositionInfo) { - SourcePosition pos = insn.getPosition(); - if (pos.getLine() >= 0) { - hasAnyPositionInfo = true; - } - } - - if (! hasAnyLocalInfo) { - if (hasLocalInfo(insn)) { - hasAnyLocalInfo = true; - } - } - } - - /** - * Reverses a branch which is buried a given number of instructions - * backward in the output. It is illegal to call this unless the - * indicated instruction really is a reversible branch. - * - * @param which how many instructions back to find the branch; - * <code>0</code> is the most recently added instruction, - * <code>1</code> is the instruction before that, etc. - * @param newTarget non-null; the new target for the reversed branch - */ - public void reverseBranch(int which, CodeAddress newTarget) { - int size = insns.size(); - int index = size - which - 1; - TargetInsn targetInsn; - - try { - targetInsn = (TargetInsn) insns.get(index); - } catch (IndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("too few instructions"); - } catch (ClassCastException ex) { - // Translate the exception. - throw new IllegalArgumentException("non-reversible instruction"); - } - - /* - * No need to call this.set(), since the format and other info - * are the same. - */ - insns.set(index, targetInsn.withNewTargetAndReversed(newTarget)); - } - - /** - * Assigns indices in all instructions that need them, using the - * given callback to perform lookups. This should be called before - * calling {@link #finishProcessingAndGetList}. - * - * @param callback non-null; callback object - */ - public void assignIndices(DalvCode.AssignIndicesCallback callback) { - for (DalvInsn insn : insns) { - if (insn instanceof CstInsn) { - assignIndices((CstInsn) insn, callback); - } - } - } - - /** - * Helper for {@link #assignIndices} which does assignment for one - * instruction. - * - * @param insn non-null; the instruction - * @param callback non-null; the callback - */ - private static void assignIndices(CstInsn insn, - DalvCode.AssignIndicesCallback callback) { - Constant cst = insn.getConstant(); - int index = callback.getIndex(cst); - - if (index >= 0) { - insn.setIndex(index); - } - - if (cst instanceof CstMemberRef) { - CstMemberRef member = (CstMemberRef) cst; - CstType definer = member.getDefiningClass(); - index = callback.getIndex(definer); - if (index >= 0) { - insn.setClassIndex(index); - } - } - } - - /** - * Does final processing on this instance and gets the output as - * a {@link DalvInsnList}. Final processing consists of: - * - * <ul> - * <li>optionally renumbering registers (to make room as needed for - * expanded instructions)</li> - * <li>picking a final opcode for each instruction</li> - * <li>rewriting instructions, because of register number, - * constant pool index, or branch target size issues</li> - * <li>assigning final addresses</li> - * </ul> - * - * <p><b>Note:</b> This method may only be called once per instance - * of this class.</p> - * - * @return non-null; the output list - * @throws UnsupportedOperationException if this method has - * already been called - */ - public DalvInsnList finishProcessingAndGetList() { - if (reservedCount >= 0) { - throw new UnsupportedOperationException("already processed"); - } - - InsnFormat[] formats = makeFormatsArray(); - reserveRegisters(formats); - massageInstructions(formats); - assignAddressesAndFixBranches(); - - return DalvInsnList.makeImmutable(insns, - reservedCount + unreservedRegCount); - } - - /** - * Helper for {@link #finishProcessingAndGetList}, which extracts - * the format out of each instruction into a separate array, to be - * further manipulated as things progress. - * - * @return non-null; the array of formats - */ - private InsnFormat[] makeFormatsArray() { - int size = insns.size(); - InsnFormat[] result = new InsnFormat[size]; - - for (int i = 0; i < size; i++) { - result[i] = insns.get(i).getOpcode().getFormat(); - } - - return result; - } - - /** - * Helper for {@link #finishProcessingAndGetList}, which figures - * out how many reserved registers are required and then reserving - * them. It also updates the given <code>formats</code> array so - * as to avoid extra work when constructing the massaged - * instruction list. - * - * @param formats non-null; array of per-instruction format selections - */ - private void reserveRegisters(InsnFormat[] formats) { - int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount; - - /* - * Call calculateReservedCount() and then perform register - * reservation, repeatedly until no new reservations happen. - */ - for (;;) { - int newReservedCount = calculateReservedCount(formats); - if (oldReservedCount >= newReservedCount) { - break; - } - - int reservedDifference = newReservedCount - oldReservedCount; - int size = insns.size(); - - for (int i = 0; i < size; i++) { - /* - * CodeAddress instance identity is used to link - * TargetInsns to their targets, so it is - * inappropriate to make replacements, and they don't - * have registers in any case. Hence, the instanceof - * test below. - */ - DalvInsn insn = insns.get(i); - if (!(insn instanceof CodeAddress)) { - /* - * No need to call this.set() since the format and - * other info are the same. - */ - insns.set(i, insn.withRegisterOffset(reservedDifference)); - } - } - - oldReservedCount = newReservedCount; - } - - reservedCount = oldReservedCount; - } - - /** - * Helper for {@link #reserveRegisters}, which does one - * pass over the instructions, calculating the number of - * registers that need to be reserved. It also updates the - * <code>formats</code> list to help avoid extra work in future - * register reservation passes. - * - * @param formats non-null; array of per-instruction format selections - * @return >= 0; the count of reserved registers - */ - private int calculateReservedCount(InsnFormat[] formats) { - int size = insns.size(); - - /* - * Potential new value of reservedCount, which gets updated in the - * following loop. It starts out with the existing reservedCount - * and gets increased if it turns out that additional registers - * need to be reserved. - */ - int newReservedCount = reservedCount; - - for (int i = 0; i < size; i++) { - DalvInsn insn = insns.get(i); - InsnFormat originalFormat = formats[i]; - InsnFormat newFormat = findFormatForInsn(insn, originalFormat); - - if (originalFormat == newFormat) { - continue; - } - - if (newFormat == null) { - /* - * The instruction will need to be expanded, so reserve - * registers for it. - */ - int reserve = insn.getMinimumRegisterRequirement(); - if (reserve > newReservedCount) { - newReservedCount = reserve; - } - } - - formats[i] = newFormat; - } - - return newReservedCount; - } - - /** - * Attempts to fit the given instruction into a format, returning - * either a format that the instruction fits into or <code>null</code> - * to indicate that the instruction will need to be expanded. This - * fitting process starts with the given format as a first "best - * guess" and then pessimizes from there if necessary. - * - * @param insn non-null; the instruction in question - * @param format null-ok; the current guess as to the best instruction - * format to use; <code>null</code> means that no simple format fits - * @return null-ok; a possibly-different format, which is either a - * good fit or <code>null</code> to indicate that no simple format - * fits - */ - private InsnFormat findFormatForInsn(DalvInsn insn, InsnFormat format) { - if (format == null) { - // The instruction is already known not to fit any simple format. - return format; - } - - if (format.isCompatible(insn)) { - // The instruction already fits in the current best-known format. - return format; - } - - Dop dop = insn.getOpcode(); - int family = dop.getFamily(); - - for (;;) { - format = format.nextUp(); - if ((format == null) || - (format.isCompatible(insn) && - (Dops.getOrNull(family, format) != null))) { - break; - } - } - - return format; - } - - /** - * Helper for {@link #finishProcessingAndGetList}, which goes - * through each instruction in the output, making sure its opcode - * can accomodate its arguments. In cases where the opcode is - * unable to do so, this replaces the instruction with a larger - * instruction with identical semantics that <i>will</i> work. - * - * <p>This method may also reserve a number of low-numbered - * registers, renumbering the instructions' original registers, in - * order to have register space available in which to move - * very-high registers when expanding instructions into - * multi-instruction sequences. This expansion is done when no - * simple instruction format can be found for a given instruction that - * is able to accomodate that instruction's registers.</p> - * - * <p>This method ignores issues of branch target size, since - * final addresses aren't known at the point that this method is - * called.</p> - * - * @param formats non-null; array of per-instruction format selections - */ - private void massageInstructions(InsnFormat[] formats) { - if (reservedCount == 0) { - /* - * The easy common case: No registers were reserved, so we - * merely need to replace any instructions whose format changed - * during the reservation pass, but all instructions will stay - * at their original indices, and the instruction list doesn't - * grow. - */ - int size = insns.size(); - - for (int i = 0; i < size; i++) { - DalvInsn insn = insns.get(i); - Dop dop = insn.getOpcode(); - InsnFormat format = formats[i]; - - if (format != dop.getFormat()) { - dop = Dops.getOrNull(dop.getFamily(), format); - insns.set(i, insn.withOpcode(dop)); - } - } - } else { - /* - * The difficult uncommon case: Some instructions have to be - * expanded to deal with high registers. - */ - insns = performExpansion(formats); - } - } - - /** - * Helper for {@link #massageInstructions}, which constructs a - * replacement list, where each {link DalvInsn} instance that - * couldn't be represented simply (due to register representation - * problems) is expanded into a series of instances that together - * perform the proper function. - * - * @param formats non-null; array of per-instruction format selections - * @return non-null; the replacement list - */ - private ArrayList<DalvInsn> performExpansion(InsnFormat[] formats) { - int size = insns.size(); - ArrayList<DalvInsn> result = new ArrayList<DalvInsn>(size * 2); - - for (int i = 0; i < size; i++) { - DalvInsn insn = insns.get(i); - Dop dop = insn.getOpcode(); - InsnFormat originalFormat = dop.getFormat(); - InsnFormat currentFormat = formats[i]; - DalvInsn prefix; - DalvInsn suffix; - - if (currentFormat != null) { - // No expansion is necessary. - prefix = null; - suffix = null; - } else { - // Expansion is required. - prefix = insn.hrPrefix(); - suffix = insn.hrSuffix(); - - /* - * Get the initial guess as to the hr version, but then - * let findFormatForInsn() pick a better format, if any. - */ - insn = insn.hrVersion(); - originalFormat = insn.getOpcode().getFormat(); - currentFormat = findFormatForInsn(insn, originalFormat); - } - - if (prefix != null) { - result.add(prefix); - } - - if (currentFormat != originalFormat) { - dop = Dops.getOrNull(dop.getFamily(), currentFormat); - insn = insn.withOpcode(dop); - } - result.add(insn); - - if (suffix != null) { - result.add(suffix); - } - } - - return result; - } - - /** - * Helper for {@link #finishProcessingAndGetList}, which assigns - * addresses to each instruction, possibly rewriting branches to - * fix ones that wouldn't otherwise be able to reach their - * targets. - */ - private void assignAddressesAndFixBranches() { - for (;;) { - assignAddresses(); - if (!fixBranches()) { - break; - } - } - } - - /** - * Helper for {@link #assignAddressesAndFixBranches}, which - * assigns an address to each instruction, in order. - */ - private void assignAddresses() { - int address = 0; - int size = insns.size(); - - for (int i = 0; i < size; i++) { - DalvInsn insn = insns.get(i); - insn.setAddress(address); - address += insn.codeSize(); - } - } - - /** - * Helper for {@link #assignAddressesAndFixBranches}, which checks - * the branch target size requirement of each branch instruction - * to make sure it fits. For instructions that don't fit, this - * rewrites them to use a <code>goto</code> of some sort. In the - * case of a conditional branch that doesn't fit, the sense of the - * test is reversed in order to branch around a <code>goto</code> - * to the original target. - * - * @return whether any branches had to be fixed - */ - private boolean fixBranches() { - int size = insns.size(); - boolean anyFixed = false; - - for (int i = 0; i < size; i++) { - DalvInsn insn = insns.get(i); - if (!(insn instanceof TargetInsn)) { - // This loop only needs to inspect TargetInsns. - continue; - } - - Dop dop = insn.getOpcode(); - InsnFormat format = dop.getFormat(); - TargetInsn target = (TargetInsn) insn; - - if (format.branchFits(target)) { - continue; - } - - if (dop.getFamily() == DalvOps.GOTO) { - // It is a goto; widen it if possible. - InsnFormat newFormat = findFormatForInsn(insn, format); - if (newFormat == null) { - /* - * The branch is already maximally large. This should - * only be possible if a method somehow manages to have - * more than 2^31 code units. - */ - throw new UnsupportedOperationException("method too long"); - } - dop = Dops.getOrNull(dop.getFamily(), newFormat); - insn = insn.withOpcode(dop); - insns.set(i, insn); - } else { - /* - * It is a conditional: Reverse its sense, and arrange for - * it to branch around an absolute goto to the original - * branch target. - * - * Note: An invariant of the list being processed is - * that every TargetInsn is followed by a CodeAddress. - * Hence, it is always safe to get the next element - * after a TargetInsn and cast it to CodeAddress, as - * is happening a few lines down. - * - * Also note: Size gets incremented by one here, as we - * have -- in the net -- added one additional element - * to the list, so we increment i to match. The added - * and changed elements will be inspected by a repeat - * call to this method after this invocation returns. - */ - CodeAddress newTarget; - try { - newTarget = (CodeAddress) insns.get(i + 1); - } catch (IndexOutOfBoundsException ex) { - // The TargetInsn / CodeAddress invariant was violated. - throw new IllegalStateException( - "unpaired TargetInsn (dangling)"); - } catch (ClassCastException ex) { - // The TargetInsn / CodeAddress invariant was violated. - throw new IllegalStateException("unpaired TargetInsn"); - } - TargetInsn gotoInsn = - new TargetInsn(Dops.GOTO, target.getPosition(), - RegisterSpecList.EMPTY, target.getTarget()); - insns.set(i, gotoInsn); - insns.add(i, target.withNewTargetAndReversed(newTarget)); - size++; - i++; - } - - anyFixed = true; - } - - return anyFixed; - } -} diff --git a/dx/src/com/android/dx/dex/code/PositionList.java b/dx/src/com/android/dx/dex/code/PositionList.java deleted file mode 100644 index d8f76ebd4..000000000 --- a/dx/src/com/android/dx/dex/code/PositionList.java +++ /dev/null @@ -1,192 +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.android.dx.dex.code; - -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.util.FixedSizeList; - -/** - * List of source position entries. This class includes a utility - * method to extract an instance out of a {@link DalvInsnList}. - */ -public final class PositionList extends FixedSizeList { - /** non-null; empty instance */ - public static final PositionList EMPTY = new PositionList(0); - - /** - * constant for {@link #make} to indicate that no actual position - * information should be returned - */ - public static final int NONE = 1; - - /** - * constant for {@link #make} to indicate that only line number - * transitions should be returned - */ - public static final int LINES = 2; - - /** - * constant for {@link #make} to indicate that only "important" position - * information should be returned. This includes block starts and - * instructions that might throw. - */ - public static final int IMPORTANT = 3; - - /** - * Extracts and returns the source position information out of an - * instruction list. - * - * @param insns non-null; instructions to convert - * @param howMuch how much information should be included; one of the - * static constants defined by this class - * @return non-null; the positions list - */ - public static PositionList make(DalvInsnList insns, int howMuch) { - switch (howMuch) { - case NONE: { - return EMPTY; - } - case LINES: - case IMPORTANT: { - // Valid. - break; - } - default: { - throw new IllegalArgumentException("bogus howMuch"); - } - } - - SourcePosition noInfo = SourcePosition.NO_INFO; - SourcePosition cur = noInfo; - int sz = insns.size(); - PositionList.Entry[] arr = new PositionList.Entry[sz]; - boolean lastWasTarget = false; - int at = 0; - - for (int i = 0; i < sz; i++) { - DalvInsn insn = insns.get(i); - - if (insn instanceof CodeAddress) { - lastWasTarget = true;; - continue; - } - - SourcePosition pos = insn.getPosition(); - - if (pos.equals(noInfo) || pos.sameLine(cur)) { - continue; - } - - if ((howMuch == IMPORTANT) && !lastWasTarget) { - continue; - } - - cur = pos; - arr[at] = new PositionList.Entry(insn.getAddress(), pos); - at++; - - lastWasTarget = false; - } - - PositionList result = new PositionList(at); - for (int i = 0; i < at; i++) { - result.set(i, arr[i]); - } - - result.setImmutable(); - return result; - } - - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size >= 0; the size of the list - */ - public PositionList(int size) { - super(size); - } - - /** - * Gets the element at the given index. 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</code>. - * - * @param n >= 0, < size(); which index - * @return non-null; element at that index - */ - public Entry get(int n) { - return (Entry) get0(n); - } - - /** - * Sets the entry at the given index. - * - * @param n >= 0, < size(); which index - * @param entry non-null; the entry to set at <code>n</code> - */ - public void set(int n, Entry entry) { - set0(n, entry); - } - - /** - * Entry in a position list. - */ - public static class Entry { - /** >= 0; address of this entry */ - private final int address; - - /** non-null; corresponding source position information */ - private final SourcePosition position; - - /** - * Constructs an instance. - * - * @param address >= 0; address of this entry - * @param position non-null; corresponding source position information - */ - public Entry (int address, SourcePosition position) { - if (address < 0) { - throw new IllegalArgumentException("address < 0"); - } - - if (position == null) { - throw new NullPointerException("position == null"); - } - - this.address = address; - this.position = position; - } - - /** - * Gets the address. - * - * @return >= 0; the address - */ - public int getAddress() { - return address; - } - - /** - * Gets the source position information. - * - * @return non-null; the position information - */ - public SourcePosition getPosition() { - return position; - } - } -} diff --git a/dx/src/com/android/dx/dex/code/RopToDop.java b/dx/src/com/android/dx/dex/code/RopToDop.java deleted file mode 100644 index 8ad0e64a8..000000000 --- a/dx/src/com/android/dx/dex/code/RopToDop.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.android.dx.dex.code; - -import com.android.dx.rop.code.Insn; -import com.android.dx.rop.code.RegOps; -import com.android.dx.rop.code.Rop; -import com.android.dx.rop.code.Rops; -import com.android.dx.rop.code.ThrowingCstInsn; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; - -import java.util.HashMap; - -/** - * Translator from rop-level {@link Insn} instances to corresponding - * {@link Dop} instances. - */ -public final class RopToDop { - /** non-null; map from all the common rops to dalvik opcodes */ - private static final HashMap<Rop, Dop> MAP; - - /** - * This class is uninstantiable. - */ - private RopToDop() { - // This space intentionally left blank. - } - - static { - /* - * Note: The choices made here are to pick the optimistically - * smallest Dalvik opcode, and leave it to later processing to - * pessimize. - */ - MAP = new HashMap<Rop, Dop>(400); - MAP.put(Rops.NOP, Dops.NOP); - MAP.put(Rops.MOVE_INT, Dops.MOVE); - MAP.put(Rops.MOVE_LONG, Dops.MOVE_WIDE); - MAP.put(Rops.MOVE_FLOAT, Dops.MOVE); - MAP.put(Rops.MOVE_DOUBLE, Dops.MOVE_WIDE); - MAP.put(Rops.MOVE_OBJECT, Dops.MOVE_OBJECT); - MAP.put(Rops.MOVE_PARAM_INT, Dops.MOVE); - MAP.put(Rops.MOVE_PARAM_LONG, Dops.MOVE_WIDE); - MAP.put(Rops.MOVE_PARAM_FLOAT, Dops.MOVE); - MAP.put(Rops.MOVE_PARAM_DOUBLE, Dops.MOVE_WIDE); - MAP.put(Rops.MOVE_PARAM_OBJECT, Dops.MOVE_OBJECT); - - /* - * Note: No entry for MOVE_EXCEPTION, since it varies by - * exception type. (That is, there is no unique instance to - * add to the map.) - */ - - MAP.put(Rops.CONST_INT, Dops.CONST_4); - MAP.put(Rops.CONST_LONG, Dops.CONST_WIDE_16); - MAP.put(Rops.CONST_FLOAT, Dops.CONST_4); - MAP.put(Rops.CONST_DOUBLE, Dops.CONST_WIDE_16); - - /* - * Note: No entry for CONST_OBJECT, since it needs to turn - * into either CONST_STRING or CONST_CLASS. - */ - - /* - * TODO: I think the only case of this is for null, and - * const/4 should cover that. - */ - MAP.put(Rops.CONST_OBJECT_NOTHROW, Dops.CONST_4); - - MAP.put(Rops.GOTO, Dops.GOTO); - MAP.put(Rops.IF_EQZ_INT, Dops.IF_EQZ); - MAP.put(Rops.IF_NEZ_INT, Dops.IF_NEZ); - MAP.put(Rops.IF_LTZ_INT, Dops.IF_LTZ); - MAP.put(Rops.IF_GEZ_INT, Dops.IF_GEZ); - MAP.put(Rops.IF_LEZ_INT, Dops.IF_LEZ); - MAP.put(Rops.IF_GTZ_INT, Dops.IF_GTZ); - MAP.put(Rops.IF_EQZ_OBJECT, Dops.IF_EQZ); - MAP.put(Rops.IF_NEZ_OBJECT, Dops.IF_NEZ); - MAP.put(Rops.IF_EQ_INT, Dops.IF_EQ); - MAP.put(Rops.IF_NE_INT, Dops.IF_NE); - MAP.put(Rops.IF_LT_INT, Dops.IF_LT); - MAP.put(Rops.IF_GE_INT, Dops.IF_GE); - MAP.put(Rops.IF_LE_INT, Dops.IF_LE); - MAP.put(Rops.IF_GT_INT, Dops.IF_GT); - MAP.put(Rops.IF_EQ_OBJECT, Dops.IF_EQ); - MAP.put(Rops.IF_NE_OBJECT, Dops.IF_NE); - MAP.put(Rops.SWITCH, Dops.SPARSE_SWITCH); - MAP.put(Rops.ADD_INT, Dops.ADD_INT_2ADDR); - MAP.put(Rops.ADD_LONG, Dops.ADD_LONG_2ADDR); - MAP.put(Rops.ADD_FLOAT, Dops.ADD_FLOAT_2ADDR); - MAP.put(Rops.ADD_DOUBLE, Dops.ADD_DOUBLE_2ADDR); - MAP.put(Rops.SUB_INT, Dops.SUB_INT_2ADDR); - MAP.put(Rops.SUB_LONG, Dops.SUB_LONG_2ADDR); - MAP.put(Rops.SUB_FLOAT, Dops.SUB_FLOAT_2ADDR); - MAP.put(Rops.SUB_DOUBLE, Dops.SUB_DOUBLE_2ADDR); - MAP.put(Rops.MUL_INT, Dops.MUL_INT_2ADDR); - MAP.put(Rops.MUL_LONG, Dops.MUL_LONG_2ADDR); - MAP.put(Rops.MUL_FLOAT, Dops.MUL_FLOAT_2ADDR); - MAP.put(Rops.MUL_DOUBLE, Dops.MUL_DOUBLE_2ADDR); - MAP.put(Rops.DIV_INT, Dops.DIV_INT_2ADDR); - MAP.put(Rops.DIV_LONG, Dops.DIV_LONG_2ADDR); - MAP.put(Rops.DIV_FLOAT, Dops.DIV_FLOAT_2ADDR); - MAP.put(Rops.DIV_DOUBLE, Dops.DIV_DOUBLE_2ADDR); - MAP.put(Rops.REM_INT, Dops.REM_INT_2ADDR); - MAP.put(Rops.REM_LONG, Dops.REM_LONG_2ADDR); - MAP.put(Rops.REM_FLOAT, Dops.REM_FLOAT_2ADDR); - MAP.put(Rops.REM_DOUBLE, Dops.REM_DOUBLE_2ADDR); - MAP.put(Rops.NEG_INT, Dops.NEG_INT); - MAP.put(Rops.NEG_LONG, Dops.NEG_LONG); - MAP.put(Rops.NEG_FLOAT, Dops.NEG_FLOAT); - MAP.put(Rops.NEG_DOUBLE, Dops.NEG_DOUBLE); - MAP.put(Rops.AND_INT, Dops.AND_INT_2ADDR); - MAP.put(Rops.AND_LONG, Dops.AND_LONG_2ADDR); - MAP.put(Rops.OR_INT, Dops.OR_INT_2ADDR); - MAP.put(Rops.OR_LONG, Dops.OR_LONG_2ADDR); - MAP.put(Rops.XOR_INT, Dops.XOR_INT_2ADDR); - MAP.put(Rops.XOR_LONG, Dops.XOR_LONG_2ADDR); - MAP.put(Rops.SHL_INT, Dops.SHL_INT_2ADDR); - MAP.put(Rops.SHL_LONG, Dops.SHL_LONG_2ADDR); - MAP.put(Rops.SHR_INT, Dops.SHR_INT_2ADDR); - MAP.put(Rops.SHR_LONG, Dops.SHR_LONG_2ADDR); - MAP.put(Rops.USHR_INT, Dops.USHR_INT_2ADDR); - MAP.put(Rops.USHR_LONG, Dops.USHR_LONG_2ADDR); - MAP.put(Rops.NOT_INT, Dops.NOT_INT); - MAP.put(Rops.NOT_LONG, Dops.NOT_LONG); - - MAP.put(Rops.ADD_CONST_INT, Dops.ADD_INT_LIT8); - // Note: No dalvik ops for other types of add_const. - - /* - * Note: No dalvik ops for any type of sub_const; there's a - * *reverse* sub (constant - reg) for ints, though, but that - * should end up getting handled at optimization time. - */ - - MAP.put(Rops.MUL_CONST_INT, Dops.MUL_INT_LIT8); - // Note: No dalvik ops for other types of mul_const. - - MAP.put(Rops.DIV_CONST_INT, Dops.DIV_INT_LIT8); - // Note: No dalvik ops for other types of div_const. - - MAP.put(Rops.REM_CONST_INT, Dops.REM_INT_LIT8); - // Note: No dalvik ops for other types of rem_const. - - MAP.put(Rops.AND_CONST_INT, Dops.AND_INT_LIT8); - // Note: No dalvik op for and_const_long. - - MAP.put(Rops.OR_CONST_INT, Dops.OR_INT_LIT8); - // Note: No dalvik op for or_const_long. - - MAP.put(Rops.XOR_CONST_INT, Dops.XOR_INT_LIT8); - // Note: No dalvik op for xor_const_long. - - MAP.put(Rops.SHL_CONST_INT, Dops.SHL_INT_LIT8); - // Note: No dalvik op for shl_const_long. - - MAP.put(Rops.SHR_CONST_INT, Dops.SHR_INT_LIT8); - // Note: No dalvik op for shr_const_long. - - MAP.put(Rops.USHR_CONST_INT, Dops.USHR_INT_LIT8); - // Note: No dalvik op for shr_const_long. - - MAP.put(Rops.CMPL_LONG, Dops.CMP_LONG); - MAP.put(Rops.CMPL_FLOAT, Dops.CMPL_FLOAT); - MAP.put(Rops.CMPL_DOUBLE, Dops.CMPL_DOUBLE); - MAP.put(Rops.CMPG_FLOAT, Dops.CMPG_FLOAT); - MAP.put(Rops.CMPG_DOUBLE, Dops.CMPG_DOUBLE); - MAP.put(Rops.CONV_L2I, Dops.LONG_TO_INT); - MAP.put(Rops.CONV_F2I, Dops.FLOAT_TO_INT); - MAP.put(Rops.CONV_D2I, Dops.DOUBLE_TO_INT); - MAP.put(Rops.CONV_I2L, Dops.INT_TO_LONG); - MAP.put(Rops.CONV_F2L, Dops.FLOAT_TO_LONG); - MAP.put(Rops.CONV_D2L, Dops.DOUBLE_TO_LONG); - MAP.put(Rops.CONV_I2F, Dops.INT_TO_FLOAT); - MAP.put(Rops.CONV_L2F, Dops.LONG_TO_FLOAT); - MAP.put(Rops.CONV_D2F, Dops.DOUBLE_TO_FLOAT); - MAP.put(Rops.CONV_I2D, Dops.INT_TO_DOUBLE); - MAP.put(Rops.CONV_L2D, Dops.LONG_TO_DOUBLE); - MAP.put(Rops.CONV_F2D, Dops.FLOAT_TO_DOUBLE); - MAP.put(Rops.TO_BYTE, Dops.INT_TO_BYTE); - MAP.put(Rops.TO_CHAR, Dops.INT_TO_CHAR); - MAP.put(Rops.TO_SHORT, Dops.INT_TO_SHORT); - MAP.put(Rops.RETURN_VOID, Dops.RETURN_VOID); - MAP.put(Rops.RETURN_INT, Dops.RETURN); - MAP.put(Rops.RETURN_LONG, Dops.RETURN_WIDE); - MAP.put(Rops.RETURN_FLOAT, Dops.RETURN); - MAP.put(Rops.RETURN_DOUBLE, Dops.RETURN_WIDE); - MAP.put(Rops.RETURN_OBJECT, Dops.RETURN_OBJECT); - MAP.put(Rops.ARRAY_LENGTH, Dops.ARRAY_LENGTH); - MAP.put(Rops.THROW, Dops.THROW); - MAP.put(Rops.MONITOR_ENTER, Dops.MONITOR_ENTER); - MAP.put(Rops.MONITOR_EXIT, Dops.MONITOR_EXIT); - MAP.put(Rops.AGET_INT, Dops.AGET); - MAP.put(Rops.AGET_LONG, Dops.AGET_WIDE); - MAP.put(Rops.AGET_FLOAT, Dops.AGET); - MAP.put(Rops.AGET_DOUBLE, Dops.AGET_WIDE); - MAP.put(Rops.AGET_OBJECT, Dops.AGET_OBJECT); - MAP.put(Rops.AGET_BOOLEAN, Dops.AGET_BOOLEAN); - MAP.put(Rops.AGET_BYTE, Dops.AGET_BYTE); - MAP.put(Rops.AGET_CHAR, Dops.AGET_CHAR); - MAP.put(Rops.AGET_SHORT, Dops.AGET_SHORT); - MAP.put(Rops.APUT_INT, Dops.APUT); - MAP.put(Rops.APUT_LONG, Dops.APUT_WIDE); - MAP.put(Rops.APUT_FLOAT, Dops.APUT); - MAP.put(Rops.APUT_DOUBLE, Dops.APUT_WIDE); - MAP.put(Rops.APUT_OBJECT, Dops.APUT_OBJECT); - MAP.put(Rops.APUT_BOOLEAN, Dops.APUT_BOOLEAN); - MAP.put(Rops.APUT_BYTE, Dops.APUT_BYTE); - MAP.put(Rops.APUT_CHAR, Dops.APUT_CHAR); - MAP.put(Rops.APUT_SHORT, Dops.APUT_SHORT); - MAP.put(Rops.NEW_INSTANCE, Dops.NEW_INSTANCE); - MAP.put(Rops.CHECK_CAST, Dops.CHECK_CAST); - MAP.put(Rops.INSTANCE_OF, Dops.INSTANCE_OF); - - MAP.put(Rops.GET_FIELD_LONG, Dops.IGET_WIDE); - MAP.put(Rops.GET_FIELD_FLOAT, Dops.IGET); - MAP.put(Rops.GET_FIELD_DOUBLE, Dops.IGET_WIDE); - MAP.put(Rops.GET_FIELD_OBJECT, Dops.IGET_OBJECT); - /* - * Note: No map entries for get_field_* for non-long integral types, - * since they need to be handled specially (see dopFor() below). - */ - - MAP.put(Rops.GET_STATIC_LONG, Dops.SGET_WIDE); - MAP.put(Rops.GET_STATIC_FLOAT, Dops.SGET); - MAP.put(Rops.GET_STATIC_DOUBLE, Dops.SGET_WIDE); - MAP.put(Rops.GET_STATIC_OBJECT, Dops.SGET_OBJECT); - /* - * Note: No map entries for get_static* for non-long integral types, - * since they need to be handled specially (see dopFor() below). - */ - - MAP.put(Rops.PUT_FIELD_LONG, Dops.IPUT_WIDE); - MAP.put(Rops.PUT_FIELD_FLOAT, Dops.IPUT); - MAP.put(Rops.PUT_FIELD_DOUBLE, Dops.IPUT_WIDE); - MAP.put(Rops.PUT_FIELD_OBJECT, Dops.IPUT_OBJECT); - /* - * Note: No map entries for put_field_* for non-long integral types, - * since they need to be handled specially (see dopFor() below). - */ - - MAP.put(Rops.PUT_STATIC_LONG, Dops.SPUT_WIDE); - MAP.put(Rops.PUT_STATIC_FLOAT, Dops.SPUT); - MAP.put(Rops.PUT_STATIC_DOUBLE, Dops.SPUT_WIDE); - MAP.put(Rops.PUT_STATIC_OBJECT, Dops.SPUT_OBJECT); - /* - * Note: No map entries for put_static* for non-long integral types, - * since they need to be handled specially (see dopFor() below). - */ - - /* - * Note: No map entries for invoke*, new_array, and - * filled_new_array, since they need to be handled specially - * (see dopFor() below). - */ - } - - /** - * Returns the dalvik opcode appropriate for the given register-based - * instruction. - * - * @param insn non-null; the original instruction - * @return the corresponding dalvik opcode; one of the constants in - * {@link Dops} - */ - public static Dop dopFor(Insn insn) { - Rop rop = insn.getOpcode(); - - /* - * First, just try looking up the rop in the MAP of easy - * cases. - */ - Dop result = MAP.get(rop); - if (result != null) { - return result; - } - - /* - * There was no easy case for the rop, so look up the opcode, and - * do something special for each: - * - * The move_exception, new_array, filled_new_array, and - * invoke* opcodes won't be found in MAP, since they'll each - * have different source and/or result register types / lists. - * - * The get* and put* opcodes for (non-long) integral types - * aren't in the map, since the type signatures aren't - * sufficient to distinguish between the types (the salient - * source or result will always be just "int"). - * - * And const instruction need to distinguish between strings and - * classes. - */ - - switch (rop.getOpcode()) { - case RegOps.MOVE_EXCEPTION: return Dops.MOVE_EXCEPTION; - case RegOps.INVOKE_STATIC: return Dops.INVOKE_STATIC; - case RegOps.INVOKE_VIRTUAL: return Dops.INVOKE_VIRTUAL; - case RegOps.INVOKE_SUPER: return Dops.INVOKE_SUPER; - case RegOps.INVOKE_DIRECT: return Dops.INVOKE_DIRECT; - case RegOps.INVOKE_INTERFACE: return Dops.INVOKE_INTERFACE; - case RegOps.NEW_ARRAY: return Dops.NEW_ARRAY; - case RegOps.FILLED_NEW_ARRAY: return Dops.FILLED_NEW_ARRAY; - case RegOps.FILL_ARRAY_DATA: return Dops.FILL_ARRAY_DATA; - case RegOps.MOVE_RESULT: { - RegisterSpec resultReg = insn.getResult(); - - if (resultReg == null) { - return Dops.NOP; - } else { - switch (resultReg.getBasicType()) { - case Type.BT_INT: - case Type.BT_FLOAT: - case Type.BT_BOOLEAN: - case Type.BT_BYTE: - case Type.BT_CHAR: - case Type.BT_SHORT: - return Dops.MOVE_RESULT; - case Type.BT_LONG: - case Type.BT_DOUBLE: - return Dops.MOVE_RESULT_WIDE; - case Type.BT_OBJECT: - return Dops.MOVE_RESULT_OBJECT; - default: { - throw new RuntimeException("Unexpected basic type"); - } - } - } - } - - case RegOps.GET_FIELD: { - CstFieldRef ref = - (CstFieldRef) ((ThrowingCstInsn) insn).getConstant(); - int basicType = ref.getBasicType(); - switch (basicType) { - case Type.BT_BOOLEAN: return Dops.IGET_BOOLEAN; - case Type.BT_BYTE: return Dops.IGET_BYTE; - case Type.BT_CHAR: return Dops.IGET_CHAR; - case Type.BT_SHORT: return Dops.IGET_SHORT; - case Type.BT_INT: return Dops.IGET; - } - break; - } - case RegOps.PUT_FIELD: { - CstFieldRef ref = - (CstFieldRef) ((ThrowingCstInsn) insn).getConstant(); - int basicType = ref.getBasicType(); - switch (basicType) { - case Type.BT_BOOLEAN: return Dops.IPUT_BOOLEAN; - case Type.BT_BYTE: return Dops.IPUT_BYTE; - case Type.BT_CHAR: return Dops.IPUT_CHAR; - case Type.BT_SHORT: return Dops.IPUT_SHORT; - case Type.BT_INT: return Dops.IPUT; - } - break; - } - case RegOps.GET_STATIC: { - CstFieldRef ref = - (CstFieldRef) ((ThrowingCstInsn) insn).getConstant(); - int basicType = ref.getBasicType(); - switch (basicType) { - case Type.BT_BOOLEAN: return Dops.SGET_BOOLEAN; - case Type.BT_BYTE: return Dops.SGET_BYTE; - case Type.BT_CHAR: return Dops.SGET_CHAR; - case Type.BT_SHORT: return Dops.SGET_SHORT; - case Type.BT_INT: return Dops.SGET; - } - break; - } - case RegOps.PUT_STATIC: { - CstFieldRef ref = - (CstFieldRef) ((ThrowingCstInsn) insn).getConstant(); - int basicType = ref.getBasicType(); - switch (basicType) { - case Type.BT_BOOLEAN: return Dops.SPUT_BOOLEAN; - case Type.BT_BYTE: return Dops.SPUT_BYTE; - case Type.BT_CHAR: return Dops.SPUT_CHAR; - case Type.BT_SHORT: return Dops.SPUT_SHORT; - case Type.BT_INT: return Dops.SPUT; - } - break; - } - case RegOps.CONST: { - Constant cst = ((ThrowingCstInsn) insn).getConstant(); - if (cst instanceof CstType) { - return Dops.CONST_CLASS; - } else if (cst instanceof CstString) { - return Dops.CONST_STRING; - } - break; - } - } - - throw new RuntimeException("unknown rop: " + rop); - } -} diff --git a/dx/src/com/android/dx/dex/code/RopTranslator.java b/dx/src/com/android/dx/dex/code/RopTranslator.java deleted file mode 100644 index f3dfe0b19..000000000 --- a/dx/src/com/android/dx/dex/code/RopTranslator.java +++ /dev/null @@ -1,872 +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.android.dx.dex.code; - -import com.android.dx.rop.code.BasicBlock; -import com.android.dx.rop.code.BasicBlockList; -import com.android.dx.rop.code.FillArrayDataInsn; -import com.android.dx.rop.code.Insn; -import com.android.dx.rop.code.LocalVariableInfo; -import com.android.dx.rop.code.PlainCstInsn; -import com.android.dx.rop.code.PlainInsn; -import com.android.dx.rop.code.RegOps; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.RegisterSpecSet; -import com.android.dx.rop.code.Rop; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.code.SwitchInsn; -import com.android.dx.rop.code.ThrowingCstInsn; -import com.android.dx.rop.code.ThrowingInsn; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.type.Type; -import com.android.dx.util.Bits; -import com.android.dx.util.IntList; - -import java.util.ArrayList; - -/** - * Translator from {@link RopMethod} to {@link DalvCode}. The {@link - * #translate} method is the thing to call on this class. - */ -public final class RopTranslator { - /** non-null; method to translate */ - private final RopMethod method; - - /** - * how much position info to preserve; one of the static - * constants in {@link PositionList} - */ - private final int positionInfo; - - /** null-ok; local variable info to use */ - private final LocalVariableInfo locals; - - /** non-null; container for all the address objects for the method */ - private final BlockAddresses addresses; - - /** non-null; list of output instructions in-progress */ - private final OutputCollector output; - - /** non-null; visitor to use during translation */ - private final TranslationVisitor translationVisitor; - - /** >= 0; register count for the method */ - private final int regCount; - - /** null-ok; block output order; becomes non-null in {@link #pickOrder} */ - private int[] order; - - /** size, in register units, of all the parameters to this method */ - private final int paramSize; - - /** - * true if the parameters to this method happen to be in proper order - * at the end of the frame (as the optimizer emits them) - */ - private boolean paramsAreInOrder; - - /** - * Translates a {@link RopMethod}. This may modify the given - * input. - * - * @param method non-null; the original method - * @param positionInfo how much position info to preserve; one of the - * static constants in {@link PositionList} - * @param locals null-ok; local variable information to use - * @param paramSize size, in register units, of all the parameters to - * this method - * @return non-null; the translated version - */ - public static DalvCode translate(RopMethod method, int positionInfo, - LocalVariableInfo locals, int paramSize) { - RopTranslator translator = - new RopTranslator(method, positionInfo, locals, - paramSize); - return translator.translateAndGetResult(); - } - - /** - * Constructs an instance. This method is private. Use {@link #translate}. - * - * @param method non-null; the original method - * @param positionInfo how much position info to preserve; one of the - * static constants in {@link PositionList} - * @param locals null-ok; local variable information to use - * @param paramSize size, in register units, of all the parameters to - * this method - */ - private RopTranslator(RopMethod method, int positionInfo, - LocalVariableInfo locals, int paramSize) { - this.method = method; - this.positionInfo = positionInfo; - this.locals = locals; - this.addresses = new BlockAddresses(method); - this.paramSize = paramSize; - this.order = null; - this.paramsAreInOrder = calculateParamsAreInOrder(method, paramSize); - - BasicBlockList blocks = method.getBlocks(); - int bsz = blocks.size(); - - /* - * Max possible instructions includes three code address - * objects per basic block (to the first and last instruction, - * and just past the end of the block), and the possibility of - * an extra goto at the end of each basic block. - */ - int maxInsns = (bsz * 3) + blocks.getInstructionCount(); - - if (locals != null) { - /* - * If we're tracking locals, then there's could be another - * extra instruction per block (for the locals state at the - * start of the block) as well as one for each interblock - * local introduction. - */ - maxInsns += bsz + locals.getAssignmentCount(); - } - - /* - * If params are not in order, we will need register space - * for them before this is all over... - */ - this.regCount = blocks.getRegCount() - + (paramsAreInOrder ? 0 : this.paramSize); - - this.output = new OutputCollector(maxInsns, bsz * 3, regCount); - - if (locals != null) { - this.translationVisitor = - new LocalVariableAwareTranslationVisitor(output, locals); - } else { - this.translationVisitor = new TranslationVisitor(output); - } - } - - /** - * Checks to see if the move-param instructions that occur in this - * method happen to slot the params in an order at the top of the - * stack frame that matches dalvik's calling conventions. This will - * alway result in "true" for methods that have run through the - * SSA optimizer. - * - * @param paramSize size, in register units, of all the parameters - * to this method - */ - private static boolean calculateParamsAreInOrder(RopMethod method, - final int paramSize) { - final boolean[] paramsAreInOrder = { true }; - final int initialRegCount = method.getBlocks().getRegCount(); - - /* - * We almost could just check the first block here, but the - * <code>cf</code> layer will put in a second move-param in a - * subsequent block in the case of synchronized methods. - */ - method.getBlocks().forEachInsn(new Insn.BaseVisitor() { - public void visitPlainCstInsn(PlainCstInsn insn) { - if (insn.getOpcode().getOpcode()== RegOps.MOVE_PARAM) { - int param = - ((CstInteger) insn.getConstant()).getValue(); - - paramsAreInOrder[0] = paramsAreInOrder[0] - && ((initialRegCount - paramSize + param) - == insn.getResult().getReg()); - } - } - }); - - return paramsAreInOrder[0]; - } - - /** - * Does the translation and returns the result. - * - * @return non-null; the result - */ - private DalvCode translateAndGetResult() { - pickOrder(); - outputInstructions(); - - StdCatchBuilder catches = - new StdCatchBuilder(method, order, addresses); - - return new DalvCode(positionInfo, output.getFinisher(), catches); - } - - /** - * Performs initial creation of output instructions based on the - * original blocks. - */ - private void outputInstructions() { - BasicBlockList blocks = method.getBlocks(); - int[] order = this.order; - int len = order.length; - - // Process the blocks in output order. - for (int i = 0; i < len; i++) { - int nextI = i + 1; - int nextLabel = (nextI == order.length) ? -1 : order[nextI]; - outputBlock(blocks.labelToBlock(order[i]), nextLabel); - } - } - - /** - * Helper for {@link #outputInstructions}, which does the processing - * and output of one block. - * - * @param block non-null; the block to process and output - * @param nextLabel >= -1; the next block that will be processed, or - * <code>-1</code> if there is no next block - */ - private void outputBlock(BasicBlock block, int nextLabel) { - // Append the code address for this block. - CodeAddress startAddress = addresses.getStart(block); - output.add(startAddress); - - // Append the local variable state for the block. - if (locals != null) { - RegisterSpecSet starts = locals.getStarts(block); - output.add(new LocalSnapshot(startAddress.getPosition(), - starts)); - } - - /* - * Choose and append an output instruction for each original - * instruction. - */ - translationVisitor.setBlock(block, addresses.getLast(block)); - block.getInsns().forEach(translationVisitor); - - // Insert the block end code address. - output.add(addresses.getEnd(block)); - - // Set up for end-of-block activities. - - int succ = block.getPrimarySuccessor(); - Insn lastInsn = block.getLastInsn(); - - /* - * Check for (and possibly correct for) a non-optimal choice of - * which block will get output next. - */ - - if ((succ >= 0) && (succ != nextLabel)) { - /* - * The block has a "primary successor" and that primary - * successor isn't the next block to be output. - */ - Rop lastRop = lastInsn.getOpcode(); - if ((lastRop.getBranchingness() == Rop.BRANCH_IF) && - (block.getSecondarySuccessor() == nextLabel)) { - /* - * The block ends with an "if" of some sort, and its - * secondary successor (the "then") is in fact the - * next block to output. So, reverse the sense of - * the test, so that we can just emit the next block - * without an interstitial goto. - */ - output.reverseBranch(1, addresses.getStart(succ)); - } else { - /* - * Our only recourse is to add a goto here to get the - * flow to be correct. - */ - TargetInsn insn = - new TargetInsn(Dops.GOTO, lastInsn.getPosition(), - RegisterSpecList.EMPTY, - addresses.getStart(succ)); - output.add(insn); - } - } - } - - /** - * Picks an order for the blocks by doing "trace" analysis. - */ - private void pickOrder() { - BasicBlockList blocks = method.getBlocks(); - int sz = blocks.size(); - int maxLabel = blocks.getMaxLabel(); - int[] workSet = Bits.makeBitSet(maxLabel); - int[] tracebackSet = Bits.makeBitSet(maxLabel); - - for (int i = 0; i < sz; i++) { - BasicBlock one = blocks.get(i); - Bits.set(workSet, one.getLabel()); - } - - int[] order = new int[sz]; - int at = 0; - - /* - * Starting with the designated "first label" (that is, the - * first block of the method), add that label to the order, - * and then pick its first as-yet unordered successor to - * immediately follow it, giving top priority to the primary - * (aka default) successor (if any). Keep following successors - * until the trace runs out of possibilities. Then, continue - * by finding an unordered chain containing the first as-yet - * unordered block, and adding it to the order, and so on. - */ - for (int label = method.getFirstLabel(); - label != -1; - label = Bits.findFirst(workSet, 0)) { - - /* - * Attempt to trace backward from the chosen block to an - * as-yet unordered predecessor which lists the chosen - * block as its primary successor, and so on, until we - * fail to find such an unordered predecessor. Start the - * trace with that block. Note that the first block in the - * method has no predecessors, so in that case this loop - * will simply terminate with zero iterations and without - * picking a new starter block. - */ - traceBack: - for (;;) { - IntList preds = method.labelToPredecessors(label); - int psz = preds.size(); - - for (int i = 0; i < psz; i++) { - int predLabel = preds.get(i); - - if (Bits.get(tracebackSet, predLabel)) { - /* - * We found a predecessor loop; stop tracing back - * from here. - */ - break; - } - - if (!Bits.get(workSet, predLabel)) { - // This one's already ordered. - continue; - } - - BasicBlock pred = blocks.labelToBlock(predLabel); - if (pred.getPrimarySuccessor() == label) { - // Found one! - label = predLabel; - Bits.set(tracebackSet, label); - continue traceBack; - } - } - - // Failed to find a better block to start the trace. - break; - } - - /* - * Trace a path from the chosen block to one of its - * unordered successors (hopefully the primary), and so - * on, until we run out of unordered successors. - */ - while (label != -1) { - Bits.clear(workSet, label); - Bits.clear(tracebackSet, label); - order[at] = label; - at++; - - BasicBlock one = blocks.labelToBlock(label); - BasicBlock preferredBlock = blocks.preferredSuccessorOf(one); - - if (preferredBlock == null) { - break; - } - - int preferred = preferredBlock.getLabel(); - int primary = one.getPrimarySuccessor(); - - if (Bits.get(workSet, preferred)) { - /* - * Order the current block's preferred successor - * next, as it has yet to be scheduled. - */ - label = preferred; - } else if ((primary != preferred) && (primary >= 0) - && Bits.get(workSet, primary)) { - /* - * The primary is available, so use that. - */ - label = primary; - } else { - /* - * There's no obvious candidate, so pick the first - * one that's available, if any. - */ - IntList successors = one.getSuccessors(); - int ssz = successors.size(); - label = -1; - for (int i = 0; i < ssz; i++) { - int candidate = successors.get(i); - if (Bits.get(workSet, candidate)) { - label = candidate; - break; - } - } - } - } - } - - if (at != sz) { - // There was a duplicate block label. - throw new RuntimeException("shouldn't happen"); - } - - this.order = order; - } - - /** - * Gets the complete register list (result and sources) out of a - * given rop instruction. For insns that are commutative, have - * two register sources, and have a source equal to the result, - * place that source first. - * - * @param insn non-null; instruction in question - * @return non-null; the instruction's complete register list - */ - private static RegisterSpecList getRegs(Insn insn) { - return getRegs(insn, insn.getResult()); - } - - /** - * Gets the complete register list (result and sources) out of a - * given rop instruction. For insns that are commutative, have - * two register sources, and have a source equal to the result, - * place that source first. - * - * @param insn non-null; instruction in question - * @param resultReg null-ok; the real result to use (ignore the insn's) - * @return non-null; the instruction's complete register list - */ - private static RegisterSpecList getRegs(Insn insn, - RegisterSpec resultReg) { - RegisterSpecList regs = insn.getSources(); - - if (insn.getOpcode().isCommutative() - && (regs.size() == 2) - && (resultReg.getReg() == regs.get(1).getReg())) { - - /* - * For commutative ops which have two register sources, - * if the second source is the same register as the result, - * swap the sources so that an opcode of form 12x can be selected - * instead of one of form 23x - */ - - regs = RegisterSpecList.make(regs.get(1), regs.get(0)); - } - - if (resultReg == null) { - return regs; - } - - return regs.withFirst(resultReg); - } - - /** - * Instruction visitor class for doing the instruction translation per se. - */ - private class TranslationVisitor implements Insn.Visitor { - /** non-null; list of output instructions in-progress */ - private final OutputCollector output; - - /** non-null; basic block being worked on */ - private BasicBlock block; - - /** - * null-ok; code address for the salient last instruction of the - * block (used before switches and throwing instructions) - */ - private CodeAddress lastAddress; - - /** - * Constructs an instance. - * - * @param output non-null; destination for instruction output - */ - public TranslationVisitor(OutputCollector output) { - this.output = output; - } - - /** - * Sets the block currently being worked on. - * - * @param block non-null; the block - * @param lastAddress non-null; code address for the salient - * last instruction of the block - */ - public void setBlock(BasicBlock block, CodeAddress lastAddress) { - this.block = block; - this.lastAddress = lastAddress; - } - - /** {@inheritDoc} */ - public void visitPlainInsn(PlainInsn insn) { - Rop rop = insn.getOpcode(); - if (rop.getOpcode() == RegOps.MARK_LOCAL) { - /* - * Ignore these. They're dealt with by - * the LocalVariableAwareTranslationVisitor - */ - return; - } - if (rop.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) { - // These get skipped - return; - } - - SourcePosition pos = insn.getPosition(); - Dop opcode = RopToDop.dopFor(insn); - DalvInsn di; - - switch (rop.getBranchingness()) { - case Rop.BRANCH_NONE: - case Rop.BRANCH_RETURN: - case Rop.BRANCH_THROW: { - di = new SimpleInsn(opcode, pos, getRegs(insn)); - break; - } - case Rop.BRANCH_GOTO: { - /* - * Code in the main translation loop will emit a - * goto if necessary (if the branch isn't to the - * immediately subsequent block). - */ - return; - } - case Rop.BRANCH_IF: { - int target = block.getSuccessors().get(1); - di = new TargetInsn(opcode, pos, getRegs(insn), - addresses.getStart(target)); - break; - } - default: { - throw new RuntimeException("shouldn't happen"); - } - } - - addOutput(di); - } - - /** {@inheritDoc} */ - public void visitPlainCstInsn(PlainCstInsn insn) { - SourcePosition pos = insn.getPosition(); - Dop opcode = RopToDop.dopFor(insn); - Rop rop = insn.getOpcode(); - int ropOpcode = rop.getOpcode(); - DalvInsn di; - - if (rop.getBranchingness() != Rop.BRANCH_NONE) { - throw new RuntimeException("shouldn't happen"); - } - - if (ropOpcode == RegOps.MOVE_PARAM) { - if (!paramsAreInOrder) { - /* - * Parameters are not in order at the top of the reg space. - * We need to add moves. - */ - - RegisterSpec dest = insn.getResult(); - int param = - ((CstInteger) insn.getConstant()).getValue(); - RegisterSpec source = - RegisterSpec.make(regCount - paramSize + param, - dest.getType()); - di = new SimpleInsn(opcode, pos, - RegisterSpecList.make(dest, source)); - addOutput(di); - } - } else { - // No moves required for the parameters - RegisterSpecList regs = getRegs(insn); - di = new CstInsn(opcode, pos, regs, insn.getConstant()); - addOutput(di); - } - } - - /** {@inheritDoc} */ - public void visitSwitchInsn(SwitchInsn insn) { - SourcePosition pos = insn.getPosition(); - IntList cases = insn.getCases(); - IntList successors = block.getSuccessors(); - int casesSz = cases.size(); - int succSz = successors.size(); - int primarySuccessor = block.getPrimarySuccessor(); - - /* - * Check the assumptions that the number of cases is one - * less than the number of successors and that the last - * successor in the list is the primary (in this case, the - * default). This test is here to guard against forgetting - * to change this code if the way switch instructions are - * constructed also gets changed. - */ - if ((casesSz != (succSz - 1)) || - (primarySuccessor != successors.get(casesSz))) { - throw new RuntimeException("shouldn't happen"); - } - - CodeAddress[] switchTargets = new CodeAddress[casesSz]; - - for (int i = 0; i < casesSz; i++) { - int label = successors.get(i); - switchTargets[i] = addresses.getStart(label); - } - - CodeAddress dataAddress = new CodeAddress(pos); - SwitchData dataInsn = - new SwitchData(pos, lastAddress, cases, switchTargets); - Dop opcode = dataInsn.isPacked() ? - Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH; - TargetInsn switchInsn = - new TargetInsn(opcode, pos, getRegs(insn), dataAddress); - - addOutput(lastAddress); - addOutput(switchInsn); - - addOutputSuffix(new OddSpacer(pos)); - addOutputSuffix(dataAddress); - addOutputSuffix(dataInsn); - } - - /** - * Looks forward to the current block's primary successor, returning - * the RegisterSpec of the result of the move-result-pseudo at the - * top of that block or null if none. - * - * @return null-ok; result of move-result-pseudo at the beginning of - * primary successor - */ - private RegisterSpec getNextMoveResultPseudo() - { - int label = block.getPrimarySuccessor(); - - if (label < 0) { - return null; - } - - Insn insn - = method.getBlocks().labelToBlock(label).getInsns().get(0); - - if (insn.getOpcode().getOpcode() != RegOps.MOVE_RESULT_PSEUDO) { - return null; - } else { - return insn.getResult(); - } - } - - /** {@inheritDoc} */ - public void visitThrowingCstInsn(ThrowingCstInsn insn) { - SourcePosition pos = insn.getPosition(); - Dop opcode = RopToDop.dopFor(insn); - Rop rop = insn.getOpcode(); - Constant cst = insn.getConstant(); - - if (rop.getBranchingness() != Rop.BRANCH_THROW) { - throw new RuntimeException("shouldn't happen"); - } - - addOutput(lastAddress); - - if (rop.isCallLike()) { - RegisterSpecList regs = insn.getSources(); - DalvInsn di = new CstInsn(opcode, pos, regs, cst); - - addOutput(di); - } else { - RegisterSpec realResult = getNextMoveResultPseudo(); - - RegisterSpecList regs = getRegs(insn, realResult); - DalvInsn di; - - boolean hasResult = opcode.hasResult() - || (rop.getOpcode() == RegOps.CHECK_CAST); - - if (hasResult != (realResult != null)) { - throw new RuntimeException( - "Insn with result/move-result-pseudo mismatch " + - insn); - } - - if ((rop.getOpcode() == RegOps.NEW_ARRAY) && - (opcode.getOpcode() != DalvOps.NEW_ARRAY)) { - /* - * It's a type-specific new-array-<primitive>, and - * so it should be turned into a SimpleInsn (no - * constant ref as it's implicit). - */ - di = new SimpleInsn(opcode, pos, regs); - } else { - /* - * This is the general case for constant-bearing - * instructions. - */ - di = new CstInsn(opcode, pos, regs, cst); - } - - addOutput(di); - } - } - - /** {@inheritDoc} */ - public void visitThrowingInsn(ThrowingInsn insn) { - SourcePosition pos = insn.getPosition(); - Dop opcode = RopToDop.dopFor(insn); - Rop rop = insn.getOpcode(); - RegisterSpec realResult; - - if (rop.getBranchingness() != Rop.BRANCH_THROW) { - throw new RuntimeException("shouldn't happen"); - } - - realResult = getNextMoveResultPseudo(); - - if (opcode.hasResult() != (realResult != null)) { - throw new RuntimeException( - "Insn with result/move-result-pseudo mismatch" + insn); - } - - addOutput(lastAddress); - - DalvInsn di = new SimpleInsn(opcode, pos, - getRegs(insn, realResult)); - - addOutput(di); - } - - /** {@inheritDoc} */ - public void visitFillArrayDataInsn(FillArrayDataInsn insn) { - SourcePosition pos = insn.getPosition(); - Constant cst = insn.getConstant(); - ArrayList<Constant> values = insn.getInitValues(); - Rop rop = insn.getOpcode(); - - if (rop.getBranchingness() != Rop.BRANCH_NONE) { - throw new RuntimeException("shouldn't happen"); - } - CodeAddress dataAddress = new CodeAddress(pos); - ArrayData dataInsn = - new ArrayData(pos, lastAddress, values, cst); - - TargetInsn fillArrayDataInsn = - new TargetInsn(Dops.FILL_ARRAY_DATA, pos, getRegs(insn), - dataAddress); - - addOutput(lastAddress); - addOutput(fillArrayDataInsn); - - addOutputSuffix(new OddSpacer(pos)); - addOutputSuffix(dataAddress); - addOutputSuffix(dataInsn); - } - - /** - * Adds to the output. - * - * @param insn non-null; instruction to add - */ - protected void addOutput(DalvInsn insn) { - output.add(insn); - } - - /** - * Adds to the output suffix. - * - * @param insn non-null; instruction to add - */ - protected void addOutputSuffix(DalvInsn insn) { - output.addSuffix(insn); - } - } - - /** - * Instruction visitor class for doing instruction translation with - * local variable tracking - */ - private class LocalVariableAwareTranslationVisitor - extends TranslationVisitor { - /** non-null; local variable info */ - private LocalVariableInfo locals; - - /** - * Constructs an instance. - * - * @param output non-null; destination for instruction output - * @param locals non-null; the local variable info - */ - public LocalVariableAwareTranslationVisitor(OutputCollector output, - LocalVariableInfo locals) { - super(output); - this.locals = locals; - } - - /** {@inheritDoc} */ - @Override - public void visitPlainInsn(PlainInsn insn) { - super.visitPlainInsn(insn); - addIntroductionIfNecessary(insn); - } - - /** {@inheritDoc} */ - @Override - public void visitPlainCstInsn(PlainCstInsn insn) { - super.visitPlainCstInsn(insn); - addIntroductionIfNecessary(insn); - } - - /** {@inheritDoc} */ - @Override - public void visitSwitchInsn(SwitchInsn insn) { - super.visitSwitchInsn(insn); - addIntroductionIfNecessary(insn); - } - - /** {@inheritDoc} */ - @Override - public void visitThrowingCstInsn(ThrowingCstInsn insn) { - super.visitThrowingCstInsn(insn); - addIntroductionIfNecessary(insn); - } - - /** {@inheritDoc} */ - @Override - public void visitThrowingInsn(ThrowingInsn insn) { - super.visitThrowingInsn(insn); - addIntroductionIfNecessary(insn); - } - - /** - * Adds a {@link LocalStart} to the output if the given - * instruction in fact introduces a local variable. - * - * @param insn non-null; instruction in question - */ - public void addIntroductionIfNecessary(Insn insn) { - RegisterSpec spec = locals.getAssignment(insn); - - if (spec != null) { - addOutput(new LocalStart(insn.getPosition(), spec)); - } - } - } -} diff --git a/dx/src/com/android/dx/dex/code/SimpleInsn.java b/dx/src/com/android/dx/dex/code/SimpleInsn.java deleted file mode 100644 index ba204090b..000000000 --- a/dx/src/com/android/dx/dex/code/SimpleInsn.java +++ /dev/null @@ -1,59 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; - -/** - * Instruction which has no extra info beyond the basics provided for in - * the base class. - */ -public final class SimpleInsn extends FixedSizeInsn { - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param opcode the opcode; one of the constants from {@link Dops} - * @param position non-null; source position - * @param registers non-null; register list, including a - * result register if appropriate (that is, registers may be either - * ins or outs) - */ - public SimpleInsn(Dop opcode, SourcePosition position, - RegisterSpecList registers) { - super(opcode, position, registers); - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withOpcode(Dop opcode) { - return new SimpleInsn(opcode, getPosition(), getRegisters()); - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisters(RegisterSpecList registers) { - return new SimpleInsn(getOpcode(), getPosition(), registers); - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - return null; - } -} diff --git a/dx/src/com/android/dx/dex/code/StdCatchBuilder.java b/dx/src/com/android/dx/dex/code/StdCatchBuilder.java deleted file mode 100644 index 1240f3f7d..000000000 --- a/dx/src/com/android/dx/dex/code/StdCatchBuilder.java +++ /dev/null @@ -1,317 +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.android.dx.dex.code; - -import com.android.dx.rop.code.BasicBlock; -import com.android.dx.rop.code.BasicBlockList; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.IntList; - -import java.util.ArrayList; -import java.util.HashSet; - -/** - * Constructor of {@link CatchTable} instances from {@link RopMethod} - * and associated data. - */ -public final class StdCatchBuilder implements CatchBuilder { - /** the maximum range of a single catch handler, in code units */ - private static final int MAX_CATCH_RANGE = 65535; - - /** non-null; method to build the list for */ - private final RopMethod method; - - /** non-null; block output order */ - private final int[] order; - - /** non-null; address objects for each block */ - private final BlockAddresses addresses; - - /** - * Constructs an instance. It merely holds onto its parameters for - * a subsequent call to {@link #build}. - * - * @param method non-null; method to build the list for - * @param order non-null; block output order - * @param addresses non-null; address objects for each block - */ - public StdCatchBuilder(RopMethod method, int[] order, - BlockAddresses addresses) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - if (order == null) { - throw new NullPointerException("order == null"); - } - - if (addresses == null) { - throw new NullPointerException("addresses == null"); - } - - this.method = method; - this.order = order; - this.addresses = addresses; - } - - /** {@inheritDoc} */ - public CatchTable build() { - return build(method, order, addresses); - } - - /** {@inheritDoc} */ - public boolean hasAnyCatches() { - HashSet<Type> result = new HashSet<Type>(20); - BasicBlockList blocks = method.getBlocks(); - int size = blocks.size(); - - for (int i = 0; i < size; i++) { - BasicBlock block = blocks.get(i); - TypeList catches = block.getLastInsn().getCatches(); - if (catches.size() != 0) { - return true; - } - } - - return false; - } - - /** {@inheritDoc} */ - public HashSet<Type> getCatchTypes() { - HashSet<Type> result = new HashSet<Type>(20); - BasicBlockList blocks = method.getBlocks(); - int size = blocks.size(); - - for (int i = 0; i < size; i++) { - BasicBlock block = blocks.get(i); - TypeList catches = block.getLastInsn().getCatches(); - int catchSize = catches.size(); - - for (int j = 0; j < catchSize; j++) { - result.add(catches.getType(j)); - } - } - - return result; - } - - /** - * Builds and returns the catch table for a given method. - * - * @param method non-null; method to build the list for - * @param order non-null; block output order - * @param addresses non-null; address objects for each block - * @return non-null; the constructed table - */ - public static CatchTable build(RopMethod method, int[] order, - BlockAddresses addresses) { - int len = order.length; - BasicBlockList blocks = method.getBlocks(); - ArrayList<CatchTable.Entry> resultList = - new ArrayList<CatchTable.Entry>(len); - CatchHandlerList currentHandlers = CatchHandlerList.EMPTY; - BasicBlock currentStartBlock = null; - BasicBlock currentEndBlock = null; - - for (int i = 0; i < len; i++) { - BasicBlock block = blocks.labelToBlock(order[i]); - - if (!block.canThrow()) { - /* - * There is no need to concern ourselves with the - * placement of blocks that can't throw with respect - * to the blocks that *can* throw. - */ - continue; - } - - CatchHandlerList handlers = handlersFor(block, addresses); - - if (currentHandlers.size() == 0) { - // This is the start of a new catch range. - currentStartBlock = block; - currentEndBlock = block; - currentHandlers = handlers; - continue; - } - - if (currentHandlers.equals(handlers) - && rangeIsValid(currentStartBlock, block, addresses)) { - /* - * The block we are looking at now has the same handlers - * as the block that started the currently open catch - * range, and adding it to the currently open range won't - * cause it to be too long. - */ - currentEndBlock = block; - continue; - } - - /* - * The block we are looking at now has incompatible handlers, - * so we need to finish off the last entry and start a new - * one. Note: We only emit an entry if it has associated handlers. - */ - if (currentHandlers.size() != 0) { - CatchTable.Entry entry = - makeEntry(currentStartBlock, currentEndBlock, - currentHandlers, addresses); - resultList.add(entry); - } - - currentStartBlock = block; - currentEndBlock = block; - currentHandlers = handlers; - } - - if (currentHandlers.size() != 0) { - // Emit an entry for the range that was left hanging. - CatchTable.Entry entry = - makeEntry(currentStartBlock, currentEndBlock, - currentHandlers, addresses); - resultList.add(entry); - } - - // Construct the final result. - - int resultSz = resultList.size(); - - if (resultSz == 0) { - return CatchTable.EMPTY; - } - - CatchTable result = new CatchTable(resultSz); - - for (int i = 0; i < resultSz; i++) { - result.set(i, resultList.get(i)); - } - - result.setImmutable(); - return result; - } - - /** - * Makes the {@link CatchHandlerList} for the given basic block. - * - * @param block non-null; block to get entries for - * @param addresses non-null; address objects for each block - * @return non-null; array of entries - */ - private static CatchHandlerList handlersFor(BasicBlock block, - BlockAddresses addresses) { - IntList successors = block.getSuccessors(); - int succSize = successors.size(); - int primary = block.getPrimarySuccessor(); - TypeList catches = block.getLastInsn().getCatches(); - int catchSize = catches.size(); - - if (catchSize == 0) { - return CatchHandlerList.EMPTY; - } - - if (((primary == -1) && (succSize != catchSize)) - || ((primary != -1) && - ((succSize != (catchSize + 1)) - || (primary != successors.get(catchSize))))) { - /* - * Blocks that throw are supposed to list their primary - * successor -- if any -- last in the successors list, but - * that constraint appears to be violated here. - */ - throw new RuntimeException( - "shouldn't happen: weird successors list"); - } - - /* - * Reduce the effective catchSize if we spot a catch-all that - * isn't at the end. - */ - for (int i = 0; i < catchSize; i++) { - Type type = catches.getType(i); - if (type.equals(Type.OBJECT)) { - catchSize = i + 1; - break; - } - } - - CatchHandlerList result = new CatchHandlerList(catchSize); - - for (int i = 0; i < catchSize; i++) { - CstType oneType = new CstType(catches.getType(i)); - CodeAddress oneHandler = addresses.getStart(successors.get(i)); - result.set(i, oneType, oneHandler.getAddress()); - } - - result.setImmutable(); - return result; - } - - /** - * Makes a {@link CatchTable#Entry} for the given block range and - * handlers. - * - * @param start non-null; the start block for the range (inclusive) - * @param end non-null; the start block for the range (also inclusive) - * @param handlers non-null; the handlers for the range - * @param addresses non-null; address objects for each block - */ - private static CatchTable.Entry makeEntry(BasicBlock start, - BasicBlock end, CatchHandlerList handlers, - BlockAddresses addresses) { - /* - * We start at the *last* instruction of the start block, since - * that's the instruction that can throw... - */ - CodeAddress startAddress = addresses.getLast(start); - - // ...And we end *after* the last instruction of the end block. - CodeAddress endAddress = addresses.getEnd(end); - - return new CatchTable.Entry(startAddress.getAddress(), - endAddress.getAddress(), handlers); - } - - /** - * Gets whether the address range for the given two blocks is valid - * for a catch handler. This is true as long as the covered range is - * under 65536 code units. - * - * @param start non-null; the start block for the range (inclusive) - * @param end non-null; the start block for the range (also inclusive) - * @param addresses non-null; address objects for each block - * @return <code>true</code> if the range is valid as a catch range - */ - private static boolean rangeIsValid(BasicBlock start, BasicBlock end, - BlockAddresses addresses) { - if (start == null) { - throw new NullPointerException("start == null"); - } - - if (end == null) { - throw new NullPointerException("end == null"); - } - - // See above about selection of instructions. - int startAddress = addresses.getLast(start).getAddress(); - int endAddress = addresses.getEnd(end).getAddress(); - - return (endAddress - startAddress) <= MAX_CATCH_RANGE; - } -} diff --git a/dx/src/com/android/dx/dex/code/SwitchData.java b/dx/src/com/android/dx/dex/code/SwitchData.java deleted file mode 100644 index 1aaafa951..000000000 --- a/dx/src/com/android/dx/dex/code/SwitchData.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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; - -/** - * Pseudo-instruction which holds switch data. The switch data is - * a map of values to target addresses, and this class writes the data - * in either a "packed" or "sparse" form. - */ -public final class SwitchData extends VariableSizeInsn { - /** - * non-null; address representing the instruction that uses this - * instance - */ - private final CodeAddress user; - - /** non-null; sorted list of switch cases (keys) */ - private final IntList cases; - - /** - * non-null; corresponding list of code addresses; the branch - * target for each case - */ - private final CodeAddress[] targets; - - /** whether the output table will be packed (vs. sparse) */ - private final boolean packed; - - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param position non-null; source position - * @param user non-null; address representing the instruction that - * uses this instance - * @param cases non-null; sorted list of switch cases (keys) - * @param targets non-null; corresponding list of code addresses; the - * branch target for each case - */ - public SwitchData(SourcePosition position, CodeAddress user, - IntList cases, CodeAddress[] targets) { - super(position, RegisterSpecList.EMPTY); - - if (user == null) { - throw new NullPointerException("user == null"); - } - - if (cases == null) { - throw new NullPointerException("cases == null"); - } - - if (targets == null) { - throw new NullPointerException("targets == null"); - } - - int sz = cases.size(); - - if (sz != targets.length) { - throw new IllegalArgumentException("cases / targets mismatch"); - } - - if (sz > 65535) { - throw new IllegalArgumentException("too many cases"); - } - - this.user = user; - this.cases = cases; - this.targets = targets; - this.packed = shouldPack(cases); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return packed ? (int) packedCodeSize(cases) : - (int) sparseCodeSize(cases); - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out) { - int baseAddress = user.getAddress(); - int defaultTarget = Dops.PACKED_SWITCH.getFormat().codeSize(); - int sz = targets.length; - - if (packed) { - int firstCase = (sz == 0) ? 0 : cases.get(0); - int lastCase = (sz == 0) ? 0 : cases.get(sz - 1); - int outSz = lastCase - firstCase + 1; - - out.writeShort(0x100 | DalvOps.NOP); - out.writeShort(outSz); - out.writeInt(firstCase); - - int caseAt = 0; - for (int i = 0; i < outSz; i++) { - int outCase = firstCase + i; - int oneCase = cases.get(caseAt); - int relTarget; - - if (oneCase > outCase) { - relTarget = defaultTarget; - } else { - relTarget = targets[caseAt].getAddress() - baseAddress; - caseAt++; - } - - out.writeInt(relTarget); - } - } else { - out.writeShort(0x200 | DalvOps.NOP); - out.writeShort(sz); - - for (int i = 0; i < sz; i++) { - out.writeInt(cases.get(i)); - } - - for (int i = 0; i < sz; i++) { - int relTarget = targets[i].getAddress() - baseAddress; - out.writeInt(relTarget); - } - } - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisters(RegisterSpecList registers) { - return new SwitchData(getPosition(), user, cases, targets); - } - - /** - * Returns whether or not this instance's data will be output as packed. - * - * @return <code>true</code> iff the data is to be packed - */ - public boolean isPacked() { - return packed; - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - StringBuffer sb = new StringBuffer(100); - - int sz = targets.length; - for (int i = 0; i < sz; i++) { - sb.append("\n "); - sb.append(cases.get(i)); - sb.append(": "); - sb.append(targets[i]); - } - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - protected String listingString0(boolean noteIndices) { - int baseAddress = user.getAddress(); - StringBuffer sb = new StringBuffer(100); - int sz = targets.length; - - sb.append(packed ? "packed" : "sparse"); - sb.append("-switch-data // for switch @ "); - sb.append(Hex.u2(baseAddress)); - - for (int i = 0; i < sz; i++) { - int absTarget = targets[i].getAddress(); - int relTarget = absTarget - baseAddress; - sb.append("\n "); - sb.append(cases.get(i)); - sb.append(": "); - sb.append(Hex.u4(absTarget)); - sb.append(" // "); - sb.append(Hex.s4(relTarget)); - } - - return sb.toString(); - } - - /** - * Gets the size of a packed table for the given cases, in 16-bit code - * units. - * - * @param cases non-null; sorted list of cases - * @return >= -1; the packed table size or <code>-1</code> if the - * cases couldn't possibly be represented as a packed table - */ - private static long packedCodeSize(IntList cases) { - int sz = cases.size(); - long low = cases.get(0); - long high = cases.get(sz - 1); - long result = ((high - low + 1)) * 2 + 4; - - return (result <= 0x7fffffff) ? result : -1; - } - - /** - * Gets the size of a sparse table for the given cases, in 16-bit code - * units. - * - * @param cases non-null; sorted list of cases - * @return > 0; the sparse table size - */ - private static long sparseCodeSize(IntList cases) { - int sz = cases.size(); - - return (sz * 4L) + 2; - } - - /** - * Determines whether the given list of cases warrant being packed. - * - * @param cases non-null; sorted list of cases - * @return <code>true</code> iff the table encoding the cases - * should be packed - */ - private static boolean shouldPack(IntList cases) { - int sz = cases.size(); - - if (sz < 2) { - return true; - } - - long packedSize = packedCodeSize(cases); - long sparseSize = sparseCodeSize(cases); - - /* - * We pick the packed representation if it is possible and - * would be as small or smaller than 5/4 of the sparse - * representation. That is, we accept some size overhead on - * the packed representation, since that format is faster to - * execute at runtime. - */ - return (packedSize >= 0) && (packedSize <= ((sparseSize * 5) / 4)); - } -} diff --git a/dx/src/com/android/dx/dex/code/TargetInsn.java b/dx/src/com/android/dx/dex/code/TargetInsn.java deleted file mode 100644 index 5620795d3..000000000 --- a/dx/src/com/android/dx/dex/code/TargetInsn.java +++ /dev/null @@ -1,132 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; - -/** - * Instruction which has a single branch target. - */ -public final class TargetInsn extends FixedSizeInsn { - /** non-null; the branch target */ - private CodeAddress target; - - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>), and the target is initially - * <code>null</code>. - * - * @param opcode the opcode; one of the constants from {@link Dops} - * @param position non-null; source position - * @param registers non-null; register list, including a - * result register if appropriate (that is, registers may be either - * ins or outs) - * @param target non-null; the branch target - */ - public TargetInsn(Dop opcode, SourcePosition position, - RegisterSpecList registers, CodeAddress target) { - super(opcode, position, registers); - - if (target == null) { - throw new NullPointerException("target == null"); - } - - this.target = target; - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withOpcode(Dop opcode) { - return new TargetInsn(opcode, getPosition(), getRegisters(), target); - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisters(RegisterSpecList registers) { - return new TargetInsn(getOpcode(), getPosition(), registers, target); - } - - /** - * Returns an instance that is just like this one, except that its - * opcode has the opposite sense (as a test; e.g. a - * <code>lt</code> test becomes a <code>ge</code>), and its branch - * target is replaced by the one given, and all set-once values - * associated with the class (such as its address) are reset. - * - * @param target non-null; the new branch target - * @return non-null; an appropriately-constructed instance - */ - public TargetInsn withNewTargetAndReversed(CodeAddress target) { - Dop opcode = getOpcode().getOppositeTest(); - - return new TargetInsn(opcode, getPosition(), getRegisters(), target); - } - - /** - * Gets the unique branch target of this instruction. - * - * @return non-null; the branch target - */ - public CodeAddress getTarget() { - return target; - } - - /** - * Gets the target address of this instruction. This is only valid - * to call if the target instruction has been assigned an address, - * and it is merely a convenient shorthand for - * <code>getTarget().getAddress()</code>. - * - * @return >= 0; the target address - */ - public int getTargetAddress() { - return target.getAddress(); - } - - /** - * Gets the branch offset of this instruction. This is only valid to - * call if both this and the target instruction each has been assigned - * an address, and it is merely a convenient shorthand for - * <code>getTargetAddress() - getAddress()</code>. - * - * @return the branch offset - */ - public int getTargetOffset() { - return target.getAddress() - getAddress(); - } - - /** - * Returns whether the target offset is known. - * - * @return <code>true</code> if the target offset is known or - * <code>false</code> if not - */ - public boolean hasTargetOffset() { - return hasAddress() && target.hasAddress(); - } - - /** {@inheritDoc} */ - @Override - protected String argString() { - if (target == null) { - return "????"; - } - - return target.identifierString(); - } -} diff --git a/dx/src/com/android/dx/dex/code/VariableSizeInsn.java b/dx/src/com/android/dx/dex/code/VariableSizeInsn.java deleted file mode 100644 index 788424901..000000000 --- a/dx/src/com/android/dx/dex/code/VariableSizeInsn.java +++ /dev/null @@ -1,49 +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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; - -/** - * Pseudo-instruction base class for variable-sized instructions. - */ -public abstract class VariableSizeInsn extends DalvInsn { - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param position non-null; source position - * @param registers non-null; source registers - */ - public VariableSizeInsn(SourcePosition position, - RegisterSpecList registers) { - super(Dops.SPECIAL_FORMAT, position, registers); - } - - /** {@inheritDoc} */ - @Override - public final DalvInsn withOpcode(Dop opcode) { - throw new RuntimeException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - public final DalvInsn withRegisterOffset(int delta) { - return withRegisters(getRegisters().withOffset(delta)); - } -} diff --git a/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java b/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java deleted file mode 100644 index 2ddb181e0..000000000 --- a/dx/src/com/android/dx/dex/code/ZeroSizeInsn.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.android.dx.dex.code; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.util.AnnotatedOutput; - -/** - * Pseudo-instruction base class for zero-size (no code emitted) - * instructions, which are generally used for tracking metainformation - * about the code they are adjacent to. - */ -public abstract class ZeroSizeInsn extends DalvInsn { - /** - * Constructs an instance. The output address of this instance is initially - * unknown (<code>-1</code>). - * - * @param position non-null; source position - */ - public ZeroSizeInsn(SourcePosition position) { - super(Dops.SPECIAL_FORMAT, position, RegisterSpecList.EMPTY); - } - - /** {@inheritDoc} */ - @Override - public final int codeSize() { - return 0; - } - - /** {@inheritDoc} */ - @Override - public final void writeTo(AnnotatedOutput out) { - // Nothing to do here, for this class. - } - - /** {@inheritDoc} */ - @Override - public final DalvInsn withOpcode(Dop opcode) { - throw new RuntimeException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - public DalvInsn withRegisterOffset(int delta) { - return withRegisters(getRegisters().withOffset(delta)); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form10t.java b/dx/src/com/android/dx/dex/code/form/Form10t.java deleted file mode 100644 index 8551012de..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form10t.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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.TargetInsn; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>10t</code>. See the instruction format spec - * for details. - */ -public final class Form10t extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form10t(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form10t() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - return branchString(insn); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - return branchComment(insn); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 1; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - if (!((insn instanceof TargetInsn) && - (insn.getRegisters().size() == 0))) { - return false; - } - - TargetInsn ti = (TargetInsn) insn; - return ti.hasTargetOffset() ? branchFits(ti) : true; - } - - /** {@inheritDoc} */ - @Override - public boolean branchFits(TargetInsn insn) { - int offset = insn.getTargetOffset(); - - // Note: A zero offset would fit, but it is prohibited by the spec. - return (offset != 0) && signedFitsInByte(offset); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form20t.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - int offset = ((TargetInsn) insn).getTargetOffset(); - - write(out, opcodeUnit(insn, (offset & 0xff))); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form10x.java b/dx/src/com/android/dx/dex/code/form/Form10x.java deleted file mode 100644 index 7dc7c43b8..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form10x.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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.SimpleInsn; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>10x</code>. See the instruction format spec - * for details. - */ -public final class Form10x extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form10x(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form10x() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - // This format has no arguments. - return ""; - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - // This format has no comment. - return ""; - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 1; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - return (insn instanceof SimpleInsn) && - (insn.getRegisters().size() == 0); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - write(out, opcodeUnit(insn, 0)); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form11n.java b/dx/src/com/android/dx/dex/code/form/Form11n.java deleted file mode 100644 index b94038bb2..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form11n.java +++ /dev/null @@ -1,104 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>11n</code>. See the instruction format spec - * for details. - */ -public final class Form11n extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form11n(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form11n() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - - return regs.get(0).regString() + ", " + literalBitsString(value); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - return literalBitsComment(value, 4); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 1; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - - if (!((insn instanceof CstInsn) && - (regs.size() == 1) && - unsignedFitsInNibble(regs.get(0).getReg()))) { - return false; - } - - CstInsn ci = (CstInsn) insn; - Constant cst = ci.getConstant(); - - if (!(cst instanceof CstLiteralBits)) { - return false; - } - - CstLiteralBits cb = (CstLiteralBits) cst; - - return cb.fitsInInt() && signedFitsInNibble(cb.getIntBits()); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form21s.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int value = - ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits(); - - write(out, - opcodeUnit(insn, makeByte(regs.get(0).getReg(), value & 0xf))); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form11x.java b/dx/src/com/android/dx/dex/code/form/Form11x.java deleted file mode 100644 index d6561472d..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form11x.java +++ /dev/null @@ -1,82 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.SimpleInsn; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>11x</code>. See the instruction format spec - * for details. - */ -public final class Form11x extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form11x(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form11x() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return regs.get(0).regString(); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - // This format has no comment. - return ""; - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 1; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return (insn instanceof SimpleInsn) && - (regs.size() == 1) && - unsignedFitsInByte(regs.get(0).getReg()); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - write(out, opcodeUnit(insn, regs.get(0).getReg())); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form12x.java b/dx/src/com/android/dx/dex/code/form/Form12x.java deleted file mode 100644 index 3ed8ce99c..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form12x.java +++ /dev/null @@ -1,132 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.HighRegisterPrefix; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.SimpleInsn; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>12x</code>. See the instruction format spec - * for details. - */ -public final class Form12x extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form12x(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form12x() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int sz = regs.size(); - - /* - * The (sz - 2) and (sz - 1) below makes this code work for - * both the two- and three-register ops. (See "case 3" in - * isCompatible(), below.) - */ - - return regs.get(sz - 2).regString() + ", " + - regs.get(sz - 1).regString(); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - // This format has no comment. - return ""; - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 1; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - if (!(insn instanceof SimpleInsn)) { - return false; - } - - RegisterSpecList regs = insn.getRegisters(); - RegisterSpec rs1; - RegisterSpec rs2; - - switch (regs.size()) { - case 2: { - rs1 = regs.get(0); - rs2 = regs.get(1); - break; - } - case 3: { - /* - * This format is allowed for ops that are effectively - * 3-arg but where the first two args are identical. - */ - rs1 = regs.get(1); - rs2 = regs.get(2); - if (rs1.getReg() != regs.get(0).getReg()) { - return false; - } - break; - } - default: { - return false; - } - } - - return unsignedFitsInNibble(rs1.getReg()) && - unsignedFitsInNibble(rs2.getReg()); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form22x.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int sz = regs.size(); - - /* - * The (sz - 2) and (sz - 1) below makes this code work for - * both the two- and three-register ops. (See "case 3" in - * isCompatible(), above.) - */ - - write(out, opcodeUnit(insn, - makeByte(regs.get(sz - 2).getReg(), - regs.get(sz - 1).getReg()))); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form20t.java b/dx/src/com/android/dx/dex/code/form/Form20t.java deleted file mode 100644 index 341bef3a0..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form20t.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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.TargetInsn; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>20t</code>. See the instruction format spec - * for details. - */ -public final class Form20t extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form20t(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form20t() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - return branchString(insn); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - return branchComment(insn); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - if (!((insn instanceof TargetInsn) && - (insn.getRegisters().size() == 0))) { - return false; - } - - TargetInsn ti = (TargetInsn) insn; - return ti.hasTargetOffset() ? branchFits(ti) : true; - } - - /** {@inheritDoc} */ - @Override - public boolean branchFits(TargetInsn insn) { - int offset = insn.getTargetOffset(); - - // Note: A zero offset would fit, but it is prohibited by the spec. - return (offset != 0) && signedFitsInShort(offset); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form30t.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - int offset = ((TargetInsn) insn).getTargetOffset(); - - write(out, opcodeUnit(insn, 0), (short) offset); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form21c.java b/dx/src/com/android/dx/dex/code/form/Form21c.java deleted file mode 100644 index 5695e7a1f..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form21c.java +++ /dev/null @@ -1,133 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>21c</code>. See the instruction format spec - * for details. - */ -public final class Form21c extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form21c(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form21c() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return regs.get(0).regString() + ", " + cstString(insn); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - if (noteIndices) { - return cstComment(insn); - } else { - return ""; - } - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - if (!(insn instanceof CstInsn)) { - return false; - } - - RegisterSpecList regs = insn.getRegisters(); - RegisterSpec reg; - - switch (regs.size()) { - case 1: { - reg = regs.get(0); - break; - } - case 2: { - /* - * This format is allowed for ops that are effectively - * 2-arg but where the two args are identical. - */ - reg = regs.get(0); - if (reg.getReg() != regs.get(1).getReg()) { - return false; - } - break; - } - default: { - return false; - } - } - - if (!unsignedFitsInByte(reg.getReg())) { - return false; - } - - CstInsn ci = (CstInsn) insn; - int cpi = ci.getIndex(); - - if (! unsignedFitsInShort(cpi)) { - return false; - } - - Constant cst = ci.getConstant(); - return (cst instanceof CstType) || - (cst instanceof CstFieldRef) || - (cst instanceof CstString); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form31c.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int cpi = ((CstInsn) insn).getIndex(); - - write(out, - opcodeUnit(insn, regs.get(0).getReg()), - (short) cpi); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form21h.java b/dx/src/com/android/dx/dex/code/form/Form21h.java deleted file mode 100644 index cf4b4714f..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form21h.java +++ /dev/null @@ -1,120 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>21h</code>. See the instruction format spec - * for details. - */ -public final class Form21h extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form21h(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form21h() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - - return regs.get(0).regString() + ", " + literalBitsString(value); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - RegisterSpecList regs = insn.getRegisters(); - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - - return - literalBitsComment(value, - (regs.get(0).getCategory() == 1) ? 32 : 64); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - if (!((insn instanceof CstInsn) && - (regs.size() == 1) && - unsignedFitsInByte(regs.get(0).getReg()))) { - return false; - } - - CstInsn ci = (CstInsn) insn; - Constant cst = ci.getConstant(); - - if (!(cst instanceof CstLiteralBits)) { - return false; - } - - CstLiteralBits cb = (CstLiteralBits) cst; - - // Where the high bits are depends on the category of the target. - if (regs.get(0).getCategory() == 1) { - int bits = cb.getIntBits(); - return ((bits & 0xffff) == 0); - } else { - long bits = cb.getLongBits(); - return ((bits & 0xffffffffffffL) == 0); - } - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form31i.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - CstLiteralBits cb = (CstLiteralBits) ((CstInsn) insn).getConstant(); - short bits; - - // Where the high bits are depends on the category of the target. - if (regs.get(0).getCategory() == 1) { - bits = (short) (cb.getIntBits() >>> 16); - } else { - bits = (short) (cb.getLongBits() >>> 48); - } - - write(out, opcodeUnit(insn, regs.get(0).getReg()), bits); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form21s.java b/dx/src/com/android/dx/dex/code/form/Form21s.java deleted file mode 100644 index df10f80a7..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form21s.java +++ /dev/null @@ -1,104 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>21s</code>. See the instruction format spec - * for details. - */ -public final class Form21s extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form21s(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form21s() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - - return regs.get(0).regString() + ", " + literalBitsString(value); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - return literalBitsComment(value, 16); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - if (!((insn instanceof CstInsn) && - (regs.size() == 1) && - unsignedFitsInByte(regs.get(0).getReg()))) { - return false; - } - - CstInsn ci = (CstInsn) insn; - Constant cst = ci.getConstant(); - - if (!(cst instanceof CstLiteralBits)) { - return false; - } - - CstLiteralBits cb = (CstLiteralBits) cst; - - return cb.fitsInInt() && signedFitsInShort(cb.getIntBits()); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form21h.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int value = - ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits(); - - write(out, - opcodeUnit(insn, regs.get(0).getReg()), - (short) value); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form21t.java b/dx/src/com/android/dx/dex/code/form/Form21t.java deleted file mode 100644 index 03f2ddfbd..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form21t.java +++ /dev/null @@ -1,100 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.TargetInsn; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>21t</code>. See the instruction format spec - * for details. - */ -public final class Form21t extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form21t(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form21t() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return regs.get(0).regString() + ", " + branchString(insn); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - return branchComment(insn); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - - if (!((insn instanceof TargetInsn) && - (regs.size() == 1) && - unsignedFitsInByte(regs.get(0).getReg()))) { - return false; - } - - TargetInsn ti = (TargetInsn) insn; - return ti.hasTargetOffset() ? branchFits(ti) : true; - } - - /** {@inheritDoc} */ - @Override - public boolean branchFits(TargetInsn insn) { - int offset = insn.getTargetOffset(); - - // Note: A zero offset would fit, but it is prohibited by the spec. - return (offset != 0) && signedFitsInShort(offset); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form31t.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int offset = ((TargetInsn) insn).getTargetOffset(); - - write(out, - opcodeUnit(insn, regs.get(0).getReg()), - (short) offset); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form22b.java b/dx/src/com/android/dx/dex/code/form/Form22b.java deleted file mode 100644 index e2a777fcc..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form22b.java +++ /dev/null @@ -1,106 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>22b</code>. See the instruction format spec - * for details. - */ -public final class Form22b extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form22b(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form22b() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - - return regs.get(0).regString() + ", " + regs.get(1).regString() + - ", " + literalBitsString(value); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - return literalBitsComment(value, 8); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - if (!((insn instanceof CstInsn) && - (regs.size() == 2) && - unsignedFitsInByte(regs.get(0).getReg()) && - unsignedFitsInByte(regs.get(1).getReg()))) { - return false; - } - - CstInsn ci = (CstInsn) insn; - Constant cst = ci.getConstant(); - - if (!(cst instanceof CstLiteralBits)) { - return false; - } - - CstLiteralBits cb = (CstLiteralBits) cst; - - return cb.fitsInInt() && signedFitsInByte(cb.getIntBits()); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form22s.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int value = - ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits(); - - write(out, - opcodeUnit(insn, regs.get(0).getReg()), - codeUnit(regs.get(1).getReg(), value & 0xff)); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form22c.java b/dx/src/com/android/dx/dex/code/form/Form22c.java deleted file mode 100644 index 547eea858..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form22c.java +++ /dev/null @@ -1,109 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>22c</code>. See the instruction format spec - * for details. - */ -public final class Form22c extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form22c(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form22c() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return regs.get(0).regString() + ", " + regs.get(1).regString() + - ", " + cstString(insn); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - if (noteIndices) { - return cstComment(insn); - } else { - return ""; - } - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - if (!((insn instanceof CstInsn) && - (regs.size() == 2) && - unsignedFitsInNibble(regs.get(0).getReg()) && - unsignedFitsInNibble(regs.get(1).getReg()))) { - return false; - } - - CstInsn ci = (CstInsn) insn; - int cpi = ci.getIndex(); - - if (! unsignedFitsInShort(cpi)) { - return false; - } - - Constant cst = ci.getConstant(); - return (cst instanceof CstType) || - (cst instanceof CstFieldRef); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int cpi = ((CstInsn) insn).getIndex(); - - write(out, - opcodeUnit(insn, - makeByte(regs.get(0).getReg(), regs.get(1).getReg())), - (short) cpi); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form22s.java b/dx/src/com/android/dx/dex/code/form/Form22s.java deleted file mode 100644 index 3ed173f22..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form22s.java +++ /dev/null @@ -1,107 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>22s</code>. See the instruction format spec - * for details. - */ -public final class Form22s extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form22s(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form22s() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - - return regs.get(0).regString() + ", " + regs.get(1).regString() - + ", " + literalBitsString(value); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - return literalBitsComment(value, 16); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - if (!((insn instanceof CstInsn) && - (regs.size() == 2) && - unsignedFitsInNibble(regs.get(0).getReg()) && - unsignedFitsInNibble(regs.get(1).getReg()))) { - return false; - } - - CstInsn ci = (CstInsn) insn; - Constant cst = ci.getConstant(); - - if (!(cst instanceof CstLiteralBits)) { - return false; - } - - CstLiteralBits cb = (CstLiteralBits) cst; - - return cb.fitsInInt() && signedFitsInShort(cb.getIntBits()); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int value = - ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits(); - - write(out, - opcodeUnit(insn, - makeByte(regs.get(0).getReg(), regs.get(1).getReg())), - (short) value); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form22t.java b/dx/src/com/android/dx/dex/code/form/Form22t.java deleted file mode 100644 index 1034b925c..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form22t.java +++ /dev/null @@ -1,103 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.TargetInsn; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>22t</code>. See the instruction format spec - * for details. - */ -public final class Form22t extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form22t(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form22t() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return regs.get(0).regString() + ", " + regs.get(1).regString() + - ", " + branchString(insn); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - return branchComment(insn); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - - if (!((insn instanceof TargetInsn) && - (regs.size() == 2) && - unsignedFitsInNibble(regs.get(0).getReg()) && - unsignedFitsInNibble(regs.get(1).getReg()))) { - return false; - } - - TargetInsn ti = (TargetInsn) insn; - return ti.hasTargetOffset() ? branchFits(ti) : true; - } - - /** {@inheritDoc} */ - @Override - public boolean branchFits(TargetInsn insn) { - int offset = insn.getTargetOffset(); - - // Note: A zero offset would fit, but it is prohibited by the spec. - return (offset != 0) && signedFitsInShort(offset); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int offset = ((TargetInsn) insn).getTargetOffset(); - - write(out, - opcodeUnit(insn, - makeByte(regs.get(0).getReg(), regs.get(1).getReg())), - (short) offset); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form22x.java b/dx/src/com/android/dx/dex/code/form/Form22x.java deleted file mode 100644 index ee91e85a2..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form22x.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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.SimpleInsn; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>22x</code>. See the instruction format spec - * for details. - */ -public final class Form22x extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form22x(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form22x() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return regs.get(0).regString() + ", " + regs.get(1).regString(); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - // This format has no comment. - return ""; - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - - return (insn instanceof SimpleInsn) && - (regs.size() == 2) && - unsignedFitsInByte(regs.get(0).getReg()) && - unsignedFitsInShort(regs.get(1).getReg()); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form23x.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - write(out, - opcodeUnit(insn, regs.get(0).getReg()), - (short) regs.get(1).getReg()); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form23x.java b/dx/src/com/android/dx/dex/code/form/Form23x.java deleted file mode 100644 index c0a4482e8..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form23x.java +++ /dev/null @@ -1,88 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.SimpleInsn; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>23x</code>. See the instruction format spec - * for details. - */ -public final class Form23x extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form23x(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form23x() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return regs.get(0).regString() + ", " + regs.get(1).regString() + - ", " + regs.get(2).regString(); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - // This format has no comment. - return ""; - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 2; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - - return (insn instanceof SimpleInsn) && - (regs.size() == 3) && - unsignedFitsInByte(regs.get(0).getReg()) && - unsignedFitsInByte(regs.get(1).getReg()) && - unsignedFitsInByte(regs.get(2).getReg()); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form32x.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - write(out, - opcodeUnit(insn, regs.get(0).getReg()), - codeUnit(regs.get(1).getReg(), regs.get(2).getReg())); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form30t.java b/dx/src/com/android/dx/dex/code/form/Form30t.java deleted file mode 100644 index 32e2efa2a..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form30t.java +++ /dev/null @@ -1,90 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.TargetInsn; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>30t</code>. See the instruction format spec - * for details. - */ -public final class Form30t extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form30t(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form30t() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - return branchString(insn); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - return branchComment(insn); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 3; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - if (!((insn instanceof TargetInsn) && - (insn.getRegisters().size() == 0))) { - return false; - } - - return true; - } - - /** {@inheritDoc} */ - @Override - public boolean branchFits(TargetInsn insn) { - return true; - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - int offset = ((TargetInsn) insn).getTargetOffset(); - - write(out, opcodeUnit(insn, 0), - (short) offset, - (short) (offset >> 16)); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form31c.java b/dx/src/com/android/dx/dex/code/form/Form31c.java deleted file mode 100644 index 5837009e5..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form31c.java +++ /dev/null @@ -1,129 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>31c</code>. See the instruction format spec - * for details. - */ -public final class Form31c extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form31c(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form31c() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return regs.get(0).regString() + ", " + cstString(insn); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - if (noteIndices) { - return cstComment(insn); - } else { - return ""; - } - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 3; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - if (!(insn instanceof CstInsn)) { - return false; - } - - RegisterSpecList regs = insn.getRegisters(); - RegisterSpec reg; - - switch (regs.size()) { - case 1: { - reg = regs.get(0); - break; - } - case 2: { - /* - * This format is allowed for ops that are effectively - * 2-arg but where the two args are identical. - */ - reg = regs.get(0); - if (reg.getReg() != regs.get(1).getReg()) { - return false; - } - break; - } - default: { - return false; - } - } - - if (!unsignedFitsInByte(reg.getReg())) { - return false; - } - - CstInsn ci = (CstInsn) insn; - Constant cst = ci.getConstant(); - - return ((cst instanceof CstType) || - (cst instanceof CstFieldRef) || - (cst instanceof CstString)); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int cpi = ((CstInsn) insn).getIndex(); - - write(out, - opcodeUnit(insn, regs.get(0).getReg()), - (short) cpi, - (short) (cpi >> 16)); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form31i.java b/dx/src/com/android/dx/dex/code/form/Form31i.java deleted file mode 100644 index 2855bcb38..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form31i.java +++ /dev/null @@ -1,103 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>31i</code>. See the instruction format spec - * for details. - */ -public final class Form31i extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form31i(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form31i() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - - return regs.get(0).regString() + ", " + literalBitsString(value); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - return literalBitsComment(value, 32); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 3; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - if (!((insn instanceof CstInsn) && - (regs.size() == 1) && - unsignedFitsInByte(regs.get(0).getReg()))) { - return false; - } - - CstInsn ci = (CstInsn) insn; - Constant cst = ci.getConstant(); - - if (!(cst instanceof CstLiteralBits)) { - return false; - } - - return ((CstLiteralBits) cst).fitsInInt(); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form51l.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int value = - ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits(); - - write(out, - opcodeUnit(insn, regs.get(0).getReg()), - (short) value, - (short) (value >> 16)); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form31t.java b/dx/src/com/android/dx/dex/code/form/Form31t.java deleted file mode 100644 index 5472687be..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form31t.java +++ /dev/null @@ -1,96 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.TargetInsn; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>31t</code>. See the instruction format spec - * for details. - */ -public final class Form31t extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form31t(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form31t() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return regs.get(0).regString() + ", " + branchString(insn); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - return branchComment(insn); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 3; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - - if (!((insn instanceof TargetInsn) && - (regs.size() == 1) && - unsignedFitsInByte(regs.get(0).getReg()))) { - return false; - } - - return true; - } - - /** {@inheritDoc} */ - @Override - public boolean branchFits(TargetInsn insn) { - return true; - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int offset = ((TargetInsn) insn).getTargetOffset(); - - write(out, opcodeUnit(insn, regs.get(0).getReg()), - (short) offset, - (short) (offset >> 16)); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form32x.java b/dx/src/com/android/dx/dex/code/form/Form32x.java deleted file mode 100644 index 9c52d9334..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form32x.java +++ /dev/null @@ -1,87 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.dex.code.SimpleInsn; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>32x</code>. See the instruction format spec - * for details. - */ -public final class Form32x extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form32x(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form32x() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return regs.get(0).regString() + ", " + regs.get(1).regString(); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - // This format has no comment. - return ""; - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 3; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - return (insn instanceof SimpleInsn) && - (regs.size() == 2) && - unsignedFitsInShort(regs.get(0).getReg()) && - unsignedFitsInShort(regs.get(1).getReg()); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - - write(out, - opcodeUnit(insn, 0), - (short) regs.get(0).getReg(), - (short) regs.get(1).getReg()); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form35c.java b/dx/src/com/android/dx/dex/code/form/Form35c.java deleted file mode 100644 index 6be55fc5c..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form35c.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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>35c</code>. See the instruction format spec - * for details. - */ -public final class Form35c extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form35c(); - - /** Maximal number of operands */ - private static final int MAX_NUM_OPS = 5; - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form35c() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = explicitize(insn.getRegisters()); - return regListString(regs) + ", " + cstString(insn); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - if (noteIndices) { - return cstComment(insn); - } else { - return ""; - } - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 3; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - if (!(insn instanceof CstInsn)) { - return false; - } - - CstInsn ci = (CstInsn) insn; - int cpi = ci.getIndex(); - - if (! unsignedFitsInShort(cpi)) { - return false; - } - - Constant cst = ci.getConstant(); - if (!((cst instanceof CstMethodRef) || - (cst instanceof CstType))) { - return false; - } - - RegisterSpecList regs = ci.getRegisters(); - return (wordCount(regs) >= 0); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return Form3rc.THE_ONE; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - int cpi = ((CstInsn) insn).getIndex(); - RegisterSpecList regs = explicitize(insn.getRegisters()); - int sz = regs.size(); - int r0 = (sz > 0) ? regs.get(0).getReg() : 0; - int r1 = (sz > 1) ? regs.get(1).getReg() : 0; - int r2 = (sz > 2) ? regs.get(2).getReg() : 0; - int r3 = (sz > 3) ? regs.get(3).getReg() : 0; - int r4 = (sz > 4) ? regs.get(4).getReg() : 0; - - write(out, - opcodeUnit(insn, - makeByte(r4, sz)), // encode the fifth operand here - (short) cpi, - codeUnit(r0, r1, r2, r3)); - } - - /** - * Gets the number of words required for the given register list, where - * category-2 values count as two words. Return <code>-1</code> if the - * list requires more than five words or contains registers that need - * more than a nibble to identify them. - * - * @param regs non-null; the register list in question - * @return >= -1; the number of words required, or <code>-1</code> - * if the list couldn't possibly fit in this format - */ - private static int wordCount(RegisterSpecList regs) { - int sz = regs.size(); - - if (sz > MAX_NUM_OPS) { - // It can't possibly fit. - return -1; - } - - int result = 0; - - for (int i = 0; i < sz; i++) { - RegisterSpec one = regs.get(i); - result += one.getCategory(); - /* - * The check below adds (category - 1) to the register, to - * account for the fact that the second half of a - * category-2 register has to be represented explicitly in - * the result. - */ - if (!unsignedFitsInNibble(one.getReg() + one.getCategory() - 1)) { - return -1; - } - } - - return (result <= MAX_NUM_OPS) ? result : -1; - } - - /** - * Returns a register list which is equivalent to the given one, - * except that it splits category-2 registers into two explicit - * entries. This returns the original list if no modification is - * required - * - * @param orig non-null; the original list - * @return non-null; the list with the described transformation - */ - private static RegisterSpecList explicitize(RegisterSpecList orig) { - int wordCount = wordCount(orig); - int sz = orig.size(); - - if (wordCount == sz) { - return orig; - } - - RegisterSpecList result = new RegisterSpecList(wordCount); - int wordAt = 0; - - for (int i = 0; i < sz; i++) { - RegisterSpec one = orig.get(i); - result.set(wordAt, one); - if (one.getCategory() == 2) { - result.set(wordAt + 1, - RegisterSpec.make(one.getReg() + 1, Type.VOID)); - wordAt += 2; - } else { - wordAt++; - } - } - - result.setImmutable(); - return result; - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form3rc.java b/dx/src/com/android/dx/dex/code/form/Form3rc.java deleted file mode 100644 index 0accbc226..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form3rc.java +++ /dev/null @@ -1,175 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>3rc</code>. See the instruction format spec - * for details. - */ -public final class Form3rc extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form3rc(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form3rc() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int size = regs.size(); - StringBuilder sb = new StringBuilder(30); - - sb.append("{"); - - switch (size) { - case 0: { - // Nothing to do. - break; - } - case 1: { - sb.append(regs.get(0).regString()); - break; - } - default: { - RegisterSpec lastReg = regs.get(size - 1); - if (lastReg.getCategory() == 2) { - /* - * Add one to properly represent a list-final - * category-2 register. - */ - lastReg = lastReg.withOffset(1); - } - - sb.append(regs.get(0).regString()); - sb.append(".."); - sb.append(lastReg.regString()); - } - } - - sb.append("}, "); - sb.append(cstString(insn)); - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - if (noteIndices) { - return cstComment(insn); - } else { - return ""; - } - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 3; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - if (!(insn instanceof CstInsn)) { - return false; - } - - CstInsn ci = (CstInsn) insn; - int cpi = ci.getIndex(); - - if (! unsignedFitsInShort(cpi)) { - return false; - } - - Constant cst = ci.getConstant(); - if (!((cst instanceof CstMethodRef) || - (cst instanceof CstType))) { - return false; - } - - RegisterSpecList regs = ci.getRegisters(); - int sz = regs.size(); - - if (sz == 0) { - return true; - } - - int first = regs.get(0).getReg(); - int next = first; - - if (!unsignedFitsInShort(first)) { - return false; - } - - for (int i = 0; i < sz; i++) { - RegisterSpec one = regs.get(i); - if (one.getReg() != next) { - return false; - } - next += one.getCategory(); - } - - return unsignedFitsInByte(next - first); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - int sz = regs.size(); - int cpi = ((CstInsn) insn).getIndex(); - int firstReg; - int count; - - if (sz == 0) { - firstReg = 0; - count = 0; - } else { - int lastReg = regs.get(sz - 1).getNextReg(); - firstReg = regs.get(0).getReg(); - count = lastReg - firstReg; - } - - write(out, - opcodeUnit(insn, count), - (short) cpi, - (short) firstReg); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/Form51l.java b/dx/src/com/android/dx/dex/code/form/Form51l.java deleted file mode 100644 index 09a32f619..000000000 --- a/dx/src/com/android/dx/dex/code/form/Form51l.java +++ /dev/null @@ -1,102 +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.android.dx.dex.code.form; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstLiteral64; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format <code>51l</code>. See the instruction format spec - * for details. - */ -public final class Form51l extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new Form51l(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private Form51l() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - - return regs.get(0).regString() + ", " + literalBitsString(value); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant(); - return literalBitsComment(value, 64); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - return 5; - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - if (!((insn instanceof CstInsn) && - (regs.size() == 1) && - unsignedFitsInByte(regs.get(0).getReg()))) { - return false; - } - - CstInsn ci = (CstInsn) insn; - Constant cst = ci.getConstant(); - - return (cst instanceof CstLiteral64); - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - return null; - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - RegisterSpecList regs = insn.getRegisters(); - long value = - ((CstLiteral64) ((CstInsn) insn).getConstant()).getLongBits(); - - write(out, - opcodeUnit(insn, regs.get(0).getReg()), - (short) value, - (short) (value >> 16), - (short) (value >> 32), - (short) (value >> 48)); - } -} diff --git a/dx/src/com/android/dx/dex/code/form/SpecialFormat.java b/dx/src/com/android/dx/dex/code/form/SpecialFormat.java deleted file mode 100644 index 79efd670b..000000000 --- a/dx/src/com/android/dx/dex/code/form/SpecialFormat.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.android.dx.dex.code.form; - -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.DalvOps; -import com.android.dx.dex.code.InsnFormat; -import com.android.dx.util.AnnotatedOutput; - -/** - * Instruction format for nonstandard format instructions, which aren't - * generally real instructions but do end up appearing in instruction - * lists. Most of the overridden methods on this class end up throwing - * exceptions, as code should know (implicitly or explicitly) to avoid - * using this class. The one exception is {@link #isCompatible}, which - * always returns <code>true</code>. - */ -public final class SpecialFormat extends InsnFormat { - /** non-null; unique instance of this class */ - public static final InsnFormat THE_ONE = new SpecialFormat(); - - /** - * Constructs an instance. This class is not publicly - * instantiable. Use {@link #THE_ONE}. - */ - private SpecialFormat() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public String insnArgString(DalvInsn insn) { - throw new RuntimeException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - public String insnCommentString(DalvInsn insn, boolean noteIndices) { - throw new RuntimeException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - public int codeSize() { - throw new RuntimeException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - public boolean isCompatible(DalvInsn insn) { - return true; - } - - /** {@inheritDoc} */ - @Override - public InsnFormat nextUp() { - throw new RuntimeException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - public void writeTo(AnnotatedOutput out, DalvInsn insn) { - throw new RuntimeException("unsupported"); - } -} diff --git a/dx/src/com/android/dx/dex/file/AnnotationItem.java b/dx/src/com/android/dx/dex/file/AnnotationItem.java deleted file mode 100644 index 43ac36266..000000000 --- a/dx/src/com/android/dx/dex/file/AnnotationItem.java +++ /dev/null @@ -1,220 +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.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.AnnotationVisibility; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.AnnotatedOutput; - -import java.util.Arrays; -import java.util.Comparator; - -/** - * Single annotation, which consists of a type and a set of name-value - * element pairs. - */ -public final class AnnotationItem extends OffsettedItem { - /** annotation visibility constant: visible at build time only */ - private static final int VISIBILITY_BUILD = 0; - - /** annotation visibility constant: visible at runtime */ - private static final int VISIBILITY_RUNTIME = 1; - - /** annotation visibility constant: visible at runtime only to system */ - private static final int VISIBILITY_SYSTEM = 2; - - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 1; - - /** non-null; unique instance of {@link #TypeIdSorter} */ - private static final TypeIdSorter TYPE_ID_SORTER = new TypeIdSorter(); - - /** non-null; the annotation to represent */ - private final Annotation annotation; - - /** - * null-ok; type reference for the annotation type; set during - * {@link #addContents} - */ - private TypeIdItem type; - - /** - * null-ok; encoded form, ready for writing to a file; set during - * {@link #place0} - */ - private byte[] encodedForm; - - /** - * Comparator that sorts (outer) instances by type id index. - */ - private static class TypeIdSorter implements Comparator<AnnotationItem> { - /** {@inheritDoc} */ - public int compare(AnnotationItem item1, AnnotationItem item2) { - int index1 = item1.type.getIndex(); - int index2 = item2.type.getIndex(); - - if (index1 < index2) { - return -1; - } else if (index1 > index2) { - return 1; - } - - return 0; - } - } - - /** - * Sorts an array of instances, in place, by type id index, - * ignoring all other aspects of the elements. This is only valid - * to use after type id indices are known. - * - * @param array non-null; array to sort - */ - public static void sortByTypeIdIndex(AnnotationItem[] array) { - Arrays.sort(array, TYPE_ID_SORTER); - } - - /** - * Constructs an instance. - * - * @param annotation non-null; annotation to represent - */ - public AnnotationItem(Annotation annotation) { - /* - * The write size isn't known up-front because (the variable-lengthed) - * leb128 type is used to represent some things. - */ - super(ALIGNMENT, -1); - - if (annotation == null) { - throw new NullPointerException("annotation == null"); - } - - this.annotation = annotation; - this.type = null; - this.encodedForm = null; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_ANNOTATION_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return annotation.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(OffsettedItem other) { - AnnotationItem otherAnnotation = (AnnotationItem) other; - - return annotation.compareTo(otherAnnotation.annotation); - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return annotation.toHuman(); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - type = file.getTypeIds().intern(annotation.getType()); - ValueEncoder.addContents(file, annotation); - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // Encode the data and note the size. - - ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(); - ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out); - - encoder.writeAnnotation(annotation, false); - encodedForm = out.toByteArray(); - - // Add one for the visibility byte in front of the encoded annotation. - setWriteSize(encodedForm.length + 1); - } - - /** - * Write a (listing file) annotation for this instance to the given - * output, that consumes no bytes of output. This is for annotating - * a reference to this instance at the point of the reference. - * - * @param out non-null; where to output to - * @param prefix non-null; prefix for each line of output - */ - public void annotateTo(AnnotatedOutput out, String prefix) { - out.annotate(0, prefix + "visibility: " + - annotation.getVisibility().toHuman()); - out.annotate(0, prefix + "type: " + annotation.getType().toHuman()); - - for (NameValuePair pair : annotation.getNameValuePairs()) { - CstUtf8 name = pair.getName(); - Constant value = pair.getValue(); - - out.annotate(0, prefix + name.toHuman() + ": " + - ValueEncoder.constantToHuman(value)); - } - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - AnnotationVisibility visibility = annotation.getVisibility(); - - if (annotates) { - out.annotate(0, offsetString() + " annotation"); - out.annotate(1, " visibility: VISBILITY_" + visibility); - } - - switch (visibility) { - case BUILD: out.writeByte(VISIBILITY_BUILD); break; - case RUNTIME: out.writeByte(VISIBILITY_RUNTIME); break; - case SYSTEM: out.writeByte(VISIBILITY_SYSTEM); break; - default: { - // EMBEDDED shouldn't appear at the top level. - throw new RuntimeException("shouldn't happen"); - } - } - - if (annotates) { - /* - * The output is to be annotated, so redo the work previously - * done by place0(), except this time annotations will actually - * get emitted. - */ - ValueEncoder encoder = new ValueEncoder(file, out); - encoder.writeAnnotation(annotation, true); - } else { - out.write(encodedForm); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/AnnotationSetItem.java b/dx/src/com/android/dx/dex/file/AnnotationSetItem.java deleted file mode 100644 index f03cc08d1..000000000 --- a/dx/src/com/android/dx/dex/file/AnnotationSetItem.java +++ /dev/null @@ -1,157 +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.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Set of annotations, where no annotation type appears more than once. - */ -public final class AnnotationSetItem extends OffsettedItem { - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 4; - - /** the size of an entry int the set: one <code>uint</code> */ - private static final int ENTRY_WRITE_SIZE = 4; - - /** non-null; the set of annotations */ - private final Annotations annotations; - - /** - * non-null; set of annotations as individual items in an array. - * <b>Note:</b> The contents have to get sorted by type id before - * writing. - */ - private final AnnotationItem[] items; - - /** - * Constructs an instance. - * - * @param annotations non-null; set of annotations - */ - public AnnotationSetItem(Annotations annotations) { - super(ALIGNMENT, writeSize(annotations)); - - this.annotations = annotations; - this.items = new AnnotationItem[annotations.size()]; - - int at = 0; - for (Annotation a : annotations.getAnnotations()) { - items[at] = new AnnotationItem(a); - at++; - } - } - - /** - * Gets the write size for the given set. - * - * @param annotations non-null; the set - * @return > 0; the write size - */ - private static int writeSize(Annotations annotations) { - // This includes an int size at the start of the list. - - try { - return (annotations.size() * ENTRY_WRITE_SIZE) + 4; - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("list == null"); - } - } - - /** - * Gets the underlying annotations of this instance - * - * @return non-null; the annotations - */ - public Annotations getAnnotations() { - return annotations; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return annotations.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(OffsettedItem other) { - AnnotationSetItem otherSet = (AnnotationSetItem) other; - - return annotations.compareTo(otherSet.annotations); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_ANNOTATION_SET_ITEM; - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return annotations.toString(); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MixedItemSection byteData = file.getByteData(); - int size = items.length; - - for (int i = 0; i < size; i++) { - items[i] = byteData.intern(items[i]); - } - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // Sort the array to be in type id index order. - AnnotationItem.sortByTypeIdIndex(items); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - int size = items.length; - - if (annotates) { - out.annotate(0, offsetString() + " annotation set"); - out.annotate(4, " size: " + Hex.u4(size)); - } - - out.writeInt(size); - - for (int i = 0; i < size; i++) { - AnnotationItem item = items[i]; - int offset = item.getAbsoluteOffset(); - - if (annotates) { - out.annotate(4, " entries[" + Integer.toHexString(i) + "]: " + - Hex.u4(offset)); - items[i].annotateTo(out, " "); - } - - out.writeInt(offset); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java b/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java deleted file mode 100644 index 422e2f019..000000000 --- a/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java +++ /dev/null @@ -1,80 +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.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Indirect reference to an {@link AnnotationSetItem}. - */ -public final class AnnotationSetRefItem extends OffsettedItem { - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 4; - - /** write size of this class, in bytes */ - private static final int WRITE_SIZE = 4; - - /** non-null; the annotation set to refer to */ - private AnnotationSetItem annotations; - - /** - * Constructs an instance. - * - * @param annotations non-null; the annotation set to refer to - */ - public AnnotationSetRefItem(AnnotationSetItem annotations) { - super(ALIGNMENT, WRITE_SIZE); - - if (annotations == null) { - throw new NullPointerException("annotations == null"); - } - - this.annotations = annotations; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_ANNOTATION_SET_REF_ITEM; - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MixedItemSection wordData = file.getWordData(); - - annotations = wordData.intern(annotations); - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return annotations.toHuman(); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - int annotationsOff = annotations.getAbsoluteOffset(); - - if (out.annotates()) { - out.annotate(4, " annotations_off: " + Hex.u4(annotationsOff)); - } - - out.writeInt(annotationsOff); - } -} diff --git a/dx/src/com/android/dx/dex/file/AnnotationUtils.java b/dx/src/com/android/dx/dex/file/AnnotationUtils.java deleted file mode 100644 index c9d796843..000000000 --- a/dx/src/com/android/dx/dex/file/AnnotationUtils.java +++ /dev/null @@ -1,254 +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.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstKnownNull; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; - -import java.util.ArrayList; - -import static com.android.dx.rop.annotation.AnnotationVisibility.*; - -/** - * Utility class for dealing with annotations. - */ -public final class AnnotationUtils { - /** non-null; type for <code>AnnotationDefault</code> annotations */ - private static final CstType ANNOTATION_DEFAULT_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;")); - - /** non-null; type for <code>EnclosingClass</code> annotations */ - private static final CstType ENCLOSING_CLASS_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;")); - - /** non-null; type for <code>EnclosingMethod</code> annotations */ - private static final CstType ENCLOSING_METHOD_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;")); - - /** non-null; type for <code>InnerClass</code> annotations */ - private static final CstType INNER_CLASS_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;")); - - /** non-null; type for <code>MemberClasses</code> annotations */ - private static final CstType MEMBER_CLASSES_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;")); - - /** non-null; type for <code>Signature</code> annotations */ - private static final CstType SIGNATURE_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/Signature;")); - - /** non-null; type for <code>Throws</code> annotations */ - private static final CstType THROWS_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/Throws;")); - - /** non-null; the UTF-8 constant <code>"accessFlags"</code> */ - private static final CstUtf8 ACCESS_FLAGS_UTF = new CstUtf8("accessFlags"); - - /** non-null; the UTF-8 constant <code>"name"</code> */ - private static final CstUtf8 NAME_UTF = new CstUtf8("name"); - - /** non-null; the UTF-8 constant <code>"value"</code> */ - private static final CstUtf8 VALUE_UTF = new CstUtf8("value"); - - /** - * This class is uninstantiable. - */ - private AnnotationUtils() { - // This space intentionally left blank. - } - - /** - * Constructs a standard <code>AnnotationDefault</code> annotation. - * - * @param defaults non-null; the defaults, itself as an annotation - * @return non-null; the constructed annotation - */ - public static Annotation makeAnnotationDefault(Annotation defaults) { - Annotation result = new Annotation(ANNOTATION_DEFAULT_TYPE, SYSTEM); - - result.put(new NameValuePair(VALUE_UTF, new CstAnnotation(defaults))); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>EnclosingClass</code> annotation. - * - * @param clazz non-null; the enclosing class - * @return non-null; the annotation - */ - public static Annotation makeEnclosingClass(CstType clazz) { - Annotation result = new Annotation(ENCLOSING_CLASS_TYPE, SYSTEM); - - result.put(new NameValuePair(VALUE_UTF, clazz)); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>EnclosingMethod</code> annotation. - * - * @param method non-null; the enclosing method - * @return non-null; the annotation - */ - public static Annotation makeEnclosingMethod(CstMethodRef method) { - Annotation result = new Annotation(ENCLOSING_METHOD_TYPE, SYSTEM); - - result.put(new NameValuePair(VALUE_UTF, method)); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>InnerClass</code> annotation. - * - * @param name null-ok; the original name of the class, or - * <code>null</code> to represent an anonymous class - * @param accessFlags the original access flags - * @return non-null; the annotation - */ - public static Annotation makeInnerClass(CstUtf8 name, int accessFlags) { - Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM); - Constant nameCst = - (name != null) ? new CstString(name) : CstKnownNull.THE_ONE; - - result.put(new NameValuePair(NAME_UTF, nameCst)); - result.put(new NameValuePair(ACCESS_FLAGS_UTF, - CstInteger.make(accessFlags))); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>MemberClasses</code> annotation. - * - * @param types non-null; the list of (the types of) the member classes - * @return non-null; the annotation - */ - public static Annotation makeMemberClasses(TypeList types) { - CstArray array = makeCstArray(types); - Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM); - result.put(new NameValuePair(VALUE_UTF, array)); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>Signature</code> annotation. - * - * @param signature non-null; the signature string - * @return non-null; the annotation - */ - public static Annotation makeSignature(CstUtf8 signature) { - Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM); - - /* - * Split the string into pieces that are likely to be common - * across many signatures and the rest of the file. - */ - - String raw = signature.getString(); - int rawLength = raw.length(); - ArrayList<String> pieces = new ArrayList<String>(20); - - for (int at = 0; at < rawLength; /*at*/) { - char c = raw.charAt(at); - int endAt = at + 1; - if (c == 'L') { - // Scan to ';' or '<'. Consume ';' but not '<'. - while (endAt < rawLength) { - c = raw.charAt(endAt); - if (c == ';') { - endAt++; - break; - } else if (c == '<') { - break; - } - endAt++; - } - } else { - // Scan to 'L' without consuming it. - while (endAt < rawLength) { - c = raw.charAt(endAt); - if (c == 'L') { - break; - } - endAt++; - } - } - - pieces.add(raw.substring(at, endAt)); - at = endAt; - } - - int size = pieces.size(); - CstArray.List list = new CstArray.List(size); - - for (int i = 0; i < size; i++) { - list.set(i, new CstString(pieces.get(i))); - } - - list.setImmutable(); - - result.put(new NameValuePair(VALUE_UTF, new CstArray(list))); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>Throws</code> annotation. - * - * @param types non-null; the list of thrown types - * @return non-null; the annotation - */ - public static Annotation makeThrows(TypeList types) { - CstArray array = makeCstArray(types); - Annotation result = new Annotation(THROWS_TYPE, SYSTEM); - result.put(new NameValuePair(VALUE_UTF, array)); - result.setImmutable(); - return result; - } - - /** - * Converts a {@link TypeList} to a {@link CstArray}. - * - * @param types non-null; the type list - * @return non-null; the corresponding array constant - */ - private static CstArray makeCstArray(TypeList types) { - int size = types.size(); - CstArray.List list = new CstArray.List(size); - - for (int i = 0; i < size; i++) { - list.set(i, CstType.intern(types.getType(i))); - } - - list.setImmutable(); - return new CstArray(list); - } -} diff --git a/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java b/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java deleted file mode 100644 index 4521e4c5b..000000000 --- a/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java +++ /dev/null @@ -1,385 +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.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; - -/** - * Per-class directory of annotations. - */ -public final class AnnotationsDirectoryItem extends OffsettedItem { - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 4; - - /** write size of this class's header, in bytes */ - private static final int HEADER_SIZE = 16; - - /** write size of a list element, in bytes */ - private static final int ELEMENT_SIZE = 8; - - /** null-ok; the class-level annotations, if any */ - private AnnotationSetItem classAnnotations; - - /** null-ok; the annotated fields, if any */ - private ArrayList<FieldAnnotationStruct> fieldAnnotations; - - /** null-ok; the annotated methods, if any */ - private ArrayList<MethodAnnotationStruct> methodAnnotations; - - /** null-ok; the annotated parameters, if any */ - private ArrayList<ParameterAnnotationStruct> parameterAnnotations; - - /** - * Constructs an empty instance. - */ - public AnnotationsDirectoryItem() { - super(ALIGNMENT, -1); - - classAnnotations = null; - fieldAnnotations = null; - methodAnnotations = null; - parameterAnnotations = null; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM; - } - - /** - * Returns whether this item is empty (has no contents). - * - * @return <code>true</code> if this item is empty, or <code>false</code> - * if not - */ - public boolean isEmpty() { - return (classAnnotations == null) && - (fieldAnnotations == null) && - (methodAnnotations == null) && - (parameterAnnotations == null); - } - - /** - * Returns whether this item is a candidate for interning. The only - * interning candidates are ones that <i>only</i> have a non-null - * set of class annotations, with no other lists. - * - * @return <code>true</code> if this is an interning candidate, or - * <code>false</code> if not - */ - public boolean isInternable() { - return (classAnnotations != null) && - (fieldAnnotations == null) && - (methodAnnotations == null) && - (parameterAnnotations == null); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - if (classAnnotations == null) { - return 0; - } - - return classAnnotations.hashCode(); - } - - /** - * {@inheritDoc} - * - * <p><b>Note:</b>: This throws an exception if this item is not - * internable.</p> - * - * @see #isInternable - */ - @Override - public int compareTo0(OffsettedItem other) { - if (! isInternable()) { - throw new UnsupportedOperationException("uninternable instance"); - } - - AnnotationsDirectoryItem otherDirectory = - (AnnotationsDirectoryItem) other; - return classAnnotations.compareTo(otherDirectory.classAnnotations); - } - - /** - * Sets the direct annotations on this instance. These are annotations - * made on the class, per se, as opposed to on one of its members. - * It is only valid to call this method at most once per instance. - * - * @param annotations non-null; annotations to set for this class - */ - public void setClassAnnotations(Annotations annotations) { - if (annotations == null) { - throw new NullPointerException("annotations == null"); - } - - if (classAnnotations != null) { - throw new UnsupportedOperationException( - "class annotations already set"); - } - - classAnnotations = new AnnotationSetItem(annotations); - } - - /** - * Adds a field annotations item to this instance. - * - * @param field non-null; field in question - * @param annotations non-null; associated annotations to add - */ - public void addFieldAnnotations(CstFieldRef field, - Annotations annotations) { - if (fieldAnnotations == null) { - fieldAnnotations = new ArrayList<FieldAnnotationStruct>(); - } - - fieldAnnotations.add(new FieldAnnotationStruct(field, - new AnnotationSetItem(annotations))); - } - - /** - * Adds a method annotations item to this instance. - * - * @param method non-null; method in question - * @param annotations non-null; associated annotations to add - */ - public void addMethodAnnotations(CstMethodRef method, - Annotations annotations) { - if (methodAnnotations == null) { - methodAnnotations = new ArrayList<MethodAnnotationStruct>(); - } - - methodAnnotations.add(new MethodAnnotationStruct(method, - new AnnotationSetItem(annotations))); - } - - /** - * Adds a parameter annotations item to this instance. - * - * @param method non-null; method in question - * @param list non-null; associated list of annotation sets to add - */ - public void addParameterAnnotations(CstMethodRef method, - AnnotationsList list) { - if (parameterAnnotations == null) { - parameterAnnotations = new ArrayList<ParameterAnnotationStruct>(); - } - - parameterAnnotations.add(new ParameterAnnotationStruct(method, list)); - } - - /** - * Gets the method annotations for a given method, if any. This is - * meant for use by debugging / dumping code. - * - * @param method non-null; the method - * @return null-ok; the method annotations, if any - */ - public Annotations getMethodAnnotations(CstMethodRef method) { - if (methodAnnotations == null) { - return null; - } - - for (MethodAnnotationStruct item : methodAnnotations) { - if (item.getMethod().equals(method)) { - return item.getAnnotations(); - } - } - - return null; - } - - /** - * Gets the parameter annotations for a given method, if any. This is - * meant for use by debugging / dumping code. - * - * @param method non-null; the method - * @return null-ok; the parameter annotations, if any - */ - public AnnotationsList getParameterAnnotations(CstMethodRef method) { - if (parameterAnnotations == null) { - return null; - } - - for (ParameterAnnotationStruct item : parameterAnnotations) { - if (item.getMethod().equals(method)) { - return item.getAnnotationsList(); - } - } - - return null; - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MixedItemSection wordData = file.getWordData(); - - if (classAnnotations != null) { - classAnnotations = wordData.intern(classAnnotations); - } - - if (fieldAnnotations != null) { - for (FieldAnnotationStruct item : fieldAnnotations) { - item.addContents(file); - } - } - - if (methodAnnotations != null) { - for (MethodAnnotationStruct item : methodAnnotations) { - item.addContents(file); - } - } - - if (parameterAnnotations != null) { - for (ParameterAnnotationStruct item : parameterAnnotations) { - item.addContents(file); - } - } - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - throw new RuntimeException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // We just need to set the write size here. - - int elementCount = listSize(fieldAnnotations) - + listSize(methodAnnotations) + listSize(parameterAnnotations); - setWriteSize(HEADER_SIZE + (elementCount * ELEMENT_SIZE)); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - int classOff = OffsettedItem.getAbsoluteOffsetOr0(classAnnotations); - int fieldsSize = listSize(fieldAnnotations); - int methodsSize = listSize(methodAnnotations); - int parametersSize = listSize(parameterAnnotations); - - if (annotates) { - out.annotate(0, offsetString() + " annotations directory"); - out.annotate(4, " class_annotations_off: " + Hex.u4(classOff)); - out.annotate(4, " fields_size: " + - Hex.u4(fieldsSize)); - out.annotate(4, " methods_size: " + - Hex.u4(methodsSize)); - out.annotate(4, " parameters_size: " + - Hex.u4(parametersSize)); - } - - out.writeInt(classOff); - out.writeInt(fieldsSize); - out.writeInt(methodsSize); - out.writeInt(parametersSize); - - if (fieldsSize != 0) { - Collections.sort(fieldAnnotations); - if (annotates) { - out.annotate(0, " fields:"); - } - for (FieldAnnotationStruct item : fieldAnnotations) { - item.writeTo(file, out); - } - } - - if (methodsSize != 0) { - Collections.sort(methodAnnotations); - if (annotates) { - out.annotate(0, " methods:"); - } - for (MethodAnnotationStruct item : methodAnnotations) { - item.writeTo(file, out); - } - } - - if (parametersSize != 0) { - Collections.sort(parameterAnnotations); - if (annotates) { - out.annotate(0, " parameters:"); - } - for (ParameterAnnotationStruct item : parameterAnnotations) { - item.writeTo(file, out); - } - } - } - - /** - * Gets the list size of the given list, or <code>0</code> if given - * <code>null</code>. - * - * @param list null-ok; the list in question - * @return >= 0; its size - */ - private static int listSize(ArrayList<?> list) { - if (list == null) { - return 0; - } - - return list.size(); - } - - /** - * Prints out the contents of this instance, in a debugging-friendly - * way. This is meant to be called from {@link ClassDefItem#debugPrint}. - * - * @param out non-null; where to output to - */ - /*package*/ void debugPrint(PrintWriter out) { - if (classAnnotations != null) { - out.println(" class annotations: " + classAnnotations); - } - - if (fieldAnnotations != null) { - out.println(" field annotations:"); - for (FieldAnnotationStruct item : fieldAnnotations) { - out.println(" " + item.toHuman()); - } - } - - if (methodAnnotations != null) { - out.println(" method annotations:"); - for (MethodAnnotationStruct item : methodAnnotations) { - out.println(" " + item.toHuman()); - } - } - - if (parameterAnnotations != null) { - out.println(" parameter annotations:"); - for (ParameterAnnotationStruct item : parameterAnnotations) { - out.println(" " + item.toHuman()); - } - } - } -} diff --git a/dx/src/com/android/dx/dex/file/CatchStructs.java b/dx/src/com/android/dx/dex/file/CatchStructs.java deleted file mode 100644 index b7abc3f53..000000000 --- a/dx/src/com/android/dx/dex/file/CatchStructs.java +++ /dev/null @@ -1,320 +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.android.dx.dex.file; - -import com.android.dx.dex.code.CatchHandlerList; -import com.android.dx.dex.code.CatchTable; -import com.android.dx.dex.code.DalvCode; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.Hex; - -import java.io.PrintWriter; -import java.util.Map; -import java.util.TreeMap; - -/** - * List of exception handlers (tuples of covered range, catch type, - * handler address) for a particular piece of code. Instances of this - * class correspond to a <code>try_item[]</code> and a - * <code>catch_handler_item[]</code>. - */ -public final class CatchStructs { - /** - * the size of a <code>try_item</code>: a <code>uint</code> - * and two <code>ushort</code>s - */ - private static final int TRY_ITEM_WRITE_SIZE = 4 + (2 * 2); - - /** non-null; code that contains the catches */ - private final DalvCode code; - - /** - * null-ok; the underlying table; set in - * {@link #finishProcessingIfNecessary} - */ - private CatchTable table; - - /** - * null-ok; the encoded handler list, if calculated; set in - * {@link #encode} - */ - private byte[] encodedHandlers; - - /** - * length of the handlers header (encoded size), if known; used for - * annotation - */ - private int encodedHandlerHeaderSize; - - /** - * null-ok; map from handler lists to byte offsets, if calculated; set in - * {@link #encode} - */ - private TreeMap<CatchHandlerList, Integer> handlerOffsets; - - /** - * Constructs an instance. - * - * @param code non-null; code that contains the catches - */ - public CatchStructs(DalvCode code) { - this.code = code; - this.table = null; - this.encodedHandlers = null; - this.encodedHandlerHeaderSize = 0; - this.handlerOffsets = null; - } - - /** - * Finish processing the catches, if necessary. - */ - private void finishProcessingIfNecessary() { - if (table == null) { - table = code.getCatches(); - } - } - - /** - * Gets the size of the tries list, in entries. - * - * @return >= 0; the tries list size - */ - public int triesSize() { - finishProcessingIfNecessary(); - return table.size(); - } - - /** - * Does a human-friendly dump of this instance. - * - * @param out non-null; where to dump - * @param prefix non-null; prefix to attach to each line of output - */ - public void debugPrint(PrintWriter out, String prefix) { - annotateEntries(prefix, out, null); - } - - /** - * Encodes the handler lists. - * - * @param file non-null; file this instance is part of - */ - public void encode(DexFile file) { - finishProcessingIfNecessary(); - - TypeIdsSection typeIds = file.getTypeIds(); - int size = table.size(); - - handlerOffsets = new TreeMap<CatchHandlerList, Integer>(); - - /* - * First add a map entry for each unique list. The tree structure - * will ensure they are sorted when we reiterate later. - */ - for (int i = 0; i < size; i++) { - handlerOffsets.put(table.get(i).getHandlers(), null); - } - - if (handlerOffsets.size() > 65535) { - throw new UnsupportedOperationException( - "too many catch handlers"); - } - - ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(); - - // Write out the handlers "header" consisting of its size in entries. - encodedHandlerHeaderSize = - out.writeUnsignedLeb128(handlerOffsets.size()); - - // Now write the lists out in order, noting the offset of each. - for (Map.Entry<CatchHandlerList, Integer> mapping : - handlerOffsets.entrySet()) { - CatchHandlerList list = mapping.getKey(); - int listSize = list.size(); - boolean catchesAll = list.catchesAll(); - - // Set the offset before we do any writing. - mapping.setValue(out.getCursor()); - - if (catchesAll) { - // A size <= 0 means that the list ends with a catch-all. - out.writeSignedLeb128(-(listSize - 1)); - listSize--; - } else { - out.writeSignedLeb128(listSize); - } - - for (int i = 0; i < listSize; i++) { - CatchHandlerList.Entry entry = list.get(i); - out.writeUnsignedLeb128( - typeIds.indexOf(entry.getExceptionType())); - out.writeUnsignedLeb128(entry.getHandler()); - } - - if (catchesAll) { - out.writeUnsignedLeb128(list.get(listSize).getHandler()); - } - } - - encodedHandlers = out.toByteArray(); - } - - /** - * Gets the write size of this instance, in bytes. - * - * @return >= 0; the write size - */ - public int writeSize() { - return (triesSize() * TRY_ITEM_WRITE_SIZE) + - + encodedHandlers.length; - } - - /** - * Writes this instance to the given stream. - * - * @param file non-null; file this instance is part of - * @param out non-null; where to write to - */ - public void writeTo(DexFile file, AnnotatedOutput out) { - finishProcessingIfNecessary(); - - TypeIdsSection typeIds = file.getTypeIds(); - int tableSize = table.size(); - int handlersSize = handlerOffsets.size(); - - if (out.annotates()) { - annotateEntries(" ", null, out); - } - - for (int i = 0; i < tableSize; i++) { - CatchTable.Entry one = table.get(i); - int start = one.getStart(); - int end = one.getEnd(); - int insnCount = end - start; - - if (insnCount >= 65536) { - throw new UnsupportedOperationException( - "bogus exception range: " + Hex.u4(start) + ".." + - Hex.u4(end)); - } - - out.writeInt(start); - out.writeShort(insnCount); - out.writeShort(handlerOffsets.get(one.getHandlers())); - } - - out.write(encodedHandlers); - } - - /** - * Helper method to annotate or simply print the exception handlers. - * Only one of <code>printTo</code> or <code>annotateTo</code> should - * be non-null. - * - * @param prefix non-null; prefix for each line - * @param printTo null-ok; where to print to - * @param annotateTo null-ok; where to consume bytes and annotate to - */ - private void annotateEntries(String prefix, PrintWriter printTo, - AnnotatedOutput annotateTo) { - finishProcessingIfNecessary(); - - boolean consume = (annotateTo != null); - int amt1 = consume ? 6 : 0; - int amt2 = consume ? 2 : 0; - int size = table.size(); - String subPrefix = prefix + " "; - - if (consume) { - annotateTo.annotate(0, prefix + "tries:"); - } else { - printTo.println(prefix + "tries:"); - } - - for (int i = 0; i < size; i++) { - CatchTable.Entry entry = table.get(i); - CatchHandlerList handlers = entry.getHandlers(); - String s1 = subPrefix + "try " + Hex.u2or4(entry.getStart()) - + ".." + Hex.u2or4(entry.getEnd()); - String s2 = handlers.toHuman(subPrefix, ""); - - if (consume) { - annotateTo.annotate(amt1, s1); - annotateTo.annotate(amt2, s2); - } else { - printTo.println(s1); - printTo.println(s2); - } - } - - if (! consume) { - // Only emit the handler lists if we are consuming bytes. - return; - } - - annotateTo.annotate(0, prefix + "handlers:"); - annotateTo.annotate(encodedHandlerHeaderSize, - subPrefix + "size: " + Hex.u2(handlerOffsets.size())); - - int lastOffset = 0; - CatchHandlerList lastList = null; - - for (Map.Entry<CatchHandlerList, Integer> mapping : - handlerOffsets.entrySet()) { - CatchHandlerList list = mapping.getKey(); - int offset = mapping.getValue(); - - if (lastList != null) { - annotateAndConsumeHandlers(lastList, lastOffset, - offset - lastOffset, subPrefix, printTo, annotateTo); - } - - lastList = list; - lastOffset = offset; - } - - annotateAndConsumeHandlers(lastList, lastOffset, - encodedHandlers.length - lastOffset, - subPrefix, printTo, annotateTo); - } - - /** - * Helper for {@link #annotateEntries} to annotate a catch handler list - * while consuming it. - * - * @param handlers non-null; handlers to annotate - * @param offset >= 0; the offset of this handler - * @param size >= 1; the number of bytes the handlers consume - * @param prefix non-null; prefix for each line - * @param printTo null-ok; where to print to - * @param annotateTo non-null; where to annotate to - */ - private static void annotateAndConsumeHandlers(CatchHandlerList handlers, - int offset, int size, String prefix, PrintWriter printTo, - AnnotatedOutput annotateTo) { - String s = handlers.toHuman(prefix, Hex.u2(offset) + ": "); - - if (printTo != null) { - printTo.println(s); - } - - annotateTo.annotate(size, s); - } -} diff --git a/dx/src/com/android/dx/dex/file/ClassDataItem.java b/dx/src/com/android/dx/dex/file/ClassDataItem.java deleted file mode 100644 index 638daed21..000000000 --- a/dx/src/com/android/dx/dex/file/ClassDataItem.java +++ /dev/null @@ -1,431 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.Zeroes; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.Writers; - -import java.io.PrintWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.HashMap; - -/** - * Representation of all the parts of a Dalvik class that are generally - * "inflated" into an in-memory representation at runtime. Instances of - * this class are represented in a compact streamable form in a - * <code>dex</code> file, as opposed to a random-access form. - */ -public final class ClassDataItem extends OffsettedItem { - /** non-null; what class this data is for, just for listing generation */ - private final CstType thisClass; - - /** non-null; list of static fields */ - private final ArrayList<EncodedField> staticFields; - - /** non-null; list of initial values for static fields */ - private final HashMap<EncodedField, Constant> staticValues; - - /** non-null; list of instance fields */ - private final ArrayList<EncodedField> instanceFields; - - /** non-null; list of direct methods */ - private final ArrayList<EncodedMethod> directMethods; - - /** non-null; list of virtual methods */ - private final ArrayList<EncodedMethod> virtualMethods; - - /** null-ok; static initializer list; set in {@link #addContents} */ - private CstArray staticValuesConstant; - - /** - * null-ok; encoded form, ready for writing to a file; set during - * {@link #place0} - */ - private byte[] encodedForm; - - /** - * Constructs an instance. Its sets of members are initially - * empty. - * - * @param thisClass non-null; what class this data is for, just - * for listing generation - */ - public ClassDataItem(CstType thisClass) { - super(1, -1); - - if (thisClass == null) { - throw new NullPointerException("thisClass == null"); - } - - this.thisClass = thisClass; - this.staticFields = new ArrayList<EncodedField>(20); - this.staticValues = new HashMap<EncodedField, Constant>(40); - this.instanceFields = new ArrayList<EncodedField>(20); - this.directMethods = new ArrayList<EncodedMethod>(20); - this.virtualMethods = new ArrayList<EncodedMethod>(20); - this.staticValuesConstant = null; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_CLASS_DATA_ITEM; - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return toString(); - } - - /** - * Returns whether this instance is empty. - * - * @return <code>true</code> if this instance is empty or - * <code>false</code> if at least one element has been added to it - */ - public boolean isEmpty() { - return staticFields.isEmpty() && instanceFields.isEmpty() - && directMethods.isEmpty() && virtualMethods.isEmpty(); - } - - /** - * Adds a static field. - * - * @param field non-null; the field to add - * @param value null-ok; initial value for the field, if any - */ - public void addStaticField(EncodedField field, Constant value) { - if (field == null) { - throw new NullPointerException("field == null"); - } - - if (staticValuesConstant != null) { - throw new UnsupportedOperationException( - "static fields already sorted"); - } - - staticFields.add(field); - staticValues.put(field, value); - } - - /** - * Adds an instance field. - * - * @param field non-null; the field to add - */ - public void addInstanceField(EncodedField field) { - if (field == null) { - throw new NullPointerException("field == null"); - } - - instanceFields.add(field); - } - - /** - * Adds a direct (<code>static</code> and/or <code>private</code>) method. - * - * @param method non-null; the method to add - */ - public void addDirectMethod(EncodedMethod method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - directMethods.add(method); - } - - /** - * Adds a virtual method. - * - * @param method non-null; the method to add - */ - public void addVirtualMethod(EncodedMethod method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - virtualMethods.add(method); - } - - /** - * Gets all the methods in this class. The returned list is not linked - * in any way to the underlying lists contained in this instance, but - * the objects contained in the list are shared. - * - * @return non-null; list of all methods - */ - public ArrayList<EncodedMethod> getMethods() { - int sz = directMethods.size() + virtualMethods.size(); - ArrayList<EncodedMethod> result = new ArrayList<EncodedMethod>(sz); - - result.addAll(directMethods); - result.addAll(virtualMethods); - - return result; - } - - - /** - * Prints out the contents of this instance, in a debugging-friendly - * way. - * - * @param out non-null; where to output to - * @param verbose whether to be verbose with the output - */ - public void debugPrint(Writer out, boolean verbose) { - PrintWriter pw = Writers.printWriterFor(out); - - int sz = staticFields.size(); - for (int i = 0; i < sz; i++) { - pw.println(" sfields[" + i + "]: " + staticFields.get(i)); - } - - sz = instanceFields.size(); - for (int i = 0; i < sz; i++) { - pw.println(" ifields[" + i + "]: " + instanceFields.get(i)); - } - - sz = directMethods.size(); - for (int i = 0; i < sz; i++) { - pw.println(" dmeths[" + i + "]:"); - directMethods.get(i).debugPrint(pw, verbose); - } - - sz = virtualMethods.size(); - for (int i = 0; i < sz; i++) { - pw.println(" vmeths[" + i + "]:"); - virtualMethods.get(i).debugPrint(pw, verbose); - } - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - if (!staticFields.isEmpty()) { - getStaticValuesConstant(); // Force the fields to be sorted. - for (EncodedField field : staticFields) { - field.addContents(file); - } - } - - if (!instanceFields.isEmpty()) { - Collections.sort(instanceFields); - for (EncodedField field : instanceFields) { - field.addContents(file); - } - } - - if (!directMethods.isEmpty()) { - Collections.sort(directMethods); - for (EncodedMethod method : directMethods) { - method.addContents(file); - } - } - - if (!virtualMethods.isEmpty()) { - Collections.sort(virtualMethods); - for (EncodedMethod method : virtualMethods) { - method.addContents(file); - } - } - } - - /** - * Gets a {@link CstArray} corresponding to {@link #staticValues} if - * it contains any non-zero non-<code>null</code> values. - * - * @return null-ok; the corresponding constant or <code>null</code> if - * there are no values to encode - */ - public CstArray getStaticValuesConstant() { - if ((staticValuesConstant == null) && (staticFields.size() != 0)) { - staticValuesConstant = makeStaticValuesConstant(); - } - - return staticValuesConstant; - } - - /** - * Gets a {@link CstArray} corresponding to {@link #staticValues} if - * it contains any non-zero non-<code>null</code> values. - * - * @return null-ok; the corresponding constant or <code>null</code> if - * there are no values to encode - */ - private CstArray makeStaticValuesConstant() { - // First sort the statics into their final order. - Collections.sort(staticFields); - - /* - * Get the size of staticValues minus any trailing zeros/nulls (both - * nulls per se as well as instances of CstKnownNull). - */ - - int size = staticFields.size(); - while (size > 0) { - EncodedField field = staticFields.get(size - 1); - Constant cst = staticValues.get(field); - if (cst instanceof CstLiteralBits) { - // Note: CstKnownNull extends CstLiteralBits. - if (((CstLiteralBits) cst).getLongBits() != 0) { - break; - } - } else if (cst != null) { - break; - } - size--; - } - - if (size == 0) { - return null; - } - - // There is something worth encoding, so build up a result. - - CstArray.List list = new CstArray.List(size); - for (int i = 0; i < size; i++) { - EncodedField field = staticFields.get(i); - Constant cst = staticValues.get(field); - if (cst == null) { - cst = Zeroes.zeroFor(field.getRef().getType()); - } - list.set(i, cst); - } - list.setImmutable(); - - return new CstArray(list); - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // Encode the data and note the size. - - ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(); - - encodeOutput(addedTo.getFile(), out); - encodedForm = out.toByteArray(); - setWriteSize(encodedForm.length); - } - - /** - * Writes out the encoded form of this instance. - * - * @param file non-null; file this instance is part of - * @param out non-null; where to write to - */ - private void encodeOutput(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - int svSize = (staticValuesConstant == null) ? 0 : - staticValuesConstant.getList().size(); - - if (annotates) { - out.annotate(0, offsetString() + " class data for " + - thisClass.toHuman()); - } - - encodeSize(file, out, "static_fields", staticFields.size()); - encodeSize(file, out, "instance_fields", instanceFields.size()); - encodeSize(file, out, "direct_methods", directMethods.size()); - encodeSize(file, out, "virtual_methods", virtualMethods.size()); - - encodeList(file, out, "static_fields", staticFields); - encodeList(file, out, "instance_fields", instanceFields); - encodeList(file, out, "direct_methods", directMethods); - encodeList(file, out, "virtual_methods", virtualMethods); - - if (annotates) { - out.endAnnotation(); - } - } - - /** - * Helper for {@link #encodeOutput}, which writes out the given - * size value, annotating it as well (if annotations are enabled). - * - * @param file non-null; file this instance is part of - * @param out non-null; where to write to - * @param label non-null; the label for the purposes of annotation - * @param size >= 0; the size to write - */ - private static void encodeSize(DexFile file, AnnotatedOutput out, - String label, int size) { - if (out.annotates()) { - out.annotate(String.format(" %-21s %08x", label + "_size:", - size)); - } - - out.writeUnsignedLeb128(size); - } - - /** - * Helper for {@link #encodeOutput}, which writes out the given - * list. It also annotates the items (if any and if annotations - * are enabled). - * - * @param file non-null; file this instance is part of - * @param out non-null; where to write to - * @param label non-null; the label for the purposes of annotation - * @param list non-null; the list in question - */ - private static void encodeList(DexFile file, AnnotatedOutput out, - String label, ArrayList<? extends EncodedMember> list) { - int size = list.size(); - int lastIndex = 0; - - if (size == 0) { - return; - } - - if (out.annotates()) { - out.annotate(0, " " + label + ":"); - } - - for (int i = 0; i < size; i++) { - lastIndex = list.get(i).encode(file, out, lastIndex, i); - } - } - - /** {@inheritDoc} */ - @Override - public void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - - if (annotates) { - /* - * The output is to be annotated, so redo the work previously - * done by place0(), except this time annotations will actually - * get emitted. - */ - encodeOutput(file, out); - } else { - out.write(encodedForm); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/ClassDefItem.java b/dx/src/com/android/dx/dex/file/ClassDefItem.java deleted file mode 100644 index 5a0b27c90..000000000 --- a/dx/src/com/android/dx/dex/file/ClassDefItem.java +++ /dev/null @@ -1,410 +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.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.Writers; - -import java.io.PrintWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.TreeSet; - -/** - * Representation of a Dalvik class, which is basically a set of - * members (fields or methods) along with a few more pieces of - * information. - */ -public final class ClassDefItem extends IndexedItem { - /** size of instances when written out to a file, in bytes */ - public static final int WRITE_SIZE = 32; - - /** non-null; type constant for this class */ - private final CstType thisClass; - - /** access flags */ - private final int accessFlags; - - /** - * null-ok; superclass or <code>null</code> if this class is a/the - * root class - */ - private final CstType superclass; - - /** null-ok; list of implemented interfaces */ - private TypeListItem interfaces; - - /** null-ok; source file name or <code>null</code> if unknown */ - private final CstUtf8 sourceFile; - - /** non-null; associated class data object */ - private final ClassDataItem classData; - - /** - * null-ok; item wrapper for the static values, initialized - * in {@link #addContents} - */ - private EncodedArrayItem staticValuesItem; - - /** non-null; annotations directory */ - private AnnotationsDirectoryItem annotationsDirectory; - - /** - * Constructs an instance. Its sets of members and annotations are - * initially empty. - * - * @param thisClass non-null; type constant for this class - * @param accessFlags access flags - * @param superclass null-ok; superclass or <code>null</code> if - * this class is a/the root class - * @param interfaces non-null; list of implemented interfaces - * @param sourceFile null-ok; source file name or - * <code>null</code> if unknown - */ - public ClassDefItem(CstType thisClass, int accessFlags, - CstType superclass, TypeList interfaces, CstUtf8 sourceFile) { - if (thisClass == null) { - throw new NullPointerException("thisClass == null"); - } - - /* - * TODO: Maybe check accessFlags and superclass, at - * least for easily-checked stuff? - */ - - if (interfaces == null) { - throw new NullPointerException("interfaces == null"); - } - - this.thisClass = thisClass; - this.accessFlags = accessFlags; - this.superclass = superclass; - this.interfaces = - (interfaces.size() == 0) ? null : new TypeListItem(interfaces); - this.sourceFile = sourceFile; - this.classData = new ClassDataItem(thisClass); - this.staticValuesItem = null; - this.annotationsDirectory = new AnnotationsDirectoryItem(); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_CLASS_DEF_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return WRITE_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - TypeIdsSection typeIds = file.getTypeIds(); - MixedItemSection byteData = file.getByteData(); - MixedItemSection wordData = file.getWordData(); - MixedItemSection typeLists = file.getTypeLists(); - StringIdsSection stringIds = file.getStringIds(); - - typeIds.intern(thisClass); - - if (!classData.isEmpty()) { - MixedItemSection classDataSection = file.getClassData(); - classDataSection.add(classData); - - CstArray staticValues = classData.getStaticValuesConstant(); - if (staticValues != null) { - staticValuesItem = - byteData.intern(new EncodedArrayItem(staticValues)); - } - } - - if (superclass != null) { - typeIds.intern(superclass); - } - - if (interfaces != null) { - interfaces = typeLists.intern(interfaces); - } - - if (sourceFile != null) { - stringIds.intern(sourceFile); - } - - if (! annotationsDirectory.isEmpty()) { - if (annotationsDirectory.isInternable()) { - annotationsDirectory = wordData.intern(annotationsDirectory); - } else { - wordData.add(annotationsDirectory); - } - } - } - - /** {@inheritDoc} */ - @Override - public void writeTo(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - TypeIdsSection typeIds = file.getTypeIds(); - int classIdx = typeIds.indexOf(thisClass); - int superIdx = (superclass == null) ? -1 : - typeIds.indexOf(superclass); - int interOff = OffsettedItem.getAbsoluteOffsetOr0(interfaces); - int annoOff = annotationsDirectory.isEmpty() ? 0 : - annotationsDirectory.getAbsoluteOffset(); - int sourceFileIdx = (sourceFile == null) ? -1 : - file.getStringIds().indexOf(sourceFile); - int dataOff = classData.isEmpty()? 0 : classData.getAbsoluteOffset(); - int staticValuesOff = - OffsettedItem.getAbsoluteOffsetOr0(staticValuesItem); - - if (annotates) { - out.annotate(0, indexString() + ' ' + thisClass.toHuman()); - out.annotate(4, " class_idx: " + Hex.u4(classIdx)); - out.annotate(4, " access_flags: " + - AccessFlags.classString(accessFlags)); - out.annotate(4, " superclass_idx: " + Hex.u4(superIdx) + - " // " + ((superclass == null) ? "<none>" : - superclass.toHuman())); - out.annotate(4, " interfaces_off: " + Hex.u4(interOff)); - if (interOff != 0) { - TypeList list = interfaces.getList(); - int sz = list.size(); - for (int i = 0; i < sz; i++) { - out.annotate(0, " " + list.getType(i).toHuman()); - } - } - out.annotate(4, " source_file_idx: " + Hex.u4(sourceFileIdx) + - " // " + ((sourceFile == null) ? "<none>" : - sourceFile.toHuman())); - out.annotate(4, " annotations_off: " + Hex.u4(annoOff)); - out.annotate(4, " class_data_off: " + Hex.u4(dataOff)); - out.annotate(4, " static_values_off: " + - Hex.u4(staticValuesOff)); - } - - out.writeInt(classIdx); - out.writeInt(accessFlags); - out.writeInt(superIdx); - out.writeInt(interOff); - out.writeInt(sourceFileIdx); - out.writeInt(annoOff); - out.writeInt(dataOff); - out.writeInt(staticValuesOff); - } - - /** - * Gets the constant corresponding to this class. - * - * @return non-null; the constant - */ - public CstType getThisClass() { - return thisClass; - } - - /** - * Gets the access flags. - * - * @return the access flags - */ - public int getAccessFlags() { - return accessFlags; - } - - /** - * Gets the superclass. - * - * @return null-ok; the superclass or <code>null</code> if - * this class is a/the root class - */ - public CstType getSuperclass() { - return superclass; - } - - /** - * Gets the list of interfaces implemented. - * - * @return non-null; the interfaces list - */ - public TypeList getInterfaces() { - if (interfaces == null) { - return StdTypeList.EMPTY; - } - - return interfaces.getList(); - } - - /** - * Gets the source file name. - * - * @return null-ok; the source file name or <code>null</code> if unknown - */ - public CstUtf8 getSourceFile() { - return sourceFile; - } - - /** - * Adds a static field. - * - * @param field non-null; the field to add - * @param value null-ok; initial value for the field, if any - */ - public void addStaticField(EncodedField field, Constant value) { - classData.addStaticField(field, value); - } - - /** - * Adds an instance field. - * - * @param field non-null; the field to add - */ - public void addInstanceField(EncodedField field) { - classData.addInstanceField(field); - } - - /** - * Adds a direct (<code>static</code> and/or <code>private</code>) method. - * - * @param method non-null; the method to add - */ - public void addDirectMethod(EncodedMethod method) { - classData.addDirectMethod(method); - } - - /** - * Adds a virtual method. - * - * @param method non-null; the method to add - */ - public void addVirtualMethod(EncodedMethod method) { - classData.addVirtualMethod(method); - } - - /** - * Gets all the methods in this class. The returned list is not linked - * in any way to the underlying lists contained in this instance, but - * the objects contained in the list are shared. - * - * @return non-null; list of all methods - */ - public ArrayList<EncodedMethod> getMethods() { - return classData.getMethods(); - } - - /** - * Sets the direct annotations on this class. These are annotations - * made on the class, per se, as opposed to on one of its members. - * It is only valid to call this method at most once per instance. - * - * @param annotations non-null; annotations to set for this class - */ - public void setClassAnnotations(Annotations annotations) { - annotationsDirectory.setClassAnnotations(annotations); - } - - /** - * Adds a field annotations item to this class. - * - * @param field non-null; field in question - * @param annotations non-null; associated annotations to add - */ - public void addFieldAnnotations(CstFieldRef field, - Annotations annotations) { - annotationsDirectory.addFieldAnnotations(field, annotations); - } - - /** - * Adds a method annotations item to this class. - * - * @param method non-null; method in question - * @param annotations non-null; associated annotations to add - */ - public void addMethodAnnotations(CstMethodRef method, - Annotations annotations) { - annotationsDirectory.addMethodAnnotations(method, annotations); - } - - /** - * Adds a parameter annotations item to this class. - * - * @param method non-null; method in question - * @param list non-null; associated list of annotation sets to add - */ - public void addParameterAnnotations(CstMethodRef method, - AnnotationsList list) { - annotationsDirectory.addParameterAnnotations(method, list); - } - - /** - * Gets the method annotations for a given method, if any. This is - * meant for use by debugging / dumping code. - * - * @param method non-null; the method - * @return null-ok; the method annotations, if any - */ - public Annotations getMethodAnnotations(CstMethodRef method) { - return annotationsDirectory.getMethodAnnotations(method); - } - - /** - * Gets the parameter annotations for a given method, if any. This is - * meant for use by debugging / dumping code. - * - * @param method non-null; the method - * @return null-ok; the parameter annotations, if any - */ - public AnnotationsList getParameterAnnotations(CstMethodRef method) { - return annotationsDirectory.getParameterAnnotations(method); - } - - /** - * Prints out the contents of this instance, in a debugging-friendly - * way. - * - * @param out non-null; where to output to - * @param verbose whether to be verbose with the output - */ - public void debugPrint(Writer out, boolean verbose) { - PrintWriter pw = Writers.printWriterFor(out); - - pw.println(getClass().getName() + " {"); - pw.println(" accessFlags: " + Hex.u2(accessFlags)); - pw.println(" superclass: " + superclass); - pw.println(" interfaces: " + - ((interfaces == null) ? "<none>" : interfaces)); - pw.println(" sourceFile: " + - ((sourceFile == null) ? "<none>" : sourceFile.toQuoted())); - - classData.debugPrint(out, verbose); - annotationsDirectory.debugPrint(pw); - - pw.println("}"); - } -} diff --git a/dx/src/com/android/dx/dex/file/ClassDefsSection.java b/dx/src/com/android/dx/dex/file/ClassDefsSection.java deleted file mode 100644 index cf61b4732..000000000 --- a/dx/src/com/android/dx/dex/file/ClassDefsSection.java +++ /dev/null @@ -1,187 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.TreeMap; - -/** - * Class definitions list section of a <code>.dex</code> file. - */ -public final class ClassDefsSection extends UniformItemSection { - /** - * non-null; map from type constants for classes to {@link - * ClassDefItem} instances that define those classes - */ - private final TreeMap<Type, ClassDefItem> classDefs; - - /** null-ok; ordered list of classes; set in {@link #orderItems} */ - private ArrayList<ClassDefItem> orderedDefs; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public ClassDefsSection(DexFile file) { - super("class_defs", file, 4); - - classDefs = new TreeMap<Type, ClassDefItem>(); - orderedDefs = null; - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - if (orderedDefs != null) { - return orderedDefs; - } - - return classDefs.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - throwIfNotPrepared(); - - Type type = ((CstType) cst).getClassType(); - IndexedItem result = classDefs.get(type); - - if (result == null) { - throw new IllegalArgumentException("not found"); - } - - return result; - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = classDefs.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (out.annotates()) { - out.annotate(4, "class_defs_size: " + Hex.u4(sz)); - out.annotate(4, "class_defs_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Adds an element to this instance. It is illegal to attempt to add more - * than one class with the same name. - * - * @param clazz non-null; the class def to add - */ - public void add(ClassDefItem clazz) { - Type type; - - try { - type = clazz.getThisClass().getClassType(); - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("clazz == null"); - } - - throwIfPrepared(); - - if (classDefs.get(type) != null) { - throw new IllegalArgumentException("already added: " + type); - } - - classDefs.put(type, clazz); - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - int sz = classDefs.size(); - int idx = 0; - - orderedDefs = new ArrayList<ClassDefItem>(sz); - - /* - * Iterate over all the classes, recursively assigning an - * index to each, implicitly skipping the ones that have - * already been assigned by the time this (top-level) - * iteration reaches them. - */ - for (Type type : classDefs.keySet()) { - idx = orderItems0(type, idx, sz - idx); - } - } - - /** - * Helper for {@link #orderItems}, which recursively assigns indices - * to classes. - * - * @param type null-ok; type ref to assign, if any - * @param idx >= 0; the next index to assign - * @param maxDepth maximum recursion depth; if negative, this will - * throw an exception indicating class definition circularity - * @return >= 0; the next index to assign - */ - private int orderItems0(Type type, int idx, int maxDepth) { - ClassDefItem c = classDefs.get(type); - - if ((c == null) || (c.hasIndex())) { - return idx; - } - - if (maxDepth < 0) { - throw new RuntimeException("class circularity with " + type); - } - - maxDepth--; - - CstType superclassCst = c.getSuperclass(); - if (superclassCst != null) { - Type superclass = superclassCst.getClassType(); - idx = orderItems0(superclass, idx, maxDepth); - } - - TypeList interfaces = c.getInterfaces(); - int sz = interfaces.size(); - for (int i = 0; i < sz; i++) { - idx = orderItems0(interfaces.getType(i), idx, maxDepth); - } - - c.setIndex(idx); - orderedDefs.add(c); - return idx + 1; - } -} diff --git a/dx/src/com/android/dx/dex/file/CodeItem.java b/dx/src/com/android/dx/dex/file/CodeItem.java deleted file mode 100644 index dc0bb5272..000000000 --- a/dx/src/com/android/dx/dex/file/CodeItem.java +++ /dev/null @@ -1,335 +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.android.dx.dex.file; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.CatchTable; -import com.android.dx.dex.code.DalvCode; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.DalvInsnList; -import com.android.dx.dex.code.LocalList; -import com.android.dx.dex.code.PositionList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstMemberRef; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; -import com.android.dx.util.Hex; - -import java.io.PrintWriter; -import java.util.HashSet; - -/** - * Representation of all the parts needed for concrete methods in a - * <code>dex</code> file. - */ -public final class CodeItem extends OffsettedItem { - /** file alignment of this class, in bytes */ - private static final int ALIGNMENT = 4; - - /** write size of the header of this class, in bytes */ - private static final int HEADER_SIZE = 16; - - /** non-null; method that this code implements */ - private final CstMethodRef ref; - - /** non-null; the bytecode instructions and associated data */ - private final DalvCode code; - - /** null-ok; the catches, if needed; set in {@link #addContents} */ - private CatchStructs catches; - - /** whether this instance is for a <code>static</code> method */ - private final boolean isStatic; - - /** - * non-null; list of possibly-thrown exceptions; just used in - * generating debugging output (listings) - */ - private final TypeList throwsList; - - /** - * null-ok; the debug info or <code>null</code> if there is none; - * set in {@link #addContents} - */ - private DebugInfoItem debugInfo; - - /** - * Constructs an instance. - * - * @param ref non-null; method that this code implements - * @param code non-null; the underlying code - * @param isStatic whether this instance is for a <code>static</code> - * method - * @param throwsList non-null; list of possibly-thrown exceptions, - * just used in generating debugging output (listings) - */ - public CodeItem(CstMethodRef ref, DalvCode code, boolean isStatic, - TypeList throwsList) { - super(ALIGNMENT, -1); - - if (ref == null) { - throw new NullPointerException("ref == null"); - } - - if (code == null) { - throw new NullPointerException("code == null"); - } - - if (throwsList == null) { - throw new NullPointerException("throwsList == null"); - } - - this.ref = ref; - this.code = code; - this.isStatic = isStatic; - this.throwsList = throwsList; - this.catches = null; - this.debugInfo = null; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_CODE_ITEM; - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MixedItemSection wordData = file.getWordData(); - MixedItemSection byteData = file.getByteData(); - TypeIdsSection typeIds = file.getTypeIds(); - - if (code.hasPositions() || code.hasLocals()) { - debugInfo = new DebugInfoItem(code, isStatic, ref); - byteData.add(debugInfo); - } - - if (code.hasAnyCatches()) { - for (Type type : code.getCatchTypes()) { - typeIds.intern(type); - } - catches = new CatchStructs(code); - } - - for (Constant c : code.getInsnConstants()) { - file.internIfAppropriate(c); - } - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return "CodeItem{" + toHuman() + "}"; - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return ref.toHuman(); - } - - /** - * Gets the reference to the method this instance implements. - * - * @return non-null; the method reference - */ - public CstMethodRef getRef() { - return ref; - } - - /** - * Does a human-friendly dump of this instance. - * - * @param out non-null; where to dump - * @param prefix non-null; per-line prefix to use - * @param verbose whether to be verbose with the output - */ - public void debugPrint(PrintWriter out, String prefix, boolean verbose) { - out.println(ref.toHuman() + ":"); - - DalvInsnList insns = code.getInsns(); - out.println("regs: " + Hex.u2(getRegistersSize()) + - "; ins: " + Hex.u2(getInsSize()) + "; outs: " + - Hex.u2(getOutsSize())); - - insns.debugPrint(out, prefix, verbose); - - String prefix2 = prefix + " "; - - if (catches != null) { - out.print(prefix); - out.println("catches"); - catches.debugPrint(out, prefix2); - } - - if (debugInfo != null) { - out.print(prefix); - out.println("debug info"); - debugInfo.debugPrint(out, prefix2); - } - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - final DexFile file = addedTo.getFile(); - int catchesSize; - - /* - * In order to get the catches and insns, all the code's - * constants need to be assigned indices. - */ - code.assignIndices(new DalvCode.AssignIndicesCallback() { - public int getIndex(Constant cst) { - IndexedItem item = file.findItemOrNull(cst); - if (item == null) { - return -1; - } - return item.getIndex(); - } - }); - - if (catches != null) { - catches.encode(file); - catchesSize = catches.writeSize(); - } else { - catchesSize = 0; - } - - /* - * The write size includes the header, two bytes per code - * unit, post-code padding if necessary, and however much - * space the catches need. - */ - - int insnsSize = code.getInsns().codeSize(); - if ((insnsSize & 1) != 0) { - insnsSize++; - } - - setWriteSize(HEADER_SIZE + (insnsSize * 2) + catchesSize); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - int regSz = getRegistersSize(); - int outsSz = getOutsSize(); - int insSz = getInsSize(); - int insnsSz = code.getInsns().codeSize(); - boolean needPadding = (insnsSz & 1) != 0; - int triesSz = (catches == null) ? 0 : catches.triesSize(); - int debugOff = (debugInfo == null) ? 0 : debugInfo.getAbsoluteOffset(); - - if (annotates) { - out.annotate(0, offsetString() + ' ' + ref.toHuman()); - out.annotate(2, " registers_size: " + Hex.u2(regSz)); - out.annotate(2, " ins_size: " + Hex.u2(insSz)); - out.annotate(2, " outs_size: " + Hex.u2(outsSz)); - out.annotate(2, " tries_size: " + Hex.u2(triesSz)); - out.annotate(4, " debug_off: " + Hex.u4(debugOff)); - out.annotate(4, " insns_size: " + Hex.u4(insnsSz)); - - // This isn't represented directly here, but it is useful to see. - int size = throwsList.size(); - if (size != 0) { - out.annotate(0, " throws " + StdTypeList.toHuman(throwsList)); - } - } - - out.writeShort(regSz); - out.writeShort(insSz); - out.writeShort(outsSz); - out.writeShort(triesSz); - out.writeInt(debugOff); - out.writeInt(insnsSz); - - writeCodes(file, out); - - if (catches != null) { - if (needPadding) { - if (annotates) { - out.annotate(2, " padding: 0"); - } - out.writeShort(0); - } - - catches.writeTo(file, out); - } - - if (annotates) { - /* - * These are pointed at in the code header (above), but it's less - * distracting to expand on them at the bottom of the code. - */ - if (debugInfo != null) { - out.annotate(0, " debug info"); - debugInfo.annotateTo(file, out, " "); - } - } - } - - /** - * Helper for {@link #writeTo0} which writes out the actual bytecode. - * - * @param file non-null; file we are part of - * @param out non-null; where to write to - */ - private void writeCodes(DexFile file, AnnotatedOutput out) { - DalvInsnList insns = code.getInsns(); - - try { - insns.writeTo(out); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, "...while writing " + - "instructions for " + ref.toHuman()); - } - } - - /** - * Get the in registers count. - * - * @return the count - */ - private int getInsSize() { - return ref.getParameterWordCount(isStatic); - } - - /** - * Get the out registers count. - * - * @return the count - */ - private int getOutsSize() { - return code.getInsns().getOutsSize(); - } - - /** - * Get the total registers count. - * - * @return the count - */ - private int getRegistersSize() { - return code.getInsns().getRegistersSize(); - } -} diff --git a/dx/src/com/android/dx/dex/file/DebugInfoConstants.java b/dx/src/com/android/dx/dex/file/DebugInfoConstants.java deleted file mode 100644 index 010acb434..000000000 --- a/dx/src/com/android/dx/dex/file/DebugInfoConstants.java +++ /dev/null @@ -1,154 +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.android.dx.dex.file; - -/** - * Constants for the dex debug info state machine format. - */ -public interface DebugInfoConstants { - - /* - * normal opcodes - */ - - /** - * Terminates a debug info sequence for a method.<p> - * Args: none - * - */ - static final int DBG_END_SEQUENCE = 0x00; - - /** - * Advances the program counter/address register without emitting - * a positions entry.<p> - * - * Args: - * <ol> - * <li>Unsigned LEB128 — amount to advance pc by - * </ol> - */ - static final int DBG_ADVANCE_PC = 0x01; - - /** - * Advances the line register without emitting - * a positions entry.<p> - * - * Args: - * <ol> - * <li>Signed LEB128 — amount to change line register by. - * </ol> - */ - static final int DBG_ADVANCE_LINE = 0x02; - - /** - * Introduces a local variable at the current address.<p> - * - * Args: - * <ol> - * <li>Unsigned LEB128 — register that will contain local. - * <li>Unsigned LEB128 — string index (shifted by 1) of local name. - * <li>Unsigned LEB128 — type index (shifted by 1) of type. - * </ol> - */ - static final int DBG_START_LOCAL = 0x03; - - /** - * Introduces a local variable at the current address with a type - * signature specified.<p> - * - * Args: - * <ol> - * <li>Unsigned LEB128 — register that will contain local. - * <li>Unsigned LEB128 — string index (shifted by 1) of local name. - * <li>Unsigned LEB128 — type index (shifted by 1) of type. - * <li>Unsigned LEB128 — string index (shifted by 1) of - * type signature. - * </ol> - */ - static final int DBG_START_LOCAL_EXTENDED = 0x04; - - /** - * Marks a currently-live local variable as out of scope at the - * current address.<p> - * - * Args: - * <ol> - * <li>Unsigned LEB128 — register that contained local - * </ol> - */ - static final int DBG_END_LOCAL = 0x05; - - /** - * Re-introduces a local variable at the current address. The name - * and type are the same as the last local that was live in the specified - * register.<p> - * - * Args: - * <ol> - * <li>Unsigned LEB128 — register to re-start. - * </ol> - */ - static final int DBG_RESTART_LOCAL = 0x06; - - - /** - * Sets the "prologue_end" state machine register, indicating that the - * next position entry that is added should be considered the end of - * a method prologue (an appropriate place for a method breakpoint).<p> - * - * The prologue_end register is cleared by any special (>= OPCODE_BASE) - * opcode. - */ - static final int DBG_SET_PROLOGUE_END = 0x07; - - /** - * Sets the "epilogue_begin" state machine register, indicating that the - * next position entry that is added should be considered the beginning of - * a method epilogue (an appropriate place to suspend execution before - * method exit).<p> - * - * The epilogue_begin register is cleared by any special (>= OPCODE_BASE) - * opcode. - */ - static final int DBG_SET_EPILOGUE_BEGIN = 0x08; - - /** - * Sets the current file that that line numbers refer to. All subsequent - * line number entries make reference to this source file name, instead - * of the default name specified in code_item. - * - * Args: - * <ol> - * <li>Unsigned LEB128 — string index (shifted by 1) of source - * file name. - * </ol> - */ - static final int DBG_SET_FILE = 0x09; - - /* IF YOU ADD A NEW OPCODE, increase OPCODE_BASE */ - - /* - * "special opcode" configuration, essentially what's found in - * the line number program header in DWARFv3, Section 6.2.4 - */ - - /** the smallest value a special opcode can take */ - static final int DBG_FIRST_SPECIAL = 0x0a; - static final int DBG_LINE_BASE = -4; - static final int DBG_LINE_RANGE = 15; - // MIN_INSN_LENGTH is always 1 -} diff --git a/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java b/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java deleted file mode 100644 index 519452b64..000000000 --- a/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java +++ /dev/null @@ -1,563 +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.android.dx.dex.file; - -import com.android.dx.dex.code.LocalList; -import com.android.dx.dex.code.PositionList; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.util.ExceptionWithContext; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -import static com.android.dx.dex.file.DebugInfoConstants.*; - -/** - * A decoder for the dex debug info state machine format. - * This code exists mostly as a reference implementation and test for - * for the <code>DebugInfoEncoder</code> - */ -public class DebugInfoDecoder { - /** encoded debug info */ - private final byte[] encoded; - /** positions decoded */ - private final ArrayList<PositionEntry> positions; - /** locals decoded */ - private final ArrayList<LocalEntry> locals; - /** size of code block in code units */ - private final int codesize; - /** indexed by register, the last local variable live in a reg */ - private final LocalEntry[] lastEntryForReg; - /** method descriptor of method this debug info is for */ - private final Prototype desc; - /** true if method is static */ - private final boolean isStatic; - /** dex file this debug info will be stored in */ - private final DexFile file; - /** - * register size, in register units, of the register space - * used by this method - */ - private final int regSize; - - /** current decoding state: line number */ - private int line = 1; - - /** current decoding state: bytecode address */ - private int address = 0; - - /** string index of the string "this" */ - private final int thisStringIdx; - - /** - * Constructs an instance. - * - * @param encoded encoded debug info - * @param codesize size of code block in code units - * @param regSize register size, in register units, of the register space - * used by this method - * @param isStatic true if method is static - * @param ref method descriptor of method this debug info is for - * @param file dex file this debug info will be stored in - */ - DebugInfoDecoder (byte[] encoded, int codesize, int regSize, - boolean isStatic, CstMethodRef ref, DexFile file) { - - this.encoded = encoded; - this.isStatic = isStatic; - this.desc = ref.getPrototype(); - this.file = file; - this.regSize = regSize; - - positions = new ArrayList(); - locals = new ArrayList(); - this.codesize = codesize; - lastEntryForReg = new LocalEntry[regSize]; - - thisStringIdx = file.getStringIds().indexOf(new CstUtf8("this")); - } - - /** - * An entry in the resulting postions table - */ - static class PositionEntry { - /** bytecode address */ - int address; - /** line number */ - int line; - - PositionEntry(int address, int line) { - this.address = address; - this.line = line; - } - } - - /** - * An entry in the resulting locals table - */ - static class LocalEntry { - LocalEntry(int start, int reg, int nameIndex, int typeIndex, - int signatureIndex) { - this.start = start; - this.reg = reg; - this.nameIndex = nameIndex; - this.typeIndex = typeIndex; - this.signatureIndex = signatureIndex; - } - - /** start of address range */ - int start; - - /** - * End of address range. Initialized to MAX_VALUE here but will - * be set to no more than 1 + max bytecode address of method. - */ - int end = Integer.MAX_VALUE; - - /** register number */ - int reg; - - /** index of name in strings table */ - int nameIndex; - - /** index of type in types table */ - int typeIndex; - - /** index of type signature in strings table */ - int signatureIndex; - - } - - /** - * Gets the decoded positions list. - * Valid after calling <code>decode</code>. - * - * @return positions list in ascending address order. - */ - public List<PositionEntry> getPositionList() { - return positions; - } - - /** - * Gets the decoded locals list, in ascending start-address order. - * Valid after calling <code>decode</code>. - * - * @return locals list in ascending address order. - */ - public List<LocalEntry> getLocals() { - // TODO move this loop: - // Any variable that didnt end ends now - for (LocalEntry local: locals) { - if (local.end == Integer.MAX_VALUE) { - local.end = codesize; - } - } - return locals; - } - - /** - * Decodes the debug info sequence. - */ - public void decode() { - try { - decode0(); - } catch (Exception ex) { - throw ExceptionWithContext.withContext(ex, - "...while decoding debug info"); - } - } - - /** - * Reads a string index. String indicies are offset by 1, and a 0 value - * in the stream (-1 as returned by this method) means "null" - * - * @param bs - * @return index into file's string ids table, -1 means null - * @throws IOException - */ - private int readStringIndex(InputStream bs) throws IOException { - int offsetIndex = readUnsignedLeb128(bs); - - return offsetIndex - 1; - } - - /** - * Gets the register that begins the method's parameter range (including - * the 'this' parameter for non-static methods). The range continues until - * <code>regSize</code> - * - * @return register as noted above. - */ - private int getParamBase() { - return regSize - - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1); - } - - private void decode0() throws IOException { - ByteArrayInputStream bs = new ByteArrayInputStream(encoded); - - line = readUnsignedLeb128(bs); - int szParams = readUnsignedLeb128(bs); - StdTypeList params = desc.getParameterTypes(); - int curReg = getParamBase(); - - if (szParams != params.size()) { - throw new RuntimeException( - "Mismatch between parameters_size and prototype"); - } - - if (!isStatic) { - // Start off with implicit 'this' entry - LocalEntry thisEntry - = new LocalEntry(0, curReg, thisStringIdx, 0, 0); - locals.add(thisEntry); - lastEntryForReg[curReg] = thisEntry; - curReg++; - } - - for (int i = 0; i < szParams; i++) { - Type paramType = params.getType(i); - LocalEntry le; - - int nameIdx = readStringIndex(bs); - - if(nameIdx == -1) { - // unnamed parameter - } else { - // final '0' should be idx of paramType.getDescriptor() - le = new LocalEntry(0, curReg, nameIdx, 0, 0); - locals.add(le); - lastEntryForReg[curReg] = le; - } - - curReg += paramType.getCategory(); - } - - for (;;) { - int opcode = bs.read(); - - if (opcode < 0) { - throw new RuntimeException - ("Reached end of debug stream without " - + "encountering end marker"); - } - - switch (opcode) { - case DBG_START_LOCAL: { - int reg = readUnsignedLeb128(bs); - int nameIdx = readStringIndex(bs); - int typeIdx = readStringIndex(bs); - LocalEntry le = new LocalEntry( - address, reg, nameIdx, typeIdx, 0); - - // a "start" is implicitly the "end" of whatever was - // previously defined in the register - if (lastEntryForReg[reg] != null - && lastEntryForReg[reg].end == Integer.MAX_VALUE) { - - lastEntryForReg[reg].end = address; - } - - locals.add(le); - lastEntryForReg[reg] = le; - } - break; - - case DBG_START_LOCAL_EXTENDED: { - int reg = readUnsignedLeb128(bs); - int nameIdx = readStringIndex(bs); - int typeIdx = readStringIndex(bs); - int sigIdx = readStringIndex(bs); - LocalEntry le = new LocalEntry( - address, reg, nameIdx, typeIdx, sigIdx); - - // a "start" is implicitly the "end" of whatever was - // previously defined in the register - if (lastEntryForReg[reg] != null - && lastEntryForReg[reg].end == Integer.MAX_VALUE) { - - lastEntryForReg[reg].end = address; - - // A 0-length entry. Almost certainly a "this" - // with a signature. - if (lastEntryForReg[reg].start == address) { - locals.remove(lastEntryForReg[reg]); - } - } - - locals.add(le); - lastEntryForReg[reg] = le; - } - break; - - case DBG_RESTART_LOCAL: { - int reg = readUnsignedLeb128(bs); - LocalEntry prevle; - LocalEntry le; - - try { - prevle = lastEntryForReg[reg]; - - if (lastEntryForReg[reg].end == Integer.MAX_VALUE) { - throw new RuntimeException ("nonsensical " - + "RESTART_LOCAL on live register v"+reg); - } - le = new LocalEntry(address, reg, - prevle.nameIndex, prevle.typeIndex, 0); - - } catch (NullPointerException ex) { - throw new RuntimeException - ("Encountered RESTART_LOCAL on new v" +reg); - } - - locals.add(le); - lastEntryForReg[reg] = le; - } - break; - - case DBG_END_LOCAL: { - int reg = readUnsignedLeb128(bs); - boolean found = false; - for (int i = locals.size() - 1; i >= 0; i--) { - if (locals.get(i).reg == reg) { - locals.get(i).end = address; - found = true; - break; - } - } - - if (!found) { - throw new RuntimeException( - "Encountered LOCAL_END without local start: v" - + reg); - } - } - break; - - case DBG_END_SEQUENCE: - // all done - return; - - case DBG_ADVANCE_PC: - address += readUnsignedLeb128(bs); - break; - - case DBG_ADVANCE_LINE: - line += readSignedLeb128(bs); - break; - - case DBG_SET_PROLOGUE_END: - //TODO do something with this. - break; - - case DBG_SET_EPILOGUE_BEGIN: - //TODO do something with this. - break; - - case DBG_SET_FILE: - //TODO do something with this. - break; - - default: - if (opcode < DBG_FIRST_SPECIAL) { - throw new RuntimeException( - "Invalid extended opcode encountered " - + opcode); - } - - int adjopcode = opcode - DBG_FIRST_SPECIAL; - - address += adjopcode / DBG_LINE_RANGE; - line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE); - - positions.add(new PositionEntry(address, line)); - break; - - } - } - } - - /** - * Validates an encoded debug info stream against data used to encode it, - * throwing an exception if they do not match. Used to validate the - * encoder. - * - * @param linecodes encoded debug info - * @param codeSize size of insn block in code units - * @param countRegisters size of used register block in register units - * @param pl position list to verify against - * @param ll locals list to verify against. - */ - public static void validateEncode(byte[] linecodes, int codeSize, - int countRegisters, PositionList pl, LocalList ll, - boolean isStatic, CstMethodRef ref, DexFile file) { - - try { - validateEncode0(linecodes, codeSize, countRegisters, - isStatic, ref, file, pl, ll); - } catch (RuntimeException ex) { -// System.err.println(ex.toString() -// + " while processing " + ref.toHuman()); - throw ExceptionWithContext.withContext(ex, - "while processing " + ref.toHuman()); - } - } - - - private static void validateEncode0(byte[] linecodes, int codeSize, - int countRegisters, boolean isStatic, CstMethodRef ref, - DexFile file, PositionList pl, LocalList ll) { - DebugInfoDecoder decoder - = new DebugInfoDecoder(linecodes, codeSize, countRegisters, - isStatic, ref, file); - - decoder.decode(); - - List<PositionEntry> decodedEntries; - - decodedEntries = decoder.getPositionList(); - - if (decodedEntries.size() != pl.size()) { - throw new RuntimeException( - "Decoded positions table not same size was " - + decodedEntries.size() + " expected " + pl.size()); - } - - for (PositionEntry entry: decodedEntries) { - boolean found = false; - for (int i = pl.size() - 1; i >= 0; i--) { - PositionList.Entry ple = pl.get(i); - - if (entry.line == ple.getPosition().getLine() - && entry.address == ple.getAddress()) { - found = true; - break; - } - } - - if (!found) { - throw new RuntimeException ("Could not match position entry: " - + entry.address + ", " + entry.line); - } - } - - List<LocalEntry> decodedLocals; - - decodedLocals = decoder.getLocals(); - - int paramBase = decoder.getParamBase(); - - int matchedLocalsEntries = 0; - - for (LocalEntry entry: decodedLocals) { - boolean found = false; - for (int i = ll.size() - 1; i >= 0; i--) { - LocalList.Entry le = ll.get(i); - - /* - * If an entry is a method parameter, then the original - * entry may not be marked as starting at 0. However, the - * end address should still match. - */ - if ((entry.start == le.getStart() - || (entry.start == 0 && entry.reg >= paramBase)) - && entry.end == le.getEnd() - && entry.reg == le.getRegister()) { - found = true; - matchedLocalsEntries++; - break; - } - } - - if (!found) { - throw new RuntimeException("Could not match local entry"); - } - } - - if (matchedLocalsEntries != ll.size()) { - throw new RuntimeException("Locals tables did not match"); - } - } - - /** - * Reads a DWARFv3-style signed LEB128 integer to the specified stream. - * See DWARF v3 section 7.6. An invalid sequence produces an IOException. - * - * @param bs stream to input from - * @return read value - * @throws IOException on invalid sequence in addition to - * those caused by the InputStream - */ - public static int readSignedLeb128(InputStream bs) throws IOException { - int result = 0; - int cur; - int count = 0; - int signBits = -1; - - do { - cur = bs.read(); - result |= (cur & 0x7f) << (count * 7); - signBits <<= 7; - count++; - } while (((cur & 0x80) == 0x80) && count < 5); - - if ((cur & 0x80) == 0x80) { - throw new IOException ("invalid LEB128 sequence"); - } - - // Sign extend if appropriate - if (((signBits >> 1) & result) != 0 ) { - result |= signBits; - } - - return result; - } - - /** - * Reads a DWARFv3-style unsigned LEB128 integer to the specified stream. - * See DWARF v3 section 7.6. An invalid sequence produces an IOException. - * - * @param bs stream to input from - * @return read value, which should be treated as an unsigned value. - * @throws IOException on invalid sequence in addition to - * those caused by the InputStream - */ - public static int readUnsignedLeb128(InputStream bs) throws IOException { - int result = 0; - int cur; - int count = 0; - - do { - cur = bs.read(); - result |= (cur & 0x7f) << (count * 7); - count++; - } while (((cur & 0x80) == 0x80) && count < 5); - - if ((cur & 0x80) == 0x80) { - throw new IOException ("invalid LEB128 sequence"); - } - - return result; - } -} diff --git a/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java b/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java deleted file mode 100644 index 49781bdd8..000000000 --- a/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java +++ /dev/null @@ -1,1035 +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.android.dx.dex.file; - -import com.android.dx.dex.code.LocalList; -import com.android.dx.dex.code.PositionList; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.BitSet; - -import static com.android.dx.dex.file.DebugInfoConstants.*; - -/** - * An encoder for the dex debug info state machine format. The format - * for each method enrty is as follows: - * <ol> - * <li> signed LEB128: initial value for line register. - * <li> n instances of signed LEB128: string indicies (offset by 1) - * for each method argument in left-to-right order - * with <code>this</code> excluded. A value of '0' indicates "no name" - * <li> A sequence of special or normal opcodes as defined in - * <code>DebugInfoConstants</code>. - * <li> A single terminating <code>OP_END_SEQUENCE</code> - * </ol> - */ -public final class DebugInfoEncoder { - private static final boolean DEBUG = false; - - /** null-ok; positions (line numbers) to encode */ - private final PositionList positionlist; - - /** null-ok; local variables to encode */ - private final LocalList locallist; - - private final ByteArrayAnnotatedOutput output; - private final DexFile file; - private final int codeSize; - private final int regSize; - - private final Prototype desc; - private final boolean isStatic; - - /** current encoding state: bytecode address */ - private int address = 0; - - /** current encoding state: line number */ - private int line = 1; - - /** - * if non-null: the output to write annotations to. No normal - * output is written to this. - */ - private AnnotatedOutput annotateTo; - - /** if non-null: another possible output for annotations */ - private PrintWriter debugPrint; - - /** if non-null: the prefix for each annotation or debugPrint line */ - private String prefix; - - /** true if output should be consumed during annotation */ - private boolean shouldConsume; - - /** indexed by register; last local alive in register */ - private final LocalList.Entry[] lastEntryForReg; - - /** - * Creates an instance. - * - * @param pl null-ok; positions (line numbers) to encode - * @param ll null-ok; local variables to encode - * @param file null-ok; may only be <code>null</code> if simply using - * this class to do a debug print - * @param codeSize - * @param regSize - * @param isStatic - * @param ref - */ - public DebugInfoEncoder(PositionList pl, LocalList ll, - DexFile file, int codeSize, int regSize, - boolean isStatic, CstMethodRef ref) { - this.positionlist = pl; - this.locallist = ll; - this.file = file; - output = new ByteArrayAnnotatedOutput(); - this.desc = ref.getPrototype(); - this.isStatic = isStatic; - - this.codeSize = codeSize; - this.regSize = regSize; - - lastEntryForReg = new LocalList.Entry[regSize]; - } - - /** - * Annotates or writes a message to the <code>debugPrint</code> writer - * if applicable. - * - * @param length the number of bytes associated with this message - * @param message the message itself - */ - private void annotate(int length, String message) { - if (prefix != null) { - message = prefix + message; - } - - if (annotateTo != null) { - annotateTo.annotate(shouldConsume ? length : 0, message); - } - - if (debugPrint != null) { - debugPrint.println(message); - } - } - - /** - * Converts this (PositionList, LocalList) pair into a state machine - * sequence. - * - * @return encoded byte sequence without padding and - * terminated with a <code>'\00'</code> - */ - public byte[] convert() { - try { - byte[] ret; - ret = convert0(); - - if (DEBUG) { - for (int i = 0 ; i < ret.length; i++) { - System.err.printf("byte %02x\n", (0xff & ret[i])); - } - } - - return ret; - } catch (IOException ex) { - throw ExceptionWithContext - .withContext(ex, "...while encoding debug info"); - } - } - - /** - * Converts and produces annotations on a stream. Does not write - * actual bits to the <code>AnnotatedOutput</code>. - * - * @param prefix null-ok; prefix to attach to each line of output - * @param debugPrint null-ok; if specified, an alternate output for - * annotations - * @param out null-ok; if specified, where annotations should go - * @param consume whether to claim to have consumed output for - * <code>out</code> - * @return output sequence - */ - public byte[] convertAndAnnotate(String prefix, PrintWriter debugPrint, - AnnotatedOutput out, boolean consume) { - this.prefix = prefix; - this.debugPrint = debugPrint; - annotateTo = out; - shouldConsume = consume; - - byte[] result = convert(); - - return result; - } - - private byte[] convert0() throws IOException { - ArrayList<PositionList.Entry> sortedPositions = buildSortedPositions(); - ArrayList<LocalList.Entry> sortedLocalsStart = buildLocalsStart(); - - // Parameter locals are removed from sortedLocalsStart here. - ArrayList<LocalList.Entry> methodArgs - = extractMethodArguments(sortedLocalsStart); - - ArrayList<LocalList.Entry> sortedLocalsEnd - = buildLocalsEnd(sortedLocalsStart); - - emitHeader(sortedPositions, methodArgs); - - // TODO: Make this mark the actual prologue end. - output.writeByte(DBG_SET_PROLOGUE_END); - - if (annotateTo != null || debugPrint != null) { - annotate(1, String.format("%04x: prologue end",address)); - } - - int szp = sortedPositions.size(); - int szl = sortedLocalsStart.size(); - - // Current index in sortedPositions - int curp = 0; - // Current index in sortedLocalsStart - int curls = 0; - // Current index in sortedLocalsEnd - int curle = 0; - - for (;;) { - /* - * Emit any information for the current address. - */ - - curle = emitLocalEndsAtAddress(curle, sortedLocalsEnd, curls, - sortedLocalsStart); - - /* - * Our locals-sorted-by-range-end has reached the end - * of the code block. Ignore everything else. - */ - if (address == codeSize) { - curle = szl; - } - - curls = emitLocalStartsAtAddress(curls, sortedLocalsStart); - - curp = emitPositionsAtAddress(curp, sortedPositions); - - /* - * Figure out what the next important address is. - */ - - int nextAddrLS = Integer.MAX_VALUE; // local start - int nextAddrLE = Integer.MAX_VALUE; // local end - int nextAddrP = Integer.MAX_VALUE; // position (line number) - - if (curls < szl) { - nextAddrLS = sortedLocalsStart.get(curls).getStart(); - } - - if (curle < szl) { - nextAddrLE = sortedLocalsEnd.get(curle).getEnd(); - } - - if (curp < szp) { - nextAddrP = sortedPositions.get(curp).getAddress(); - } - - int next = Math.min(nextAddrP, Math.min(nextAddrLS, nextAddrLE)); - - // No next important address == done. - if (next == Integer.MAX_VALUE) { - break; - } - - /* - * If the only work remaining are local ends at the end of the - * block, stop here. Those are implied anyway. - */ - if (next == codeSize - && nextAddrLS == Integer.MAX_VALUE - && nextAddrP == Integer.MAX_VALUE) { - break; - } - - if (next == nextAddrP) { - // Combined advance PC + position entry - emitPosition(sortedPositions.get(curp++)); - } else { - emitAdvancePc(next - address); - } - } - - emitEndSequence(); - - return output.toByteArray(); - } - - /** - * Emits all local ends that occur at the current <code>address</code> - * - * @param curle Current index in sortedLocalsEnd - * @param sortedLocalsEnd Locals, sorted by ascending end address - * @param curls Current index in sortedLocalsStart - * @param sortedLocalsStart Locals, sorted by ascending start address - * @return new value for <code>curle</code> - * @throws IOException - */ - private int emitLocalEndsAtAddress(int curle, - ArrayList<LocalList.Entry> sortedLocalsEnd, int curls, - ArrayList<LocalList.Entry> sortedLocalsStart) - throws IOException { - - int szl = sortedLocalsEnd.size(); - - // Ignore "local ends" at end of code. - while (curle < szl - && sortedLocalsEnd.get(curle).getEnd() == address - && address != codeSize) { - - boolean skipLocalEnd = false; - - /* - * Check to see if there's a range-start that appears at - * the same address for the same register. If so, the - * end-range is implicit so skip it. - */ - for (int j = curls; j < szl - && sortedLocalsStart.get(j).getStart() == address - ; j++) { - - if (sortedLocalsStart.get(j).getRegister() - == sortedLocalsEnd.get(curle).getRegister()) { - skipLocalEnd = true; - - if (DEBUG) { - System.err.printf("skip local end v%d\n", - sortedLocalsEnd.get(curle).getRegister()); - } - break; - } - } - - if (!skipLocalEnd) { - emitLocalEnd(sortedLocalsEnd.get(curle)); - } - - curle++; - } - return curle; - } - - /** - * Emits all local starts that occur at the current <code>address</code> - * - * @param curls Current index in sortedLocalsStart - * @param sortedLocalsStart Locals, sorted by ascending start address - * @return new value for <code>curls</code> - * @throws IOException - */ - private int emitLocalStartsAtAddress(int curls, - ArrayList<LocalList.Entry> sortedLocalsStart) - throws IOException { - - int szl = sortedLocalsStart.size(); - - while (curls < szl - && sortedLocalsStart.get(curls).getStart() == address) { - LocalList.Entry lle = sortedLocalsStart.get(curls++); - int reg = lle.getRegister(); - LocalList.Entry prevlle = lastEntryForReg[reg]; - - if (lle == prevlle) { - /* - * Here we ignore locals entries for parameters, - * which have already been represented and placed in the - * lastEntryForReg array. - */ - continue; - } - - // At this point we have a new live entry one way or another. - lastEntryForReg[reg] = lle; - - if ((prevlle != null) && lle.matches(prevlle)) { - if (prevlle.getEnd() == lle.getStart()) { - /* - * There is nothing more to do in this case: It's - * an adjacent range with the same register. The - * previous emitLocalEndsAtAddress() call skipped - * this local end, so we'll skip this local start - * as well. - */ - } else { - emitLocalRestart(lle); - } - } else { - emitLocalStart(lle); - } - } - return curls; - } - - /** - * Emits all positions that occur at the current <code>address</code> - * - * @param curp Current index in sortedPositions - * @param sortedPositions positions, sorted by ascending address - * @return new value for <code>curp</code> - * @throws IOException - */ - private int emitPositionsAtAddress(int curp, - ArrayList<PositionList.Entry> sortedPositions) - throws IOException { - - int szp = sortedPositions.size(); - while (curp < szp - && sortedPositions.get(curp).getAddress() == address) { - emitPosition(sortedPositions.get(curp++)); - } - return curp; - } - - /** - * Emits the header sequence, which consists of LEB128-encoded initial - * line number and string indicies for names of all non-"this" arguments. - * - * @param sortedPositions positions, sorted by ascending address - * @param methodArgs local list entries for method argumens arguments, - * in left-to-right order omitting "this" - * @throws IOException - */ - private void emitHeader(ArrayList<PositionList.Entry> sortedPositions, - ArrayList<LocalList.Entry> methodArgs) throws IOException { - boolean annotate = (annotateTo != null) || (debugPrint != null); - int mark = output.getCursor(); - - // Start by initializing the line number register. - if (sortedPositions.size() > 0) { - PositionList.Entry entry = sortedPositions.get(0); - line = entry.getPosition().getLine(); - } - output.writeUnsignedLeb128(line); - - if (annotate) { - annotate(output.getCursor() - mark, "line_start: " + line); - } - - int curParam = getParamBase(); - // paramTypes will not include 'this' - StdTypeList paramTypes = desc.getParameterTypes(); - int szParamTypes = paramTypes.size(); - - /* - * Initialize lastEntryForReg to have an initial - * entry for the 'this' pointer. - */ - if (!isStatic) { - for (LocalList.Entry arg: methodArgs) { - if (curParam == arg.getRegister()) { - lastEntryForReg[curParam] = arg; - break; - } - } - curParam++; - } - - // Write out the number of parameter entries that will follow. - mark = output.getCursor(); - output.writeUnsignedLeb128(szParamTypes); - - if (annotate) { - annotate(output.getCursor() - mark, - String.format("parameters_size: %04x", szParamTypes)); - } - - /* - * Then emit the string indicies of all the method parameters. - * Note that 'this', if applicable, is excluded. - */ - for (int i = 0; i < szParamTypes; i++) { - Type pt = paramTypes.get(i); - LocalList.Entry found = null; - - mark = output.getCursor(); - - for (LocalList.Entry arg: methodArgs) { - if (curParam == arg.getRegister()) { - found = arg; - - if (arg.getSignature() != null) { - /* - * Parameters with signatures will be re-emitted - * in complete as LOCAL_START_EXTENDED's below. - */ - emitStringIndex(null); - } else { - emitStringIndex(arg.getName()); - } - lastEntryForReg[curParam] = arg; - - break; - } - } - - if (found == null) { - /* - * Emit a null symbol for "unnamed." This is common - * for, e.g., synthesized methods and inner-class - * this$0 arguments. - */ - emitStringIndex(null); - } - - if (annotate) { - String parameterName - = (found == null || found.getSignature() != null) - ? "<unnamed>" : found.getName().toHuman(); - annotate(output.getCursor() - mark, - "parameter " + parameterName + " " - + RegisterSpec.PREFIX + curParam); - } - - curParam += pt.getCategory(); - } - - /* - * If anything emitted above has a type signature, emit it again as - * a LOCAL_RESTART_EXTENDED - */ - - for (LocalList.Entry arg: lastEntryForReg) { - if (arg == null) { - continue; - } - - CstUtf8 signature = arg.getSignature(); - - if (signature != null) { - emitLocalStartExtended(arg); - } - } - } - - /** - * Builds a list of position entries, sorted by ascending address. - * - * @return A sorted positions list - */ - private ArrayList<PositionList.Entry> buildSortedPositions() { - int sz = (positionlist == null) ? 0 : positionlist.size(); - ArrayList<PositionList.Entry> result = new ArrayList(sz); - - for (int i = 0; i < sz; i++) { - result.add(positionlist.get(i)); - } - - // Sort ascending by address. - Collections.sort (result, new Comparator<PositionList.Entry>() { - public int compare (PositionList.Entry a, PositionList.Entry b) { - return a.getAddress() - b.getAddress(); - } - - public boolean equals (Object obj) { - return obj == this; - } - }); - return result; - } - - /** - * Builds a list of locals entries sorted by ascending start address. - * - * @return A sorted locals list list - */ - private ArrayList<LocalList.Entry> buildLocalsStart() { - int sz = (locallist == null) ? 0 : locallist.size(); - ArrayList<LocalList.Entry> result = new ArrayList(sz); - - // Add all the entries - for (int i = 0; i < sz; i++) { - LocalList.Entry e = locallist.get(i); - result.add(locallist.get(i)); - } - - // Sort ascending by start address. - Collections.sort (result, new Comparator<LocalList.Entry>() { - public int compare (LocalList.Entry a, LocalList.Entry b) { - return a.getStart() - b.getStart(); - } - - public boolean equals (Object obj) { - return obj == this; - } - }); - return result; - } - - /** - * Builds a list of locals entries sorted by ascending end address. - * - * @param list locals list in any order - * @return a sorted locals list - */ - private ArrayList<LocalList.Entry> buildLocalsEnd( - ArrayList<LocalList.Entry> list) { - - ArrayList<LocalList.Entry> sortedLocalsEnd = new ArrayList(list); - - // Sort ascending by end address. - Collections.sort (sortedLocalsEnd, new Comparator<LocalList.Entry>() { - public int compare (LocalList.Entry a, LocalList.Entry b) { - return a.getEnd() - b.getEnd(); - } - - public boolean equals (Object obj) { - return obj == this; - } - }); - return sortedLocalsEnd; - } - - /** - * Gets the register that begins the method's parameter range (including - * the 'this' parameter for non-static methods). The range continues until - * <code>regSize</code> - * - * @return register as noted above - */ - private int getParamBase() { - return regSize - - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1); - } - - /** - * Extracts method arguments from a locals list. These will be collected - * from the input list and sorted by ascending register in the - * returned list. - * - * @param sortedLocals locals list, sorted by ascending start address, - * to process; left unmodified - * @return list of non-<code>this</code> method argument locals, - * sorted by ascending register - */ - private ArrayList<LocalList.Entry> extractMethodArguments ( - ArrayList<LocalList.Entry> sortedLocals) { - - ArrayList<LocalList.Entry> result - = new ArrayList(desc.getParameterTypes().size()); - - int argBase = getParamBase(); - - BitSet seen = new BitSet(regSize - argBase); - - int sz = sortedLocals.size(); - for (int i = 0; i < sz; i++) { - LocalList.Entry e = sortedLocals.get(i); - int reg = e.getRegister(); - - if (reg < argBase) { - continue; - } - - // only the lowest-start-address entry is included. - if (seen.get(reg - argBase)) { - continue; - } - - seen.set(reg - argBase); - result.add(e); - } - - // Sort by ascending register. - Collections.sort (result, new Comparator<LocalList.Entry>() { - public int compare (LocalList.Entry a, LocalList.Entry b) { - return a.getRegister() - b.getRegister(); - } - - public boolean equals (Object obj) { - return obj == this; - } - }); - - return result; - } - - /** - * Returns a string representation of this LocalList entry that is - * appropriate for emitting as an annotation. - * - * @param e non-null; entry - * @return non-null; annotation string - */ - private String entryAnnotationString(LocalList.Entry e) { - StringBuilder sb = new StringBuilder(); - - sb.append(RegisterSpec.PREFIX); - sb.append(e.getRegister()); - sb.append(' '); - - CstUtf8 name = e.getName(); - if (name == null) { - sb.append("null"); - } else { - sb.append(name.toHuman()); - } - sb.append(' '); - - CstType type = e.getType(); - if (type == null) { - sb.append("null"); - } else { - sb.append(type.toHuman()); - } - - CstUtf8 signature = e.getSignature(); - - if (signature != null) { - sb.append(' '); - sb.append(signature.toHuman()); - } - - return sb.toString(); - } - - /** - * Emits a {@link DebugInfoConstants#DBG_RESTART_LOCAL DBG_RESTART_LOCAL} - * sequence. - * - * @param entry entry associated with this restart - * @throws IOException - */ - private void emitLocalRestart(LocalList.Entry entry) - throws IOException { - - int mark = output.getCursor(); - - output.writeByte(DBG_RESTART_LOCAL); - emitUnsignedLeb128(entry.getRegister()); - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("%04x: +local restart %s", - address, entryAnnotationString(entry))); - } - - if (DEBUG) { - System.err.println("emit local restart"); - } - } - - /** - * Emits a string index as an unsigned LEB128. The actual value written - * is shifted by 1, so that the '0' value is reserved for "null". The - * null symbol is used in some cases by the parameter name list - * at the beginning of the sequence. - * - * @param string null-ok; string to emit - * @throws IOException - */ - private void emitStringIndex(CstUtf8 string) throws IOException { - if ((string == null) || (file == null)) { - output.writeUnsignedLeb128(0); - } else { - output.writeUnsignedLeb128( - 1 + file.getStringIds().indexOf(string)); - } - - if (DEBUG) { - System.err.printf("Emit string %s\n", - string == null ? "<null>" : string.toQuoted()); - } - } - - /** - * Emits a type index as an unsigned LEB128. The actual value written - * is shifted by 1, so that the '0' value is reserved for "null". - * - * @param type null-ok; type to emit - * @throws IOException - */ - private void emitTypeIndex(CstType type) throws IOException { - if ((type == null) || (file == null)) { - output.writeUnsignedLeb128(0); - } else { - output.writeUnsignedLeb128( - 1 + file.getTypeIds().indexOf(type)); - } - - if (DEBUG) { - System.err.printf("Emit type %s\n", - type == null ? "<null>" : type.toHuman()); - } - } - - /** - * Emits a {@link DebugInfoConstants#DBG_START_LOCAL DBG_START_LOCAL} or - * {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED - * DBG_START_LOCAL_EXTENDED} sequence. - * - * @param entry entry to emit - * @throws IOException - */ - private void emitLocalStart(LocalList.Entry entry) - throws IOException { - - if (entry.getSignature() != null) { - emitLocalStartExtended(entry); - return; - } - - int mark = output.getCursor(); - - output.writeByte(DBG_START_LOCAL); - - emitUnsignedLeb128(entry.getRegister()); - emitStringIndex(entry.getName()); - emitTypeIndex(entry.getType()); - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("%04x: +local %s", address, - entryAnnotationString(entry))); - } - - if (DEBUG) { - System.err.println("emit local start"); - } - } - - /** - * Emits a {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED - * DBG_START_LOCAL_EXTENDED} sequence. - * - * @param entry entry to emit - * @throws IOException - */ - private void emitLocalStartExtended(LocalList.Entry entry) - throws IOException { - - int mark = output.getCursor(); - - output.writeByte(DBG_START_LOCAL_EXTENDED); - - emitUnsignedLeb128(entry.getRegister()); - emitStringIndex(entry.getName()); - emitTypeIndex(entry.getType()); - emitStringIndex(entry.getSignature()); - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("%04x: +localx %s", address, - entryAnnotationString(entry))); - } - - if (DEBUG) { - System.err.println("emit local start"); - } - } - - /** - * Emits a {@link DebugInfoConstants#DBG_END_LOCAL DBG_END_LOCAL} sequence. - * - * @param entry entry non-null; entry associated with end. - * @throws IOException - */ - private void emitLocalEnd(LocalList.Entry entry) - throws IOException { - - int mark = output.getCursor(); - - output.writeByte(DBG_END_LOCAL); - output.writeUnsignedLeb128(entry.getRegister()); - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("%04x: -local %s", address, - entryAnnotationString(entry))); - } - - if (DEBUG) { - System.err.println("emit local end"); - } - } - - /** - * Emits the necessary byte sequences to emit the given position table - * entry. This will typically be a single special opcode, although - * it may also require DBG_ADVANCE_PC or DBG_ADVANCE_LINE. - * - * @param entry position entry to emit. - * @throws IOException - */ - private void emitPosition(PositionList.Entry entry) - throws IOException { - - SourcePosition pos = entry.getPosition(); - int newLine = pos.getLine(); - int newAddress = entry.getAddress(); - - int opcode; - - int deltaLines = newLine - line; - int deltaAddress = newAddress - address; - - if (deltaAddress < 0) { - throw new RuntimeException( - "Position entries must be in ascending address order"); - } - - if ((deltaLines < DBG_LINE_BASE) - || (deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1))) { - emitAdvanceLine(deltaLines); - deltaLines = 0; - } - - opcode = computeOpcode (deltaLines, deltaAddress); - - if ((opcode & ~0xff) > 0) { - emitAdvancePc(deltaAddress); - deltaAddress = 0; - opcode = computeOpcode (deltaLines, deltaAddress); - - if ((opcode & ~0xff) > 0) { - emitAdvanceLine(deltaLines); - deltaLines = 0; - opcode = computeOpcode (deltaLines, deltaAddress); - } - } - - output.writeByte(opcode); - - line += deltaLines; - address += deltaAddress; - - if (annotateTo != null || debugPrint != null) { - annotate(1, - String.format("%04x: line %d", address, line)); - } - } - - /** - * Computes a special opcode that will encode the given position change. - * If the return value is > 0xff, then the request cannot be fulfilled. - * Essentially the same as described in "DWARF Debugging Format Version 3" - * section 6.2.5.1. - * - * @param deltaLines >= DBG_LINE_BASE and <= DBG_LINE_BASE + - * DBG_LINE_RANGE, the line change to encode - * @param deltaAddress >= 0; the address change to encode - * @return <= 0xff if in range, otherwise parameters are out of range - */ - private static int computeOpcode(int deltaLines, int deltaAddress) { - if (deltaLines < DBG_LINE_BASE - || deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1)) { - - throw new RuntimeException("Parameter out of range"); - } - - return (deltaLines - DBG_LINE_BASE) - + (DBG_LINE_RANGE * deltaAddress) + DBG_FIRST_SPECIAL; - } - - /** - * Emits an {@link DebugInfoConstants#DBG_ADVANCE_LINE DBG_ADVANCE_LINE} - * sequence. - * - * @param deltaLines amount to change line number register by - * @throws IOException - */ - private void emitAdvanceLine(int deltaLines) throws IOException { - int mark = output.getCursor(); - - output.writeByte(DBG_ADVANCE_LINE); - output.writeSignedLeb128(deltaLines); - line += deltaLines; - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("line = %d", line)); - } - - if (DEBUG) { - System.err.printf("Emitting advance_line for %d\n", deltaLines); - } - } - - /** - * Emits an {@link DebugInfoConstants#DBG_ADVANCE_PC DBG_ADVANCE_PC} - * sequence. - * - * @param deltaAddress >= 0 amount to change program counter by - * @throws IOException - */ - private void emitAdvancePc(int deltaAddress) throws IOException { - int mark = output.getCursor(); - - output.writeByte(DBG_ADVANCE_PC); - output.writeUnsignedLeb128(deltaAddress); - address += deltaAddress; - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("%04x: advance pc", address)); - } - - if (DEBUG) { - System.err.printf("Emitting advance_pc for %d\n", deltaAddress); - } - } - - /** - * Emits an unsigned LEB128 value. - * - * @param n >= 0 vallue to emit. Note that, although this can represent - * integers larger than Integer.MAX_VALUE, we currently don't allow that. - * @throws IOException - */ - private void emitUnsignedLeb128(int n) throws IOException { - // We'll never need the top end of the unsigned range anyway. - if (n < 0) { - throw new RuntimeException( - "Signed value where unsigned required: " + n); - } - - output.writeSignedLeb128(n); - } - - /** - * Emits the {@link DebugInfoConstants#DBG_END_SEQUENCE DBG_END_SEQUENCE} - * bytecode. - */ - private void emitEndSequence() { - output.writeByte(DBG_END_SEQUENCE); - - if (annotateTo != null || debugPrint != null) { - annotate(1, "end sequence"); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/DebugInfoItem.java b/dx/src/com/android/dx/dex/file/DebugInfoItem.java deleted file mode 100644 index b0745935d..000000000 --- a/dx/src/com/android/dx/dex/file/DebugInfoItem.java +++ /dev/null @@ -1,170 +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.android.dx.dex.file; - -import com.android.dx.dex.code.DalvCode; -import com.android.dx.dex.code.DalvInsnList; -import com.android.dx.dex.code.LocalList; -import com.android.dx.dex.code.PositionList; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; - -import java.io.PrintWriter; - -public class DebugInfoItem extends OffsettedItem { - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 1; - - private static final boolean ENABLE_ENCODER_SELF_CHECK = false; - - /** non-null; the code this item represents */ - private final DalvCode code; - - private byte[] encoded; - - private final boolean isStatic; - private final CstMethodRef ref; - - public DebugInfoItem(DalvCode code, boolean isStatic, CstMethodRef ref) { - // We don't know the write size yet. - super (ALIGNMENT, -1); - - if (code == null) { - throw new NullPointerException("code == null"); - } - - this.code = code; - this.isStatic = isStatic; - this.ref = ref; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_DEBUG_INFO_ITEM; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - // No contents to add. - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // Encode the data and note the size. - - try { - encoded = encode(addedTo.getFile(), null, null, null, false); - setWriteSize(encoded.length); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, - "...while placing debug info for " + ref.toHuman()); - } - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - throw new RuntimeException("unsupported"); - } - - /** - * Writes annotations for the elements of this list, as - * zero-length. This is meant to be used for dumping this instance - * directly after a code dump (with the real local list actually - * existing elsewhere in the output). - * - * @param file non-null; the file to use for referencing other sections - * @param out non-null; where to annotate to - * @param prefix null-ok; prefix to attach to each line of output - */ - public void annotateTo(DexFile file, AnnotatedOutput out, String prefix) { - encode(file, prefix, null, out, false); - } - - /** - * Does a human-friendly dump of this instance. - * - * @param out non-null; where to dump - * @param prefix non-null; prefix to attach to each line of output - */ - public void debugPrint(PrintWriter out, String prefix) { - encode(null, prefix, out, null, false); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - if (out.annotates()) { - /* - * Re-run the encoder to generate the annotations, - * but write the bits from the original encode - */ - - out.annotate(offsetString() + " debug info"); - encode(file, null, null, out, true); - } - - out.write(encoded); - } - - /** - * Performs debug info encoding. - * - * @param file null-ok; file to refer to during encoding - * @param prefix null-ok; prefix to attach to each line of output - * @param debugPrint null-ok; if specified, an alternate output for - * annotations - * @param out null-ok; if specified, where annotations should go - * @param consume whether to claim to have consumed output for - * <code>out</code> - * @return non-null; the encoded array - */ - private byte[] encode(DexFile file, String prefix, PrintWriter debugPrint, - AnnotatedOutput out, boolean consume) { - PositionList positions = code.getPositions(); - LocalList locals = code.getLocals(); - DalvInsnList insns = code.getInsns(); - int codeSize = insns.codeSize(); - int regSize = insns.getRegistersSize(); - - DebugInfoEncoder encoder = - new DebugInfoEncoder(positions, locals, - file, codeSize, regSize, isStatic, ref); - - byte[] result; - - if ((debugPrint == null) && (out == null)) { - result = encoder.convert(); - } else { - result = encoder.convertAndAnnotate( - prefix, debugPrint, out, consume); - } - - if (ENABLE_ENCODER_SELF_CHECK && (file != null)) { - DebugInfoDecoder.validateEncode(encoded, codeSize, - regSize, positions, locals, isStatic, ref, file); - } - - return result; - } -} diff --git a/dx/src/com/android/dx/dex/file/DexFile.java b/dx/src/com/android/dx/dex/file/DexFile.java deleted file mode 100644 index 8a4075d67..000000000 --- a/dx/src/com/android/dx/dex/file/DexFile.java +++ /dev/null @@ -1,647 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstBaseMethodRef; -import com.android.dx.rop.cst.CstEnumRef; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Type; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.security.DigestException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.zip.Adler32; - -import static com.android.dx.dex.file.MixedItemSection.SortType; - -/** - * Representation of an entire <code>.dex</code> (Dalvik EXecutable) - * file, which itself consists of a set of Dalvik classes. - */ -public final class DexFile { - /** non-null; word data section */ - private final MixedItemSection wordData; - - /** - * non-null; type lists section. This is word data, but separating - * it from {@link #wordData} helps break what would otherwise be a - * circular dependency between the that and {@link #protoIds}. - */ - private final MixedItemSection typeLists; - - /** - * non-null; map section. The map needs to be in a section by itself - * for the self-reference mechanics to work in a reasonably - * straightforward way. See {@link MapItem#addMap} for more detail. - */ - private final MixedItemSection map; - - /** non-null; string data section */ - private final MixedItemSection stringData; - - /** non-null; string identifiers section */ - private final StringIdsSection stringIds; - - /** non-null; type identifiers section */ - private final TypeIdsSection typeIds; - - /** non-null; prototype identifiers section */ - private final ProtoIdsSection protoIds; - - /** non-null; field identifiers section */ - private final FieldIdsSection fieldIds; - - /** non-null; method identifiers section */ - private final MethodIdsSection methodIds; - - /** non-null; class definitions section */ - private final ClassDefsSection classDefs; - - /** non-null; class data section */ - private final MixedItemSection classData; - - /** non-null; byte data section */ - private final MixedItemSection byteData; - - /** non-null; file header */ - private final HeaderSection header; - - /** - * non-null; array of sections in the order they will appear in the - * final output file - */ - private final Section[] sections; - - /** >= -1; total file size or <code>-1</code> if unknown */ - private int fileSize; - - /** >= 40; maximum width of the file dump */ - private int dumpWidth; - - /** - * Constructs an instance. It is initially empty. - */ - public DexFile() { - header = new HeaderSection(this); - typeLists = new MixedItemSection(null, this, 4, SortType.NONE); - wordData = new MixedItemSection("word_data", this, 4, SortType.TYPE); - stringData = - new MixedItemSection("string_data", this, 1, SortType.INSTANCE); - classData = new MixedItemSection(null, this, 1, SortType.NONE); - byteData = new MixedItemSection("byte_data", this, 1, SortType.TYPE); - stringIds = new StringIdsSection(this); - typeIds = new TypeIdsSection(this); - protoIds = new ProtoIdsSection(this); - fieldIds = new FieldIdsSection(this); - methodIds = new MethodIdsSection(this); - classDefs = new ClassDefsSection(this); - map = new MixedItemSection("map", this, 4, SortType.NONE); - - /* - * This is the list of sections in the order they appear in - * the final output. - */ - sections = new Section[] { - header, stringIds, typeIds, protoIds, fieldIds, methodIds, - classDefs, wordData, typeLists, stringData, byteData, - classData, map }; - - fileSize = -1; - dumpWidth = 79; - } - - /** - * Adds a class to this instance. It is illegal to attempt to add more - * than one class with the same name. - * - * @param clazz non-null; the class to add - */ - public void add(ClassDefItem clazz) { - classDefs.add(clazz); - } - - /** - * Gets the class definition with the given name, if any. - * - * @param name non-null; the class name to look for - * @return null-ok; the class with the given name, or <code>null</code> - * if there is no such class - */ - public ClassDefItem getClassOrNull(String name) { - try { - Type type = Type.internClassName(name); - return (ClassDefItem) classDefs.get(new CstType(type)); - } catch (IllegalArgumentException ex) { - // Translate exception, per contract. - return null; - } - } - - /** - * Writes the contents of this instance as either a binary or a - * human-readable form, or both. - * - * @param out null-ok; where to write to - * @param humanOut null-ok; where to write human-oriented output to - * @param verbose whether to be verbose when writing human-oriented output - */ - public void writeTo(OutputStream out, Writer humanOut, boolean verbose) - throws IOException { - boolean annotate = (humanOut != null); - ByteArrayAnnotatedOutput result = toDex0(annotate, verbose); - - if (out != null) { - out.write(result.getArray()); - } - - if (annotate) { - result.writeAnnotationsTo(humanOut); - } - } - - /** - * Returns the contents of this instance as a <code>.dex</code> file, - * in <code>byte[]</code> form. - * - * @param humanOut null-ok; where to write human-oriented output to - * @param verbose whether to be verbose when writing human-oriented output - * @return non-null; a <code>.dex</code> file for this instance - */ - public byte[] toDex(Writer humanOut, boolean verbose) - throws IOException { - boolean annotate = (humanOut != null); - ByteArrayAnnotatedOutput result = toDex0(annotate, verbose); - - if (annotate) { - result.writeAnnotationsTo(humanOut); - } - - return result.getArray(); - } - - /** - * Sets the maximum width of the human-oriented dump of the instance. - * - * @param dumpWidth >= 40; the width - */ - public void setDumpWidth(int dumpWidth) { - if (dumpWidth < 40) { - throw new IllegalArgumentException("dumpWidth < 40"); - } - - this.dumpWidth = dumpWidth; - } - - /** - * Gets the total file size, if known. - * - * <p>This is package-scope in order to allow - * the {@link HeaderSection} to set itself up properly.</p> - * - * @return >= 0; the total file size - * @throws RuntimeException thrown if the file size is not yet known - */ - /*package*/ int getFileSize() { - if (fileSize < 0) { - throw new RuntimeException("file size not yet known"); - } - - return fileSize; - } - - /** - * Gets the string data section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the string data section - */ - /*package*/ MixedItemSection getStringData() { - return stringData; - } - - /** - * Gets the word data section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the word data section - */ - /*package*/ MixedItemSection getWordData() { - return wordData; - } - - /** - * Gets the type lists section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the word data section - */ - /*package*/ MixedItemSection getTypeLists() { - return typeLists; - } - - /** - * Gets the map section. - * - * <p>This is package-scope in order to allow the header section - * to query it.</p> - * - * @return non-null; the map section - */ - /*package*/ MixedItemSection getMap() { - return map; - } - - /** - * Gets the string identifiers section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the string identifiers section - */ - /*package*/ StringIdsSection getStringIds() { - return stringIds; - } - - /** - * Gets the class definitions section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the class definitions section - */ - /*package*/ ClassDefsSection getClassDefs() { - return classDefs; - } - - /** - * Gets the class data section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the class data section - */ - /*package*/ MixedItemSection getClassData() { - return classData; - } - - /** - * Gets the type identifiers section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the class identifiers section - */ - /*package*/ TypeIdsSection getTypeIds() { - return typeIds; - } - - /** - * Gets the prototype identifiers section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the prototype identifiers section - */ - /*package*/ ProtoIdsSection getProtoIds() { - return protoIds; - } - - /** - * Gets the field identifiers section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the field identifiers section - */ - /*package*/ FieldIdsSection getFieldIds() { - return fieldIds; - } - - /** - * Gets the method identifiers section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the method identifiers section - */ - /*package*/ MethodIdsSection getMethodIds() { - return methodIds; - } - - /** - * Gets the byte data section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the byte data section - */ - /*package*/ MixedItemSection getByteData() { - return byteData; - } - - /** - * Gets the first section of the file that is to be considered - * part of the data section. - * - * <p>This is package-scope in order to allow the header section - * to query it.</p> - * - * @return non-null; the section - */ - /*package*/ Section getFirstDataSection() { - return wordData; - } - - /** - * Gets the last section of the file that is to be considered - * part of the data section. - * - * <p>This is package-scope in order to allow the header section - * to query it.</p> - * - * @return non-null; the section - */ - /*package*/ Section getLastDataSection() { - return map; - } - - /** - * Interns the given constant in the appropriate section of this - * instance, or do nothing if the given constant isn't the sort - * that should be interned. - * - * @param cst non-null; constant to possibly intern - */ - /*package*/ void internIfAppropriate(Constant cst) { - if (cst instanceof CstString) { - stringIds.intern((CstString) cst); - } else if (cst instanceof CstUtf8) { - stringIds.intern((CstUtf8) cst); - } else if (cst instanceof CstType) { - typeIds.intern((CstType) cst); - } else if (cst instanceof CstBaseMethodRef) { - methodIds.intern((CstBaseMethodRef) cst); - } else if (cst instanceof CstFieldRef) { - fieldIds.intern((CstFieldRef) cst); - } else if (cst instanceof CstEnumRef) { - fieldIds.intern(((CstEnumRef) cst).getFieldRef()); - } else if (cst == null) { - throw new NullPointerException("cst == null"); - } - } - - /** - * Gets the {@link IndexedItem} corresponding to the given constant, - * if it is a constant that has such a correspondence, or return - * <code>null</code> if it isn't such a constant. This will throw - * an exception if the given constant <i>should</i> have been found - * but wasn't. - * - * @param cst non-null; the constant to look up - * @return null-ok; its corresponding item, if it has a corresponding - * item, or <code>null</code> if it's not that sort of constant - */ - /*package*/ IndexedItem findItemOrNull(Constant cst) { - IndexedItem item; - - if (cst instanceof CstString) { - return stringIds.get(cst); - } else if (cst instanceof CstType) { - return typeIds.get(cst); - } else if (cst instanceof CstBaseMethodRef) { - return methodIds.get(cst); - } else if (cst instanceof CstFieldRef) { - return fieldIds.get(cst); - } else { - return null; - } - } - - /** - * Returns the contents of this instance as a <code>.dex</code> file, - * in a {@link ByteArrayAnnotatedOutput} instance. - * - * @param annotate whether or not to keep annotations - * @param verbose if annotating, whether to be verbose - * @return non-null; a <code>.dex</code> file for this instance - */ - private ByteArrayAnnotatedOutput toDex0(boolean annotate, - boolean verbose) { - /* - * The following is ordered so that the prepare() calls which - * add items happen before the calls to the sections that get - * added to. - */ - - classDefs.prepare(); - classData.prepare(); - wordData.prepare(); - byteData.prepare(); - methodIds.prepare(); - fieldIds.prepare(); - protoIds.prepare(); - typeLists.prepare(); - typeIds.prepare(); - stringIds.prepare(); - stringData.prepare(); - header.prepare(); - - // Place the sections within the file. - - int count = sections.length; - int offset = 0; - - for (int i = 0; i < count; i++) { - Section one = sections[i]; - int placedAt = one.setFileOffset(offset); - if (placedAt < offset) { - throw new RuntimeException("bogus placement for section " + i); - } - - try { - if (one == map) { - /* - * Inform the map of all the sections, and add it - * to the file. This can only be done after all - * the other items have been sorted and placed. - */ - MapItem.addMap(sections, map); - map.prepare(); - } - - if (one instanceof MixedItemSection) { - /* - * Place the items of a MixedItemSection that just - * got placed. - */ - ((MixedItemSection) one).placeItems(); - } - - offset = placedAt + one.writeSize(); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, - "...while writing section " + i); - } - } - - // Write out all the sections. - - fileSize = offset; - byte[] barr = new byte[fileSize]; - ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(barr); - - if (annotate) { - out.enableAnnotations(dumpWidth, verbose); - } - - for (int i = 0; i < count; i++) { - try { - Section one = sections[i]; - int zeroCount = one.getFileOffset() - out.getCursor(); - if (zeroCount < 0) { - throw new ExceptionWithContext("excess write of " + - (-zeroCount)); - } - out.writeZeroes(one.getFileOffset() - out.getCursor()); - one.writeTo(out); - } catch (RuntimeException ex) { - ExceptionWithContext ec; - if (ex instanceof ExceptionWithContext) { - ec = (ExceptionWithContext) ex; - } else { - ec = new ExceptionWithContext(ex); - } - ec.addContext("...while writing section " + i); - throw ec; - } - } - - if (out.getCursor() != fileSize) { - throw new RuntimeException("foreshortened write"); - } - - // Perform final bookkeeping. - - calcSignature(barr); - calcChecksum(barr); - - if (annotate) { - wordData.writeIndexAnnotation(out, ItemType.TYPE_CODE_ITEM, - "\nmethod code index:\n\n"); - getStatistics().writeAnnotation(out); - out.finishAnnotating(); - } - - return out; - } - - /** - * Generates and returns statistics for all the items in the file. - * - * @return non-null; the statistics - */ - public Statistics getStatistics() { - Statistics stats = new Statistics(); - - for (Section s : sections) { - stats.addAll(s); - } - - return stats; - } - - /** - * Calculates the signature for the <code>.dex</code> file in the - * given array, and modify the array to contain it. - * - * @param bytes non-null; the bytes of the file - */ - private static void calcSignature(byte[] bytes) { - MessageDigest md; - - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); - } - - md.update(bytes, 32, bytes.length - 32); - - try { - int amt = md.digest(bytes, 12, 20); - if (amt != 20) { - throw new RuntimeException("unexpected digest write: " + amt + - " bytes"); - } - } catch (DigestException ex) { - throw new RuntimeException(ex); - } - } - - /** - * Calculates the checksum for the <code>.dex</code> file in the - * given array, and modify the array to contain it. - * - * @param bytes non-null; the bytes of the file - */ - private static void calcChecksum(byte[] bytes) { - Adler32 a32 = new Adler32(); - - a32.update(bytes, 12, bytes.length - 12); - - int sum = (int) a32.getValue(); - - bytes[8] = (byte) sum; - bytes[9] = (byte) (sum >> 8); - bytes[10] = (byte) (sum >> 16); - bytes[11] = (byte) (sum >> 24); - } -} diff --git a/dx/src/com/android/dx/dex/file/EncodedArrayItem.java b/dx/src/com/android/dx/dex/file/EncodedArrayItem.java deleted file mode 100644 index 9ec72fa42..000000000 --- a/dx/src/com/android/dx/dex/file/EncodedArrayItem.java +++ /dev/null @@ -1,131 +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.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.AnnotationVisibility; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.AnnotatedOutput; - -import java.util.Arrays; -import java.util.Comparator; - -/** - * Encoded array of constant values. - */ -public final class EncodedArrayItem extends OffsettedItem { - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 1; - - /** non-null; the array to represent */ - private final CstArray array; - - /** - * null-ok; encoded form, ready for writing to a file; set during - * {@link #place0} - */ - private byte[] encodedForm; - - /** - * Constructs an instance. - * - * @param array non-null; array to represent - */ - public EncodedArrayItem(CstArray array) { - /* - * The write size isn't known up-front because (the variable-lengthed) - * leb128 type is used to represent some things. - */ - super(ALIGNMENT, -1); - - if (array == null) { - throw new NullPointerException("array == null"); - } - - this.array = array; - this.encodedForm = null; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_ENCODED_ARRAY_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return array.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(OffsettedItem other) { - EncodedArrayItem otherArray = (EncodedArrayItem) other; - - return array.compareTo(otherArray.array); - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return array.toHuman(); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - ValueEncoder.addContents(file, array); - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // Encode the data and note the size. - - ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(); - ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out); - - encoder.writeArray(array, false); - encodedForm = out.toByteArray(); - setWriteSize(encodedForm.length); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - - if (annotates) { - out.annotate(0, offsetString() + " encoded array"); - - /* - * The output is to be annotated, so redo the work previously - * done by place0(), except this time annotations will actually - * get emitted. - */ - ValueEncoder encoder = new ValueEncoder(file, out); - encoder.writeArray(array, true); - } else { - out.write(encodedForm); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/EncodedField.java b/dx/src/com/android/dx/dex/file/EncodedField.java deleted file mode 100644 index 62a5789d4..000000000 --- a/dx/src/com/android/dx/dex/file/EncodedField.java +++ /dev/null @@ -1,154 +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.android.dx.dex.file; - -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.Leb128Utils; - -import java.io.PrintWriter; - -/** - * Representation of a field of a class, of any sort. - */ -public final class EncodedField extends EncodedMember - implements Comparable<EncodedField> { - /** non-null; constant for the field */ - private final CstFieldRef field; - - /** - * Constructs an instance. - * - * @param field non-null; constant for the field - * @param accessFlags access flags - */ - public EncodedField(CstFieldRef field, int accessFlags) { - super(accessFlags); - - if (field == null) { - throw new NullPointerException("field == null"); - } - - /* - * TODO: Maybe check accessFlags, at least for - * easily-checked stuff? - */ - - this.field = field; - } - - /** {@inheritDoc} */ - public int hashCode() { - return field.hashCode(); - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof EncodedField)) { - return false; - } - - return compareTo((EncodedField) other) == 0; - } - - /** - * {@inheritDoc} - * - * <p><b>Note:</b> This compares the method constants only, - * ignoring any associated code, because it should never be the - * case that two different items with the same method constant - * ever appear in the same list (or same file, even).</p> - */ - public int compareTo(EncodedField other) { - return field.compareTo(other.field); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(100); - - sb.append(getClass().getName()); - sb.append('{'); - sb.append(Hex.u2(getAccessFlags())); - sb.append(' '); - sb.append(field); - sb.append('}'); - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - FieldIdsSection fieldIds = file.getFieldIds(); - fieldIds.intern(field); - } - - /** {@inheritDoc} */ - @Override - public CstUtf8 getName() { - return field.getNat().getName(); - } - - /** {@inheritDoc} */ - public String toHuman() { - return field.toHuman(); - } - - /** {@inheritDoc} */ - @Override - public void debugPrint(PrintWriter out, boolean verbose) { - // TODO: Maybe put something better here? - out.println(toString()); - } - - /** - * Gets the constant for the field. - * - * @return non-null; the constant - */ - public CstFieldRef getRef() { - return field; - } - - /** {@inheritDoc} */ - @Override - public int encode(DexFile file, AnnotatedOutput out, - int lastIndex, int dumpSeq) { - int fieldIdx = file.getFieldIds().indexOf(field); - int diff = fieldIdx - lastIndex; - int accessFlags = getAccessFlags(); - - if (out.annotates()) { - out.annotate(0, String.format(" [%x] %s", dumpSeq, - field.toHuman())); - out.annotate(Leb128Utils.unsignedLeb128Size(diff), - " field_idx: " + Hex.u4(fieldIdx)); - out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags), - " access_flags: " + - AccessFlags.fieldString(accessFlags)); - } - - out.writeUnsignedLeb128(diff); - out.writeUnsignedLeb128(accessFlags); - - return fieldIdx; - } -} diff --git a/dx/src/com/android/dx/dex/file/EncodedMember.java b/dx/src/com/android/dx/dex/file/EncodedMember.java deleted file mode 100644 index 3ae0d0902..000000000 --- a/dx/src/com/android/dx/dex/file/EncodedMember.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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ToHuman; - -import java.io.PrintWriter; - -/** - * Representation of a member (field or method) of a class, for the - * purposes of encoding it inside a {@link ClassDataItem}. - */ -public abstract class EncodedMember implements ToHuman { - /** access flags */ - private final int accessFlags; - - /** - * Constructs an instance. - * - * @param accessFlags access flags for the member - */ - public EncodedMember(int accessFlags) { - this.accessFlags = accessFlags; - } - - /** - * Gets the access flags. - * - * @return the access flags - */ - public final int getAccessFlags() { - return accessFlags; - } - - /** - * Gets the name. - * - * @return non-null; the name - */ - public abstract CstUtf8 getName(); - - /** - * Does a human-friendly dump of this instance. - * - * @param out non-null; where to dump - * @param verbose whether to be verbose with the output - */ - public abstract void debugPrint(PrintWriter out, boolean verbose); - - /** - * Populates a {@link DexFile} with items from within this instance. - * - * @param file non-null; the file to populate - */ - public abstract void addContents(DexFile file); - - /** - * Encodes this instance to the given output. - * - * @param file non-null; file this instance is part of - * @param out non-null; where to write to - * @param lastIndex >= 0; the previous member index value encoded, or - * <code>0</code> if this is the first element to encode - * @param dumpSeq >= 0; sequence number of this instance for - * annotation purposes - * @return >= 0; the member index value that was encoded - */ - public abstract int encode(DexFile file, AnnotatedOutput out, - int lastIndex, int dumpSeq); -} diff --git a/dx/src/com/android/dx/dex/file/EncodedMethod.java b/dx/src/com/android/dx/dex/file/EncodedMethod.java deleted file mode 100644 index 319fbb72b..000000000 --- a/dx/src/com/android/dx/dex/file/EncodedMethod.java +++ /dev/null @@ -1,196 +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.android.dx.dex.file; - -import com.android.dx.dex.code.DalvCode; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.Leb128Utils; - -import java.io.PrintWriter; - -/** - * Class that representats a method of a class. - */ -public final class EncodedMethod extends EncodedMember - implements Comparable<EncodedMethod> { - /** non-null; constant for the method */ - private final CstMethodRef method; - - /** - * null-ok; code for the method, if the method is neither - * <code>abstract</code> nor <code>native</code> - */ - private final CodeItem code; - - /** - * Constructs an instance. - * - * @param method non-null; constant for the method - * @param accessFlags access flags - * @param code null-ok; code for the method, if it is neither - * <code>abstract</code> nor <code>native</code> - * @param throwsList non-null; list of possibly-thrown exceptions, - * just used in generating debugging output (listings) - */ - public EncodedMethod(CstMethodRef method, int accessFlags, - DalvCode code, TypeList throwsList) { - super(accessFlags); - - if (method == null) { - throw new NullPointerException("method == null"); - } - - this.method = method; - - if (code == null) { - this.code = null; - } else { - boolean isStatic = (accessFlags & AccessFlags.ACC_STATIC) != 0; - this.code = new CodeItem(method, code, isStatic, throwsList); - } - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof EncodedMethod)) { - return false; - } - - return compareTo((EncodedMethod) other) == 0; - } - - /** - * {@inheritDoc} - * - * <p><b>Note:</b> This compares the method constants only, - * ignoring any associated code, because it should never be the - * case that two different items with the same method constant - * ever appear in the same list (or same file, even).</p> - */ - public int compareTo(EncodedMethod other) { - return method.compareTo(other.method); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(100); - - sb.append(getClass().getName()); - sb.append('{'); - sb.append(Hex.u2(getAccessFlags())); - sb.append(' '); - sb.append(method); - - if (code != null) { - sb.append(' '); - sb.append(code); - } - - sb.append('}'); - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - MethodIdsSection methodIds = file.getMethodIds(); - MixedItemSection wordData = file.getWordData(); - - methodIds.intern(method); - - if (code != null) { - wordData.add(code); - } - } - - /** {@inheritDoc} */ - public final String toHuman() { - return method.toHuman(); - } - - /** {@inheritDoc} */ - @Override - public final CstUtf8 getName() { - return method.getNat().getName(); - } - - /** {@inheritDoc} */ - @Override - public void debugPrint(PrintWriter out, boolean verbose) { - if (code == null) { - out.println(getRef().toHuman() + ": abstract or native"); - } else { - code.debugPrint(out, " ", verbose); - } - } - - /** - * Gets the constant for the method. - * - * @return non-null; the constant - */ - public final CstMethodRef getRef() { - return method; - } - - /** {@inheritDoc} */ - @Override - public int encode(DexFile file, AnnotatedOutput out, - int lastIndex, int dumpSeq) { - int methodIdx = file.getMethodIds().indexOf(method); - int diff = methodIdx - lastIndex; - int accessFlags = getAccessFlags(); - int codeOff = OffsettedItem.getAbsoluteOffsetOr0(code); - boolean hasCode = (codeOff != 0); - boolean shouldHaveCode = (accessFlags & - (AccessFlags.ACC_ABSTRACT | AccessFlags.ACC_NATIVE)) == 0; - - /* - * Verify that code appears if and only if a method is - * declared to have it. - */ - if (hasCode != shouldHaveCode) { - throw new UnsupportedOperationException( - "code vs. access_flags mismatch"); - } - - if (out.annotates()) { - out.annotate(0, String.format(" [%x] %s", dumpSeq, - method.toHuman())); - out.annotate(Leb128Utils.unsignedLeb128Size(diff), - " method_idx: " + Hex.u4(methodIdx)); - out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags), - " access_flags: " + - AccessFlags.methodString(accessFlags)); - out.annotate(Leb128Utils.unsignedLeb128Size(codeOff), - " code_off: " + Hex.u4(codeOff)); - } - - out.writeUnsignedLeb128(diff); - out.writeUnsignedLeb128(accessFlags); - out.writeUnsignedLeb128(codeOff); - - return methodIdx; - } -} diff --git a/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java b/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java deleted file mode 100644 index e6169bd21..000000000 --- a/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java +++ /dev/null @@ -1,122 +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.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.ToHuman; - -/** - * Association of a field and its annotations. - */ -public final class FieldAnnotationStruct - implements ToHuman, Comparable<FieldAnnotationStruct> { - /** non-null; the field in question */ - private final CstFieldRef field; - - /** non-null; the associated annotations */ - private AnnotationSetItem annotations; - - /** - * Constructs an instance. - * - * @param field non-null; the field in question - * @param annotations non-null; the associated annotations - */ - public FieldAnnotationStruct(CstFieldRef field, - AnnotationSetItem annotations) { - if (field == null) { - throw new NullPointerException("field == null"); - } - - if (annotations == null) { - throw new NullPointerException("annotations == null"); - } - - this.field = field; - this.annotations = annotations; - } - - /** {@inheritDoc} */ - public int hashCode() { - return field.hashCode(); - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof FieldAnnotationStruct)) { - return false; - } - - return field.equals(((FieldAnnotationStruct) other).field); - } - - /** {@inheritDoc} */ - public int compareTo(FieldAnnotationStruct other) { - return field.compareTo(other.field); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - FieldIdsSection fieldIds = file.getFieldIds(); - MixedItemSection wordData = file.getWordData(); - - fieldIds.intern(field); - annotations = wordData.intern(annotations); - } - - /** {@inheritDoc} */ - public void writeTo(DexFile file, AnnotatedOutput out) { - int fieldIdx = file.getFieldIds().indexOf(field); - int annotationsOff = annotations.getAbsoluteOffset(); - - if (out.annotates()) { - out.annotate(0, " " + field.toHuman()); - out.annotate(4, " field_idx: " + Hex.u4(fieldIdx)); - out.annotate(4, " annotations_off: " + - Hex.u4(annotationsOff)); - } - - out.writeInt(fieldIdx); - out.writeInt(annotationsOff); - } - - /** {@inheritDoc} */ - public String toHuman() { - return field.toHuman() + ": " + annotations; - } - - /** - * Gets the field this item is for. - * - * @return non-null; the field - */ - public CstFieldRef getField() { - return field; - } - - /** - * Gets the associated annotations. - * - * @return non-null; the annotations - */ - public Annotations getAnnotations() { - return annotations.getAnnotations(); - } -} diff --git a/dx/src/com/android/dx/dex/file/FieldIdItem.java b/dx/src/com/android/dx/dex/file/FieldIdItem.java deleted file mode 100644 index d098d52ab..000000000 --- a/dx/src/com/android/dx/dex/file/FieldIdItem.java +++ /dev/null @@ -1,70 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstFieldRef; - -/** - * Representation of a field reference inside a Dalvik file. - */ -public final class FieldIdItem extends MemberIdItem { - /** - * Constructs an instance. - * - * @param field non-null; the constant for the field - */ - public FieldIdItem(CstFieldRef field) { - super(field); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_FIELD_ID_ITEM; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - super.addContents(file); - - TypeIdsSection typeIds = file.getTypeIds(); - typeIds.intern(getFieldRef().getType()); - } - - /** - * Gets the field constant. - * - * @return non-null; the constant - */ - public CstFieldRef getFieldRef() { - return (CstFieldRef) getRef(); - } - - /** {@inheritDoc} */ - @Override - protected int getTypoidIdx(DexFile file) { - TypeIdsSection typeIds = file.getTypeIds(); - return typeIds.indexOf(getFieldRef().getType()); - } - - /** {@inheritDoc} */ - @Override - protected String getTypoidName() { - return "type_idx"; - } -} diff --git a/dx/src/com/android/dx/dex/file/FieldIdsSection.java b/dx/src/com/android/dx/dex/file/FieldIdsSection.java deleted file mode 100644 index fddf55f47..000000000 --- a/dx/src/com/android/dx/dex/file/FieldIdsSection.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.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; -import java.util.TreeMap; - -/** - * Field refs list section of a <code>.dex</code> file. - */ -public final class FieldIdsSection extends MemberIdsSection { - /** - * non-null; map from field constants to {@link - * FieldIdItem} instances - */ - private final TreeMap<CstFieldRef, FieldIdItem> fieldIds; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public FieldIdsSection(DexFile file) { - super("field_ids", file); - - fieldIds = new TreeMap<CstFieldRef, FieldIdItem>(); - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return fieldIds.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - throwIfNotPrepared(); - - IndexedItem result = fieldIds.get((CstFieldRef) cst); - - if (result == null) { - throw new IllegalArgumentException("not found"); - } - - return result; - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = fieldIds.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (out.annotates()) { - out.annotate(4, "field_ids_size: " + Hex.u4(sz)); - out.annotate(4, "field_ids_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Interns an element into this instance. - * - * @param field non-null; the reference to intern - * @return non-null; the interned reference - */ - public FieldIdItem intern(CstFieldRef field) { - if (field == null) { - throw new NullPointerException("field == null"); - } - - throwIfPrepared(); - - FieldIdItem result = fieldIds.get(field); - - if (result == null) { - result = new FieldIdItem(field); - fieldIds.put(field, result); - } - - return result; - } - - /** - * Gets the index of the given reference, which must have been added - * to this instance. - * - * @param ref non-null; the reference to look up - * @return >= 0; the reference's index - */ - public int indexOf(CstFieldRef ref) { - if (ref == null) { - throw new NullPointerException("ref == null"); - } - - throwIfNotPrepared(); - - FieldIdItem item = fieldIds.get(ref); - - if (item == null) { - throw new IllegalArgumentException("not found"); - } - - return item.getIndex(); - } -} diff --git a/dx/src/com/android/dx/dex/file/HeaderItem.java b/dx/src/com/android/dx/dex/file/HeaderItem.java deleted file mode 100644 index 55c1f1c5f..000000000 --- a/dx/src/com/android/dx/dex/file/HeaderItem.java +++ /dev/null @@ -1,123 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * File header section of a <code>.dex</code> file. - */ -public final class HeaderItem extends IndexedItem { - /** - * non-null; the file format magic number, represented as the - * low-order bytes of a string - */ - private static final String MAGIC = "dex\n035\0"; - - /** size of this section, in bytes */ - private static final int HEADER_SIZE = 0x70; - - /** the endianness tag */ - private static final int ENDIAN_TAG = 0x12345678; - - /** - * Constructs an instance. - */ - public HeaderItem() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_HEADER_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return HEADER_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - // Nothing to do here. - } - - /** {@inheritDoc} */ - @Override - public void writeTo(DexFile file, AnnotatedOutput out) { - int mapOff = file.getMap().getFileOffset(); - Section firstDataSection = file.getFirstDataSection(); - Section lastDataSection = file.getLastDataSection(); - int dataOff = firstDataSection.getFileOffset(); - int dataSize = lastDataSection.getFileOffset() + - lastDataSection.writeSize() - dataOff; - - if (out.annotates()) { - out.annotate(8, "magic: " + new CstUtf8(MAGIC).toQuoted()); - out.annotate(4, "checksum"); - out.annotate(20, "signature"); - out.annotate(4, "file_size: " + - Hex.u4(file.getFileSize())); - out.annotate(4, "header_size: " + Hex.u4(HEADER_SIZE)); - out.annotate(4, "endian_tag: " + Hex.u4(ENDIAN_TAG)); - out.annotate(4, "link_size: 0"); - out.annotate(4, "link_off: 0"); - out.annotate(4, "map_off: " + Hex.u4(mapOff)); - } - - // Write the magic number. - for (int i = 0; i < 8; i++) { - out.writeByte(MAGIC.charAt(i)); - } - - // Leave space for the checksum and signature. - out.writeZeroes(24); - - out.writeInt(file.getFileSize()); - out.writeInt(HEADER_SIZE); - out.writeInt(ENDIAN_TAG); - - /* - * Write zeroes for the link size and data, as the output - * isn't a staticly linked file. - */ - out.writeZeroes(8); - - out.writeInt(mapOff); - - // Write out each section's respective header part. - file.getStringIds().writeHeaderPart(out); - file.getTypeIds().writeHeaderPart(out); - file.getProtoIds().writeHeaderPart(out); - file.getFieldIds().writeHeaderPart(out); - file.getMethodIds().writeHeaderPart(out); - file.getClassDefs().writeHeaderPart(out); - - if (out.annotates()) { - out.annotate(4, "data_size: " + Hex.u4(dataSize)); - out.annotate(4, "data_off: " + Hex.u4(dataOff)); - } - - out.writeInt(dataSize); - out.writeInt(dataOff); - } -} diff --git a/dx/src/com/android/dx/dex/file/HeaderSection.java b/dx/src/com/android/dx/dex/file/HeaderSection.java deleted file mode 100644 index 9022e0f2b..000000000 --- a/dx/src/com/android/dx/dex/file/HeaderSection.java +++ /dev/null @@ -1,63 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * File header section of a <code>.dex</code> file. - */ -public final class HeaderSection extends UniformItemSection { - /** non-null; the list of the one item in the section */ - private final List<HeaderItem> list; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public HeaderSection(DexFile file) { - super(null, file, 4); - - HeaderItem item = new HeaderItem(); - item.setIndex(0); - - this.list = Collections.singletonList(item); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - return null; - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return list; - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - // Nothing to do here. - } -} diff --git a/dx/src/com/android/dx/dex/file/IdItem.java b/dx/src/com/android/dx/dex/file/IdItem.java deleted file mode 100644 index 8342514be..000000000 --- a/dx/src/com/android/dx/dex/file/IdItem.java +++ /dev/null @@ -1,61 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstType; - -/** - * Representation of a reference to an item inside a Dalvik file. - */ -public abstract class IdItem extends IndexedItem { - /** - * non-null; the type constant for the defining class of - * the reference - */ - private final CstType type; - - /** - * Constructs an instance. - * - * @param type non-null; the type constant for the defining - * class of the reference - */ - public IdItem(CstType type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - this.type = type; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - TypeIdsSection typeIds = file.getTypeIds(); - typeIds.intern(type); - } - - /** - * Gets the type constant for the defining class of the - * reference. - * - * @return non-null; the type constant - */ - public final CstType getDefiningClass() { - return type; - } -} diff --git a/dx/src/com/android/dx/dex/file/IndexedItem.java b/dx/src/com/android/dx/dex/file/IndexedItem.java deleted file mode 100644 index 9bf7fd29a..000000000 --- a/dx/src/com/android/dx/dex/file/IndexedItem.java +++ /dev/null @@ -1,81 +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.android.dx.dex.file; - -/** - * An item in a Dalvik file which is referenced by index. - */ -public abstract class IndexedItem extends Item { - /** >= -1; assigned index of the item, or <code>-1</code> if not - * yet assigned */ - private int index; - - /** - * Constructs an instance. The index is initially unassigned. - */ - public IndexedItem() { - index = -1; - } - - /** - * Gets whether or not this instance has been assigned an index. - * - * @return <code>true</code> iff this instance has been assigned an index - */ - public final boolean hasIndex() { - return (index >= 0); - } - - /** - * Gets the item index. - * - * @return >= 0; the index - * @throws RuntimeException thrown if the item index is not yet assigned - */ - public final int getIndex() { - if (index < 0) { - throw new RuntimeException("index not yet set"); - } - - return index; - } - - /** - * Sets the item index. This method may only ever be called once - * per instance, and this will throw a <code>RuntimeException</code> if - * called a second (or subsequent) time. - * - * @param index >= 0; the item index - */ - public final void setIndex(int index) { - if (this.index != -1) { - throw new RuntimeException("index already set"); - } - - this.index = index; - } - - /** - * Gets the index of this item as a string, suitable for including in - * annotations. - * - * @return non-null; the index string - */ - public final String indexString() { - return '[' + Integer.toHexString(index) + ']'; - } -} diff --git a/dx/src/com/android/dx/dex/file/Item.java b/dx/src/com/android/dx/dex/file/Item.java deleted file mode 100644 index 3708d4561..000000000 --- a/dx/src/com/android/dx/dex/file/Item.java +++ /dev/null @@ -1,80 +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.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; - -/** - * Base class for any structurally-significant and (potentially) - * repeated piece of a Dalvik file. - */ -public abstract class Item { - /** - * Constructs an instance. - */ - public Item() { - // This space intentionally left blank. - } - - /** - * Returns the item type for this instance. - * - * @return non-null; the item type - */ - public abstract ItemType itemType(); - - /** - * Returns the human name for the particular type of item this - * instance is. - * - * @return non-null; the name - */ - public final String typeName() { - return itemType().toHuman(); - } - - /** - * Gets the size of this instance when written, in bytes. - * - * @return >= 0; the write size - */ - public abstract int writeSize(); - - /** - * Populates a {@link DexFile} with items from within this instance. - * This will <i>not</i> add an item to the file for this instance itself - * (which should have been done by whatever refers to this instance). - * - * <p><b>Note:</b> Subclasses must override this to do something - * appropriate.</p> - * - * @param file non-null; the file to populate - */ - public abstract void addContents(DexFile file); - - /** - * Writes the representation of this instance to the given data section, - * using the given {@link DexFile} to look things up as needed. - * If this instance keeps track of its offset, then this method will - * note the written offset and will also throw an exception if this - * instance has already been written. - * - * @param file non-null; the file to use for reference - * @param out non-null; where to write to - */ - public abstract void writeTo(DexFile file, AnnotatedOutput out); -} diff --git a/dx/src/com/android/dx/dex/file/ItemType.java b/dx/src/com/android/dx/dex/file/ItemType.java deleted file mode 100644 index ffa65735f..000000000 --- a/dx/src/com/android/dx/dex/file/ItemType.java +++ /dev/null @@ -1,97 +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.android.dx.dex.file; - -import com.android.dx.util.ToHuman; - -/** - * Enumeration of all the top-level item types. - */ -public enum ItemType implements ToHuman { - TYPE_HEADER_ITEM( 0x0000, "header_item"), - TYPE_STRING_ID_ITEM( 0x0001, "string_id_item"), - TYPE_TYPE_ID_ITEM( 0x0002, "type_id_item"), - TYPE_PROTO_ID_ITEM( 0x0003, "proto_id_item"), - TYPE_FIELD_ID_ITEM( 0x0004, "field_id_item"), - TYPE_METHOD_ID_ITEM( 0x0005, "method_id_item"), - TYPE_CLASS_DEF_ITEM( 0x0006, "class_def_item"), - TYPE_MAP_LIST( 0x1000, "map_list"), - TYPE_TYPE_LIST( 0x1001, "type_list"), - TYPE_ANNOTATION_SET_REF_LIST( 0x1002, "annotation_set_ref_list"), - TYPE_ANNOTATION_SET_ITEM( 0x1003, "annotation_set_item"), - TYPE_CLASS_DATA_ITEM( 0x2000, "class_data_item"), - TYPE_CODE_ITEM( 0x2001, "code_item"), - TYPE_STRING_DATA_ITEM( 0x2002, "string_data_item"), - TYPE_DEBUG_INFO_ITEM( 0x2003, "debug_info_item"), - TYPE_ANNOTATION_ITEM( 0x2004, "annotation_item"), - TYPE_ENCODED_ARRAY_ITEM( 0x2005, "encoded_array_item"), - TYPE_ANNOTATIONS_DIRECTORY_ITEM(0x2006, "annotations_directory_item"), - TYPE_MAP_ITEM( -1, "map_item"), - TYPE_TYPE_ITEM( -1, "type_item"), - TYPE_EXCEPTION_HANDLER_ITEM( -1, "exception_handler_item"), - TYPE_ANNOTATION_SET_REF_ITEM( -1, "annotation_set_ref_item"); - - /** value when represented in a {@link MapItem} */ - private final int mapValue; - - /** non-null; name of the type */ - private final String typeName; - - /** non-null; the short human name */ - private final String humanName; - - /** - * Constructs an instance. - * - * @param mapValue value when represented in a {@link MapItem} - * @param typeName non-null; name of the type - */ - private ItemType(int mapValue, String typeName) { - this.mapValue = mapValue; - this.typeName = typeName; - - // Make the human name. - String human = typeName; - if (human.endsWith("_item")) { - human = human.substring(0, human.length() - 5); - } - this.humanName = human.replace('_', ' '); - } - - /** - * Gets the map value. - * - * @return the map value - */ - public int getMapValue() { - return mapValue; - } - - /** - * Gets the type name. - * - * @return non-null; the type name - */ - public String getTypeName() { - return typeName; - } - - /** {@inheritDoc} */ - public String toHuman() { - return humanName; - } -} diff --git a/dx/src/com/android/dx/dex/file/MapItem.java b/dx/src/com/android/dx/dex/file/MapItem.java deleted file mode 100644 index 5e7465ce0..000000000 --- a/dx/src/com/android/dx/dex/file/MapItem.java +++ /dev/null @@ -1,235 +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.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.ArrayList; - -/** - * Class that represents a map item. - */ -public final class MapItem extends OffsettedItem { - /** file alignment of this class, in bytes */ - private static final int ALIGNMENT = 4; - - /** write size of this class, in bytes: three <code>uint</code>s */ - private static final int WRITE_SIZE = (4 * 3); - - /** non-null; item type this instance covers */ - private final ItemType type; - - /** non-null; section this instance covers */ - private final Section section; - - /** - * null-ok; first item covered or <code>null</code> if this is - * a self-reference - */ - private final Item firstItem; - - /** - * null-ok; last item covered or <code>null</code> if this is - * a self-reference - */ - private final Item lastItem; - - /** - * > 0; count of items covered; <code>1</code> if this - * is a self-reference - */ - private final int itemCount; - - /** - * Constructs a list item with instances of this class representing - * the contents of the given array of sections, adding it to the - * given map section. - * - * @param sections non-null; the sections - * @param mapSection non-null; the section that the resulting map - * should be added to; it should be empty on entry to this method - */ - public static void addMap(Section[] sections, - MixedItemSection mapSection) { - if (sections == null) { - throw new NullPointerException("sections == null"); - } - - if (mapSection.items().size() != 0) { - throw new IllegalArgumentException( - "mapSection.items().size() != 0"); - } - - ArrayList<MapItem> items = new ArrayList<MapItem>(50); - - for (Section section : sections) { - ItemType currentType = null; - Item firstItem = null; - Item lastItem = null; - int count = 0; - - for (Item item : section.items()) { - ItemType type = item.itemType(); - if (type != currentType) { - if (count != 0) { - items.add(new MapItem(currentType, section, - firstItem, lastItem, count)); - } - currentType = type; - firstItem = item; - count = 0; - } - lastItem = item; - count++; - } - - if (count != 0) { - // Add a MapItem for the final items in the section. - items.add(new MapItem(currentType, section, - firstItem, lastItem, count)); - } else if (section == mapSection) { - // Add a MapItem for the self-referential section. - items.add(new MapItem(mapSection)); - } - } - - mapSection.add( - new UniformListItem<MapItem>(ItemType.TYPE_MAP_LIST, items)); - } - - /** - * Constructs an instance. - * - * @param type non-null; item type this instance covers - * @param section non-null; section this instance covers - * @param firstItem non-null; first item covered - * @param lastItem non-null; last item covered - * @param itemCount > 0; count of items covered - */ - private MapItem(ItemType type, Section section, Item firstItem, - Item lastItem, int itemCount) { - super(ALIGNMENT, WRITE_SIZE); - - if (type == null) { - throw new NullPointerException("type == null"); - } - - if (section == null) { - throw new NullPointerException("section == null"); - } - - if (firstItem == null) { - throw new NullPointerException("firstItem == null"); - } - - if (lastItem == null) { - throw new NullPointerException("lastItem == null"); - } - - if (itemCount <= 0) { - throw new IllegalArgumentException("itemCount <= 0"); - } - - this.type = type; - this.section = section; - this.firstItem = firstItem; - this.lastItem = lastItem; - this.itemCount = itemCount; - } - - /** - * Constructs a self-referential instance. This instance is meant to - * represent the section containing the <code>map_list</code>. - * - * @param section non-null; section this instance covers - */ - private MapItem(Section section) { - super(ALIGNMENT, WRITE_SIZE); - - if (section == null) { - throw new NullPointerException("section == null"); - } - - this.type = ItemType.TYPE_MAP_LIST; - this.section = section; - this.firstItem = null; - this.lastItem = null; - this.itemCount = 1; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_MAP_ITEM; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(100); - - sb.append(getClass().getName()); - sb.append('{'); - sb.append(section.toString()); - sb.append(' '); - sb.append(type.toHuman()); - sb.append('}'); - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - // We have nothing to add. - } - - /** {@inheritDoc} */ - @Override - public final String toHuman() { - return toString(); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - int value = type.getMapValue(); - int offset; - - if (firstItem == null) { - offset = section.getFileOffset(); - } else { - offset = section.getAbsoluteItemOffset(firstItem); - } - - if (out.annotates()) { - out.annotate(0, offsetString() + ' ' + type.getTypeName() + - " map"); - out.annotate(2, " type: " + Hex.u2(value) + " // " + - type.toString()); - out.annotate(2, " unused: 0"); - out.annotate(4, " size: " + Hex.u4(itemCount)); - out.annotate(4, " offset: " + Hex.u4(offset)); - } - - out.writeShort(value); - out.writeShort(0); // unused - out.writeInt(itemCount); - out.writeInt(offset); - } -} diff --git a/dx/src/com/android/dx/dex/file/MemberIdItem.java b/dx/src/com/android/dx/dex/file/MemberIdItem.java deleted file mode 100644 index d43715259..000000000 --- a/dx/src/com/android/dx/dex/file/MemberIdItem.java +++ /dev/null @@ -1,111 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstMemberRef; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Representation of a member (field or method) reference inside a - * Dalvik file. - */ -public abstract class MemberIdItem extends IdItem { - /** size of instances when written out to a file, in bytes */ - public static final int WRITE_SIZE = 8; - - /** non-null; the constant for the member */ - private final CstMemberRef cst; - - /** - * Constructs an instance. - * - * @param cst non-null; the constant for the member - */ - public MemberIdItem(CstMemberRef cst) { - super(cst.getDefiningClass()); - - this.cst = cst; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return WRITE_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - super.addContents(file); - - StringIdsSection stringIds = file.getStringIds(); - stringIds.intern(getRef().getNat().getName()); - } - - /** {@inheritDoc} */ - @Override - public final void writeTo(DexFile file, AnnotatedOutput out) { - TypeIdsSection typeIds = file.getTypeIds(); - StringIdsSection stringIds = file.getStringIds(); - CstNat nat = cst.getNat(); - int classIdx = typeIds.indexOf(getDefiningClass()); - int nameIdx = stringIds.indexOf(nat.getName()); - int typoidIdx = getTypoidIdx(file); - - if (out.annotates()) { - out.annotate(0, indexString() + ' ' + cst.toHuman()); - out.annotate(2, " class_idx: " + Hex.u2(classIdx)); - out.annotate(2, String.format(" %-10s %s", getTypoidName() + ':', - Hex.u2(typoidIdx))); - out.annotate(4, " name_idx: " + Hex.u4(nameIdx)); - } - - out.writeShort(classIdx); - out.writeShort(typoidIdx); - out.writeInt(nameIdx); - } - - /** - * Returns the index of the type-like thing associated with - * this item, in order that it may be written out. Subclasses must - * override this to get whatever it is they need to store. - * - * @param file non-null; the file being written - * @return the index in question - */ - protected abstract int getTypoidIdx(DexFile file); - - /** - * Returns the field name of the type-like thing associated with - * this item, for listing-generating purposes. Subclasses must override - * this. - * - * @return non-null; the name in question - */ - protected abstract String getTypoidName(); - - /** - * Gets the member constant. - * - * @return non-null; the constant - */ - public final CstMemberRef getRef() { - return cst; - } -} diff --git a/dx/src/com/android/dx/dex/file/MemberIdsSection.java b/dx/src/com/android/dx/dex/file/MemberIdsSection.java deleted file mode 100644 index 885b5590a..000000000 --- a/dx/src/com/android/dx/dex/file/MemberIdsSection.java +++ /dev/null @@ -1,44 +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.android.dx.dex.file; - -/** - * Member (field or method) refs list section of a <code>.dex</code> file. - */ -public abstract class MemberIdsSection extends UniformItemSection { - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param name null-ok; the name of this instance, for annotation - * purposes - * @param file non-null; file that this instance is part of - */ - public MemberIdsSection(String name, DexFile file) { - super(name, file, 4); - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - int idx = 0; - - for (Object i : items()) { - ((MemberIdItem) i).setIndex(idx); - idx++; - } - } -} diff --git a/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java b/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java deleted file mode 100644 index 175c1d29d..000000000 --- a/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java +++ /dev/null @@ -1,122 +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.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.ToHuman; - -/** - * Association of a method and its annotations. - */ -public final class MethodAnnotationStruct - implements ToHuman, Comparable<MethodAnnotationStruct> { - /** non-null; the method in question */ - private final CstMethodRef method; - - /** non-null; the associated annotations */ - private AnnotationSetItem annotations; - - /** - * Constructs an instance. - * - * @param method non-null; the method in question - * @param annotations non-null; the associated annotations - */ - public MethodAnnotationStruct(CstMethodRef method, - AnnotationSetItem annotations) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - if (annotations == null) { - throw new NullPointerException("annotations == null"); - } - - this.method = method; - this.annotations = annotations; - } - - /** {@inheritDoc} */ - public int hashCode() { - return method.hashCode(); - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof MethodAnnotationStruct)) { - return false; - } - - return method.equals(((MethodAnnotationStruct) other).method); - } - - /** {@inheritDoc} */ - public int compareTo(MethodAnnotationStruct other) { - return method.compareTo(other.method); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MethodIdsSection methodIds = file.getMethodIds(); - MixedItemSection wordData = file.getWordData(); - - methodIds.intern(method); - annotations = wordData.intern(annotations); - } - - /** {@inheritDoc} */ - public void writeTo(DexFile file, AnnotatedOutput out) { - int methodIdx = file.getMethodIds().indexOf(method); - int annotationsOff = annotations.getAbsoluteOffset(); - - if (out.annotates()) { - out.annotate(0, " " + method.toHuman()); - out.annotate(4, " method_idx: " + Hex.u4(methodIdx)); - out.annotate(4, " annotations_off: " + - Hex.u4(annotationsOff)); - } - - out.writeInt(methodIdx); - out.writeInt(annotationsOff); - } - - /** {@inheritDoc} */ - public String toHuman() { - return method.toHuman() + ": " + annotations; - } - - /** - * Gets the method this item is for. - * - * @return non-null; the method - */ - public CstMethodRef getMethod() { - return method; - } - - /** - * Gets the associated annotations. - * - * @return non-null; the annotations - */ - public Annotations getAnnotations() { - return annotations.getAnnotations(); - } -} diff --git a/dx/src/com/android/dx/dex/file/MethodIdItem.java b/dx/src/com/android/dx/dex/file/MethodIdItem.java deleted file mode 100644 index 5d78e961c..000000000 --- a/dx/src/com/android/dx/dex/file/MethodIdItem.java +++ /dev/null @@ -1,70 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstBaseMethodRef; - -/** - * Representation of a method reference inside a Dalvik file. - */ -public final class MethodIdItem extends MemberIdItem { - /** - * Constructs an instance. - * - * @param method non-null; the constant for the method - */ - public MethodIdItem(CstBaseMethodRef method) { - super(method); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_METHOD_ID_ITEM; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - super.addContents(file); - - ProtoIdsSection protoIds = file.getProtoIds(); - protoIds.intern(getMethodRef().getPrototype()); - } - - /** - * Gets the method constant. - * - * @return non-null; the constant - */ - public CstBaseMethodRef getMethodRef() { - return (CstBaseMethodRef) getRef(); - } - - /** {@inheritDoc} */ - @Override - protected int getTypoidIdx(DexFile file) { - ProtoIdsSection protoIds = file.getProtoIds(); - return protoIds.indexOf(getMethodRef().getPrototype()); - } - - /** {@inheritDoc} */ - @Override - protected String getTypoidName() { - return "proto_idx"; - } -} diff --git a/dx/src/com/android/dx/dex/file/MethodIdsSection.java b/dx/src/com/android/dx/dex/file/MethodIdsSection.java deleted file mode 100644 index 6ba7cac95..000000000 --- a/dx/src/com/android/dx/dex/file/MethodIdsSection.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.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstBaseMethodRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; -import java.util.TreeMap; - -/** - * Method refs list section of a <code>.dex</code> file. - */ -public final class MethodIdsSection extends MemberIdsSection { - /** - * non-null; map from method constants to {@link - * MethodIdItem} instances - */ - private final TreeMap<CstBaseMethodRef, MethodIdItem> methodIds; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public MethodIdsSection(DexFile file) { - super("method_ids", file); - - methodIds = new TreeMap<CstBaseMethodRef, MethodIdItem>(); - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return methodIds.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - throwIfNotPrepared(); - - IndexedItem result = methodIds.get((CstBaseMethodRef) cst); - - if (result == null) { - throw new IllegalArgumentException("not found"); - } - - return result; - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = methodIds.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (out.annotates()) { - out.annotate(4, "method_ids_size: " + Hex.u4(sz)); - out.annotate(4, "method_ids_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Interns an element into this instance. - * - * @param method non-null; the reference to intern - * @return non-null; the interned reference - */ - public MethodIdItem intern(CstBaseMethodRef method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - throwIfPrepared(); - - MethodIdItem result = methodIds.get(method); - - if (result == null) { - result = new MethodIdItem(method); - methodIds.put(method, result); - } - - return result; - } - - /** - * Gets the index of the given reference, which must have been added - * to this instance. - * - * @param ref non-null; the reference to look up - * @return >= 0; the reference's index - */ - public int indexOf(CstBaseMethodRef ref) { - if (ref == null) { - throw new NullPointerException("ref == null"); - } - - throwIfNotPrepared(); - - MethodIdItem item = methodIds.get(ref); - - if (item == null) { - throw new IllegalArgumentException("not found"); - } - - return item.getIndex(); - } -} diff --git a/dx/src/com/android/dx/dex/file/MixedItemSection.java b/dx/src/com/android/dx/dex/file/MixedItemSection.java deleted file mode 100644 index f03a9a387..000000000 --- a/dx/src/com/android/dx/dex/file/MixedItemSection.java +++ /dev/null @@ -1,362 +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.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; -import com.android.dx.util.Hex; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.TreeMap; - -/** - * A section of a <code>.dex</code> file which consists of a sequence of - * {@link OffsettedItem} objects, which may each be of a different concrete - * class and/or size. - * - * <b>Note:</b> It is invalid for an item in an instance of this class to - * have a larger alignment requirement than the alignment of this instance. - */ -public final class MixedItemSection extends Section { - static enum SortType { - /** no sorting */ - NONE, - - /** sort by type only */ - TYPE, - - /** sort in class-major order, with instances sorted per-class */ - INSTANCE; - }; - - /** non-null; sorter which sorts instances by type */ - private static final Comparator<OffsettedItem> TYPE_SORTER = - new Comparator<OffsettedItem>() { - public int compare(OffsettedItem item1, OffsettedItem item2) { - ItemType type1 = item1.itemType(); - ItemType type2 = item2.itemType(); - return type1.compareTo(type2); - } - }; - - /** non-null; the items in this part */ - private final ArrayList<OffsettedItem> items; - - /** non-null; items that have been explicitly interned */ - private final HashMap<OffsettedItem, OffsettedItem> interns; - - /** non-null; how to sort the items */ - private final SortType sort; - - /** - * >= -1; the current size of this part, in bytes, or <code>-1</code> - * if not yet calculated - */ - private int writeSize; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param name null-ok; the name of this instance, for annotation - * purposes - * @param file non-null; file that this instance is part of - * @param alignment > 0; alignment requirement for the final output; - * must be a power of 2 - * @param sort how the items should be sorted in the final output - */ - public MixedItemSection(String name, DexFile file, int alignment, - SortType sort) { - super(name, file, alignment); - - this.items = new ArrayList<OffsettedItem>(100); - this.interns = new HashMap<OffsettedItem, OffsettedItem>(100); - this.sort = sort; - this.writeSize = -1; - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return items; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - throwIfNotPrepared(); - return writeSize; - } - - /** {@inheritDoc} */ - @Override - public int getAbsoluteItemOffset(Item item) { - OffsettedItem oi = (OffsettedItem) item; - return oi.getAbsoluteOffset(); - } - - /** - * Gets the size of this instance, in items. - * - * @return >= 0; the size - */ - public int size() { - return items.size(); - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - if (writeSize == -1) { - throw new RuntimeException("write size not yet set"); - } - - int sz = writeSize; - int offset = (sz == 0) ? 0 : getFileOffset(); - String name = getName(); - - if (name == null) { - name = "<unnamed>"; - } - - int spaceCount = 15 - name.length(); - char[] spaceArr = new char[spaceCount]; - Arrays.fill(spaceArr, ' '); - String spaces = new String(spaceArr); - - if (out.annotates()) { - out.annotate(4, name + "_size:" + spaces + Hex.u4(sz)); - out.annotate(4, name + "_off: " + spaces + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Adds an item to this instance. This will in turn tell the given item - * that it has been added to this instance. It is invalid to add the - * same item to more than one instance, nor to add the same items - * multiple times to a single instance. - * - * @param item non-null; the item to add - */ - public void add(OffsettedItem item) { - throwIfPrepared(); - - try { - if (item.getAlignment() > getAlignment()) { - throw new IllegalArgumentException( - "incompatible item alignment"); - } - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("item == null"); - } - - items.add(item); - } - - /** - * Interns an item in this instance, returning the interned instance - * (which may not be the one passed in). This will add the item if no - * equal item has been added. - * - * @param item non-null; the item to intern - * @return non-null; the equivalent interned instance - */ - public <T extends OffsettedItem> T intern(T item) { - throwIfPrepared(); - - OffsettedItem result = interns.get(item); - - if (result != null) { - return (T) result; - } - - add(item); - interns.put(item, item); - return item; - } - - /** - * Gets an item which was previously interned. - * - * @param item non-null; the item to look for - * @return non-null; the equivalent already-interned instance - */ - public <T extends OffsettedItem> T get(T item) { - throwIfNotPrepared(); - - OffsettedItem result = interns.get(item); - - if (result != null) { - return (T) result; - } - - throw new NoSuchElementException(item.toString()); - } - - /** - * Writes an index of contents of the items in this instance of the - * given type. If there are none, this writes nothing. If there are any, - * then the index is preceded by the given intro string. - * - * @param out non-null; where to write to - * @param itemType non-null; the item type of interest - * @param intro non-null; the introductory string for non-empty indices - */ - public void writeIndexAnnotation(AnnotatedOutput out, ItemType itemType, - String intro) { - throwIfNotPrepared(); - - TreeMap<String, OffsettedItem> index = - new TreeMap<String, OffsettedItem>(); - - for (OffsettedItem item : items) { - if (item.itemType() == itemType) { - String label = item.toHuman(); - index.put(label, item); - } - } - - if (index.size() == 0) { - return; - } - - out.annotate(0, intro); - - for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) { - String label = entry.getKey(); - OffsettedItem item = entry.getValue(); - out.annotate(0, item.offsetString() + ' ' + label + '\n'); - } - } - - /** {@inheritDoc} */ - @Override - protected void prepare0() { - DexFile file = getFile(); - - /* - * It's okay for new items to be added as a result of an - * addContents() call; we just have to deal with the possibility. - */ - - int i = 0; - for (;;) { - int sz = items.size(); - if (i >= sz) { - break; - } - - for (/*i*/; i < sz; i++) { - OffsettedItem one = items.get(i); - one.addContents(file); - } - } - } - - /** - * Places all the items in this instance at particular offsets. This - * will call {@link OffsettedItem#place} on each item. If an item - * does not know its write size before the call to <code>place</code>, - * it is that call which is responsible for setting the write size. - * This method may only be called once per instance; subsequent calls - * will throw an exception. - */ - public void placeItems() { - throwIfNotPrepared(); - - switch (sort) { - case INSTANCE: { - Collections.sort(items); - break; - } - case TYPE: { - Collections.sort(items, TYPE_SORTER); - break; - } - } - - int sz = items.size(); - int outAt = 0; - for (int i = 0; i < sz; i++) { - OffsettedItem one = items.get(i); - try { - int placedAt = one.place(this, outAt); - - if (placedAt < outAt) { - throw new RuntimeException("bogus place() result for " + - one); - } - - outAt = placedAt + one.writeSize(); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, - "...while placing " + one); - } - } - - writeSize = outAt; - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(AnnotatedOutput out) { - boolean annotates = out.annotates(); - boolean first = true; - DexFile file = getFile(); - int at = 0; - - for (OffsettedItem one : items) { - if (annotates) { - if (first) { - first = false; - } else { - out.annotate(0, "\n"); - } - } - - int alignMask = one.getAlignment() - 1; - int writeAt = (at + alignMask) & ~alignMask; - - if (at != writeAt) { - out.writeZeroes(writeAt - at); - at = writeAt; - } - - one.writeTo(file, out); - at += one.writeSize(); - } - - if (at != writeSize) { - throw new RuntimeException("output size mismatch"); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/OffsettedItem.java b/dx/src/com/android/dx/dex/file/OffsettedItem.java deleted file mode 100644 index 030c37089..000000000 --- a/dx/src/com/android/dx/dex/file/OffsettedItem.java +++ /dev/null @@ -1,313 +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.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; - -/** - * An item in a Dalvik file which is referenced by absolute offset. - */ -public abstract class OffsettedItem extends Item - implements Comparable<OffsettedItem> { - /** > 0; alignment requirement */ - private final int alignment; - - /** >= -1; the size of this instance when written, in bytes, or - * <code>-1</code> if not yet known */ - private int writeSize; - - /** - * null-ok; section the item was added to, or <code>null</code> if - * not yet added - */ - private Section addedTo; - - /** - * >= -1; assigned offset of the item from the start of its section, - * or <code>-1</code> if not yet assigned - */ - private int offset; - - /** - * Gets the absolute offset of the given item, returning <code>0</code> - * if handed <code>null</code>. - * - * @param item null-ok; the item in question - * @return >= 0; the item's absolute offset, or <code>0</code> - * if <code>item == null</code> - */ - public static int getAbsoluteOffsetOr0(OffsettedItem item) { - if (item == null) { - return 0; - } - - return item.getAbsoluteOffset(); - } - - /** - * Constructs an instance. The offset is initially unassigned. - * - * @param alignment > 0; output alignment requirement; must be a - * power of 2 - * @param writeSize >= -1; the size of this instance when written, - * in bytes, or <code>-1</code> if not immediately known - */ - public OffsettedItem(int alignment, int writeSize) { - Section.validateAlignment(alignment); - - if (writeSize < -1) { - throw new IllegalArgumentException("writeSize < -1"); - } - - this.alignment = alignment; - this.writeSize = writeSize; - this.addedTo = null; - this.offset = -1; - } - - /** - * {@inheritDoc} - * - * Comparisons for this class are defined to be type-major (if the - * types don't match then the objects are not equal), with - * {@link #compareTo0} deciding same-type comparisons. - */ - @Override - public final boolean equals(Object other) { - if (this == other) { - return true; - } - - OffsettedItem otherItem = (OffsettedItem) other; - ItemType thisType = itemType(); - ItemType otherType = otherItem.itemType(); - - if (thisType != otherType) { - return false; - } - - return (compareTo0(otherItem) == 0); - } - - /** - * {@inheritDoc} - * - * Comparisons for this class are defined to be class-major (if the - * classes don't match then the objects are not equal), with - * {@link #compareTo0} deciding same-class comparisons. - */ - public final int compareTo(OffsettedItem other) { - if (this == other) { - return 0; - } - - ItemType thisType = itemType(); - ItemType otherType = other.itemType(); - - if (thisType != otherType) { - return thisType.compareTo(otherType); - } - - return compareTo0(other); - } - - /** - * Sets the write size of this item. This may only be called once - * per instance, and only if the size was unknown upon instance - * creation. - * - * @param writeSize > 0; the write size, in bytes - */ - public final void setWriteSize(int writeSize) { - if (writeSize < 0) { - throw new IllegalArgumentException("writeSize < 0"); - } - - if (this.writeSize >= 0) { - throw new UnsupportedOperationException("writeSize already set"); - } - - this.writeSize = writeSize; - } - - /** {@inheritDoc} - * - * @throws UnsupportedOperationException thrown if the write size - * is not yet known - */ - @Override - public final int writeSize() { - if (writeSize < 0) { - throw new UnsupportedOperationException("writeSize is unknown"); - } - - return writeSize; - } - - /** {@inheritDoc} */ - @Override - public final void writeTo(DexFile file, AnnotatedOutput out) { - out.alignTo(alignment); - - try { - if (writeSize < 0) { - throw new UnsupportedOperationException( - "writeSize is unknown"); - } - out.assertCursor(getAbsoluteOffset()); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, - "...while writing " + this); - } - - writeTo0(file, out); - } - - /** - * Gets the relative item offset. The offset is from the start of - * the section which the instance was written to. - * - * @return >= 0; the offset - * @throws RuntimeException thrown if the offset is not yet known - */ - public final int getRelativeOffset() { - if (offset < 0) { - throw new RuntimeException("offset not yet known"); - } - - return offset; - } - - /** - * Gets the absolute item offset. The offset is from the start of - * the file which the instance was written to. - * - * @return >= 0; the offset - * @throws RuntimeException thrown if the offset is not yet known - */ - public final int getAbsoluteOffset() { - if (offset < 0) { - throw new RuntimeException("offset not yet known"); - } - - return addedTo.getAbsoluteOffset(offset); - } - - /** - * Indicates that this item has been added to the given section at - * the given offset. It is only valid to call this method once per - * instance. - * - * @param addedTo non-null; the section this instance has been added to - * @param offset >= 0; the desired offset from the start of the - * section where this instance was placed - * @return >= 0; the offset that this instance should be placed at - * in order to meet its alignment constraint - */ - public final int place(Section addedTo, int offset) { - if (addedTo == null) { - throw new NullPointerException("addedTo == null"); - } - - if (offset < 0) { - throw new IllegalArgumentException("offset < 0"); - } - - if (this.addedTo != null) { - throw new RuntimeException("already written"); - } - - int mask = alignment - 1; - offset = (offset + mask) & ~mask; - - this.addedTo = addedTo; - this.offset = offset; - - place0(addedTo, offset); - - return offset; - } - - /** - * Gets the alignment requirement of this instance. An instance should - * only be written when so aligned. - * - * @return > 0; the alignment requirement; must be a power of 2 - */ - public final int getAlignment() { - return alignment; - } - - /** - * Gets the absolute offset of this item as a string, suitable for - * including in annotations. - * - * @return non-null; the offset string - */ - public final String offsetString() { - return '[' + Integer.toHexString(getAbsoluteOffset()) + ']'; - } - - /** - * Gets a short human-readable string representing this instance. - * - * @return non-null; the human form - */ - public abstract String toHuman(); - - /** - * Compares this instance to another which is guaranteed to be of - * the same class. The default implementation of this method is to - * throw an exception (unsupported operation). If a particular - * class needs to actually sort, then it should override this - * method. - * - * @param other non-null; instance to compare to - * @return <code>-1</code>, <code>0</code>, or <code>1</code>, depending - * on the sort order of this instance and the other - */ - protected int compareTo0(OffsettedItem other) { - throw new UnsupportedOperationException("unsupported"); - } - - /** - * Does additional work required when placing an instance. The - * default implementation of this method is a no-op. If a - * particular class needs to do something special, then it should - * override this method. In particular, if this instance did not - * know its write size up-front, then this method is responsible - * for setting it. - * - * @param addedTo non-null; the section this instance has been added to - * @param offset >= 0; the offset from the start of the - * section where this instance was placed - */ - protected void place0(Section addedTo, int offset) { - // This space intentionally left blank. - } - - /** - * Performs the actual write of the contents of this instance to - * the given data section. This is called by {@link #writeTo}, - * which will have taken care of ensuring alignment. - * - * @param file non-null; the file to use for reference - * @param out non-null; where to write to - */ - protected abstract void writeTo0(DexFile file, AnnotatedOutput out); -} diff --git a/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java b/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java deleted file mode 100644 index 0c2d28692..000000000 --- a/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java +++ /dev/null @@ -1,161 +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.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.ToHuman; - -import java.util.ArrayList; - -/** - * Association of a method and its parameter annotations. - */ -public final class ParameterAnnotationStruct - implements ToHuman, Comparable<ParameterAnnotationStruct> { - /** non-null; the method in question */ - private final CstMethodRef method; - - /** non-null; the associated annotations list */ - private final AnnotationsList annotationsList; - - /** non-null; the associated annotations list, as an item */ - private final UniformListItem<AnnotationSetRefItem> annotationsItem; - - /** - * Constructs an instance. - * - * @param method non-null; the method in question - * @param annotationsList non-null; the associated annotations list - */ - public ParameterAnnotationStruct(CstMethodRef method, - AnnotationsList annotationsList) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - if (annotationsList == null) { - throw new NullPointerException("annotationsList == null"); - } - - this.method = method; - this.annotationsList = annotationsList; - - /* - * Construct an item for the annotations list. TODO: This - * requires way too much copying; fix it. - */ - - int size = annotationsList.size(); - ArrayList<AnnotationSetRefItem> arrayList = new - ArrayList<AnnotationSetRefItem>(size); - - for (int i = 0; i < size; i++) { - Annotations annotations = annotationsList.get(i); - AnnotationSetItem item = new AnnotationSetItem(annotations); - arrayList.add(new AnnotationSetRefItem(item)); - } - - this.annotationsItem = new UniformListItem<AnnotationSetRefItem>( - ItemType.TYPE_ANNOTATION_SET_REF_LIST, arrayList); - } - - /** {@inheritDoc} */ - public int hashCode() { - return method.hashCode(); - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof ParameterAnnotationStruct)) { - return false; - } - - return method.equals(((ParameterAnnotationStruct) other).method); - } - - /** {@inheritDoc} */ - public int compareTo(ParameterAnnotationStruct other) { - return method.compareTo(other.method); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MethodIdsSection methodIds = file.getMethodIds(); - MixedItemSection wordData = file.getWordData(); - - methodIds.intern(method); - wordData.add(annotationsItem); - } - - /** {@inheritDoc} */ - public void writeTo(DexFile file, AnnotatedOutput out) { - int methodIdx = file.getMethodIds().indexOf(method); - int annotationsOff = annotationsItem.getAbsoluteOffset(); - - if (out.annotates()) { - out.annotate(0, " " + method.toHuman()); - out.annotate(4, " method_idx: " + Hex.u4(methodIdx)); - out.annotate(4, " annotations_off: " + - Hex.u4(annotationsOff)); - } - - out.writeInt(methodIdx); - out.writeInt(annotationsOff); - } - - /** {@inheritDoc} */ - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - sb.append(method.toHuman()); - sb.append(": "); - - boolean first = true; - for (AnnotationSetRefItem item : annotationsItem.getItems()) { - if (first) { - first = false; - } else { - sb.append(", "); - } - sb.append(item.toHuman()); - } - - return sb.toString(); - } - - /** - * Gets the method this item is for. - * - * @return non-null; the method - */ - public CstMethodRef getMethod() { - return method; - } - - /** - * Gets the associated annotations list. - * - * @return non-null; the annotations list - */ - public AnnotationsList getAnnotationsList() { - return annotationsList; - } -} diff --git a/dx/src/com/android/dx/dex/file/ProtoIdItem.java b/dx/src/com/android/dx/dex/file/ProtoIdItem.java deleted file mode 100644 index a144c304e..000000000 --- a/dx/src/com/android/dx/dex/file/ProtoIdItem.java +++ /dev/null @@ -1,162 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Representation of a method prototype reference inside a Dalvik file. - */ -public final class ProtoIdItem extends IndexedItem { - /** size of instances when written out to a file, in bytes */ - public static final int WRITE_SIZE = 12; - - /** non-null; the wrapped prototype */ - private final Prototype prototype; - - /** non-null; the short-form of the prototype */ - private final CstUtf8 shortForm; - - /** - * null-ok; the list of parameter types or <code>null</code> if this - * prototype has no parameters - */ - private TypeListItem parameterTypes; - - /** - * Constructs an instance. - * - * @param prototype non-null; the constant for the prototype - */ - public ProtoIdItem(Prototype prototype) { - if (prototype == null) { - throw new NullPointerException("prototype == null"); - } - - this.prototype = prototype; - this.shortForm = makeShortForm(prototype); - - StdTypeList parameters = prototype.getParameterTypes(); - this.parameterTypes = (parameters.size() == 0) ? null - : new TypeListItem(parameters); - } - - /** - * Creates the short-form of the given prototype. - * - * @param prototype non-null; the prototype - * @return non-null; the short form - */ - private static CstUtf8 makeShortForm(Prototype prototype) { - StdTypeList parameters = prototype.getParameterTypes(); - int size = parameters.size(); - StringBuilder sb = new StringBuilder(size + 1); - - sb.append(shortFormCharFor(prototype.getReturnType())); - - for (int i = 0; i < size; i++) { - sb.append(shortFormCharFor(parameters.getType(i))); - } - - return new CstUtf8(sb.toString()); - } - - /** - * Gets the short-form character for the given type. - * - * @param type non-null; the type - * @return the corresponding short-form character - */ - private static char shortFormCharFor(Type type) { - char descriptorChar = type.getDescriptor().charAt(0); - - if (descriptorChar == '[') { - return 'L'; - } - - return descriptorChar; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_PROTO_ID_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return WRITE_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - StringIdsSection stringIds = file.getStringIds(); - TypeIdsSection typeIds = file.getTypeIds(); - MixedItemSection typeLists = file.getTypeLists(); - - typeIds.intern(prototype.getReturnType()); - stringIds.intern(shortForm); - - if (parameterTypes != null) { - parameterTypes = typeLists.intern(parameterTypes); - } - } - - /** {@inheritDoc} */ - @Override - public void writeTo(DexFile file, AnnotatedOutput out) { - int shortyIdx = file.getStringIds().indexOf(shortForm); - int returnIdx = file.getTypeIds().indexOf(prototype.getReturnType()); - int paramsOff = OffsettedItem.getAbsoluteOffsetOr0(parameterTypes); - - if (out.annotates()) { - StringBuilder sb = new StringBuilder(); - sb.append(prototype.getReturnType().toHuman()); - sb.append(" proto("); - - StdTypeList params = prototype.getParameterTypes(); - int size = params.size(); - - for (int i = 0; i < size; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(params.getType(i).toHuman()); - } - - sb.append(")"); - out.annotate(0, indexString() + ' ' + sb.toString()); - out.annotate(4, " shorty_idx: " + Hex.u4(shortyIdx) + - " // " + shortForm.toQuoted()); - out.annotate(4, " return_type_idx: " + Hex.u4(returnIdx) + - " // " + prototype.getReturnType().toHuman()); - out.annotate(4, " parameters_off: " + Hex.u4(paramsOff)); - } - - out.writeInt(shortyIdx); - out.writeInt(returnIdx); - out.writeInt(paramsOff); - } -} diff --git a/dx/src/com/android/dx/dex/file/ProtoIdsSection.java b/dx/src/com/android/dx/dex/file/ProtoIdsSection.java deleted file mode 100644 index 852ab9d5f..000000000 --- a/dx/src/com/android/dx/dex/file/ProtoIdsSection.java +++ /dev/null @@ -1,140 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.type.Prototype; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; -import java.util.TreeMap; - -/** - * Proto (method prototype) identifiers list section of a - * <code>.dex</code> file. - */ -public final class ProtoIdsSection extends UniformItemSection { - /** - * non-null; map from method prototypes to {@link ProtoIdItem} instances - */ - private final TreeMap<Prototype, ProtoIdItem> protoIds; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public ProtoIdsSection(DexFile file) { - super("proto_ids", file, 4); - - protoIds = new TreeMap<Prototype, ProtoIdItem>(); - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return protoIds.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - throw new UnsupportedOperationException("unsupported"); - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = protoIds.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (sz > 65536) { - throw new UnsupportedOperationException("too many proto ids"); - } - - if (out.annotates()) { - out.annotate(4, "proto_ids_size: " + Hex.u4(sz)); - out.annotate(4, "proto_ids_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Interns an element into this instance. - * - * @param prototype non-null; the prototype to intern - * @return non-null; the interned reference - */ - public ProtoIdItem intern(Prototype prototype) { - if (prototype == null) { - throw new NullPointerException("prototype == null"); - } - - throwIfPrepared(); - - ProtoIdItem result = protoIds.get(prototype); - - if (result == null) { - result = new ProtoIdItem(prototype); - protoIds.put(prototype, result); - } - - return result; - } - - /** - * Gets the index of the given prototype, which must have - * been added to this instance. - * - * @param prototype non-null; the prototype to look up - * @return >= 0; the reference's index - */ - public int indexOf(Prototype prototype) { - if (prototype == null) { - throw new NullPointerException("prototype == null"); - } - - throwIfNotPrepared(); - - ProtoIdItem item = protoIds.get(prototype); - - if (item == null) { - throw new IllegalArgumentException("not found"); - } - - return item.getIndex(); - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - int idx = 0; - - for (Object i : items()) { - ((ProtoIdItem) i).setIndex(idx); - idx++; - } - } -} diff --git a/dx/src/com/android/dx/dex/file/Section.java b/dx/src/com/android/dx/dex/file/Section.java deleted file mode 100644 index 9f7657c6c..000000000 --- a/dx/src/com/android/dx/dex/file/Section.java +++ /dev/null @@ -1,287 +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.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; - -import java.util.Collection; - -/** - * A section of a <code>.dex</code> file. Each section consists of a list - * of items of some sort or other. - */ -public abstract class Section { - /** null-ok; name of this part, for annotation purposes */ - private final String name; - - /** non-null; file that this instance is part of */ - private final DexFile file; - - /** > 0; alignment requirement for the final output; - * must be a power of 2 */ - private final int alignment; - - /** >= -1; offset from the start of the file to this part, or - * <code>-1</code> if not yet known */ - private int fileOffset; - - /** whether {@link #prepare} has been called successfully on this - * instance */ - private boolean prepared; - - /** - * Validates an alignment. - * - * @param alignment the alignment - * @throws IllegalArgumentException thrown if <code>alignment</code> - * isn't a positive power of 2 - */ - public static void validateAlignment(int alignment) { - if ((alignment <= 0) || - (alignment & (alignment - 1)) != 0) { - throw new IllegalArgumentException("invalid alignment"); - } - } - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param name null-ok; the name of this instance, for annotation - * purposes - * @param file non-null; file that this instance is part of - * @param alignment > 0; alignment requirement for the final output; - * must be a power of 2 - */ - public Section(String name, DexFile file, int alignment) { - if (file == null) { - throw new NullPointerException("file == null"); - } - - validateAlignment(alignment); - - this.name = name; - this.file = file; - this.alignment = alignment; - this.fileOffset = -1; - this.prepared = false; - } - - /** - * Gets the file that this instance is part of. - * - * @return non-null; the file - */ - public final DexFile getFile() { - return file; - } - - /** - * Gets the alignment for this instance's final output. - * - * @return > 0; the alignment - */ - public final int getAlignment() { - return alignment; - } - - /** - * Gets the offset from the start of the file to this part. This - * throws an exception if the offset has not yet been set. - * - * @return >= 0; the file offset - */ - public final int getFileOffset() { - if (fileOffset < 0) { - throw new RuntimeException("fileOffset not set"); - } - - return fileOffset; - } - - /** - * Sets the file offset. It is only valid to call this method once - * once per instance. - * - * @param fileOffset >= 0; the desired offset from the start of the - * file where this for this instance - * @return >= 0; the offset that this instance should be placed at - * in order to meet its alignment constraint - */ - public final int setFileOffset(int fileOffset) { - if (fileOffset < 0) { - throw new IllegalArgumentException("fileOffset < 0"); - } - - if (this.fileOffset >= 0) { - throw new RuntimeException("fileOffset already set"); - } - - int mask = alignment - 1; - fileOffset = (fileOffset + mask) & ~mask; - - this.fileOffset = fileOffset; - - return fileOffset; - } - - /** - * Writes this instance to the given raw data object. - * - * @param out non-null; where to write to - */ - public final void writeTo(AnnotatedOutput out) { - throwIfNotPrepared(); - align(out); - - int cursor = out.getCursor(); - - if (fileOffset < 0) { - fileOffset = cursor; - } else if (fileOffset != cursor) { - throw new RuntimeException("alignment mismatch: for " + this + - ", at " + cursor + - ", but expected " + fileOffset); - } - - if (out.annotates()) { - if (name != null) { - out.annotate(0, "\n" + name + ":"); - } else if (cursor != 0) { - out.annotate(0, "\n"); - } - } - - writeTo0(out); - } - - /** - * Returns the absolute file offset, given an offset from the - * start of this instance's output. This is only valid to call - * once this instance has been assigned a file offset (via {@link - * #setFileOffset}). - * - * @param relative >= 0; the relative offset - * @return >= 0; the corresponding absolute file offset - */ - public final int getAbsoluteOffset(int relative) { - if (relative < 0) { - throw new IllegalArgumentException("relative < 0"); - } - - if (fileOffset < 0) { - throw new RuntimeException("fileOffset not yet set"); - } - - return fileOffset + relative; - } - - /** - * Returns the absolute file offset of the given item which must - * be contained in this section. This is only valid to call - * once this instance has been assigned a file offset (via {@link - * #setFileOffset}). - * - * <p><b>Note:</b> Subclasses must implement this as appropriate for - * their contents.</p> - * - * @param item non-null; the item in question - * @return >= 0; the item's absolute file offset - */ - public abstract int getAbsoluteItemOffset(Item item); - - /** - * Prepares this instance for writing. This performs any necessary - * prerequisites, including particularly adding stuff to other - * sections. This method may only be called once per instance; - * subsequent calls will throw an exception. - */ - public final void prepare() { - throwIfPrepared(); - prepare0(); - prepared = true; - } - - /** - * Gets the collection of all the items in this section. - * It is not valid to attempt to change the returned list. - * - * @return non-null; the items - */ - public abstract Collection<? extends Item> items(); - - /** - * Does the main work of {@link #prepare}. - */ - protected abstract void prepare0(); - - /** - * Gets the size of this instance when output, in bytes. - * - * @return >= 0; the size of this instance, in bytes - */ - public abstract int writeSize(); - - /** - * Throws an exception if {@link #prepare} has not been - * called on this instance. - */ - protected final void throwIfNotPrepared() { - if (!prepared) { - throw new RuntimeException("not prepared"); - } - } - - /** - * Throws an exception if {@link #prepare} has already been called - * on this instance. - */ - protected final void throwIfPrepared() { - if (prepared) { - throw new RuntimeException("already prepared"); - } - } - - /** - * Aligns the output of the given data to the alignment of this instance. - * - * @param out non-null; the output to align - */ - protected final void align(AnnotatedOutput out) { - out.alignTo(alignment); - } - - /** - * Writes this instance to the given raw data object. This gets - * called by {@link #writeTo} after aligning the cursor of - * <code>out</code> and verifying that either the assigned file - * offset matches the actual cursor <code>out</code> or that the - * file offset was not previously assigned, in which case it gets - * assigned to <code>out</code>'s cursor. - * - * @param out non-null; where to write to - */ - protected abstract void writeTo0(AnnotatedOutput out); - - /** - * Returns the name of this section, for annotation purposes. - * - * @return null-ok; name of this part, for annotation purposes - */ - protected final String getName() { - return name; - } -} diff --git a/dx/src/com/android/dx/dex/file/Statistics.java b/dx/src/com/android/dx/dex/file/Statistics.java deleted file mode 100644 index b11ab6eb1..000000000 --- a/dx/src/com/android/dx/dex/file/Statistics.java +++ /dev/null @@ -1,195 +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.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; - -import java.util.Collection; -import java.util.HashMap; -import java.util.TreeMap; - -/** - * Statistics about the contents of a file. - */ -public final class Statistics { - /** non-null; data about each type of item */ - private final HashMap<String, Data> dataMap; - - /** - * Constructs an instance. - */ - public Statistics() { - dataMap = new HashMap<String, Data>(50); - } - - /** - * Adds the given item to the statistics. - * - * @param item non-null; the item to add - */ - public void add(Item item) { - String typeName = item.typeName(); - Data data = dataMap.get(typeName); - - if (data == null) { - dataMap.put(typeName, new Data(item, typeName)); - } else { - data.add(item); - } - } - - /** - * Adds the given list of items to the statistics. - * - * @param list non-null; the list of items to add - */ - public void addAll(Section list) { - Collection<? extends Item> items = list.items(); - for (Item item : items) { - add(item); - } - } - - /** - * Writes the statistics as an annotation. - * - * @param out non-null; where to write to - */ - public final void writeAnnotation(AnnotatedOutput out) { - if (dataMap.size() == 0) { - return; - } - - out.annotate(0, "\nstatistics:\n"); - - TreeMap<String, Data> sortedData = new TreeMap<String, Data>(); - - for (Data data : dataMap.values()) { - sortedData.put(data.name, data); - } - - for (Data data : sortedData.values()) { - data.writeAnnotation(out); - } - } - - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - sb.append("Statistics:\n"); - - TreeMap<String, Data> sortedData = new TreeMap<String, Data>(); - - for (Data data : dataMap.values()) { - sortedData.put(data.name, data); - } - - for (Data data : sortedData.values()) { - sb.append(data.toHuman()); - } - - return sb.toString(); - } - - /** - * Statistical data about a particular class. - */ - private static class Data { - /** non-null; name to use as a label */ - private final String name; - - /** >= 0; number of instances */ - private int count; - - /** >= 0; total size of instances in bytes */ - private int totalSize; - - /** >= 0; largest size of any individual item */ - private int largestSize; - - /** >= 0; smallest size of any individual item */ - private int smallestSize; - - /** - * Constructs an instance for the given item. - * - * @param item non-null; item in question - * @param name non-null; type name to use - */ - public Data(Item item, String name) { - int size = item.writeSize(); - - this.name = name; - this.count = 1; - this.totalSize = size; - this.largestSize = size; - this.smallestSize = size; - } - - /** - * Incorporates a new item. This assumes the type name matches. - * - * @param item non-null; item to incorporate - */ - public void add(Item item) { - int size = item.writeSize(); - - count++; - totalSize += size; - - if (size > largestSize) { - largestSize = size; - } - - if (size < smallestSize) { - smallestSize = size; - } - } - - /** - * Writes this instance as an annotation. - * - * @param out non-null; where to write to - */ - public void writeAnnotation(AnnotatedOutput out) { - out.annotate(toHuman()); - } - - /** - * Generates a human-readable string for this data item. - * - * @return string for human consumption. - */ - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - sb.append(" " + name + ": " + - count + " item" + (count == 1 ? "" : "s") + "; " + - totalSize + " bytes total\n"); - - if (smallestSize == largestSize) { - sb.append(" " + smallestSize + " bytes/item\n"); - } else { - int average = totalSize / count; - sb.append(" " + smallestSize + ".." + largestSize + - " bytes/item; average " + average + "\n"); - } - - return sb.toString(); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/StringDataItem.java b/dx/src/com/android/dx/dex/file/StringDataItem.java deleted file mode 100644 index 49eea5757..000000000 --- a/dx/src/com/android/dx/dex/file/StringDataItem.java +++ /dev/null @@ -1,99 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; -import com.android.dx.util.Leb128Utils; - -/** - * Representation of string data for a particular string, in a Dalvik file. - */ -public final class StringDataItem extends OffsettedItem { - /** non-null; the string value */ - private final CstUtf8 value; - - /** - * Constructs an instance. - * - * @param value non-null; the string value - */ - public StringDataItem(CstUtf8 value) { - super(1, writeSize(value)); - - this.value = value; - } - - /** - * Gets the write size for a given value. - * - * @param value non-null; the string value - * @return >= 2 the write size, in bytes - */ - private static int writeSize(CstUtf8 value) { - int utf16Size = value.getUtf16Size(); - - // The +1 is for the '\0' termination byte. - return Leb128Utils.unsignedLeb128Size(utf16Size) - + value.getUtf8Size() + 1; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_STRING_DATA_ITEM; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - // Nothing to do here. - } - - /** {@inheritDoc} */ - @Override - public void writeTo0(DexFile file, AnnotatedOutput out) { - ByteArray bytes = value.getBytes(); - int utf16Size = value.getUtf16Size(); - - if (out.annotates()) { - out.annotate(Leb128Utils.unsignedLeb128Size(utf16Size), - "utf16_size: " + Hex.u4(utf16Size)); - out.annotate(bytes.size() + 1, value.toQuoted()); - } - - out.writeUnsignedLeb128(utf16Size); - out.write(bytes); - out.writeByte(0); - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return value.toQuoted(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(OffsettedItem other) { - StringDataItem otherData = (StringDataItem) other; - - return value.compareTo(otherData.value); - } -} diff --git a/dx/src/com/android/dx/dex/file/StringIdItem.java b/dx/src/com/android/dx/dex/file/StringIdItem.java deleted file mode 100644 index e80a7f877..000000000 --- a/dx/src/com/android/dx/dex/file/StringIdItem.java +++ /dev/null @@ -1,128 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Representation of a string inside a Dalvik file. - */ -public final class StringIdItem - extends IndexedItem implements Comparable { - /** size of instances when written out to a file, in bytes */ - public static final int WRITE_SIZE = 4; - - /** non-null; the string value */ - private final CstUtf8 value; - - /** null-ok; associated string data object, if known */ - private StringDataItem data; - - /** - * Constructs an instance. - * - * @param value non-null; the string value - */ - public StringIdItem(CstUtf8 value) { - if (value == null) { - throw new NullPointerException("value == null"); - } - - this.value = value; - this.data = null; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof StringIdItem)) { - return false; - } - - StringIdItem otherString = (StringIdItem) other; - return value.equals(otherString.value); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return value.hashCode(); - } - - /** {@inheritDoc} */ - public int compareTo(Object other) { - StringIdItem otherString = (StringIdItem) other; - return value.compareTo(otherString.value); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_STRING_ID_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return WRITE_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - if (data == null) { - // The string data hasn't yet been added, so add it. - MixedItemSection stringData = file.getStringData(); - data = new StringDataItem(value); - stringData.add(data); - } - } - - /** {@inheritDoc} */ - @Override - public void writeTo(DexFile file, AnnotatedOutput out) { - int dataOff = data.getAbsoluteOffset(); - - if (out.annotates()) { - out.annotate(0, indexString() + ' ' + value.toQuoted(100)); - out.annotate(4, " string_data_off: " + Hex.u4(dataOff)); - } - - out.writeInt(dataOff); - } - - /** - * Gets the string value. - * - * @return non-null; the value - */ - public CstUtf8 getValue() { - return value; - } - - /** - * Gets the associated data object for this instance, if known. - * - * @return null-ok; the associated data object or <code>null</code> - * if not yet known - */ - public StringDataItem getData() { - return data; - } -} diff --git a/dx/src/com/android/dx/dex/file/StringIdsSection.java b/dx/src/com/android/dx/dex/file/StringIdsSection.java deleted file mode 100644 index 17fbb578b..000000000 --- a/dx/src/com/android/dx/dex/file/StringIdsSection.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.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; -import java.util.TreeMap; - -/** - * Strings list section of a <code>.dex</code> file. - */ -public final class StringIdsSection - extends UniformItemSection { - /** - * non-null; map from string constants to {@link - * StringIdItem} instances - */ - private final TreeMap<CstUtf8, StringIdItem> strings; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public StringIdsSection(DexFile file) { - super("string_ids", file, 4); - - strings = new TreeMap<CstUtf8, StringIdItem>(); - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return strings.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - throwIfNotPrepared(); - - if (cst instanceof CstString) { - cst = ((CstString) cst).getString(); - } - - IndexedItem result = strings.get((CstUtf8) cst); - - if (result == null) { - throw new IllegalArgumentException("not found"); - } - - return result; - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = strings.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (out.annotates()) { - out.annotate(4, "string_ids_size: " + Hex.u4(sz)); - out.annotate(4, "string_ids_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Interns an element into this instance. - * - * @param string non-null; the string to intern, as a regular Java - * <code>String</code> - * @return non-null; the interned string - */ - public StringIdItem intern(String string) { - CstUtf8 utf8 = new CstUtf8(string); - return intern(new StringIdItem(utf8)); - } - - /** - * Interns an element into this instance. - * - * @param string non-null; the string to intern, as a {@link CstString} - * @return non-null; the interned string - */ - public StringIdItem intern(CstString string) { - CstUtf8 utf8 = string.getString(); - return intern(new StringIdItem(utf8)); - } - - /** - * Interns an element into this instance. - * - * @param string non-null; the string to intern, as a constant - * @return non-null; the interned string - */ - public StringIdItem intern(CstUtf8 string) { - return intern(new StringIdItem(string)); - } - - /** - * Interns an element into this instance. - * - * @param string non-null; the string to intern - * @return non-null; the interned string - */ - public StringIdItem intern(StringIdItem string) { - if (string == null) { - throw new NullPointerException("string == null"); - } - - throwIfPrepared(); - - CstUtf8 value = string.getValue(); - StringIdItem already = strings.get(value); - - if (already != null) { - return already; - } - - strings.put(value, string); - return string; - } - - /** - * Interns the components of a name-and-type into this instance. - * - * @param nat non-null; the name-and-type - */ - public void intern(CstNat nat) { - intern(nat.getName()); - intern(nat.getDescriptor()); - } - - /** - * Gets the index of the given string, which must have been added - * to this instance. - * - * @param string non-null; the string to look up - * @return >= 0; the string's index - */ - public int indexOf(CstUtf8 string) { - if (string == null) { - throw new NullPointerException("string == null"); - } - - throwIfNotPrepared(); - - StringIdItem s = strings.get(string); - - if (s == null) { - throw new IllegalArgumentException("not found"); - } - - return s.getIndex(); - } - - /** - * Gets the index of the given string, which must have been added - * to this instance. - * - * @param string non-null; the string to look up - * @return >= 0; the string's index - */ - public int indexOf(CstString string) { - return indexOf(string.getString()); - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - int idx = 0; - - for (StringIdItem s : strings.values()) { - s.setIndex(idx); - idx++; - } - } -} diff --git a/dx/src/com/android/dx/dex/file/TypeIdItem.java b/dx/src/com/android/dx/dex/file/TypeIdItem.java deleted file mode 100644 index f3402e643..000000000 --- a/dx/src/com/android/dx/dex/file/TypeIdItem.java +++ /dev/null @@ -1,72 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Representation of a type reference inside a Dalvik file. - */ -public final class TypeIdItem extends IdItem { - /** size of instances when written out to a file, in bytes */ - public static final int WRITE_SIZE = 4; - - /** - * Constructs an instance. - * - * @param type non-null; the constant for the type - */ - public TypeIdItem(CstType type) { - super(type); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_TYPE_ID_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return WRITE_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - file.getStringIds().intern(getDefiningClass().getDescriptor()); - } - - /** {@inheritDoc} */ - @Override - public void writeTo(DexFile file, AnnotatedOutput out) { - CstType type = getDefiningClass(); - CstUtf8 descriptor = type.getDescriptor(); - int idx = file.getStringIds().indexOf(descriptor); - - if (out.annotates()) { - out.annotate(0, indexString() + ' ' + descriptor.toHuman()); - out.annotate(4, " descriptor_idx: " + Hex.u4(idx)); - } - - out.writeInt(idx); - } -} diff --git a/dx/src/com/android/dx/dex/file/TypeIdsSection.java b/dx/src/com/android/dx/dex/file/TypeIdsSection.java deleted file mode 100644 index 296263f09..000000000 --- a/dx/src/com/android/dx/dex/file/TypeIdsSection.java +++ /dev/null @@ -1,192 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; -import java.util.TreeMap; - -/** - * Type identifiers list section of a <code>.dex</code> file. - */ -public final class TypeIdsSection extends UniformItemSection { - /** - * non-null; map from types to {@link TypeIdItem} instances - */ - private final TreeMap<Type, TypeIdItem> typeIds; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public TypeIdsSection(DexFile file) { - super("type_ids", file, 4); - - typeIds = new TreeMap<Type, TypeIdItem>(); - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return typeIds.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - throwIfNotPrepared(); - - Type type = ((CstType) cst).getClassType(); - IndexedItem result = typeIds.get(type); - - if (result == null) { - throw new IllegalArgumentException("not found: " + cst); - } - - return result; - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = typeIds.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (sz > 65536) { - throw new UnsupportedOperationException("too many type ids"); - } - - if (out.annotates()) { - out.annotate(4, "type_ids_size: " + Hex.u4(sz)); - out.annotate(4, "type_ids_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Interns an element into this instance. - * - * @param type non-null; the type to intern - * @return non-null; the interned reference - */ - public TypeIdItem intern(Type type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - throwIfPrepared(); - - TypeIdItem result = typeIds.get(type); - - if (result == null) { - result = new TypeIdItem(new CstType(type)); - typeIds.put(type, result); - } - - return result; - } - - /** - * Interns an element into this instance. - * - * @param type non-null; the type to intern - * @return non-null; the interned reference - */ - public TypeIdItem intern(CstType type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - throwIfPrepared(); - - Type typePerSe = type.getClassType(); - TypeIdItem result = typeIds.get(typePerSe); - - if (result == null) { - result = new TypeIdItem(type); - typeIds.put(typePerSe, result); - } - - return result; - } - - /** - * Gets the index of the given type, which must have - * been added to this instance. - * - * @param type non-null; the type to look up - * @return >= 0; the reference's index - */ - public int indexOf(Type type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - throwIfNotPrepared(); - - TypeIdItem item = typeIds.get(type); - - if (item == null) { - throw new IllegalArgumentException("not found: " + type); - } - - return item.getIndex(); - } - - /** - * Gets the index of the given type, which must have - * been added to this instance. - * - * @param type non-null; the type to look up - * @return >= 0; the reference's index - */ - public int indexOf(CstType type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - return indexOf(type.getClassType()); - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - int idx = 0; - - for (Object i : items()) { - ((TypeIdItem) i).setIndex(idx); - idx++; - } - } -} diff --git a/dx/src/com/android/dx/dex/file/TypeListItem.java b/dx/src/com/android/dx/dex/file/TypeListItem.java deleted file mode 100644 index 6557ca415..000000000 --- a/dx/src/com/android/dx/dex/file/TypeListItem.java +++ /dev/null @@ -1,122 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Representation of a list of class references. - */ -public final class TypeListItem extends OffsettedItem { - /** alignment requirement */ - private static final int ALIGNMENT = 4; - - /** element size in bytes */ - private static final int ELEMENT_SIZE = 2; - - /** header size in bytes */ - private static final int HEADER_SIZE = 4; - - /** non-null; the actual list */ - private final TypeList list; - - /** - * Constructs an instance. - * - * @param list non-null; the actual list - */ - public TypeListItem(TypeList list) { - super(ALIGNMENT, (list.size() * ELEMENT_SIZE) + HEADER_SIZE); - - this.list = list; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return StdTypeList.hashContents(list); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_TYPE_LIST; - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - TypeIdsSection typeIds = file.getTypeIds(); - int sz = list.size(); - - for (int i = 0; i < sz; i++) { - typeIds.intern(list.getType(i)); - } - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - throw new RuntimeException("unsupported"); - } - - /** - * Gets the underlying list. - * - * @return non-null; the list - */ - public TypeList getList() { - return list; - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - TypeIdsSection typeIds = file.getTypeIds(); - int sz = list.size(); - - if (out.annotates()) { - out.annotate(0, offsetString() + " type_list"); - out.annotate(HEADER_SIZE, " size: " + Hex.u4(sz)); - for (int i = 0; i < sz; i++) { - Type one = list.getType(i); - int idx = typeIds.indexOf(one); - out.annotate(ELEMENT_SIZE, - " " + Hex.u2(idx) + " // " + one.toHuman()); - } - } - - out.writeInt(sz); - - for (int i = 0; i < sz; i++) { - out.writeShort(typeIds.indexOf(list.getType(i))); - } - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(OffsettedItem other) { - TypeList thisList = this.list; - TypeList otherList = ((TypeListItem) other).list; - - return StdTypeList.compareContents(thisList, otherList); - } -} diff --git a/dx/src/com/android/dx/dex/file/UniformItemSection.java b/dx/src/com/android/dx/dex/file/UniformItemSection.java deleted file mode 100644 index 602bc2dcb..000000000 --- a/dx/src/com/android/dx/dex/file/UniformItemSection.java +++ /dev/null @@ -1,112 +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.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.util.AnnotatedOutput; - -import java.util.Collection; - -/** - * A section of a <code>.dex</code> file which consists of a sequence of - * {@link Item} objects. Each of the items must have the same size in - * the output. - */ -public abstract class UniformItemSection extends Section { - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param name null-ok; the name of this instance, for annotation - * purposes - * @param file non-null; file that this instance is part of - * @param alignment > 0; alignment requirement for the final output; - * must be a power of 2 - */ - public UniformItemSection(String name, DexFile file, int alignment) { - super(name, file, alignment); - } - - /** {@inheritDoc} */ - @Override - public final int writeSize() { - Collection<? extends Item> items = items(); - int sz = items.size(); - - if (sz == 0) { - return 0; - } - - // Since each item has to be the same size, we can pick any. - return sz * items.iterator().next().writeSize(); - } - - /** - * Gets the item corresponding to the given {@link Constant}. This - * will throw an exception if the constant is not found, including - * if this instance isn't the sort that maps constants to {@link - * IndexedItem} instances. - * - * @param cst non-null; constant to look for - * @return non-null; the corresponding item found in this instance - */ - public abstract IndexedItem get(Constant cst); - - /** {@inheritDoc} */ - @Override - protected final void prepare0() { - DexFile file = getFile(); - - orderItems(); - - for (Item one : items()) { - one.addContents(file); - } - } - - /** {@inheritDoc} */ - @Override - protected final void writeTo0(AnnotatedOutput out) { - DexFile file = getFile(); - int alignment = getAlignment(); - - for (Item one : items()) { - one.writeTo(file, out); - out.alignTo(alignment); - } - } - - /** {@inheritDoc} */ - @Override - public final int getAbsoluteItemOffset(Item item) { - /* - * Since all items must be the same size, we can use the size - * of the one we're given to calculate its offset. - */ - IndexedItem ii = (IndexedItem) item; - int relativeOffset = ii.getIndex() * ii.writeSize(); - - return getAbsoluteOffset(relativeOffset); - } - - /** - * Alters or picks the order for items in this instance if desired, - * so that subsequent calls to {@link #items} will yield a - * so-ordered collection. If the items in this instance are indexed, - * then this method should also assign indices. - */ - protected abstract void orderItems(); -} diff --git a/dx/src/com/android/dx/dex/file/UniformListItem.java b/dx/src/com/android/dx/dex/file/UniformListItem.java deleted file mode 100644 index 3af39428a..000000000 --- a/dx/src/com/android/dx/dex/file/UniformListItem.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.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.HashMap; -import java.util.List; - -/** - * Class that represents a contiguous list of uniform items. Each - * item in the list, in particular, must have the same write size and - * alignment. - * - * <p>This class inherits its alignment from its items, bumped up to - * <code>4</code> if the items have a looser alignment requirement. If - * it is more than <code>4</code>, then there will be a gap after the - * output list size (which is four bytes) and before the first item.</p> - * - * @param <T> type of element contained in an instance - */ -public final class UniformListItem<T extends OffsettedItem> - extends OffsettedItem { - /** the size of the list header */ - private static final int HEADER_SIZE = 4; - - /** non-null; the item type */ - private final ItemType itemType; - - /** non-null; the contents */ - private final List<T> items; - - /** - * Constructs an instance. It is illegal to modify the given list once - * it is used to construct an instance of this class. - * - * @param itemType non-null; the type of the item - * @param items non-null and non-empty; list of items to represent - */ - public UniformListItem(ItemType itemType, List<T> items) { - super(getAlignment(items), writeSize(items)); - - if (itemType == null) { - throw new NullPointerException("itemType == null"); - } - - this.items = items; - this.itemType = itemType; - } - - /** - * Helper for {@link #UniformListItem}, which returns the alignment - * requirement implied by the given list. See the header comment for - * more details. - * - * @param items non-null; list of items being represented - * @return >= 4; the alignment requirement - */ - private static int getAlignment(List<? extends OffsettedItem> items) { - try { - // Since they all must have the same alignment, any one will do. - return Math.max(HEADER_SIZE, items.get(0).getAlignment()); - } catch (IndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("items.size() == 0"); - } catch (NullPointerException ex) { - // Translate the exception. - throw new NullPointerException("items == null"); - } - } - - /** - * Calculates the write size for the given list. - * - * @param items non-null; the list in question - * @return >= 0; the write size - */ - private static int writeSize(List<? extends OffsettedItem> items) { - /* - * This class assumes all included items are the same size, - * an assumption which is verified in place0(). - */ - OffsettedItem first = items.get(0); - return (items.size() * first.writeSize()) + getAlignment(items); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return itemType; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(100); - - sb.append(getClass().getName()); - sb.append(items); - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - for (OffsettedItem i : items) { - i.addContents(file); - } - } - - /** {@inheritDoc} */ - @Override - public final String toHuman() { - StringBuffer sb = new StringBuffer(100); - boolean first = true; - - sb.append("{"); - - for (OffsettedItem i : items) { - if (first) { - first = false; - } else { - sb.append(", "); - } - sb.append(i.toHuman()); - } - - sb.append("}"); - return sb.toString(); - } - - /** - * Gets the underlying list of items. - * - * @return non-null; the list - */ - public final List<T> getItems() { - return items; - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - offset += headerSize(); - - boolean first = true; - int theSize = -1; - int theAlignment = -1; - - for (OffsettedItem i : items) { - int size = i.writeSize(); - if (first) { - theSize = size; - theAlignment = i.getAlignment(); - first = false; - } else { - if (size != theSize) { - throw new UnsupportedOperationException( - "item size mismatch"); - } - if (i.getAlignment() != theAlignment) { - throw new UnsupportedOperationException( - "item alignment mismatch"); - } - } - - offset = i.place(addedTo, offset) + size; - } - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - int size = items.size(); - - if (out.annotates()) { - out.annotate(0, offsetString() + " " + typeName()); - out.annotate(4, " size: " + Hex.u4(size)); - } - - out.writeInt(size); - - for (OffsettedItem i : items) { - i.writeTo(file, out); - } - } - - /** - * Get the size of the header of this list. - * - * @return >= 0; the header size - */ - private int headerSize() { - /* - * Because of how this instance was set up, this is the same - * as the alignment. - */ - return getAlignment(); - } -} diff --git a/dx/src/com/android/dx/dex/file/ValueEncoder.java b/dx/src/com/android/dx/dex/file/ValueEncoder.java deleted file mode 100644 index 02a34194f..000000000 --- a/dx/src/com/android/dx/dex/file/ValueEncoder.java +++ /dev/null @@ -1,532 +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.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstBoolean; -import com.android.dx.rop.cst.CstByte; -import com.android.dx.rop.cst.CstChar; -import com.android.dx.rop.cst.CstDouble; -import com.android.dx.rop.cst.CstEnumRef; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstFloat; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstKnownNull; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.rop.cst.CstLong; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstShort; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; - -/** - * Handler for writing out <code>encoded_values</code> and parts - * thereof. - */ -public final class ValueEncoder { - /** annotation value type constant: <code>byte</code> */ - private static final int VALUE_BYTE = 0x00; - - /** annotation value type constant: <code>short</code> */ - private static final int VALUE_SHORT = 0x02; - - /** annotation value type constant: <code>char</code> */ - private static final int VALUE_CHAR = 0x03; - - /** annotation value type constant: <code>int</code> */ - private static final int VALUE_INT = 0x04; - - /** annotation value type constant: <code>long</code> */ - private static final int VALUE_LONG = 0x06; - - /** annotation value type constant: <code>float</code> */ - private static final int VALUE_FLOAT = 0x10; - - /** annotation value type constant: <code>double</code> */ - private static final int VALUE_DOUBLE = 0x11; - - /** annotation value type constant: <code>string</code> */ - private static final int VALUE_STRING = 0x17; - - /** annotation value type constant: <code>type</code> */ - private static final int VALUE_TYPE = 0x18; - - /** annotation value type constant: <code>field</code> */ - private static final int VALUE_FIELD = 0x19; - - /** annotation value type constant: <code>method</code> */ - private static final int VALUE_METHOD = 0x1a; - - /** annotation value type constant: <code>enum</code> */ - private static final int VALUE_ENUM = 0x1b; - - /** annotation value type constant: <code>array</code> */ - private static final int VALUE_ARRAY = 0x1c; - - /** annotation value type constant: <code>annotation</code> */ - private static final int VALUE_ANNOTATION = 0x1d; - - /** annotation value type constant: <code>null</code> */ - private static final int VALUE_NULL = 0x1e; - - /** annotation value type constant: <code>boolean</code> */ - private static final int VALUE_BOOLEAN = 0x1f; - - /** non-null; file being written */ - private final DexFile file; - - /** non-null; output stream to write to */ - private final AnnotatedOutput out; - - /** - * Construct an instance. - * - * @param file non-null; file being written - * @param out non-null; output stream to write to - */ - public ValueEncoder(DexFile file, AnnotatedOutput out) { - if (file == null) { - throw new NullPointerException("file == null"); - } - - if (out == null) { - throw new NullPointerException("out == null"); - } - - this.file = file; - this.out = out; - } - - /** - * Writes out the encoded form of the given constant. - * - * @param cst non-null; the constant to write - */ - public void writeConstant(Constant cst) { - int type = constantToValueType(cst); - int arg; - - switch (type) { - case VALUE_BYTE: - case VALUE_SHORT: - case VALUE_INT: - case VALUE_LONG: { - long value = ((CstLiteralBits) cst).getLongBits(); - writeSignedIntegralValue(type, value); - break; - } - case VALUE_CHAR: { - long value = ((CstLiteralBits) cst).getLongBits(); - writeUnsignedIntegralValue(type, value); - break; - } - case VALUE_FLOAT: { - // Shift value left 32 so that right-zero-extension works. - long value = ((CstFloat) cst).getLongBits() << 32; - writeRightZeroExtendedValue(type, value); - break; - } - case VALUE_DOUBLE: { - long value = ((CstDouble) cst).getLongBits(); - writeRightZeroExtendedValue(type, value); - break; - } - case VALUE_STRING: { - int index = file.getStringIds().indexOf((CstString) cst); - writeUnsignedIntegralValue(type, (long) index); - break; - } - case VALUE_TYPE: { - int index = file.getTypeIds().indexOf((CstType) cst); - writeUnsignedIntegralValue(type, (long) index); - break; - } - case VALUE_FIELD: { - int index = file.getFieldIds().indexOf((CstFieldRef) cst); - writeUnsignedIntegralValue(type, (long) index); - break; - } - case VALUE_METHOD: { - int index = file.getMethodIds().indexOf((CstMethodRef) cst); - writeUnsignedIntegralValue(type, (long) index); - break; - } - case VALUE_ENUM: { - CstFieldRef fieldRef = ((CstEnumRef) cst).getFieldRef(); - int index = file.getFieldIds().indexOf(fieldRef); - writeUnsignedIntegralValue(type, (long) index); - break; - } - case VALUE_ARRAY: { - out.writeByte(type); - writeArray((CstArray) cst, false); - break; - } - case VALUE_ANNOTATION: { - out.writeByte(type); - writeAnnotation(((CstAnnotation) cst).getAnnotation(), - false); - break; - } - case VALUE_NULL: { - out.writeByte(type); - break; - } - case VALUE_BOOLEAN: { - int value = ((CstBoolean) cst).getIntBits(); - out.writeByte(type | (value << 5)); - break; - } - default: { - throw new RuntimeException("Shouldn't happen"); - } - } - } - - /** - * Gets the value type for the given constant. - * - * @param cst non-null; the constant - * @return the value type; one of the <code>VALUE_*</code> constants - * defined by this class - */ - private static int constantToValueType(Constant cst) { - /* - * TODO: Constant should probable have an associated enum, so this - * can be a switch(). - */ - if (cst instanceof CstByte) { - return VALUE_BYTE; - } else if (cst instanceof CstShort) { - return VALUE_SHORT; - } else if (cst instanceof CstChar) { - return VALUE_CHAR; - } else if (cst instanceof CstInteger) { - return VALUE_INT; - } else if (cst instanceof CstLong) { - return VALUE_LONG; - } else if (cst instanceof CstFloat) { - return VALUE_FLOAT; - } else if (cst instanceof CstDouble) { - return VALUE_DOUBLE; - } else if (cst instanceof CstString) { - return VALUE_STRING; - } else if (cst instanceof CstType) { - return VALUE_TYPE; - } else if (cst instanceof CstFieldRef) { - return VALUE_FIELD; - } else if (cst instanceof CstMethodRef) { - return VALUE_METHOD; - } else if (cst instanceof CstEnumRef) { - return VALUE_ENUM; - } else if (cst instanceof CstArray) { - return VALUE_ARRAY; - } else if (cst instanceof CstAnnotation) { - return VALUE_ANNOTATION; - } else if (cst instanceof CstKnownNull) { - return VALUE_NULL; - } else if (cst instanceof CstBoolean) { - return VALUE_BOOLEAN; - } else { - throw new RuntimeException("Shouldn't happen"); - } - } - - /** - * Writes out the encoded form of the given array, that is, as - * an <code>encoded_array</code> and not including a - * <code>value_type</code> prefix. If the output stream keeps - * (debugging) annotations and <code>topLevel</code> is - * <code>true</code>, then this method will write (debugging) - * annotations. - * - * @param array non-null; array instance to write - * @param topLevel <code>true</code> iff the given annotation is the - * top-level annotation or <code>false</code> if it is a sub-annotation - * of some other annotation - */ - public void writeArray(CstArray array, boolean topLevel) { - boolean annotates = topLevel && out.annotates(); - CstArray.List list = ((CstArray) array).getList(); - int size = list.size(); - - if (annotates) { - out.annotate(" size: " + Hex.u4(size)); - } - - out.writeUnsignedLeb128(size); - - for (int i = 0; i < size; i++) { - Constant cst = list.get(i); - if (annotates) { - out.annotate(" [" + Integer.toHexString(i) + "] " + - constantToHuman(cst)); - } - writeConstant(cst); - } - - if (annotates) { - out.endAnnotation(); - } - } - - /** - * Writes out the encoded form of the given annotation, that is, - * as an <code>encoded_annotation</code> and not including a - * <code>value_type</code> prefix. If the output stream keeps - * (debugging) annotations and <code>topLevel</code> is - * <code>true</code>, then this method will write (debugging) - * annotations. - * - * @param annotation non-null; annotation instance to write - * @param topLevel <code>true</code> iff the given annotation is the - * top-level annotation or <code>false</code> if it is a sub-annotation - * of some other annotation - */ - public void writeAnnotation(Annotation annotation, boolean topLevel) { - boolean annotates = topLevel && out.annotates(); - StringIdsSection stringIds = file.getStringIds(); - TypeIdsSection typeIds = file.getTypeIds(); - - CstType type = annotation.getType(); - int typeIdx = typeIds.indexOf(type); - - if (annotates) { - out.annotate(" type_idx: " + Hex.u4(typeIdx) + " // " + - type.toHuman()); - } - - out.writeUnsignedLeb128(typeIds.indexOf(annotation.getType())); - - Collection<NameValuePair> pairs = annotation.getNameValuePairs(); - int size = pairs.size(); - - if (annotates) { - out.annotate(" size: " + Hex.u4(size)); - } - - out.writeUnsignedLeb128(size); - - int at = 0; - for (NameValuePair pair : pairs) { - CstUtf8 name = pair.getName(); - int nameIdx = stringIds.indexOf(name); - Constant value = pair.getValue(); - - if (annotates) { - out.annotate(0, " elements[" + at + "]:"); - at++; - out.annotate(" name_idx: " + Hex.u4(nameIdx) + " // " + - name.toHuman()); - } - - out.writeUnsignedLeb128(nameIdx); - - if (annotates) { - out.annotate(" value: " + constantToHuman(value)); - } - - writeConstant(value); - } - - if (annotates) { - out.endAnnotation(); - } - } - - /** - * Gets the colloquial type name and human form of the type of the - * given constant, when used as an encoded value. - * - * @param cst non-null; the constant - * @return non-null; its type name and human form - */ - public static String constantToHuman(Constant cst) { - int type = constantToValueType(cst); - - if (type == VALUE_NULL) { - return "null"; - } - - StringBuilder sb = new StringBuilder(); - - sb.append(cst.typeName()); - sb.append(' '); - sb.append(cst.toHuman()); - - return sb.toString(); - } - - /** - * Helper for {@link #writeConstant}, which writes out the value - * for any signed integral type. - * - * @param type the type constant - * @param value <code>long</code> bits of the value - */ - private void writeSignedIntegralValue(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--; - } - } - - /** - * Helper for {@link #writeConstant}, which writes out the value - * for any unsigned integral type. - * - * @param type the type constant - * @param value <code>long</code> bits of the value - */ - private void writeUnsignedIntegralValue(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--; - } - } - - /** - * Helper for {@link #writeConstant}, which writes out a - * right-zero-extended value. - * - * @param type the type constant - * @param value <code>long</code> bits of the value - */ - private void writeRightZeroExtendedValue(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--; - } - } - - - /** - * Helper for <code>addContents()</code> methods, which adds - * contents for a particular {@link Annotation}, calling itself - * recursively should it encounter a nested annotation. - * - * @param file non-null; the file to add to - * @param annotation non-null; the annotation to add contents for - */ - public static void addContents(DexFile file, Annotation annotation) { - TypeIdsSection typeIds = file.getTypeIds(); - StringIdsSection stringIds = file.getStringIds(); - - typeIds.intern(annotation.getType()); - - for (NameValuePair pair : annotation.getNameValuePairs()) { - stringIds.intern(pair.getName()); - addContents(file, pair.getValue()); - } - } - - /** - * Helper for <code>addContents()</code> methods, which adds - * contents for a particular constant, calling itself recursively - * should it encounter a {@link CstArray} and calling {@link - * #addContents(DexFile,Annotation)} recursively should it - * encounter a {@link CstAnnotation}. - * - * @param file non-null; the file to add to - * @param cst non-null; the constant to add contents for - */ - public static void addContents(DexFile file, Constant cst) { - TypeIdsSection typeIds = file.getTypeIds(); - StringIdsSection stringIds = file.getStringIds(); - - if (cst instanceof CstAnnotation) { - addContents(file, ((CstAnnotation) cst).getAnnotation()); - } else if (cst instanceof CstArray) { - CstArray.List list = ((CstArray) cst).getList(); - int size = list.size(); - for (int i = 0; i < size; i++) { - addContents(file, list.get(i)); - } - } else { - file.internIfAppropriate(cst); - } - } -} diff --git a/dx/src/com/android/dx/rop/annotation/Annotation.java b/dx/src/com/android/dx/rop/annotation/Annotation.java deleted file mode 100644 index b7cf16494..000000000 --- a/dx/src/com/android/dx/rop/annotation/Annotation.java +++ /dev/null @@ -1,232 +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.android.dx.rop.annotation; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.cst.TypedConstant; -import com.android.dx.util.Hex; -import com.android.dx.util.MutabilityControl; -import com.android.dx.util.ToHuman; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.TreeMap; - -/** - * An annotation on an element of a class. Annotations have an - * associated type and additionally consist of a set of (name, value) - * pairs, where the names are unique. - */ -public final class Annotation extends MutabilityControl - implements Comparable<Annotation>, ToHuman { - /** non-null; type of the annotation */ - private final CstType type; - - /** non-null; the visibility of the annotation */ - private final AnnotationVisibility visibility; - - /** non-null; map from names to {@link NameValuePair} instances */ - private final TreeMap<CstUtf8, NameValuePair> elements; - - /** - * Construct an instance. It initially contains no elements. - * - * @param type non-null; type of the annotation - * @param visibility non-null; the visibility of the annotation - */ - public Annotation(CstType type, AnnotationVisibility visibility) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - if (visibility == null) { - throw new NullPointerException("visibility == null"); - } - - this.type = type; - this.visibility = visibility; - this.elements = new TreeMap<CstUtf8, NameValuePair>(); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (! (other instanceof Annotation)) { - return false; - } - - Annotation otherAnnotation = (Annotation) other; - - if (! (type.equals(otherAnnotation.type) - && (visibility == otherAnnotation.visibility))) { - return false; - } - - return elements.equals(otherAnnotation.elements); - } - - /** {@inheritDoc} */ - public int hashCode() { - int hash = type.hashCode(); - hash = (hash * 31) + elements.hashCode(); - hash = (hash * 31) + visibility.hashCode(); - return hash; - } - - /** {@inheritDoc} */ - public int compareTo(Annotation other) { - int result = type.compareTo(other.type); - - if (result != 0) { - return result; - } - - result = visibility.compareTo(other.visibility); - - if (result != 0) { - return result; - } - - Iterator<NameValuePair> thisIter = elements.values().iterator(); - Iterator<NameValuePair> otherIter = other.elements.values().iterator(); - - while (thisIter.hasNext() && otherIter.hasNext()) { - NameValuePair thisOne = thisIter.next(); - NameValuePair otherOne = otherIter.next(); - - result = thisOne.compareTo(otherOne); - if (result != 0) { - return result; - } - } - - if (thisIter.hasNext()) { - return 1; - } else if (otherIter.hasNext()) { - return -1; - } - - return 0; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return toHuman(); - } - - /** {@inheritDoc} */ - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - sb.append(visibility.toHuman()); - sb.append("-annotation "); - sb.append(type.toHuman()); - sb.append(" {"); - - boolean first = true; - for (NameValuePair pair : elements.values()) { - if (first) { - first = false; - } else { - sb.append(", "); - } - sb.append(pair.getName().toHuman()); - sb.append(": "); - sb.append(pair.getValue().toHuman()); - } - - sb.append("}"); - return sb.toString(); - } - - /** - * Gets the type of this instance. - * - * @return non-null; the type - */ - public CstType getType() { - return type; - } - - /** - * Gets the visibility of this instance. - * - * @return non-null; the visibility - */ - public AnnotationVisibility getVisibility() { - return visibility; - } - - /** - * Put an element into the set of (name, value) pairs for this instance. - * If there is a preexisting element with the same name, it will be - * replaced by this method. - * - * @param pair non-null; the (name, value) pair to place into this instance - */ - public void put(NameValuePair pair) { - throwIfImmutable(); - - if (pair == null) { - throw new NullPointerException("pair == null"); - } - - elements.put(pair.getName(), pair); - } - - /** - * Add an element to the set of (name, value) pairs for this instance. - * It is an error to call this method if there is a preexisting element - * with the same name. - * - * @param pair non-null; the (name, value) pair to add to this instance - */ - public void add(NameValuePair pair) { - throwIfImmutable(); - - if (pair == null) { - throw new NullPointerException("pair == null"); - } - - CstUtf8 name = pair.getName(); - - if (elements.get(name) != null) { - throw new IllegalArgumentException("name already added: " + name); - } - - elements.put(name, pair); - } - - /** - * Gets the set of name-value pairs contained in this instance. The - * result is always unmodifiable. - * - * @return non-null; the set of name-value pairs - */ - public Collection<NameValuePair> getNameValuePairs() { - return Collections.unmodifiableCollection(elements.values()); - } -} diff --git a/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java b/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java deleted file mode 100644 index c53fcd804..000000000 --- a/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java +++ /dev/null @@ -1,46 +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.android.dx.rop.annotation; - -import com.android.dx.util.ToHuman; - -/** - * Visibility scope of an annotation. - */ -public enum AnnotationVisibility implements ToHuman { - RUNTIME("runtime"), - BUILD("build"), - SYSTEM("system"), - EMBEDDED("embedded"); - - /** non-null; the human-oriented string representation */ - private final String human; - - /** - * Constructs an instance. - * - * @param human non-null; the human-oriented string representation - */ - private AnnotationVisibility(String human) { - this.human = human; - } - - /** {@inheritDoc} */ - public String toHuman() { - return human; - } -} diff --git a/dx/src/com/android/dx/rop/annotation/Annotations.java b/dx/src/com/android/dx/rop/annotation/Annotations.java deleted file mode 100644 index c1da88364..000000000 --- a/dx/src/com/android/dx/rop/annotation/Annotations.java +++ /dev/null @@ -1,213 +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.android.dx.rop.annotation; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.util.MutabilityControl; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.TreeMap; - -/** - * List of {@link Annotation} instances. - */ -public final class Annotations extends MutabilityControl - implements Comparable<Annotations> { - /** non-null; immutable empty instance */ - public static final Annotations EMPTY = new Annotations(); - - static { - EMPTY.setImmutable(); - } - - /** non-null; map from types to annotations */ - private final TreeMap<CstType, Annotation> annotations; - - /** - * Constructs an immutable instance which is the combination of the - * two given instances. The two instances must contain disjoint sets - * of types. - * - * @param a1 non-null; an instance - * @param a2 non-null; the other instance - * @return non-null; the combination - * @throws IllegalArgumentException thrown if there is a duplicate type - */ - public static Annotations combine(Annotations a1, Annotations a2) { - Annotations result = new Annotations(); - - result.addAll(a1); - result.addAll(a2); - result.setImmutable(); - - return result; - } - - /** - * Constructs an immutable instance which is the combination of the - * given instance with the given additional annotation. The latter's - * type must not already appear in the former. - * - * @param annotations non-null; the instance to augment - * @param annotation non-null; the additional annotation - * @return non-null; the combination - * @throws IllegalArgumentException thrown if there is a duplicate type - */ - public static Annotations combine(Annotations annotations, - Annotation annotation) { - Annotations result = new Annotations(); - - result.addAll(annotations); - result.add(annotation); - result.setImmutable(); - - return result; - } - - /** - * Constructs an empty instance. - */ - public Annotations() { - annotations = new TreeMap<CstType, Annotation>(); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return annotations.hashCode(); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (! (other instanceof Annotations)) { - return false; - } - - Annotations otherAnnotations = (Annotations) other; - - return annotations.equals(otherAnnotations.annotations); - } - - /** {@inheritDoc} */ - public int compareTo(Annotations other) { - Iterator<Annotation> thisIter = annotations.values().iterator(); - Iterator<Annotation> otherIter = other.annotations.values().iterator(); - - while (thisIter.hasNext() && otherIter.hasNext()) { - Annotation thisOne = thisIter.next(); - Annotation otherOne = otherIter.next(); - - int result = thisOne.compareTo(otherOne); - if (result != 0) { - return result; - } - } - - if (thisIter.hasNext()) { - return 1; - } else if (otherIter.hasNext()) { - return -1; - } - - return 0; - } - - /** {@inheritDoc} */ - public String toString() { - StringBuilder sb = new StringBuilder(); - boolean first = true; - - sb.append("annotations{"); - - for (Annotation a : annotations.values()) { - if (first) { - first = false; - } else { - sb.append(", "); - } - sb.append(a.toHuman()); - } - - sb.append("}"); - return sb.toString(); - } - - /** - * Gets the number of elements in this instance. - * - * @return >= 0; the size - */ - public int size() { - return annotations.size(); - } - - /** - * Adds an element to this instance. There must not already be an - * element of the same type. - * - * @param annotation non-null; the element to add - * @throws IllegalArgumentException thrown if there is a duplicate type - */ - public void add(Annotation annotation) { - throwIfImmutable(); - - if (annotation == null) { - throw new NullPointerException("annotation == null"); - } - - CstType type = annotation.getType(); - - if (annotations.containsKey(type)) { - throw new IllegalArgumentException("duplicate type: " + - type.toHuman()); - } - - annotations.put(type, annotation); - } - - /** - * Adds all of the elements of the given instance to this one. The - * instances must not have any duplicate types. - * - * @param toAdd non-null; the annotations to add - * @throws IllegalArgumentException thrown if there is a duplicate type - */ - public void addAll(Annotations toAdd) { - throwIfImmutable(); - - if (toAdd == null) { - throw new NullPointerException("toAdd == null"); - } - - for (Annotation a : toAdd.annotations.values()) { - add(a); - } - } - - /** - * Gets the set of annotations contained in this instance. The - * result is always unmodifiable. - * - * @return non-null; the set of annotations - */ - public Collection<Annotation> getAnnotations() { - return Collections.unmodifiableCollection(annotations.values()); - } -} diff --git a/dx/src/com/android/dx/rop/annotation/AnnotationsList.java b/dx/src/com/android/dx/rop/annotation/AnnotationsList.java deleted file mode 100644 index 43a07ba94..000000000 --- a/dx/src/com/android/dx/rop/annotation/AnnotationsList.java +++ /dev/null @@ -1,91 +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.android.dx.rop.annotation; - -import com.android.dx.util.FixedSizeList; - -/** - * List of {@link Annotations} instances. - */ -public final class AnnotationsList - extends FixedSizeList { - /** non-null; immutable empty instance */ - public static final AnnotationsList EMPTY = new AnnotationsList(0); - - /** - * Constructs an immutable instance which is the combination of - * the two given instances. The two instances must each have the - * same number of elements, and each pair of elements must contain - * disjoint sets of types. - * - * @param list1 non-null; an instance - * @param list2 non-null; the other instance - * @return non-null; the combination - */ - public static AnnotationsList combine(AnnotationsList list1, - AnnotationsList list2) { - int size = list1.size(); - - if (size != list2.size()) { - throw new IllegalArgumentException("list1.size() != list2.size()"); - } - - AnnotationsList result = new AnnotationsList(size); - - for (int i = 0; i < size; i++) { - Annotations a1 = list1.get(i); - Annotations a2 = list2.get(i); - result.set(i, Annotations.combine(a1, a2)); - } - - result.setImmutable(); - return result; - } - - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size the size of the list - */ - public AnnotationsList(int size) { - super(size); - } - - /** - * Gets the element at the given index. 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</code>. - * - * @param n >= 0, < size(); which index - * @return non-null; element at that index - */ - public Annotations get(int n) { - return (Annotations) get0(n); - } - - /** - * Sets the element at the given index. The given element must be - * immutable. - * - * @param n >= 0, < size(); which index - * @param a null-ok; the element to set at <code>n</code> - */ - public void set(int n, Annotations a) { - a.throwIfMutable(); - set0(n, a); - } -} diff --git a/dx/src/com/android/dx/rop/annotation/NameValuePair.java b/dx/src/com/android/dx/rop/annotation/NameValuePair.java deleted file mode 100644 index dadabaa71..000000000 --- a/dx/src/com/android/dx/rop/annotation/NameValuePair.java +++ /dev/null @@ -1,112 +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.android.dx.rop.annotation; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstUtf8; - -/** - * A (name, value) pair. These are used as the contents of an annotation. - */ -public final class NameValuePair implements Comparable<NameValuePair> { - /** non-null; the name */ - private final CstUtf8 name; - - /** non-null; the value */ - private final Constant value; - - /** - * Construct an instance. - * - * @param name non-null; the name - * @param value non-null; the value - */ - public NameValuePair(CstUtf8 name, Constant value) { - if (name == null) { - throw new NullPointerException("name == null"); - } - - if (value == null) { - throw new NullPointerException("value == null"); - } - - // Reject CstUtf8 values. (They should be CstStrings.) - if (value instanceof CstUtf8) { - throw new IllegalArgumentException("bad value: " + value); - } - - this.name = name; - this.value = value; - } - - /** {@inheritDoc} */ - public String toString() { - return name.toHuman() + ":" + value; - } - - /** {@inheritDoc} */ - public int hashCode() { - return name.hashCode() * 31 + value.hashCode(); - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof NameValuePair)) { - return false; - } - - NameValuePair otherPair = (NameValuePair) other; - - return name.equals(otherPair.name) - && value.equals(otherPair.value); - } - - /** - * {@inheritDoc} - * - * <p>Instances of this class compare in name-major and value-minor - * order.</p> - */ - public int compareTo(NameValuePair other) { - int result = name.compareTo(other.name); - - if (result != 0) { - return result; - } - - return value.compareTo(other.value); - } - - /** - * Gets the name. - * - * @return non-null; the name - */ - public CstUtf8 getName() { - return name; - } - - /** - * Gets the value. - * - * @return non-null; the valute - */ - public Constant getValue() { - return value; - } -} diff --git a/dx/src/com/android/dx/rop/code/AccessFlags.java b/dx/src/com/android/dx/rop/code/AccessFlags.java deleted file mode 100644 index 265cfa619..000000000 --- a/dx/src/com/android/dx/rop/code/AccessFlags.java +++ /dev/null @@ -1,374 +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.android.dx.rop.code; - -import com.android.dx.util.Hex; - -/** - * Constants used as "access flags" in various places in classes, and - * related utilities. Although, at the rop layer, flags are generally - * ignored, this is the layer of communication, and as such, this - * package is where these definitions belong. The flag definitions are - * identical to Java access flags, but <code>ACC_SUPER</code> isn't - * used at all in translated code, and <code>ACC_SYNCHRONIZED</code> - * is only used in a very limited way. - */ -public final class AccessFlags { - /** public member / class */ - public static final int ACC_PUBLIC = 0x0001; - - /** private member */ - public static final int ACC_PRIVATE = 0x0002; - - /** protected member */ - public static final int ACC_PROTECTED = 0x0004; - - /** static member */ - public static final int ACC_STATIC = 0x0008; - - /** final member / class */ - public static final int ACC_FINAL = 0x0010; - - /** - * synchronized method; only valid in dex files for <code>native</code> - * methods - */ - public static final int ACC_SYNCHRONIZED = 0x0020; - - /** - * class with new-style <code>invokespecial</code> for superclass - * method access - */ - public static final int ACC_SUPER = 0x0020; - - /** volatile field */ - public static final int ACC_VOLATILE = 0x0040; - - /** bridge method (generated) */ - public static final int ACC_BRIDGE = 0x0040; - - /** transient field */ - public static final int ACC_TRANSIENT = 0x0080; - - /** varargs method */ - public static final int ACC_VARARGS = 0x0080; - - /** native method */ - public static final int ACC_NATIVE = 0x0100; - - /** "class" is in fact an public static final interface */ - public static final int ACC_INTERFACE = 0x0200; - - /** abstract method / class */ - public static final int ACC_ABSTRACT = 0x0400; - - /** - * method with strict floating point (<code>strictfp</code>) - * behavior - */ - public static final int ACC_STRICT = 0x0800; - - /** synthetic member */ - public static final int ACC_SYNTHETIC = 0x1000; - - /** class is an annotation type */ - public static final int ACC_ANNOTATION = 0x2000; - - /** - * class is an enumerated type; field is an element of an enumerated - * type - */ - public static final int ACC_ENUM = 0x4000; - - /** method is a constructor */ - public static final int ACC_CONSTRUCTOR = 0x10000; - - /** - * method was declared <code>synchronized</code>; has no effect on - * execution (other than inspecting this flag, per se) - */ - public static final int ACC_DECLARED_SYNCHRONIZED = 0x20000; - - /** flags defined on classes */ - public static final int CLASS_FLAGS = - ACC_PUBLIC | ACC_FINAL | ACC_SUPER | ACC_INTERFACE | ACC_ABSTRACT | - ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM; - - /** flags defined on inner classes */ - public static final int INNER_CLASS_FLAGS = - ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | - ACC_INTERFACE | ACC_ABSTRACT | ACC_SYNTHETIC | ACC_ANNOTATION | - ACC_ENUM; - - /** flags defined on fields */ - public static final int FIELD_FLAGS = - ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | - ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM; - - /** flags defined on methods */ - public static final int METHOD_FLAGS = - ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | - ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE | - ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR | - ACC_DECLARED_SYNCHRONIZED; - - /** indicates conversion of class flags */ - private static final int CONV_CLASS = 1; - - /** indicates conversion of field flags */ - private static final int CONV_FIELD = 2; - - /** indicates conversion of method flags */ - private static final int CONV_METHOD = 3; - - /** - * This class is uninstantiable. - */ - private AccessFlags() { - // This space intentionally left blank. - } - - /** - * Returns a human-oriented string representing the given access flags, - * as defined on classes (not fields or methods). - * - * @param flags the flags - * @return non-null; human-oriented string - */ - public static String classString(int flags) { - return humanHelper(flags, CLASS_FLAGS, CONV_CLASS); - } - - /** - * Returns a human-oriented string representing the given access flags, - * as defined on inner classes. - * - * @param flags the flags - * @return non-null; human-oriented string - */ - public static String innerClassString(int flags) { - return humanHelper(flags, INNER_CLASS_FLAGS, CONV_CLASS); - } - - /** - * Returns a human-oriented string representing the given access flags, - * as defined on fields (not classes or methods). - * - * @param flags the flags - * @return non-null; human-oriented string - */ - public static String fieldString(int flags) { - return humanHelper(flags, FIELD_FLAGS, CONV_FIELD); - } - - /** - * Returns a human-oriented string representing the given access flags, - * as defined on methods (not classes or fields). - * - * @param flags the flags - * @return non-null; human-oriented string - */ - public static String methodString(int flags) { - return humanHelper(flags, METHOD_FLAGS, CONV_METHOD); - } - - /** - * Returns whether the flag <code>ACC_PUBLIC</code> is on in the given - * flags. - * - * @param flags the flags to check - * @return the value of the <code>ACC_PUBLIC</code> flag - */ - public static boolean isPublic(int flags) { - return (flags & ACC_PUBLIC) != 0; - } - - /** - * Returns whether the flag <code>ACC_PROTECTED</code> is on in the given - * flags. - * - * @param flags the flags to check - * @return the value of the <code>ACC_PROTECTED</code> flag - */ - public static boolean isProtected(int flags) { - return (flags & ACC_PROTECTED) != 0; - } - - /** - * Returns whether the flag <code>ACC_PRIVATE</code> is on in the given - * flags. - * - * @param flags the flags to check - * @return the value of the <code>ACC_PRIVATE</code> flag - */ - public static boolean isPrivate(int flags) { - return (flags & ACC_PRIVATE) != 0; - } - - /** - * Returns whether the flag <code>ACC_STATIC</code> is on in the given - * flags. - * - * @param flags the flags to check - * @return the value of the <code>ACC_STATIC</code> flag - */ - public static boolean isStatic(int flags) { - return (flags & ACC_STATIC) != 0; - } - - /** - * Returns whether the flag <code>ACC_SYNCHRONIZED</code> is on in - * the given flags. - * - * @param flags the flags to check - * @return the value of the <code>ACC_SYNCHRONIZED</code> flag - */ - public static boolean isSynchronized(int flags) { - return (flags & ACC_SYNCHRONIZED) != 0; - } - - /** - * Returns whether the flag <code>ACC_ABSTRACT</code> is on in the given - * flags. - * - * @param flags the flags to check - * @return the value of the <code>ACC_ABSTRACT</code> flag - */ - public static boolean isAbstract(int flags) { - return (flags & ACC_ABSTRACT) != 0; - } - - /** - * Returns whether the flag <code>ACC_NATIVE</code> is on in the given - * flags. - * - * @param flags the flags to check - * @return the value of the <code>ACC_NATIVE</code> flag - */ - public static boolean isNative(int flags) { - return (flags & ACC_NATIVE) != 0; - } - - /** - * Returns whether the flag <code>ACC_ANNOTATION</code> is on in the given - * flags. - * - * @param flags the flags to check - * @return the value of the <code>ACC_ANNOTATION</code> flag - */ - public static boolean isAnnotation(int flags) { - return (flags & ACC_ANNOTATION) != 0; - } - - /** - * Returns whether the flag <code>ACC_DECLARED_SYNCHRONIZED</code> is - * on in the given flags. - * - * @param flags the flags to check - * @return the value of the <code>ACC_DECLARED_SYNCHRONIZED</code> flag - */ - public static boolean isDeclaredSynchronized(int flags) { - return (flags & ACC_DECLARED_SYNCHRONIZED) != 0; - } - - /** - * Helper to return a human-oriented string representing the given - * access flags. - * - * @param flags the defined flags - * @param mask mask for the "defined" bits - * @param what what the flags represent (one of <code>CONV_*</code>) - * @return non-null; human-oriented string - */ - private static String humanHelper(int flags, int mask, int what) { - StringBuffer sb = new StringBuffer(80); - int extra = flags & ~mask; - - flags &= mask; - - if ((flags & ACC_PUBLIC) != 0) { - sb.append("|public"); - } - if ((flags & ACC_PRIVATE) != 0) { - sb.append("|private"); - } - if ((flags & ACC_PROTECTED) != 0) { - sb.append("|protected"); - } - if ((flags & ACC_STATIC) != 0) { - sb.append("|static"); - } - if ((flags & ACC_FINAL) != 0) { - sb.append("|final"); - } - if ((flags & ACC_SYNCHRONIZED) != 0) { - if (what == CONV_CLASS) { - sb.append("|super"); - } else { - sb.append("|synchronized"); - } - } - if ((flags & ACC_VOLATILE) != 0) { - if (what == CONV_METHOD) { - sb.append("|bridge"); - } else { - sb.append("|volatile"); - } - } - if ((flags & ACC_TRANSIENT) != 0) { - if (what == CONV_METHOD) { - sb.append("|varargs"); - } else { - sb.append("|transient"); - } - } - if ((flags & ACC_NATIVE) != 0) { - sb.append("|native"); - } - if ((flags & ACC_INTERFACE) != 0) { - sb.append("|interface"); - } - if ((flags & ACC_ABSTRACT) != 0) { - sb.append("|abstract"); - } - if ((flags & ACC_STRICT) != 0) { - sb.append("|strictfp"); - } - if ((flags & ACC_SYNTHETIC) != 0) { - sb.append("|synthetic"); - } - if ((flags & ACC_ANNOTATION) != 0) { - sb.append("|annotation"); - } - if ((flags & ACC_ENUM) != 0) { - sb.append("|enum"); - } - if ((flags & ACC_CONSTRUCTOR) != 0) { - sb.append("|constructor"); - } - if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) { - sb.append("|declared_synchronized"); - } - - if ((extra != 0) || (sb.length() == 0)) { - sb.append('|'); - sb.append(Hex.u2(extra)); - } - - return sb.substring(1); - } -} diff --git a/dx/src/com/android/dx/rop/code/BasicBlock.java b/dx/src/com/android/dx/rop/code/BasicBlock.java deleted file mode 100644 index 66db5aa29..000000000 --- a/dx/src/com/android/dx/rop/code/BasicBlock.java +++ /dev/null @@ -1,281 +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.android.dx.rop.code; - -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; -import com.android.dx.util.LabeledItem; - -/** - * Basic block of register-based instructions. - */ -public final class BasicBlock implements LabeledItem { - /** >= 0; target label for this block */ - private final int label; - - /** non-null; list of instructions in this block */ - private final InsnList insns; - - /** - * non-null; full list of successors that this block may - * branch to - */ - private final IntList successors; - - /** - * >= -1; the primary / standard-flow / "default" successor, or - * <code>-1</code> if this block has no successors (that is, it - * exits the function/method) - */ - private final int primarySuccessor; - - /** - * Constructs an instance. The predecessor set is set to <code>null</code>. - * - * @param label >= 0; target label for this block - * @param insns non-null; list of instructions in this block - * @param successors non-null; full list of successors that this - * block may branch to - * @param primarySuccessor >= -1; the primary / standard-flow / - * "default" successor, or <code>-1</code> if this block has no - * successors (that is, it exits the function/method or is an - * unconditional throw) - */ - public BasicBlock(int label, InsnList insns, IntList successors, - int primarySuccessor) { - if (label < 0) { - throw new IllegalArgumentException("label < 0"); - } - - try { - insns.throwIfMutable(); - } catch (NullPointerException ex) { - // Elucidate exception. - throw new NullPointerException("insns == null"); - } - - int sz = insns.size(); - - if (sz == 0) { - throw new IllegalArgumentException("insns.size() == 0"); - } - - for (int i = sz - 2; i >= 0; i--) { - Rop one = insns.get(i).getOpcode(); - if (one.getBranchingness() != Rop.BRANCH_NONE) { - throw new IllegalArgumentException("insns[" + i + "] is a " + - "branch or can throw"); - } - } - - Insn lastInsn = insns.get(sz - 1); - if (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) { - throw new IllegalArgumentException("insns does not end with " + - "a branch or throwing " + - "instruction"); - } - - try { - successors.throwIfMutable(); - } catch (NullPointerException ex) { - // Elucidate exception. - throw new NullPointerException("successors == null"); - } - - if (primarySuccessor < -1) { - throw new IllegalArgumentException("primarySuccessor < -1"); - } - - if (primarySuccessor >= 0 && !successors.contains(primarySuccessor)) { - throw new IllegalArgumentException( - "primarySuccessor not in successors"); - } - - this.label = label; - this.insns = insns; - this.successors = successors; - this.primarySuccessor = primarySuccessor; - } - - /** - * {@inheritDoc} - * - * Instances of this class compare by identity. That is, - * <code>x.equals(y)</code> is only true if <code>x == y</code>. - */ - @Override - public boolean equals(Object other) { - return (this == other); - } - - /** - * {@inheritDoc} - * - * Return the identity hashcode of this instance. This is proper, - * since instances of this class compare by identity (see {@link #equals}). - */ - @Override - public int hashCode() { - return System.identityHashCode(this); - } - - /** - * Gets the target label of this block. - * - * @return >= 0; the label - */ - public int getLabel() { - return label; - } - - /** - * Gets the list of instructions inside this block. - * - * @return non-null; the instruction list - */ - public InsnList getInsns() { - return insns; - } - - /** - * Gets the list of successors that this block may branch to. - * - * @return non-null; the successors list - */ - public IntList getSuccessors() { - return successors; - } - - /** - * Gets the primary successor of this block. - * - * @return >= -1; the primary successor, or <code>-1</code> if this - * block has no successors at all - */ - public int getPrimarySuccessor() { - return primarySuccessor; - } - - /** - * Gets the secondary successor of this block. It is only valid to call - * this method on blocks that have exactly two successors. - * - * @return >= 0; the secondary successor - */ - public int getSecondarySuccessor() { - if (successors.size() != 2) { - throw new UnsupportedOperationException( - "block doesn't have exactly two successors"); - } - - int succ = successors.get(0); - if (succ == primarySuccessor) { - succ = successors.get(1); - } - - return succ; - } - - /** - * Gets the first instruction of this block. This is just a - * convenient shorthand for <code>getInsns().get(0)</code>. - * - * @return non-null; the first instruction - */ - public Insn getFirstInsn() { - return insns.get(0); - } - - /** - * Gets the last instruction of this block. This is just a - * convenient shorthand for <code>getInsns().getLast()</code>. - * - * @return non-null; the last instruction - */ - public Insn getLastInsn() { - return insns.getLast(); - } - - /** - * Returns whether this block might throw an exception. This is - * just a convenient shorthand for <code>getLastInsn().canThrow()</code>. - * - * @return <code>true</code> iff this block might throw an - * exception - */ - public boolean canThrow() { - return insns.getLast().canThrow(); - } - - /** - * Returns whether this block has any associated exception handlers. - * This is just a shorthand for inspecting the last instruction in - * the block to see if it could throw, and if so, whether it in fact - * has any associated handlers. - * - * @return <code>true</code> iff this block has any associated - * exception handlers - */ - public boolean hasExceptionHandlers() { - Insn lastInsn = insns.getLast(); - return lastInsn.getCatches().size() != 0; - } - - /** - * Returns the exception handler types associated with this block, - * if any. This is just a shorthand for inspecting the last - * instruction in the block to see if it could throw, and if so, - * grabbing the catch list out of it. If not, this returns an - * empty list (not <code>null</code>). - * - * @return non-null; the exception handler types associated with - * this block - */ - public TypeList getExceptionHandlerTypes() { - Insn lastInsn = insns.getLast(); - return lastInsn.getCatches(); - } - - /** - * Returns an instance that is identical to this one, except that - * the registers in each instruction are offset by the given - * amount. - * - * @param delta the amount to offset register numbers by - * @return non-null; an appropriately-constructed instance - */ - public BasicBlock withRegisterOffset(int delta) { - return new BasicBlock(label, insns.withRegisterOffset(delta), - successors, primarySuccessor); - } - - public String toString() { - return '{' + Hex.u2(label) + '}'; - } - - /** - * BasicBlock visitor interface - */ - public interface Visitor { - /** - * Visits a basic block - * @param b block visited - */ - public void visitBlock (BasicBlock b); - } -} diff --git a/dx/src/com/android/dx/rop/code/BasicBlockList.java b/dx/src/com/android/dx/rop/code/BasicBlockList.java deleted file mode 100644 index 6564318e1..000000000 --- a/dx/src/com/android/dx/rop/code/BasicBlockList.java +++ /dev/null @@ -1,398 +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.android.dx.rop.code; - -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; -import com.android.dx.util.LabeledList; - -/** - * List of {@link BasicBlock} instances. - */ -public final class BasicBlockList extends LabeledList { - /** - * >= -1; the count of registers required by this method or - * <code>-1</code> if not yet calculated - */ - private int regCount; - - /** - * Constructs an instance. All indices initially contain <code>null</code>, - * and the first-block label is initially <code>-1</code>. - * - * @param size the size of the list - */ - public BasicBlockList(int size) { - super(size); - - regCount = -1; - } - - /** - * Constructs a mutable copy for <code>getMutableCopy()</code>. - * - * @param old block to copy - */ - private BasicBlockList (BasicBlockList old) { - super(old); - regCount = old.regCount; - } - - - /** - * Gets the element at the given index. 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</code>. - * - * @param n >= 0, < size(); which index - * @return non-null; element at that index - */ - public BasicBlock get(int n) { - return (BasicBlock) get0(n); - } - - /** - * Sets the basic block at the given index. - * - * @param n >= 0, < size(); which index - * @param bb null-ok; the element to set at <code>n</code> - */ - public void set(int n, BasicBlock bb) { - super.set(n, bb); - - // Reset regCount, since it will need to be recalculated. - regCount = -1; - } - - /** - * Returns how many registers this method requires. This is simply - * the maximum of register-number-plus-category referred to by this - * instance's instructions (indirectly through {@link BasicBlock} - * instances). - * - * @return >= 0; the register count - */ - public int getRegCount() { - if (regCount == -1) { - RegCountVisitor visitor = new RegCountVisitor(); - forEachInsn(visitor); - regCount = visitor.getRegCount(); - } - - return regCount; - } - - /** - * Gets the total instruction count for this instance. This is the - * sum of the instruction counts of each block. - * - * @return >= 0; the total instruction count - */ - public int getInstructionCount() { - int sz = size(); - int result = 0; - - for (int i = 0; i < sz; i++) { - BasicBlock one = (BasicBlock) getOrNull0(i); - if (one != null) { - result += one.getInsns().size(); - } - } - - return result; - } - - /** - * Gets the total instruction count for this instance, ignoring - * mark-local instructions which are not actually emitted. - * - * @return >= 0; the total instruction count - */ - public int getEffectiveInstructionCount() { - int sz = size(); - int result = 0; - - for (int i = 0; i < sz; i++) { - BasicBlock one = (BasicBlock) getOrNull0(i); - if (one != null) { - InsnList insns = one.getInsns(); - int insnsSz = insns.size(); - - for (int j = 0; j < insnsSz; j++) { - Insn insn = insns.get(j); - - if (insn.getOpcode().getOpcode() != RegOps.MARK_LOCAL) { - result++; - } - } - } - } - - return result; - } - - - /** - * Gets the first block in the list with the given label, if any. - * - * @param label >= 0; the label to look for - * @return non-null; the so-labelled block - * @throws IllegalArgumentException thrown if the label isn't found - */ - public BasicBlock labelToBlock(int label) { - int idx = indexOfLabel(label); - - if (idx < 0) { - throw new IllegalArgumentException("no such label: " - + Hex.u2(label)); - } - - return get(idx); - } - - /** - * Visits each instruction of each block in the list, in order. - * - * @param visitor non-null; visitor to use - */ - public void forEachInsn(Insn.Visitor visitor) { - int sz = size(); - - for (int i = 0; i < sz; i++) { - BasicBlock one = get(i); - InsnList insns = one.getInsns(); - insns.forEach(visitor); - } - } - - /** - * Returns an instance that is identical to this one, except that - * the registers in each instruction are offset by the given - * amount. Mutability of the result is inherited from the - * original. - * - * @param delta the amount to offset register numbers by - * @return non-null; an appropriately-constructed instance - */ - public BasicBlockList withRegisterOffset(int delta) { - int sz = size(); - BasicBlockList result = new BasicBlockList(sz); - - for (int i = 0; i < sz; i++) { - BasicBlock one = (BasicBlock) get0(i); - if (one != null) { - result.set(i, one.withRegisterOffset(delta)); - } - } - - if (isImmutable()) { - result.setImmutable(); - } - - return result; - } - - /** - * Returns a mutable copy of this list. - * - * @return non-null; an appropriately-constructed instance - */ - public BasicBlockList getMutableCopy() { - return new BasicBlockList(this); - } - - /** - * Gets the preferred successor for the given block. If the block - * only has one successor, then that is the preferred successor. - * Otherwise, if the block has a primay successor, then that is - * the preferred successor. If the block has no successors, then - * this returns <code>null</code>. - * - * @param block non-null; the block in question - * @return null-ok; the preferred successor, if any - */ - public BasicBlock preferredSuccessorOf(BasicBlock block) { - int primarySuccessor = block.getPrimarySuccessor(); - IntList successors = block.getSuccessors(); - int succSize = successors.size(); - - switch (succSize) { - case 0: { - return null; - } - case 1: { - return labelToBlock(successors.get(0)); - } - } - - if (primarySuccessor != -1) { - return labelToBlock(primarySuccessor); - } else { - return labelToBlock(successors.get(0)); - } - } - - /** - * Compares the catches of two blocks for equality. This includes - * both the catch types and target labels. - * - * @param block1 non-null; one block to compare - * @param block2 non-null; the other block to compare - * @return <code>true</code> if the two blocks' non-primary successors - * are identical - */ - public boolean catchesEqual(BasicBlock block1, - BasicBlock block2) { - TypeList catches1 = block1.getExceptionHandlerTypes(); - TypeList catches2 = block2.getExceptionHandlerTypes(); - - if (!StdTypeList.equalContents(catches1, catches2)) { - return false; - } - - IntList succ1 = block1.getSuccessors(); - IntList succ2 = block2.getSuccessors(); - int size = succ1.size(); // Both are guaranteed to be the same size. - - int primary1 = block1.getPrimarySuccessor(); - int primary2 = block2.getPrimarySuccessor(); - - if (((primary1 == -1) || (primary2 == -1)) - && (primary1 != primary2)) { - /* - * For the current purpose, both blocks in question must - * either both have a primary or both not have a primary to - * be considered equal, and it turns out here that that's not - * the case. - */ - return false; - } - - for (int i = 0; i < size; i++) { - int label1 = succ1.get(i); - int label2 = succ2.get(i); - - if (label1 == primary1) { - /* - * It should be the case that block2's primary is at the - * same index. If not, we consider the blocks unequal for - * the current purpose. - */ - if (label2 != primary2) { - return false; - } - continue; - } - - if (label1 != label2) { - return false; - } - } - - return true; - } - - /** - * Instruction visitor class for counting registers used. - */ - private static class RegCountVisitor - implements Insn.Visitor { - /** >= 0; register count in-progress */ - private int regCount; - - /** - * Constructs an instance. - */ - public RegCountVisitor() { - regCount = 0; - } - - /** - * Gets the register count. - * - * @return >= 0; the count - */ - public int getRegCount() { - return regCount; - } - - /** {@inheritDoc} */ - public void visitPlainInsn(PlainInsn insn) { - visit(insn); - } - - /** {@inheritDoc} */ - public void visitPlainCstInsn(PlainCstInsn insn) { - visit(insn); - } - - /** {@inheritDoc} */ - public void visitSwitchInsn(SwitchInsn insn) { - visit(insn); - } - - /** {@inheritDoc} */ - public void visitThrowingCstInsn(ThrowingCstInsn insn) { - visit(insn); - } - - /** {@inheritDoc} */ - public void visitThrowingInsn(ThrowingInsn insn) { - visit(insn); - } - - /** {@inheritDoc} */ - public void visitFillArrayDataInsn(FillArrayDataInsn insn) { - visit(insn); - } - - /** - * Helper for all the <code>visit*</code> methods. - * - * @param insn non-null; instruction being visited - */ - private void visit(Insn insn) { - RegisterSpec result = insn.getResult(); - - if (result != null) { - processReg(result); - } - - RegisterSpecList sources = insn.getSources(); - int sz = sources.size(); - - for (int i = 0; i < sz; i++) { - processReg(sources.get(i)); - } - } - - /** - * Processes the given register spec. - * - * @param spec non-null; the register spec - */ - private void processReg(RegisterSpec spec) { - int reg = spec.getNextReg(); - - if (reg > regCount) { - regCount = reg; - } - } - } -} diff --git a/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java b/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java deleted file mode 100644 index a9da10932..000000000 --- a/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java +++ /dev/null @@ -1,52 +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.android.dx.rop.code; - -/** - * Implementation of {@link TranslationAdvice} which conservatively answers - * <code>false</code> to all methods. - */ -public final class ConservativeTranslationAdvice - implements TranslationAdvice { - /** non-null; standard instance of this class */ - public static final ConservativeTranslationAdvice THE_ONE = - new ConservativeTranslationAdvice(); - - /** - * This class is not publicly instantiable. Use {@link #THE_ONE}. - */ - private ConservativeTranslationAdvice() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public boolean hasConstantOperation(Rop opcode, - RegisterSpec sourceA, RegisterSpec sourceB) { - return false; - } - - /** {@inheritDoc} */ - public boolean requiresSourcesInOrder(Rop opcode, - RegisterSpecList sources) { - return false; - } - - /** {@inheritDoc} */ - public int getMaxOptimalRegisterCount() { - return Integer.MAX_VALUE; - } -} diff --git a/dx/src/com/android/dx/rop/code/CstInsn.java b/dx/src/com/android/dx/rop/code/CstInsn.java deleted file mode 100644 index d1cf523a5..000000000 --- a/dx/src/com/android/dx/rop/code/CstInsn.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.android.dx.rop.code; - -import com.android.dx.rop.cst.Constant; - -/** - * Instruction which contains an explicit reference to a constant. - */ -public abstract class CstInsn - extends Insn { - /** non-null; the constant */ - private final Constant cst; - - /** - * Constructs an instance. - * - * @param opcode non-null; the opcode - * @param position non-null; source position - * @param result null-ok; spec for the result, if any - * @param sources non-null; specs for all the sources - * @param cst non-null; constant - */ - public CstInsn(Rop opcode, SourcePosition position, RegisterSpec result, - RegisterSpecList sources, Constant cst) { - super(opcode, position, result, sources); - - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - this.cst = cst; - } - - /** {@inheritDoc} */ - @Override - public String getInlineString() { - return cst.toHuman(); - } - - /** - * Gets the constant. - * - * @return non-null; the constant - */ - public Constant getConstant() { - return cst; - } - - /** {@inheritDoc} */ - @Override - public boolean contentEquals(Insn b) { - /* - * The cast (CstInsn)b below should always succeed since - * Insn.contentEquals compares classes of this and b. - */ - return super.contentEquals(b) - && cst.equals(((CstInsn)b).getConstant()); - } -} diff --git a/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java b/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java deleted file mode 100644 index 1c2382464..000000000 --- a/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java +++ /dev/null @@ -1,119 +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.android.dx.rop.code; - -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.type.Type; - -/** - * Implementation of {@link TranslationAdvice} which represents what - * the dex format will be able to represent. - */ -public final class DexTranslationAdvice - implements TranslationAdvice { - /** non-null; standard instance of this class */ - public static final DexTranslationAdvice THE_ONE = - new DexTranslationAdvice(); - - /** debug advice for disabling invoke-range optimization */ - public static final DexTranslationAdvice NO_SOURCES_IN_ORDER = - new DexTranslationAdvice(true); - - /** - * The minimum source width, in register units, for an invoke - * instruction that requires its sources to be in order and contiguous. - */ - private static final int MIN_INVOKE_IN_ORDER = 6; - - /** when true: always returns false for requiresSourcesInOrder */ - private final boolean disableSourcesInOrder; - - /** - * This class is not publicly instantiable. Use {@link #THE_ONE}. - */ - private DexTranslationAdvice() { - disableSourcesInOrder = false; - } - - private DexTranslationAdvice(boolean disableInvokeRange) { - this.disableSourcesInOrder = disableInvokeRange; - } - - /** {@inheritDoc} */ - public boolean hasConstantOperation(Rop opcode, - RegisterSpec sourceA, RegisterSpec sourceB) { - if (sourceA.getType() != Type.INT) { - return false; - } - - if (! (sourceB.getTypeBearer() instanceof CstInteger)) { - return false; - } - - CstInteger cst = (CstInteger) sourceB.getTypeBearer(); - - // TODO handle rsub - switch (opcode.getOpcode()) { - // These have 8 and 16 bit cst representations - case RegOps.REM: - case RegOps.ADD: - case RegOps.MUL: - case RegOps.DIV: - case RegOps.AND: - case RegOps.OR: - case RegOps.XOR: - return cst.fitsIn16Bits(); - // These only have 8 bit cst reps - case RegOps.SHL: - case RegOps.SHR: - case RegOps.USHR: - return cst.fitsIn8Bits(); - default: - return false; - } - } - - /** {@inheritDoc} */ - public boolean requiresSourcesInOrder(Rop opcode, - RegisterSpecList sources) { - - return !disableSourcesInOrder && opcode.isCallLike() - && totalRopWidth(sources) >= MIN_INVOKE_IN_ORDER; - } - - /** - * Calculates the total rop width of the list of SSA registers - * - * @param sources non-null; list of SSA registers - * @return >= 0 rop-form width in register units - */ - private int totalRopWidth(RegisterSpecList sources) { - int sz = sources.size(); - int total = 0; - - for (int i = 0; i < sz; i++) { - total += sources.get(i).getCategory(); - } - - return total; - } - - /** {@inheritDoc} */ - public int getMaxOptimalRegisterCount() { - return 16; - } -} diff --git a/dx/src/com/android/dx/rop/code/Exceptions.java b/dx/src/com/android/dx/rop/code/Exceptions.java deleted file mode 100644 index 3ef4879e6..000000000 --- a/dx/src/com/android/dx/rop/code/Exceptions.java +++ /dev/null @@ -1,133 +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.android.dx.rop.code; - -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; - -/** - * Common exception types. - */ -public final class Exceptions { - /** non-null; the type <code>java.lang.ArithmeticException</code> */ - public static final Type TYPE_ArithmeticException = - Type.intern("Ljava/lang/ArithmeticException;"); - - /** - * non-null; the type - * <code>java.lang.ArrayIndexOutOfBoundsException</code> - */ - public static final Type TYPE_ArrayIndexOutOfBoundsException = - Type.intern("Ljava/lang/ArrayIndexOutOfBoundsException;"); - - /** non-null; the type <code>java.lang.ArrayStoreException</code> */ - public static final Type TYPE_ArrayStoreException = - Type.intern("Ljava/lang/ArrayStoreException;"); - - /** non-null; the type <code>java.lang.ClassCastException</code> */ - public static final Type TYPE_ClassCastException = - Type.intern("Ljava/lang/ClassCastException;"); - - /** non-null; the type <code>java.lang.Error</code> */ - public static final Type TYPE_Error = Type.intern("Ljava/lang/Error;"); - - /** - * non-null; the type - * <code>java.lang.IllegalMonitorStateException</code> - */ - public static final Type TYPE_IllegalMonitorStateException = - Type.intern("Ljava/lang/IllegalMonitorStateException;"); - - /** non-null; the type <code>java.lang.NegativeArraySizeException</code> */ - public static final Type TYPE_NegativeArraySizeException = - Type.intern("Ljava/lang/NegativeArraySizeException;"); - - /** non-null; the type <code>java.lang.NullPointerException</code> */ - public static final Type TYPE_NullPointerException = - Type.intern("Ljava/lang/NullPointerException;"); - - /** non-null; the list <code>[java.lang.Error]</code> */ - public static final StdTypeList LIST_Error = StdTypeList.make(TYPE_Error); - - /** - * non-null; the list <code>[java.lang.Error, - * java.lang.ArithmeticException]</code> - */ - public static final StdTypeList LIST_Error_ArithmeticException = - StdTypeList.make(TYPE_Error, TYPE_ArithmeticException); - - /** - * non-null; the list <code>[java.lang.Error, - * java.lang.ClassCastException]</code> - */ - public static final StdTypeList LIST_Error_ClassCastException = - StdTypeList.make(TYPE_Error, TYPE_ClassCastException); - - /** - * non-null; the list <code>[java.lang.Error, - * java.lang.NegativeArraySizeException]</code> - */ - public static final StdTypeList LIST_Error_NegativeArraySizeException = - StdTypeList.make(TYPE_Error, TYPE_NegativeArraySizeException); - - /** - * non-null; the list <code>[java.lang.Error, - * java.lang.NullPointerException]</code> - */ - public static final StdTypeList LIST_Error_NullPointerException = - StdTypeList.make(TYPE_Error, TYPE_NullPointerException); - - /** - * non-null; the list <code>[java.lang.Error, - * java.lang.NullPointerException, - * java.lang.ArrayIndexOutOfBoundsException]</code> - */ - public static final StdTypeList LIST_Error_Null_ArrayIndexOutOfBounds = - StdTypeList.make(TYPE_Error, - TYPE_NullPointerException, - TYPE_ArrayIndexOutOfBoundsException); - - /** - * non-null; the list <code>[java.lang.Error, - * java.lang.NullPointerException, - * java.lang.ArrayIndexOutOfBoundsException, - * java.lang.ArrayStoreException]</code> - */ - public static final StdTypeList LIST_Error_Null_ArrayIndex_ArrayStore = - StdTypeList.make(TYPE_Error, - TYPE_NullPointerException, - TYPE_ArrayIndexOutOfBoundsException, - TYPE_ArrayStoreException); - - /** - * non-null; the list <code>[java.lang.Error, - * java.lang.NullPointerException, - * java.lang.IllegalMonitorStateException]</code> - */ - public static final StdTypeList - LIST_Error_Null_IllegalMonitorStateException = - StdTypeList.make(TYPE_Error, - TYPE_NullPointerException, - TYPE_IllegalMonitorStateException); - - /** - * This class is uninstantiable. - */ - private Exceptions() { - // This space intentionally left blank. - } -} diff --git a/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java b/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java deleted file mode 100644 index 3798afbf2..000000000 --- a/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java +++ /dev/null @@ -1,116 +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.android.dx.rop.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.rop.type.StdTypeList; - -import java.util.ArrayList; - -/** - * Instruction which fills a newly created array with a predefined list of - * constant values. - */ -public final class FillArrayDataInsn - extends Insn { - - /** non-null: initial values to fill the newly created array */ - private final ArrayList<Constant> initValues; - - /** - * non-null: type of the array. Will be used to determine the width of - * elements in the array-data table. - */ - private final Constant arrayType; - - /** - * Constructs an instance. - * - * @param opcode non-null; the opcode - * @param position non-null; source position - * @param sources non-null; specs for all the sources - * @param initValues non-null; list of initial values to fill the array - * @param cst non-null; type of the new array - */ - public FillArrayDataInsn(Rop opcode, SourcePosition position, - RegisterSpecList sources, - ArrayList<Constant> initValues, - Constant cst) { - super(opcode, position, null, sources); - - if (opcode.getBranchingness() != Rop.BRANCH_NONE) { - throw new IllegalArgumentException("bogus branchingness"); - } - - this.initValues = initValues; - this.arrayType = cst; - } - - - /** {@inheritDoc} */ - @Override - public TypeList getCatches() { - return StdTypeList.EMPTY; - } - - /** - * Return the list of init values - * @return non-null; list of init values - */ - public ArrayList<Constant> getInitValues() { - return initValues; - } - - /** - * Return the type of the newly created array - * @return non-null; array type - */ - public Constant getConstant() { - return arrayType; - } - - /** {@inheritDoc} */ - @Override - public void accept(Visitor visitor) { - visitor.visitFillArrayDataInsn(this); - } - - /** {@inheritDoc} */ - @Override - public Insn withAddedCatch(Type type) { - throw new UnsupportedOperationException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - public Insn withRegisterOffset(int delta) { - return new FillArrayDataInsn(getOpcode(), getPosition(), - getSources().withOffset(delta), - initValues, arrayType); - } - - /** {@inheritDoc} */ - @Override - public Insn withNewRegisters(RegisterSpec result, - RegisterSpecList sources) { - - return new FillArrayDataInsn(getOpcode(), getPosition(), - sources, initValues, arrayType); - } -} diff --git a/dx/src/com/android/dx/rop/code/Insn.java b/dx/src/com/android/dx/rop/code/Insn.java deleted file mode 100644 index b1ad0ade4..000000000 --- a/dx/src/com/android/dx/rop/code/Insn.java +++ /dev/null @@ -1,458 +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.android.dx.rop.code; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.ToHuman; - -/** - * A register-based instruction. An instruction is the combination of - * an opcode (which specifies operation and source/result types), a - * list of actual sources and result registers/values, and additional - * information. - */ -public abstract class Insn implements ToHuman { - /** non-null; opcode */ - private final Rop opcode; - - /** non-null; source position */ - private final SourcePosition position; - - /** null-ok; spec for the result of this instruction, if any */ - private final RegisterSpec result; - - /** non-null; specs for all the sources of this instruction */ - private final RegisterSpecList sources; - - /** - * Constructs an instance. - * - * @param opcode non-null; the opcode - * @param position non-null; source position - * @param result null-ok; spec for the result, if any - * @param sources non-null; specs for all the sources - */ - public Insn(Rop opcode, SourcePosition position, RegisterSpec result, - RegisterSpecList sources) { - if (opcode == null) { - throw new NullPointerException("opcode == null"); - } - - if (position == null) { - throw new NullPointerException("position == null"); - } - - if (sources == null) { - throw new NullPointerException("sources == null"); - } - - this.opcode = opcode; - this.position = position; - this.result = result; - this.sources = sources; - } - - /** - * {@inheritDoc} - * - * Instances of this class compare by identity. That is, - * <code>x.equals(y)</code> is only true if <code>x == y</code>. - */ - @Override - public final boolean equals(Object other) { - return (this == other); - } - - /** - * {@inheritDoc} - * - * This implementation returns the identity hashcode of this - * instance. This is proper, since instances of this class compare - * by identity (see {@link #equals}). - */ - @Override - public final int hashCode() { - return System.identityHashCode(this); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return toStringWithInline(getInlineString()); - } - - /** - * Gets a human-oriented (and slightly lossy) string for this instance. - * - * @return non-null; the human string form - */ - public String toHuman() { - return toHumanWithInline(getInlineString()); - } - - /** - * Gets an "inline" string portion for toHuman(), if available. This - * is the portion that appears after the Rop opcode - * - * @return null-ok; if non-null, the inline text for toHuman() - */ - public String getInlineString() { - return null; - } - - /** - * Gets the opcode. - * - * @return non-null; the opcode - */ - public final Rop getOpcode() { - return opcode; - } - - /** - * Gets the source position. - * - * @return non-null; the source position - */ - public final SourcePosition getPosition() { - return position; - } - - /** - * Gets the result spec, if any. A return value of <code>null</code> - * means this instruction returns nothing. - * - * @return null-ok; the result spec, if any - */ - public final RegisterSpec getResult() { - return result; - } - - /** - * Gets the spec of a local variable assignment that occurs at this - * instruction, or null if no local variable assignment occurs. This - * may be the result register, or for <code>mark-local</code> insns - * it may be the source. - * - * @return null-ok; a named register spec or null - */ - public final RegisterSpec getLocalAssignment() { - RegisterSpec assignment; - if (opcode.getOpcode() == RegOps.MARK_LOCAL) { - assignment = sources.get(0); - } else { - assignment = result; - } - - if (assignment == null) { - return null; - } - - LocalItem localItem = assignment.getLocalItem(); - - if (localItem == null) { - return null; - } - - return assignment; - } - - /** - * Gets the source specs. - * - * @return non-null; the source specs - */ - public final RegisterSpecList getSources() { - return sources; - } - - /** - * Gets whether this instruction can possibly throw an exception. This - * is just a convenient wrapper for <code>getOpcode().canThrow()</code>. - * - * @return <code>true</code> iff this instruction can possibly throw - */ - public final boolean canThrow() { - return opcode.canThrow(); - } - - /** - * Gets the list of possibly-caught exceptions. This returns {@link - * StdTypeList#EMPTY} if this instruction has no handlers, - * which can be <i>either</i> if this instruction can't possibly - * throw or if it merely doesn't handle any of its possible - * exceptions. To determine whether this instruction can throw, - * use {@link #canThrow}. - * - * @return non-null; the catches list - */ - public abstract TypeList getCatches(); - - /** - * Calls the appropriate method on the given visitor, depending on the - * class of this instance. Subclasses must override this. - * - * @param visitor non-null; the visitor to call on - */ - public abstract void accept(Visitor visitor); - - /** - * Returns an instance that is just like this one, except that it - * has a catch list with the given item appended to the end. This - * method throws an exception if this instance can't possibly - * throw. To determine whether this instruction can throw, use - * {@link #canThrow}. - * - * @param type non-null; type to append to the catch list - * @return non-null; an appropriately-constructed instance - */ - public abstract Insn withAddedCatch(Type type); - - /** - * Returns an instance that is just like this one, except that all - * register references have been offset by the given delta. - * - * @param delta the amount to offset register references by - * @return non-null; an appropriately-constructed instance - */ - public abstract Insn withRegisterOffset(int delta); - - /** - * Returns an instance that is just like this one, except that, if - * possible, the insn is converted into a version in which the last - * source (if it is a constant) is represented directly rather than - * as a register reference. <code>this</code> is returned in cases where - * the translation is not possible. - * - * @return non-null; an appropriately-constructed instance - */ - public Insn withLastSourceLiteral() { - return this; - } - - /** - * Returns an exact copy of this Insn - * - * @return non-null; an appropriately-constructed instance - */ - public Insn copy() { - return withRegisterOffset(0); - } - - - /** - * Compares, handling nulls safely - * - * @param a first object - * @param b second object - * @return true if they're equal or both null. - */ - private static boolean equalsHandleNulls (Object a, Object b) { - return (a == b) || ((a != null) && a.equals(b)); - } - - /** - * Compares Insn contents, since <code>Insn.equals()</code> is defined - * to be an identity compare. Insn's are <code>contentEquals()</code> - * if they have the same opcode, registers, source position, and other - * metadata. - * - * @return true in the case described above - */ - public boolean contentEquals(Insn b) { - return opcode == b.getOpcode() - && position.equals(b.getPosition()) - && (getClass() == b.getClass()) - && equalsHandleNulls(result, b.getResult()) - && equalsHandleNulls(sources, b.getSources()) - && StdTypeList.equalContents(getCatches(), b.getCatches()); - } - - /** - * Returns an instance that is just like this one, except - * with new result and source registers. - * - * @param result null-ok; new result register - * @param sources non-null; new sources registers - * @return non-null; an appropriately-constructed instance - */ - public abstract Insn withNewRegisters(RegisterSpec result, - RegisterSpecList sources); - - /** - * Returns the string form of this instance, with the given bit added in - * the standard location for an inline argument. - * - * @param extra null-ok; the inline argument string - * @return non-null; the string form - */ - protected final String toStringWithInline(String extra) { - StringBuffer sb = new StringBuffer(80); - - sb.append("Insn{"); - sb.append(position); - sb.append(' '); - sb.append(opcode); - - if (extra != null) { - sb.append(' '); - sb.append(extra); - } - - sb.append(" :: "); - - if (result != null) { - sb.append(result); - sb.append(" <- "); - } - - sb.append(sources); - sb.append('}'); - - return sb.toString(); - } - - /** - * Returns the human string form of this instance, with the given - * bit added in the standard location for an inline argument. - * - * @param extra null-ok; the inline argument string - * @return non-null; the human string form - */ - protected final String toHumanWithInline(String extra) { - StringBuffer sb = new StringBuffer(80); - - sb.append(position); - sb.append(": "); - sb.append(opcode.getNickname()); - - if (extra != null) { - sb.append("("); - sb.append(extra); - sb.append(")"); - } - - if (result == null) { - sb.append(" ."); - } else { - sb.append(" "); - sb.append(result.toHuman()); - } - - sb.append(" <-"); - - int sz = sources.size(); - if (sz == 0) { - sb.append(" ."); - } else { - for (int i = 0; i < sz; i++) { - sb.append(" "); - sb.append(sources.get(i).toHuman()); - } - } - - return sb.toString(); - } - - - /** - * Visitor interface for this (outer) class. - */ - public static interface Visitor { - /** - * Visits a {@link PlainInsn}. - * - * @param insn non-null; the instruction to visit - */ - public void visitPlainInsn(PlainInsn insn); - - /** - * Visits a {@link PlainCstInsn}. - * - * @param insn non-null; the instruction to visit - */ - public void visitPlainCstInsn(PlainCstInsn insn); - - /** - * Visits a {@link SwitchInsn}. - * - * @param insn non-null; the instruction to visit - */ - public void visitSwitchInsn(SwitchInsn insn); - - /** - * Visits a {@link ThrowingCstInsn}. - * - * @param insn non-null; the instruction to visit - */ - public void visitThrowingCstInsn(ThrowingCstInsn insn); - - /** - * Visits a {@link ThrowingInsn}. - * - * @param insn non-null; the instruction to visit - */ - public void visitThrowingInsn(ThrowingInsn insn); - - /** - * Visits a {@link FillArrayDataInsn}. - * - * @param insn non-null; the instruction to visit - */ - public void visitFillArrayDataInsn(FillArrayDataInsn insn); - } - - /** - * Base implementation of {@link Visitor}, which has empty method - * bodies for all methods. - */ - public static class BaseVisitor implements Visitor { - /** {@inheritDoc} */ - public void visitPlainInsn(PlainInsn insn) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitPlainCstInsn(PlainCstInsn insn) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitSwitchInsn(SwitchInsn insn) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitThrowingCstInsn(ThrowingCstInsn insn) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitThrowingInsn(ThrowingInsn insn) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - public void visitFillArrayDataInsn(FillArrayDataInsn insn) { - // This space intentionally left blank. - } - } -} diff --git a/dx/src/com/android/dx/rop/code/InsnList.java b/dx/src/com/android/dx/rop/code/InsnList.java deleted file mode 100644 index 34f124cca..000000000 --- a/dx/src/com/android/dx/rop/code/InsnList.java +++ /dev/null @@ -1,130 +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.android.dx.rop.code; - -import com.android.dx.util.FixedSizeList; - -/** - * List of {@link Insn} instances. - */ -public final class InsnList - extends FixedSizeList { - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size the size of the list - */ - public InsnList(int size) { - super(size); - } - - /** - * Gets the element at the given index. 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</code>. - * - * @param n >= 0, < size(); which index - * @return non-null; element at that index - */ - public Insn get(int n) { - return (Insn) get0(n); - } - - /** - * Sets the instruction at the given index. - * - * @param n >= 0, < size(); which index - * @param insn non-null; the instruction to set at <code>n</code> - */ - public void set(int n, Insn insn) { - set0(n, insn); - } - - /** - * Gets the last instruction. This is just a convenient shorthand for - * <code>get(size() - 1)</code>. - * - * @return non-null; the last instruction - */ - public Insn getLast() { - return get(size() - 1); - } - - /** - * Visits each instruction in the list, in order. - * - * @param visitor non-null; visitor to use - */ - public void forEach(Insn.Visitor visitor) { - int sz = size(); - - for (int i = 0; i < sz; i++) { - get(i).accept(visitor); - } - } - - /** - * Compares the contents of this <code>InsnList</code> with another. - * The blocks must have the same number of insns, and each Insn must - * also return true to <code>Insn.contentEquals()</code>. - * - * @param b to compare - * @return true in the case described above. - */ - public boolean contentEquals(InsnList b) { - if (b == null) return false; - - int sz = size(); - - if (sz != b.size()) return false; - - for (int i = 0; i < sz; i++) { - if (!get(i).contentEquals(b.get(i))) { - return false; - } - } - - return true; - } - - /** - * Returns an instance that is identical to this one, except that - * the registers in each instruction are offset by the given - * amount. Mutability of the result is inherited from the - * original. - * - * @param delta the amount to offset register numbers by - * @return non-null; an appropriately-constructed instance - */ - public InsnList withRegisterOffset(int delta) { - int sz = size(); - InsnList result = new InsnList(sz); - - for (int i = 0; i < sz; i++) { - Insn one = (Insn) get0(i); - if (one != null) { - result.set0(i, one.withRegisterOffset(delta)); - } - } - - if (isImmutable()) { - result.setImmutable(); - } - - return result; - } -} diff --git a/dx/src/com/android/dx/rop/code/LocalItem.java b/dx/src/com/android/dx/rop/code/LocalItem.java deleted file mode 100644 index b1e1a4be6..000000000 --- a/dx/src/com/android/dx/rop/code/LocalItem.java +++ /dev/null @@ -1,144 +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.android.dx.rop.code; - -import com.android.dx.rop.cst.CstUtf8; - -/** - * A local variable item: either a name or a signature or both. - */ -public class LocalItem implements Comparable<LocalItem> { - - /** null-ok; local variable name */ - private final CstUtf8 name; - - /** null-ok; local variable signature */ - private final CstUtf8 signature; - - /** - * Make a new item. If both name and signature are null, null is returned. - * - * TODO: intern these - * - * @param name null-ok; local variable name - * @param signature null-ok; local variable signature - * @return non-null; appropriate instance. - */ - public static LocalItem make (CstUtf8 name, CstUtf8 signature) { - if (name == null && signature == null) { - return null; - } - - return new LocalItem (name, signature); - } - - /** - * Constructs instance. - * - * @param name null-ok; local variable name - * @param signature null-ok; local variable signature - */ - private LocalItem (CstUtf8 name, CstUtf8 signature) { - this.name = name; - this.signature = signature; - } - - /** {@inheritDoc} */ - @Override - public boolean equals (Object other) { - if (!(other instanceof LocalItem)) { - return false; - } - - LocalItem local = (LocalItem) other; - - return 0 == compareTo(local); - } - - /** - * Compares two strings like String.compareTo(), excepts treats a null - * as the least-possible string value. - * - * @return negative integer, zero, or positive integer in accordance - * with Comparable.compareTo() - */ - private static int compareHandlesNulls(CstUtf8 a, CstUtf8 b) { - if (a == b) { - return 0; - } else if (a == null) { - return -1; - } else if (b == null) { - return 1; - } else { - return a.compareTo(b); - } - } - - /** {@inheritDoc} */ - public int compareTo (LocalItem local) { - int ret; - - ret = compareHandlesNulls(name, local.name); - - if (ret != 0) { - return ret; - } - - ret = compareHandlesNulls(signature, local.signature); - - return ret; - } - - - /** {@inheritDoc} */ - @Override - public int hashCode () { - return (name == null ? 0 : name.hashCode()) * 31 - + (signature == null ? 0 : signature.hashCode()); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - if (name != null && signature == null) { - return name.toQuoted(); - } else if (name == null && signature == null) { - return ""; - } - - return "[" + (name == null ? "" : name.toQuoted()) - + "|" + (signature == null ? "" : signature.toQuoted()); - } - - /** - * Gets name. - * - * @return null-ok; name - */ - public CstUtf8 getName() { - return name; - } - - /** - * Gets signature. - * - * @return null-ok; signature - */ - public CstUtf8 getSignature() { - return signature; - } -} diff --git a/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java b/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java deleted file mode 100644 index 2d4cbced8..000000000 --- a/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java +++ /dev/null @@ -1,192 +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.android.dx.rop.code; - -import com.android.dx.util.Bits; -import com.android.dx.util.IntList; - -/** - * Code to figure out which local variables are active at which points in - * a method. - */ -public final class LocalVariableExtractor { - /** non-null; method being extracted from */ - private final RopMethod method; - - /** non-null; block list for the method */ - private final BasicBlockList blocks; - - /** non-null; result in-progress */ - private final LocalVariableInfo resultInfo; - - /** non-null; work set indicating blocks needing to be processed */ - private final int[] workSet; - - /** - * Extracts out all the local variable information from the given method. - * - * @param method non-null; the method to extract from - * @return non-null; the extracted information - */ - public static LocalVariableInfo extract(RopMethod method) { - LocalVariableExtractor lve = new LocalVariableExtractor(method); - return lve.doit(); - } - - /** - * Constructs an instance. This method is private. Use {@link #extract}. - * - * @param method non-null; the method to extract from - */ - private LocalVariableExtractor(RopMethod method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - BasicBlockList blocks = method.getBlocks(); - int maxLabel = blocks.getMaxLabel(); - - this.method = method; - this.blocks = blocks; - this.resultInfo = new LocalVariableInfo(method); - this.workSet = Bits.makeBitSet(maxLabel); - } - - /** - * Does the extraction. - * - * @return non-null; the extracted information - */ - private LocalVariableInfo doit() { - for (int label = method.getFirstLabel(); - label >= 0; - label = Bits.findFirst(workSet, 0)) { - Bits.clear(workSet, label); - processBlock(label); - } - - resultInfo.setImmutable(); - return resultInfo; - } - - /** - * Processes a single block. - * - * @param label >= 0; label of the block to process - */ - private void processBlock(int label) { - RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(label); - BasicBlock block = blocks.labelToBlock(label); - InsnList insns = block.getInsns(); - int insnSz = insns.size(); - - /* - * We may have to treat the last instruction specially: If it - * can (but doesn't always) throw, and the exception can be - * caught within the same method, then we need to use the - * state *before* executing it to be what is merged into - * exception targets. - */ - Insn lastInsn = insns.getLast(); - boolean canThrowDuringLastInsn = block.hasExceptionHandlers() && - (insns.getLast().getResult() != null); - int freezeSecondaryStateAt = insnSz - 1; - RegisterSpecSet secondaryState = primaryState; - - /* - * Iterate over the instructions, adding information for each place - * that the active variable set changes. - */ - - for (int i = 0; i < insnSz; i++) { - if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) { - // Until this point, primaryState == secondaryState. - primaryState.setImmutable(); - primaryState = primaryState.mutableCopy(); - } - - Insn insn = insns.get(i); - RegisterSpec result; - - result = insn.getLocalAssignment(); - - if (result == null) { - /* - * If an assignment assigns over an existing local, make - * sure to mark the local as going out of scope. - */ - - result = insn.getResult(); - - if (result != null - && primaryState.get(result.getReg()) != null) { - primaryState.remove(primaryState.get(result.getReg())); - } - continue; - } - - result = result.withSimpleType(); - - RegisterSpec already = primaryState.get(result); - /* - * The equals() check ensures we only add new info if - * the instruction causes a change to the set of - * active variables. - */ - if (!result.equals(already)) { - /* - * If this insn represents a local moving from one register - * to another, remove the association between the old register - * and the local. - */ - RegisterSpec previous - = primaryState.localItemToSpec(result.getLocalItem()); - - if (previous != null - && (previous.getReg() != result.getReg())) { - - primaryState.remove(previous); - } - - resultInfo.addAssignment(insn, result); - primaryState.put(result); - } - } - - primaryState.setImmutable(); - - /* - * Merge this state into the start state for each successor, - * and update the work set where required (that is, in cases - * where the start state for a block changes). - */ - - IntList successors = block.getSuccessors(); - int succSz = successors.size(); - int primarySuccessor = block.getPrimarySuccessor(); - - for (int i = 0; i < succSz; i++) { - int succ = successors.get(i); - RegisterSpecSet state = (succ == primarySuccessor) ? - primaryState : secondaryState; - - if (resultInfo.mergeStarts(succ, state)) { - Bits.set(workSet, succ); - } - } - } -} diff --git a/dx/src/com/android/dx/rop/code/LocalVariableInfo.java b/dx/src/com/android/dx/rop/code/LocalVariableInfo.java deleted file mode 100644 index 29c239b23..000000000 --- a/dx/src/com/android/dx/rop/code/LocalVariableInfo.java +++ /dev/null @@ -1,250 +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.android.dx.rop.code; - -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.util.MutabilityControl; - -import java.util.HashMap; - -/** - * Container for local variable information for a particular {@link - * RopMethod}. - */ -public final class LocalVariableInfo - extends MutabilityControl { - /** >= 0; the register count for the method */ - private final int regCount; - - /** - * non-null; {@link RegisterSpecSet} to use when indicating a block - * that has no locals; it is empty and immutable but has an appropriate - * max size for the method - */ - private final RegisterSpecSet emptySet; - - /** - * non-null; array consisting of register sets representing the - * sets of variables already assigned upon entry to each block, - * where array indices correspond to block labels - */ - private final RegisterSpecSet[] blockStarts; - - /** non-null; map from instructions to the variable each assigns */ - private final HashMap<Insn, RegisterSpec> insnAssignments; - - /** - * Constructs an instance. - * - * @param method non-null; the method being represented by this instance - */ - public LocalVariableInfo(RopMethod method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - BasicBlockList blocks = method.getBlocks(); - int maxLabel = blocks.getMaxLabel(); - - this.regCount = blocks.getRegCount(); - this.emptySet = new RegisterSpecSet(regCount); - this.blockStarts = new RegisterSpecSet[maxLabel]; - this.insnAssignments = - new HashMap<Insn, RegisterSpec>(blocks.getInstructionCount()); - - emptySet.setImmutable(); - } - - /** - * Sets the register set associated with the start of the block with - * the given label. - * - * @param label >= 0; the block label - * @param specs non-null; the register set to associate with the block - */ - public void setStarts(int label, RegisterSpecSet specs) { - throwIfImmutable(); - - if (specs == null) { - throw new NullPointerException("specs == null"); - } - - try { - blockStarts[label] = specs; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("bogus label"); - } - } - - /** - * Merges the given register set into the set for the block with the - * given label. If there was not already an associated set, then this - * is the same as calling {@link #setStarts}. Otherwise, this will - * merge the two sets and call {@link #setStarts} on the result of the - * merge. - * - * @param label >= 0; the block label - * @param specs non-null; the register set to merge into the start set - * for the block - * @return <code>true</code> if the merge resulted in an actual change - * to the associated set (including storing one for the first time) or - * <code>false</code> if there was no change - */ - public boolean mergeStarts(int label, RegisterSpecSet specs) { - RegisterSpecSet start = getStarts0(label); - boolean changed = false; - - if (start == null) { - setStarts(label, specs); - return true; - } - - RegisterSpecSet newStart = start.mutableCopy(); - newStart.intersect(specs, true); - - if (start.equals(newStart)) { - return false; - } - - newStart.setImmutable(); - setStarts(label, newStart); - - return true; - } - - /** - * Gets the register set associated with the start of the block - * with the given label. This returns an empty set with the appropriate - * max size if no set was associated with the block in question. - * - * @param label >= 0; the block label - * @return non-null; the associated register set - */ - public RegisterSpecSet getStarts(int label) { - RegisterSpecSet result = getStarts0(label); - - return (result != null) ? result : emptySet; - } - - /** - * Gets the register set associated with the start of the given - * block. This is just convenient shorthand for - * <code>getStarts(block.getLabel())</code>. - * - * @param block non-null; the block in question - * @return non-null; the associated register set - */ - public RegisterSpecSet getStarts(BasicBlock block) { - return getStarts(block.getLabel()); - } - - /** - * Gets a mutable copy of the register set associated with the - * start of the block with the given label. This returns a - * newly-allocated empty {@link RegisterSpecSet} of appropriate - * max size if there is not yet any set associated with the block. - * - * @param label >= 0; the block label - * @return non-null; the associated register set - */ - public RegisterSpecSet mutableCopyOfStarts(int label) { - RegisterSpecSet result = getStarts0(label); - - return (result != null) ? - result.mutableCopy() : new RegisterSpecSet(regCount); - } - - /** - * Adds an assignment association for the given instruction and - * register spec. This throws an exception if the instruction - * doesn't actually perform a named variable assignment. - * - * <b>Note:</b> Although the instruction contains its own spec for - * the result, it still needs to be passed in explicitly to this - * method, since the spec that is stored here should always have a - * simple type and the one in the instruction can be an arbitrary - * {@link TypeBearer} (such as a constant value). - * - * @param insn non-null; the instruction in question - * @param spec non-null; the associated register spec - */ - public void addAssignment(Insn insn, RegisterSpec spec) { - throwIfImmutable(); - - if (insn == null) { - throw new NullPointerException("insn == null"); - } - - if (spec == null) { - throw new NullPointerException("spec == null"); - } - - insnAssignments.put(insn, spec); - } - - /** - * Gets the named register being assigned by the given instruction, if - * previously stored in this instance. - * - * @param insn non-null; instruction in question - * @return null-ok; the named register being assigned, if any - */ - public RegisterSpec getAssignment(Insn insn) { - return insnAssignments.get(insn); - } - - /** - * Gets the number of assignments recorded by this instance. - * - * @return >= 0; the number of assignments - */ - public int getAssignmentCount() { - return insnAssignments.size(); - } - - public void debugDump() { - for (int label = 0 ; label < blockStarts.length; label++) { - if (blockStarts[label] == null) { - continue; - } - - if (blockStarts[label] == emptySet) { - System.out.printf("%04x: empty set\n", label); - } else { - System.out.printf("%04x: %s\n", label, blockStarts[label]); - } - } - } - - /** - * Helper method, to get the starts for a label, throwing the - * right exception for range problems. - * - * @param label >= 0; the block label - * @return null-ok; associated register set or <code>null</code> if there - * is none - */ - private RegisterSpecSet getStarts0(int label) { - try { - return blockStarts[label]; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("bogus label"); - } - } -} diff --git a/dx/src/com/android/dx/rop/code/PlainCstInsn.java b/dx/src/com/android/dx/rop/code/PlainCstInsn.java deleted file mode 100644 index 908b3cb34..000000000 --- a/dx/src/com/android/dx/rop/code/PlainCstInsn.java +++ /dev/null @@ -1,87 +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.android.dx.rop.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; - -/** - * Instruction which contains an explicit reference to a constant - * but which cannot throw an exception. - */ -public final class PlainCstInsn - extends CstInsn { - /** - * Constructs an instance. - * - * @param opcode non-null; the opcode - * @param position non-null; source position - * @param result null-ok; spec for the result, if any - * @param sources non-null; specs for all the sources - * @param cst non-null; the constant - */ - public PlainCstInsn(Rop opcode, SourcePosition position, - RegisterSpec result, RegisterSpecList sources, - Constant cst) { - super(opcode, position, result, sources, cst); - - if (opcode.getBranchingness() != Rop.BRANCH_NONE) { - throw new IllegalArgumentException("bogus branchingness"); - } - } - - /** {@inheritDoc} */ - @Override - public TypeList getCatches() { - return StdTypeList.EMPTY; - } - - /** {@inheritDoc} */ - @Override - public void accept(Visitor visitor) { - visitor.visitPlainCstInsn(this); - } - - /** {@inheritDoc} */ - @Override - public Insn withAddedCatch(Type type) { - throw new UnsupportedOperationException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - public Insn withRegisterOffset(int delta) { - return new PlainCstInsn(getOpcode(), getPosition(), - getResult().withOffset(delta), - getSources().withOffset(delta), - getConstant()); - } - - /** {@inheritDoc} */ - @Override - public Insn withNewRegisters(RegisterSpec result, - RegisterSpecList sources) { - - return new PlainCstInsn(getOpcode(), getPosition(), - result, - sources, - getConstant()); - - } -} diff --git a/dx/src/com/android/dx/rop/code/PlainInsn.java b/dx/src/com/android/dx/rop/code/PlainInsn.java deleted file mode 100644 index 4c5c9b701..000000000 --- a/dx/src/com/android/dx/rop/code/PlainInsn.java +++ /dev/null @@ -1,140 +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.android.dx.rop.code; - -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.rop.cst.Constant; - -/** - * Plain instruction, which has no embedded data and which cannot possibly - * throw an exception. - */ -public final class PlainInsn - extends Insn { - /** - * Constructs an instance. - * - * @param opcode non-null; the opcode - * @param position non-null; source position - * @param result null-ok; spec for the result, if any - * @param sources non-null; specs for all the sources - */ - public PlainInsn(Rop opcode, SourcePosition position, - RegisterSpec result, RegisterSpecList sources) { - super(opcode, position, result, sources); - - switch (opcode.getBranchingness()) { - case Rop.BRANCH_SWITCH: - case Rop.BRANCH_THROW: { - throw new IllegalArgumentException("bogus branchingness"); - } - } - - if (result != null && opcode.getBranchingness() != Rop.BRANCH_NONE) { - // move-result-pseudo is required here - throw new IllegalArgumentException - ("can't mix branchingness with result"); - } - } - - /** - * Constructs a single-source instance. - * - * @param opcode non-null; the opcode - * @param position non-null; source position - * @param result null-ok; spec for the result, if any - * @param source non-null; spec for the source - */ - public PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result, - RegisterSpec source) { - this(opcode, position, result, RegisterSpecList.make(source)); - } - - /** {@inheritDoc} */ - @Override - public TypeList getCatches() { - return StdTypeList.EMPTY; - } - - /** {@inheritDoc} */ - @Override - public void accept(Visitor visitor) { - visitor.visitPlainInsn(this); - } - - /** {@inheritDoc} */ - @Override - public Insn withAddedCatch(Type type) { - throw new UnsupportedOperationException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - public Insn withRegisterOffset(int delta) { - return new PlainInsn(getOpcode(), getPosition(), - getResult().withOffset(delta), - getSources().withOffset(delta)); - } - - /** {@inheritDoc} */ - @Override - public Insn withLastSourceLiteral() { - RegisterSpecList sources = getSources(); - int szSources = sources.size(); - - if (szSources == 0) { - return this; - } - - TypeBearer lastType = sources.get(szSources - 1).getTypeBearer(); - - if (!lastType.isConstant()) { - return this; - } - - Constant cst = (Constant) lastType; - - RegisterSpecList newSources = sources.withoutLast(); - - Rop newRop; - try { - newRop = Rops.ropFor(getOpcode().getOpcode(), - getResult(), newSources, (Constant)lastType); - } catch (IllegalArgumentException ex) { - // There's no rop for this case - return this; - } - - return new PlainCstInsn(newRop, getPosition(), - getResult(), newSources, cst); - } - - - /** {@inheritDoc} */ - @Override - public Insn withNewRegisters(RegisterSpec result, - RegisterSpecList sources) { - - return new PlainInsn(getOpcode(), getPosition(), - result, - sources); - - } -} diff --git a/dx/src/com/android/dx/rop/code/RegOps.java b/dx/src/com/android/dx/rop/code/RegOps.java deleted file mode 100644 index f201f68da..000000000 --- a/dx/src/com/android/dx/rop/code/RegOps.java +++ /dev/null @@ -1,403 +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.android.dx.rop.code; - -import com.android.dx.util.Hex; - -/** - * All the register-based opcodes, and related utilities. - * - * <p><b>Note:</b> Opcode descriptions use a rough pseudocode. <code>r</code> - * is the result register, <code>x</code> is the first argument, - * <code>y</code> is the second argument, and <code>z</code> is the - * third argument. The expression which describes - * the operation uses Java-ish syntax but is preceded by type indicators for - * each of the values. - */ -public final class RegOps { - /** <code>nop()</code> */ - public static final int NOP = 1; - - /** <code>T: any type; r,x: T :: r = x;</code> */ - public static final int MOVE = 2; - - /** <code>T: any type; r,param(x): T :: r = param(x)</code> */ - public static final int MOVE_PARAM = 3; - - /** - * <code>T: Throwable; r: T :: r = caught_exception</code>. - * <b>Note:</b> This opcode should only ever be used in the - * first instruction of a block, and such blocks must be - * the start of an exception handler. - */ - public static final int MOVE_EXCEPTION = 4; - - /** <code>T: any type; r, literal: T :: r = literal;</code> */ - public static final int CONST = 5; - - /** <code>goto <i>label</i></code> */ - public static final int GOTO = 6; - - /** - * <code>T: int or Object; x,y: T :: if (x == y) goto - * <i>label</i></code> - */ - public static final int IF_EQ = 7; - - /** - * <code>T: int or Object; x,y: T :: if (x != y) goto - * <i>label</i></code> - */ - public static final int IF_NE = 8; - - /** <code>x,y: int :: if (x < y) goto <i>label</i></code> */ - public static final int IF_LT = 9; - - /** <code>x,y: int :: if (x >= y) goto <i>label</i></code> */ - public static final int IF_GE = 10; - - /** <code>x,y: int :: if (x <= y) goto <i>label</i></code> */ - public static final int IF_LE = 11; - - /** <code>x,y: int :: if (x > y) goto <i>label</i></code> */ - public static final int IF_GT = 12; - - /** <code>x: int :: goto <i>table[x]</i></code> */ - public static final int SWITCH = 13; - - /** <code>T: any numeric type; r,x,y: T :: r = x + y</code> */ - public static final int ADD = 14; - - /** <code>T: any numeric type; r,x,y: T :: r = x - y</code> */ - public static final int SUB = 15; - - /** <code>T: any numeric type; r,x,y: T :: r = x * y</code> */ - public static final int MUL = 16; - - /** <code>T: any numeric type; r,x,y: T :: r = x / y</code> */ - public static final int DIV = 17; - - /** - * <code>T: any numeric type; r,x,y: T :: r = x % y</code> - * (Java-style remainder) - */ - public static final int REM = 18; - - /** <code>T: any numeric type; r,x: T :: r = -x</code> */ - public static final int NEG = 19; - - /** <code>T: any integral type; r,x,y: T :: r = x & y</code> */ - public static final int AND = 20; - - /** <code>T: any integral type; r,x,y: T :: r = x | y</code> */ - public static final int OR = 21; - - /** <code>T: any integral type; r,x,y: T :: r = x ^ y</code> */ - public static final int XOR = 22; - - /** - * <code>T: any integral type; r,x: T; y: int :: r = x << - * y</code> - */ - public static final int SHL = 23; - - /** - * <code>T: any integral type; r,x: T; y: int :: r = x >> - * y</code> (signed right-shift) - */ - public static final int SHR = 24; - - /** - * <code>T: any integral type; r,x: T; y: int :: r = x - * >>> y</code> (unsigned right-shift) - */ - public static final int USHR = 25; - - /** <code>T: any integral type; r,x: T :: r = ~x</code> */ - public static final int NOT = 26; - - /** - * <code>T: any numeric type; r: int; x,y: T :: r = (x == y) ? 0 - * : (x > y) ? 1 : -1</code> (Java-style "cmpl" where a NaN is - * considered "less than" all other values; also used for integral - * comparisons) - */ - public static final int CMPL = 27; - - /** - * <code>T: any floating point type; r: int; x,y: T :: r = (x == y) ? 0 - * : (x < y) ? -1 : 1</code> (Java-style "cmpg" where a NaN is - * considered "greater than" all other values) - */ - public static final int CMPG = 28; - - /** - * <code>T: any numeric type; U: any numeric type; r: T; x: U :: - * r = (T) x</code> (numeric type conversion between the four - * "real" numeric types) - */ - public static final int CONV = 29; - - /** - * <code>r,x: int :: r = (x << 24) >> 24</code> (Java-style - * convert int to byte) - */ - public static final int TO_BYTE = 30; - - /** - * <code>r,x: int :: r = x & 0xffff</code> (Java-style - * convert int to char) - */ - public static final int TO_CHAR = 31; - - /** - * <code>r,x: int :: r = (x << 16) >> 16</code> (Java-style - * convert int to short) - */ - public static final int TO_SHORT = 32; - - /** <code>T: return type for the method; x: T; return x</code> */ - public static final int RETURN = 33; - - /** <code>T: any type; r: int; x: T[]; :: r = x.length</code> */ - public static final int ARRAY_LENGTH = 34; - - /** <code>x: Throwable :: throw(x)</code> */ - public static final int THROW = 35; - - /** <code>x: Object :: monitorenter(x)</code> */ - public static final int MONITOR_ENTER = 36; - - /** <code>x: Object :: monitorexit(x)</code> */ - public static final int MONITOR_EXIT = 37; - - /** <code>T: any type; r: T; x: T[]; y: int :: r = x[y]</code> */ - public static final int AGET = 38; - - /** <code>T: any type; x: T; y: T[]; z: int :: x[y] = z</code> */ - public static final int APUT = 39; - - /** - * <code>T: any non-array object type :: r = - * alloc(T)</code> (allocate heap space for an object) - */ - public static final int NEW_INSTANCE = 40; - - /** <code>T: any array type; r: T; x: int :: r = new T[x]</code> */ - public static final int NEW_ARRAY = 41; - - /** - * <code>T: any array type; r: T; x: int; v0..vx: T :: r = new T[x] - * {v0, ..., vx}</code> - */ - public static final int FILLED_NEW_ARRAY = 42; - - /** - * <code>T: any object type; x: Object :: (T) x</code> (can - * throw <code>ClassCastException</code>) - */ - public static final int CHECK_CAST = 43; - - /** - * <code>T: any object type; x: Object :: x instanceof - * T</code> - */ - public static final int INSTANCE_OF = 44; - - /** - * <code>T: any type; r: T; x: Object; f: instance field spec of - * type T :: r = x.f</code> - */ - public static final int GET_FIELD = 45; - - /** - * <code>T: any type; r: T; f: static field spec of type T :: r = - * f</code> - */ - public static final int GET_STATIC = 46; - - /** - * <code>T: any type; x: T; y: Object; f: instance field spec of type - * T :: y.f = x</code> - */ - public static final int PUT_FIELD = 47; - - /** - * <code>T: any type; f: static field spec of type T; x: T :: f = - * x</code> - */ - public static final int PUT_STATIC = 48; - - /** - * <code>Tr, T0, T1...: any types; r: Tr; m: static method spec; - * y0: T0; y1: T1 ... :: r = m(y0, y1, ...)</code> (call static - * method) - */ - public static final int INVOKE_STATIC = 49; - - /** - * <code>Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method - * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)</code> (call normal - * virtual method) - */ - public static final int INVOKE_VIRTUAL = 50; - - /** - * <code>Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method - * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)</code> (call - * superclass virtual method) - */ - public static final int INVOKE_SUPER = 51; - - /** - * <code>Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method - * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)</code> (call - * direct/special method) - */ - public static final int INVOKE_DIRECT = 52; - - /** - * <code>Tr, T0, T1...: any types; r: Tr; x: Object; m: interface - * (instance) method spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, - * ...)</code> (call interface method) - */ - public static final int INVOKE_INTERFACE = 53; - - /** - * <code> T0: any type; </code> (mark beginning or end of local variable - * name - */ - public static final int MARK_LOCAL = 54; - - /** - * <code>T: Any type; r: T :: r = return_type</code>. - * <b>Note:</b> This opcode should only ever be used in the - * first instruction of a block following an invoke-*. - */ - public static final int MOVE_RESULT = 55; - - /** - * <code>T: Any type; r: T :: r = return_type</code>. - * <b>Note:</b> This opcode should only ever be used in the - * first instruction of a block following a non-invoke throwing insn - */ - public static final int MOVE_RESULT_PSEUDO = 56; - - /** <code>T: Any primitive type; v0..vx: T :: {v0, ..., vx}</code> */ - public static final int FILL_ARRAY_DATA = 57; - - /** - * This class is uninstantiable. - */ - private RegOps() { - // This space intentionally left blank. - } - - /** - * Gets the name of the given opcode. - * - * @param opcode >= 0, <= 255; the opcode - * @return non-null; its name - */ - public static String opName(int opcode) { - switch (opcode) { - case NOP: return "nop"; - case MOVE: return "move"; - case MOVE_PARAM: return "move-param"; - case MOVE_EXCEPTION: return "move-exception"; - case CONST: return "const"; - case GOTO: return "goto"; - case IF_EQ: return "if-eq"; - case IF_NE: return "if-ne"; - case IF_LT: return "if-lt"; - case IF_GE: return "if-ge"; - case IF_LE: return "if-le"; - case IF_GT: return "if-gt"; - case SWITCH: return "switch"; - case ADD: return "add"; - case SUB: return "sub"; - case MUL: return "mul"; - case DIV: return "div"; - case REM: return "rem"; - case NEG: return "neg"; - case AND: return "and"; - case OR: return "or"; - case XOR: return "xor"; - case SHL: return "shl"; - case SHR: return "shr"; - case USHR: return "ushr"; - case NOT: return "not"; - case CMPL: return "cmpl"; - case CMPG: return "cmpg"; - case CONV: return "conv"; - case TO_BYTE: return "to-byte"; - case TO_CHAR: return "to-char"; - case TO_SHORT: return "to-short"; - case RETURN: return "return"; - case ARRAY_LENGTH: return "array-length"; - case THROW: return "throw"; - case MONITOR_ENTER: return "monitor-enter"; - case MONITOR_EXIT: return "monitor-exit"; - case AGET: return "aget"; - case APUT: return "aput"; - case NEW_INSTANCE: return "new-instance"; - case NEW_ARRAY: return "new-array"; - case FILLED_NEW_ARRAY: return "filled-new-array"; - case CHECK_CAST: return "check-cast"; - case INSTANCE_OF: return "instance-of"; - case GET_FIELD: return "get-field"; - case GET_STATIC: return "get-static"; - case PUT_FIELD: return "put-field"; - case PUT_STATIC: return "put-static"; - case INVOKE_STATIC: return "invoke-static"; - case INVOKE_VIRTUAL: return "invoke-virtual"; - case INVOKE_SUPER: return "invoke-super"; - case INVOKE_DIRECT: return "invoke-direct"; - case INVOKE_INTERFACE: return "invoke-interface"; - case MOVE_RESULT: return "move-result"; - case MOVE_RESULT_PSEUDO: return "move-result-pseudo"; - case FILL_ARRAY_DATA: return "fill-array-data"; - } - - return "unknown-" + Hex.u1(opcode); - } - - /** - * Given an IF_* RegOp, returns the right-to-left flipped version. For - * example, IF_GT becomes IF_LT. - * - * @param opcode An IF_* RegOp - * @return flipped IF Regop - */ - public static int flippedIfOpcode(final int opcode) { - switch (opcode) { - case RegOps.IF_EQ: - case RegOps.IF_NE: - return opcode; - case RegOps.IF_LT: - return RegOps.IF_GT; - case RegOps.IF_GE: - return RegOps.IF_LE; - case RegOps.IF_LE: - return RegOps.IF_GE; - case RegOps.IF_GT: - return RegOps.IF_LT; - default: - throw new RuntimeException("Unrecognized IF regop: " + opcode); - } - } -} diff --git a/dx/src/com/android/dx/rop/code/RegisterSpec.java b/dx/src/com/android/dx/rop/code/RegisterSpec.java deleted file mode 100644 index 09f7f1829..000000000 --- a/dx/src/com/android/dx/rop/code/RegisterSpec.java +++ /dev/null @@ -1,552 +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.android.dx.rop.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.util.ToHuman; - -import java.util.HashMap; - -/** - * Combination of a register number and a type, used as the sources and - * destinations of register-based operations. - */ -public final class RegisterSpec - implements TypeBearer, ToHuman { - /** non-null; string to prefix register numbers with */ - public static final String PREFIX = "v"; - - /** non-null; intern table for instances */ - private static final HashMap<Object, RegisterSpec> theInterns = - new HashMap<Object, RegisterSpec>(1000); - - /** non-null; common comparison instance used while interning */ - private static final ForComparison theInterningItem = new ForComparison(); - - /** >= 0; register number */ - private final int reg; - - /** non-null; type loaded or stored */ - private final TypeBearer type; - - /** null-ok; local variable info associated with this register, if any */ - private final LocalItem local; - - /** - * Intern the given triple as an instance of this class. - * - * @param reg >= 0; the register number - * @param type non-null; the type (or possibly actual value) which - * is loaded from or stored to the indicated register - * @param local null-ok; the associated local variable, if any - * @return non-null; an appropriately-constructed instance - */ - private static RegisterSpec intern(int reg, TypeBearer type, - LocalItem local) { - theInterningItem.set(reg, type, local); - RegisterSpec found = theInterns.get(theInterningItem); - - if (found != null) { - return found; - } - - found = theInterningItem.toRegisterSpec(); - theInterns.put(found, found); - return found; - } - - /** - * Returns an instance for the given register number and type, with - * no variable info. This method is allowed to return shared - * instances (but doesn't necessarily do so). - * - * @param reg >= 0; the register number - * @param type non-null; the type (or possibly actual value) which - * is loaded from or stored to the indicated register - * @return non-null; an appropriately-constructed instance - */ - public static RegisterSpec make(int reg, TypeBearer type) { - return intern(reg, type, null); - } - - /** - * Returns an instance for the given register number, type, and - * variable info. This method is allowed to return shared - * instances (but doesn't necessarily do so). - * - * @param reg >= 0; the register number - * @param type non-null; the type (or possibly actual value) which - * is loaded from or stored to the indicated register - * @param local non-null; the associated local variable - * @return non-null; an appropriately-constructed instance - */ - public static RegisterSpec make(int reg, TypeBearer type, LocalItem local) { - if (local == null) { - throw new NullPointerException("local == null"); - } - - return intern(reg, type, local); - } - - /** - * Returns an instance for the given register number, type, and - * variable info. This method is allowed to return shared - * instances (but doesn't necessarily do so). - * - * @param reg >= 0; the register number - * @param type non-null; the type (or possibly actual value) which - * is loaded from or stored to the indicated register - * @param local null-ok; the associated variable info or null for - * none - * @return non-null; an appropriately-constructed instance - */ - public static RegisterSpec makeLocalOptional( - int reg, TypeBearer type, LocalItem local) { - - return intern(reg, type, local); - } - - /** - * Gets the string form for the given register number. - * - * @param reg >= 0; the register number - * @return non-null; the string form - */ - public static String regString(int reg) { - return PREFIX + reg; - } - - /** - * Constructs an instance. This constructor is private. Use - * {@link #make}. - * - * @param reg >= 0; the register number - * @param type non-null; the type (or possibly actual value) which - * is loaded from or stored to the indicated register - * @param local null-ok; the associated local variable, if any - */ - private RegisterSpec(int reg, TypeBearer type, LocalItem local) { - if (reg < 0) { - throw new IllegalArgumentException("reg < 0"); - } - - if (type == null) { - throw new NullPointerException("type == null"); - } - - this.reg = reg; - this.type = type; - this.local = local; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof RegisterSpec)) { - if (other instanceof ForComparison) { - ForComparison fc = (ForComparison) other; - return equals(fc.reg, fc.type, fc.local); - } - return false; - } - - RegisterSpec spec = (RegisterSpec) other; - return equals(spec.reg, spec.type, spec.local); - } - - /** - * Helper for {@link #equals} and {@link #ForComparison.equals}, - * which actually does the test. - * - * @param reg value of the instance variable, for another instance - * @param type value of the instance variable, for another instance - * @param local value of the instance variable, for another instance - * @return whether this instance is equal to one with the given - * values - */ - private boolean equals(int reg, TypeBearer type, LocalItem local) { - return (this.reg == reg) - && this.type.equals(type) - && ((this.local == local) - || ((this.local != null) && this.local.equals(local))); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return hashCodeOf(reg, type, local); - } - - /** - * Helper for {@link #hashCode} and {@link #ForComparison.hashCode}, - * which actually does the calculation. - * - * @param reg value of the instance variable - * @param type value of the instance variable - * @param local value of the instance variable - * @return the hash code - */ - private static int hashCodeOf(int reg, TypeBearer type, LocalItem local) { - int hash = (local != null) ? local.hashCode() : 0; - - hash = (hash * 31 + type.hashCode()) * 31 + reg; - return hash; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return toString0(false); - } - - /** {@inheritDoc} */ - public String toHuman() { - return toString0(true); - } - - /** {@inheritDoc} */ - public Type getType() { - return type.getType(); - } - - /** {@inheritDoc} */ - public TypeBearer getFrameType() { - return type.getFrameType(); - } - - /** {@inheritDoc} */ - public final int getBasicType() { - return type.getBasicType(); - } - - /** {@inheritDoc} */ - public final int getBasicFrameType() { - return type.getBasicFrameType(); - } - - /** {@inheritDoc} */ - public final boolean isConstant() { - return false; - } - - /** - * Gets the register number. - * - * @return >= 0; the register number - */ - public int getReg() { - return reg; - } - - /** - * Gets the type (or actual value) which is loaded from or stored - * to the register associated with this instance. - * - * @return non-null; the type - */ - public TypeBearer getTypeBearer() { - return type; - } - - /** - * Gets the variable info associated with this instance, if any. - * - * @return null-ok; the variable info, or <code>null</code> if this - * instance has none - */ - public LocalItem getLocalItem() { - return local; - } - - /** - * Gets the next available register number after the one in this - * instance. This is equal to the register number plus the width - * (category) of the type used. Among other things, this may also - * be used to determine the minimum required register count - * implied by this instance. - * - * @return >= 0; the required registers size - */ - public int getNextReg() { - return reg + getCategory(); - } - - /** - * Gets the category of this instance's type. This is just a convenient - * shorthand for <code>getType().getCategory()</code>. - * - * @return 1..2; the category of this instance's type - */ - public int getCategory() { - return type.getType().getCategory(); - } - - /** - * Gets the string form for just the register number of this instance. - * - * @return non-null; the register string form - */ - public String regString() { - return regString(reg); - } - - /** - * Returns an instance that is the intersection between this instance - * and the given one, if any. The intersection is defined as follows: - * - * <ul> - * <li>If <code>other</code> is <code>null</code>, then the result - * is <code>null</code>. - * <li>If the register numbers don't match, then the intersection - * is <code>null</code>. Otherwise, the register number of the - * intersection is the same as the one in the two instances.</li> - * <li>If the types returned by <code>getType()</code> are not - * <code>equals()</code>, then the intersection is null.</li> - * <li>If the type bearers returned by <code>getTypeBearer()</code> - * are <code>equals()</code>, then the intersection's type bearer - * is the one from this instance. Otherwise, the intersection's - * type bearer is the <code>getType()</code> of this instance.</li> - * <li>If the locals are <code>equals()</code>, then the local info of the - * intersection is the local info of this instance. Otherwise, the local info - * of the intersection is <code>null</code>.</li> - * </ul> - * - * @param other null-ok; instance to intersect with (or <code>null</code>) - * @param localPrimary whether local variables are primary to - * the intersection; if <code>true</code>, then the only non-null - * results occur when registers being intersected have equal local infos (or - * both have <code>null</code> local infos) - * @return null-ok; the intersection - */ - public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) { - if (this == other) { - // Easy out. - return this; - } - - if ((other == null) || (reg != other.getReg())) { - return null; - } - - LocalItem resultLocal = - ((local == null) || !local.equals(other.getLocalItem())) ? null : local; - boolean sameName = (resultLocal == local); - - if (localPrimary && !sameName) { - return null; - } - - Type thisType = getType(); - Type otherType = other.getType(); - - // Note: Types are always interned. - if (thisType != otherType) { - return null; - } - - TypeBearer resultTypeBearer = - type.equals(other.getTypeBearer()) ? type : thisType; - - if ((resultTypeBearer == type) && sameName) { - // It turns out that the intersection is "this" after all. - return this; - } - - return (resultLocal == null) ? make(reg, resultTypeBearer) : - make(reg, resultTypeBearer, resultLocal); - } - - /** - * Returns an instance that is identical to this one, except that the - * register number is replaced by the given one. - * - * @param newReg >= 0; the new register number - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpec withReg(int newReg) { - if (reg == newReg) { - return this; - } - - return makeLocalOptional(newReg, type, local); - } - - /** - * Returns an instance that is identical to this one, except that - * the type is replaced by the given one. - * - * @param newType non-null; the new type - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpec withType(TypeBearer newType) { - return makeLocalOptional(reg, newType, local); - } - - /** - * Returns an instance that is identical to this one, except that the - * register number is offset by the given amount. - * - * @param delta the amount to offset the register number by - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpec withOffset(int delta) { - if (delta == 0) { - return this; - } - - return withReg(reg + delta); - } - - /** - * Returns an instance that is identical to this one, except that - * the type bearer is replaced by the actual underlying type - * (thereby stripping off non-type information) with any - * initialization information stripped away as well. - * - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpec withSimpleType() { - TypeBearer orig = type; - Type newType; - - if (orig instanceof Type) { - newType = (Type) orig; - } else { - newType = orig.getType(); - } - - if (newType.isUninitialized()) { - newType = newType.getInitializedType(); - } - - if (newType == orig) { - return this; - } - - return makeLocalOptional(reg, newType, local); - } - - /** - * Returns an instance that is identical to this one except that the - * local variable is as specified in the parameter. - * - * @param local null-ok; the local item or null for none - * @return an appropriate instance - */ - public RegisterSpec withLocalItem(LocalItem local) { - if ((this.local== local) - || ((this.local != null) && this.local.equals(local))) { - - return this; - } - - return makeLocalOptional(reg, type, local); - } - - - /** - * Helper for {@link #toString} and {@link #toHuman}. - * - * @param human whether to be human-oriented - * @return non-null; the string form - */ - private String toString0(boolean human) { - StringBuffer sb = new StringBuffer(40); - - sb.append(regString()); - sb.append(":"); - - if (local != null) { - sb.append(local.toString()); - } - - Type justType = type.getType(); - sb.append(justType); - - if (justType != type) { - sb.append("="); - if (human && (type instanceof Constant)) { - sb.append(((Constant) type).toHuman()); - } else { - sb.append(type); - } - } - - return sb.toString(); - } - - /** - * Holder of register spec data for the purposes of comparison (so that - * <code>RegisterSpec</code> itself can still keep <code>final</code> - * instance variables. - */ - private static class ForComparison { - /** >= 0; register number */ - private int reg; - - /** non-null; type loaded or stored */ - private TypeBearer type; - - /** null-ok; local variable associated with this register, if any */ - private LocalItem local; - - /** - * Set all the instance variables. - * - * @param reg >= 0; the register number - * @param type non-null; the type (or possibly actual value) which - * is loaded from or stored to the indicated register - * @param local null-ok; the associated local variable, if any - * @return non-null; an appropriately-constructed instance - */ - public void set(int reg, TypeBearer type, LocalItem local) { - this.reg = reg; - this.type = type; - this.local = local; - } - - /** - * Construct a <code>RegisterSpec</code> of this instance's - * contents. - * - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpec toRegisterSpec() { - return new RegisterSpec(reg, type, local); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof RegisterSpec)) { - return false; - } - - RegisterSpec spec = (RegisterSpec) other; - return spec.equals(reg, type, local); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return hashCodeOf(reg, type, local); - } - } -} diff --git a/dx/src/com/android/dx/rop/code/RegisterSpecList.java b/dx/src/com/android/dx/rop/code/RegisterSpecList.java deleted file mode 100644 index 28657a197..000000000 --- a/dx/src/com/android/dx/rop/code/RegisterSpecList.java +++ /dev/null @@ -1,362 +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.android.dx.rop.code; - -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.FixedSizeList; - -/** - * List of {@link RegisterSpec} instances. - */ -public final class RegisterSpecList - extends FixedSizeList implements TypeList { - /** non-null; no-element instance */ - public static final RegisterSpecList EMPTY = new RegisterSpecList(0); - - /** - * Makes a single-element instance. - * - * @param spec non-null; the element - * @return non-null; an appropriately-constructed instance - */ - public static RegisterSpecList make(RegisterSpec spec) { - RegisterSpecList result = new RegisterSpecList(1); - result.set(0, spec); - return result; - } - - /** - * Makes a two-element instance. - * - * @param spec0 non-null; the first element - * @param spec1 non-null; the second element - * @return non-null; an appropriately-constructed instance - */ - public static RegisterSpecList make(RegisterSpec spec0, - RegisterSpec spec1) { - RegisterSpecList result = new RegisterSpecList(2); - result.set(0, spec0); - result.set(1, spec1); - return result; - } - - /** - * Makes a three-element instance. - * - * @param spec0 non-null; the first element - * @param spec1 non-null; the second element - * @param spec2 non-null; the third element - * @return non-null; an appropriately-constructed instance - */ - public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1, - RegisterSpec spec2) { - RegisterSpecList result = new RegisterSpecList(3); - result.set(0, spec0); - result.set(1, spec1); - result.set(2, spec2); - return result; - } - - /** - * Makes a four-element instance. - * - * @param spec0 non-null; the first element - * @param spec1 non-null; the second element - * @param spec2 non-null; the third element - * @param spec3 non-null; the fourth element - * @return non-null; an appropriately-constructed instance - */ - public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1, - RegisterSpec spec2, - RegisterSpec spec3) { - RegisterSpecList result = new RegisterSpecList(4); - result.set(0, spec0); - result.set(1, spec1); - result.set(2, spec2); - result.set(3, spec3); - return result; - } - - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size the size of the list - */ - public RegisterSpecList(int size) { - super(size); - } - - /** {@inheritDoc} */ - public Type getType(int n) { - return get(n).getType().getType(); - } - - /** {@inheritDoc} */ - public int getWordCount() { - int sz = size(); - int result = 0; - - for (int i = 0; i < sz; i++) { - result += getType(i).getCategory(); - } - - return result; - } - - /** {@inheritDoc} */ - public TypeList withAddedType(Type type) { - throw new UnsupportedOperationException("unsupported"); - } - - /** - * 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</code>. - * - * @param n >= 0, < size(); which element - * @return non-null; the indicated element - */ - public RegisterSpec get(int n) { - return (RegisterSpec) get0(n); - } - - /** - * Returns a RegisterSpec in this list that uses the specified register, - * or null if there is none in this list. - * @param reg Register to find - * @return RegisterSpec that uses argument or null. - */ - public RegisterSpec specForRegister(int reg) { - int sz = size(); - for (int i = 0; i < sz; i++) { - RegisterSpec rs; - - rs = get(i); - - if (rs.getReg() == reg) { - return rs; - } - } - - return null; - } - - /** - * Returns the index of a RegisterSpec in this list that uses the specified - * register, or -1 if none in this list uses the register. - * @param reg Register to find - * @return index of RegisterSpec or -1 - */ - public int indexOfRegister(int reg) { - int sz = size(); - for (int i = 0; i < sz; i++) { - RegisterSpec rs; - - rs = get(i); - - if (rs.getReg() == reg) { - return i; - } - } - - return -1; - } - - /** - * Sets the element at the given index. - * - * @param n >= 0, < size(); which element - * @param spec non-null; the value to store - */ - public void set(int n, RegisterSpec spec) { - set0(n, spec); - } - - /** - * Gets the minimum required register count implied by this - * instance. This is equal to the highest register number referred - * to plus the widest width (largest category) of the type used in - * that register. - * - * @return >= 0; the required registers size - */ - public int getRegistersSize() { - int sz = size(); - int result = 0; - - for (int i = 0; i < sz; i++) { - RegisterSpec spec = (RegisterSpec) get0(i); - if (spec != null) { - int min = spec.getNextReg(); - if (min > result) { - result = min; - } - } - } - - return result; - } - - /** - * Returns a new instance, which is the same as this instance, - * except that it has an additional element prepended to the original. - * Mutability of the result is inherited from the original. - * - * @param spec non-null; the new first spec (to prepend) - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpecList withFirst(RegisterSpec spec) { - int sz = size(); - RegisterSpecList result = new RegisterSpecList(sz + 1); - - for (int i = 0; i < sz; i++) { - result.set0(i + 1, get0(i)); - } - - result.set0(0, spec); - if (isImmutable()) { - result.setImmutable(); - } - - return result; - } - - /** - * Returns a new instance, which is the same as this instance, - * except that its first element is removed. Mutability of the - * result is inherited from the original. - * - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpecList withoutFirst() { - int newSize = size() - 1; - - if (newSize == 0) { - return EMPTY; - } - - RegisterSpecList result = new RegisterSpecList(newSize); - - for (int i = 0; i < newSize; i++) { - result.set0(i, get0(i + 1)); - } - - if (isImmutable()) { - result.setImmutable(); - } - - return result; - } - - /** - * Returns a new instance, which is the same as this instance, - * except that its last element is removed. Mutability of the - * result is inherited from the original. - * - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpecList withoutLast() { - int newSize = size() - 1; - - if (newSize == 0) { - return EMPTY; - } - - RegisterSpecList result = new RegisterSpecList(newSize); - - for (int i = 0; i < newSize; i++) { - result.set0(i, get0(i)); - } - - if (isImmutable()) { - result.setImmutable(); - } - - return result; - } - - /** - * Returns an instance that is identical to this one, except that - * all register numbers are offset by the given amount. Mutability - * of the result is inherited from the original. - * - * @param delta the amount to offset the register numbers by - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpecList withOffset(int delta) { - int sz = size(); - - if (sz == 0) { - // Don't bother making a new zero-element instance. - return this; - } - - RegisterSpecList result = new RegisterSpecList(sz); - - for (int i = 0; i < sz; i++) { - RegisterSpec one = (RegisterSpec) get0(i); - if (one != null) { - result.set0(i, one.withOffset(delta)); - } - } - - if (isImmutable()) { - result.setImmutable(); - } - - return result; - } - - /** - * Returns an instance that is identical to this one, except that - * all register numbers are renumbered sequentially from the given - * base, with the first number duplicated if indicated. - * - * @param base the base register number - * @param duplicateFirst whether to duplicate the first number - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpecList withSequentialRegisters(int base, - boolean duplicateFirst) { - int sz = size(); - - if (sz == 0) { - // Don't bother making a new zero-element instance. - return this; - } - - RegisterSpecList result = new RegisterSpecList(sz); - - for (int i = 0; i < sz; i++) { - RegisterSpec one = (RegisterSpec) get0(i); - result.set0(i, one.withReg(base)); - if (duplicateFirst) { - duplicateFirst = false; - } else { - base += one.getCategory(); - } - } - - if (isImmutable()) { - result.setImmutable(); - } - - return result; - } - -} diff --git a/dx/src/com/android/dx/rop/code/RegisterSpecSet.java b/dx/src/com/android/dx/rop/code/RegisterSpecSet.java deleted file mode 100644 index 4eb2f65e8..000000000 --- a/dx/src/com/android/dx/rop/code/RegisterSpecSet.java +++ /dev/null @@ -1,350 +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.android.dx.rop.code; - -import com.android.dx.util.MutabilityControl; -import com.android.dx.rop.cst.CstUtf8; - -/** - * Set of {@link RegisterSpec} instances, where a given register number - * may appear only once in the set. - */ -public final class RegisterSpecSet - extends MutabilityControl { - /** non-null; no-element instance */ - public static final RegisterSpecSet EMPTY = new RegisterSpecSet(0); - - /** - * non-null; array of register specs, where each element is - * <code>null</code> or is an instance whose <code>reg</code> - * matches the array index - */ - private final RegisterSpec[] specs; - - /** >= -1; size of the set or <code>-1</code> if not yet calculated */ - private int size; - - /** - * Constructs an instance. The instance is initially empty. - * - * @param maxSize >= 0; the maximum register number (exclusive) that - * may be represented in this instance - */ - public RegisterSpecSet(int maxSize) { - super(maxSize != 0); - - this.specs = new RegisterSpec[maxSize]; - this.size = 0; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof RegisterSpecSet)) { - return false; - } - - RegisterSpecSet otherSet = (RegisterSpecSet) other; - RegisterSpec[] otherSpecs = otherSet.specs; - int len = specs.length; - - if ((len != otherSpecs.length) || (size() != otherSet.size())) { - return false; - } - - for (int i = 0; i < len; i++) { - RegisterSpec s1 = specs[i]; - RegisterSpec s2 = otherSpecs[i]; - - if (s1 == s2) { - continue; - } - - if ((s1 == null) || !s1.equals(s2)) { - return false; - } - } - - return true; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int len = specs.length; - int hash = 0; - - for (int i = 0; i < len; i++) { - RegisterSpec spec = specs[i]; - int oneHash = (spec == null) ? 0 : spec.hashCode(); - hash = (hash * 31) + oneHash; - } - - return hash; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - int len = specs.length; - StringBuffer sb = new StringBuffer(len * 25); - - sb.append('{'); - - boolean any = false; - for (int i = 0; i < len; i++) { - RegisterSpec spec = specs[i]; - if (spec != null) { - if (any) { - sb.append(", "); - } else { - any = true; - } - sb.append(spec); - } - } - - sb.append('}'); - return sb.toString(); - } - - /** - * Gets the maximum number of registers that may be in this instance, which - * is also the maximum-plus-one of register numbers that may be - * represented. - * - * @return >= 0; the maximum size - */ - public int getMaxSize() { - return specs.length; - } - - /** - * Gets the current size of this instance. - * - * @return >= 0; the size - */ - public int size() { - int result = size; - - if (result < 0) { - int len = specs.length; - - result = 0; - for (int i = 0; i < len; i++) { - if (specs[i] != null) { - result++; - } - } - - size = result; - } - - return result; - } - - /** - * Gets the element with the given register number, if any. - * - * @param reg >= 0; the desired register number - * @return null-ok; the element with the given register number or - * <code>null</code> if there is none - */ - public RegisterSpec get(int reg) { - try { - return specs[reg]; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("bogus reg"); - } - } - - /** - * Gets the element with the same register number as the given - * spec, if any. This is just a convenient shorthand for - * <code>get(spec.getReg())</code>. - * - * @param spec non-null; spec with the desired register number - * @return null-ok; the element with the matching register number or - * <code>null</code> if there is none - */ - public RegisterSpec get(RegisterSpec spec) { - return get(spec.getReg()); - } - - /** - * Returns the spec in this set that's currently associated with a given - * name, or null if there is none. - * - * @param local non-null; local item to search for - * @return null-ok; first register found with name. - */ - public RegisterSpec localItemToSpec(LocalItem local) { - for (int reg = 0; reg < specs.length; reg++) { - if (specs[reg] != null && local.equals(specs[reg].getLocalItem())) { - return specs[reg]; - } - } - - return null; - } - - /** - * Removes a spec from the set. Only the register number - * of the parameter is significant. - * - * @param toRemove non-null; register to remove. - */ - public void remove(RegisterSpec toRemove) { - try { - specs[toRemove.getReg()] = null; - size = -1; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("bogus reg"); - } - } - - /** - * Puts the given spec into the set. If there is already an element in - * the set with the same register number, it is replaced. Additionally, - * if the previous element is for a category-2 register, then that - * previous element is nullified. Finally, if the given spec is for - * a category-2 register, then the immediately subsequent element - * is nullified. - * - * @param spec non-null; the register spec to put in the instance - */ - public void put(RegisterSpec spec) { - throwIfImmutable(); - - if (spec == null) { - throw new NullPointerException("spec == null"); - } - - size = -1; - - try { - int reg = spec.getReg(); - specs[reg] = spec; - - if (reg > 0) { - int prevReg = reg - 1; - RegisterSpec prevSpec = specs[prevReg]; - if ((prevSpec != null) && (prevSpec.getCategory() == 2)) { - specs[prevReg] = null; - } - } - - if (spec.getCategory() == 2) { - specs[reg + 1] = null; - } - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("spec.getReg() out of range"); - } - } - - /** - * Intersects this instance with the given one, modifying this - * instance. The intersection consists of the pairwise - * {@link RegisterSpec#intersect} of corresponding elements from - * this instance and the given one where both are non-null. - * - * @param other non-null; set to intersect with - * @param localPrimary whether local variables are primary to - * the intersection; if <code>true</code>, then the only non-null - * result elements occur when registers being intersected have - * equal names (or both have <code>null</code> names) - */ - public void intersect(RegisterSpecSet other, boolean localPrimary) { - throwIfImmutable(); - - RegisterSpec[] otherSpecs = other.specs; - int thisLen = specs.length; - int len = Math.min(thisLen, otherSpecs.length); - - size = -1; - - for (int i = 0; i < len; i++) { - RegisterSpec spec = specs[i]; - - if (spec == null) { - continue; - } - - RegisterSpec intersection = - spec.intersect(otherSpecs[i], localPrimary); - if (intersection != spec) { - specs[i] = intersection; - } - } - - for (int i = len; i < thisLen; i++) { - specs[i] = null; - } - } - - /** - * Returns an instance that is identical to this one, except that - * all register numbers are offset by the given amount. Mutability - * of the result is inherited from the original. - * - * @param delta the amount to offset the register numbers by - * @return non-null; an appropriately-constructed instance - */ - public RegisterSpecSet withOffset(int delta) { - int len = specs.length; - RegisterSpecSet result = new RegisterSpecSet(len + delta); - - for (int i = 0; i < len; i++) { - RegisterSpec spec = specs[i]; - if (spec != null) { - result.put(spec.withOffset(delta)); - } - } - - result.size = size; - - if (isImmutable()) { - result.setImmutable(); - } - - return result; - } - - /** - * Makes and return a mutable copy of this instance. - * - * @return non-null; the mutable copy - */ - public RegisterSpecSet mutableCopy() { - int len = specs.length; - RegisterSpecSet copy = new RegisterSpecSet(len); - - for (int i = 0; i < len; i++) { - RegisterSpec spec = specs[i]; - if (spec != null) { - copy.put(spec); - } - } - - copy.size = size; - - return copy; - } -} diff --git a/dx/src/com/android/dx/rop/code/Rop.java b/dx/src/com/android/dx/rop/code/Rop.java deleted file mode 100644 index f918e126c..000000000 --- a/dx/src/com/android/dx/rop/code/Rop.java +++ /dev/null @@ -1,407 +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.android.dx.rop.code; - -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.Hex; - -/** - * Class that describes all the immutable parts of register-based operations. - */ -public final class Rop { - /** minimum <code>BRANCH_*</code> value */ - public static final int BRANCH_MIN = 1; - - /** indicates a non-branching op */ - public static final int BRANCH_NONE = 1; - - /** indicates a function/method return */ - public static final int BRANCH_RETURN = 2; - - /** indicates an unconditional goto */ - public static final int BRANCH_GOTO = 3; - - /** indicates a two-way branch */ - public static final int BRANCH_IF = 4; - - /** indicates a switch-style branch */ - public static final int BRANCH_SWITCH = 5; - - /** indicates a throw-style branch (both always-throws and may-throw) */ - public static final int BRANCH_THROW = 6; - - /** maximum <code>BRANCH_*</code> value */ - public static final int BRANCH_MAX = 6; - - /** the opcode; one of the constants in {@link RegOps} */ - private final int opcode; - - /** - * non-null; result type of this operation; {@link Type#VOID} for - * no-result operations - */ - private final Type result; - - /** non-null; types of all the sources of this operation */ - private final TypeList sources; - - /** non-null; list of possible types thrown by this operation */ - private final TypeList exceptions; - - /** - * the branchingness of this op; one of the <code>BRANCH_*</code> - * constants in this class - */ - private final int branchingness; - - /** whether this is a function/method call op or similar */ - private final boolean isCallLike; - - /** null-ok; nickname, if specified (used for debugging) */ - private final String nickname; - - /** - * Constructs an instance. This method is private. Use one of the - * public constructors. - * - * @param opcode the opcode; one of the constants in {@link RegOps} - * @param result non-null; result type of this operation; {@link - * Type#VOID} for no-result operations - * @param sources non-null; types of all the sources of this operation - * @param exceptions non-null; list of possible types thrown by this - * operation - * @param branchingness the branchingness of this op; one of the - * <code>BRANCH_*</code> constants - * @param isCallLike whether the op is a function/method call or similar - * @param nickname null-ok; optional nickname (used for debugging) - */ - public Rop(int opcode, Type result, TypeList sources, - TypeList exceptions, int branchingness, boolean isCallLike, - String nickname) { - if (result == null) { - throw new NullPointerException("result == null"); - } - - if (sources == null) { - throw new NullPointerException("sources == null"); - } - - if (exceptions == null) { - throw new NullPointerException("exceptions == null"); - } - - if ((branchingness < BRANCH_MIN) || (branchingness > BRANCH_MAX)) { - throw new IllegalArgumentException("bogus branchingness"); - } - - if ((exceptions.size() != 0) && (branchingness != BRANCH_THROW)) { - throw new IllegalArgumentException("exceptions / branchingness " + - "mismatch"); - } - - this.opcode = opcode; - this.result = result; - this.sources = sources; - this.exceptions = exceptions; - this.branchingness = branchingness; - this.isCallLike = isCallLike; - this.nickname = nickname; - } - - /** - * Constructs an instance. The constructed instance is never a - * call-like op (see {@link #isCallLike}). - * - * @param opcode the opcode; one of the constants in {@link RegOps} - * @param result non-null; result type of this operation; {@link - * Type#VOID} for no-result operations - * @param sources non-null; types of all the sources of this operation - * @param exceptions non-null; list of possible types thrown by this - * operation - * @param branchingness the branchingness of this op; one of the - * <code>BRANCH_*</code> constants - * @param nickname null-ok; optional nickname (used for debugging) - */ - public Rop(int opcode, Type result, TypeList sources, - TypeList exceptions, int branchingness, String nickname) { - this(opcode, result, sources, exceptions, branchingness, false, - nickname); - } - - /** - * Constructs a no-exception instance. The constructed instance is never a - * call-like op (see {@link #isCallLike}). - * - * @param opcode the opcode; one of the constants in {@link RegOps} - * @param result non-null; result type of this operation; {@link - * Type#VOID} for no-result operations - * @param sources non-null; types of all the sources of this operation - * @param branchingness the branchingness of this op; one of the - * <code>BRANCH_*</code> constants - * @param nickname null-ok; optional nickname (used for debugging) - */ - public Rop(int opcode, Type result, TypeList sources, int branchingness, - String nickname) { - this(opcode, result, sources, StdTypeList.EMPTY, branchingness, false, - nickname); - } - - /** - * Constructs a non-branching no-exception instance. The - * <code>branchingness</code> is always <code>BRANCH_NONE</code>, - * and it is never a call-like op (see {@link #isCallLike}). - * - * @param opcode the opcode; one of the constants in {@link RegOps} - * @param result non-null; result type of this operation; {@link - * Type#VOID} for no-result operations - * @param sources non-null; types of all the sources of this operation - * @param nickname null-ok; optional nickname (used for debugging) - */ - public Rop(int opcode, Type result, TypeList sources, String nickname) { - this(opcode, result, sources, StdTypeList.EMPTY, Rop.BRANCH_NONE, - false, nickname); - } - - /** - * Constructs a non-empty exceptions instance. Its - * <code>branchingness</code> is always <code>BRANCH_THROW</code>, - * but it is never a call-like op (see {@link #isCallLike}). - * - * @param opcode the opcode; one of the constants in {@link RegOps} - * @param result non-null; result type of this operation; {@link - * Type#VOID} for no-result operations - * @param sources non-null; types of all the sources of this operation - * @param exceptions non-null; list of possible types thrown by this - * operation - * @param nickname null-ok; optional nickname (used for debugging) - */ - public Rop(int opcode, Type result, TypeList sources, TypeList exceptions, - String nickname) { - this(opcode, result, sources, exceptions, Rop.BRANCH_THROW, false, - nickname); - } - - /** - * Constructs a non-nicknamed instance with non-empty exceptions, which - * is always a call-like op (see {@link #isCallLike}). Its - * <code>branchingness</code> is always <code>BRANCH_THROW</code>. - * - * @param opcode the opcode; one of the constants in {@link RegOps} - * @param sources non-null; types of all the sources of this operation - * @param exceptions non-null; list of possible types thrown by this - * operation - */ - public Rop(int opcode, TypeList sources, TypeList exceptions) { - this(opcode, Type.VOID, sources, exceptions, Rop.BRANCH_THROW, true, - null); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (this == other) { - // Easy out. - return true; - } - - if (!(other instanceof Rop)) { - return false; - } - - Rop rop = (Rop) other; - - return (opcode == rop.opcode) && - (branchingness == rop.branchingness) && - (result == rop.result) && - sources.equals(rop.sources) && - exceptions.equals(rop.exceptions); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int h = (opcode * 31) + branchingness; - h = (h * 31) + result.hashCode(); - h = (h * 31) + sources.hashCode(); - h = (h * 31) + exceptions.hashCode(); - - return h; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(40); - - sb.append("Rop{"); - - sb.append(RegOps.opName(opcode)); - - if (result != Type.VOID) { - sb.append(" "); - sb.append(result); - } else { - sb.append(" ."); - } - - sb.append(" <-"); - - int sz = sources.size(); - if (sz == 0) { - sb.append(" ."); - } else { - for (int i = 0; i < sz; i++) { - sb.append(' '); - sb.append(sources.getType(i)); - } - } - - if (isCallLike) { - sb.append(" call"); - } - - sz = exceptions.size(); - if (sz != 0) { - sb.append(" throws"); - for (int i = 0; i < sz; i++) { - sb.append(' '); - Type one = exceptions.getType(i); - if (one == Type.THROWABLE) { - sb.append("<any>"); - } else { - sb.append(exceptions.getType(i)); - } - } - } else { - switch (branchingness) { - case BRANCH_NONE: sb.append(" flows"); break; - case BRANCH_RETURN: sb.append(" returns"); break; - case BRANCH_GOTO: sb.append(" gotos"); break; - case BRANCH_IF: sb.append(" ifs"); break; - case BRANCH_SWITCH: sb.append(" switches"); break; - default: sb.append(" " + Hex.u1(branchingness)); break; - } - } - - sb.append('}'); - - return sb.toString(); - } - - /** - * Gets the opcode. - * - * @return the opcode - */ - public int getOpcode() { - return opcode; - } - - /** - * Gets the result type. A return value of {@link Type#VOID} - * means this operation returns nothing. - * - * @return null-ok; the result spec - */ - public Type getResult() { - return result; - } - - /** - * Gets the source types. - * - * @return non-null; the source types - */ - public TypeList getSources() { - return sources; - } - - /** - * Gets the list of exception types that might be thrown. - * - * @return non-null; the list of exception types - */ - public TypeList getExceptions() { - return exceptions; - } - - /** - * Gets the branchingness of this instance. - * - * @return the branchingness - */ - public int getBranchingness() { - return branchingness; - } - - /** - * Gets whether this opcode is a function/method call or similar. - * - * @return <code>true</code> iff this opcode is call-like - */ - public boolean isCallLike() { - return isCallLike; - } - - - /** - * Gets whether this opcode is commutative (the order of its sources are - * unimportant) or not. All commutative Rops have exactly two sources and - * have no branchiness. - * - * @return true if rop is commutative - */ - public boolean isCommutative() { - switch (opcode) { - case RegOps.AND: - case RegOps.OR: - case RegOps.XOR: - case RegOps.ADD: - case RegOps.MUL: - return true; - default: - return false; - } - } - - /** - * Gets the nickname. If this instance has no nickname, this returns - * the result of calling {@link #toString}. - * - * @return non-null; the nickname - */ - public String getNickname() { - if (nickname != null) { - return nickname; - } - - return toString(); - } - - /** - * Gets whether this operation can possibly throw an exception. This - * is just a convenient wrapper for - * <code>getExceptions().size() != 0</code>. - * - * @return <code>true</code> iff this operation can possibly throw - */ - public final boolean canThrow() { - return (exceptions.size() != 0); - } -} diff --git a/dx/src/com/android/dx/rop/code/RopMethod.java b/dx/src/com/android/dx/rop/code/RopMethod.java deleted file mode 100644 index 0c0d8f1a7..000000000 --- a/dx/src/com/android/dx/rop/code/RopMethod.java +++ /dev/null @@ -1,207 +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.android.dx.rop.code; - -import com.android.dx.util.Bits; -import com.android.dx.util.Hex; -import com.android.dx.util.IntList; - -/** - * All of the parts that make up a method at the rop layer. - */ -public final class RopMethod { - /** non-null; basic block list of the method */ - private final BasicBlockList blocks; - - /** >= 0; label for the block which starts the method */ - private final int firstLabel; - - /** - * null-ok; array of predecessors for each block, indexed by block - * label - */ - private IntList[] predecessors; - - /** - * null-ok; the predecessors for the implicit "exit" block, that is - * the labels for the blocks that return, if calculated - */ - private IntList exitPredecessors; - - /** - * Constructs an instance. - * - * @param blocks non-null; basic block list of the method - * @param firstLabel >= 0; the label of the first block to execute - */ - public RopMethod(BasicBlockList blocks, int firstLabel) { - if (blocks == null) { - throw new NullPointerException("blocks == null"); - } - - if (firstLabel < 0) { - throw new IllegalArgumentException("firstLabel < 0"); - } - - this.blocks = blocks; - this.firstLabel = firstLabel; - - this.predecessors = null; - this.exitPredecessors = null; - } - - /** - * Gets the basic block list for this method. - * - * @return non-null; the list - */ - public BasicBlockList getBlocks() { - return blocks; - } - - /** - * Gets the label for the first block in the method that this list - * represents. - * - * @return >= 0; the first-block label - */ - public int getFirstLabel() { - return firstLabel; - } - - /** - * Gets the predecessors associated with the given block. This throws - * an exception if there is no block with the given label. - * - * @param label >= 0; the label of the block in question - * @return non-null; the predecessors of that block - */ - public IntList labelToPredecessors(int label) { - if (exitPredecessors == null) { - calcPredecessors(); - } - - IntList result = predecessors[label]; - - if (result == null) { - throw new RuntimeException("no such block: " + Hex.u2(label)); - } - - return result; - } - - /** - * Gets the exit predecessors for this instance. - * - * @return non-null; the exit predecessors - */ - public IntList getExitPredecessors() { - if (exitPredecessors == null) { - calcPredecessors(); - } - - return exitPredecessors; - } - - - /** - * Returns an instance that is identical to this one, except that - * the registers in each instruction are offset by the given - * amount. - * - * @param delta the amount to offset register numbers by - * @return non-null; an appropriately-constructed instance - */ - public RopMethod withRegisterOffset(int delta) { - RopMethod result = new RopMethod(blocks.withRegisterOffset(delta), - firstLabel); - - if (exitPredecessors != null) { - /* - * The predecessors have been calculated. It's safe to - * inject these into the new instance, since the - * transformation being applied doesn't affect the - * predecessors. - */ - result.exitPredecessors = exitPredecessors; - result.predecessors = predecessors; - } - - return result; - } - - /** - * Calculates the predecessor sets for each block as well as for the - * exit. - */ - private void calcPredecessors() { - int maxLabel = blocks.getMaxLabel(); - IntList[] predecessors = new IntList[maxLabel]; - IntList exitPredecessors = new IntList(10); - int sz = blocks.size(); - - /* - * For each block, find its successors, and add the block's label to - * the successor's predecessors. - */ - for (int i = 0; i < sz; i++) { - BasicBlock one = blocks.get(i); - int label = one.getLabel(); - IntList successors = one.getSuccessors(); - int ssz = successors.size(); - if (ssz == 0) { - // This block exits. - exitPredecessors.add(label); - } else { - for (int j = 0; j < ssz; j++) { - int succLabel = successors.get(j); - IntList succPreds = predecessors[succLabel]; - if (succPreds == null) { - succPreds = new IntList(10); - predecessors[succLabel] = succPreds; - } - succPreds.add(label); - } - } - } - - // Sort and immutablize all the predecessor lists. - for (int i = 0; i < maxLabel; i++) { - IntList preds = predecessors[i]; - if (preds != null) { - preds.sort(); - preds.setImmutable(); - } - } - - exitPredecessors.sort(); - exitPredecessors.setImmutable(); - - /* - * The start label might not ever have had any predecessors - * added to it (probably doesn't, because of how Java gets - * translated into rop form). So, check for this and rectify - * the situation if required. - */ - if (predecessors[firstLabel] == null) { - predecessors[firstLabel] = IntList.EMPTY; - } - - this.predecessors = predecessors; - this.exitPredecessors = exitPredecessors; - } -} diff --git a/dx/src/com/android/dx/rop/code/Rops.java b/dx/src/com/android/dx/rop/code/Rops.java deleted file mode 100644 index b662656f7..000000000 --- a/dx/src/com/android/dx/rop/code/Rops.java +++ /dev/null @@ -1,2124 +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.android.dx.rop.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstBaseMethodRef; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.rop.type.TypeList; - -/** - * Standard instances of {@link Rop}. - */ -public final class Rops { - /** <code>nop()</code> */ - public static final Rop NOP = - new Rop(RegOps.NOP, Type.VOID, StdTypeList.EMPTY, "nop"); - - /** <code>r,x: int :: r = x;</code> */ - public static final Rop MOVE_INT = - new Rop(RegOps.MOVE, Type.INT, StdTypeList.INT, "move-int"); - - /** <code>r,x: long :: r = x;</code> */ - public static final Rop MOVE_LONG = - new Rop(RegOps.MOVE, Type.LONG, StdTypeList.LONG, "move-long"); - - /** <code>r,x: float :: r = x;</code> */ - public static final Rop MOVE_FLOAT = - new Rop(RegOps.MOVE, Type.FLOAT, StdTypeList.FLOAT, "move-float"); - - /** <code>r,x: double :: r = x;</code> */ - public static final Rop MOVE_DOUBLE = - new Rop(RegOps.MOVE, Type.DOUBLE, StdTypeList.DOUBLE, "move-double"); - - /** <code>r,x: Object :: r = x;</code> */ - public static final Rop MOVE_OBJECT = - new Rop(RegOps.MOVE, Type.OBJECT, StdTypeList.OBJECT, "move-object"); - - /** - * <code>r,x: ReturnAddress :: r = x;</code> - * - * Note that this rop-form instruction has no dex-form equivilent and - * must be removed before the dex conversion. - */ - public static final Rop MOVE_RETURN_ADDRESS = - new Rop(RegOps.MOVE, Type.RETURN_ADDRESS, - StdTypeList.RETURN_ADDRESS, "move-return-address"); - - /** <code>r,param(x): int :: r = param(x);</code> */ - public static final Rop MOVE_PARAM_INT = - new Rop(RegOps.MOVE_PARAM, Type.INT, StdTypeList.EMPTY, - "move-param-int"); - - /** <code>r,param(x): long :: r = param(x);</code> */ - public static final Rop MOVE_PARAM_LONG = - new Rop(RegOps.MOVE_PARAM, Type.LONG, StdTypeList.EMPTY, - "move-param-long"); - - /** <code>r,param(x): float :: r = param(x);</code> */ - public static final Rop MOVE_PARAM_FLOAT = - new Rop(RegOps.MOVE_PARAM, Type.FLOAT, StdTypeList.EMPTY, - "move-param-float"); - - /** <code>r,param(x): double :: r = param(x);</code> */ - public static final Rop MOVE_PARAM_DOUBLE = - new Rop(RegOps.MOVE_PARAM, Type.DOUBLE, StdTypeList.EMPTY, - "move-param-double"); - - /** <code>r,param(x): Object :: r = param(x);</code> */ - public static final Rop MOVE_PARAM_OBJECT = - new Rop(RegOps.MOVE_PARAM, Type.OBJECT, StdTypeList.EMPTY, - "move-param-object"); - - /** <code>r, literal: int :: r = literal;</code> */ - public static final Rop CONST_INT = - new Rop(RegOps.CONST, Type.INT, StdTypeList.EMPTY, "const-int"); - - /** <code>r, literal: long :: r = literal;</code> */ - public static final Rop CONST_LONG = - new Rop(RegOps.CONST, Type.LONG, StdTypeList.EMPTY, "const-long"); - - /** <code>r, literal: float :: r = literal;</code> */ - public static final Rop CONST_FLOAT = - new Rop(RegOps.CONST, Type.FLOAT, StdTypeList.EMPTY, "const-float"); - - /** <code>r, literal: double :: r = literal;</code> */ - public static final Rop CONST_DOUBLE = - new Rop(RegOps.CONST, Type.DOUBLE, StdTypeList.EMPTY, "const-double"); - - /** <code>r, literal: Object :: r = literal;</code> */ - public static final Rop CONST_OBJECT = - new Rop(RegOps.CONST, Type.OBJECT, StdTypeList.EMPTY, - Exceptions.LIST_Error, "const-object"); - - /** <code>r, literal: Object :: r = literal;</code> */ - public static final Rop CONST_OBJECT_NOTHROW = - new Rop(RegOps.CONST, Type.OBJECT, StdTypeList.EMPTY, - "const-object-nothrow"); - - /** <code>goto <i>label</i></code> */ - public static final Rop GOTO = - new Rop(RegOps.GOTO, Type.VOID, StdTypeList.EMPTY, Rop.BRANCH_GOTO, - "goto"); - - /** <code>x: int :: if (x == 0) goto <i>label</i></code> */ - public static final Rop IF_EQZ_INT = - new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, - "if-eqz-int"); - - /** <code>x: int :: if (x != 0) goto <i>label</i></code> */ - public static final Rop IF_NEZ_INT = - new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, - "if-nez-int"); - - /** <code>x: int :: if (x < 0) goto <i>label</i></code> */ - public static final Rop IF_LTZ_INT = - new Rop(RegOps.IF_LT, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, - "if-ltz-int"); - - /** <code>x: int :: if (x >= 0) goto <i>label</i></code> */ - public static final Rop IF_GEZ_INT = - new Rop(RegOps.IF_GE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, - "if-gez-int"); - - /** <code>x: int :: if (x <= 0) goto <i>label</i></code> */ - public static final Rop IF_LEZ_INT = - new Rop(RegOps.IF_LE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, - "if-lez-int"); - - /** <code>x: int :: if (x > 0) goto <i>label</i></code> */ - public static final Rop IF_GTZ_INT = - new Rop(RegOps.IF_GT, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF, - "if-gtz-int"); - - /** <code>x: Object :: if (x == null) goto <i>label</i></code> */ - public static final Rop IF_EQZ_OBJECT = - new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.OBJECT, Rop.BRANCH_IF, - "if-eqz-object"); - - /** <code>x: Object :: if (x != null) goto <i>label</i></code> */ - public static final Rop IF_NEZ_OBJECT = - new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.OBJECT, Rop.BRANCH_IF, - "if-nez-object"); - - /** <code>x,y: int :: if (x == y) goto <i>label</i></code> */ - public static final Rop IF_EQ_INT = - new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, - "if-eq-int"); - - /** <code>x,y: int :: if (x != y) goto <i>label</i></code> */ - public static final Rop IF_NE_INT = - new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, - "if-ne-int"); - - /** <code>x,y: int :: if (x < y) goto <i>label</i></code> */ - public static final Rop IF_LT_INT = - new Rop(RegOps.IF_LT, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, - "if-lt-int"); - - /** <code>x,y: int :: if (x >= y) goto <i>label</i></code> */ - public static final Rop IF_GE_INT = - new Rop(RegOps.IF_GE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, - "if-ge-int"); - - /** <code>x,y: int :: if (x <= y) goto <i>label</i></code> */ - public static final Rop IF_LE_INT = - new Rop(RegOps.IF_LE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, - "if-le-int"); - - /** <code>x,y: int :: if (x > y) goto <i>label</i></code> */ - public static final Rop IF_GT_INT = - new Rop(RegOps.IF_GT, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF, - "if-gt-int"); - - /** <code>x,y: Object :: if (x == y) goto <i>label</i></code> */ - public static final Rop IF_EQ_OBJECT = - new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.OBJECT_OBJECT, - Rop.BRANCH_IF, "if-eq-object"); - - /** <code>x,y: Object :: if (x != y) goto <i>label</i></code> */ - public static final Rop IF_NE_OBJECT = - new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.OBJECT_OBJECT, - Rop.BRANCH_IF, "if-ne-object"); - - /** <code>x: int :: goto switchtable[x]</code> */ - public static final Rop SWITCH = - new Rop(RegOps.SWITCH, Type.VOID, StdTypeList.INT, Rop.BRANCH_SWITCH, - "switch"); - - /** <code>r,x,y: int :: r = x + y;</code> */ - public static final Rop ADD_INT = - new Rop(RegOps.ADD, Type.INT, StdTypeList.INT_INT, "add-int"); - - /** <code>r,x,y: long :: r = x + y;</code> */ - public static final Rop ADD_LONG = - new Rop(RegOps.ADD, Type.LONG, StdTypeList.LONG_LONG, "add-long"); - - /** <code>r,x,y: float :: r = x + y;</code> */ - public static final Rop ADD_FLOAT = - new Rop(RegOps.ADD, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "add-float"); - - /** <code>r,x,y: double :: r = x + y;</code> */ - public static final Rop ADD_DOUBLE = - new Rop(RegOps.ADD, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE, - Rop.BRANCH_NONE, "add-double"); - - /** <code>r,x,y: int :: r = x - y;</code> */ - public static final Rop SUB_INT = - new Rop(RegOps.SUB, Type.INT, StdTypeList.INT_INT, "sub-int"); - - /** <code>r,x,y: long :: r = x - y;</code> */ - public static final Rop SUB_LONG = - new Rop(RegOps.SUB, Type.LONG, StdTypeList.LONG_LONG, "sub-long"); - - /** <code>r,x,y: float :: r = x - y;</code> */ - public static final Rop SUB_FLOAT = - new Rop(RegOps.SUB, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "sub-float"); - - /** <code>r,x,y: double :: r = x - y;</code> */ - public static final Rop SUB_DOUBLE = - new Rop(RegOps.SUB, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE, - Rop.BRANCH_NONE, "sub-double"); - - /** <code>r,x,y: int :: r = x * y;</code> */ - public static final Rop MUL_INT = - new Rop(RegOps.MUL, Type.INT, StdTypeList.INT_INT, "mul-int"); - - /** <code>r,x,y: long :: r = x * y;</code> */ - public static final Rop MUL_LONG = - new Rop(RegOps.MUL, Type.LONG, StdTypeList.LONG_LONG, "mul-long"); - - /** <code>r,x,y: float :: r = x * y;</code> */ - public static final Rop MUL_FLOAT = - new Rop(RegOps.MUL, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "mul-float"); - - /** <code>r,x,y: double :: r = x * y;</code> */ - public static final Rop MUL_DOUBLE = - new Rop(RegOps.MUL, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE, - Rop.BRANCH_NONE, "mul-double"); - - /** <code>r,x,y: int :: r = x / y;</code> */ - public static final Rop DIV_INT = - new Rop(RegOps.DIV, Type.INT, StdTypeList.INT_INT, - Exceptions.LIST_Error_ArithmeticException, "div-int"); - - /** <code>r,x,y: long :: r = x / y;</code> */ - public static final Rop DIV_LONG = - new Rop(RegOps.DIV, Type.LONG, StdTypeList.LONG_LONG, - Exceptions.LIST_Error_ArithmeticException, "div-long"); - - /** <code>r,x,y: float :: r = x / y;</code> */ - public static final Rop DIV_FLOAT = - new Rop(RegOps.DIV, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "div-float"); - - /** <code>r,x,y: double :: r = x / y;</code> */ - public static final Rop DIV_DOUBLE = - new Rop(RegOps.DIV, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE, - "div-double"); - - /** <code>r,x,y: int :: r = x % y;</code> */ - public static final Rop REM_INT = - new Rop(RegOps.REM, Type.INT, StdTypeList.INT_INT, - Exceptions.LIST_Error_ArithmeticException, "rem-int"); - - /** <code>r,x,y: long :: r = x % y;</code> */ - public static final Rop REM_LONG = - new Rop(RegOps.REM, Type.LONG, StdTypeList.LONG_LONG, - Exceptions.LIST_Error_ArithmeticException, "rem-long"); - - /** <code>r,x,y: float :: r = x % y;</code> */ - public static final Rop REM_FLOAT = - new Rop(RegOps.REM, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "rem-float"); - - /** <code>r,x,y: double :: r = x % y;</code> */ - public static final Rop REM_DOUBLE = - new Rop(RegOps.REM, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE, - "rem-double"); - - /** <code>r,x: int :: r = -x;</code> */ - public static final Rop NEG_INT = - new Rop(RegOps.NEG, Type.INT, StdTypeList.INT, "neg-int"); - - /** <code>r,x: long :: r = -x;</code> */ - public static final Rop NEG_LONG = - new Rop(RegOps.NEG, Type.LONG, StdTypeList.LONG, "neg-long"); - - /** <code>r,x: float :: r = -x;</code> */ - public static final Rop NEG_FLOAT = - new Rop(RegOps.NEG, Type.FLOAT, StdTypeList.FLOAT, "neg-float"); - - /** <code>r,x: double :: r = -x;</code> */ - public static final Rop NEG_DOUBLE = - new Rop(RegOps.NEG, Type.DOUBLE, StdTypeList.DOUBLE, "neg-double"); - - /** <code>r,x,y: int :: r = x & y;</code> */ - public static final Rop AND_INT = - new Rop(RegOps.AND, Type.INT, StdTypeList.INT_INT, "and-int"); - - /** <code>r,x,y: long :: r = x & y;</code> */ - public static final Rop AND_LONG = - new Rop(RegOps.AND, Type.LONG, StdTypeList.LONG_LONG, "and-long"); - - /** <code>r,x,y: int :: r = x | y;</code> */ - public static final Rop OR_INT = - new Rop(RegOps.OR, Type.INT, StdTypeList.INT_INT, "or-int"); - - /** <code>r,x,y: long :: r = x | y;</code> */ - public static final Rop OR_LONG = - new Rop(RegOps.OR, Type.LONG, StdTypeList.LONG_LONG, "or-long"); - - /** <code>r,x,y: int :: r = x ^ y;</code> */ - public static final Rop XOR_INT = - new Rop(RegOps.XOR, Type.INT, StdTypeList.INT_INT, "xor-int"); - - /** <code>r,x,y: long :: r = x ^ y;</code> */ - public static final Rop XOR_LONG = - new Rop(RegOps.XOR, Type.LONG, StdTypeList.LONG_LONG, "xor-long"); - - /** <code>r,x,y: int :: r = x << y;</code> */ - public static final Rop SHL_INT = - new Rop(RegOps.SHL, Type.INT, StdTypeList.INT_INT, "shl-int"); - - /** <code>r,x: long; y: int :: r = x << y;</code> */ - public static final Rop SHL_LONG = - new Rop(RegOps.SHL, Type.LONG, StdTypeList.LONG_INT, "shl-long"); - - /** <code>r,x,y: int :: r = x >> y;</code> */ - public static final Rop SHR_INT = - new Rop(RegOps.SHR, Type.INT, StdTypeList.INT_INT, "shr-int"); - - /** <code>r,x: long; y: int :: r = x >> y;</code> */ - public static final Rop SHR_LONG = - new Rop(RegOps.SHR, Type.LONG, StdTypeList.LONG_INT, "shr-long"); - - /** <code>r,x,y: int :: r = x >>> y;</code> */ - public static final Rop USHR_INT = - new Rop(RegOps.USHR, Type.INT, StdTypeList.INT_INT, "ushr-int"); - - /** <code>r,x: long; y: int :: r = x >>> y;</code> */ - public static final Rop USHR_LONG = - new Rop(RegOps.USHR, Type.LONG, StdTypeList.LONG_INT, "ushr-long"); - - /** <code>r,x: int :: r = ~x;</code> */ - public static final Rop NOT_INT = - new Rop(RegOps.NOT, Type.INT, StdTypeList.INT, "not-int"); - - /** <code>r,x: long :: r = ~x;</code> */ - public static final Rop NOT_LONG = - new Rop(RegOps.NOT, Type.LONG, StdTypeList.LONG, "not-long"); - - /** <code>r,x,c: int :: r = x + c;</code> */ - public static final Rop ADD_CONST_INT = - new Rop(RegOps.ADD, Type.INT, StdTypeList.INT, "add-const-int"); - - /** <code>r,x,c: long :: r = x + c;</code> */ - public static final Rop ADD_CONST_LONG = - new Rop(RegOps.ADD, Type.LONG, StdTypeList.LONG, "add-const-long"); - - /** <code>r,x,c: float :: r = x + c;</code> */ - public static final Rop ADD_CONST_FLOAT = - new Rop(RegOps.ADD, Type.FLOAT, StdTypeList.FLOAT, "add-const-float"); - - /** <code>r,x,c: double :: r = x + c;</code> */ - public static final Rop ADD_CONST_DOUBLE = - new Rop(RegOps.ADD, Type.DOUBLE, StdTypeList.DOUBLE, - "add-const-double"); - - /** <code>r,x,c: int :: r = x - c;</code> */ - public static final Rop SUB_CONST_INT = - new Rop(RegOps.SUB, Type.INT, StdTypeList.INT, "sub-const-int"); - - /** <code>r,x,c: long :: r = x - c;</code> */ - public static final Rop SUB_CONST_LONG = - new Rop(RegOps.SUB, Type.LONG, StdTypeList.LONG, "sub-const-long"); - - /** <code>r,x,c: float :: r = x - c;</code> */ - public static final Rop SUB_CONST_FLOAT = - new Rop(RegOps.SUB, Type.FLOAT, StdTypeList.FLOAT, "sub-const-float"); - - /** <code>r,x,c: double :: r = x - c;</code> */ - public static final Rop SUB_CONST_DOUBLE = - new Rop(RegOps.SUB, Type.DOUBLE, StdTypeList.DOUBLE, - "sub-const-double"); - - /** <code>r,x,c: int :: r = x * c;</code> */ - public static final Rop MUL_CONST_INT = - new Rop(RegOps.MUL, Type.INT, StdTypeList.INT, "mul-const-int"); - - /** <code>r,x,c: long :: r = x * c;</code> */ - public static final Rop MUL_CONST_LONG = - new Rop(RegOps.MUL, Type.LONG, StdTypeList.LONG, "mul-const-long"); - - /** <code>r,x,c: float :: r = x * c;</code> */ - public static final Rop MUL_CONST_FLOAT = - new Rop(RegOps.MUL, Type.FLOAT, StdTypeList.FLOAT, "mul-const-float"); - - /** <code>r,x,c: double :: r = x * c;</code> */ - public static final Rop MUL_CONST_DOUBLE = - new Rop(RegOps.MUL, Type.DOUBLE, StdTypeList.DOUBLE, - "mul-const-double"); - - /** <code>r,x,c: int :: r = x / c;</code> */ - public static final Rop DIV_CONST_INT = - new Rop(RegOps.DIV, Type.INT, StdTypeList.INT, - Exceptions.LIST_Error_ArithmeticException, "div-const-int"); - - /** <code>r,x,c: long :: r = x / c;</code> */ - public static final Rop DIV_CONST_LONG = - new Rop(RegOps.DIV, Type.LONG, StdTypeList.LONG, - Exceptions.LIST_Error_ArithmeticException, "div-const-long"); - - /** <code>r,x,c: float :: r = x / c;</code> */ - public static final Rop DIV_CONST_FLOAT = - new Rop(RegOps.DIV, Type.FLOAT, StdTypeList.FLOAT, "div-const-float"); - - /** <code>r,x,c: double :: r = x / c;</code> */ - public static final Rop DIV_CONST_DOUBLE = - new Rop(RegOps.DIV, Type.DOUBLE, StdTypeList.DOUBLE, - "div-const-double"); - - /** <code>r,x,c: int :: r = x % c;</code> */ - public static final Rop REM_CONST_INT = - new Rop(RegOps.REM, Type.INT, StdTypeList.INT, - Exceptions.LIST_Error_ArithmeticException, "rem-const-int"); - - /** <code>r,x,c: long :: r = x % c;</code> */ - public static final Rop REM_CONST_LONG = - new Rop(RegOps.REM, Type.LONG, StdTypeList.LONG, - Exceptions.LIST_Error_ArithmeticException, "rem-const-long"); - - /** <code>r,x,c: float :: r = x % c;</code> */ - public static final Rop REM_CONST_FLOAT = - new Rop(RegOps.REM, Type.FLOAT, StdTypeList.FLOAT, "rem-const-float"); - - /** <code>r,x,c: double :: r = x % c;</code> */ - public static final Rop REM_CONST_DOUBLE = - new Rop(RegOps.REM, Type.DOUBLE, StdTypeList.DOUBLE, - "rem-const-double"); - - /** <code>r,x,c: int :: r = x & c;</code> */ - public static final Rop AND_CONST_INT = - new Rop(RegOps.AND, Type.INT, StdTypeList.INT, "and-const-int"); - - /** <code>r,x,c: long :: r = x & c;</code> */ - public static final Rop AND_CONST_LONG = - new Rop(RegOps.AND, Type.LONG, StdTypeList.LONG, "and-const-long"); - - /** <code>r,x,c: int :: r = x | c;</code> */ - public static final Rop OR_CONST_INT = - new Rop(RegOps.OR, Type.INT, StdTypeList.INT, "or-const-int"); - - /** <code>r,x,c: long :: r = x | c;</code> */ - public static final Rop OR_CONST_LONG = - new Rop(RegOps.OR, Type.LONG, StdTypeList.LONG, "or-const-long"); - - /** <code>r,x,c: int :: r = x ^ c;</code> */ - public static final Rop XOR_CONST_INT = - new Rop(RegOps.XOR, Type.INT, StdTypeList.INT, "xor-const-int"); - - /** <code>r,x,c: long :: r = x ^ c;</code> */ - public static final Rop XOR_CONST_LONG = - new Rop(RegOps.XOR, Type.LONG, StdTypeList.LONG, "xor-const-long"); - - /** <code>r,x,c: int :: r = x << c;</code> */ - public static final Rop SHL_CONST_INT = - new Rop(RegOps.SHL, Type.INT, StdTypeList.INT, "shl-const-int"); - - /** <code>r,x: long; c: int :: r = x << c;</code> */ - public static final Rop SHL_CONST_LONG = - new Rop(RegOps.SHL, Type.LONG, StdTypeList.INT, "shl-const-long"); - - /** <code>r,x,c: int :: r = x >> c;</code> */ - public static final Rop SHR_CONST_INT = - new Rop(RegOps.SHR, Type.INT, StdTypeList.INT, "shr-const-int"); - - /** <code>r,x: long; c: int :: r = x >> c;</code> */ - public static final Rop SHR_CONST_LONG = - new Rop(RegOps.SHR, Type.LONG, StdTypeList.INT, "shr-const-long"); - - /** <code>r,x,c: int :: r = x >>> c;</code> */ - public static final Rop USHR_CONST_INT = - new Rop(RegOps.USHR, Type.INT, StdTypeList.INT, "ushr-const-int"); - - /** <code>r,x: long; c: int :: r = x >>> c;</code> */ - public static final Rop USHR_CONST_LONG = - new Rop(RegOps.USHR, Type.LONG, StdTypeList.INT, "ushr-const-long"); - - /** <code>r: int; x,y: long :: r = cmp(x, y);</code> */ - public static final Rop CMPL_LONG = - new Rop(RegOps.CMPL, Type.INT, StdTypeList.LONG_LONG, "cmpl-long"); - - /** <code>r: int; x,y: float :: r = cmpl(x, y);</code> */ - public static final Rop CMPL_FLOAT = - new Rop(RegOps.CMPL, Type.INT, StdTypeList.FLOAT_FLOAT, "cmpl-float"); - - /** <code>r: int; x,y: double :: r = cmpl(x, y);</code> */ - public static final Rop CMPL_DOUBLE = - new Rop(RegOps.CMPL, Type.INT, StdTypeList.DOUBLE_DOUBLE, - "cmpl-double"); - - /** <code>r: int; x,y: float :: r = cmpg(x, y);</code> */ - public static final Rop CMPG_FLOAT = - new Rop(RegOps.CMPG, Type.INT, StdTypeList.FLOAT_FLOAT, "cmpg-float"); - - /** <code>r: int; x,y: double :: r = cmpg(x, y);</code> */ - public static final Rop CMPG_DOUBLE = - new Rop(RegOps.CMPG, Type.INT, StdTypeList.DOUBLE_DOUBLE, - "cmpg-double"); - - /** <code>r: int; x: long :: r = (int) x</code> */ - public static final Rop CONV_L2I = - new Rop(RegOps.CONV, Type.INT, StdTypeList.LONG, "conv-l2i"); - - /** <code>r: int; x: float :: r = (int) x</code> */ - public static final Rop CONV_F2I = - new Rop(RegOps.CONV, Type.INT, StdTypeList.FLOAT, "conv-f2i"); - - /** <code>r: int; x: double :: r = (int) x</code> */ - public static final Rop CONV_D2I = - new Rop(RegOps.CONV, Type.INT, StdTypeList.DOUBLE, "conv-d2i"); - - /** <code>r: long; x: int :: r = (long) x</code> */ - public static final Rop CONV_I2L = - new Rop(RegOps.CONV, Type.LONG, StdTypeList.INT, "conv-i2l"); - - /** <code>r: long; x: float :: r = (long) x</code> */ - public static final Rop CONV_F2L = - new Rop(RegOps.CONV, Type.LONG, StdTypeList.FLOAT, "conv-f2l"); - - /** <code>r: long; x: double :: r = (long) x</code> */ - public static final Rop CONV_D2L = - new Rop(RegOps.CONV, Type.LONG, StdTypeList.DOUBLE, "conv-d2l"); - - /** <code>r: float; x: int :: r = (float) x</code> */ - public static final Rop CONV_I2F = - new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.INT, "conv-i2f"); - - /** <code>r: float; x: long :: r = (float) x</code> */ - public static final Rop CONV_L2F = - new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.LONG, "conv-l2f"); - - /** <code>r: float; x: double :: r = (float) x</code> */ - public static final Rop CONV_D2F = - new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.DOUBLE, "conv-d2f"); - - /** <code>r: double; x: int :: r = (double) x</code> */ - public static final Rop CONV_I2D = - new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.INT, "conv-i2d"); - - /** <code>r: double; x: long :: r = (double) x</code> */ - public static final Rop CONV_L2D = - new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.LONG, "conv-l2d"); - - /** <code>r: double; x: float :: r = (double) x</code> */ - public static final Rop CONV_F2D = - new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.FLOAT, "conv-f2d"); - - /** - * <code>r,x: int :: r = (x << 24) >> 24</code> (Java-style - * convert int to byte) - */ - public static final Rop TO_BYTE = - new Rop(RegOps.TO_BYTE, Type.INT, StdTypeList.INT, "to-byte"); - - /** - * <code>r,x: int :: r = x & 0xffff</code> (Java-style - * convert int to char) - */ - public static final Rop TO_CHAR = - new Rop(RegOps.TO_CHAR, Type.INT, StdTypeList.INT, "to-char"); - - /** - * <code>r,x: int :: r = (x << 16) >> 16</code> (Java-style - * convert int to short) - */ - public static final Rop TO_SHORT = - new Rop(RegOps.TO_SHORT, Type.INT, StdTypeList.INT, "to-short"); - - /** <code>return void</code> */ - public static final Rop RETURN_VOID = - new Rop(RegOps.RETURN, Type.VOID, StdTypeList.EMPTY, Rop.BRANCH_RETURN, - "return-void"); - - /** <code>x: int; return x</code> */ - public static final Rop RETURN_INT = - new Rop(RegOps.RETURN, Type.VOID, StdTypeList.INT, Rop.BRANCH_RETURN, - "return-int"); - - /** <code>x: long; return x</code> */ - public static final Rop RETURN_LONG = - new Rop(RegOps.RETURN, Type.VOID, StdTypeList.LONG, Rop.BRANCH_RETURN, - "return-long"); - - /** <code>x: float; return x</code> */ - public static final Rop RETURN_FLOAT = - new Rop(RegOps.RETURN, Type.VOID, StdTypeList.FLOAT, Rop.BRANCH_RETURN, - "return-float"); - - /** <code>x: double; return x</code> */ - public static final Rop RETURN_DOUBLE = - new Rop(RegOps.RETURN, Type.VOID, StdTypeList.DOUBLE, - Rop.BRANCH_RETURN, "return-double"); - - /** <code>x: Object; return x</code> */ - public static final Rop RETURN_OBJECT = - new Rop(RegOps.RETURN, Type.VOID, StdTypeList.OBJECT, - Rop.BRANCH_RETURN, "return-object"); - - /** <code>T: any type; r: int; x: T[]; :: r = x.length</code> */ - public static final Rop ARRAY_LENGTH = - new Rop(RegOps.ARRAY_LENGTH, Type.INT, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, "array-length"); - - /** <code>x: Throwable :: throw(x)</code> */ - public static final Rop THROW = - new Rop(RegOps.THROW, Type.VOID, StdTypeList.THROWABLE, - StdTypeList.THROWABLE, "throw"); - - /** <code>x: Object :: monitorenter(x)</code> */ - public static final Rop MONITOR_ENTER = - new Rop(RegOps.MONITOR_ENTER, Type.VOID, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, "monitor-enter"); - - /** <code>x: Object :: monitorexit(x)</code> */ - public static final Rop MONITOR_EXIT = - new Rop(RegOps.MONITOR_EXIT, Type.VOID, StdTypeList.OBJECT, - Exceptions.LIST_Error_Null_IllegalMonitorStateException, - "monitor-exit"); - - /** <code>r,y: int; x: int[] :: r = x[y]</code> */ - public static final Rop AGET_INT = - new Rop(RegOps.AGET, Type.INT, StdTypeList.INTARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, - "aget-int"); - - /** <code>r: long; x: long[]; y: int :: r = x[y]</code> */ - public static final Rop AGET_LONG = - new Rop(RegOps.AGET, Type.LONG, StdTypeList.LONGARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, - "aget-long"); - - /** <code>r: float; x: float[]; y: int :: r = x[y]</code> */ - public static final Rop AGET_FLOAT = - new Rop(RegOps.AGET, Type.FLOAT, StdTypeList.FLOATARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, - "aget-float"); - - /** <code>r: double; x: double[]; y: int :: r = x[y]</code> */ - public static final Rop AGET_DOUBLE = - new Rop(RegOps.AGET, Type.DOUBLE, StdTypeList.DOUBLEARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, - "aget-double"); - - /** <code>r: Object; x: Object[]; y: int :: r = x[y]</code> */ - public static final Rop AGET_OBJECT = - new Rop(RegOps.AGET, Type.OBJECT, StdTypeList.OBJECTARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, - "aget-object"); - - /** <code>r: boolean; x: boolean[]; y: int :: r = x[y]</code> */ - public static final Rop AGET_BOOLEAN = - new Rop(RegOps.AGET, Type.INT, StdTypeList.BOOLEANARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, - "aget-boolean"); - - /** <code>r: byte; x: byte[]; y: int :: r = x[y]</code> */ - public static final Rop AGET_BYTE = - new Rop(RegOps.AGET, Type.INT, StdTypeList.BYTEARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-byte"); - - /** <code>r: char; x: char[]; y: int :: r = x[y]</code> */ - public static final Rop AGET_CHAR = - new Rop(RegOps.AGET, Type.INT, StdTypeList.CHARARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-char"); - - /** <code>r: short; x: short[]; y: int :: r = x[y]</code> */ - public static final Rop AGET_SHORT = - new Rop(RegOps.AGET, Type.INT, StdTypeList.SHORTARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, - "aget-short"); - - /** <code>x,z: int; y: int[] :: y[z] = x</code> */ - public static final Rop APUT_INT = - new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_INTARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-int"); - - /** <code>x: long; y: long[]; z: int :: y[z] = x</code> */ - public static final Rop APUT_LONG = - new Rop(RegOps.APUT, Type.VOID, StdTypeList.LONG_LONGARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-long"); - - /** <code>x: float; y: float[]; z: int :: y[z] = x</code> */ - public static final Rop APUT_FLOAT = - new Rop(RegOps.APUT, Type.VOID, StdTypeList.FLOAT_FLOATARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, - "aput-float"); - - /** <code>x: double; y: double[]; z: int :: y[z] = x</code> */ - public static final Rop APUT_DOUBLE = - new Rop(RegOps.APUT, Type.VOID, StdTypeList.DOUBLE_DOUBLEARR_INT, - Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, - "aput-double"); - - /** <code>x: Object; y: Object[]; z: int :: y[z] = x</code> */ - public static final Rop APUT_OBJECT = - new Rop(RegOps.APUT, Type.VOID, StdTypeList.OBJECT_OBJECTARR_INT, - Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, - "aput-object"); - - /** <code>x: boolean; y: boolean[]; z: int :: y[z] = x</code> */ - public static final Rop APUT_BOOLEAN = - new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BOOLEANARR_INT, - Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, - "aput-boolean"); - - /** <code>x: byte; y: byte[]; z: int :: y[z] = x</code> */ - public static final Rop APUT_BYTE = - new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BYTEARR_INT, - Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-byte"); - - /** <code>x: char; y: char[]; z: int :: y[z] = x</code> */ - public static final Rop APUT_CHAR = - new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_CHARARR_INT, - Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-char"); - - /** <code>x: short; y: short[]; z: int :: y[z] = x</code> */ - public static final Rop APUT_SHORT = - new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_SHORTARR_INT, - Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, - "aput-short"); - - /** - * <code>T: any non-array object type :: r = - * alloc(T)</code> (allocate heap space for an object) - */ - public static final Rop NEW_INSTANCE = - new Rop(RegOps.NEW_INSTANCE, Type.OBJECT, StdTypeList.EMPTY, - Exceptions.LIST_Error, "new-instance"); - - /** <code>r: int[]; x: int :: r = new int[x]</code> */ - public static final Rop NEW_ARRAY_INT = - new Rop(RegOps.NEW_ARRAY, Type.INT_ARRAY, StdTypeList.INT, - Exceptions.LIST_Error_NegativeArraySizeException, - "new-array-int"); - - /** <code>r: long[]; x: int :: r = new long[x]</code> */ - public static final Rop NEW_ARRAY_LONG = - new Rop(RegOps.NEW_ARRAY, Type.LONG_ARRAY, StdTypeList.INT, - Exceptions.LIST_Error_NegativeArraySizeException, - "new-array-long"); - - /** <code>r: float[]; x: int :: r = new float[x]</code> */ - public static final Rop NEW_ARRAY_FLOAT = - new Rop(RegOps.NEW_ARRAY, Type.FLOAT_ARRAY, StdTypeList.INT, - Exceptions.LIST_Error_NegativeArraySizeException, - "new-array-float"); - - /** <code>r: double[]; x: int :: r = new double[x]</code> */ - public static final Rop NEW_ARRAY_DOUBLE = - new Rop(RegOps.NEW_ARRAY, Type.DOUBLE_ARRAY, StdTypeList.INT, - Exceptions.LIST_Error_NegativeArraySizeException, - "new-array-double"); - - /** <code>r: boolean[]; x: int :: r = new boolean[x]</code> */ - public static final Rop NEW_ARRAY_BOOLEAN = - new Rop(RegOps.NEW_ARRAY, Type.BOOLEAN_ARRAY, StdTypeList.INT, - Exceptions.LIST_Error_NegativeArraySizeException, - "new-array-boolean"); - - /** <code>r: byte[]; x: int :: r = new byte[x]</code> */ - public static final Rop NEW_ARRAY_BYTE = - new Rop(RegOps.NEW_ARRAY, Type.BYTE_ARRAY, StdTypeList.INT, - Exceptions.LIST_Error_NegativeArraySizeException, - "new-array-byte"); - - /** <code>r: char[]; x: int :: r = new char[x]</code> */ - public static final Rop NEW_ARRAY_CHAR = - new Rop(RegOps.NEW_ARRAY, Type.CHAR_ARRAY, StdTypeList.INT, - Exceptions.LIST_Error_NegativeArraySizeException, - "new-array-char"); - - /** <code>r: short[]; x: int :: r = new short[x]</code> */ - public static final Rop NEW_ARRAY_SHORT = - new Rop(RegOps.NEW_ARRAY, Type.SHORT_ARRAY, StdTypeList.INT, - Exceptions.LIST_Error_NegativeArraySizeException, - "new-array-short"); - - /** - * <code>T: any non-array object type; x: Object :: (T) x</code> (can - * throw <code>ClassCastException</code>) - */ - public static final Rop CHECK_CAST = - new Rop(RegOps.CHECK_CAST, Type.VOID, StdTypeList.OBJECT, - Exceptions.LIST_Error_ClassCastException, "check-cast"); - - /** - * <code>T: any non-array object type; x: Object :: x instanceof - * T</code>. Note: This is listed as throwing <code>Error</code> - * explicitly because the op <i>can</i> throw, but there are no - * other predefined exceptions for it. - */ - public static final Rop INSTANCE_OF = - new Rop(RegOps.INSTANCE_OF, Type.INT, StdTypeList.OBJECT, - Exceptions.LIST_Error, "instance-of"); - - /** - * <code>r: int; x: Object; f: instance field spec of - * type int :: r = x.f</code> - */ - public static final Rop GET_FIELD_INT = - new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, "get-field-int"); - - /** - * <code>r: long; x: Object; f: instance field spec of - * type long :: r = x.f</code> - */ - public static final Rop GET_FIELD_LONG = - new Rop(RegOps.GET_FIELD, Type.LONG, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, "get-field-long"); - - /** - * <code>r: float; x: Object; f: instance field spec of - * type float :: r = x.f</code> - */ - public static final Rop GET_FIELD_FLOAT = - new Rop(RegOps.GET_FIELD, Type.FLOAT, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, - "get-field-float"); - - /** - * <code>r: double; x: Object; f: instance field spec of - * type double :: r = x.f</code> - */ - public static final Rop GET_FIELD_DOUBLE = - new Rop(RegOps.GET_FIELD, Type.DOUBLE, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, - "get-field-double"); - - /** - * <code>r: Object; x: Object; f: instance field spec of - * type Object :: r = x.f</code> - */ - public static final Rop GET_FIELD_OBJECT = - new Rop(RegOps.GET_FIELD, Type.OBJECT, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, - "get-field-object"); - - /** - * <code>r: boolean; x: Object; f: instance field spec of - * type boolean :: r = x.f</code> - */ - public static final Rop GET_FIELD_BOOLEAN = - new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, - "get-field-boolean"); - - /** - * <code>r: byte; x: Object; f: instance field spec of - * type byte :: r = x.f</code> - */ - public static final Rop GET_FIELD_BYTE = - new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, - "get-field-byte"); - - /** - * <code>r: char; x: Object; f: instance field spec of - * type char :: r = x.f</code> - */ - public static final Rop GET_FIELD_CHAR = - new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, - "get-field-char"); - - /** - * <code>r: short; x: Object; f: instance field spec of - * type short :: r = x.f</code> - */ - public static final Rop GET_FIELD_SHORT = - new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT, - Exceptions.LIST_Error_NullPointerException, - "get-field-short"); - - /** - * <code>r: int; f: static field spec of type int :: r = - * f</code> - */ - public static final Rop GET_STATIC_INT = - new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY, - Exceptions.LIST_Error, "get-static-int"); - - /** - * <code>r: long; f: static field spec of type long :: r = - * f</code> - */ - public static final Rop GET_STATIC_LONG = - new Rop(RegOps.GET_STATIC, Type.LONG, StdTypeList.EMPTY, - Exceptions.LIST_Error, "get-static-long"); - - /** - * <code>r: float; f: static field spec of type float :: r = - * f</code> - */ - public static final Rop GET_STATIC_FLOAT = - new Rop(RegOps.GET_STATIC, Type.FLOAT, StdTypeList.EMPTY, - Exceptions.LIST_Error, "get-static-float"); - - /** - * <code>r: double; f: static field spec of type double :: r = - * f</code> - */ - public static final Rop GET_STATIC_DOUBLE = - new Rop(RegOps.GET_STATIC, Type.DOUBLE, StdTypeList.EMPTY, - Exceptions.LIST_Error, "get-static-double"); - - /** - * <code>r: Object; f: static field spec of type Object :: r = - * f</code> - */ - public static final Rop GET_STATIC_OBJECT = - new Rop(RegOps.GET_STATIC, Type.OBJECT, StdTypeList.EMPTY, - Exceptions.LIST_Error, "get-static-object"); - - /** - * <code>r: boolean; f: static field spec of type boolean :: r = - * f</code> - */ - public static final Rop GET_STATIC_BOOLEAN = - new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY, - Exceptions.LIST_Error, "get-field-boolean"); - - /** - * <code>r: byte; f: static field spec of type byte :: r = - * f</code> - */ - public static final Rop GET_STATIC_BYTE = - new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY, - Exceptions.LIST_Error, "get-field-byte"); - - /** - * <code>r: char; f: static field spec of type char :: r = - * f</code> - */ - public static final Rop GET_STATIC_CHAR = - new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY, - Exceptions.LIST_Error, "get-field-char"); - - /** - * <code>r: short; f: static field spec of type short :: r = - * f</code> - */ - public static final Rop GET_STATIC_SHORT = - new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY, - Exceptions.LIST_Error, "get-field-short"); - - /** - * <code>x: int; y: Object; f: instance field spec of type - * int :: y.f = x</code> - */ - public static final Rop PUT_FIELD_INT = - new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT, - Exceptions.LIST_Error_NullPointerException, "put-field-int"); - - /** - * <code>x: long; y: Object; f: instance field spec of type - * long :: y.f = x</code> - */ - public static final Rop PUT_FIELD_LONG = - new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.LONG_OBJECT, - Exceptions.LIST_Error_NullPointerException, "put-field-long"); - - /** - * <code>x: float; y: Object; f: instance field spec of type - * float :: y.f = x</code> - */ - public static final Rop PUT_FIELD_FLOAT = - new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.FLOAT_OBJECT, - Exceptions.LIST_Error_NullPointerException, - "put-field-float"); - - /** - * <code>x: double; y: Object; f: instance field spec of type - * double :: y.f = x</code> - */ - public static final Rop PUT_FIELD_DOUBLE = - new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.DOUBLE_OBJECT, - Exceptions.LIST_Error_NullPointerException, - "put-field-double"); - - /** - * <code>x: Object; y: Object; f: instance field spec of type - * Object :: y.f = x</code> - */ - public static final Rop PUT_FIELD_OBJECT = - new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.OBJECT_OBJECT, - Exceptions.LIST_Error_NullPointerException, - "put-field-object"); - - /** - * <code>x: int; y: Object; f: instance field spec of type - * boolean :: y.f = x</code> - */ - public static final Rop PUT_FIELD_BOOLEAN = - new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT, - Exceptions.LIST_Error_NullPointerException, - "put-field-boolean"); - - /** - * <code>x: int; y: Object; f: instance field spec of type - * byte :: y.f = x</code> - */ - public static final Rop PUT_FIELD_BYTE = - new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT, - Exceptions.LIST_Error_NullPointerException, - "put-field-byte"); - - /** - * <code>x: int; y: Object; f: instance field spec of type - * char :: y.f = x</code> - */ - public static final Rop PUT_FIELD_CHAR = - new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT, - Exceptions.LIST_Error_NullPointerException, - "put-field-char"); - - /** - * <code>x: int; y: Object; f: instance field spec of type - * short :: y.f = x</code> - */ - public static final Rop PUT_FIELD_SHORT = - new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT, - Exceptions.LIST_Error_NullPointerException, - "put-field-short"); - - /** - * <code>f: static field spec of type int; x: int :: f = - * x</code> - */ - public static final Rop PUT_STATIC_INT = - new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT, - Exceptions.LIST_Error, "put-static-int"); - - /** - * <code>f: static field spec of type long; x: long :: f = - * x</code> - */ - public static final Rop PUT_STATIC_LONG = - new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.LONG, - Exceptions.LIST_Error, "put-static-long"); - - /** - * <code>f: static field spec of type float; x: float :: f = - * x</code> - */ - public static final Rop PUT_STATIC_FLOAT = - new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.FLOAT, - Exceptions.LIST_Error, "put-static-float"); - - /** - * <code>f: static field spec of type double; x: double :: f = - * x</code> - */ - public static final Rop PUT_STATIC_DOUBLE = - new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.DOUBLE, - Exceptions.LIST_Error, "put-static-double"); - - /** - * <code>f: static field spec of type Object; x: Object :: f = - * x</code> - */ - public static final Rop PUT_STATIC_OBJECT = - new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.OBJECT, - Exceptions.LIST_Error, "put-static-object"); - - /** - * <code>f: static field spec of type boolean; x: boolean :: f = - * x</code> - */ - public static final Rop PUT_STATIC_BOOLEAN = - new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT, - Exceptions.LIST_Error, "put-static-boolean"); - - /** - * <code>f: static field spec of type byte; x: byte :: f = - * x</code> - */ - public static final Rop PUT_STATIC_BYTE = - new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT, - Exceptions.LIST_Error, "put-static-byte"); - - /** - * <code>f: static field spec of type char; x: char :: f = - * x</code> - */ - public static final Rop PUT_STATIC_CHAR = - new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT, - Exceptions.LIST_Error, "put-static-char"); - - /** - * <code>f: static field spec of type short; x: short :: f = - * x</code> - */ - public static final Rop PUT_STATIC_SHORT = - new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT, - Exceptions.LIST_Error, "put-static-short"); - - /** <code>x: Int :: local variable begins in x */ - public static final Rop MARK_LOCAL_INT = - new Rop (RegOps.MARK_LOCAL, Type.VOID, - StdTypeList.INT, "mark-local-int"); - - /** <code>x: Long :: local variable begins in x */ - public static final Rop MARK_LOCAL_LONG = - new Rop (RegOps.MARK_LOCAL, Type.VOID, - StdTypeList.LONG, "mark-local-long"); - - /** <code>x: Float :: local variable begins in x */ - public static final Rop MARK_LOCAL_FLOAT = - new Rop (RegOps.MARK_LOCAL, Type.VOID, - StdTypeList.FLOAT, "mark-local-float"); - - /** <code>x: Double :: local variable begins in x */ - public static final Rop MARK_LOCAL_DOUBLE = - new Rop (RegOps.MARK_LOCAL, Type.VOID, - StdTypeList.DOUBLE, "mark-local-double"); - - /** <code>x: Object :: local variable begins in x */ - public static final Rop MARK_LOCAL_OBJECT = - new Rop (RegOps.MARK_LOCAL, Type.VOID, - StdTypeList.OBJECT, "mark-local-object"); - - /** <code>T: Any primitive type; v0..vx: T :: {v0, ..., vx}</code> */ - public static final Rop FILL_ARRAY_DATA = - new Rop(RegOps.FILL_ARRAY_DATA, Type.VOID, StdTypeList.EMPTY, - "fill-array-data"); - - /** - * Returns the appropriate rop for the given opcode, destination, - * and sources. The result is typically, but not necessarily, a - * shared instance. - * - * <p><b>Note:</b> This method does not do complete error checking on - * its arguments, and so it may return an instance which seemed "right - * enough" even though in actuality the passed arguments don't quite - * match what is returned. TODO: Revisit this issue.</p> - * - * @param opcode the opcode - * @param dest non-null; destination type, or {@link Type#VOID} if none - * @param sources non-null; list of source types - * @param cst null-ok; associated constant, if any - * @return non-null; an appropriate instance - */ - public static Rop ropFor(int opcode, TypeBearer dest, TypeList sources, - Constant cst) { - switch (opcode) { - case RegOps.NOP: return NOP; - case RegOps.MOVE: return opMove(dest); - case RegOps.MOVE_PARAM: return opMoveParam(dest); - case RegOps.MOVE_EXCEPTION: return opMoveException(dest); - case RegOps.CONST: return opConst(dest); - case RegOps.GOTO: return GOTO; - case RegOps.IF_EQ: return opIfEq(sources); - case RegOps.IF_NE: return opIfNe(sources); - case RegOps.IF_LT: return opIfLt(sources); - case RegOps.IF_GE: return opIfGe(sources); - case RegOps.IF_LE: return opIfLe(sources); - case RegOps.IF_GT: return opIfGt(sources); - case RegOps.SWITCH: return SWITCH; - case RegOps.ADD: return opAdd(sources); - case RegOps.SUB: return opSub(sources); - case RegOps.MUL: return opMul(sources); - case RegOps.DIV: return opDiv(sources); - case RegOps.REM: return opRem(sources); - case RegOps.NEG: return opNeg(dest); - case RegOps.AND: return opAnd(sources); - case RegOps.OR: return opOr(sources); - case RegOps.XOR: return opXor(sources); - case RegOps.SHL: return opShl(sources); - case RegOps.SHR: return opShr(sources); - case RegOps.USHR: return opUshr(sources); - case RegOps.NOT: return opNot(dest); - case RegOps.CMPL: return opCmpl(sources.getType(0)); - case RegOps.CMPG: return opCmpg(sources.getType(0)); - case RegOps.CONV: return opConv(dest, sources.getType(0)); - case RegOps.TO_BYTE: return TO_BYTE; - case RegOps.TO_CHAR: return TO_CHAR; - case RegOps.TO_SHORT: return TO_SHORT; - case RegOps.RETURN: { - if (sources.size() == 0) { - return RETURN_VOID; - } - return opReturn(sources.getType(0)); - } - case RegOps.ARRAY_LENGTH: return ARRAY_LENGTH; - case RegOps.THROW: return THROW; - case RegOps.MONITOR_ENTER: return MONITOR_ENTER; - case RegOps.MONITOR_EXIT: return MONITOR_EXIT; - case RegOps.AGET: { - Type source = sources.getType(0); - if (source == Type.KNOWN_NULL) { - // Treat a known-null as an Object[] in this context. - source = Type.OBJECT_ARRAY; - } - return opAget(source.getComponentType()); - } - case RegOps.APUT: { - Type source = sources.getType(1); - if (source == Type.KNOWN_NULL) { - // Treat a known-null as an Object[] in this context. - source = Type.OBJECT_ARRAY; - } - return opAput(source.getComponentType()); - } - case RegOps.NEW_INSTANCE: return NEW_INSTANCE; - case RegOps.NEW_ARRAY: return opNewArray(dest.getType()); - case RegOps.CHECK_CAST: return CHECK_CAST; - case RegOps.INSTANCE_OF: return INSTANCE_OF; - case RegOps.GET_FIELD: return opGetField(dest); - case RegOps.GET_STATIC: return opGetStatic(dest); - case RegOps.PUT_FIELD: return opPutField(sources.getType(0)); - case RegOps.PUT_STATIC: return opPutStatic(sources.getType(0)); - case RegOps.INVOKE_STATIC: { - return opInvokeStatic(((CstMethodRef) cst).getPrototype()); - } - case RegOps.INVOKE_VIRTUAL: { - CstBaseMethodRef cstMeth = (CstMethodRef) cst; - Prototype meth = cstMeth.getPrototype(); - CstType definer = cstMeth.getDefiningClass(); - meth = meth.withFirstParameter(definer.getClassType()); - return opInvokeVirtual(meth); - } - case RegOps.INVOKE_SUPER: { - CstBaseMethodRef cstMeth = (CstMethodRef) cst; - Prototype meth = cstMeth.getPrototype(); - CstType definer = cstMeth.getDefiningClass(); - meth = meth.withFirstParameter(definer.getClassType()); - return opInvokeSuper(meth); - } - case RegOps.INVOKE_DIRECT: { - CstBaseMethodRef cstMeth = (CstMethodRef) cst; - Prototype meth = cstMeth.getPrototype(); - CstType definer = cstMeth.getDefiningClass(); - meth = meth.withFirstParameter(definer.getClassType()); - return opInvokeDirect(meth); - } - case RegOps.INVOKE_INTERFACE: { - CstBaseMethodRef cstMeth = (CstMethodRef) cst; - Prototype meth = cstMeth.getPrototype(); - CstType definer = cstMeth.getDefiningClass(); - meth = meth.withFirstParameter(definer.getClassType()); - return opInvokeInterface(meth); - } - } - - throw new RuntimeException("unknown opcode " + RegOps.opName(opcode)); - } - - /** - * Returns the appropriate <code>move</code> rop for the given type. The - * result is a shared instance. - * - * @param type non-null; type of value being moved - * @return non-null; an appropriate instance - */ - public static Rop opMove(TypeBearer type) { - switch (type.getBasicFrameType()) { - case Type.BT_INT: return MOVE_INT; - case Type.BT_LONG: return MOVE_LONG; - case Type.BT_FLOAT: return MOVE_FLOAT; - case Type.BT_DOUBLE: return MOVE_DOUBLE; - case Type.BT_OBJECT: return MOVE_OBJECT; - case Type.BT_ADDR: return MOVE_RETURN_ADDRESS; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>move-param</code> rop for the - * given type. The result is a shared instance. - * - * @param type non-null; type of value being moved - * @return non-null; an appropriate instance - */ - public static Rop opMoveParam(TypeBearer type) { - switch (type.getBasicFrameType()) { - case Type.BT_INT: return MOVE_PARAM_INT; - case Type.BT_LONG: return MOVE_PARAM_LONG; - case Type.BT_FLOAT: return MOVE_PARAM_FLOAT; - case Type.BT_DOUBLE: return MOVE_PARAM_DOUBLE; - case Type.BT_OBJECT: return MOVE_PARAM_OBJECT; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>move-exception</code> rop for the - * given type. The result may be a shared instance. - * - * @param type non-null; type of the exception - * @return non-null; an appropriate instance - */ - public static Rop opMoveException(TypeBearer type) { - return new Rop(RegOps.MOVE_EXCEPTION, type.getType(), - StdTypeList.EMPTY, (String) null); - } - - /** - * Returns the appropriate <code>move-result</code> rop for the - * given type. The result may be a shared instance. - * - * @param type non-null; type of the parameter - * @return non-null; an appropriate instance - */ - public static Rop opMoveResult(TypeBearer type) { - return new Rop(RegOps.MOVE_RESULT, type.getType(), - StdTypeList.EMPTY, (String) null); - } - - /** - * Returns the appropriate <code>move-result-pseudo</code> rop for the - * given type. The result may be a shared instance. - * - * @param type non-null; type of the parameter - * @return non-null; an appropriate instance - */ - public static Rop opMoveResultPseudo(TypeBearer type) { - return new Rop(RegOps.MOVE_RESULT_PSEUDO, type.getType(), - StdTypeList.EMPTY, (String) null); - } - - /** - * Returns the appropriate <code>const</code> rop for the given - * type. The result is a shared instance. - * - * @param type non-null; type of the constant - * @return non-null; an appropriate instance - */ - public static Rop opConst(TypeBearer type) { - if (type.getType() == Type.KNOWN_NULL) { - return CONST_OBJECT_NOTHROW; - } - - switch (type.getBasicFrameType()) { - case Type.BT_INT: return CONST_INT; - case Type.BT_LONG: return CONST_LONG; - case Type.BT_FLOAT: return CONST_FLOAT; - case Type.BT_DOUBLE: return CONST_DOUBLE; - case Type.BT_OBJECT: return CONST_OBJECT; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>if-eq</code> rop for the given - * sources. The result is a shared instance. - * - * @param types non-null; source types - * @return non-null; an appropriate instance - */ - public static Rop opIfEq(TypeList types) { - return pickIf(types, IF_EQZ_INT, IF_EQZ_OBJECT, - IF_EQ_INT, IF_EQ_OBJECT); - } - - /** - * Returns the appropriate <code>if-ne</code> rop for the given - * sources. The result is a shared instance. - * - * @param types non-null; source types - * @return non-null; an appropriate instance - */ - public static Rop opIfNe(TypeList types) { - return pickIf(types, IF_NEZ_INT, IF_NEZ_OBJECT, - IF_NE_INT, IF_NE_OBJECT); - } - - /** - * Returns the appropriate <code>if-lt</code> rop for the given - * sources. The result is a shared instance. - * - * @param types non-null; source types - * @return non-null; an appropriate instance - */ - public static Rop opIfLt(TypeList types) { - return pickIf(types, IF_LTZ_INT, null, IF_LT_INT, null); - } - - /** - * Returns the appropriate <code>if-ge</code> rop for the given - * sources. The result is a shared instance. - * - * @param types non-null; source types - * @return non-null; an appropriate instance - */ - public static Rop opIfGe(TypeList types) { - return pickIf(types, IF_GEZ_INT, null, IF_GE_INT, null); - } - - /** - * Returns the appropriate <code>if-gt</code> rop for the given - * sources. The result is a shared instance. - * - * @param types non-null; source types - * @return non-null; an appropriate instance - */ - public static Rop opIfGt(TypeList types) { - return pickIf(types, IF_GTZ_INT, null, IF_GT_INT, null); - } - - /** - * Returns the appropriate <code>if-le</code> rop for the given - * sources. The result is a shared instance. - * - * @param types non-null; source types - * @return non-null; an appropriate instance - */ - public static Rop opIfLe(TypeList types) { - return pickIf(types, IF_LEZ_INT, null, IF_LE_INT, null); - } - - /** - * Helper for all the <code>if*</code>-related methods, which - * checks types and picks one of the four variants, throwing if - * there's a problem. - * - * @param types non-null; the types - * @param intZ non-null; the int-to-0 comparison - * @param objZ null-ok; the object-to-null comparison - * @param intInt non-null; the int-to-int comparison - * @param objObj non-null; the object-to-object comparison - * @return non-null; the appropriate instance - */ - private static Rop pickIf(TypeList types, Rop intZ, Rop objZ, Rop intInt, - Rop objObj) { - switch(types.size()) { - case 1: { - switch (types.getType(0).getBasicFrameType()) { - case Type.BT_INT: { - return intZ; - } - case Type.BT_OBJECT: { - if (objZ != null) { - return objZ; - } - } - } - break; - } - case 2: { - int bt = types.getType(0).getBasicFrameType(); - if (bt == types.getType(1).getBasicFrameType()) { - switch (bt) { - case Type.BT_INT: { - return intInt; - } - case Type.BT_OBJECT: { - if (objObj != null) { - return objObj; - } - } - } - } - break; - } - } - - return throwBadTypes(types); - } - - /** - * Returns the appropriate <code>add</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opAdd(TypeList types) { - return pickBinaryOp(types, ADD_CONST_INT, ADD_CONST_LONG, - ADD_CONST_FLOAT, ADD_CONST_DOUBLE, ADD_INT, - ADD_LONG, ADD_FLOAT, ADD_DOUBLE); - } - - /** - * Returns the appropriate <code>sub</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opSub(TypeList types) { - return pickBinaryOp(types, SUB_CONST_INT, SUB_CONST_LONG, - SUB_CONST_FLOAT, SUB_CONST_DOUBLE, SUB_INT, - SUB_LONG, SUB_FLOAT, SUB_DOUBLE); - } - - /** - * Returns the appropriate <code>mul</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opMul(TypeList types) { - return pickBinaryOp(types, MUL_CONST_INT, MUL_CONST_LONG, - MUL_CONST_FLOAT, MUL_CONST_DOUBLE, MUL_INT, - MUL_LONG, MUL_FLOAT, MUL_DOUBLE); - } - - /** - * Returns the appropriate <code>div</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opDiv(TypeList types) { - return pickBinaryOp(types, DIV_CONST_INT, DIV_CONST_LONG, - DIV_CONST_FLOAT, DIV_CONST_DOUBLE, DIV_INT, - DIV_LONG, DIV_FLOAT, DIV_DOUBLE); - } - - /** - * Returns the appropriate <code>rem</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opRem(TypeList types) { - return pickBinaryOp(types, REM_CONST_INT, REM_CONST_LONG, - REM_CONST_FLOAT, REM_CONST_DOUBLE, REM_INT, - REM_LONG, REM_FLOAT, REM_DOUBLE); - } - - /** - * Returns the appropriate <code>and</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opAnd(TypeList types) { - return pickBinaryOp(types, AND_CONST_INT, AND_CONST_LONG, null, null, - AND_INT, AND_LONG, null, null); - } - - /** - * Returns the appropriate <code>or</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opOr(TypeList types) { - return pickBinaryOp(types, OR_CONST_INT, OR_CONST_LONG, null, null, - OR_INT, OR_LONG, null, null); - } - - /** - * Returns the appropriate <code>xor</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opXor(TypeList types) { - return pickBinaryOp(types, XOR_CONST_INT, XOR_CONST_LONG, null, null, - XOR_INT, XOR_LONG, null, null); - } - - /** - * Returns the appropriate <code>shl</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opShl(TypeList types) { - return pickBinaryOp(types, SHL_CONST_INT, SHL_CONST_LONG, null, null, - SHL_INT, SHL_LONG, null, null); - } - - /** - * Returns the appropriate <code>shr</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opShr(TypeList types) { - return pickBinaryOp(types, SHR_CONST_INT, SHR_CONST_LONG, null, null, - SHR_INT, SHR_LONG, null, null); - } - - /** - * Returns the appropriate <code>ushr</code> rop for the given - * types. The result is a shared instance. - * - * @param types non-null; types of the sources - * @return non-null; an appropriate instance - */ - public static Rop opUshr(TypeList types) { - return pickBinaryOp(types, USHR_CONST_INT, USHR_CONST_LONG, null, null, - USHR_INT, USHR_LONG, null, null); - } - - /** - * Returns the appropriate binary arithmetic rop for the given type - * and arguments. The result is a shared instance. - * - * @param types non-null; sources of the operation - * @param int1 non-null; the int-to-constant rop - * @param long1 non-null; the long-to-constant rop - * @param float1 null-ok; the float-to-constant rop, if any - * @param double1 null-ok; the double-to-constant rop, if any - * @param int2 non-null; the int-to-int rop - * @param long2 non-null; the long-to-long or long-to-int rop - * @param float2 null-ok; the float-to-float rop, if any - * @param double2 null-ok; the double-to-double rop, if any - * @return non-null; an appropriate instance - */ - private static Rop pickBinaryOp(TypeList types, Rop int1, Rop long1, - Rop float1, Rop double1, Rop int2, - Rop long2, Rop float2, Rop double2) { - int bt1 = types.getType(0).getBasicFrameType(); - Rop result = null; - - switch (types.size()) { - case 1: { - switch(bt1) { - case Type.BT_INT: return int1; - case Type.BT_LONG: return long1; - case Type.BT_FLOAT: result = float1; break; - case Type.BT_DOUBLE: result = double1; break; - } - break; - } - case 2: { - switch(bt1) { - case Type.BT_INT: return int2; - case Type.BT_LONG: return long2; - case Type.BT_FLOAT: result = float2; break; - case Type.BT_DOUBLE: result = double2; break; - } - break; - } - } - - if (result == null) { - return throwBadTypes(types); - } - - return result; - } - - /** - * Returns the appropriate <code>neg</code> rop for the given type. The - * result is a shared instance. - * - * @param type non-null; type of value being operated on - * @return non-null; an appropriate instance - */ - public static Rop opNeg(TypeBearer type) { - switch (type.getBasicFrameType()) { - case Type.BT_INT: return NEG_INT; - case Type.BT_LONG: return NEG_LONG; - case Type.BT_FLOAT: return NEG_FLOAT; - case Type.BT_DOUBLE: return NEG_DOUBLE; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>not</code> rop for the given type. The - * result is a shared instance. - * - * @param type non-null; type of value being operated on - * @return non-null; an appropriate instance - */ - public static Rop opNot(TypeBearer type) { - switch (type.getBasicFrameType()) { - case Type.BT_INT: return NOT_INT; - case Type.BT_LONG: return NOT_LONG; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>cmpl</code> rop for the given type. The - * result is a shared instance. - * - * @param type non-null; type of value being compared - * @return non-null; an appropriate instance - */ - public static Rop opCmpl(TypeBearer type) { - switch (type.getBasicType()) { - case Type.BT_LONG: return CMPL_LONG; - case Type.BT_FLOAT: return CMPL_FLOAT; - case Type.BT_DOUBLE: return CMPL_DOUBLE; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>cmpg</code> rop for the given type. The - * result is a shared instance. - * - * @param type non-null; type of value being compared - * @return non-null; an appropriate instance - */ - public static Rop opCmpg(TypeBearer type) { - switch (type.getBasicType()) { - case Type.BT_FLOAT: return CMPG_FLOAT; - case Type.BT_DOUBLE: return CMPG_DOUBLE; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>conv</code> rop for the given types. The - * result is a shared instance. - * - * @param dest non-null; target value type - * @param source non-null; source value type - * @return non-null; an appropriate instance - */ - public static Rop opConv(TypeBearer dest, TypeBearer source) { - int dbt = dest.getBasicFrameType(); - switch (source.getBasicFrameType()) { - case Type.BT_INT: { - switch (dbt) { - case Type.BT_LONG: return CONV_I2L; - case Type.BT_FLOAT: return CONV_I2F; - case Type.BT_DOUBLE: return CONV_I2D; - } - } - case Type.BT_LONG: { - switch (dbt) { - case Type.BT_INT: return CONV_L2I; - case Type.BT_FLOAT: return CONV_L2F; - case Type.BT_DOUBLE: return CONV_L2D; - } - } - case Type.BT_FLOAT: { - switch (dbt) { - case Type.BT_INT: return CONV_F2I; - case Type.BT_LONG: return CONV_F2L; - case Type.BT_DOUBLE: return CONV_F2D; - } - } - case Type.BT_DOUBLE: { - switch (dbt) { - case Type.BT_INT: return CONV_D2I; - case Type.BT_LONG: return CONV_D2L; - case Type.BT_FLOAT: return CONV_D2F; - } - } - } - - return throwBadTypes(StdTypeList.make(dest.getType(), - source.getType())); - } - - /** - * Returns the appropriate <code>return</code> rop for the given type. The - * result is a shared instance. - * - * @param type non-null; type of value being returned - * @return non-null; an appropriate instance - */ - public static Rop opReturn(TypeBearer type) { - switch (type.getBasicFrameType()) { - case Type.BT_INT: return RETURN_INT; - case Type.BT_LONG: return RETURN_LONG; - case Type.BT_FLOAT: return RETURN_FLOAT; - case Type.BT_DOUBLE: return RETURN_DOUBLE; - case Type.BT_OBJECT: return RETURN_OBJECT; - case Type.BT_VOID: return RETURN_VOID; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>aget</code> rop for the given type. The - * result is a shared instance. - * - * @param type non-null; element type of array being accessed - * @return non-null; an appropriate instance - */ - public static Rop opAget(TypeBearer type) { - switch (type.getBasicType()) { - case Type.BT_INT: return AGET_INT; - case Type.BT_LONG: return AGET_LONG; - case Type.BT_FLOAT: return AGET_FLOAT; - case Type.BT_DOUBLE: return AGET_DOUBLE; - case Type.BT_OBJECT: return AGET_OBJECT; - case Type.BT_BOOLEAN: return AGET_BOOLEAN; - case Type.BT_BYTE: return AGET_BYTE; - case Type.BT_CHAR: return AGET_CHAR; - case Type.BT_SHORT: return AGET_SHORT; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>aput</code> rop for the given type. The - * result is a shared instance. - * - * @param type non-null; element type of array being accessed - * @return non-null; an appropriate instance - */ - public static Rop opAput(TypeBearer type) { - switch (type.getBasicType()) { - case Type.BT_INT: return APUT_INT; - case Type.BT_LONG: return APUT_LONG; - case Type.BT_FLOAT: return APUT_FLOAT; - case Type.BT_DOUBLE: return APUT_DOUBLE; - case Type.BT_OBJECT: return APUT_OBJECT; - case Type.BT_BOOLEAN: return APUT_BOOLEAN; - case Type.BT_BYTE: return APUT_BYTE; - case Type.BT_CHAR: return APUT_CHAR; - case Type.BT_SHORT: return APUT_SHORT; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>new-array</code> rop for the given - * type. The result is a shared instance. - * - * @param arrayType non-null; array type of array being created - * @return non-null; an appropriate instance - */ - public static Rop opNewArray(TypeBearer arrayType) { - Type type = arrayType.getType(); - Type elementType = type.getComponentType(); - - switch (elementType.getBasicType()) { - case Type.BT_INT: return NEW_ARRAY_INT; - case Type.BT_LONG: return NEW_ARRAY_LONG; - case Type.BT_FLOAT: return NEW_ARRAY_FLOAT; - case Type.BT_DOUBLE: return NEW_ARRAY_DOUBLE; - case Type.BT_BOOLEAN: return NEW_ARRAY_BOOLEAN; - case Type.BT_BYTE: return NEW_ARRAY_BYTE; - case Type.BT_CHAR: return NEW_ARRAY_CHAR; - case Type.BT_SHORT: return NEW_ARRAY_SHORT; - case Type.BT_OBJECT: { - return new Rop(RegOps.NEW_ARRAY, type, StdTypeList.INT, - Exceptions.LIST_Error_NegativeArraySizeException, - "new-array-object"); - } - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>filled-new-array</code> rop for the given - * type. The result may be a shared instance. - * - * @param arrayType non-null; type of array being created - * @param count >= 0; number of elements that the array should have - * @return non-null; an appropriate instance - */ - public static Rop opFilledNewArray(TypeBearer arrayType, int count) { - Type type = arrayType.getType(); - Type elementType = type.getComponentType(); - - if (elementType.isCategory2()) { - return throwBadType(arrayType); - } - - if (count < 0) { - throw new IllegalArgumentException("count < 0"); - } - - StdTypeList sourceTypes = new StdTypeList(count); - - for (int i = 0; i < count; i++) { - sourceTypes.set(i, elementType); - } - - // Note: The resulting rop is considered call-like. - return new Rop(RegOps.FILLED_NEW_ARRAY, - sourceTypes, - Exceptions.LIST_Error); - } - - /** - * Returns the appropriate <code>get-field</code> rop for the given - * type. The result is a shared instance. - * - * @param type non-null; type of the field in question - * @return non-null; an appropriate instance - */ - public static Rop opGetField(TypeBearer type) { - switch (type.getBasicType()) { - case Type.BT_INT: return GET_FIELD_INT; - case Type.BT_LONG: return GET_FIELD_LONG; - case Type.BT_FLOAT: return GET_FIELD_FLOAT; - case Type.BT_DOUBLE: return GET_FIELD_DOUBLE; - case Type.BT_OBJECT: return GET_FIELD_OBJECT; - case Type.BT_BOOLEAN: return GET_FIELD_BOOLEAN; - case Type.BT_BYTE: return GET_FIELD_BYTE; - case Type.BT_CHAR: return GET_FIELD_CHAR; - case Type.BT_SHORT: return GET_FIELD_SHORT; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>put-field</code> rop for the given - * type. The result is a shared instance. - * - * @param type non-null; type of the field in question - * @return non-null; an appropriate instance - */ - public static Rop opPutField(TypeBearer type) { - switch (type.getBasicType()) { - case Type.BT_INT: return PUT_FIELD_INT; - case Type.BT_LONG: return PUT_FIELD_LONG; - case Type.BT_FLOAT: return PUT_FIELD_FLOAT; - case Type.BT_DOUBLE: return PUT_FIELD_DOUBLE; - case Type.BT_OBJECT: return PUT_FIELD_OBJECT; - case Type.BT_BOOLEAN: return PUT_FIELD_BOOLEAN; - case Type.BT_BYTE: return PUT_FIELD_BYTE; - case Type.BT_CHAR: return PUT_FIELD_CHAR; - case Type.BT_SHORT: return PUT_FIELD_SHORT; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>get-static</code> rop for the given - * type. The result is a shared instance. - * - * @param type non-null; type of the field in question - * @return non-null; an appropriate instance - */ - public static Rop opGetStatic(TypeBearer type) { - switch (type.getBasicType()) { - case Type.BT_INT: return GET_STATIC_INT; - case Type.BT_LONG: return GET_STATIC_LONG; - case Type.BT_FLOAT: return GET_STATIC_FLOAT; - case Type.BT_DOUBLE: return GET_STATIC_DOUBLE; - case Type.BT_OBJECT: return GET_STATIC_OBJECT; - case Type.BT_BOOLEAN: return GET_STATIC_BOOLEAN; - case Type.BT_BYTE: return GET_STATIC_BYTE; - case Type.BT_CHAR: return GET_STATIC_CHAR; - case Type.BT_SHORT: return GET_STATIC_SHORT; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>put-static</code> rop for the given - * type. The result is a shared instance. - * - * @param type non-null; type of the field in question - * @return non-null; an appropriate instance - */ - public static Rop opPutStatic(TypeBearer type) { - switch (type.getBasicType()) { - case Type.BT_INT: return PUT_STATIC_INT; - case Type.BT_LONG: return PUT_STATIC_LONG; - case Type.BT_FLOAT: return PUT_STATIC_FLOAT; - case Type.BT_DOUBLE: return PUT_STATIC_DOUBLE; - case Type.BT_OBJECT: return PUT_STATIC_OBJECT; - case Type.BT_BOOLEAN: return PUT_STATIC_BOOLEAN; - case Type.BT_BYTE: return PUT_STATIC_BYTE; - case Type.BT_CHAR: return PUT_STATIC_CHAR; - case Type.BT_SHORT: return PUT_STATIC_SHORT; - } - - return throwBadType(type); - } - - /** - * Returns the appropriate <code>invoke-static</code> rop for the - * given type. The result is typically a newly-allocated instance. - * - * @param meth non-null; descriptor of the method - * @return non-null; an appropriate instance - */ - public static Rop opInvokeStatic(Prototype meth) { - return new Rop(RegOps.INVOKE_STATIC, - meth.getParameterFrameTypes(), - StdTypeList.THROWABLE); - } - - /** - * Returns the appropriate <code>invoke-virtual</code> rop for the - * given type. The result is typically a newly-allocated instance. - * - * @param meth non-null; descriptor of the method, including the - * <code>this</code> parameter - * @return non-null; an appropriate instance - */ - public static Rop opInvokeVirtual(Prototype meth) { - return new Rop(RegOps.INVOKE_VIRTUAL, - meth.getParameterFrameTypes(), - StdTypeList.THROWABLE); - } - - /** - * Returns the appropriate <code>invoke-super</code> rop for the - * given type. The result is typically a newly-allocated instance. - * - * @param meth non-null; descriptor of the method, including the - * <code>this</code> parameter - * @return non-null; an appropriate instance - */ - public static Rop opInvokeSuper(Prototype meth) { - return new Rop(RegOps.INVOKE_SUPER, - meth.getParameterFrameTypes(), - StdTypeList.THROWABLE); - } - - /** - * Returns the appropriate <code>invoke-direct</code> rop for the - * given type. The result is typically a newly-allocated instance. - * - * @param meth non-null; descriptor of the method, including the - * <code>this</code> parameter - * @return non-null; an appropriate instance - */ - public static Rop opInvokeDirect(Prototype meth) { - return new Rop(RegOps.INVOKE_DIRECT, - meth.getParameterFrameTypes(), - StdTypeList.THROWABLE); - } - - /** - * Returns the appropriate <code>invoke-interface</code> rop for the - * given type. The result is typically a newly-allocated instance. - * - * @param meth non-null; descriptor of the method, including the - * <code>this</code> parameter - * @return non-null; an appropriate instance - */ - public static Rop opInvokeInterface(Prototype meth) { - return new Rop(RegOps.INVOKE_INTERFACE, - meth.getParameterFrameTypes(), - StdTypeList.THROWABLE); - } - - /** - * Returns the appropriate <code>mark-local</code> rop for the given type. - * The result is a shared instance. - * - * @param type non-null; type of value being marked - * @return non-null; an appropriate instance - */ - public static Rop opMarkLocal(TypeBearer type) { - switch (type.getBasicFrameType()) { - case Type.BT_INT: return MARK_LOCAL_INT; - case Type.BT_LONG: return MARK_LOCAL_LONG; - case Type.BT_FLOAT: return MARK_LOCAL_FLOAT; - case Type.BT_DOUBLE: return MARK_LOCAL_DOUBLE; - case Type.BT_OBJECT: return MARK_LOCAL_OBJECT; - } - - return throwBadType(type); - } - - /** - * This class is uninstantiable. - */ - private Rops() { - // This space intentionally left blank. - } - - /** - * Throws the right exception to complain about a bogus type. - * - * @param type non-null; the bad type - * @return never - */ - private static Rop throwBadType(TypeBearer type) { - throw new IllegalArgumentException("bad type: " + type); - } - - /** - * Throws the right exception to complain about a bogus list of types. - * - * @param types non-null; the bad types - * @return never - */ - private static Rop throwBadTypes(TypeList types) { - throw new IllegalArgumentException("bad types: " + types); - } -} diff --git a/dx/src/com/android/dx/rop/code/SourcePosition.java b/dx/src/com/android/dx/rop/code/SourcePosition.java deleted file mode 100644 index da66c7de2..000000000 --- a/dx/src/com/android/dx/rop/code/SourcePosition.java +++ /dev/null @@ -1,168 +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.android.dx.rop.code; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.Hex; - -/** - * Information about a source position for code, which includes both a - * line number and original bytecode address. - */ -public final class SourcePosition { - /** non-null; convenient "no information known" instance */ - public static final SourcePosition NO_INFO = - new SourcePosition(null, -1, -1); - - /** null-ok; name of the file of origin or <code>null</code> if unknown */ - private final CstUtf8 sourceFile; - - /** - * >= -1; the bytecode address, or <code>-1</code> if that - * information is unknown - */ - private final int address; - - /** - * >= -1; the line number, or <code>-1</code> if that - * information is unknown - */ - private final int line; - - /** - * Constructs an instance. - * - * @param sourceFile null-ok; name of the file of origin or - * <code>null</code> if unknown - * @param address >= -1; original bytecode address or <code>-1</code> - * if unknown - * @param line >= -1; original line number or <code>-1</code> if - * unknown - */ - public SourcePosition(CstUtf8 sourceFile, int address, int line) { - if (address < -1) { - throw new IllegalArgumentException("address < -1"); - } - - if (line < -1) { - throw new IllegalArgumentException("line < -1"); - } - - this.sourceFile = sourceFile; - this.address = address; - this.line = line; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(50); - - if (sourceFile != null) { - sb.append(sourceFile.toHuman()); - sb.append(":"); - } - - if (line >= 0) { - sb.append(line); - } - - sb.append('@'); - - if (address < 0) { - sb.append("????"); - } else { - sb.append(Hex.u2(address)); - } - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof SourcePosition)) { - return false; - } - - if (this == other) { - return true; - } - - SourcePosition pos = (SourcePosition) other; - - return (address == pos.address) && sameLineAndFile(pos); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return sourceFile.hashCode() + address + line; - } - - /** - * Returns whether the lines match between this instance and - * the one given. - * - * @param other non-null; the instance to compare to - * @return <code>true</code> iff the lines match - */ - public boolean sameLine(SourcePosition other) { - return (line == other.line); - } - - /** - * Returns whether the lines and files match between this instance and - * the one given. - * - * @param other non-null; the instance to compare to - * @return <code>true</code> iff the lines and files match - */ - public boolean sameLineAndFile(SourcePosition other) { - return (line == other.line) && - ((sourceFile == other.sourceFile) || - ((sourceFile != null) && sourceFile.equals(other.sourceFile))); - } - - /** - * Gets the source file, if known. - * - * @return null-ok; the source file or <code>null</code> if unknown - */ - public CstUtf8 getSourceFile() { - return sourceFile; - } - - /** - * Gets the original bytecode address. - * - * @return >= -1; the address or <code>-1</code> if unknown - */ - public int getAddress() { - return address; - } - - /** - * Gets the original line number. - * - * @return >= -1; the original line number or <code>-1</code> if - * unknown - */ - public int getLine() { - return line; - } -} diff --git a/dx/src/com/android/dx/rop/code/SwitchInsn.java b/dx/src/com/android/dx/rop/code/SwitchInsn.java deleted file mode 100644 index fdf1a468f..000000000 --- a/dx/src/com/android/dx/rop/code/SwitchInsn.java +++ /dev/null @@ -1,119 +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.android.dx.rop.code; - -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.IntList; - -/** - * Instruction which contains switch cases. - */ -public final class SwitchInsn - extends Insn { - /** non-null; list of switch cases */ - private final IntList cases; - - /** - * Constructs an instance. - * - * @param opcode non-null; the opcode - * @param position non-null; source position - * @param result null-ok; spec for the result, if any - * @param sources non-null; specs for all the sources - * @param cases non-null; list of switch cases - */ - public SwitchInsn(Rop opcode, SourcePosition position, RegisterSpec result, - RegisterSpecList sources, IntList cases) { - super(opcode, position, result, sources); - - if (opcode.getBranchingness() != Rop.BRANCH_SWITCH) { - throw new IllegalArgumentException("bogus branchingness"); - } - - if (cases == null) { - throw new NullPointerException("cases == null"); - } - - this.cases = cases; - } - - /** {@inheritDoc} */ - @Override - public String getInlineString() { - return cases.toString(); - } - - /** {@inheritDoc} */ - @Override - public TypeList getCatches() { - return StdTypeList.EMPTY; - } - - /** {@inheritDoc} */ - @Override - public void accept(Visitor visitor) { - visitor.visitSwitchInsn(this); - } - - /** {@inheritDoc} */ - @Override - public Insn withAddedCatch(Type type) { - throw new UnsupportedOperationException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - public Insn withRegisterOffset(int delta) { - return new SwitchInsn(getOpcode(), getPosition(), - getResult().withOffset(delta), - getSources().withOffset(delta), - cases); - } - - /** - * {@inheritDoc} - * - * <p> SwitchInsn always compares false. The current use for this method - * never encounters <code>SwitchInsn</code>s - */ - @Override - public boolean contentEquals(Insn b) { - return false; - } - - /** {@inheritDoc} */ - @Override - public Insn withNewRegisters(RegisterSpec result, - RegisterSpecList sources) { - - return new SwitchInsn(getOpcode(), getPosition(), - result, - sources, - cases); - } - - /** - * Gets the list of switch cases. - * - * @return non-null; the case list - */ - public IntList getCases() { - return cases; - } -} diff --git a/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java b/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java deleted file mode 100644 index 49ebc91a5..000000000 --- a/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java +++ /dev/null @@ -1,105 +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.android.dx.rop.code; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; - -/** - * Instruction which contains an explicit reference to a constant - * and which might throw an exception. - */ -public final class ThrowingCstInsn - extends CstInsn { - /** non-null; list of exceptions caught */ - private final TypeList catches; - - /** - * Constructs an instance. - * - * @param opcode non-null; the opcode - * @param position non-null; source position - * @param sources non-null; specs for all the sources - * @param catches non-null; list of exceptions caught - * @param cst non-null; the constant - */ - public ThrowingCstInsn(Rop opcode, SourcePosition position, - RegisterSpecList sources, - TypeList catches, Constant cst) { - super(opcode, position, null, sources, cst); - - if (opcode.getBranchingness() != Rop.BRANCH_THROW) { - throw new IllegalArgumentException("bogus branchingness"); - } - - if (catches == null) { - throw new NullPointerException("catches == null"); - } - - this.catches = catches; - } - - /** {@inheritDoc} */ - @Override - public String getInlineString() { - return getConstant().toHuman() + " " + - ThrowingInsn.toCatchString(catches); - } - - /** {@inheritDoc} */ - @Override - public TypeList getCatches() { - return catches; - } - - /** {@inheritDoc} */ - @Override - public void accept(Visitor visitor) { - visitor.visitThrowingCstInsn(this); - } - - /** {@inheritDoc} */ - @Override - public Insn withAddedCatch(Type type) { - return new ThrowingCstInsn(getOpcode(), getPosition(), - getSources(), catches.withAddedType(type), - getConstant()); - } - - /** {@inheritDoc} */ - @Override - public Insn withRegisterOffset(int delta) { - return new ThrowingCstInsn(getOpcode(), getPosition(), - getSources().withOffset(delta), - catches, - getConstant()); - } - - /** {@inheritDoc} */ - @Override - public Insn withNewRegisters(RegisterSpec result, - RegisterSpecList sources) { - - return new ThrowingCstInsn(getOpcode(), getPosition(), - sources, - catches, - getConstant()); - } - - -} diff --git a/dx/src/com/android/dx/rop/code/ThrowingInsn.java b/dx/src/com/android/dx/rop/code/ThrowingInsn.java deleted file mode 100644 index 24a5bed9b..000000000 --- a/dx/src/com/android/dx/rop/code/ThrowingInsn.java +++ /dev/null @@ -1,120 +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.android.dx.rop.code; - -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; - -/** - * Instruction which possibly throws. The <code>successors</code> list in the - * basic block an instance of this class is inside corresponds in-order to - * the list of exceptions handled by this instruction, with the - * no-exception case appended as the final target. - */ -public final class ThrowingInsn - extends Insn { - /** non-null; list of exceptions caught */ - private final TypeList catches; - - /** - * Gets the string form of a register spec list to be used as a catches - * list. - * - * @param catches non-null; the catches list - * @return non-null; the string form - */ - public static String toCatchString(TypeList catches) { - StringBuffer sb = new StringBuffer(100); - - sb.append("catch"); - - int sz = catches.size(); - for (int i = 0; i < sz; i++) { - sb.append(" "); - sb.append(catches.getType(i).toHuman()); - } - - return sb.toString(); - } - - /** - * Constructs an instance. - * - * @param opcode non-null; the opcode - * @param position non-null; source position - * @param sources non-null; specs for all the sources - * @param catches non-null; list of exceptions caught - */ - public ThrowingInsn(Rop opcode, SourcePosition position, - RegisterSpecList sources, - TypeList catches) { - super(opcode, position, null, sources); - - if (opcode.getBranchingness() != Rop.BRANCH_THROW) { - throw new IllegalArgumentException("bogus branchingness"); - } - - if (catches == null) { - throw new NullPointerException("catches == null"); - } - - this.catches = catches; - } - - /** {@inheritDoc} */ - @Override - public String getInlineString() { - return toCatchString(catches); - } - - /** {@inheritDoc} */ - @Override - public TypeList getCatches() { - return catches; - } - - /** {@inheritDoc} */ - @Override - public void accept(Visitor visitor) { - visitor.visitThrowingInsn(this); - } - - /** {@inheritDoc} */ - @Override - public Insn withAddedCatch(Type type) { - return new ThrowingInsn(getOpcode(), getPosition(), - getSources(), catches.withAddedType(type)); - } - - /** {@inheritDoc} */ - @Override - public Insn withRegisterOffset(int delta) { - return new ThrowingInsn(getOpcode(), getPosition(), - getSources().withOffset(delta), - catches); - } - - /** {@inheritDoc} */ - @Override - public Insn withNewRegisters(RegisterSpec result, - RegisterSpecList sources) { - - return new ThrowingInsn(getOpcode(), getPosition(), - sources, - catches); - } -} diff --git a/dx/src/com/android/dx/rop/code/TranslationAdvice.java b/dx/src/com/android/dx/rop/code/TranslationAdvice.java deleted file mode 100644 index 8c2cde984..000000000 --- a/dx/src/com/android/dx/rop/code/TranslationAdvice.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.android.dx.rop.code; - -/** - * Interface for "advice" passed from the late stage of translation back - * to the early stage. This allows for the final target architecture to - * exert its influence early in the translation process without having - * the early stage code be explicitly tied to the target. - */ -public interface TranslationAdvice { - /** - * Returns an indication of whether the target can directly represent an - * instruction with the given opcode operating on the given arguments, - * where the last source argument is used as a constant. (That is, the - * last argument must have a type which indicates it is a known constant.) - * The instruction associated must have exactly two sources. - * - * @param opcode non-null; the opcode - * @param sourceA non-null; the first source - * @param sourceB non-null; the second source - * @return <code>true</code> iff the target can represent the operation - * using a constant for the last argument - */ - public boolean hasConstantOperation(Rop opcode, - RegisterSpec sourceA, RegisterSpec sourceB); - - /** - * Returns true if the translation target requires the sources of the - * specified opcode to be in order and contiguous (eg, for an invoke-range) - * - * @param opcode non-null; opcode - * @param sources non-null; source list - * @return <code>true</code> iff the target requires the sources to be - * in order and contiguous. - */ - public boolean requiresSourcesInOrder(Rop opcode, RegisterSpecList sources); - - /** - * Gets the maximum register width that can be represented optimally. - * For example, Dex bytecode does not have instruction forms that take - * register numbers larger than 15 for all instructions so - * DexTranslationAdvice returns 15 here. - * - * @return register count noted above - */ - public int getMaxOptimalRegisterCount(); -} diff --git a/dx/src/com/android/dx/rop/code/package.html b/dx/src/com/android/dx/rop/code/package.html deleted file mode 100644 index 86566b497..000000000 --- a/dx/src/com/android/dx/rop/code/package.html +++ /dev/null @@ -1,8 +0,0 @@ -<body> -<p>Classes relating to a register-based opcode system.</p> - -<p><b>PACKAGES USED:</b> -<ul> -<li><code>com.android.dx.util</code></li> -</ul> -</body> diff --git a/dx/src/com/android/dx/rop/cst/Constant.java b/dx/src/com/android/dx/rop/cst/Constant.java deleted file mode 100644 index 0f440103c..000000000 --- a/dx/src/com/android/dx/rop/cst/Constant.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.android.dx.rop.cst; - -import com.android.dx.util.ToHuman; - -/** - * Base class for constants of all sorts. - */ -public abstract class Constant - implements ToHuman, Comparable<Constant> { - /** - * Returns <code>true</code> if this instance is a category-2 constant, - * meaning it takes up two slots in the constant pool, or - * <code>false</code> if this instance is category-1. - * - * @return <code>true</code> iff this instance is category-2 - */ - public abstract boolean isCategory2(); - - /** - * Returns the human name for the particular type of constant - * this instance is. - * - * @return non-null; the name - */ - public abstract String typeName(); - - /** - * {@inheritDoc} - * - * This compares in class-major and value-minor order. - */ - public final int compareTo(Constant other) { - Class clazz = getClass(); - Class otherClazz = other.getClass(); - - if (clazz != otherClazz) { - return clazz.getName().compareTo(otherClazz.getName()); - } - - return compareTo0(other); - } - - /** - * Compare the values of this and another instance, which are guaranteed - * to be of the same class. Subclasses must implement this. - * - * @param other non-null; the instance to compare to - * @return <code>-1</code>, <code>0</code>, or <code>1</code>, as usual - * for a comparison - */ - protected abstract int compareTo0(Constant other); -} diff --git a/dx/src/com/android/dx/rop/cst/ConstantPool.java b/dx/src/com/android/dx/rop/cst/ConstantPool.java deleted file mode 100644 index 9a64a2aab..000000000 --- a/dx/src/com/android/dx/rop/cst/ConstantPool.java +++ /dev/null @@ -1,70 +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.android.dx.rop.cst; - -/** - * Interface for constant pools, which are, more or less, just lists of - * {@link Constant} objects. - */ -public interface ConstantPool { - /** - * Get the "size" of the constant pool. This corresponds to the - * class file field <code>constant_pool_count</code>, and is in fact - * always at least one more than the actual size of the constant pool, - * as element <code>0</code> is always invalid. - * - * @return <code>>= 1</code>; the size - */ - public int size(); - - /** - * Get the <code>n</code>th entry in the constant pool, which must - * be valid. - * - * @param n <code>n >= 0, n < size()</code>; the constant pool index - * @return non-null; the corresponding entry - * @throws IllegalArgumentException thrown if <code>n</code> is - * in-range but invalid - */ - public Constant get(int n); - - /** - * Get the <code>n</code>th entry in the constant pool, which must - * be valid unless <code>n == 0</code>, in which case <code>null</code> - * is returned. - * - * @param n <code>n >= 0, n < size()</code>; the constant pool index - * @return null-ok; the corresponding entry, if <code>n != 0</code> - * @throws IllegalArgumentException thrown if <code>n</code> is - * in-range and non-zero but invalid - */ - public Constant get0Ok(int n); - - /** - * Get the <code>n</code>th entry in the constant pool, or - * <code>null</code> if the index is in-range but invalid. In - * particular, <code>null</code> is returned for index <code>0</code> - * as well as the index after any entry which is defined to take up - * two slots (that is, <code>Long</code> and <code>Double</code> - * entries). - * - * @param n <code>n >= 0, n < size()</code>; the constant pool index - * @return null-ok; the corresponding entry, or <code>null</code> if - * the index is in-range but invalid - */ - public Constant getOrNull(int n); -} diff --git a/dx/src/com/android/dx/rop/cst/CstAnnotation.java b/dx/src/com/android/dx/rop/cst/CstAnnotation.java deleted file mode 100644 index d6dc1f255..000000000 --- a/dx/src/com/android/dx/rop/cst/CstAnnotation.java +++ /dev/null @@ -1,96 +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.android.dx.rop.cst; - -import com.android.dx.rop.annotation.Annotation; - -/** - * Constant type that represents an annotation. - */ -public final class CstAnnotation extends Constant { - /** non-null; the actual annotation */ - private final Annotation annotation; - - /** - * Constructs an instance. - * - * @param annotation non-null; the annotation to hold - */ - public CstAnnotation(Annotation annotation) { - if (annotation == null) { - throw new NullPointerException("annotation == null"); - } - - annotation.throwIfMutable(); - - this.annotation = annotation; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (! (other instanceof CstAnnotation)) { - return false; - } - - return annotation.equals(((CstAnnotation) other).annotation); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return annotation.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(Constant other) { - return annotation.compareTo(((CstAnnotation) other).annotation); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return annotation.toString(); - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "annotation"; - } - - /** {@inheritDoc} */ - @Override - public boolean isCategory2() { - return false; - } - - /** {@inheritDoc} */ - public String toHuman() { - return annotation.toString(); - } - - /** - * Get the underlying annotation. - * - * @return non-null; the annotation - */ - public Annotation getAnnotation() { - return annotation; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstArray.java b/dx/src/com/android/dx/rop/cst/CstArray.java deleted file mode 100644 index 69c0aeffa..000000000 --- a/dx/src/com/android/dx/rop/cst/CstArray.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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; -import com.android.dx.util.FixedSizeList; - -/** - * Constant type to represent a fixed array of other constants. The contents - * may be of any type <i>other</i> than {@link CstUtf8}. - */ -public final class CstArray extends Constant { - /** non-null; the actual list of contents */ - private final List list; - - /** - * Constructs an instance. - * - * @param list non-null; the actual list of contents - */ - public CstArray(List list) { - if (list == null) { - throw new NullPointerException("list == null"); - } - - list.throwIfMutable(); - - this.list = list; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (! (other instanceof CstArray)) { - return false; - } - - return list.equals(((CstArray) other).list); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return list.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(Constant other) { - return list.compareTo(((CstArray) other).list); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return list.toString("array{", ", ", "}"); - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "array"; - } - - /** {@inheritDoc} */ - @Override - public boolean isCategory2() { - return false; - } - - /** {@inheritDoc} */ - public String toHuman() { - return list.toHuman("{", ", ", "}"); - } - - /** - * Get the underlying list. - * - * @return non-null; the list - */ - public List getList() { - return list; - } - - /** - * List of {@link Constant} instances. - */ - public static final class List - extends FixedSizeList implements Comparable<List> { - /** - * Constructs an instance. All indices initially contain - * <code>null</code>. - * - * @param size the size of the list - */ - public List(int size) { - super(size); - } - - /** {@inheritDoc} */ - public int compareTo(List other) { - int thisSize = size(); - int otherSize = other.size(); - int compareSize = (thisSize < otherSize) ? thisSize : otherSize; - - for (int i = 0; i < compareSize; i++) { - Constant thisItem = (Constant) get0(i); - Constant otherItem = (Constant) other.get0(i); - int compare = thisItem.compareTo(otherItem); - if (compare != 0) { - return compare; - } - } - - if (thisSize < otherSize) { - return -1; - } else if (thisSize > otherSize) { - return 1; - } - - return 0; - } - - /** - * Gets the element at the given index. 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</code>. - * - * @param n >= 0, < size(); which index - * @return non-null; element at that index - */ - public Constant get(int n) { - return (Constant) get0(n); - } - - /** - * Sets the element at the given index. - * - * @param n >= 0, < size(); which index - * @param a null-ok; the element to set at <code>n</code> - */ - public void set(int n, Constant a) { - if (a instanceof CstUtf8) { - throw new IllegalArgumentException("bad value: " + a); - } - - set0(n, a); - } - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java b/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java deleted file mode 100644 index c8856019d..000000000 --- a/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java +++ /dev/null @@ -1,151 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; - -/** - * Base class for constants of "methodish" type. - * - * <p><b>Note:</b> As a {@link TypeBearer}, this class bears the return type - * of the method.</p> - */ -public abstract class CstBaseMethodRef - extends CstMemberRef { - /** non-null; the raw prototype for this method */ - private final Prototype prototype; - - /** - * null-ok; the prototype for this method taken to be an instance - * method, or <code>null</code> if not yet calculated - */ - private Prototype instancePrototype; - - /** - * Constructs an instance. - * - * @param definingClass non-null; the type of the defining class - * @param nat non-null; the name-and-type - */ - /*package*/ CstBaseMethodRef(CstType definingClass, CstNat nat) { - super(definingClass, nat); - - String descriptor = getNat().getDescriptor().getString(); - this.prototype = Prototype.intern(descriptor); - this.instancePrototype = null; - } - - /** - * Gets the raw prototype of this method. This doesn't include a - * <code>this</code> argument. - * - * @return non-null; the method prototype - */ - public final Prototype getPrototype() { - return prototype; - } - - /** - * Gets the prototype of this method as either a - * <code>static</code> or instance method. In the case of a - * <code>static</code> method, this is the same as the raw - * prototype. In the case of an instance method, this has an - * appropriately-typed <code>this</code> argument as the first - * one. - * - * @param isStatic whether the method should be considered static - * @return non-null; the method prototype - */ - public final Prototype getPrototype(boolean isStatic) { - if (isStatic) { - return prototype; - } else { - if (instancePrototype == null) { - Type thisType = getDefiningClass().getClassType(); - instancePrototype = prototype.withFirstParameter(thisType); - } - return instancePrototype; - } - } - - /** {@inheritDoc} */ - @Override - protected final int compareTo0(Constant other) { - int cmp = super.compareTo0(other); - - if (cmp != 0) { - return cmp; - } - - CstBaseMethodRef otherMethod = (CstBaseMethodRef) other; - return prototype.compareTo(otherMethod.prototype); - } - - /** - * {@inheritDoc} - * - * In this case, this method returns the <i>return type</i> of this method. - * - * @return non-null; the method's return type - */ - public final Type getType() { - return prototype.getReturnType(); - } - - /** - * Gets the number of words of parameters required by this - * method's descriptor. Since instances of this class have no way - * to know if they will be used in a <code>static</code> or - * instance context, one has to indicate this explicitly as an - * argument. This method is just a convenient shorthand for - * <code>getPrototype().getParameterTypes().getWordCount()</code>, - * plus <code>1</code> if the method is to be treated as an - * instance method. - * - * @param isStatic whether the method should be considered static - * @return >= 0; the argument word count - */ - public final int getParameterWordCount(boolean isStatic) { - return getPrototype(isStatic).getParameterTypes().getWordCount(); - } - - /** - * Gets whether this is a reference to an instance initialization - * method. This is just a convenient shorthand for - * <code>getNat().isInstanceInit()</code>. - * - * @return <code>true</code> iff this is a reference to an - * instance initialization method - */ - public final boolean isInstanceInit() { - return getNat().isInstanceInit(); - } - - /** - * Gets whether this is a reference to a class initialization - * method. This is just a convenient shorthand for - * <code>getNat().isClassInit()</code>. - * - * @return <code>true</code> iff this is a reference to an - * instance initialization method - */ - public final boolean isClassInit() { - return getNat().isClassInit(); - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstBoolean.java b/dx/src/com/android/dx/rop/cst/CstBoolean.java deleted file mode 100644 index ab25d5bcf..000000000 --- a/dx/src/com/android/dx/rop/cst/CstBoolean.java +++ /dev/null @@ -1,99 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; - -/** - * Constants of type <code>boolean</code>. - */ -public final class CstBoolean - extends CstLiteral32 { - /** non-null; instance representing <code>false</code> */ - public static final CstBoolean VALUE_FALSE = new CstBoolean(false); - - /** non-null; instance representing <code>true</code> */ - public static final CstBoolean VALUE_TRUE = new CstBoolean(true); - - /** - * Makes an instance for the given value. This will return an - * already-allocated instance. - * - * @param value the <code>boolean</code> value - * @return non-null; the appropriate instance - */ - public static CstBoolean make(boolean value) { - return value ? VALUE_TRUE : VALUE_FALSE; - } - - /** - * Makes an instance for the given <code>int</code> value. This - * will return an already-allocated instance. - * - * @param value must be either <code>0</code> or <code>1</code> - * @return non-null; the appropriate instance - */ - public static CstBoolean make(int value) { - if (value == 0) { - return VALUE_FALSE; - } else if (value == 1) { - return VALUE_TRUE; - } else { - throw new IllegalArgumentException("bogus value: " + value); - } - } - - /** - * Constructs an instance. This constructor is private; use {@link #make}. - * - * @param value the <code>boolean</code> value - */ - private CstBoolean(boolean value) { - super(value ? 1 : 0); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return getValue() ? "boolean{true}" : "boolean{false}"; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.BOOLEAN; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "boolean"; - } - - /** {@inheritDoc} */ - public String toHuman() { - return getValue() ? "true" : "false"; - } - - /** - * Gets the <code>boolean</code> value. - * - * @return the value - */ - public boolean getValue() { - return (getIntBits() == 0) ? false : true; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstByte.java b/dx/src/com/android/dx/rop/cst/CstByte.java deleted file mode 100644 index ffc3206b6..000000000 --- a/dx/src/com/android/dx/rop/cst/CstByte.java +++ /dev/null @@ -1,99 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; -import com.android.dx.util.Hex; - -/** - * Constants of type <code>byte</code>. - */ -public final class CstByte - extends CstLiteral32 { - /** non-null; the value <code>0</code> as an instance of this class */ - public static final CstByte VALUE_0 = make((byte) 0); - - /** - * Makes an instance for the given value. This may (but does not - * necessarily) return an already-allocated instance. - * - * @param value the <code>byte</code> value - */ - public static CstByte make(byte value) { - return new CstByte(value); - } - - /** - * Makes an instance for the given <code>int</code> value. This - * may (but does not necessarily) return an already-allocated - * instance. - * - * @param value the value, which must be in range for a <code>byte</code> - * @return non-null; the appropriate instance - */ - public static CstByte make(int value) { - byte cast = (byte) value; - - if (cast != value) { - throw new IllegalArgumentException("bogus byte value: " + - value); - } - - return make(cast); - } - - /** - * Constructs an instance. This constructor is private; use {@link #make}. - * - * @param value the <code>byte</code> value - */ - private CstByte(byte value) { - super(value); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - int value = getIntBits(); - return "byte{0x" + Hex.u1(value) + " / " + value + '}'; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.BYTE; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "byte"; - } - - /** {@inheritDoc} */ - public String toHuman() { - return Integer.toString(getIntBits()); - } - - /** - * Gets the <code>byte</code> value. - * - * @return the value - */ - public byte getValue() { - return (byte) getIntBits(); - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstChar.java b/dx/src/com/android/dx/rop/cst/CstChar.java deleted file mode 100644 index a31bd7fc0..000000000 --- a/dx/src/com/android/dx/rop/cst/CstChar.java +++ /dev/null @@ -1,99 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; -import com.android.dx.util.Hex; - -/** - * Constants of type <code>char</code>. - */ -public final class CstChar - extends CstLiteral32 { - /** non-null; the value <code>0</code> as an instance of this class */ - public static final CstChar VALUE_0 = make((char) 0); - - /** - * Makes an instance for the given value. This may (but does not - * necessarily) return an already-allocated instance. - * - * @param value the <code>char</code> value - */ - public static CstChar make(char value) { - return new CstChar(value); - } - - /** - * Makes an instance for the given <code>int</code> value. This - * may (but does not necessarily) return an already-allocated - * instance. - * - * @param value the value, which must be in range for a <code>char</code> - * @return non-null; the appropriate instance - */ - public static CstChar make(int value) { - char cast = (char) value; - - if (cast != value) { - throw new IllegalArgumentException("bogus char value: " + - value); - } - - return make(cast); - } - - /** - * Constructs an instance. This constructor is private; use {@link #make}. - * - * @param value the <code>char</code> value - */ - private CstChar(char value) { - super(value); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - int value = getIntBits(); - return "char{0x" + Hex.u2(value) + " / " + value + '}'; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.CHAR; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "char"; - } - - /** {@inheritDoc} */ - public String toHuman() { - return Integer.toString(getIntBits()); - } - - /** - * Gets the <code>char</code> value. - * - * @return the value - */ - public char getValue() { - return (char) getIntBits(); - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstDouble.java b/dx/src/com/android/dx/rop/cst/CstDouble.java deleted file mode 100644 index 451666791..000000000 --- a/dx/src/com/android/dx/rop/cst/CstDouble.java +++ /dev/null @@ -1,90 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; -import com.android.dx.util.Hex; - -/** - * Constants of type <code>CONSTANT_Double_info</code>. - */ -public final class CstDouble - extends CstLiteral64 { - /** non-null; instance representing <code>0</code> */ - public static final CstDouble VALUE_0 = - new CstDouble(Double.doubleToLongBits(0.0)); - - /** non-null; instance representing <code>1</code> */ - public static final CstDouble VALUE_1 = - new CstDouble(Double.doubleToLongBits(1.0)); - - /** - * Makes an instance for the given value. This may (but does not - * necessarily) return an already-allocated instance. - * - * @param bits the <code>double</code> value as <code>long</code> bits - */ - public static CstDouble make(long bits) { - /* - * Note: Javadoc notwithstanding, this implementation always - * allocates. - */ - return new CstDouble(bits); - } - - /** - * Constructs an instance. This constructor is private; use {@link #make}. - * - * @param bits the <code>double</code> value as <code>long</code> bits - */ - private CstDouble(long bits) { - super(bits); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - long bits = getLongBits(); - return "double{0x" + Hex.u8(bits) + " / " + - Double.longBitsToDouble(bits) + '}'; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.DOUBLE; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "double"; - } - - /** {@inheritDoc} */ - public String toHuman() { - return Double.toString(Double.longBitsToDouble(getLongBits())); - } - - /** - * Gets the <code>double</code> value. - * - * @return the value - */ - public double getValue() { - return Double.longBitsToDouble(getLongBits()); - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstEnumRef.java b/dx/src/com/android/dx/rop/cst/CstEnumRef.java deleted file mode 100644 index f5aec0549..000000000 --- a/dx/src/com/android/dx/rop/cst/CstEnumRef.java +++ /dev/null @@ -1,68 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; - -/** - * Constant type to represent a reference to a particular constant - * value of an enumerated type. - */ -public final class CstEnumRef extends CstMemberRef { - /** null-ok; the corresponding field ref, lazily initialized */ - private CstFieldRef fieldRef; - - /** - * Constructs an instance. - * - * @param nat non-null; the name-and-type; the defining class is derived - * from this - */ - public CstEnumRef(CstNat nat) { - super(new CstType(nat.getFieldType()), nat); - - fieldRef = null; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "enum"; - } - - /** - * {@inheritDoc} - * - * <b>Note:</b> This returns the enumerated type. - */ - public Type getType() { - return getDefiningClass().getClassType(); - } - - /** - * Get a {@link CstFieldRef} that corresponds with this instance. - * - * @return non-null; the corresponding field reference - */ - public CstFieldRef getFieldRef() { - if (fieldRef == null) { - fieldRef = new CstFieldRef(getDefiningClass(), getNat()); - } - - return fieldRef; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstFieldRef.java b/dx/src/com/android/dx/rop/cst/CstFieldRef.java deleted file mode 100644 index 306eca928..000000000 --- a/dx/src/com/android/dx/rop/cst/CstFieldRef.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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; - -/** - * Constants of type <code>CONSTANT_Fieldref_info</code>. - */ -public final class CstFieldRef extends CstMemberRef { - /** - * Returns an instance of this class that represents the static - * field which should hold the class corresponding to a given - * primitive type. For example, if given {@link Type#INT}, this - * method returns an instance corresponding to the field - * <code>java.lang.Integer.TYPE</code>. - * - * @param primitiveType non-null; the primitive type - * @return non-null; the corresponding static field - */ - public static CstFieldRef forPrimitiveType(Type primitiveType) { - return new CstFieldRef(CstType.forBoxedPrimitiveType(primitiveType), - CstNat.PRIMITIVE_TYPE_NAT); - } - - /** - * Constructs an instance. - * - * @param definingClass non-null; the type of the defining class - * @param nat non-null; the name-and-type - */ - public CstFieldRef(CstType definingClass, CstNat nat) { - super(definingClass, nat); - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "field"; - } - - /** - * Returns the type of this field. - * - * @return non-null; the field's type - */ - public Type getType() { - return getNat().getFieldType(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(Constant other) { - int cmp = super.compareTo0(other); - - if (cmp != 0) { - return cmp; - } - - CstFieldRef otherField = (CstFieldRef) other; - CstUtf8 thisDescriptor = getNat().getDescriptor(); - CstUtf8 otherDescriptor = otherField.getNat().getDescriptor(); - return thisDescriptor.compareTo(otherDescriptor); - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstFloat.java b/dx/src/com/android/dx/rop/cst/CstFloat.java deleted file mode 100644 index 08b7f764e..000000000 --- a/dx/src/com/android/dx/rop/cst/CstFloat.java +++ /dev/null @@ -1,91 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; -import com.android.dx.util.Hex; - -/** - * Constants of type <code>CONSTANT_Float_info</code>. - */ -public final class CstFloat - extends CstLiteral32 { - /** non-null; instance representing <code>0</code> */ - public static final CstFloat VALUE_0 = make(Float.floatToIntBits(0.0f)); - - /** non-null; instance representing <code>1</code> */ - public static final CstFloat VALUE_1 = make(Float.floatToIntBits(1.0f)); - - /** non-null; instance representing <code>2</code> */ - public static final CstFloat VALUE_2 = make(Float.floatToIntBits(2.0f)); - - /** - * Makes an instance for the given value. This may (but does not - * necessarily) return an already-allocated instance. - * - * @param bits the <code>float</code> value as <code>int</code> bits - */ - public static CstFloat make(int bits) { - /* - * Note: Javadoc notwithstanding, this implementation always - * allocates. - */ - return new CstFloat(bits); - } - - /** - * Constructs an instance. This constructor is private; use {@link #make}. - * - * @param bits the <code>float</code> value as <code>int</code> bits - */ - private CstFloat(int bits) { - super(bits); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - int bits = getIntBits(); - return "float{0x" + Hex.u4(bits) + " / " + - Float.intBitsToFloat(bits) + '}'; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.FLOAT; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "float"; - } - - /** {@inheritDoc} */ - public String toHuman() { - return Float.toString(Float.intBitsToFloat(getIntBits())); - } - - /** - * Gets the <code>float</code> value. - * - * @return the value - */ - public float getValue() { - return Float.intBitsToFloat(getIntBits()); - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstInteger.java b/dx/src/com/android/dx/rop/cst/CstInteger.java deleted file mode 100644 index d3fafccd7..000000000 --- a/dx/src/com/android/dx/rop/cst/CstInteger.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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; -import com.android.dx.util.Hex; - -/** - * Constants of type <code>CONSTANT_Integer_info</code>. - */ -public final class CstInteger - extends CstLiteral32 { - /** non-null; array of cached instances */ - private static final CstInteger[] cache = new CstInteger[511]; - - /** non-null; instance representing <code>-1</code> */ - public static final CstInteger VALUE_M1 = make(-1); - - /** non-null; instance representing <code>0</code> */ - public static final CstInteger VALUE_0 = make(0); - - /** non-null; instance representing <code>1</code> */ - public static final CstInteger VALUE_1 = make(1); - - /** non-null; instance representing <code>2</code> */ - public static final CstInteger VALUE_2 = make(2); - - /** non-null; instance representing <code>3</code> */ - public static final CstInteger VALUE_3 = make(3); - - /** non-null; instance representing <code>4</code> */ - public static final CstInteger VALUE_4 = make(4); - - /** non-null; instance representing <code>5</code> */ - public static final CstInteger VALUE_5 = make(5); - - /** - * Makes an instance for the given value. This may (but does not - * necessarily) return an already-allocated instance. - * - * @param value the <code>int</code> value - * @return non-null; the appropriate instance - */ - public static CstInteger make(int value) { - /* - * Note: No need to synchronize, since we don't make any sort - * of guarantee about ==, and it's okay to overwrite existing - * entries too. - */ - int idx = (value & 0x7fffffff) % cache.length; - CstInteger obj = cache[idx]; - - if ((obj != null) && (obj.getValue() == value)) { - return obj; - } - - obj = new CstInteger(value); - cache[idx] = obj; - return obj; - } - - /** - * Constructs an instance. This constructor is private; use {@link #make}. - * - * @param value the <code>int</code> value - */ - private CstInteger(int value) { - super(value); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - int value = getIntBits(); - return "int{0x" + Hex.u4(value) + " / " + value + '}'; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.INT; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "int"; - } - - /** {@inheritDoc} */ - public String toHuman() { - return Integer.toString(getIntBits()); - } - - /** - * Gets the <code>int</code> value. - * - * @return the value - */ - public int getValue() { - return getIntBits(); - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java b/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java deleted file mode 100644 index f169ec939..000000000 --- a/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.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.android.dx.rop.cst; - -/** - * Constants of type <code>CONSTANT_InterfaceMethodref_info</code>. - */ -public final class CstInterfaceMethodRef - extends CstBaseMethodRef { - /** - * null-ok; normal {@link CstMethodRef} that corresponds to this - * instance, if calculated - */ - private CstMethodRef methodRef; - - /** - * Constructs an instance. - * - * @param definingClass non-null; the type of the defining class - * @param nat non-null; the name-and-type - */ - public CstInterfaceMethodRef(CstType definingClass, CstNat nat) { - super(definingClass, nat); - methodRef = null; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "ifaceMethod"; - } - - /** - * Gets a normal (non-interface) {@link CstMethodRef} that corresponds to - * this instance. - * - * @return non-null; an appropriate instance - */ - public CstMethodRef toMethodRef() { - if (methodRef == null) { - methodRef = new CstMethodRef(getDefiningClass(), getNat()); - } - - return methodRef; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstKnownNull.java b/dx/src/com/android/dx/rop/cst/CstKnownNull.java deleted file mode 100644 index 853e57e56..000000000 --- a/dx/src/com/android/dx/rop/cst/CstKnownNull.java +++ /dev/null @@ -1,110 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; - -/** - * Constant type to represent a known-<code>null</code> value. - */ -public final class CstKnownNull extends CstLiteralBits { - /** non-null; unique instance of this class */ - public static final CstKnownNull THE_ONE = new CstKnownNull(); - - /** - * Constructs an instance. This class is not publicly instantiable. Use - * {@link #THE_ONE}. - */ - private CstKnownNull() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - return (other instanceof CstKnownNull); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return 0x4466757a; - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(Constant other) { - return 0; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return "known-null"; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.KNOWN_NULL; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "known-null"; - } - - /** {@inheritDoc} */ - @Override - public boolean isCategory2() { - return false; - } - - /** {@inheritDoc} */ - public String toHuman() { - return "null"; - } - - /** {@inheritDoc} */ - @Override - public boolean fitsInInt() { - // See comment in getIntBits(). - return true; - } - - /** - * {@inheritDoc} - * - * As "literal bits," a known-null is always represented as the - * number zero. - */ - @Override - public int getIntBits() { - return 0; - } - - /** - * {@inheritDoc} - * - * As "literal bits," a known-null is always represented as the - * number zero. - */ - @Override - public long getLongBits() { - return 0; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstLiteral32.java b/dx/src/com/android/dx/rop/cst/CstLiteral32.java deleted file mode 100644 index 31e96dd63..000000000 --- a/dx/src/com/android/dx/rop/cst/CstLiteral32.java +++ /dev/null @@ -1,87 +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.android.dx.rop.cst; - -/** - * Constants which are literal 32-bit values of some sort. - */ -public abstract class CstLiteral32 - extends CstLiteralBits { - /** the value as <code>int</code> bits */ - private final int bits; - - /** - * Constructs an instance. - * - * @param bits the value as <code>int</code> bits - */ - /*package*/ CstLiteral32(int bits) { - this.bits = bits; - } - - /** {@inheritDoc} */ - @Override - public final boolean equals(Object other) { - return (other != null) && - (getClass() == other.getClass()) && - bits == ((CstLiteral32) other).bits; - } - - /** {@inheritDoc} */ - @Override - public final int hashCode() { - return bits; - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(Constant other) { - int otherBits = ((CstLiteral32) other).bits; - - if (bits < otherBits) { - return -1; - } else if (bits > otherBits) { - return 1; - } else { - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public final boolean isCategory2() { - return false; - } - - /** {@inheritDoc} */ - @Override - public final boolean fitsInInt() { - return true; - } - - /** {@inheritDoc} */ - @Override - public final int getIntBits() { - return bits; - } - - /** {@inheritDoc} */ - @Override - public final long getLongBits() { - return (long) bits; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstLiteral64.java b/dx/src/com/android/dx/rop/cst/CstLiteral64.java deleted file mode 100644 index dd7d24dea..000000000 --- a/dx/src/com/android/dx/rop/cst/CstLiteral64.java +++ /dev/null @@ -1,87 +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.android.dx.rop.cst; - -/** - * Constants which are literal 64-bit values of some sort. - */ -public abstract class CstLiteral64 - extends CstLiteralBits { - /** the value as <code>long</code> bits */ - private final long bits; - - /** - * Constructs an instance. - * - * @param bits the value as <code>long</code> bits - */ - /*package*/ CstLiteral64(long bits) { - this.bits = bits; - } - - /** {@inheritDoc} */ - @Override - public final boolean equals(Object other) { - return (other != null) && - (getClass() == other.getClass()) && - bits == ((CstLiteral64) other).bits; - } - - /** {@inheritDoc} */ - @Override - public final int hashCode() { - return (int) bits ^ (int) (bits >> 32); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(Constant other) { - long otherBits = ((CstLiteral64) other).bits; - - if (bits < otherBits) { - return -1; - } else if (bits > otherBits) { - return 1; - } else { - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public final boolean isCategory2() { - return true; - } - - /** {@inheritDoc} */ - @Override - public final boolean fitsInInt() { - return (int) bits == bits; - } - - /** {@inheritDoc} */ - @Override - public final int getIntBits() { - return (int) bits; - } - - /** {@inheritDoc} */ - @Override - public final long getLongBits() { - return bits; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstLiteralBits.java b/dx/src/com/android/dx/rop/cst/CstLiteralBits.java deleted file mode 100644 index 98a3f0e53..000000000 --- a/dx/src/com/android/dx/rop/cst/CstLiteralBits.java +++ /dev/null @@ -1,82 +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.android.dx.rop.cst; - -/** - * Constants which are literal bitwise values of some sort. - */ -public abstract class CstLiteralBits - extends TypedConstant { - /** - * Returns whether or not this instance's value may be accurately - * represented as an <code>int</code>. The rule is that if there - * is an <code>int</code> which may be sign-extended to yield this - * instance's value, then this method returns <code>true</code>. - * Otherwise, it returns <code>false</code>. - * - * @return <code>true</code> iff this instance fits in an <code>int</code> - */ - public abstract boolean fitsInInt(); - - /** - * Gets the value as <code>int</code> bits. If this instance contains - * more bits than fit in an <code>int</code>, then this returns only - * the low-order bits. - * - * @return the bits - */ - public abstract int getIntBits(); - - /** - * Gets the value as <code>long</code> bits. If this instance contains - * fewer bits than fit in a <code>long</code>, then the result of this - * method is the sign extension of the value. - * - * @return the bits - */ - public abstract long getLongBits(); - - /** - * Returns true if this value can fit in 16 bits with sign-extension. - * - * @return true if the sign-extended lower 16 bits are the same as - * the value. - */ - public boolean fitsIn16Bits() { - if (! fitsInInt()) { - return false; - } - - int bits = getIntBits(); - return (short) bits == bits; - } - - /** - * Returns true if this value can fit in 8 bits with sign-extension. - * - * @return true if the sign-extended lower 8 bits are the same as - * the value. - */ - public boolean fitsIn8Bits() { - if (! fitsInInt()) { - return false; - } - - int bits = getIntBits(); - return (byte) bits == bits; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstLong.java b/dx/src/com/android/dx/rop/cst/CstLong.java deleted file mode 100644 index 377eb9312..000000000 --- a/dx/src/com/android/dx/rop/cst/CstLong.java +++ /dev/null @@ -1,87 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; -import com.android.dx.util.Hex; - -/** - * Constants of type <code>CONSTANT_Long_info</code>. - */ -public final class CstLong - extends CstLiteral64 { - /** non-null; instance representing <code>0</code> */ - public static final CstLong VALUE_0 = make(0); - - /** non-null; instance representing <code>1</code> */ - public static final CstLong VALUE_1 = make(1); - - /** - * Makes an instance for the given value. This may (but does not - * necessarily) return an already-allocated instance. - * - * @param value the <code>long</code> value - */ - public static CstLong make(long value) { - /* - * Note: Javadoc notwithstanding, this implementation always - * allocates. - */ - return new CstLong(value); - } - - /** - * Constructs an instance. This constructor is private; use {@link #make}. - * - * @param value the <code>long</code> value - */ - private CstLong(long value) { - super(value); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - long value = getLongBits(); - return "long{0x" + Hex.u8(value) + " / " + value + '}'; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.LONG; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "long"; - } - - /** {@inheritDoc} */ - public String toHuman() { - return Long.toString(getLongBits()); - } - - /** - * Gets the <code>long</code> value. - * - * @return the value - */ - public long getValue() { - return getLongBits(); - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstMemberRef.java b/dx/src/com/android/dx/rop/cst/CstMemberRef.java deleted file mode 100644 index dbaad47eb..000000000 --- a/dx/src/com/android/dx/rop/cst/CstMemberRef.java +++ /dev/null @@ -1,122 +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.android.dx.rop.cst; - -/** - * Constants of type <code>CONSTANT_*ref_info</code>. - */ -public abstract class CstMemberRef extends TypedConstant { - /** non-null; the type of the defining class */ - private final CstType definingClass; - - /** non-null; the name-and-type */ - private final CstNat nat; - - /** - * Constructs an instance. - * - * @param definingClass non-null; the type of the defining class - * @param nat non-null; the name-and-type - */ - /*package*/ CstMemberRef(CstType definingClass, CstNat nat) { - if (definingClass == null) { - throw new NullPointerException("definingClass == null"); - } - - if (nat == null) { - throw new NullPointerException("nat == null"); - } - - this.definingClass = definingClass; - this.nat = nat; - } - - /** {@inheritDoc} */ - @Override - public final boolean equals(Object other) { - if ((other == null) || (getClass() != other.getClass())) { - return false; - } - - CstMemberRef otherRef = (CstMemberRef) other; - return definingClass.equals(otherRef.definingClass) && - nat.equals(otherRef.nat); - } - - /** {@inheritDoc} */ - @Override - public final int hashCode() { - return (definingClass.hashCode() * 31) ^ nat.hashCode(); - } - - /** - * {@inheritDoc} - * - * <p><b>Note:</b> This implementation just compares the defining - * class and name, and it is up to subclasses to compare the rest - * after calling <code>super.compareTo0()</code>.</p> - */ - @Override - protected int compareTo0(Constant other) { - CstMemberRef otherMember = (CstMemberRef) other; - int cmp = definingClass.compareTo(otherMember.definingClass); - - if (cmp != 0) { - return cmp; - } - - CstUtf8 thisName = nat.getName(); - CstUtf8 otherName = otherMember.nat.getName(); - - return thisName.compareTo(otherName); - } - - /** {@inheritDoc} */ - @Override - public final String toString() { - return typeName() + '{' + toHuman() + '}'; - } - - /** {@inheritDoc} */ - @Override - public final boolean isCategory2() { - return false; - } - - /** {@inheritDoc} */ - public final String toHuman() { - return definingClass.toHuman() + '.' + nat.toHuman(); - } - - /** - * Gets the type of the defining class. - * - * @return non-null; the type of defining class - */ - public final CstType getDefiningClass() { - return definingClass; - } - - /** - * Gets the defining name-and-type. - * - * @return non-null; the name-and-type - */ - public final CstNat getNat() { - return nat; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstMethodRef.java b/dx/src/com/android/dx/rop/cst/CstMethodRef.java deleted file mode 100644 index 766c9bfba..000000000 --- a/dx/src/com/android/dx/rop/cst/CstMethodRef.java +++ /dev/null @@ -1,39 +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.android.dx.rop.cst; - -/** - * Constants of type <code>CONSTANT_Methodref_info</code>. - */ -public final class CstMethodRef - extends CstBaseMethodRef { - /** - * Constructs an instance. - * - * @param definingClass non-null; the type of the defining class - * @param nat non-null; the name-and-type - */ - public CstMethodRef(CstType definingClass, CstNat nat) { - super(definingClass, nat); - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "method"; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstNat.java b/dx/src/com/android/dx/rop/cst/CstNat.java deleted file mode 100644 index 106b599cc..000000000 --- a/dx/src/com/android/dx/rop/cst/CstNat.java +++ /dev/null @@ -1,170 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; - -/** - * Constants of type <code>CONSTANT_NameAndType_info</code>. - */ -public final class CstNat extends Constant { - /** - * non-null; the instance for name <code>TYPE</code> and descriptor - * <code>java.lang.Class</code>, which is useful when dealing with - * wrapped primitives - */ - public static final CstNat PRIMITIVE_TYPE_NAT = - new CstNat(new CstUtf8("TYPE"), - new CstUtf8("Ljava/lang/Class;")); - - /** non-null; the name */ - private final CstUtf8 name; - - /** non-null; the descriptor (type) */ - private final CstUtf8 descriptor; - - /** - * Constructs an instance. - * - * @param name non-null; the name - * @param descriptor non-null; the descriptor - */ - public CstNat(CstUtf8 name, CstUtf8 descriptor) { - if (name == null) { - throw new NullPointerException("name == null"); - } - - if (descriptor == null) { - throw new NullPointerException("descriptor == null"); - } - - this.name = name; - this.descriptor = descriptor; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof CstNat)) { - return false; - } - - CstNat otherNat = (CstNat) other; - return name.equals(otherNat.name) && - descriptor.equals(otherNat.descriptor); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return (name.hashCode() * 31) ^ descriptor.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(Constant other) { - CstNat otherNat = (CstNat) other; - int cmp = name.compareTo(otherNat.name); - - if (cmp != 0) { - return cmp; - } - - return descriptor.compareTo(otherNat.descriptor); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return "nat{" + toHuman() + '}'; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "nat"; - } - - /** {@inheritDoc} */ - @Override - public boolean isCategory2() { - return false; - } - - /** - * Gets the name. - * - * @return non-null; the name - */ - public CstUtf8 getName() { - return name; - } - - /** - * Gets the descriptor. - * - * @return non-null; the descriptor - */ - public CstUtf8 getDescriptor() { - return descriptor; - } - - /** - * Returns an unadorned but human-readable version of the name-and-type - * value. - * - * @return non-null; the human form - */ - public String toHuman() { - return name.toHuman() + ':' + descriptor.toHuman(); - } - - /** - * Gets the field type corresponding to this instance's descriptor. - * This method is only valid to call if the descriptor in fact describes - * a field (and not a method). - * - * @return non-null; the field type - */ - public Type getFieldType() { - return Type.intern(descriptor.getString()); - } - - /** - * Gets whether this instance has the name of a standard instance - * initialization method. This is just a convenient shorthand for - * <code>getName().getString().equals("<init>")</code>. - * - * @return <code>true</code> iff this is a reference to an - * instance initialization method - */ - public final boolean isInstanceInit() { - return name.getString().equals("<init>"); - } - - /** - * Gets whether this instance has the name of a standard class - * initialization method. This is just a convenient shorthand for - * <code>getName().getString().equals("<clinit>")</code>. - * - * @return <code>true</code> iff this is a reference to an - * instance initialization method - */ - public final boolean isClassInit() { - return name.getString().equals("<clinit>"); - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstShort.java b/dx/src/com/android/dx/rop/cst/CstShort.java deleted file mode 100644 index 38042541a..000000000 --- a/dx/src/com/android/dx/rop/cst/CstShort.java +++ /dev/null @@ -1,100 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; -import com.android.dx.util.Hex; - -/** - * Constants of type <code>short</code>. - */ -public final class CstShort - extends CstLiteral32 { - /** non-null; the value <code>0</code> as an instance of this class */ - public static final CstShort VALUE_0 = make((short) 0); - - /** - * Makes an instance for the given value. This may (but does not - * necessarily) return an already-allocated instance. - * - * @param value the <code>short</code> value - * @return non-null; the appropriate instance - */ - public static CstShort make(short value) { - return new CstShort(value); - } - - /** - * Makes an instance for the given <code>int</code> value. This - * may (but does not necessarily) return an already-allocated - * instance. - * - * @param value the value, which must be in range for a <code>short</code> - * @return non-null; the appropriate instance - */ - public static CstShort make(int value) { - short cast = (short) value; - - if (cast != value) { - throw new IllegalArgumentException("bogus short value: " + - value); - } - - return make(cast); - } - - /** - * Constructs an instance. This constructor is private; use {@link #make}. - * - * @param value the <code>short</code> value - */ - private CstShort(short value) { - super(value); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - int value = getIntBits(); - return "short{0x" + Hex.u2(value) + " / " + value + '}'; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.SHORT; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "short"; - } - - /** {@inheritDoc} */ - public String toHuman() { - return Integer.toString(getIntBits()); - } - - /** - * Gets the <code>short</code> value. - * - * @return the value - */ - public short getValue() { - return (short) getIntBits(); - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstString.java b/dx/src/com/android/dx/rop/cst/CstString.java deleted file mode 100644 index 89a4c8bfe..000000000 --- a/dx/src/com/android/dx/rop/cst/CstString.java +++ /dev/null @@ -1,109 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; - -/** - * Constants of type <code>CONSTANT_String_info</code>. - */ -public final class CstString - extends TypedConstant { - /** non-null; the string value */ - private final CstUtf8 string; - - /** - * Constructs an instance. - * - * @param string non-null; the string value - */ - public CstString(CstUtf8 string) { - if (string == null) { - throw new NullPointerException("string == null"); - } - - this.string = string; - } - - /** - * Constructs an instance. - * - * @param string non-null; the string value - */ - public CstString(String string) { - this(new CstUtf8(string)); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof CstString)) { - return false; - } - - return string.equals(((CstString) other).string); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return string.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(Constant other) { - return string.compareTo(((CstString) other).string); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return "string{" + toHuman() + '}'; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.STRING; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "string"; - } - - /** {@inheritDoc} */ - @Override - public boolean isCategory2() { - return false; - } - - /** {@inheritDoc} */ - public String toHuman() { - return string.toQuoted(); - } - - /** - * Gets the string value. - * - * @return non-null; the string value - */ - public CstUtf8 getString() { - return string; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstType.java b/dx/src/com/android/dx/rop/cst/CstType.java deleted file mode 100644 index 02df28d98..000000000 --- a/dx/src/com/android/dx/rop/cst/CstType.java +++ /dev/null @@ -1,230 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; - -import java.util.HashMap; - -/** - * Constants that represent an arbitrary type (reference or primitive). - */ -public final class CstType extends TypedConstant { - /** non-null; map of interned types */ - private static final HashMap<Type, CstType> interns = - new HashMap<Type, CstType>(100); - - /** non-null; instance corresponding to the class <code>Object</code> */ - public static final CstType OBJECT = intern(Type.OBJECT); - - /** non-null; instance corresponding to the class <code>Boolean</code> */ - public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS); - - /** non-null; instance corresponding to the class <code>Byte</code> */ - public static final CstType BYTE = intern(Type.BYTE_CLASS); - - /** non-null; instance corresponding to the class <code>Character</code> */ - public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS); - - /** non-null; instance corresponding to the class <code>Double</code> */ - public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS); - - /** non-null; instance corresponding to the class <code>Float</code> */ - public static final CstType FLOAT = intern(Type.FLOAT_CLASS); - - /** non-null; instance corresponding to the class <code>Long</code> */ - public static final CstType LONG = intern(Type.LONG_CLASS); - - /** non-null; instance corresponding to the class <code>Integer</code> */ - public static final CstType INTEGER = intern(Type.INTEGER_CLASS); - - /** non-null; instance corresponding to the class <code>Short</code> */ - public static final CstType SHORT = intern(Type.SHORT_CLASS); - - /** non-null; instance corresponding to the class <code>Void</code> */ - public static final CstType VOID = intern(Type.VOID_CLASS); - - /** non-null; instance corresponding to the type <code>boolean[]</code> */ - public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY); - - /** non-null; instance corresponding to the type <code>byte[]</code> */ - public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY); - - /** non-null; instance corresponding to the type <code>char[]</code> */ - public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY); - - /** non-null; instance corresponding to the type <code>double[]</code> */ - public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY); - - /** non-null; instance corresponding to the type <code>float[]</code> */ - public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY); - - /** non-null; instance corresponding to the type <code>long[]</code> */ - public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY); - - /** non-null; instance corresponding to the type <code>int[]</code> */ - public static final CstType INT_ARRAY = intern(Type.INT_ARRAY); - - /** non-null; instance corresponding to the type <code>short[]</code> */ - public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY); - - /** non-null; the underlying type */ - private final Type type; - - /** - * null-ok; the type descriptor corresponding to this instance, if - * calculated - */ - private CstUtf8 descriptor; - - /** - * Returns an instance of this class that represents the wrapper - * class corresponding to a given primitive type. For example, if - * given {@link Type#INT}, this method returns the class reference - * <code>java.lang.Integer</code>. - * - * @param primitiveType non-null; the primitive type - * @return non-null; the corresponding wrapper class - */ - public static CstType forBoxedPrimitiveType(Type primitiveType) { - switch (primitiveType.getBasicType()) { - case Type.BT_BOOLEAN: return BOOLEAN; - case Type.BT_BYTE: return BYTE; - case Type.BT_CHAR: return CHARACTER; - case Type.BT_DOUBLE: return DOUBLE; - case Type.BT_FLOAT: return FLOAT; - case Type.BT_INT: return INTEGER; - case Type.BT_LONG: return LONG; - case Type.BT_SHORT: return SHORT; - case Type.BT_VOID: return VOID; - } - - throw new IllegalArgumentException("not primitive: " + primitiveType); - } - - /** - * Returns an interned instance of this class for the given type. - * - * @param type non-null; the underlying type - * @return non-null; an appropriately-constructed instance - */ - public static CstType intern(Type type) { - CstType cst = interns.get(type); - - if (cst == null) { - cst = new CstType(type); - interns.put(type, cst); - } - - return cst; - } - - /** - * Constructs an instance. - * - * @param type non-null; the underlying type - */ - public CstType(Type type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - if (type == type.KNOWN_NULL) { - throw new UnsupportedOperationException( - "KNOWN_NULL is not representable"); - } - - this.type = type; - this.descriptor = null; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof CstType)) { - return false; - } - - return type == ((CstType) other).type; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return type.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(Constant other) { - String thisDescriptor = type.getDescriptor(); - String otherDescriptor = ((CstType) other).type.getDescriptor(); - return thisDescriptor.compareTo(otherDescriptor); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return "type{" + toHuman() + '}'; - } - - /** {@inheritDoc} */ - public Type getType() { - return Type.CLASS; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "type"; - } - - /** {@inheritDoc} */ - @Override - public boolean isCategory2() { - return false; - } - - /** {@inheritDoc} */ - public String toHuman() { - return type.toHuman(); - } - - /** - * Gets the underlying type (as opposed to the type corresponding - * to this instance as a constant, which is always - * <code>Class</code>). - * - * @return non-null; the type corresponding to the name - */ - public Type getClassType() { - return type; - } - - /** - * Gets the type descriptor for this instance. - * - * @return non-null; the descriptor - */ - public CstUtf8 getDescriptor() { - if (descriptor == null) { - descriptor = new CstUtf8(type.getDescriptor()); - } - - return descriptor; - } -} diff --git a/dx/src/com/android/dx/rop/cst/CstUtf8.java b/dx/src/com/android/dx/rop/cst/CstUtf8.java deleted file mode 100644 index f0ca5f5b9..000000000 --- a/dx/src/com/android/dx/rop/cst/CstUtf8.java +++ /dev/null @@ -1,371 +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.android.dx.rop.cst; - -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; - -/** - * Constants of type <code>CONSTANT_Utf8_info</code>. - */ -public final class CstUtf8 extends Constant { - /** - * non-null; instance representing <code>""</code>, that is, the - * empty string - */ - public static final CstUtf8 EMPTY_STRING = new CstUtf8(""); - - /** non-null; the UTF-8 value as a string */ - private final String string; - - /** non-null; the UTF-8 value as bytes */ - private final ByteArray bytes; - - /** - * Converts a string into its Java-style UTF-8 form. Java-style UTF-8 - * differs from normal UTF-8 in the handling of character '\0' and - * surrogate pairs. - * - * @param string non-null; the string to convert - * @return non-null; the UTF-8 bytes for it - */ - public static byte[] stringToUtf8Bytes(String string) { - int len = string.length(); - byte[] bytes = new byte[len * 3]; // Avoid having to reallocate. - int outAt = 0; - - for (int i = 0; i < len; i++) { - char c = string.charAt(i); - if ((c != 0) && (c < 0x80)) { - bytes[outAt] = (byte) c; - outAt++; - } else if (c < 0x800) { - bytes[outAt] = (byte) (((c >> 6) & 0x1f) | 0xc0); - bytes[outAt + 1] = (byte) ((c & 0x3f) | 0x80); - outAt += 2; - } else { - bytes[outAt] = (byte) (((c >> 12) & 0x0f) | 0xe0); - bytes[outAt + 1] = (byte) (((c >> 6) & 0x3f) | 0x80); - bytes[outAt + 2] = (byte) ((c & 0x3f) | 0x80); - outAt += 3; - } - } - - byte[] result = new byte[outAt]; - System.arraycopy(bytes, 0, result, 0, outAt); - return result; - } - - /** - * Converts an array of UTF-8 bytes into a string. - * - * @param bytes non-null; the bytes to convert - * @return non-null; the converted string - */ - public static String utf8BytesToString(ByteArray bytes) { - int length = bytes.size(); - char[] chars = new char[length]; // This is sized to avoid a realloc. - int outAt = 0; - - for (int at = 0; length > 0; /*at*/) { - int v0 = bytes.getUnsignedByte(at); - char out; - switch (v0 >> 4) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: { - // 0XXXXXXX -- single-byte encoding - length--; - if (v0 == 0) { - // A single zero byte is illegal. - return throwBadUtf8(v0, at); - } - out = (char) v0; - at++; - break; - } - case 0x0c: case 0x0d: { - // 110XXXXX -- two-byte encoding - length -= 2; - if (length < 0) { - return throwBadUtf8(v0, at); - } - int v1 = bytes.getUnsignedByte(at + 1); - if ((v1 & 0xc0) != 0x80) { - return throwBadUtf8(v1, at + 1); - } - int value = ((v0 & 0x1f) << 6) | (v1 & 0x3f); - if ((value != 0) && (value < 0x80)) { - /* - * This should have been represented with - * one-byte encoding. - */ - return throwBadUtf8(v1, at + 1); - } - out = (char) value; - at += 2; - break; - } - case 0x0e: { - // 1110XXXX -- three-byte encoding - length -= 3; - if (length < 0) { - return throwBadUtf8(v0, at); - } - int v1 = bytes.getUnsignedByte(at + 1); - if ((v1 & 0xc0) != 0x80) { - return throwBadUtf8(v1, at + 1); - } - int v2 = bytes.getUnsignedByte(at + 2); - if ((v1 & 0xc0) != 0x80) { - return throwBadUtf8(v2, at + 2); - } - int value = ((v0 & 0x0f) << 12) | ((v1 & 0x3f) << 6) | - (v2 & 0x3f); - if (value < 0x800) { - /* - * This should have been represented with one- or - * two-byte encoding. - */ - return throwBadUtf8(v2, at + 2); - } - out = (char) value; - at += 3; - break; - } - default: { - // 10XXXXXX, 1111XXXX -- illegal - return throwBadUtf8(v0, at); - } - } - chars[outAt] = out; - outAt++; - } - - return new String(chars, 0, outAt); - } - - /** - * Helper for {@link #utf8BytesToString}, which throws the right - * exception for a bogus utf-8 byte. - * - * @param value the byte value - * @param offset the file offset - * @return never - * @throws IllegalArgumentException always thrown - */ - private static String throwBadUtf8(int value, int offset) { - throw new IllegalArgumentException("bad utf-8 byte " + Hex.u1(value) + - " at offset " + Hex.u4(offset)); - } - - /** - * Constructs an instance from a <code>String</code>. - * - * @param string non-null; the UTF-8 value as a string - */ - public CstUtf8(String string) { - if (string == null) { - throw new NullPointerException("string == null"); - } - - this.string = string.intern(); - this.bytes = new ByteArray(stringToUtf8Bytes(string)); - } - - /** - * Constructs an instance from some UTF-8 bytes. - * - * @param bytes non-null; array of the UTF-8 bytes - */ - public CstUtf8(ByteArray bytes) { - if (bytes == null) { - throw new NullPointerException("bytes == null"); - } - - this.bytes = bytes; - this.string = utf8BytesToString(bytes).intern(); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof CstUtf8)) { - return false; - } - - return string.equals(((CstUtf8) other).string); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return string.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(Constant other) { - return string.compareTo(((CstUtf8) other).string); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return "utf8{\"" + toHuman() + "\"}"; - } - - /** {@inheritDoc} */ - @Override - public String typeName() { - return "utf8"; - } - - /** {@inheritDoc} */ - @Override - public boolean isCategory2() { - return false; - } - - /** {@inheritDoc} */ - public String toHuman() { - int len = string.length(); - StringBuilder sb = new StringBuilder(len * 3 / 2); - - for (int i = 0; i < len; i++) { - char c = string.charAt(i); - if ((c >= ' ') && (c < 0x7f)) { - if ((c == '\'') || (c == '\"') || (c == '\\')) { - sb.append('\\'); - } - sb.append(c); - } else if (c <= 0x7f) { - switch (c) { - case '\n': sb.append("\\n"); break; - case '\r': sb.append("\\r"); break; - case '\t': sb.append("\\t"); break; - default: { - /* - * Represent the character as an octal escape. - * If the next character is a valid octal - * digit, disambiguate by using the - * three-digit form. - */ - char nextChar = - (i < (len - 1)) ? string.charAt(i + 1) : 0; - boolean displayZero = - (nextChar >= '0') && (nextChar <= '7'); - sb.append('\\'); - for (int shift = 6; shift >= 0; shift -= 3) { - char outChar = (char) (((c >> shift) & 7) + '0'); - if ((outChar != '0') || displayZero) { - sb.append(outChar); - displayZero = true; - } - } - if (! displayZero) { - // Ironic edge case: The original value was 0. - sb.append('0'); - } - break; - } - } - } else { - sb.append("\\u"); - sb.append(Character.forDigit(c >> 12, 16)); - sb.append(Character.forDigit((c >> 8) & 0x0f, 16)); - sb.append(Character.forDigit((c >> 4) & 0x0f, 16)); - sb.append(Character.forDigit(c & 0x0f, 16)); - } - } - - return sb.toString(); - } - - /** - * Gets the value as a human-oriented string, surrounded by double - * quotes. - * - * @return non-null; the quoted string - */ - public String toQuoted() { - return '\"' + toHuman() + '\"'; - } - - /** - * Gets the value as a human-oriented string, surrounded by double - * quotes, but ellipsizes the result if it is longer than the given - * maximum length - * - * @param maxLength >= 5; the maximum length of the string to return - * @return non-null; the quoted string - */ - public String toQuoted(int maxLength) { - String string = toHuman(); - int length = string.length(); - String ellipses; - - if (length <= (maxLength - 2)) { - ellipses = ""; - } else { - string = string.substring(0, maxLength - 5); - ellipses = "..."; - } - - return '\"' + string + ellipses + '\"'; - } - - /** - * Gets the UTF-8 value as a string. - * The returned string is always already interned. - * - * @return non-null; the UTF-8 value as a string - */ - public String getString() { - return string; - } - - /** - * Gets the UTF-8 value as UTF-8 encoded bytes. - * - * @return non-null; an array of the UTF-8 bytes - */ - public ByteArray getBytes() { - return bytes; - } - - /** - * Gets the size of this instance as UTF-8 code points. That is, - * get the number of bytes in the UTF-8 encoding of this instance. - * - * @return >= 0; the UTF-8 size - */ - public int getUtf8Size() { - return bytes.size(); - } - - /** - * Gets the size of this instance as UTF-16 code points. That is, - * get the number of 16-bit chars in the UTF-16 encoding of this - * instance. This is the same as the <code>length</code> of the - * Java <code>String</code> representation of this instance. - * - * @return >= 0; the UTF-16 size - */ - public int getUtf16Size() { - return string.length(); - } -} diff --git a/dx/src/com/android/dx/rop/cst/StdConstantPool.java b/dx/src/com/android/dx/rop/cst/StdConstantPool.java deleted file mode 100644 index 69791020f..000000000 --- a/dx/src/com/android/dx/rop/cst/StdConstantPool.java +++ /dev/null @@ -1,139 +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.android.dx.rop.cst; - -import com.android.dx.util.ExceptionWithContext; -import com.android.dx.util.Hex; -import com.android.dx.util.MutabilityControl; - -/** - * Standard implementation of {@link ConstantPool}, which directly stores - * an array of {@link Constant} objects and can be made immutable. - */ -public final class StdConstantPool - extends MutabilityControl implements ConstantPool { - /** non-null; array of entries */ - private final Constant[] entries; - - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size the size of the pool; this corresponds to the - * class file field <code>constant_pool_count</code>, and is in fact - * always at least one more than the actual size of the constant pool, - * as element <code>0</code> is always invalid. - */ - public StdConstantPool(int size) { - super(size > 1); - - if (size < 1) { - throw new IllegalArgumentException("size < 1"); - } - - entries = new Constant[size]; - } - - /** {@inheritDoc} */ - public int size() { - return entries.length; - } - - /** {@inheritDoc} */ - public Constant getOrNull(int n) { - try { - return entries[n]; - } catch (IndexOutOfBoundsException ex) { - // Translate the exception. - return throwInvalid(n); - } - } - - /** {@inheritDoc} */ - public Constant get0Ok(int n) { - if (n == 0) { - return null; - } - - return get(n); - } - - /** {@inheritDoc} */ - public Constant get(int n) { - try { - Constant result = entries[n]; - - if (result == null) { - throwInvalid(n); - } - - return result; - } catch (IndexOutOfBoundsException ex) { - // Translate the exception. - return throwInvalid(n); - } - } - - /** - * Sets the entry at the given index. - * - * @param n >= 1, < size(); which entry - * @param cst null-ok; the constant to store - */ - public void set(int n, Constant cst) { - throwIfImmutable(); - - boolean cat2 = (cst != null) && cst.isCategory2(); - - if (n < 1) { - throw new IllegalArgumentException("n < 1"); - } - - if (cat2) { - // Storing a category-2 entry nulls out the next index. - if (n == (entries.length - 1)) { - throw new IllegalArgumentException("(n == size - 1) && " + - "cst.isCategory2()"); - } - entries[n + 1] = null; - } - - if ((cst != null) && (entries[n] == null)) { - /* - * Overwriting the second half of a category-2 entry nulls out - * the first half. - */ - Constant prev = entries[n - 1]; - if ((prev != null) && prev.isCategory2()) { - entries[n - 1] = null; - } - } - - entries[n] = cst; - } - - /** - * Throws the right exception for an invalid cpi. - * - * @param idx the bad cpi - * @return never - * @throws ExceptionWithContext always thrown - */ - private static Constant throwInvalid(int idx) { - throw new ExceptionWithContext("invalid constant pool index " + - Hex.u2(idx)); - } -} diff --git a/dx/src/com/android/dx/rop/cst/TypedConstant.java b/dx/src/com/android/dx/rop/cst/TypedConstant.java deleted file mode 100644 index 54472b058..000000000 --- a/dx/src/com/android/dx/rop/cst/TypedConstant.java +++ /dev/null @@ -1,49 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.TypeBearer; - -/** - * Base class for constants which implement {@link TypeBearer}. - */ -public abstract class TypedConstant - extends Constant implements TypeBearer { - /** - * {@inheritDoc} - * - * This implentation always returns <code>this</code>. - */ - public final TypeBearer getFrameType() { - return this; - } - - /** {@inheritDoc} */ - public final int getBasicType() { - return getType().getBasicType(); - } - - /** {@inheritDoc} */ - public final int getBasicFrameType() { - return getType().getBasicFrameType(); - } - - /** {@inheritDoc} */ - public final boolean isConstant() { - return true; - } -} diff --git a/dx/src/com/android/dx/rop/cst/Zeroes.java b/dx/src/com/android/dx/rop/cst/Zeroes.java deleted file mode 100644 index 3379b6cc4..000000000 --- a/dx/src/com/android/dx/rop/cst/Zeroes.java +++ /dev/null @@ -1,55 +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.android.dx.rop.cst; - -import com.android.dx.rop.type.Type; - -/** - * Utility for turning types into zeroes. - */ -public final class Zeroes { - /** - * This class is uninstantiable. - */ - private Zeroes() { - // This space intentionally left blank. - } - - /** - * Gets the "zero" (or <code>null</code>) value for the given type. - * - * @param type non-null; the type in question - * @return non-null; its "zero" value - */ - public static Constant zeroFor(Type type) { - switch (type.getBasicType()) { - case Type.BT_BOOLEAN: return CstBoolean.VALUE_FALSE; - case Type.BT_BYTE: return CstByte.VALUE_0; - case Type.BT_CHAR: return CstChar.VALUE_0; - case Type.BT_DOUBLE: return CstDouble.VALUE_0; - case Type.BT_FLOAT: return CstFloat.VALUE_0; - case Type.BT_INT: return CstInteger.VALUE_0; - case Type.BT_LONG: return CstLong.VALUE_0; - case Type.BT_SHORT: return CstShort.VALUE_0; - case Type.BT_OBJECT: return CstKnownNull.THE_ONE; - default: { - throw new UnsupportedOperationException("no zero for type: " + - type.toHuman()); - } - } - } -} diff --git a/dx/src/com/android/dx/rop/cst/package.html b/dx/src/com/android/dx/rop/cst/package.html deleted file mode 100644 index c784d163d..000000000 --- a/dx/src/com/android/dx/rop/cst/package.html +++ /dev/null @@ -1,9 +0,0 @@ -<body> -<p>Interfaces and implementation of things related to the constant pool.</p> - -<p><b>PACKAGES USED:</b> -<ul> -<li><code>com.android.dx.rop.type</code></li> -<li><code>com.android.dx.util</code></li> -</ul> -</body> diff --git a/dx/src/com/android/dx/rop/package-info.java b/dx/src/com/android/dx/rop/package-info.java deleted file mode 100644 index 97fe9de73..000000000 --- a/dx/src/com/android/dx/rop/package-info.java +++ /dev/null @@ -1,201 +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.android.dx.rop; - -/** - * <h1>An Introduction to Rop Form</h1> - * - * This package contains classes associated with dx's <code>Rop</code> - * intermediate form.<p> - * - * The Rop form is intended to represent the instructions and the control-flow - * graph in a reasonably programmatically useful form while closely mirroring - * the dex instruction set.<p> - * - * <h2>Key Classes</h2> - * - * <ul> - * <li> {@link RopMethod}, the representation of an individual method - * <li> {@link BasicBlock} and its per-method container, {@link BasicBlockList}, - * the representation of control flow elements. - * <li> {@link Insn} and its subclasses along with its per-basic block - * container {@link InsnList}. <code>Insn</code> instances represent - * individual instructions in the abstract register machine. - * <li> {@link RegisterSpec} and its container {@link RegisterSpecList}. A - * register spec encodes register number, register width, type information, - * and potentially local variable information as well for instruction sources - * and results. - * <li> {@link Rop} instances represent opcodes in the abstract machine. Many - * <code>Rop</code> instances are singletons defined in static fields in - * {@link Rops}. The rest are constructed dynamically using static methods - * in <code>Rops</code> - * <li> {@link RegOps} lists numeric constants for the opcodes - * <li> {@link Constant} and its subclasses represent constant data values - * that opcodes may refer to. - * <li> {@link Type} instances represent the core data types that can be - * handled by the abstract machine. - * <li> The {@link TypeBearer} interface is implemented by classes that - * represent a core data type, but may also have secondary information - * (such as constant value) associated with them. - * <ul> - * - * <h2>Control-Flow Graph</h2> - * - * Each method is separated into a list of basic blocks. For the most part, - * basic blocks are referred to by a positive integer - * {@link BasicBlock#getLabel label}, which is always unique per method. The - * label value is typically derived from a bytecode address from the source - * bytecode. Blocks that don't originate directly from source bytecode have - * labels generated for them in a mostly arbitrary order.<p> - * - * Blocks are referred to by their label, for the most part, because <code> - * BasicBlock</code> instances are immutable and thus any modification to - * the control flow graph or the instruction list results in replacement - * instances (with identical labels) being created.<p> - * - * A method has a single {@link RopMethod#getFirstLabel entry block} and 0 - * to N {@link RopMethod#getExitPredecessors exit predecessor blocks} which - * will return. All blocks that are not the entry block will have at least - * one predecessor (or are unreachable and should be removed from the block - * list). All blocks that are not exit predecessors must have at least one - * successor.<p> - * - * Since all blocks must branch, all blocks must have, as their final - * instruction, an instruction whose opcode has a {@link Rop#getBranchingness - * branchingness} other than {@link Rop.BRANCH_NONE}. Furthermore, branching - * instructions may only be the final instruction in any basic block. If - * no other terminating opcode is appropriate, use a {@link Rops#GOTO GOTO}.<p> - * - * Typically a block will have a {@link BasicBlock#getPrimarySuccessor - * primary successor} which distinguishes a particular control flow path. - * For {Rops#isCallLike}call or call-like} opcodes, this is the path taken - * in the non-exceptional case, where all other successors represent - * various exception paths. For comparison operators such as - * {@link Rops#IF_EQZ_INT}, the primary successor represents the path taken - * if the <b>condition evaluates to false</b>. For {@link SwitchInsn switch - * instructions}, the primary successor is the default case.<p> - * - * A basic block's successor list is ordered and may refer to unique labels - * multiple times. For example, if a switch statement contains multiple case - * statements for the same code path, a single basic block will likely - * appear in the successor list multiple times. In general, the - * significance of the successor list's order (like the significance of - * the primary successor) is a property of the final instruction of the basic - * block. A basic block containing a {@link ThrowingInsn}, for example, has - * its successor list in an order identical to the - * {@link ThrowingInsn#getCatches} instruction's catches list, with the - * primary successor (the no-exception case) listed at the end. - * - * It is legal for a basic block to have no primary successor. An obvious - * example of this is a block that terminates in a {@link Rops#THROW throw} - * instruction where a catch block exists inside the current method for that - * exception class. Since the only possible path is the exception path, only - * the exception path (which cannot be a primary successor) is a successor. - * An example of this is shown in <code>dx/tests/092-ssa-cfg-edge-cases</code>. - * - * <h2>Rop Instructions</h2> - * - * <h3>move-result and move-result-pseudo</h3> - * - * An instruction that may throw an exception may not specify a result. This - * is necessary because the result register will not be assigned to if an - * exception occurs while processing said instruction and a result assignment - * may not occur. Since result assignments only occur in the non-exceptional - * case, the result assignments for throwing instructions can be said to occur - * at the beginning of the primary successor block rather than at the end of - * the current block. The Rop form represents the result assignments this way. - * Throwing instructions may not directly specify results. Instead, result - * assignments are represented by {@link - * Rops#MOVE_RESULT move-result} or {@link Rops#MOVE_RESULT_PSEUDO - * move-result-pseudo} instructions at the top of the primary successor block. - * - * Only a single <code>move-result</code> or <code>move-result-pseudo</code> - * may exist in any block and it must be exactly the first instruction in the - * block. - * - * A <code>move-result</code> instruction is used for the results of call-like - * instructions. If the value produced by a <code>move-result</code> is not - * used by the method, it may be eliminated as dead code. - * - * A <code>move-result-pseudo</code> instruction is used for the results of - * non-call-like throwing instructions. It may never be considered dead code - * since the final dex instruction will always indicate a result register. - * If a required <code>move-result-pseudo</code> instruction is not found - * during conversion to dex bytecode, an exception will be thrown. - * - * <h3>move-exception</h3> - * - * A {@link RegOps.MOVE_EXCEPTION move-exception} instruction may appear at - * the start of a catch block, and represents the obtaining of the thrown - * exception instance. It may only occur as the first instruction in a - * basic block, and any basic block in which it occurs must be reachable only - * as an exception successor. - * - * <h3>move-param</h3> - * - * A {@link RegOps.MOVE_PARAM move-param} instruction represents a method - * parameter. Every <code>move-param</code> instruction is a - * {@link PlainCstInsn}. The index of the method parameter they refer to is - * carried as the {@link CstInteger integer constant} associated with the - * instruction. - * - * Any number of <code>move-param</code> instructions referring to the same - * parameter index may be included in a method's instruction lists. They - * have no restrictions on placement beyond those of any other - * {@link Rop.BRANCH_NONE} instruction. Note that the SSA optimizer arranges the - * parameter assignments to align with the dex bytecode calling conventions. - * With parameter assignments so arranged, the - * {@link com.android.dx.dex.code.RopTranslator} sees Rop <code>move-param</code> - * instructions as unnecessary in dex form and eliminates them. - * - * <h3>mark-local</h3> - * - * A {@link RegOps.MARK_LOCAL mark-local} instruction indicates that a local - * variable becomes live in a specified register specified register for the - * purposes of debug information. A <code>mark-local</code> instruction has - * a single source (the register which will now be considered a local variable) - * and no results. The instruction has no side effect.<p> - * - * In a typical case, a local variable's lifetime begins with an - * assignment. The local variable whose information is present in a result's - * {@link RegisterSpec#getLocalItem LocalItem} is considered to begin (or move - * between registers) when the instruction is executed.<p> - * - * However, sometimes a local variable can begin its life or move without - * an assignment occurring. A common example of this is occurs in the Rop - * representation of the following code:<p> - * - * <code> - * try { - * Object foo = null; - * foo = new Object(); - * } catch (Throwable ex) { - * } - * </code> - * - * An object's initialization occurs in two steps. First, a <code>new-instance - * </code> instruction is executed, whose result is stored in a register. - * However, that register can not yet be considered to contain "foo". That's - * because the instance's constructor method must be called via an - * <code>invoke</code> instruction. The constructor method, however, may - * throw an exception. And if an exception occurs, then "foo" should remain - * null. So "foo" becomes the value of the result of the <code>new-instance - * </code> instruction after the (void) constructor method is invoked and - * returns successfully. In such a case, a <code>mark-local</code> will - * typically occur at the beginning of the primary successor block following - * the invocation to the constructor. - */ diff --git a/dx/src/com/android/dx/rop/type/Prototype.java b/dx/src/com/android/dx/rop/type/Prototype.java deleted file mode 100644 index a6ee74252..000000000 --- a/dx/src/com/android/dx/rop/type/Prototype.java +++ /dev/null @@ -1,397 +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.android.dx.rop.type; - -import java.util.HashMap; - -/** - * Representation of a method decriptor. Instances of this class are - * generally interned and may be usefully compared with each other - * using <code>==</code>. - */ -public final class Prototype implements Comparable<Prototype> { - /** non-null; intern table mapping string descriptors to instances */ - private static final HashMap<String, Prototype> internTable = - new HashMap<String, Prototype>(500); - - /** non-null; method descriptor */ - private final String descriptor; - - /** non-null; return type */ - private final Type returnType; - - /** non-null; list of parameter types */ - private final StdTypeList parameterTypes; - - /** null-ok; list of parameter frame types, if calculated */ - private StdTypeList parameterFrameTypes; - - /** - * Returns the unique instance corresponding to the - * given method descriptor. See vmspec-2 sec4.3.3 for details on the - * field descriptor syntax. - * - * @param descriptor non-null; the descriptor - * @return non-null; the corresponding instance - * @throws IllegalArgumentException thrown if the descriptor has - * invalid syntax - */ - public static Prototype intern(String descriptor) { - if (descriptor == null) { - throw new NullPointerException("descriptor == null"); - } - - Prototype result = internTable.get(descriptor); - if (result != null) { - return result; - } - - Type[] params = makeParameterArray(descriptor); - int paramCount = 0; - int at = 1; - - for (;;) { - int startAt = at; - char c = descriptor.charAt(at); - if (c == ')') { - at++; - break; - } - - // Skip array markers. - while (c == '[') { - at++; - c = descriptor.charAt(at); - } - - if (c == 'L') { - // It looks like the start of a class name; find the end. - int endAt = descriptor.indexOf(';', at); - if (endAt == -1) { - throw new IllegalArgumentException("bad descriptor"); - } - at = endAt + 1; - } else { - at++; - } - - params[paramCount] = - Type.intern(descriptor.substring(startAt, at)); - paramCount++; - } - - Type returnType = Type.internReturnType(descriptor.substring(at)); - StdTypeList parameterTypes = new StdTypeList(paramCount); - - for (int i = 0; i < paramCount; i++) { - parameterTypes.set(i, params[i]); - } - - result = new Prototype(descriptor, returnType, parameterTypes); - return putIntern(result); - } - - /** - * Helper for {@link #intern} which returns an empty array to - * populate with parsed parameter types, and which also ensures - * that there is a '(' at the start of the descriptor and a - * single ')' somewhere before the end. - * - * @param descriptor non-null; the descriptor string - * @return non-null; array large enough to hold all parsed parameter - * types, but which is likely actually larger than needed - */ - private static Type[] makeParameterArray(String descriptor) { - int length = descriptor.length(); - - if (descriptor.charAt(0) != '(') { - throw new IllegalArgumentException("bad descriptor"); - } - - /* - * This is a cheesy way to establish an upper bound on the - * number of parameters: Just count capital letters. - */ - int closeAt = 0; - int maxParams = 0; - for (int i = 1; i < length; i++) { - char c = descriptor.charAt(i); - if (c == ')') { - closeAt = i; - break; - } - if ((c >= 'A') && (c <= 'Z')) { - maxParams++; - } - } - - if ((closeAt == 0) || (closeAt == (length - 1))) { - throw new IllegalArgumentException("bad descriptor"); - } - - if (descriptor.indexOf(')', closeAt + 1) != -1) { - throw new IllegalArgumentException("bad descriptor"); - } - - return new Type[maxParams]; - } - - /** - * Interns an instance, adding to the descriptor as necessary based - * on the given definer, name, and flags. For example, an init - * method has an uninitialized object of type <code>definer</code> - * as its first argument. - * - * @param descriptor non-null; the descriptor string - * @param definer non-null; class the method is defined on - * @param isStatic whether this is a static method - * @param isInit whether this is an init method - * @return non-null; the interned instance - */ - public static Prototype intern(String descriptor, Type definer, - boolean isStatic, boolean isInit) { - Prototype base = intern(descriptor); - - if (isStatic) { - return base; - } - - if (isInit) { - definer = definer.asUninitialized(Integer.MAX_VALUE); - } - - return base.withFirstParameter(definer); - } - - /** - * Interns an instance which consists of the given number of - * <code>int</code>s along with the given return type - * - * @param returnType non-null; the return type - * @param count > 0; the number of elements in the prototype - * @return non-null; the interned instance - */ - public static Prototype internInts(Type returnType, int count) { - // Make the descriptor... - - StringBuffer sb = new StringBuffer(100); - - sb.append('('); - - for (int i = 0; i < count; i++) { - sb.append('I'); - } - - sb.append(')'); - sb.append(returnType.getDescriptor()); - - // ...and intern it. - return intern(sb.toString()); - } - - /** - * Constructs an instance. This is a private constructor; use one - * of the public static methods to get instances. - * - * @param descriptor non-null; the descriptor string - */ - private Prototype(String descriptor, Type returnType, - StdTypeList parameterTypes) { - if (descriptor == null) { - throw new NullPointerException("descriptor == null"); - } - - if (returnType == null) { - throw new NullPointerException("returnType == null"); - } - - if (parameterTypes == null) { - throw new NullPointerException("parameterTypes == null"); - } - - this.descriptor = descriptor; - this.returnType = returnType; - this.parameterTypes = parameterTypes; - this.parameterFrameTypes = null; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (this == other) { - /* - * Since externally-visible instances are interned, this - * check helps weed out some easy cases. - */ - return true; - } - - if (!(other instanceof Prototype)) { - return false; - } - - return descriptor.equals(((Prototype) other).descriptor); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return descriptor.hashCode(); - } - - /** {@inheritDoc} */ - public int compareTo(Prototype other) { - if (this == other) { - return 0; - } - - /* - * The return type is the major order, and then args in order, - * and then the shorter list comes first (similar to string - * sorting). - */ - - int result = returnType.compareTo(other.returnType); - - if (result != 0) { - return result; - } - - int thisSize = parameterTypes.size(); - int otherSize = other.parameterTypes.size(); - int size = Math.min(thisSize, otherSize); - - for (int i = 0; i < size; i++) { - Type thisType = parameterTypes.get(i); - Type otherType = other.parameterTypes.get(i); - - result = thisType.compareTo(otherType); - - if (result != 0) { - return result; - } - } - - if (thisSize < otherSize) { - return -1; - } else if (thisSize > otherSize) { - return 1; - } else { - return 0; - } - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return descriptor; - } - - /** - * Gets the descriptor string. - * - * @return non-null; the descriptor - */ - public String getDescriptor() { - return descriptor; - } - - /** - * Gets the return type. - * - * @return non-null; the return type - */ - public Type getReturnType() { - return returnType; - } - - /** - * Gets the list of parameter types. - * - * @return non-null; the list of parameter types - */ - public StdTypeList getParameterTypes() { - return parameterTypes; - } - - /** - * Gets the list of frame types corresponding to the list of parameter - * types. The difference between the two lists (if any) is that all - * "intlike" types (see {@link Type#isIntlike}) are replaced by - * {@link Type#INT}. - * - * @return non-null; the list of parameter frame types - */ - public StdTypeList getParameterFrameTypes() { - if (parameterFrameTypes == null) { - int sz = parameterTypes.size(); - StdTypeList list = new StdTypeList(sz); - boolean any = false; - for (int i = 0; i < sz; i++) { - Type one = parameterTypes.get(i); - if (one.isIntlike()) { - any = true; - one = Type.INT; - } - list.set(i, one); - } - parameterFrameTypes = any ? list : parameterTypes; - } - - return parameterFrameTypes; - } - - /** - * Returns a new interned instance, which is the same as this instance, - * except that it has an additional parameter prepended to the original's - * argument list. - * - * @param param non-null; the new first parameter - * @return non-null; an appropriately-constructed instance - */ - public Prototype withFirstParameter(Type param) { - String newDesc = "(" + param.getDescriptor() + descriptor.substring(1); - StdTypeList newParams = parameterTypes.withFirst(param); - - newParams.setImmutable(); - - Prototype result = - new Prototype(newDesc, returnType, newParams); - - return putIntern(result); - } - - /** - * Puts the given instance in the intern table if it's not already - * there. If a conflicting value is already in the table, then leave it. - * Return the interned value. - * - * @param desc non-null; instance to make interned - * @return non-null; the actual interned object - */ - private static Prototype putIntern(Prototype desc) { - synchronized (internTable) { - String descriptor = desc.getDescriptor(); - Prototype already = internTable.get(descriptor); - if (already != null) { - return already; - } - internTable.put(descriptor, desc); - return desc; - } - } -} diff --git a/dx/src/com/android/dx/rop/type/StdTypeList.java b/dx/src/com/android/dx/rop/type/StdTypeList.java deleted file mode 100644 index a4c2d44b0..000000000 --- a/dx/src/com/android/dx/rop/type/StdTypeList.java +++ /dev/null @@ -1,407 +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.android.dx.rop.type; - -import com.android.dx.util.FixedSizeList; - -/** - * Standard implementation of {@link TypeList}. - */ -public final class StdTypeList - extends FixedSizeList implements TypeList { - /** non-null; no-element instance */ - public static final StdTypeList EMPTY = new StdTypeList(0); - - /** non-null; the list <code>[int]</code> */ - public static final StdTypeList INT = StdTypeList.make(Type.INT); - - /** non-null; the list <code>[long]</code> */ - public static final StdTypeList LONG = StdTypeList.make(Type.LONG); - - /** non-null; the list <code>[float]</code> */ - public static final StdTypeList FLOAT = StdTypeList.make(Type.FLOAT); - - /** non-null; the list <code>[double]</code> */ - public static final StdTypeList DOUBLE = StdTypeList.make(Type.DOUBLE); - - /** non-null; the list <code>[Object]</code> */ - public static final StdTypeList OBJECT = StdTypeList.make(Type.OBJECT); - - /** non-null; the list <code>[ReturnAddress]</code> */ - public static final StdTypeList RETURN_ADDRESS - = StdTypeList.make(Type.RETURN_ADDRESS); - - /** non-null; the list <code>[Throwable]</code> */ - public static final StdTypeList THROWABLE = - StdTypeList.make(Type.THROWABLE); - - /** non-null; the list <code>[int, int]</code> */ - public static final StdTypeList INT_INT = - StdTypeList.make(Type.INT, Type.INT); - - /** non-null; the list <code>[long, long]</code> */ - public static final StdTypeList LONG_LONG = - StdTypeList.make(Type.LONG, Type.LONG); - - /** non-null; the list <code>[float, float]</code> */ - public static final StdTypeList FLOAT_FLOAT = - StdTypeList.make(Type.FLOAT, Type.FLOAT); - - /** non-null; the list <code>[double, double]</code> */ - public static final StdTypeList DOUBLE_DOUBLE = - StdTypeList.make(Type.DOUBLE, Type.DOUBLE); - - /** non-null; the list <code>[Object, Object]</code> */ - public static final StdTypeList OBJECT_OBJECT = - StdTypeList.make(Type.OBJECT, Type.OBJECT); - - /** non-null; the list <code>[int, Object]</code> */ - public static final StdTypeList INT_OBJECT = - StdTypeList.make(Type.INT, Type.OBJECT); - - /** non-null; the list <code>[long, Object]</code> */ - public static final StdTypeList LONG_OBJECT = - StdTypeList.make(Type.LONG, Type.OBJECT); - - /** non-null; the list <code>[float, Object]</code> */ - public static final StdTypeList FLOAT_OBJECT = - StdTypeList.make(Type.FLOAT, Type.OBJECT); - - /** non-null; the list <code>[double, Object]</code> */ - public static final StdTypeList DOUBLE_OBJECT = - StdTypeList.make(Type.DOUBLE, Type.OBJECT); - - /** non-null; the list <code>[long, int]</code> */ - public static final StdTypeList LONG_INT = - StdTypeList.make(Type.LONG, Type.INT); - - /** non-null; the list <code>[int[], int]</code> */ - public static final StdTypeList INTARR_INT = - StdTypeList.make(Type.INT_ARRAY, Type.INT); - - /** non-null; the list <code>[long[], int]</code> */ - public static final StdTypeList LONGARR_INT = - StdTypeList.make(Type.LONG_ARRAY, Type.INT); - - /** non-null; the list <code>[float[], int]</code> */ - public static final StdTypeList FLOATARR_INT = - StdTypeList.make(Type.FLOAT_ARRAY, Type.INT); - - /** non-null; the list <code>[double[], int]</code> */ - public static final StdTypeList DOUBLEARR_INT = - StdTypeList.make(Type.DOUBLE_ARRAY, Type.INT); - - /** non-null; the list <code>[Object[], int]</code> */ - public static final StdTypeList OBJECTARR_INT = - StdTypeList.make(Type.OBJECT_ARRAY, Type.INT); - - /** non-null; the list <code>[boolean[], int]</code> */ - public static final StdTypeList BOOLEANARR_INT = - StdTypeList.make(Type.BOOLEAN_ARRAY, Type.INT); - - /** non-null; the list <code>[byte[], int]</code> */ - public static final StdTypeList BYTEARR_INT = - StdTypeList.make(Type.BYTE_ARRAY, Type.INT); - - /** non-null; the list <code>[char[], int]</code> */ - public static final StdTypeList CHARARR_INT = - StdTypeList.make(Type.CHAR_ARRAY, Type.INT); - - /** non-null; the list <code>[short[], int]</code> */ - public static final StdTypeList SHORTARR_INT = - StdTypeList.make(Type.SHORT_ARRAY, Type.INT); - - /** non-null; the list <code>[int, int[], int]</code> */ - public static final StdTypeList INT_INTARR_INT = - StdTypeList.make(Type.INT, Type.INT_ARRAY, Type.INT); - - /** non-null; the list <code>[long, long[], int]</code> */ - public static final StdTypeList LONG_LONGARR_INT = - StdTypeList.make(Type.LONG, Type.LONG_ARRAY, Type.INT); - - /** non-null; the list <code>[float, float[], int]</code> */ - public static final StdTypeList FLOAT_FLOATARR_INT = - StdTypeList.make(Type.FLOAT, Type.FLOAT_ARRAY, Type.INT); - - /** non-null; the list <code>[double, double[], int]</code> */ - public static final StdTypeList DOUBLE_DOUBLEARR_INT = - StdTypeList.make(Type.DOUBLE, Type.DOUBLE_ARRAY, Type.INT); - - /** non-null; the list <code>[Object, Object[], int]</code> */ - public static final StdTypeList OBJECT_OBJECTARR_INT = - StdTypeList.make(Type.OBJECT, Type.OBJECT_ARRAY, Type.INT); - - /** non-null; the list <code>[int, boolean[], int]</code> */ - public static final StdTypeList INT_BOOLEANARR_INT = - StdTypeList.make(Type.INT, Type.BOOLEAN_ARRAY, Type.INT); - - /** non-null; the list <code>[int, byte[], int]</code> */ - public static final StdTypeList INT_BYTEARR_INT = - StdTypeList.make(Type.INT, Type.BYTE_ARRAY, Type.INT); - - /** non-null; the list <code>[int, char[], int]</code> */ - public static final StdTypeList INT_CHARARR_INT = - StdTypeList.make(Type.INT, Type.CHAR_ARRAY, Type.INT); - - /** non-null; the list <code>[int, short[], int]</code> */ - public static final StdTypeList INT_SHORTARR_INT = - StdTypeList.make(Type.INT, Type.SHORT_ARRAY, Type.INT); - - /** - * Makes a single-element instance. - * - * @param type non-null; the element - * @return non-null; an appropriately-constructed instance - */ - public static StdTypeList make(Type type) { - StdTypeList result = new StdTypeList(1); - result.set(0, type); - return result; - } - - /** - * Makes a two-element instance. - * - * @param type0 non-null; the first element - * @param type1 non-null; the second element - * @return non-null; an appropriately-constructed instance - */ - public static StdTypeList make(Type type0, Type type1) { - StdTypeList result = new StdTypeList(2); - result.set(0, type0); - result.set(1, type1); - return result; - } - - /** - * Makes a three-element instance. - * - * @param type0 non-null; the first element - * @param type1 non-null; the second element - * @param type2 non-null; the third element - * @return non-null; an appropriately-constructed instance - */ - public static StdTypeList make(Type type0, Type type1, Type type2) { - StdTypeList result = new StdTypeList(3); - result.set(0, type0); - result.set(1, type1); - result.set(2, type2); - return result; - } - - /** - * Makes a four-element instance. - * - * @param type0 non-null; the first element - * @param type1 non-null; the second element - * @param type2 non-null; the third element - * @param type3 non-null; the fourth element - * @return non-null; an appropriately-constructed instance - */ - public static StdTypeList make(Type type0, Type type1, Type type2, - Type type3) { - StdTypeList result = new StdTypeList(4); - result.set(0, type0); - result.set(1, type1); - result.set(2, type2); - result.set(3, type3); - return result; - } - - /** - * Returns the given list as a comma-separated list of human forms. This - * is a static method so as to work on arbitrary {@link TypeList} - * instances. - * - * @param list non-null; the list to convert - * @return non-null; the human form - */ - public static String toHuman(TypeList list) { - int size = list.size(); - - if (size == 0) { - return "<empty>"; - } - - StringBuffer sb = new StringBuffer(100); - - for (int i = 0; i < size; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(list.getType(i).toHuman()); - } - - return sb.toString(); - } - - /** - * Returns a hashcode of the contents of the given list. This - * is a static method so as to work on arbitrary {@link TypeList} - * instances. - * - * @param list non-null; the list to inspect - * @return non-null; the hash code - */ - public static int hashContents(TypeList list) { - int size = list.size(); - int hash = 0; - - for (int i = 0; i < size; i++) { - hash = (hash * 31) + list.getType(i).hashCode(); - } - - return hash; - } - - /** - * Compares the contents of the given two instances for equality. This - * is a static method so as to work on arbitrary {@link TypeList} - * instances. - * - * @param list1 non-null; one list to compare - * @param list2 non-null; another list to compare - * @return whether the two lists contain corresponding equal elements - */ - public static boolean equalContents(TypeList list1, TypeList list2) { - int size = list1.size(); - - if (list2.size() != size) { - return false; - } - - for (int i = 0; i < size; i++) { - if (! list1.getType(i).equals(list2.getType(i))) { - return false; - } - } - - return true; - } - - /** - * Compares the contents of the given two instances for ordering. This - * is a static method so as to work on arbitrary {@link TypeList} - * instances. - * - * @param list1 non-null; one list to compare - * @param list2 non-null; another list to compare - * @return the order of the two lists - */ - public static int compareContents(TypeList list1, TypeList list2) { - int size1 = list1.size(); - int size2 = list2.size(); - int size = Math.min(size1, size2); - - for (int i = 0; i < size; i++) { - int comparison = list1.getType(i).compareTo(list2.getType(i)); - if (comparison != 0) { - return comparison; - } - } - - if (size1 == size2) { - return 0; - } else if (size1 < size2) { - return -1; - } else { - return 1; - } - } - - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size the size of the list - */ - public StdTypeList(int size) { - super(size); - } - - /** {@inheritDoc} */ - public Type getType(int n) { - return get(n); - } - - /** {@inheritDoc} */ - public int getWordCount() { - int sz = size(); - int result = 0; - - for (int i = 0; i < sz; i++) { - result += get(i).getCategory(); - } - - return result; - } - - /** {@inheritDoc} */ - public TypeList withAddedType(Type type) { - int sz = size(); - StdTypeList result = new StdTypeList(sz + 1); - - for (int i = 0; i < sz; i++) { - result.set0(i, get0(i)); - } - - result.set(sz, type); - result.setImmutable(); - return result; - } - - /** - * 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</code>. - * - * @param n >= 0, < size(); which element - * @return non-null; the indicated element - */ - public Type get(int n) { - return (Type) get0(n); - } - - /** - * Sets the type at the given index. - * - * @param n >= 0, < size(); which element - * @param type non-null; the type to store - */ - public void set(int n, Type type) { - set0(n, type); - } - - /** - * Returns a new instance, which is the same as this instance, - * except that it has an additional type prepended to the - * original. - * - * @param type non-null; the new first element - * @return non-null; an appropriately-constructed instance - */ - public StdTypeList withFirst(Type type) { - int sz = size(); - StdTypeList result = new StdTypeList(sz + 1); - - result.set0(0, type); - for (int i = 0; i < sz; i++) { - result.set0(i + 1, getOrNull0(i)); - } - - return result; - } -} diff --git a/dx/src/com/android/dx/rop/type/Type.java b/dx/src/com/android/dx/rop/type/Type.java deleted file mode 100644 index 09ea2e26d..000000000 --- a/dx/src/com/android/dx/rop/type/Type.java +++ /dev/null @@ -1,855 +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.android.dx.rop.type; - -import com.android.dx.util.Hex; - -import java.util.HashMap; - -/** - * Representation of a value type, such as may appear in a field, in a - * local, on a stack, or in a method descriptor. Instances of this - * class are generally interned and may be usefully compared with each - * other using <code>==</code>. - */ -public final class Type implements TypeBearer, Comparable<Type> { - /** non-null; intern table mapping string descriptors to instances */ - private static final HashMap<String, Type> internTable = - new HashMap<String, Type>(500); - - /** basic type constant for <code>void</code> */ - public static final int BT_VOID = 0; - - /** basic type constant for <code>boolean</code> */ - public static final int BT_BOOLEAN = 1; - - /** basic type constant for <code>byte</code> */ - public static final int BT_BYTE = 2; - - /** basic type constant for <code>char</code> */ - public static final int BT_CHAR = 3; - - /** basic type constant for <code>double</code> */ - public static final int BT_DOUBLE = 4; - - /** basic type constant for <code>float</code> */ - public static final int BT_FLOAT = 5; - - /** basic type constant for <code>int</code> */ - public static final int BT_INT = 6; - - /** basic type constant for <code>long</code> */ - public static final int BT_LONG = 7; - - /** basic type constant for <code>short</code> */ - public static final int BT_SHORT = 8; - - /** basic type constant for <code>Object</code> */ - public static final int BT_OBJECT = 9; - - /** basic type constant for a return address */ - public static final int BT_ADDR = 10; - - /** count of basic type constants */ - public static final int BT_COUNT = 11; - - /** non-null; instance representing <code>boolean</code> */ - public static final Type BOOLEAN = new Type("Z", BT_BOOLEAN); - - /** non-null; instance representing <code>byte</code> */ - public static final Type BYTE = new Type("B", BT_BYTE); - - /** non-null; instance representing <code>char</code> */ - public static final Type CHAR = new Type("C", BT_CHAR); - - /** non-null; instance representing <code>double</code> */ - public static final Type DOUBLE = new Type("D", BT_DOUBLE); - - /** non-null; instance representing <code>float</code> */ - public static final Type FLOAT = new Type("F", BT_FLOAT); - - /** non-null; instance representing <code>int</code> */ - public static final Type INT = new Type("I", BT_INT); - - /** non-null; instance representing <code>long</code> */ - public static final Type LONG = new Type("J", BT_LONG); - - /** non-null; instance representing <code>short</code> */ - public static final Type SHORT = new Type("S", BT_SHORT); - - /** non-null; instance representing <code>void</code> */ - public static final Type VOID = new Type("V", BT_VOID); - - /** non-null; instance representing a known-<code>null</code> */ - public static final Type KNOWN_NULL = new Type("<null>", BT_OBJECT); - - /** non-null; instance representing a subroutine return address */ - public static final Type RETURN_ADDRESS = new Type("<addr>", BT_ADDR); - - static { - /* - * Put all the primitive types into the intern table. This needs - * to happen before the array types below get interned. - */ - putIntern(BOOLEAN); - putIntern(BYTE); - putIntern(CHAR); - putIntern(DOUBLE); - putIntern(FLOAT); - putIntern(INT); - putIntern(LONG); - putIntern(SHORT); - /* - * Note: VOID isn't put in the intern table, since it's special and - * shouldn't be found by a normal call to intern(). - */ - } - - /** - * non-null; instance representing - * <code>java.lang.annotation.Annotation</code> - */ - public static final Type ANNOTATION = - intern("Ljava/lang/annotation/Annotation;"); - - /** non-null; instance representing <code>java.lang.Class</code> */ - public static final Type CLASS = intern("Ljava/lang/Class;"); - - /** non-null; instance representing <code>java.lang.Cloneable</code> */ - public static final Type CLONEABLE = intern("Ljava/lang/Cloneable;"); - - /** non-null; instance representing <code>java.lang.Object</code> */ - public static final Type OBJECT = intern("Ljava/lang/Object;"); - - /** non-null; instance representing <code>java.io.Serializable</code> */ - public static final Type SERIALIZABLE = intern("Ljava/io/Serializable;"); - - /** non-null; instance representing <code>java.lang.String</code> */ - public static final Type STRING = intern("Ljava/lang/String;"); - - /** non-null; instance representing <code>java.lang.Throwable</code> */ - public static final Type THROWABLE = intern("Ljava/lang/Throwable;"); - - /** - * non-null; instance representing <code>java.lang.Boolean</code>; the - * suffix on the name helps disambiguate this from the instance - * representing a primitive type - */ - public static final Type BOOLEAN_CLASS = intern("Ljava/lang/Boolean;"); - - /** - * non-null; instance representing <code>java.lang.Byte</code>; the - * suffix on the name helps disambiguate this from the instance - * representing a primitive type - */ - public static final Type BYTE_CLASS = intern("Ljava/lang/Byte;"); - - /** - * non-null; instance representing <code>java.lang.Character</code>; the - * suffix on the name helps disambiguate this from the instance - * representing a primitive type - */ - public static final Type CHARACTER_CLASS = intern("Ljava/lang/Character;"); - - /** - * non-null; instance representing <code>java.lang.Double</code>; the - * suffix on the name helps disambiguate this from the instance - * representing a primitive type - */ - public static final Type DOUBLE_CLASS = intern("Ljava/lang/Double;"); - - /** - * non-null; instance representing <code>java.lang.Float</code>; the - * suffix on the name helps disambiguate this from the instance - * representing a primitive type - */ - public static final Type FLOAT_CLASS = intern("Ljava/lang/Float;"); - - /** - * non-null; instance representing <code>java.lang.Integer</code>; the - * suffix on the name helps disambiguate this from the instance - * representing a primitive type - */ - public static final Type INTEGER_CLASS = intern("Ljava/lang/Integer;"); - - /** - * non-null; instance representing <code>java.lang.Long</code>; the - * suffix on the name helps disambiguate this from the instance - * representing a primitive type - */ - public static final Type LONG_CLASS = intern("Ljava/lang/Long;"); - - /** - * non-null; instance representing <code>java.lang.Short</code>; the - * suffix on the name helps disambiguate this from the instance - * representing a primitive type - */ - public static final Type SHORT_CLASS = intern("Ljava/lang/Short;"); - - /** - * non-null; instance representing <code>java.lang.Void</code>; the - * suffix on the name helps disambiguate this from the instance - * representing a primitive type - */ - public static final Type VOID_CLASS = intern("Ljava/lang/Void;"); - - /** non-null; instance representing <code>boolean[]</code> */ - public static final Type BOOLEAN_ARRAY = BOOLEAN.getArrayType(); - - /** non-null; instance representing <code>byte[]</code> */ - public static final Type BYTE_ARRAY = BYTE.getArrayType(); - - /** non-null; instance representing <code>char[]</code> */ - public static final Type CHAR_ARRAY = CHAR.getArrayType(); - - /** non-null; instance representing <code>double[]</code> */ - public static final Type DOUBLE_ARRAY = DOUBLE.getArrayType(); - - /** non-null; instance representing <code>float[]</code> */ - public static final Type FLOAT_ARRAY = FLOAT.getArrayType(); - - /** non-null; instance representing <code>int[]</code> */ - public static final Type INT_ARRAY = INT.getArrayType(); - - /** non-null; instance representing <code>long[]</code> */ - public static final Type LONG_ARRAY = LONG.getArrayType(); - - /** non-null; instance representing <code>Object[]</code> */ - public static final Type OBJECT_ARRAY = OBJECT.getArrayType(); - - /** non-null; instance representing <code>short[]</code> */ - public static final Type SHORT_ARRAY = SHORT.getArrayType(); - - /** non-null; field descriptor for the type */ - private final String descriptor; - - /** - * basic type corresponding to this type; one of the - * <code>BT_*</code> constants - */ - private final int basicType; - - /** - * >= -1; for an uninitialized type, bytecode index that this - * instance was allocated at; <code>Integer.MAX_VALUE</code> if it - * was an incoming uninitialized instance; <code>-1</code> if this - * is an <i>inititialized</i> instance - */ - private final int newAt; - - /** - * null-ok; the internal-form class name corresponding to this type, if - * calculated; only valid if <code>this</code> is a reference type and - * additionally not a return address - */ - private String className; - - /** - * null-ok; the type corresponding to an array of this type, if - * calculated - */ - private Type arrayType; - - /** - * null-ok; the type corresponding to elements of this type, if - * calculated; only valid if <code>this</code> is an array type - */ - private Type componentType; - - /** - * null-ok; the type corresponding to the initialized version of - * this type, if this instance is in fact an uninitialized type - */ - private Type initializedType; - - /** - * Returns the unique instance corresponding to the type with the - * given descriptor. See vmspec-2 sec4.3.2 for details on the - * field descriptor syntax. This method does <i>not</i> allow - * <code>"V"</code> (that is, type <code>void</code>) as a valid - * descriptor. - * - * @param descriptor non-null; the descriptor - * @return non-null; the corresponding instance - * @throws IllegalArgumentException thrown if the descriptor has - * invalid syntax - */ - public static Type intern(String descriptor) { - Type result = internTable.get(descriptor); - if (result != null) { - return result; - } - - char firstChar; - try { - firstChar = descriptor.charAt(0); - } catch (IndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("descriptor is empty"); - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("descriptor == null"); - } - - if (firstChar == '[') { - /* - * Recursively strip away array markers to get at the underlying - * type, and build back on to form the result. - */ - result = intern(descriptor.substring(1)); - return result.getArrayType(); - } - - /* - * If the first character isn't '[' and it wasn't found in the - * intern cache, then it had better be the descriptor for a class. - */ - - int length = descriptor.length(); - if ((firstChar != 'L') || - (descriptor.charAt(length - 1) != ';')) { - throw new IllegalArgumentException("bad descriptor"); - } - - /* - * Validate the characters of the class name itself. Note that - * vmspec-2 does not have a coherent definition for valid - * internal-form class names, and the definition here is fairly - * liberal: A name is considered valid as long as it doesn't - * contain any of '[' ';' '.' '(' ')', and it has no more than one - * '/' in a row, and no '/' at either end. - */ - - int limit = (length - 1); // Skip the final ';'. - for (int i = 1; i < limit; i++) { - char c = descriptor.charAt(i); - switch (c) { - case '[': - case ';': - case '.': - case '(': - case ')': { - throw new IllegalArgumentException("bad descriptor"); - } - case '/': { - if ((i == 1) || - (i == (length - 1)) || - (descriptor.charAt(i - 1) == '/')) { - throw new IllegalArgumentException("bad descriptor"); - } - break; - } - } - } - - result = new Type(descriptor, BT_OBJECT); - return putIntern(result); - } - - /** - * Returns the unique instance corresponding to the type with the - * given descriptor, allowing <code>"V"</code> to return the type - * for <code>void</code>. Other than that one caveat, this method - * is identical to {@link #intern}. - * - * @param descriptor non-null; the descriptor - * @return non-null; the corresponding instance - * @throws IllegalArgumentException thrown if the descriptor has - * invalid syntax - */ - public static Type internReturnType(String descriptor) { - try { - if (descriptor.equals("V")) { - // This is the one special case where void may be returned. - return VOID; - } - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("descriptor == null"); - } - - return intern(descriptor); - } - - /** - * Returns the unique instance corresponding to the type of the - * class with the given name. Calling this method is equivalent to - * calling <code>intern(name)</code> if <code>name</code> begins - * with <code>"["</code> and calling <code>intern("L" + name + ";")</code> - * in all other cases. - * - * @param name non-null; the name of the class whose type is desired - * @return non-null; the corresponding type - * @throws IllegalArgumentException thrown if the name has - * invalid syntax - */ - public static Type internClassName(String name) { - if (name == null) { - throw new NullPointerException("name == null"); - } - - if (name.startsWith("[")) { - return intern(name); - } - - return intern('L' + name + ';'); - } - - /** - * Constructs an instance corresponding to an "uninitialized type." - * This is a private constructor; use one of the public static - * methods to get instances. - * - * @param descriptor non-null; the field descriptor for the type - * @param basicType basic type corresponding to this type; one of the - * <code>BT_*</code> constants - * @param newAt >= -1 allocation bytecode index - */ - private Type(String descriptor, int basicType, int newAt) { - if (descriptor == null) { - throw new NullPointerException("descriptor == null"); - } - - if ((basicType < 0) || (basicType >= BT_COUNT)) { - throw new IllegalArgumentException("bad basicType"); - } - - if (newAt < -1) { - throw new IllegalArgumentException("newAt < -1"); - } - - this.descriptor = descriptor; - this.basicType = basicType; - this.newAt = newAt; - this.arrayType = null; - this.componentType = null; - this.initializedType = null; - } - - /** - * Constructs an instance corresponding to an "initialized type." - * This is a private constructor; use one of the public static - * methods to get instances. - * - * @param descriptor non-null; the field descriptor for the type - * @param basicType basic type corresponding to this type; one of the - * <code>BT_*</code> constants - */ - private Type(String descriptor, int basicType) { - this(descriptor, basicType, -1); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (this == other) { - /* - * Since externally-visible types are interned, this check - * helps weed out some easy cases. - */ - return true; - } - - if (!(other instanceof Type)) { - return false; - } - - return descriptor.equals(((Type) other).descriptor); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return descriptor.hashCode(); - } - - /** {@inheritDoc} */ - public int compareTo(Type other) { - return descriptor.compareTo(other.descriptor); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return descriptor; - } - - /** {@inheritDoc} */ - public String toHuman() { - switch (basicType) { - case BT_VOID: return "void"; - case BT_BOOLEAN: return "boolean"; - case BT_BYTE: return "byte"; - case BT_CHAR: return "char"; - case BT_DOUBLE: return "double"; - case BT_FLOAT: return "float"; - case BT_INT: return "int"; - case BT_LONG: return "long"; - case BT_SHORT: return "short"; - case BT_OBJECT: break; - default: return descriptor; - } - - if (isArray()) { - return getComponentType().toHuman() + "[]"; - } - - // Remove the "L...;" around the type and convert "/" to ".". - return getClassName().replace("/", "."); - } - - /** {@inheritDoc} */ - public Type getType() { - return this; - } - - /** {@inheritDoc} */ - public Type getFrameType() { - switch (basicType) { - case BT_BOOLEAN: - case BT_BYTE: - case BT_CHAR: - case BT_INT: - case BT_SHORT: { - return INT; - } - } - - return this; - } - - /** {@inheritDoc} */ - public int getBasicType() { - return basicType; - } - - /** {@inheritDoc} */ - public int getBasicFrameType() { - switch (basicType) { - case BT_BOOLEAN: - case BT_BYTE: - case BT_CHAR: - case BT_INT: - case BT_SHORT: { - return BT_INT; - } - } - - return basicType; - } - - /** {@inheritDoc} */ - public boolean isConstant() { - return false; - } - - /** - * Gets the descriptor. - * - * @return non-null; the descriptor - */ - public String getDescriptor() { - return descriptor; - } - - /** - * Gets the name of the class this type corresponds to, in internal - * form. This method is only valid if this instance is for a - * normal reference type (that is, a reference type and - * additionally not a return address). - * - * @return non-null; the internal-form class name - */ - public String getClassName() { - if (className == null) { - if (!isReference()) { - throw new IllegalArgumentException("not an object type: " + - descriptor); - } - - if (descriptor.charAt(0) == '[') { - className = descriptor; - } else { - className = descriptor.substring(1, descriptor.length() - 1); - } - } - - return className; - } - - /** - * Gets the category. Most instances are category 1. <code>long</code> - * and <code>double</code> are the only category 2 types. - * - * @see #isCategory1 - * @see #isCategory2 - * @return the category - */ - public int getCategory() { - switch (basicType) { - case BT_LONG: - case BT_DOUBLE: { - return 2; - } - } - - return 1; - } - - /** - * Returns whether or not this is a category 1 type. - * - * @see #getCategory - * @see #isCategory2 - * @return whether or not this is a category 1 type - */ - public boolean isCategory1() { - switch (basicType) { - case BT_LONG: - case BT_DOUBLE: { - return false; - } - } - - return true; - } - - /** - * Returns whether or not this is a category 2 type. - * - * @see #getCategory - * @see #isCategory1 - * @return whether or not this is a category 2 type - */ - public boolean isCategory2() { - switch (basicType) { - case BT_LONG: - case BT_DOUBLE: { - return true; - } - } - - return false; - } - - /** - * Gets whether this type is "intlike." An intlike type is one which, when - * placed on a stack or in a local, is automatically converted to an - * <code>int</code>. - * - * @return whether this type is "intlike" - */ - public boolean isIntlike() { - switch (basicType) { - case BT_BOOLEAN: - case BT_BYTE: - case BT_CHAR: - case BT_INT: - case BT_SHORT: { - return true; - } - } - - return false; - } - - /** - * Gets whether this type is a primitive type. All types are either - * primitive or reference types. - * - * @return whether this type is primitive - */ - public boolean isPrimitive() { - switch (basicType) { - case BT_BOOLEAN: - case BT_BYTE: - case BT_CHAR: - case BT_DOUBLE: - case BT_FLOAT: - case BT_INT: - case BT_LONG: - case BT_SHORT: - case BT_VOID: { - return true; - } - } - - return false; - } - - /** - * Gets whether this type is a normal reference type. A normal - * reference type is a reference type that is not a return - * address. This method is just convenient shorthand for - * <code>getBasicType() == Type.BT_OBJECT</code>. - * - * @return whether this type is a normal reference type - */ - public boolean isReference() { - return (basicType == BT_OBJECT); - } - - /** - * Gets whether this type is an array type. If this method returns - * <code>true</code>, then it is safe to use {@link #getComponentType} - * to determine the component type. - * - * @return whether this type is an array type - */ - public boolean isArray() { - return (descriptor.charAt(0) == '['); - } - - /** - * Gets whether this type is an array type or is a known-null, and - * hence is compatible with array types. - * - * @return whether this type is an array type - */ - public boolean isArrayOrKnownNull() { - return isArray() || equals(KNOWN_NULL); - } - - /** - * Gets whether this type represents an uninitialized instance. An - * uninitialized instance is what one gets back from the <code>new</code> - * opcode, and remains uninitialized until a valid constructor is - * invoked on it. - * - * @return whether this type is "uninitialized" - */ - public boolean isUninitialized() { - return (newAt >= 0); - } - - /** - * Gets the bytecode index at which this uninitialized type was - * allocated. This returns <code>Integer.MAX_VALUE</code> if this - * type is an uninitialized incoming parameter (i.e., the - * <code>this</code> of an <code><init></code> method) or - * <code>-1</code> if this type is in fact <i>initialized</i>. - * - * @return >= -1; the allocation bytecode index - */ - public int getNewAt() { - return newAt; - } - - /** - * Gets the initialized type corresponding to this instance, but only - * if this instance is in fact an uninitialized object type. - * - * @return non-null; the initialized type - */ - public Type getInitializedType() { - if (initializedType == null) { - throw new IllegalArgumentException("initialized type: " + - descriptor); - } - - return initializedType; - } - - /** - * Gets the type corresponding to an array of this type. - * - * @return non-null; the array type - */ - public Type getArrayType() { - if (arrayType == null) { - arrayType = putIntern(new Type('[' + descriptor, BT_OBJECT)); - } - - return arrayType; - } - - /** - * Gets the component type of this type. This method is only valid on - * array types. - * - * @return non-null; the component type - */ - public Type getComponentType() { - if (componentType == null) { - if (descriptor.charAt(0) != '[') { - throw new IllegalArgumentException("not an array type: " + - descriptor); - } - componentType = intern(descriptor.substring(1)); - } - - return componentType; - } - - /** - * Returns a new interned instance which is identical to this one, except - * it is indicated as uninitialized and allocated at the given bytecode - * index. This instance must be an initialized object type. - * - * @param newAt >= 0; the allocation bytecode index - * @return non-null; an appropriately-constructed instance - */ - public Type asUninitialized(int newAt) { - if (newAt < 0) { - throw new IllegalArgumentException("newAt < 0"); - } - - if (!isReference()) { - throw new IllegalArgumentException("not a reference type: " + - descriptor); - } - - if (isUninitialized()) { - /* - * Dealing with uninitialized types as a starting point is - * a pain, and it's not clear that it'd ever be used, so - * just disallow it. - */ - throw new IllegalArgumentException("already uninitialized: " + - descriptor); - } - - /* - * Create a new descriptor that is unique and shouldn't conflict - * with "normal" type descriptors - */ - String newDesc = 'N' + Hex.u2(newAt) + descriptor; - Type result = new Type(newDesc, BT_OBJECT, newAt); - result.initializedType = this; - return putIntern(result); - } - - /** - * Puts the given instance in the intern table if it's not already - * there. If a conflicting value is already in the table, then leave it. - * Return the interned value. - * - * @param type non-null; instance to make interned - * @return non-null; the actual interned object - */ - private static Type putIntern(Type type) { - synchronized (internTable) { - String descriptor = type.getDescriptor(); - Type already = internTable.get(descriptor); - if (already != null) { - return already; - } - internTable.put(descriptor, type); - return type; - } - } -} diff --git a/dx/src/com/android/dx/rop/type/TypeBearer.java b/dx/src/com/android/dx/rop/type/TypeBearer.java deleted file mode 100644 index b9e4ea576..000000000 --- a/dx/src/com/android/dx/rop/type/TypeBearer.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.android.dx.rop.type; - -import com.android.dx.util.ToHuman; - -/** - * Object which has an associated type, possibly itself. - */ -public interface TypeBearer - extends ToHuman { - /** - * Gets the type associated with this instance. - * - * @return non-null; the type - */ - public Type getType(); - - /** - * Gets the frame type corresponding to this type. This method returns - * <code>this</code>, except if {@link Type#isIntlike} on the underlying - * type returns <code>true</code> but the underlying type is not in - * fact {@link Type#INT}, in which case this method returns an instance - * whose underlying type <i>is</i> <code>INT</code>. - * - * @return non-null; the frame type for this instance - */ - public TypeBearer getFrameType(); - - /** - * Gets the basic type corresponding to this instance. - * - * @return the basic type; one of the <code>BT_*</code> constants - * defined by {@link Type} - */ - public int getBasicType(); - - /** - * Gets the basic type corresponding to this instance's frame type. This - * is equivalent to <code>getFrameType().getBasicType()</code>, and - * is the same as calling <code>getFrameType()</code> unless this - * instance is an int-like type, in which case this method returns - * <code>BT_INT</code>. - * - * @see #getBasicType - * @see #getFrameType - * - * @return the basic frame type; one of the <code>BT_*</code> constants - * defined by {@link Type} - */ - public int getBasicFrameType(); - - /** - * Returns whether this instance represents a constant value. - * - * @return <code>true</code> if this instance represents a constant value - * and <code>false</code> if not - */ - public boolean isConstant(); -} diff --git a/dx/src/com/android/dx/rop/type/TypeList.java b/dx/src/com/android/dx/rop/type/TypeList.java deleted file mode 100644 index 0944fe271..000000000 --- a/dx/src/com/android/dx/rop/type/TypeList.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.android.dx.rop.type; - -/** - * List of {@link Type} instances (or of things that contain types). - */ -public interface TypeList { - /** - * Returns whether this instance is mutable. Note that the - * <code>TypeList</code> interface itself doesn't provide any - * means of mutation, but that doesn't mean that there isn't an - * extra-interface way of mutating an instance. - * - * @return <code>true</code> if this instance is mutable or - * <code>false</code> if it is immutable - */ - public boolean isMutable(); - - /** - * Gets the size of this list. - * - * @return >= 0; the size - */ - public int 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</code>. - * - * @param n >= 0, < size(); which element - * @return non-null; the indicated element - */ - public Type getType(int n); - - /** - * Gets the number of 32-bit words required to hold instances of - * all the elements of this list. This is a sum of the widths (categories) - * of all the elements. - * - * @return >= 0; the required number of words - */ - public int getWordCount(); - - /** - * Returns a new instance which is identical to this one, except that - * the given item is appended to the end and it is guaranteed to be - * immutable. - * - * @param type non-null; item to append - * @return non-null; an appropriately-constructed instance - */ - public TypeList withAddedType(Type type); -} diff --git a/dx/src/com/android/dx/rop/type/package.html b/dx/src/com/android/dx/rop/type/package.html deleted file mode 100644 index 93d9d5f0b..000000000 --- a/dx/src/com/android/dx/rop/type/package.html +++ /dev/null @@ -1,8 +0,0 @@ -<body> -<p>Implementation of classes that represent types (classes or primitives).</p> - -<p><b>PACKAGES USED:</b> -<ul> -<li><code>com.android.dx.util</code></li> -</ul> -</body> diff --git a/dx/src/com/android/dx/ssa/BasicRegisterMapper.java b/dx/src/com/android/dx/ssa/BasicRegisterMapper.java deleted file mode 100644 index 86fcf8131..000000000 --- a/dx/src/com/android/dx/ssa/BasicRegisterMapper.java +++ /dev/null @@ -1,127 +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.android.dx.ssa; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.util.IntList; - -/** - * This class maps one register space into another, with - * each mapping built up individually and added via addMapping() - */ -public class BasicRegisterMapper - extends RegisterMapper { - - /** indexed by old register, containing new name */ - private IntList oldToNew; - - /** Running count of used registers in new namespace */ - private int runningCountNewRegisters; - - /** - * Creates a new OneToOneRegisterMapper - * @param countOldRegisters the number of registers in the old name space - */ - public BasicRegisterMapper(int countOldRegisters) { - oldToNew = new IntList(countOldRegisters); - } - - /** {@inheritDoc} */ - @Override - public int getNewRegisterCount() { - return runningCountNewRegisters; - } - - /** {@inheritDoc} */ - @Override - public RegisterSpec map(RegisterSpec registerSpec) { - if (registerSpec == null) { - return null; - } - - int newReg; - try { - newReg = oldToNew.get(registerSpec.getReg()); - } catch (IndexOutOfBoundsException ex) { - newReg = -1; - } - - if (newReg < 0) { - throw new RuntimeException("no mapping specified for register"); - } - - return registerSpec.withReg(newReg); - } - - /** - * Returns the new-namespace mapping for the specified - * old-namespace register, or -1 if one exists - * - * @param oldReg >=0; old-namespace register - * @return new-namespace register or -1 if none. - */ - public int oldToNew(int oldReg) { - if(oldReg >= oldToNew.size()) { - return -1; - } - return oldToNew.get(oldReg); - } - - /** {@inheritDoc} */ - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - sb.append("Old\tNew\n"); - int sz = oldToNew.size(); - for(int i = 0; i < sz; i++) { - sb.append(i); - sb.append('\t'); - sb.append(oldToNew.get(i)); - sb.append('\n'); - } - - sb.append("new reg count:"); - - sb.append(runningCountNewRegisters); - sb.append('\n'); - - return sb.toString(); - } - - /** - * adds a mapping to the mapper. If oldReg has already been mapped, - * overwrites previous mapping with new mapping. - * - * @param oldReg >=0 - * @param newReg >=0 - * @param category width of reg (1 or 2) - */ - public void addMapping(int oldReg, int newReg, int category) { - if (oldReg >= oldToNew.size()) { - // expand the array as necessary - for (int i = oldReg - oldToNew.size(); i >= 0; i--) { - oldToNew.add(-1); - } - } - oldToNew.set(oldReg, newReg); - - if (runningCountNewRegisters < (newReg + category)) { - runningCountNewRegisters = newReg + category; - } - } -} diff --git a/dx/src/com/android/dx/ssa/ConstCollector.java b/dx/src/com/android/dx/ssa/ConstCollector.java deleted file mode 100644 index afdede7c2..000000000 --- a/dx/src/com/android/dx/ssa/ConstCollector.java +++ /dev/null @@ -1,378 +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.android.dx.ssa; - -import com.android.dx.rop.code.*; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.TypedConstant; -import com.android.dx.rop.cst.CstString; - -import java.util.HashMap; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; - -/** - * Collects constants that are used more than once at the top of the - * method block. This increases register usage by about 5% but decreases - * insn size by about 3%. - */ -public class ConstCollector { - - /** Maximum constants to collect per method. Puts cap on reg use */ - private static final int MAX_COLLECTED_CONSTANTS = 5; - - /** - * Also collect string consts, although they can throw exceptions. - * This is off now because it just doesn't seem to gain a whole lot. - * TODO if you turn this on, you must change SsaInsn.hasSideEffect() - * to return false for const-string insns whose exceptions are not - * caught in the current method. - */ - private static boolean COLLECT_STRINGS = false; - - /** - * If true, allow one local var to be involved with a collected const. - * Turned off because it mostly just inserts more moves. - */ - private static boolean COLLECT_ONE_LOCAL = false; - - /** method we're processing */ - private final SsaMethod ssaMeth; - - /** - * Process a method. - * - * @param ssaMethod non-null; method to process - */ - public static void process(SsaMethod ssaMethod) { - ConstCollector dc; - - dc = new ConstCollector(ssaMethod); - - dc.run(); - } - - private ConstCollector(SsaMethod ssaMethod) { - this.ssaMeth = ssaMethod; - } - - /** - * Applies the optimization. - */ - private void run() { - int regSz = ssaMeth.getRegCount(); - - ArrayList<TypedConstant> constantList - = getConstsSortedByCountUse(); - - int toCollect = Math.min(constantList.size(), MAX_COLLECTED_CONSTANTS); - - SsaBasicBlock start = ssaMeth.getEntryBlock(); - - // Constant to new register containing the constant - HashMap<TypedConstant, RegisterSpec> newRegs - = new HashMap<TypedConstant, RegisterSpec> (toCollect); - - for (int i = 0; i < toCollect; i++) { - TypedConstant cst = constantList.get(i); - RegisterSpec result - = RegisterSpec.make(ssaMeth.makeNewSsaReg(), cst); - - Rop constRop = Rops.opConst(cst); - - if (constRop.getBranchingness() == Rop.BRANCH_NONE) { - start.addInsnToHead( - new PlainCstInsn(Rops.opConst(cst), - SourcePosition.NO_INFO, result, - RegisterSpecList.EMPTY, cst)); - } else { - // We need two new basic blocks along with the new insn - SsaBasicBlock entryBlock = ssaMeth.getEntryBlock(); - SsaBasicBlock successorBlock - = entryBlock.getPrimarySuccessor(); - - /* - * Insert a block containing the const insn - */ - SsaBasicBlock constBlock - = entryBlock.insertNewSuccessor(successorBlock); - - constBlock.replaceLastInsn( - new ThrowingCstInsn(constRop, SourcePosition.NO_INFO, - RegisterSpecList.EMPTY, - StdTypeList.EMPTY, cst)); - - /* - * Insert a block containing the move-result-pseudo insn - */ - - SsaBasicBlock resultBlock - = constBlock.insertNewSuccessor(successorBlock); - - resultBlock.addInsnToHead( - new PlainInsn( - Rops.opMoveResultPseudo(result.getTypeBearer()), - SourcePosition.NO_INFO, - result, RegisterSpecList.EMPTY)); - } - - newRegs.put(cst, result); - } - - updateConstUses(newRegs, regSz); - } - - /** - * Gets all of the collectable constant values used in this method, - * sorted by most used first. Skips non-collectable consts, such as - * non-string object constants - * - * @return non-null; list of constants in most-to-least used order - */ - private ArrayList<TypedConstant> getConstsSortedByCountUse() { - int regSz = ssaMeth.getRegCount(); - - final HashMap<TypedConstant, Integer> countUses - = new HashMap<TypedConstant, Integer>(); - - // Each collected constant can be used by just one local - // (used only if COLLECT_ONE_LOCAL is true) - final HashSet<TypedConstant> usedByLocal - = new HashSet<TypedConstant>(); - - // Count how many times each const value is used - for (int i = 0; i < regSz; i++) { - SsaInsn insn = ssaMeth.getDefinitionForRegister(i); - - if (insn == null) continue; - - RegisterSpec result = insn.getResult(); - - TypeBearer typeBearer = insn.getResult().getTypeBearer(); - - if (!typeBearer.isConstant()) continue; - - TypedConstant cst = (TypedConstant) typeBearer; - - if (insn.canThrow()) { - /* - * Don't move anything other than strings -- the risk - * of changing where an exception is thrown is too high. - */ - if (!(cst instanceof CstString) || !COLLECT_STRINGS) { - continue; - } - /* - * We can't move any throwable const whose throw will be caught, - * so don't count them. - */ - if (insn.getBlock().getSuccessors().cardinality() > 1) { - continue; - } - } - - // TODO might be nice to try and figure out which local wins most - // when collected - if (ssaMeth.isRegALocal(result)) { - if (!COLLECT_ONE_LOCAL) { - continue; - } else { - if (usedByLocal.contains(cst)) { - // Count one local usage only - continue; - } else { - usedByLocal.add(cst); - } - } - } - - Integer has = countUses.get(cst); - if (has == null) { - countUses.put(cst, 1); - } else { - countUses.put(cst, has + 1); - } - } - - // Collect constants that have been reused - Iterator<TypedConstant> it = countUses.keySet().iterator(); - ArrayList<TypedConstant> constantList = new ArrayList<TypedConstant>(); - while (it.hasNext()) { - TypedConstant cst = it.next(); - - if (countUses.get(cst) > 1) { - constantList.add(cst); - } - } - - // Sort by use, with most used at the beginning of the list - Collections.sort(constantList, new Comparator<Constant>() { - public int compare(Constant a, Constant b) { - int ret; - ret = countUses.get(b) - countUses.get(a); - - if (ret == 0) { - /* - * Provide sorting determinisim for constants with same - * usage count. - */ - ret = a.compareTo(b); - } - - return ret; - } - public boolean equals (Object obj) { - return obj == this; - } - }); - return constantList; - } - - /** - * Inserts mark-locals if necessary when changing a register. If - * the definition of <code>origReg</code> is associated with a local - * variable, then insert a mark-local for <code>newReg</code> just below - * it. We expect the definition of <code>origReg</code> to ultimately - * be removed by the dead code eliminator - * - * @param origReg non-null; original register - * @param newReg non-null; new register that will replace - * <code>origReg</code> - */ - private void fixLocalAssignment(RegisterSpec origReg, RegisterSpec newReg) { - for (SsaInsn use: ssaMeth.getUseListForRegister(origReg.getReg())) { - RegisterSpec localAssignment = use.getLocalAssignment(); - if (localAssignment == null) { - continue; - } - - if (use.getResult() == null) { - // this is a mark-local. it will be updated when all uses - // are updated - continue; - } - - LocalItem local = localAssignment.getLocalItem(); - - /* - * un-associate original use - */ - use.setResultLocal(null); - - /* - * now add a mark-local to the new reg immediately after - */ - newReg = newReg.withLocalItem(local); - - SsaInsn newInsn - = SsaInsn.makeFromRop( - new PlainInsn(Rops.opMarkLocal(newReg), - SourcePosition.NO_INFO, null, - RegisterSpecList.make(newReg)), - use.getBlock()); - - ArrayList<SsaInsn> insns = use.getBlock().getInsns(); - - insns.add(insns.indexOf(use) + 1, newInsn); - } - } - - /** - * Updates all uses of various consts to use the values in the newly - * assigned registers. - * - * @param newRegs non-null; mapping between constant and new reg - * @param origRegCount >=0; original SSA reg count, not including - * newly added constant regs - */ - private void updateConstUses(HashMap<TypedConstant, RegisterSpec> newRegs, - int origRegCount) { - - // Set of constants associated with a local variable - // Used only if COLLECT_ONE_LOCAL is true - final HashSet<TypedConstant> usedByLocal - = new HashSet<TypedConstant>(); - - final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy(); - - for (int i = 0; i < origRegCount; i++) { - SsaInsn insn = ssaMeth.getDefinitionForRegister(i); - - if (insn == null) { - continue; - } - - final RegisterSpec origReg = insn.getResult(); - TypeBearer typeBearer = insn.getResult().getTypeBearer(); - - if (!typeBearer.isConstant()) continue; - - TypedConstant cst = (TypedConstant) typeBearer; - final RegisterSpec newReg = newRegs.get(cst); - - if (newReg == null) { - continue; - } - - if (ssaMeth.isRegALocal(origReg)) { - if (!COLLECT_ONE_LOCAL) { - continue; - } else { - // TODO if the same local gets the same cst multiple times, - // it would be nice to reuse the register - if (usedByLocal.contains(cst)) { - continue; - } else { - usedByLocal.add(cst); - fixLocalAssignment(origReg, newRegs.get(cst)); - } - } - } - - // Maps an original const register to the new collected register - RegisterMapper mapper = new RegisterMapper() { - @Override - public int getNewRegisterCount() { - return ssaMeth.getRegCount(); - } - - @Override - public RegisterSpec map(RegisterSpec registerSpec) { - if (registerSpec.getReg() == origReg.getReg()) { - return newReg.withLocalItem(registerSpec.getLocalItem()); - } - - return registerSpec; - } - }; - - for (SsaInsn use: useList[origReg.getReg()]) { - if (use.canThrow() - && use.getBlock().getSuccessors().cardinality() > 1) { - continue; - } - use.mapSourceRegisters(mapper); - } - } - } -} diff --git a/dx/src/com/android/dx/ssa/DeadCodeRemover.java b/dx/src/com/android/dx/ssa/DeadCodeRemover.java deleted file mode 100644 index 4fded44aa..000000000 --- a/dx/src/com/android/dx/ssa/DeadCodeRemover.java +++ /dev/null @@ -1,226 +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.android.dx.ssa; - -import com.android.dx.rop.code.RegOps; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.Rop; -import com.android.dx.rop.code.PlainInsn; -import com.android.dx.rop.code.Rops; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.code.Insn; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.HashSet; - -/** - * A variation on Appel Algorithm 19.12 "Dead code elimination in SSA form". - * - * TODO this algorithm is more efficient if run in reverse from exit - * block to entry block. - */ -public class DeadCodeRemover { - - /** method we're processing */ - private SsaMethod ssaMeth; - /** ssaMeth.getRegCount() */ - private int regCount; - - /** - * indexed by register: whether reg should be examined - * (does it correspond to a no-side-effect insn?) - */ - private BitSet worklist; - - /** use list indexed by register; modified during operation */ - private ArrayList<SsaInsn>[] useList; - - /** - * Process a method with the dead-code remver - * @param ssaMethod method to process - */ - public static void process(SsaMethod ssaMethod) { - DeadCodeRemover dc; - - dc = new DeadCodeRemover(ssaMethod); - - dc.run(); - } - - private DeadCodeRemover(SsaMethod ssaMethod) { - this.ssaMeth = ssaMethod; - - regCount = ssaMethod.getRegCount(); - - worklist = new BitSet(regCount); - - useList = ssaMeth.getUseListCopy(); - } - - /** - * Run the dead code remover - */ - private void run() { - - HashSet<SsaInsn> deletedInsns = (HashSet<SsaInsn>) new HashSet(); - - ssaMeth.forEachInsn(new NoSideEffectVisitor(worklist)); - - int regV; - - while ( 0 <= (regV = worklist.nextSetBit(0)) ) { - worklist.clear(regV); - - if (useList[regV].size() == 0 - || isCircularNoSideEffect(regV, null)) { - - SsaInsn insnS = ssaMeth.getDefinitionForRegister(regV); - - // This insn has already been deleted - if (deletedInsns.contains(insnS)) { - continue; - } - - RegisterSpecList sources = insnS.getSources(); - - int sz = sources.size(); - for (int i = 0; i < sz; i++) { - - // Delete this insn from all usage lists - RegisterSpec source = sources.get(i); - useList[source.getReg()].remove(insnS); - - if (!hasSideEffect( - ssaMeth.getDefinitionForRegister( - source.getReg()))) { - /* - * Only registers who's definition has no side effect - * should be added back to the worklist - */ - worklist.set(source.getReg()); - } - } - - // Schedule this insn for later deletion - deletedInsns.add(insnS); - } - } - - ssaMeth.deleteInsns(deletedInsns); - } - - /** - * Returns true if the only uses of this register form a circle of - * operations with no side effects - * @param regV register to examine - * @param set a set of registers that we've already determined - * are only used as sources in operations with no side effect or null - * if this is the first recursion - * @return true if usage is circular without side effect - */ - private boolean isCircularNoSideEffect(int regV, BitSet set) { - if ((set != null) && set.get(regV)) { - return true; - } - - for (SsaInsn use: useList[regV]) { - if (hasSideEffect(use)) { - return false; - } - } - - if (set == null) { - set = new BitSet(regCount); - } - - // This register is only used in operations that have no side effect. - set.set(regV); - - for (SsaInsn use: useList[regV]) { - RegisterSpec result = use.getResult(); - - if (result == null - || !isCircularNoSideEffect(result.getReg(), set)) { - return false; - } - } - - return true; - } - - /** - * Returns true if this insn has a side-effect. Returns true - * if the insn is null for reasons stated in the code block. - * @param insn null-ok; instruction in question - * @return true if it has a side-effect - */ - private static boolean hasSideEffect(SsaInsn insn) { - if (insn == null) { - /* while false would seem to make more sense here, true - * prevents us from adding this back to a worklist unnecessarally - */ - return true; - } - - return insn.hasSideEffect(); - } - - /** - * A callback class used to build up the initial worklist of - * registers defined by an instruction with no side effect. - */ - static class NoSideEffectVisitor implements SsaInsn.Visitor { - BitSet noSideEffectRegs; - - /** - * Passes in data structures that will be filled out after - * ssaMeth.forEachInsn() is called with this instance. - * - * @param noSideEffectRegs to-build bitset of regs that are - * results of regs with no side effects - */ - NoSideEffectVisitor(BitSet noSideEffectRegs) { - this.noSideEffectRegs = noSideEffectRegs; - } - - /** {@inheritDoc} */ - public void visitMoveInsn (NormalSsaInsn insn) { - // If we're tracking local vars, some moves have side effects - if (!hasSideEffect(insn)) { - noSideEffectRegs.set(insn.getResult().getReg()); - } - } - - /** {@inheritDoc} */ - public void visitPhiInsn (PhiInsn phi) { - // If we're tracking local vars, then some phis have side effects - if (!hasSideEffect(phi)) { - noSideEffectRegs.set(phi.getResult().getReg()); - } - } - - /** {@inheritDoc} */ - public void visitNonMoveInsn (NormalSsaInsn insn) { - RegisterSpec result = insn.getResult(); - if (!hasSideEffect(insn) && result != null) { - noSideEffectRegs.set(result.getReg()); - } - } - } -} diff --git a/dx/src/com/android/dx/ssa/DomFront.java b/dx/src/com/android/dx/ssa/DomFront.java deleted file mode 100644 index ea089ec13..000000000 --- a/dx/src/com/android/dx/ssa/DomFront.java +++ /dev/null @@ -1,188 +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.android.dx.ssa; - -import com.android.dx.util.IntSet; -import com.android.dx.util.BitIntSet; -import com.android.dx.util.ListIntSet; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; - -/** - * Calculates the dominance-frontiers of a methot's basic blocks. - * Algorithm from "A Simple, Fast Dominance Algorithm" by Cooper, - * Harvey, and Kennedy; transliterated to Java. - */ -public class DomFront { - private static boolean DEBUG = false; - - private final SsaMethod meth; - private final ArrayList<SsaBasicBlock> nodes; - private final DomInfo[] domInfos; - - /** - * Dominance-frontier information for a single basic block. - */ - public static class DomInfo { - /** non-null; the dominance frontier set indexed by block index */ - IntSet dominanceFrontiers; - /** >= 0 after run(); the index of the immediate dominator */ - int idom = -1; - /** depth-first traversal index */ - int traversalIndex; - } - - /** - * Constructs instance. Call {@link DomFront#run} to process. - * @param meth - */ - public DomFront(SsaMethod meth) { - this.meth = meth; - nodes = meth.getBlocks(); - - int szNodes = nodes.size(); - domInfos = new DomInfo[szNodes]; - - for (int i = 0; i < szNodes; i++) { - domInfos[i] = new DomInfo(); - } - } - - /** - * Calculates the dominance frontier information for the method. - * - * @return non-null; an array of DomInfo structures - */ - public DomInfo[] run() { - int szNodes = nodes.size(); - - if (DEBUG) { - for (int i = 0; i < szNodes; i++) { - SsaBasicBlock node = nodes.get(i); - System.out.println("pred[" + i + "]: " - + node.getPredecessors()); - } - } - - Dominators methDom = new Dominators(domInfos, false); - methDom.run(meth); - - if (DEBUG) { - for (int i = 0; i < szNodes; i++) { - DomInfo info = domInfos[i]; - System.out.println("idom[" + i + "]: " - + info.idom); - } - } - - buildDomTree(); - - if (DEBUG) { - debugPrintDomChildren(); - } - - for (int i = 0; i < szNodes; i++) { - domInfos[i].dominanceFrontiers - = SetFactory.makeDomFrontSet(szNodes); - } - - calcDomFronts(); - - if (DEBUG) { - for (int i = 0; i < szNodes; i++) { - System.out.println("df[" + i + "]: " - + domInfos[i].dominanceFrontiers); - } - } - - return domInfos; - } - - private void debugPrintDomChildren() { - int szNodes = nodes.size(); - - for (int i = 0; i < szNodes; i++) { - SsaBasicBlock node = nodes.get(i); - StringBuffer sb = new StringBuffer(); - - sb.append('{'); - boolean comma = false; - for (SsaBasicBlock child: node.getDomChildren()) { - if (comma) { - sb.append(','); - } - sb.append(child); - comma = true; - } - sb.append('}'); - - System.out.println("domChildren[" + node + "]: " - + sb); - } - } - - /** - * The dominators algorithm leaves us knowing who the immediate dominator - * is for each node. This sweeps the node list and builds the proper - * dominance tree. - */ - private void buildDomTree() { - int szNodes = nodes.size(); - - for (int i = 0; i < szNodes; i++) { - DomInfo info = domInfos[i]; - SsaBasicBlock domParent = nodes.get(info.idom); - domParent.addDomChild(nodes.get(i)); - } - } - - /** - * Calculates the dominance-frontier set. - * from "A Simple, Fast Dominance Algorithm" by Cooper, - * Harvey, and Kennedy; transliterated to Java. - */ - private void calcDomFronts() { - int szNodes = nodes.size(); - - for (int b = 0; b < szNodes; b++) { - SsaBasicBlock nb = nodes.get(b); - DomInfo nbInfo = domInfos[b]; - BitSet pred = nb.getPredecessors(); - if (pred.cardinality() > 1) { - for (int i = pred.nextSetBit(0); i >= 0; - i = pred.nextSetBit(i + 1)) { - - for(int runnerIndex = i - ; runnerIndex != nbInfo.idom - ;) { - // We can stop if we hit a block we already - // added label to, since we must be at a part - // of the dom tree we have seen before. - DomInfo runnerInfo = domInfos[runnerIndex]; - if (runnerInfo.dominanceFrontiers.has(b)) - break; - // "add b to runner's dominance frontier set" - runnerInfo.dominanceFrontiers.add(b); - runnerIndex = runnerInfo.idom; - } - } - } - } - } -} diff --git a/dx/src/com/android/dx/ssa/Dominators.java b/dx/src/com/android/dx/ssa/Dominators.java deleted file mode 100644 index 1af2cbc88..000000000 --- a/dx/src/com/android/dx/ssa/Dominators.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.android.dx.ssa; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.HashSet; - -/** - * This class computes dominator and post-dominator information using the - * Lengauer-Tarjan method. - * - * See A Fast Algorithm for Finding Dominators in a Flowgraph - * T. Lengauer & R. Tarjan, ACM TOPLAS July 1979, pgs 121-141. - * - * This implementation runs in time O(n log n). The time bound - * could be changed to O(n * ack(n)) with a small change to the link and eval, - * and an addition of a child field to the DFS info. In reality, the constant - * overheads are high enough that the current method is faster in all but the - * strangest artificially constructed examples. - * - * The basic idea behind this algorithm is to perform a DFS walk, keeping track - * of various info about parents. We then use this info to calculate the - * dominators, using union-find structures to link together the DFS info, - * then finally evaluate the union-find results to get the dominators. - * This implementation is m log n because it does not perform union by - * rank to keep the union-find tree balanced. - */ -public final class Dominators { - /* postdom is true if we want post dominators. */ - private boolean postdom; - /* Method's basic blocks. */ - private ArrayList<SsaBasicBlock> blocks; - - private static final class DFSInfo { - int semidom; - SsaBasicBlock parent; - // rep(resentative) is known as "label" in the paper. It is the node - // that our block's DFS info has been unioned to. - SsaBasicBlock rep; - SsaBasicBlock ancestor; - ArrayList<SsaBasicBlock> bucket; - - public DFSInfo() { - bucket = new ArrayList<SsaBasicBlock>(); - } - - } - - /** Indexed by basic block index */ - private DFSInfo[] info; - private ArrayList<SsaBasicBlock> vertex; - - private DomFront.DomInfo domInfos[]; - - private BitSet getSuccs(SsaBasicBlock block) { - if (postdom) { - return block.getPredecessors(); - } else { - return block.getSuccessors(); - } - } - - private BitSet getPreds(SsaBasicBlock block) { - if (postdom) { - return block.getSuccessors(); - } else { - return block.getPredecessors(); - } - } - - /** - * Performs path compress on the DFS info. - * @param in Basic block whose DFS info we are path compressing. - */ - private void compress(SsaBasicBlock in) { - DFSInfo bbInfo = info[in.getIndex()]; - DFSInfo ancestorbbInfo = info[bbInfo.ancestor.getIndex()]; - - if (ancestorbbInfo.ancestor != null) { - ArrayList<SsaBasicBlock> worklist = new ArrayList<SsaBasicBlock>(); - HashSet<SsaBasicBlock> visited = new HashSet<SsaBasicBlock>(); - worklist.add(in); - - while (!worklist.isEmpty()) { - int wsize = worklist.size(); - SsaBasicBlock v = worklist.get(wsize - 1); - DFSInfo vbbInfo = info[v.getIndex()]; - SsaBasicBlock vAncestor = vbbInfo.ancestor; - DFSInfo vabbInfo = info[vAncestor.getIndex()]; - - // Make sure we process our ancestor before ourselves. - if (visited.add(vAncestor) && vabbInfo.ancestor != null) { - worklist.add(vAncestor); - continue; - } - worklist.remove(wsize - 1); - - // Update based on ancestor info - if (vabbInfo.ancestor == null) { - continue; - } - SsaBasicBlock vAncestorRep = vabbInfo.rep; - SsaBasicBlock vRep = vbbInfo.rep; - if (info[vAncestorRep.getIndex()].semidom - < info[vRep.getIndex()].semidom) { - vbbInfo.rep = vAncestorRep; - } - vbbInfo.ancestor = vabbInfo.ancestor; - } - } - } - private SsaBasicBlock eval(SsaBasicBlock v) { - DFSInfo bbInfo = info[v.getIndex()]; - if (bbInfo.ancestor == null) { - return v; - } - compress(v); - return bbInfo.rep; - } - - /** - * Callback for depth-first walk through control flow graph (either - * from the entry block or the exit block). Records the traversal order - * in the <code>info</code>list. - */ - private class DfsWalker implements SsaBasicBlock.Visitor { - int dfsNum = 0; - - public void visitBlock (SsaBasicBlock v, SsaBasicBlock parent) { - DFSInfo bbInfo = new DFSInfo(); - bbInfo.semidom = ++dfsNum; - bbInfo.rep = v; - bbInfo.parent = parent; - vertex.add(v); - info[v.getIndex()] = bbInfo; - } - } - - /** - * Performs dominator/post-dominator calculation for the control flow graph. - * @param meth Method to analyze - */ - public void run(SsaMethod meth) { - - this.blocks = meth.getBlocks(); - this.info = new DFSInfo[blocks.size() + 2]; - this.vertex = new ArrayList<SsaBasicBlock>(); - SsaBasicBlock root = postdom - ? meth.getExitBlock() : meth.getEntryBlock(); - - if (root != null) { - vertex.add(root); - domInfos[root.getIndex()].idom = root.getIndex(); - } - - // First we perform a DFS numbering of the blocks, by numbering the dfs - // tree roots - - DfsWalker walker = new DfsWalker(); - meth.forEachBlockDepthFirst(postdom, walker); - - // the largest semidom number assigned - int dfsMax = vertex.size() - 1; - - // Now calculate semidominators. - for (int i = dfsMax; i >= 2; --i) { - SsaBasicBlock w = vertex.get(i); - DFSInfo wInfo = info[w.getIndex()]; - - BitSet preds = getPreds(w); - for (int j = preds.nextSetBit(0); - j >= 0; - j = preds.nextSetBit(j + 1)) { - SsaBasicBlock predBlock = blocks.get(j); - DFSInfo predInfo = info[predBlock.getIndex()]; - // PredInfo may not exist in case the predecessor is not - // reachable - if (predInfo != null) { - int predSemidom = info[eval(predBlock).getIndex()].semidom; - if (predSemidom < wInfo.semidom) { - wInfo.semidom = predSemidom; - } - } - } - info[vertex.get(wInfo.semidom).getIndex()].bucket.add(w); - - // Normally we would call link here, but in our m log n - // implementation this is equivalent to the following single line - wInfo.ancestor = wInfo.parent; - - // Implicity define idom for each vertex - ArrayList<SsaBasicBlock> wParentBucket; - wParentBucket = info[wInfo.parent.getIndex()].bucket; - - while (!wParentBucket.isEmpty()) { - int lastItem = wParentBucket.size() - 1; - SsaBasicBlock last = wParentBucket.remove(lastItem); - SsaBasicBlock U = eval(last); - if (info[U.getIndex()].semidom - < info[last.getIndex()].semidom) { - domInfos[last.getIndex()].idom = U.getIndex(); - } else { - domInfos[last.getIndex()].idom = wInfo.parent.getIndex(); - } - } - } - // Now explicitly define the immediate dominator of each vertex - for (int i = 2; i <= dfsMax; ++i) { - SsaBasicBlock w = vertex.get(i); - if (domInfos[w.getIndex()].idom - != vertex.get(info[w.getIndex()].semidom).getIndex()) { - domInfos[w.getIndex()].idom - = domInfos[domInfos[w.getIndex()].idom].idom; - } - } - } - - /** - * @param postdom true for postdom information, false for normal dom info - */ - public Dominators(DomFront.DomInfo[] domInfos, boolean postdom) { - this.domInfos = domInfos; - this.postdom = postdom; - } -} diff --git a/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java b/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java deleted file mode 100644 index be678ddde..000000000 --- a/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.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.android.dx.ssa; - -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.ssa.back.InterferenceGraph; -import com.android.dx.util.IntSet; -import com.android.dx.util.BitIntSet; - -import java.util.ArrayList; -import java.util.BitSet; - -/** - * A register mapper that keeps track of the accumulated interference - * information for the registers in the new namespace. - * - * Please note that this mapper requires that the old namespace does not - * have variable register widths/categories, and the new namespace does. - */ -public class InterferenceRegisterMapper extends BasicRegisterMapper { - - /** - * Array of interference sets. ArrayList is indexed by new namespace - * and BitIntSet's are indexed by old namespace. The list expands - * as needed and missing items are assumed to interfere with nothing. - * - * Bit sets are always used here, unlike elsewhere, because the max - * size of this matrix will be (countSsaRegs * countRopRegs), which may - * grow to hundreds of K but not megabytes. - */ - private final ArrayList<BitIntSet> newRegInterference; - - /** - * The interference graph for the old namespace - */ - private final InterferenceGraph oldRegInterference; - - /** - * @param countOldRegisters number of registers in old namespace. - */ - public InterferenceRegisterMapper( - InterferenceGraph oldRegInterference, - int countOldRegisters) { - super(countOldRegisters); - - newRegInterference = new ArrayList<BitIntSet>(); - this.oldRegInterference = oldRegInterference; - } - - /** {@inheritDoc} */ - @Override - public void addMapping(int oldReg, int newReg, int category) { - super.addMapping(oldReg, newReg, category); - - addInterfence(newReg, oldReg); - - if (category == 2) { - addInterfence(newReg + 1, oldReg); - } - } - - /** - * Checks to see if old namespace reg <code>oldReg</code> interferes - * with what currently maps to <code>newReg</code>. - * - * @param oldReg old namespace register - * @param newReg new namespace register - * @param category category of old namespace register - * @return true if oldReg will interfere with newReg - */ - public boolean interferes(int oldReg, int newReg, int category) { - if (newReg >= newRegInterference.size()) { - return false; - } else { - IntSet existing = newRegInterference.get(newReg); - - if (existing == null) { - return false; - } else if (category == 1) { - return existing.has(oldReg); - } else { - return existing.has(oldReg) - || (interferes(oldReg, newReg+1, category-1)); - } - } - } - - /** - * Checks to see if old namespace reg <code>oldReg</code> interferes - * with what currently maps to <code>newReg</code>. - * - * @param oldSpec non-null; old namespace register - * @param newReg new namespace register - * @return true if oldReg will interfere with newReg - */ - public boolean interferes(RegisterSpec oldSpec, int newReg) { - return interferes(oldSpec.getReg(), newReg, oldSpec.getCategory()); - } - - /** - * Adds a register's interference set to the interference list, - * growing it if necessary. - * @param newReg register in new namespace - * @param oldReg register in old namespace - */ - private void addInterfence(int newReg, int oldReg) { - newRegInterference.ensureCapacity(newReg + 1); - - while (newReg >= newRegInterference.size()) { - newRegInterference.add(new BitIntSet(newReg +1)); - } - - oldRegInterference.mergeInterferenceSet( - oldReg, newRegInterference.get(newReg)); - } - - /** - * Checks to see if any of a set of old-namespace registers are - * pinned to the specified new-namespace reg + category. Takes into - * account the category of the old-namespace registers. - * - * @param oldSpecs non-null; set of old-namespace regs - * @param newReg >= 0 new-namespace register - * @param targetCategory 1 or 2; the number of adjacent new-namespace - * registers (starting at ropReg) to consider - * @return true if any of the old-namespace register have been mapped - * to the new-namespace register + category - */ - public boolean areAnyPinned(RegisterSpecList oldSpecs, - int newReg, int targetCategory) { - - int sz = oldSpecs.size(); - for (int i = 0; i < sz; i++) { - RegisterSpec oldSpec = oldSpecs.get(i); - int r = oldToNew(oldSpec.getReg()); - - /* - * If oldSpec is a category-2 register, then check both newReg - * and newReg - 1. - */ - if (r == newReg - || (oldSpec.getCategory() == 2 && (r + 1) == newReg) - || (targetCategory == 2 && (r == newReg + 1))) { - return true; - } - } - return false; - } -} diff --git a/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java b/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java deleted file mode 100644 index ad10cd75d..000000000 --- a/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java +++ /dev/null @@ -1,160 +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.android.dx.ssa; - -import com.android.dx.rop.code.TranslationAdvice; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.Insn; -import com.android.dx.rop.code.Rop; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.PlainInsn; -import com.android.dx.rop.code.Rops; -import com.android.dx.rop.code.RegOps; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.rop.type.TypeBearer; - -import java.util.List; - -/** - * Upgrades insn to their literal (constant-immediate) equivilent if possible. - * Also switches IF instructions that compare with a constant zero or null - * to be their IF_*Z equivalents. - */ -public class LiteralOpUpgrader { - - /** method we're processing */ - private final SsaMethod ssaMeth; - - /** - * Process a method. - * - * @param ssaMethod non-null; method to process - */ - public static void process(SsaMethod ssaMethod) { - LiteralOpUpgrader dc; - - dc = new LiteralOpUpgrader(ssaMethod); - - dc.run(); - } - - private LiteralOpUpgrader(SsaMethod ssaMethod) { - this.ssaMeth = ssaMethod; - } - - /** - * Returns true if the register contains an integer 0 or a known-null - * object reference - * - * @param spec non-null spec - * @return true for 0 or null type bearers - */ - private static boolean isConstIntZeroOrKnownNull(RegisterSpec spec) { - TypeBearer tb = spec.getTypeBearer(); - if (tb instanceof CstLiteralBits) { - CstLiteralBits clb = (CstLiteralBits) tb; - return (clb.getLongBits() == 0); - } - return false; - } - - /** - * Run the literal op upgrader - */ - private void run() { - final TranslationAdvice advice = Optimizer.getAdvice(); - - ssaMeth.forEachInsn(new SsaInsn.Visitor() { - public void visitMoveInsn(NormalSsaInsn insn) { - // do nothing - } - - public void visitPhiInsn(PhiInsn insn) { - // do nothing - } - - public void visitNonMoveInsn(NormalSsaInsn insn) { - - Insn originalRopInsn = insn.getOriginalRopInsn(); - Rop opcode = originalRopInsn.getOpcode(); - RegisterSpecList sources = insn.getSources(); - - if (sources.size() != 2 ) { - // We're only dealing with two-source insns here. - return; - } - - if (opcode.getBranchingness() == Rop.BRANCH_IF) { - /* - * An if instruction can become an if-*z instruction. - */ - if (isConstIntZeroOrKnownNull(sources.get(0))) { - replacePlainInsn(insn, sources.withoutFirst(), - RegOps.flippedIfOpcode(opcode.getOpcode())); - } else if (isConstIntZeroOrKnownNull(sources.get(1))) { - replacePlainInsn(insn, sources.withoutLast(), - opcode.getOpcode()); - } - } else if (advice.hasConstantOperation( - opcode, sources.get(0), sources.get(1))) { - insn.upgradeToLiteral(); - } else if (opcode.isCommutative() - && advice.hasConstantOperation( - opcode, sources.get(1), sources.get(0))) { - /* - * An instruction can be commuted to a literal operation - */ - - insn.setNewSources( - RegisterSpecList.make( - sources.get(1), sources.get(0))); - - insn.upgradeToLiteral(); - } - } - }); - } - - /** - * Replaces an SsaInsn containing a PlainInsn with a new PlainInsn. The - * new PlainInsn is contructed with a new RegOp and new sources. - * - * TODO move this somewhere else. - * - * @param insn non-null; an SsaInsn containing a PlainInsn - * @param newSources non-null; new sources list for new insn - * @param newOpcode A RegOp from {@link RegOps} - */ - private void replacePlainInsn(NormalSsaInsn insn, - RegisterSpecList newSources, int newOpcode) { - - Insn originalRopInsn = insn.getOriginalRopInsn(); - Rop newRop = Rops.ropFor(newOpcode, - insn.getResult(), newSources, null); - Insn newRopInsn = new PlainInsn(newRop, - originalRopInsn.getPosition(), insn.getResult(), - newSources); - NormalSsaInsn newInsn - = new NormalSsaInsn(newRopInsn, insn.getBlock()); - - List<SsaInsn> insns = insn.getBlock().getInsns(); - - ssaMeth.onInsnRemoved(insn); - insns.set(insns.lastIndexOf(insn), newInsn); - ssaMeth.onInsnAdded(newInsn); - } -} diff --git a/dx/src/com/android/dx/ssa/LocalVariableExtractor.java b/dx/src/com/android/dx/ssa/LocalVariableExtractor.java deleted file mode 100644 index 21c306b7e..000000000 --- a/dx/src/com/android/dx/ssa/LocalVariableExtractor.java +++ /dev/null @@ -1,208 +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.android.dx.ssa; - -import com.android.dx.rop.code.RegisterSpecSet; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.util.IntList; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.List; - -/** - * Code to figure out which local variables are active at which points in - * a method. Stolen and retrofitted from - * com.android.dx.rop.code.LocalVariableExtractor - * - * TODO remove this. Allow Rop-form LocalVariableInfo to be passed in, - * converted, and adapted through edge-splitting. - */ -public class LocalVariableExtractor { - /** non-null; method being extracted from */ - private final SsaMethod method; - - /** non-null; block list for the method */ - private final ArrayList<SsaBasicBlock> blocks; - - /** non-null; result in-progress */ - private final LocalVariableInfo resultInfo; - - /** non-null; work set indicating blocks needing to be processed */ - private final BitSet workSet; - - /** - * Extracts out all the local variable information from the given method. - * - * @param method non-null; the method to extract from - * @return non-null; the extracted information - */ - public static LocalVariableInfo extract(SsaMethod method) { - LocalVariableExtractor lve = new LocalVariableExtractor(method); - return lve.doit(); - } - - /** - * Constructs an instance. This method is private. Use {@link #extract}. - * - * @param method non-null; the method to extract from - */ - private LocalVariableExtractor(SsaMethod method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - ArrayList<SsaBasicBlock> blocks = method.getBlocks(); - - this.method = method; - this.blocks = blocks; - this.resultInfo = new LocalVariableInfo(method); - this.workSet = new BitSet(blocks.size()); - } - - /** - * Does the extraction. - * - * @return non-null; the extracted information - */ - private LocalVariableInfo doit() { - - //FIXME why is this needed here? - if (method.getRegCount() > 0 ) { - for (int bi = method.getEntryBlockIndex(); - bi >= 0; - bi = workSet.nextSetBit(0)) { - workSet.clear(bi); - processBlock(bi); - } - } - - resultInfo.setImmutable(); - return resultInfo; - } - - /** - * Processes a single block. - * - * @param blockIndex >= 0; block index of the block to process - */ - private void processBlock(int blockIndex) { - RegisterSpecSet primaryState - = resultInfo.mutableCopyOfStarts(blockIndex); - SsaBasicBlock block = blocks.get(blockIndex); - List<SsaInsn> insns = block.getInsns(); - int insnSz = insns.size(); - - // The exit block has no insns and no successors - if (blockIndex == method.getExitBlockIndex()) { - return; - } - - /* - * We may have to treat the last instruction specially: If it - * can (but doesn't always) throw, and the exception can be - * caught within the same method, then we need to use the - * state *before* executing it to be what is merged into - * exception targets. - */ - SsaInsn lastInsn = insns.get(insnSz - 1); - boolean hasExceptionHandlers - = lastInsn.getOriginalRopInsn().getCatches().size() !=0 ; - boolean canThrowDuringLastInsn = hasExceptionHandlers - && (lastInsn.getResult() != null); - int freezeSecondaryStateAt = insnSz - 1; - RegisterSpecSet secondaryState = primaryState; - - /* - * Iterate over the instructions, adding information for each place - * that the active variable set changes. - */ - - for (int i = 0; i < insnSz; i++) { - if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) { - // Until this point, primaryState == secondaryState. - primaryState.setImmutable(); - primaryState = primaryState.mutableCopy(); - } - - SsaInsn insn = insns.get(i); - RegisterSpec result; - - result = insn.getLocalAssignment(); - - if (result == null) { - // We may be nuking an existing local - - result = insn.getResult(); - - if (result != null && primaryState.get(result.getReg()) != null) { - primaryState.remove(primaryState.get(result.getReg())); - } - continue; - } - - result = result.withSimpleType(); - - RegisterSpec already = primaryState.get(result); - /* - * The equals() check ensures we only add new info if - * the instruction causes a change to the set of - * active variables. - */ - if (!result.equals(already)) { - /* - * If this insn represents a local moving from one register - * to another, remove the association between the old register - * and the local. - */ - RegisterSpec previous - = primaryState.localItemToSpec(result.getLocalItem()); - - if (previous != null - && (previous.getReg() != result.getReg())) { - - primaryState.remove(previous); - } - - resultInfo.addAssignment(insn, result); - primaryState.put(result); - } - } - - primaryState.setImmutable(); - - /* - * Merge this state into the start state for each successor, - * and update the work set where required (that is, in cases - * where the start state for a block changes). - */ - - IntList successors = block.getSuccessorList(); - int succSz = successors.size(); - int primarySuccessor = block.getPrimarySuccessorIndex(); - - for (int i = 0; i < succSz; i++) { - int succ = successors.get(i); - RegisterSpecSet state = (succ == primarySuccessor) ? - primaryState : secondaryState; - - if (resultInfo.mergeStarts(succ, state)) { - workSet.set(succ); - } - } - } -} diff --git a/dx/src/com/android/dx/ssa/LocalVariableInfo.java b/dx/src/com/android/dx/ssa/LocalVariableInfo.java deleted file mode 100644 index f7c37d24d..000000000 --- a/dx/src/com/android/dx/ssa/LocalVariableInfo.java +++ /dev/null @@ -1,251 +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.android.dx.ssa; - -import com.android.dx.util.MutabilityControl; -import com.android.dx.rop.code.RegisterSpecSet; -import com.android.dx.rop.code.RegisterSpec; - -import java.util.HashMap; -import java.util.List; - -/** - * Container for local variable information for a particular {@link - * com.android.dx.ssa.SsaMethod}. - * Stolen from {@link com.android.dx.rop.code.LocalVariableInfo}. - */ -public class LocalVariableInfo extends MutabilityControl { - /** >= 0; the register count for the method */ - private final int regCount; - - /** - * non-null; {@link com.android.dx.rop.code.RegisterSpecSet} to use when indicating a block - * that has no locals; it is empty and immutable but has an appropriate - * max size for the method - */ - private final RegisterSpecSet emptySet; - - /** - * non-null; array consisting of register sets representing the - * sets of variables already assigned upon entry to each block, - * where array indices correspond to block indices - */ - private final RegisterSpecSet[] blockStarts; - - /** non-null; map from instructions to the variable each assigns */ - private final HashMap<SsaInsn, RegisterSpec> insnAssignments; - - /** - * Constructs an instance. - * - * @param method non-null; the method being represented by this instance - */ - public LocalVariableInfo(SsaMethod method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - List<SsaBasicBlock> blocks = method.getBlocks(); - - this.regCount = method.getRegCount(); - this.emptySet = new RegisterSpecSet(regCount); - this.blockStarts = new RegisterSpecSet[blocks.size()]; - this.insnAssignments = - new HashMap<SsaInsn, RegisterSpec>(/*hint here*/); - - emptySet.setImmutable(); - } - - /** - * Sets the register set associated with the start of the block with - * the given index. - * - * @param index >= 0; the block index - * @param specs non-null; the register set to associate with the block - */ - public void setStarts(int index, RegisterSpecSet specs) { - throwIfImmutable(); - - if (specs == null) { - throw new NullPointerException("specs == null"); - } - - try { - blockStarts[index] = specs; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("bogus index"); - } - } - - /** - * Merges the given register set into the set for the block with the - * given index. If there was not already an associated set, then this - * is the same as calling {@link #setStarts}. Otherwise, this will - * merge the two sets and call {@link #setStarts} on the result of the - * merge. - * - * @param index >= 0; the block index - * @param specs non-null; the register set to merge into the start set - * for the block - * @return <code>true</code> if the merge resulted in an actual change - * to the associated set (including storing one for the first time) or - * <code>false</code> if there was no change - */ - public boolean mergeStarts(int index, RegisterSpecSet specs) { - RegisterSpecSet start = getStarts0(index); - boolean changed = false; - - if (start == null) { - setStarts(index, specs); - return true; - } - - RegisterSpecSet newStart = start.mutableCopy(); - newStart.intersect(specs, true); - - if (start.equals(newStart)) { - return false; - } - - newStart.setImmutable(); - setStarts(index, newStart); - - return true; - } - - /** - * Gets the register set associated with the start of the block - * with the given index. This returns an empty set with the appropriate - * max size if no set was associated with the block in question. - * - * @param index >= 0; the block index - * @return non-null; the associated register set - */ - public RegisterSpecSet getStarts(int index) { - RegisterSpecSet result = getStarts0(index); - - return (result != null) ? result : emptySet; - } - - /** - * Gets the register set associated with the start of the given - * block. This is just convenient shorthand for - * <code>getStarts(block.getLabel())</code>. - * - * @param block non-null; the block in question - * @return non-null; the associated register set - */ - public RegisterSpecSet getStarts(SsaBasicBlock block) { - return getStarts(block.getIndex()); - } - - /** - * Gets a mutable copy of the register set associated with the - * start of the block with the given index. This returns a - * newly-allocated empty {@link RegisterSpecSet} of appropriate - * max size if there is not yet any set associated with the block. - * - * @param index >= 0; the block index - * @return non-null; the associated register set - */ - public RegisterSpecSet mutableCopyOfStarts(int index) { - RegisterSpecSet result = getStarts0(index); - - return (result != null) ? - result.mutableCopy() : new RegisterSpecSet(regCount); - } - - /** - * Adds an assignment association for the given instruction and - * register spec. This throws an exception if the instruction - * doesn't actually perform a named variable assignment. - * - * <b>Note:</b> Although the instruction contains its own spec for - * the result, it still needs to be passed in explicitly to this - * method, since the spec that is stored here should always have a - * simple type and the one in the instruction can be an arbitrary - * {@link com.android.dx.rop.type.TypeBearer} (such as a constant value). - * - * @param insn non-null; the instruction in question - * @param spec non-null; the associated register spec - */ - public void addAssignment(SsaInsn insn, RegisterSpec spec) { - throwIfImmutable(); - - if (insn == null) { - throw new NullPointerException("insn == null"); - } - - if (spec == null) { - throw new NullPointerException("spec == null"); - } - - insnAssignments.put(insn, spec); - } - - /** - * Gets the named register being assigned by the given instruction, if - * previously stored in this instance. - * - * @param insn non-null; instruction in question - * @return null-ok; the named register being assigned, if any - */ - public RegisterSpec getAssignment(SsaInsn insn) { - return insnAssignments.get(insn); - } - - /** - * Gets the number of assignments recorded by this instance. - * - * @return >= 0; the number of assignments - */ - public int getAssignmentCount() { - return insnAssignments.size(); - } - - public void debugDump() { - for (int index = 0 ; index < blockStarts.length; index++) { - if (blockStarts[index] == null) { - continue; - } - - if (blockStarts[index] == emptySet) { - System.out.printf("%04x: empty set\n", index); - } else { - System.out.printf("%04x: %s\n", index, blockStarts[index]); - } - } - } - - /** - * Helper method, to get the starts for a index, throwing the - * right exception for range problems. - * - * @param index >= 0; the block index - * @return null-ok; associated register set or <code>null</code> if there - * is none - */ - private RegisterSpecSet getStarts0(int index) { - try { - return blockStarts[index]; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("bogus index"); - } - } -} diff --git a/dx/src/com/android/dx/ssa/MoveParamCombiner.java b/dx/src/com/android/dx/ssa/MoveParamCombiner.java deleted file mode 100644 index a27aec58b..000000000 --- a/dx/src/com/android/dx/ssa/MoveParamCombiner.java +++ /dev/null @@ -1,156 +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.android.dx.ssa; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegOps; -import com.android.dx.rop.code.CstInsn; -import com.android.dx.rop.code.LocalItem; -import com.android.dx.rop.cst.CstInteger; - -import java.util.HashSet; -import java.util.ArrayList; -import java.util.List; - -/** - * Combine identical move-param insns, which may result from Ropper's - * handling of synchronized methods. - */ -public class MoveParamCombiner { - - /** method to process */ - private final SsaMethod ssaMeth; - - /** - * Processes a method with this optimization step. - * - * @param ssaMethod method to process - */ - public static void process(SsaMethod ssaMethod) { - new MoveParamCombiner(ssaMethod).run(); - } - - private MoveParamCombiner(SsaMethod ssaMeth) { - this.ssaMeth = ssaMeth; - } - - /** - * Runs this optimization step. - */ - private void run() { - // This will contain the definition specs for each parameter - final RegisterSpec[] paramSpecs - = new RegisterSpec[ssaMeth.getParamWidth()]; - - // Insns to delete when all done - final HashSet<SsaInsn> deletedInsns = new HashSet(); - - ssaMeth.forEachInsn(new SsaInsn.Visitor() { - public void visitMoveInsn (NormalSsaInsn insn) { - } - public void visitPhiInsn (PhiInsn phi) { - } - public void visitNonMoveInsn (NormalSsaInsn insn) { - if (insn.getOpcode().getOpcode() != RegOps.MOVE_PARAM) { - return; - } - - int param = getParamIndex(insn); - - if (paramSpecs[param] == null) { - paramSpecs[param] = insn.getResult(); - } else { - final RegisterSpec specA = paramSpecs[param]; - final RegisterSpec specB = insn.getResult(); - LocalItem localA = specA.getLocalItem(); - LocalItem localB = specB.getLocalItem(); - LocalItem newLocal; - - /* - * Is there local information to preserve? - */ - - if (localA == null) { - newLocal = localB; - } else if (localB == null) { - newLocal = localA; - } else if (localA.equals(localB)) { - newLocal = localA; - } else { - /* - * Oddly, these two identical move-params have distinct - * debug info. We'll just keep them distinct. - */ - return; - } - - ssaMeth.getDefinitionForRegister(specA.getReg()) - .setResultLocal(newLocal); - - /* - * Map all uses of specB to specA - */ - - RegisterMapper mapper = new RegisterMapper() { - /** @inheritDoc */ - public int getNewRegisterCount() { - return ssaMeth.getRegCount(); - } - - /** @inheritDoc */ - public RegisterSpec map(RegisterSpec registerSpec) { - if (registerSpec.getReg() == specB.getReg()) { - return specA; - } - - return registerSpec; - } - }; - - List<SsaInsn> uses - = ssaMeth.getUseListForRegister(specB.getReg()); - - // Use list is modified by mapSourceRegisters - for (int i = uses.size() - 1; i >= 0; i--) { - SsaInsn use = uses.get(i); - use.mapSourceRegisters(mapper); - } - - deletedInsns.add(insn); - } - - } - }); - - ssaMeth.deleteInsns(deletedInsns); - } - - /** - * Returns the parameter index associated with a move-param insn. Does - * not verify that the insn is a move-param insn. - * - * @param insn non-null; a move-param insn - * @return >=0 parameter index - */ - private int getParamIndex(NormalSsaInsn insn) { - CstInsn cstInsn = (CstInsn)(insn.getOriginalRopInsn()); - - int param = ((CstInteger)cstInsn.getConstant()).getValue(); - return param; - } - -} diff --git a/dx/src/com/android/dx/ssa/NormalSsaInsn.java b/dx/src/com/android/dx/ssa/NormalSsaInsn.java deleted file mode 100644 index ad9315a16..000000000 --- a/dx/src/com/android/dx/ssa/NormalSsaInsn.java +++ /dev/null @@ -1,235 +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.android.dx.ssa; - -import com.android.dx.rop.code.*; - -/** - * A "normal" (non-phi) instruction in SSA form. Always wraps a ROP insn. - */ -public final class NormalSsaInsn extends SsaInsn implements Cloneable { - - /** - * ROP insn that we're wrapping - */ - private Insn insn; - - /** - * Creates an instance. - * - * @param insn Rop insn to wrap - * @param block block that contains this insn - */ - NormalSsaInsn(final Insn insn, final SsaBasicBlock block) { - super(block); - this.insn = insn; - this.result = insn.getResult(); - } - - /** {@inheritDoc} */ - @Override - public final void mapSourceRegisters(RegisterMapper mapper) { - - RegisterSpecList oldSources = insn.getSources(); - RegisterSpecList newSources = mapper.map(oldSources); - - if (newSources != oldSources) { - insn = insn.withNewRegisters(result, newSources); - block.getParent().onSourcesChanged(this, oldSources); - } - } - - /** - * Changes one of the insn's sources. New source should be of same type - * and category. - * - * @param index >=0; index of source to change - * @param newSpec spec for new source - */ - public final void changeOneSource(int index, RegisterSpec newSpec) { - RegisterSpecList origSources = insn.getSources(); - int sz = origSources.size(); - RegisterSpecList newSources = new RegisterSpecList(sz); - - for (int i = 0; i < sz; i++) { - newSources.set(i, i == index ? newSpec : origSources.get(i)); - } - newSources.setImmutable(); - - RegisterSpec origSpec = origSources.get(index); - if (origSpec.getReg() != newSpec.getReg()) { - /* - * If the register remains unchanged, we're only changing - * the type or local var name so don't update use list - */ - block.getParent().onSourceChanged(this, origSpec, newSpec); - } - - insn = insn.withNewRegisters(result, newSources); - } - - /** - * Changes the source list of the insn. New source list should be the - * same size and consist of sources of identical types. - * - * @param newSources non-null new sources list. - */ - public final void setNewSources (RegisterSpecList newSources) { - RegisterSpecList origSources = insn.getSources(); - if (origSources.size() != newSources.size()) { - throw new RuntimeException("Sources counts don't match"); - } - - insn = insn.withNewRegisters(result, newSources); - } - - /** {@inheritDoc} */ - @Override - public NormalSsaInsn clone() { - return (NormalSsaInsn)super.clone(); - } - - /** - * Like rop.Insn.getSources() - * @return null-ok; sources list - */ - public RegisterSpecList getSources() { - return insn.getSources(); - } - - /** {@inheritDoc} */ - public String toHuman() { - return toRopInsn().toHuman(); - } - - /** {@inheritDoc} */ - @Override - public Insn toRopInsn() { - return insn.withNewRegisters(result,insn.getSources()); - } - - /** - * @return the Rop opcode for this insn - */ - @Override - public Rop getOpcode() { - return insn.getOpcode(); - } - - /** {@inheritDoc} */ - @Override - public Insn getOriginalRopInsn() { - return insn; - } - - /** {@inheritDoc} */ - public RegisterSpec getLocalAssignment() { - RegisterSpec assignment; - - if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) { - assignment = insn.getSources().get(0); - } else { - assignment = result; - } - - if (assignment == null) { - return null; - } - - LocalItem local = assignment.getLocalItem(); - - if (local == null) { - return null; - } - - return assignment; - } - - /** - * Upgrades this insn to a version that represents the constant last - * source literally. If the upgrade is not possible, this does nothing. - * - * @see Insn#withLastSourceLiteral - */ - public void upgradeToLiteral() { - RegisterSpecList oldSources = insn.getSources(); - insn = insn.withLastSourceLiteral(); - block.getParent().onSourcesChanged(this, oldSources); - } - - /** - * @return true if this is a move (but not a move-operand) instruction - */ - @Override - public boolean isNormalMoveInsn() { - return insn.getOpcode().getOpcode() == RegOps.MOVE; - } - - /** {@inheritDoc} */ - @Override - public boolean isMoveException() { - return insn.getOpcode().getOpcode() == RegOps.MOVE_EXCEPTION; - } - - /** {@inheritDoc} */ - @Override - public boolean canThrow() { - return insn.canThrow(); - } - - /** {@inheritDoc} */ - @Override - public void accept(Visitor v) { - if (isNormalMoveInsn()) { - v.visitMoveInsn(this); - } else { - v.visitNonMoveInsn(this); - } - } - - /** {@inheritDoc} */ - @Override - public boolean isPhiOrMove() { - return isNormalMoveInsn(); - } - - /** - * {@inheritDoc} - * - * TODO increase the scope of this. - */ - @Override - public boolean hasSideEffect() { - Rop opcode = getOpcode(); - - if (opcode.getBranchingness() != Rop.BRANCH_NONE) { - return true; - } - - boolean hasLocalSideEffect - = Optimizer.getPreserveLocals() && getLocalAssignment() != null; - - switch (opcode.getOpcode()) { - case RegOps.MOVE_RESULT: - case RegOps.MOVE: - case RegOps.CONST: - return hasLocalSideEffect; - default: - return true; - } - } -} diff --git a/dx/src/com/android/dx/ssa/Optimizer.java b/dx/src/com/android/dx/ssa/Optimizer.java deleted file mode 100644 index cee6d7b37..000000000 --- a/dx/src/com/android/dx/ssa/Optimizer.java +++ /dev/null @@ -1,246 +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.android.dx.ssa; - -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.TranslationAdvice; -import com.android.dx.ssa.back.SsaToRop; -import com.android.dx.ssa.back.LivenessAnalyzer; - -import java.util.EnumSet; -import java.util.BitSet; -import java.util.ArrayList; - -/** - * Runs a method through the SSA form conversion, any optimization algorithms, - * and returns it to rop form. - */ -public class Optimizer { - private static boolean preserveLocals = true; - - private static TranslationAdvice advice; - - /** optional optimizer steps */ - public enum OptionalStep { - MOVE_PARAM_COMBINER,SCCP,LITERAL_UPGRADE,CONST_COLLECTOR - } - - /** - * @return true if local variable information should be preserved, even - * at code size/register size cost - */ - public static boolean getPreserveLocals() { - return preserveLocals; - } - - /** - * @return non-null; translation advice - */ - public static TranslationAdvice getAdvice() { - return advice; - } - - /** - * Runs optimization algorthims over this method, and returns a new - * instance of RopMethod with the changes. - * - * @param rmeth method to process - * @param paramWidth the total width, in register-units, of this method's - * parameters - * @param isStatic true if this method has no 'this' pointer argument. - * @param inPreserveLocals true if local variable info should be preserved, - * at the cost of some registers and insns - * @param inAdvice non-null; translation advice - * @return optimized method - */ - public static RopMethod optimize(RopMethod rmeth, int paramWidth, - boolean isStatic, boolean inPreserveLocals, - TranslationAdvice inAdvice) { - - return optimize(rmeth, paramWidth, isStatic, inPreserveLocals, inAdvice, - EnumSet.allOf(OptionalStep.class)); - } - - /** - * Runs optimization algorthims over this method, and returns a new - * instance of RopMethod with the changes. - * - * @param rmeth method to process - * @param paramWidth the total width, in register-units, of this method's - * parameters - * @param isStatic true if this method has no 'this' pointer argument. - * @param inPreserveLocals true if local variable info should be preserved, - * at the cost of some registers and insns - * @param inAdvice non-null; translation advice - * @param steps set of optional optimization steps to run - * @return optimized method - */ - public static RopMethod optimize(RopMethod rmeth, int paramWidth, - boolean isStatic, boolean inPreserveLocals, - TranslationAdvice inAdvice, EnumSet<OptionalStep> steps) { - SsaMethod ssaMeth = null; - - preserveLocals = inPreserveLocals; - advice = inAdvice; - - ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic); - runSsaFormSteps(ssaMeth, steps); - - RopMethod resultMeth = SsaToRop.convertToRopMethod(ssaMeth, false); - - if (resultMeth.getBlocks().getRegCount() - > advice.getMaxOptimalRegisterCount()) { - // Try to see if we can squeeze it under the register count bar - resultMeth = optimizeMinimizeRegisters(rmeth, paramWidth, isStatic, - steps); - } - return resultMeth; - } - - /** - * Runs the optimizer with a strategy to minimize the number of rop-form - * registers used by the end result. Dex bytecode does not have instruction - * forms that take register numbers larger than 15 for all instructions. - * If we've produced a method that uses more than 16 registers, try again - * with a different strategy to see if we can get under the bar. The end - * result will be much more efficient. - * - * @param rmeth method to process - * @param paramWidth the total width, in register-units, of this method's - * parameters - * @param isStatic true if this method has no 'this' pointer argument. - * @param steps set of optional optimization steps to run - * @return optimized method - */ - private static RopMethod optimizeMinimizeRegisters(RopMethod rmeth, - int paramWidth, boolean isStatic, - EnumSet<OptionalStep> steps) { - SsaMethod ssaMeth; - RopMethod resultMeth; - - ssaMeth = SsaConverter.convertToSsaMethod( - rmeth, paramWidth, isStatic); - - EnumSet<OptionalStep> newSteps = steps.clone(); - - /* - * CONST_COLLECTOR trades insns for registers, which is not an - * appropriate strategy here. - */ - newSteps.remove(OptionalStep.CONST_COLLECTOR); - - runSsaFormSteps(ssaMeth, newSteps); - - resultMeth = SsaToRop.convertToRopMethod(ssaMeth, true); - return resultMeth; - } - - private static void runSsaFormSteps(SsaMethod ssaMeth, - EnumSet<OptionalStep> steps) { - boolean needsDeadCodeRemover = true; - - if (steps.contains(OptionalStep.MOVE_PARAM_COMBINER)) { - MoveParamCombiner.process(ssaMeth); - } - - if (steps.contains(OptionalStep.SCCP)) { - SCCP.process(ssaMeth); - } - - if (steps.contains(OptionalStep.LITERAL_UPGRADE)) { - LiteralOpUpgrader.process(ssaMeth); - DeadCodeRemover.process(ssaMeth); - needsDeadCodeRemover = false; - } - - if (steps.contains(OptionalStep.CONST_COLLECTOR)) { - ConstCollector.process(ssaMeth); - DeadCodeRemover.process(ssaMeth); - needsDeadCodeRemover = false; - } - - // dead code remover must be run before phi type resolver - if (needsDeadCodeRemover) { - DeadCodeRemover.process(ssaMeth); - } - - PhiTypeResolver.process(ssaMeth); - } - - public static SsaMethod debugEdgeSplit(RopMethod rmeth, int paramWidth, - boolean isStatic, boolean inPreserveLocals, - TranslationAdvice inAdvice) { - - preserveLocals = inPreserveLocals; - advice = inAdvice; - - return SsaConverter.testEdgeSplit(rmeth, paramWidth, isStatic); - } - - public static SsaMethod debugPhiPlacement(RopMethod rmeth, int paramWidth, - boolean isStatic, boolean inPreserveLocals, - TranslationAdvice inAdvice) { - - preserveLocals = inPreserveLocals; - advice = inAdvice; - - return SsaConverter.testPhiPlacement(rmeth, paramWidth, isStatic); - } - - public static SsaMethod debugRenaming(RopMethod rmeth, int paramWidth, - boolean isStatic, boolean inPreserveLocals, - TranslationAdvice inAdvice) { - - preserveLocals = inPreserveLocals; - advice = inAdvice; - - return SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic); - } - - public static SsaMethod debugDeadCodeRemover(RopMethod rmeth, - int paramWidth, boolean isStatic, boolean inPreserveLocals, - TranslationAdvice inAdvice) { - - SsaMethod ssaMeth; - - preserveLocals = inPreserveLocals; - advice = inAdvice; - - ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic); - DeadCodeRemover.process(ssaMeth); - - return ssaMeth; - } - - public static SsaMethod debugNoRegisterAllocation(RopMethod rmeth, - int paramWidth, boolean isStatic, boolean inPreserveLocals, - TranslationAdvice inAdvice, EnumSet<OptionalStep> steps) { - - SsaMethod ssaMeth; - - preserveLocals = inPreserveLocals; - advice = inAdvice; - - ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic); - - runSsaFormSteps(ssaMeth, steps); - - LivenessAnalyzer.constructInterferenceGraph(ssaMeth); - - return ssaMeth; - } -} diff --git a/dx/src/com/android/dx/ssa/PhiInsn.java b/dx/src/com/android/dx/ssa/PhiInsn.java deleted file mode 100644 index 1829133bb..000000000 --- a/dx/src/com/android/dx/ssa/PhiInsn.java +++ /dev/null @@ -1,364 +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.android.dx.ssa; - -import com.android.dx.rop.code.*; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.util.Hex; - -import java.util.ArrayList; -import java.util.List; - -/** - * A Phi instruction (magical post-control-flow-merge) instruction - * in SSA form. Will be converted to moves in predecessor blocks before - * conversion back to ROP form. - */ -public final class PhiInsn extends SsaInsn { - - /** - * the original result register of the phi insn is needed during the - * renaming process after the new result register has already been chosen. - */ - private int ropResultReg; - private ArrayList<Operand> operands = new ArrayList<Operand>(); - private RegisterSpecList sources; - - /** - * A single phi operand, consiting of source register and block index - * for move. - */ - class Operand { - RegisterSpec regSpec; - int blockIndex; - int ropLabel; //mostly for debugging - - Operand (final RegisterSpec regSpec, final int blockIndex, - final int ropLabel){ - this.regSpec = regSpec; - this.blockIndex = blockIndex; - this.ropLabel = ropLabel; - } - } - - public static interface Visitor { - public void visitPhiInsn(PhiInsn insn); - } - - public PhiInsn clone() { - throw new UnsupportedOperationException("can't clone phi"); - } - - /** - * Constructs a new phi insn with no operands. - * @param resultReg the result reg for this phi insn - * @param block block containing this insn. - */ - PhiInsn(final RegisterSpec resultReg, final SsaBasicBlock block) { - super(block); - this.result = resultReg; - ropResultReg = resultReg.getReg(); - } - - /** - * Makes a phi insn with a void result type. - * @param resultReg the result register for this phi insn. - * @param block block containing this insn. - */ - PhiInsn(final int resultReg, final SsaBasicBlock block) { - super(block); - - /* - * The type here is bogus: the type depends on the operand and - * will be derived later. - */ - this.result = RegisterSpec.make(resultReg, Type.VOID); - ropResultReg = resultReg; - } - - /** - * Updates the TypeBearers of all the sources (phi operands) to be - * the current TypeBearer of the register-defining instruction's result. - * This is used during phi-type resolution.<p> - * - * Note that local association of operands are preserved in this step. - * - * @param ssaMeth method that contains this insn - */ - void updateSourcesToDefinitions(SsaMethod ssaMeth) { - - for (Operand o: operands) { - RegisterSpec def - = ssaMeth.getDefinitionForRegister( - o.regSpec.getReg()).getResult(); - - o.regSpec = o.regSpec.withType(def.getType()); - } - - sources = null; - } - - /** - * Changes the result type. Used during phi type resolution - * - * @param type non-null; new TypeBearer - * @param local null-ok; new local info, if available - */ - void changeResultType(TypeBearer type, LocalItem local) { - result = RegisterSpec.makeLocalOptional(result.getReg(), type, local); - } - - /** - * @return the original rop-form result reg. Useful during renaming. - */ - int getRopResultReg() { - return ropResultReg; - } - - /** - * Add an operand to this phi instruction - * @param registerSpec register spec, including type and reg of operand - * @param predBlock Predecessor block to be associated with this operand - */ - public void addPhiOperand(RegisterSpec registerSpec, - SsaBasicBlock predBlock) { - operands.add(new Operand(registerSpec, predBlock.getIndex(), - predBlock.getRopLabel())); - - // in case someone has already called getSources() - sources = null; - } - - /** - * Gets the index of the pred block associated with the RegisterSpec - * at the particular getSources() index. - * @param sourcesIndex index of source in getSources() - * @return block index - */ - public int predBlockIndexForSourcesIndex(int sourcesIndex) { - return operands.get(sourcesIndex).blockIndex; - } - - /** - * {@inheritDoc} - * - * Always returns null for <code>PhiInsn</code>s - */ - @Override - public Rop getOpcode() { - return null; - } - - /** - * {@inheritDoc} - * - * Always returns null for <code>PhiInsn</code>s - */ - @Override - public Insn getOriginalRopInsn() { - return null; - } - - - /** - * {@inheritDoc} - * - * Always returns false for <code>PhiInsn</code>s - */ - @Override - public boolean canThrow() { - return false; - } - - /** - * Gets sources. Constructed lazily from phi operand data structures and - * then cached. - * @return sources list - */ - public RegisterSpecList getSources() { - - if (sources != null) { - return sources; - } - - if (operands.size() == 0) { - // How'd this happen? A phi insn with no operand? - return RegisterSpecList.EMPTY; - } - - int szSources = operands.size(); - sources = new RegisterSpecList(szSources); - - for (int i = 0; i < szSources; i++) { - Operand o = operands.get(i); - - sources.set(i, o.regSpec); - } - - sources.setImmutable(); - return sources; - } - - /** {@inheritDoc} */ - @Override - public boolean isRegASource(int reg) { - /* - * Avoid creating a sources list in case it has not already been - * created - */ - - for (Operand o: operands) { - if (o.regSpec.getReg() == reg) { - return true; - } - } - - return false; - } - - /** - * @return true if all operands use the same register - */ - public boolean areAllOperandsEqual() { - if (operands.size() == 0 ) { - // this should never happen - return true; - } - - int firstReg = operands.get(0).regSpec.getReg(); - for (Operand o: operands) { - if (firstReg != o.regSpec.getReg()) { - return false; - } - } - - return true; - } - - /** {@inheritDoc} */ - @Override - public final void mapSourceRegisters(RegisterMapper mapper) { - for (Operand o: operands) { - RegisterSpec old = o.regSpec; - o.regSpec = mapper.map(old); - if (old != o.regSpec) { - block.getParent().onSourceChanged(this, old, o.regSpec); - } - } - sources = null; - } - - /** - * Always throws an exeption, since - * a phi insn may not be converted back to rop form - * @return always throws exception - */ - @Override - public Insn toRopInsn() { - throw new IllegalArgumentException( - "Cannot convert phi insns to rop form"); - } - - /** - * Returns the list of predecessor blocks associated with all operands - * that have <code>reg</code> as an operand register. - * - * @param reg register to look up - * @param ssaMeth method we're operating on - * @return List of predecessor blocks, empty if none - */ - public List<SsaBasicBlock> predBlocksForReg (int reg, SsaMethod ssaMeth) { - ArrayList<SsaBasicBlock> ret - = (ArrayList<SsaBasicBlock>)new ArrayList(); - - for (Operand o: operands) { - if (o.regSpec.getReg() == reg) { - ret.add(ssaMeth.getBlocks().get(o.blockIndex)); - } - } - - return ret; - } - - /** {@inheritDoc} */ - @Override - public boolean isPhiOrMove() { - return true; - } - - /** {@inheritDoc} */ - @Override public boolean hasSideEffect() { - return Optimizer.getPreserveLocals() && getLocalAssignment() != null; - } - - /** {@inheritDoc} */ - @Override - public void accept(SsaInsn.Visitor v) { - v.visitPhiInsn(this); - } - - /** - * @return human-readable string for listing dumps - */ - public String toHuman() { - return toHumanWithInline(null); - } - - /** - * Returns human-readable string for listing dumps. - * Allows sub-classes to specify extra text - * @param extra null-ok; the argument to print after the opcode - * @return human-readable string for listing dumps - */ - protected final String toHumanWithInline(String extra) { - StringBuffer sb = new StringBuffer(80); - - sb.append(SourcePosition.NO_INFO); - sb.append(": "); - sb.append("phi"); - - if (extra != null) { - sb.append("("); - sb.append(extra); - sb.append(")"); - } - - if (result == null) { - sb.append(" ."); - } else { - sb.append(" "); - sb.append(result.toHuman()); - } - - sb.append(" <-"); - - int sz = getSources().size(); - if (sz == 0) { - sb.append(" ."); - } else { - for (int i = 0; i < sz; i++) { - sb.append(" "); - sb.append(sources.get(i).toHuman() - + "[b=" - + Hex.u2(operands.get(i).ropLabel) + "]"); - } - } - - return sb.toString(); - } -} diff --git a/dx/src/com/android/dx/ssa/PhiTypeResolver.java b/dx/src/com/android/dx/ssa/PhiTypeResolver.java deleted file mode 100644 index f4c26d700..000000000 --- a/dx/src/com/android/dx/ssa/PhiTypeResolver.java +++ /dev/null @@ -1,200 +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.android.dx.ssa; - -import com.android.dx.cf.code.Merger; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.LocalItem; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeBearer; - -import java.util.BitSet; -import java.util.List; - -/** - * Resolves the result types of phi instructions. When phi instructions - * are inserted, their result types are set to BT_VOID (which is a nonsensical - * type for a register) but must be resolve to a real type before converting - * out of SSA form.<p> - * - * The resolve is done as an iterative merge of each phi's operand types. - * Phi operands may be themselves be the result of unresolved phis, - * and the algorithm tries to find the most-fit type (for example, if every - * operand is the same constant value or the same local variable info, we want - * that to be reflected).<p> - * - * This algorithm assumes a dead-code remover has already removed all - * circular-only phis that may have been inserted. - */ -public class PhiTypeResolver { - - SsaMethod ssaMeth; - /** indexed by register; all registers still defined by unresolved phis */ - private final BitSet worklist; - - /** - * Resolves all phi types in the method - * @param ssaMeth method to process - */ - public static void process (SsaMethod ssaMeth) { - new PhiTypeResolver(ssaMeth).run(); - } - - private PhiTypeResolver(SsaMethod ssaMeth) { - this.ssaMeth = ssaMeth; - worklist = new BitSet(ssaMeth.getRegCount()); - } - - /** - * Runs the phi-type resolver. - */ - private void run() { - - int regCount = ssaMeth.getRegCount(); - - for (int reg = 0; reg < regCount; reg++) { - SsaInsn definsn = ssaMeth.getDefinitionForRegister(reg); - - if (definsn != null - && (definsn.getResult().getBasicType() == Type.BT_VOID)) { - worklist.set(reg); - } - } - - int reg; - while ( 0 <= (reg = worklist.nextSetBit(0))) { - worklist.clear(reg); - - /* - * definitions on the worklist have a type of BT_VOID, which - * must have originated from a PhiInsn. - */ - PhiInsn definsn = (PhiInsn)ssaMeth.getDefinitionForRegister(reg); - - if (resolveResultType(definsn)) { - /* - * If the result type has changed, re-resolve all phis - * that use this. - */ - - List<SsaInsn> useList = ssaMeth.getUseListForRegister(reg); - - int sz = useList.size(); - for (int i = 0; i < sz; i++ ) { - SsaInsn useInsn = useList.get(i); - RegisterSpec resultReg = useInsn.getResult(); - if (resultReg != null && useInsn instanceof PhiInsn) { - worklist.set(resultReg.getReg()); - } - } - } - } - } - - /** - * Returns true if a and b are equal, whether - * or not either of them are null. - * @param a - * @param b - * @return true if equal - */ - private static boolean equalsHandlesNulls(LocalItem a, LocalItem b) { - return (a == b) || ((a != null) && a.equals(b)); - } - - /** - * Resolves the result of a phi insn based on its operands. The "void" - * type, which is a nonsensical type for a register, is used for - * registers defined by as-of-yet-unresolved phi operations. - * - * @return true if the result type changed, false if no change - */ - boolean resolveResultType(PhiInsn insn) { - insn.updateSourcesToDefinitions(ssaMeth); - - RegisterSpecList sources = insn.getSources(); - - // Start by finding the first non-void operand - RegisterSpec first = null; - int firstIndex = -1; - - int szSources = sources.size(); - for (int i = 0 ; i <szSources ; i++) { - RegisterSpec rs = sources.get(i); - - if (rs.getBasicType() != Type.BT_VOID) { - first = rs; - firstIndex = i; - } - } - - if (first == null) { - // All operands are void -- we're not ready to resolve yet - return false; - } - - LocalItem firstLocal = first.getLocalItem(); - TypeBearer mergedType = first.getType(); - boolean sameLocals = true; - for (int i = 0 ; i < szSources ; i++) { - if (i == firstIndex) { - continue; - } - - RegisterSpec rs = sources.get(i); - - // Just skip void (unresolved phi results) for now - if (rs.getBasicType() == Type.BT_VOID){ - continue; - } - - sameLocals = sameLocals - && equalsHandlesNulls(firstLocal, rs.getLocalItem()); - - mergedType = Merger.mergeType(mergedType, rs.getType()); - } - - TypeBearer newResultType; - - if (mergedType != null) { - newResultType = mergedType; - } else { - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < szSources; i++) { - sb.append(sources.get(i).toString()); - sb.append(' '); - } - - throw new RuntimeException ("Couldn't map types in phi insn:" + sb); - } - - LocalItem newLocal = sameLocals ? firstLocal : null; - - RegisterSpec result = insn.getResult(); - - if ((result.getTypeBearer() == newResultType) - && equalsHandlesNulls(newLocal, result.getLocalItem())) { - return false; - } - - insn.changeResultType(newResultType, newLocal); - - return true; - } -} diff --git a/dx/src/com/android/dx/ssa/RegisterMapper.java b/dx/src/com/android/dx/ssa/RegisterMapper.java deleted file mode 100644 index 98503e2d8..000000000 --- a/dx/src/com/android/dx/ssa/RegisterMapper.java +++ /dev/null @@ -1,63 +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.android.dx.ssa; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.util.ToHuman; - -/** - * Represents a mapping between two register numbering schemes. - * Subclasses of this may be mutable, and as such the mapping provided is only - * valid for the lifetime of the method call in which instances of this class - * are passed. - */ -public abstract class RegisterMapper { - - /** - * Gets the count of registers (really, the total register width, since - * category width is counted) in the new namespace. - * @return >= 0 width of new namespace. - */ - public abstract int getNewRegisterCount(); - - /** - * @param registerSpec old register - * @return register in new space - */ - public abstract RegisterSpec map(RegisterSpec registerSpec); - - /** - * - * @param sources old register list - * @return new mapped register list, or old if nothing has changed. - */ - public final RegisterSpecList map(RegisterSpecList sources) { - RegisterSpecList newSources; - - newSources = new RegisterSpecList(sources.size()); - - int sz = sources.size(); - for (int i = 0; i < sz; i++) { - newSources.set(i, map(sources.get(i))); - } - - newSources.setImmutable(); - // Return the old sources if nothing has changed - return newSources.equals(sources)? sources: newSources; - } -} diff --git a/dx/src/com/android/dx/ssa/SCCP.java b/dx/src/com/android/dx/ssa/SCCP.java deleted file mode 100644 index 1d95da63c..000000000 --- a/dx/src/com/android/dx/ssa/SCCP.java +++ /dev/null @@ -1,486 +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.android.dx.ssa; - -import com.android.dx.rop.code.CstInsn; -import com.android.dx.rop.code.Insn; -import com.android.dx.rop.code.RegOps; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.Rop; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.TypedConstant; -import com.android.dx.rop.type.TypeBearer; -import com.android.dx.rop.type.Type; - -import java.util.ArrayList; -import java.util.BitSet; - -/** - * A small variant of Wegman and Zadeck's Sparse Conditional Constant - * Propagation algorithm. - */ -public class SCCP { - /** Lattice values */ - private static final int TOP = 0; - private static final int CONSTANT = 1; - private static final int VARYING = 2; - /** method we're processing */ - private SsaMethod ssaMeth; - /** ssaMeth.getRegCount() */ - private int regCount; - /** Lattice values for each SSA register */ - private int[] latticeValues; - /** For those registers that are constant, this is the constant value */ - private Constant[] latticeConstants; - /** Worklist of basic blocks to be processed */ - private ArrayList<SsaBasicBlock> cfgWorklist; - /** Bitset containing bits for each block that has been found executable */ - private BitSet executableBlocks; - /** Worklist for SSA edges. This is a list of registers to process */ - private ArrayList<SsaInsn> ssaWorklist; - /** - * Worklist for SSA edges that represent varying values. It makes the - * algorithm much faster if you move all values to VARYING as fast as - * possible. - */ - private ArrayList<SsaInsn> varyingWorklist; - - private SCCP(SsaMethod ssaMeth) { - this.ssaMeth = ssaMeth; - this.regCount = ssaMeth.getRegCount(); - this.latticeValues = new int[this.regCount]; - this.latticeConstants = new Constant[this.regCount]; - this.cfgWorklist = new ArrayList<SsaBasicBlock>(); - this.executableBlocks = new BitSet(ssaMeth.getBlocks().size()); - this.ssaWorklist = new ArrayList<SsaInsn>(); - this.varyingWorklist = new ArrayList<SsaInsn>(); - for (int i = 0; i < this.regCount; i++) { - latticeValues[i] = TOP; - latticeConstants[i] = null; - } - } - - /** - * Performs sparse conditional constant propagation on a method. - * @param ssaMethod Method to process - */ - public static void process (SsaMethod ssaMethod) { - new SCCP(ssaMethod).run(); - } - - /** - * Add a new SSA basic block to the CFG worklist - * @param ssaBlock Block to add - */ - private void addBlockToWorklist(SsaBasicBlock ssaBlock) { - if (!executableBlocks.get(ssaBlock.getIndex())) { - cfgWorklist.add(ssaBlock); - executableBlocks.set(ssaBlock.getIndex()); - } - } - - /** - * Adds an SSA register's uses to the SSA worklist. - * @param reg SSA register - * @param latticeValue new lattice value for @param reg. - */ - private void addUsersToWorklist(int reg, int latticeValue) { - if (latticeValue == VARYING) { - for (SsaInsn insn: ssaMeth.getUseListForRegister(reg)) { - varyingWorklist.add(insn); - } - } else { - for (SsaInsn insn: ssaMeth.getUseListForRegister(reg)) { - ssaWorklist.add(insn); - } - } - } - - /** - * Sets a lattice value for a register to value. - * @param reg SSA register - * @param value Lattice value - * @param cst Constant value (may be null) - * @return true if the lattice value changed. - */ - private boolean setLatticeValueTo(int reg, int value, Constant cst) { - if (value != CONSTANT) { - if (latticeValues[reg] != value) { - latticeValues[reg] = value; - return true; - } - return false; - } else { - if (latticeValues[reg] != value - || !latticeConstants[reg].equals(cst)) { - latticeValues[reg] = value; - latticeConstants[reg] = cst; - return true; - } - return false; - } - } - - private boolean setLatticeValueTo(int reg, int value) { - return setLatticeValueTo(reg, value, null); - } - /** - * Simulates a PHI node and set the lattice for the result - * to the approriate value. - * Meet values: - * TOP x anything = anything - * VARYING x anything = VARYING - * CONSTANT x CONSTANT = CONSTANT if equal constants, VARYING otherwise - * @param insn PHI to simulate. - */ - private void simulatePhi(PhiInsn insn) { - int phiResultReg = insn.getResult().getReg(); - - if (latticeValues[phiResultReg] == VARYING) { - return; - } - - RegisterSpecList sources = insn.getSources(); - int phiResultValue = TOP; - Constant phiConstant = null; - int sourceSize = sources.size(); - for (int i = 0; i < sourceSize; i++) { - int predBlockIndex = insn.predBlockIndexForSourcesIndex(i); - int sourceReg = sources.get(i).getReg(); - int sourceRegValue = latticeValues[sourceReg]; - - if (!executableBlocks.get(predBlockIndex) - || sourceRegValue == TOP) { - continue; - } - - if (sourceRegValue == CONSTANT) { - if (phiConstant == null) { - phiConstant = latticeConstants[sourceReg]; - phiResultValue = CONSTANT; - } else if (!latticeConstants[sourceReg].equals(phiConstant)){ - phiResultValue = VARYING; - break; - } - - } else if (sourceRegValue == VARYING) { - phiResultValue = VARYING; - break; - } - } - if (setLatticeValueTo(phiResultReg, phiResultValue, phiConstant)) { - addUsersToWorklist(phiResultReg, phiResultValue); - } - } - - /** - * Simulate a block and note the results in the lattice. - * @param block Block to visit - */ - private void simulateBlock(SsaBasicBlock block) { - for (SsaInsn insn: block.getInsns()) { - if (insn instanceof PhiInsn) { - simulatePhi((PhiInsn) insn); - } else { - simulateStmt(insn); - } - } - } - private static String latticeValName(int latticeVal) { - switch (latticeVal) { - case TOP: return "TOP"; - case CONSTANT: return "CONSTANT"; - case VARYING: return "VARYING"; - default: return "UNKNOWN"; - } - } - - /** - * Simplifies a jump statement. - * @param insn jump to simplify - * @return an instruction representing the simplified jump. - */ - private Insn simplifyJump (Insn insn) { - return insn; - } - - /** - * Simulates math insns, if possible. - * - * @param insn non-null insn to simulate - * @return constant result or null if not simulatable. - */ - private Constant simulateMath(SsaInsn insn) { - Insn ropInsn = insn.getOriginalRopInsn(); - int opcode = insn.getOpcode().getOpcode(); - RegisterSpecList sources = insn.getSources(); - int regA = sources.get(0).getReg(); - Constant cA; - Constant cB; - - if (latticeValues[regA] != CONSTANT) { - cA = null; - } else { - cA = latticeConstants[regA]; - } - - if (sources.size() == 1) { - CstInsn cstInsn = (CstInsn) ropInsn; - cB = cstInsn.getConstant(); - } else { /* sources.size() == 2 */ - int regB = sources.get(1).getReg(); - if (latticeValues[regB] != CONSTANT) { - cB = null; - } else { - cB = latticeConstants[regB]; - } - } - - if (cA == null || cB == null) { - //TODO handle a constant of 0 with MUL or AND - return null; - } - - switch (insn.getResult().getBasicType()) { - case Type.BT_INT: - int vR; - boolean skip=false; - - int vA = ((CstInteger) cA).getValue(); - int vB = ((CstInteger) cB).getValue(); - - switch (opcode) { - case RegOps.ADD: - vR = vA + vB; - break; - case RegOps.SUB: - vR = vA - vB; - break; - case RegOps.MUL: - vR = vA * vB; - break; - case RegOps.DIV: - if (vB == 0) { - skip = true; - vR = 0; // just to hide a warning - } else { - vR = vA / vB; - } - break; - case RegOps.AND: - vR = vA & vB; - break; - case RegOps.OR: - vR = vA | vB; - break; - case RegOps.XOR: - vR = vA ^ vB; - break; - case RegOps.SHL: - vR = vA << vB; - break; - case RegOps.SHR: - vR = vA >> vB; - break; - case RegOps.USHR: - vR = vA >>> vB; - break; - case RegOps.REM: - vR = vA % vB; - break; - default: - throw new RuntimeException("Unexpected op"); - } - - return skip ? null : CstInteger.make(vR); - - default: - // not yet supported - return null; - } - } - - /** - * Simulates a statement and set the result lattice value. - * @param insn instruction to simulate - */ - private void simulateStmt(SsaInsn insn) { - Insn ropInsn = insn.getOriginalRopInsn(); - if (ropInsn.getOpcode().getBranchingness() != Rop.BRANCH_NONE - || ropInsn.getOpcode().isCallLike()) { - ropInsn = simplifyJump (ropInsn); - /* TODO: If jump becomes constant, only take true edge. */ - SsaBasicBlock block = insn.getBlock(); - int successorSize = block.getSuccessorList().size(); - for (int i = 0; i < successorSize; i++) { - int successor = block.getSuccessorList().get(i); - addBlockToWorklist(ssaMeth.getBlocks().get(successor)); - } - } - - if (insn.getResult() == null) { - return; - } - - /* TODO: Simplify statements when possible using the constants. */ - int resultReg = insn.getResult().getReg(); - int resultValue = VARYING; - Constant resultConstant = null; - int opcode = insn.getOpcode().getOpcode(); - switch (opcode) { - case RegOps.CONST: { - CstInsn cstInsn = (CstInsn)ropInsn; - resultValue = CONSTANT; - resultConstant = cstInsn.getConstant(); - break; - } - case RegOps.MOVE: { - if (insn.getSources().size() == 1) { - int sourceReg = insn.getSources().get(0).getReg(); - resultValue = latticeValues[sourceReg]; - resultConstant = latticeConstants[sourceReg]; - } - break; - } - - case RegOps.ADD: - case RegOps.SUB: - case RegOps.MUL: - case RegOps.DIV: - case RegOps.AND: - case RegOps.OR: - case RegOps.XOR: - case RegOps.SHL: - case RegOps.SHR: - case RegOps.USHR: - case RegOps.REM: - - resultConstant = simulateMath(insn); - - if (resultConstant == null) { - resultValue = VARYING; - } else { - resultValue = CONSTANT; - } - break; - /* TODO: Handle non-int arithmetic. - TODO: Eliminate check casts that we can prove the type of. */ - default: {} - } - if (setLatticeValueTo(resultReg, resultValue, resultConstant)) { - addUsersToWorklist(resultReg, resultValue); - } - } - - private void run() { - SsaBasicBlock firstBlock = ssaMeth.getEntryBlock(); - addBlockToWorklist(firstBlock); - - /* Empty all the worklists by propagating our values */ - while (!cfgWorklist.isEmpty() - || !ssaWorklist.isEmpty() - || !varyingWorklist.isEmpty()) { - while (!cfgWorklist.isEmpty()) { - int listSize = cfgWorklist.size() - 1; - SsaBasicBlock block = cfgWorklist.remove(listSize); - simulateBlock(block); - } - while (!varyingWorklist.isEmpty()) { - int listSize = varyingWorklist.size() - 1; - SsaInsn insn = varyingWorklist.remove(listSize); - - if (!executableBlocks.get(insn.getBlock().getIndex())) { - continue; - } - - if (insn instanceof PhiInsn) { - simulatePhi((PhiInsn)insn); - } else { - simulateStmt(insn); - } - } - while (!ssaWorklist.isEmpty()) { - int listSize = ssaWorklist.size() - 1; - SsaInsn insn = ssaWorklist.remove(listSize); - - if (!executableBlocks.get(insn.getBlock().getIndex())) { - continue; - } - - if (insn instanceof PhiInsn) { - simulatePhi((PhiInsn)insn); - } else { - simulateStmt(insn); - } - } - } - - replaceConstants(); - } - - /** - * Replaces TypeBearers in source register specs with constant type - * bearers if possible. These are then referenced in later optimization - * steps. - */ - private void replaceConstants() { - for (int reg = 0; reg < regCount; reg++) { - if (latticeValues[reg] != CONSTANT) { - continue; - } - if (!(latticeConstants[reg] instanceof TypedConstant)) { - // We can't do much with these - continue; - } - - SsaInsn defn = ssaMeth.getDefinitionForRegister(reg); - TypeBearer typeBearer = defn.getResult().getTypeBearer(); - - if (typeBearer.isConstant()) { - /* - * The definition was a constant already. - * The uses should be as well. - */ - continue; - } - - /* - * Update the sources RegisterSpec's of all non-move uses. - * These will be used in later steps. - */ - for(SsaInsn insn: ssaMeth.getUseListForRegister(reg)) { - if (insn.isPhiOrMove()) { - continue; - } - - NormalSsaInsn nInsn = (NormalSsaInsn) insn; - RegisterSpecList sources = insn.getSources(); - - int index = sources.indexOfRegister(reg); - - RegisterSpec spec = sources.get(index); - RegisterSpec newSpec - = spec.withType((TypedConstant)latticeConstants[reg]); - - - nInsn.changeOneSource(index, newSpec); - } - } - } -} diff --git a/dx/src/com/android/dx/ssa/SetFactory.java b/dx/src/com/android/dx/ssa/SetFactory.java deleted file mode 100644 index f34d08d91..000000000 --- a/dx/src/com/android/dx/ssa/SetFactory.java +++ /dev/null @@ -1,95 +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.android.dx.ssa; - -import com.android.dx.util.BitIntSet; -import com.android.dx.util.IntSet; -import com.android.dx.util.ListIntSet; - - -/** - * Makes int sets for various parts of the optimizer. - */ -public final class SetFactory { - - /** - * BitIntSet/ListIntSet threshold for dominance frontier sets. These - * sets are kept per basic block until phi placement and tend to be, - * like the CFG itself, very sparse at large sizes. - * - * A value of 3072 here is somewhere around 1.125mb of total bitset size. - */ - private static final int DOMFRONT_SET_THRESHOLD_SIZE = 3072; - - /** - * BitIntSet/ListIntSet threshold for interference graph sets. These - * sets are kept per register until register allocation is done. - * - * A value of 3072 here is somewhere around 1.125mb of total bitset size. - */ - private static final int INTERFERENCE_SET_THRESHOLD_SIZE = 3072; - - /** - * BitIntSet/ListIntSet threshold for the live in/out sets kept by - * {@link SsaBasicBlock}. These are sets of SSA registers kept per basic - * block during register allocation. - * - * The total size of a bitset for this would be the count of blocks - * times the size of registers. The threshold value here is merely - * the register count, which is typically on the order of the block - * count as well. - */ - private static final int LIVENESS_SET_THRESHOLD_SIZE = 3072; - - - /** - * Make IntSet for the dominance-frontier sets. - * - * @param szBlocks >=0; count of basic blocks in method - * @return non-null; appropriate set - */ - /*package*/ static IntSet makeDomFrontSet(int szBlocks) { - return szBlocks <= DOMFRONT_SET_THRESHOLD_SIZE - ? new BitIntSet(szBlocks) - : new ListIntSet(); - } - - /** - * Make IntSet for the interference graph sets. Public because - * InterferenceGraph is in another package. - * - * @param countRegs >=0; count of SSA registers used in method - * @return non-null; appropriate set - */ - public static IntSet makeInterferenceSet(int countRegs) { - return countRegs <= INTERFERENCE_SET_THRESHOLD_SIZE - ? new BitIntSet(countRegs) - : new ListIntSet(); - } - - /** - * Make IntSet for register live in/out sets. - * - * @param countRegs >=0; count of SSA registers used in method - * @return non-null; appropriate set - */ - /*package*/ static IntSet makeLivenessSet(int countRegs) { - return countRegs <= LIVENESS_SET_THRESHOLD_SIZE - ? new BitIntSet(countRegs) - : new ListIntSet(); - } -} diff --git a/dx/src/com/android/dx/ssa/SsaBasicBlock.java b/dx/src/com/android/dx/ssa/SsaBasicBlock.java deleted file mode 100644 index 99ada7edb..000000000 --- a/dx/src/com/android/dx/ssa/SsaBasicBlock.java +++ /dev/null @@ -1,949 +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.android.dx.ssa; - -import com.android.dx.rop.code.BasicBlock; -import com.android.dx.rop.code.BasicBlockList; -import com.android.dx.rop.code.InsnList; -import com.android.dx.rop.code.PlainInsn; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.Rops; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.code.Insn; -import com.android.dx.rop.code.Rop; -import com.android.dx.util.IntList; -import com.android.dx.util.Hex; -import com.android.dx.util.IntSet; -import com.android.dx.util.BitIntSet; -import com.android.dx.util.ListIntSet; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Collections; -import java.util.List; - -/** - * An SSA representation of a basic block. - */ -public final class SsaBasicBlock { - - /** non-null; insn list associated with this instance */ - private ArrayList<SsaInsn> insns; - /** non-null; predecessor set (by block list index) */ - private BitSet predecessors; - /** non-null; successor set (by block list index) */ - private BitSet successors; - /** - * non-null; ordered successor list - * (same block may be listed more than once) - */ - private IntList successorList; - /** block list index of primary successor, or -1 for no primary successor */ - private int primarySuccessor = -1; - /** label of block in rop form */ - private int ropLabel; - /** non-null; method we belong to */ - private SsaMethod parent; - /** our index into parent.getBlock() */ - private int index; - /** list of dom children */ - private final ArrayList<SsaBasicBlock> domChildren; - - /** - * The number of moves added to the end of the block during the - * phi-removal process. Retained for subsequent move scheduling. - */ - private int movesFromPhisAtEnd = 0; - /** - * The number of moves added to the beginning of the block during the - * phi-removal process. Retained for subsequent move scheduling. - */ - private int movesFromPhisAtBeginning = 0; - - /** null-ok; indexed by reg: the regs that are live-in at this block */ - private IntSet liveIn; - /** null-ok; indexed by reg: the regs that are live-out at this block */ - private IntSet liveOut; - - /** - * Create a new empty basic block - * @param basicBlockIndex index this block will have - * @param ropLabel original rop-form label - * @param parent method of this block - */ - public SsaBasicBlock(final int basicBlockIndex, final int ropLabel, - final SsaMethod parent) { - this.parent = parent; - this.index = basicBlockIndex; - this.insns = new ArrayList<SsaInsn>(); - this.ropLabel = ropLabel; - - this.predecessors = new BitSet(parent.getBlocks().size()); - this.successors = new BitSet(parent.getBlocks().size()); - this.successorList = new IntList(); - - domChildren = new ArrayList<SsaBasicBlock>(); - } - - /** - * Creates a new SSA basic block from a ROP form basic block. - * - * @param rmeth original method - * @param basicBlockIndex index this block will have - * @param parent method of this block - * predecessor set will be updated. - * @return new instance - */ - public static SsaBasicBlock newFromRop(RopMethod rmeth, - int basicBlockIndex, final SsaMethod parent) { - - BasicBlockList ropBlocks; - SsaBasicBlock result; - InsnList ropInsns; - BasicBlock bb; - - ropBlocks = rmeth.getBlocks(); - bb = ropBlocks.get(basicBlockIndex); - - result = new SsaBasicBlock(basicBlockIndex, bb.getLabel(), parent); - - ropInsns = bb.getInsns(); - - result.insns.ensureCapacity(ropInsns.size()); - for (int i = 0, sz = ropInsns.size() ; i < sz ; i++) { - result.insns.add(new NormalSsaInsn (ropInsns.get(i), result)); - } - - result.predecessors = SsaMethod.bitSetFromLabelList( - ropBlocks, - rmeth.labelToPredecessors(bb.getLabel())); - - result.successors - = SsaMethod.bitSetFromLabelList(ropBlocks, bb.getSuccessors()); - - result.successorList - = SsaMethod.indexListFromLabelList(ropBlocks, - bb.getSuccessors()); - - - if (result.successorList.size() != 0) { - int primarySuccessor = bb.getPrimarySuccessor(); - - result.primarySuccessor = (primarySuccessor < 0) - ? -1 : ropBlocks.indexOfLabel(primarySuccessor); - } - - return result; - } - - /** - * Adds a basic block as a dom child for this block. Used when constructing - * the dom tree. - * - * @param child non-null; new dom child - */ - void addDomChild(SsaBasicBlock child) { - domChildren.add(child); - } - - /** - * Gets the dom children for this node. Don't modify this list. - * - * @return non-null; list of dom children - */ - ArrayList<SsaBasicBlock> getDomChildren() { - return domChildren; - } - - /** - * Adds a phi insn to the beginning of this block. The result type of - * the phi will be set to void, to indicate that it's currently unknown. - * - * @param reg >=0 result reg - */ - void addPhiInsnForReg(int reg) { - insns.add(0, new PhiInsn(reg, this)); - } - - /** - * Adds a phi insn to the beginning of this block. This is to be used - * when the result type or local-association can be determined at phi - * insert time. - * - * @param resultSpec non-null; reg - */ - void addPhiInsnForReg(RegisterSpec resultSpec) { - insns.add(0, new PhiInsn(resultSpec, this)); - } - - /** - * Adds an insn to the head of this basic block, just after any phi - * insns. - * - * @param insn non-null; rop-form insn to add - */ - void addInsnToHead(Insn insn) { - SsaInsn newInsn = SsaInsn.makeFromRop(insn, this); - insns.add(getCountPhiInsns(), newInsn); - parent.onInsnAdded(newInsn); - } - - /** - * Replaces the last insn in this block. The provided insn must have - * some branchingness. - * - * @param insn non-null; rop-form insn to add, which must branch. - */ - void replaceLastInsn(Insn insn) { - if (insn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) { - throw new IllegalArgumentException("last insn must branch"); - } - - SsaInsn oldInsn = insns.get(insns.size() - 1); - SsaInsn newInsn = SsaInsn.makeFromRop(insn, this); - - insns.set(insns.size() - 1, newInsn); - - parent.onInsnRemoved(oldInsn); - parent.onInsnAdded(newInsn); - } - - /** - * Visits each phi insn - * @param v callback - */ - public void forEachPhiInsn(PhiInsn.Visitor v) { - - int sz = insns.size(); - for (int i = 0; i < sz; i++) { - SsaInsn insn = insns.get(i); - if (insn instanceof PhiInsn) { - v.visitPhiInsn((PhiInsn) insn); - } else { - /* - * Presently we assume PhiInsn's are in a continuous - * block at the top of the list - */ - break; - } - } - } - - /** - * Deletes all phi insns. Do this after adding appropriate move insns. - */ - public void removeAllPhiInsns() { - /* - * Presently we assume PhiInsn's are in a continuous - * block at the top of the list - */ - - insns.subList(0, getCountPhiInsns()).clear(); - } - - /** - * Gets the number of phi insns at the top of this basic block. - * @return count of phi insns - */ - private int getCountPhiInsns() { - int countPhiInsns; - - int sz = insns.size(); - for (countPhiInsns = 0; countPhiInsns < sz; countPhiInsns++) { - SsaInsn insn = insns.get(countPhiInsns); - if (!(insn instanceof PhiInsn)) { - break; - } - } - - return countPhiInsns; - } - - /** - * @return non-null;the (mutable) instruction list for this block, - * with phi insns at the beginning. - */ - public ArrayList<SsaInsn> getInsns() { - return insns; - } - - /** - * @return non-null; the (mutable) list of phi insns for this block - */ - public List<SsaInsn> getPhiInsns() { - return insns.subList(0, getCountPhiInsns()); - } - - /** - * @return the block index of this block - */ - public int getIndex() { - return index; - } - - /** - * @return the label of this block in rop form - */ - public int getRopLabel() { - return ropLabel; - } - - /** - * @return the label of this block in rop form as a hex string - */ - public String getRopLabelString() { - return Hex.u2(ropLabel); - } - - /** - * @return non-null;predecessors set, indexed by block index - */ - public BitSet getPredecessors() { - return predecessors; - } - - /** - * @return non-null;successors set, indexed by block index - */ - public BitSet getSuccessors() { - return successors; - } - - /** - * @return non-null;ordered successor list, containing block indicies - */ - public IntList getSuccessorList() { - return successorList; - } - - /** - * @return >= -1; block index of primary successor or -1 if no - * primary successor. - */ - public int getPrimarySuccessorIndex() { - return primarySuccessor; - } - - /** - * @return rop label of primary successor - */ - public int getPrimarySuccessorRopLabel() { - return parent.blockIndexToRopLabel(primarySuccessor); - } - - /** - * @return null-ok; the primary successor block or null if there is none. - */ - public SsaBasicBlock getPrimarySuccessor() { - if (primarySuccessor < 0) { - return null; - } else { - return parent.getBlocks().get(primarySuccessor); - } - } - - /** - * @return successor list of rop labels - */ - public IntList getRopLabelSuccessorList() { - IntList result = new IntList(successorList.size()); - - int sz = successorList.size(); - - for (int i = 0; i < sz; i++) { - result.add(parent.blockIndexToRopLabel(successorList.get(i))); - } - return result; - } - - /** - * @return non-null; method that contains this block - */ - public SsaMethod getParent() { - return parent; - } - - /** - * Inserts a new empty GOTO block as a predecessor to this block. - * All previous predecessors will be predecessors to the new block. - * - * @return non-null; an appropriately-constructed instance - */ - public SsaBasicBlock insertNewPredecessor() { - SsaBasicBlock newPred = parent.makeNewGotoBlock(); - - // Update the new block - newPred.predecessors = predecessors; - newPred.successors.set(index) ; - newPred.successorList.add(index); - newPred.primarySuccessor = index; - - - // Update us - predecessors = new BitSet(parent.getBlocks().size()); - predecessors.set(newPred.index); - - // Update our (soon-to-be) old predecessors - for (int i = newPred.predecessors.nextSetBit(0); i >= 0; - i = newPred.predecessors.nextSetBit(i + 1)) { - - SsaBasicBlock predBlock = parent.getBlocks().get(i); - - predBlock.replaceSuccessor(index, newPred.index); - } - - return newPred; - } - - /** - * Constructs and inserts a new empty GOTO block <code>Z</code> between - * this block (<code>A</code>) and a current successor block - * (<code>B</code>). The new block will replace B as A's successor and - * A as B's predecessor. A and B will no longer be directly connected. - * If B is listed as a successor multiple times, all references - * are replaced. - * - * @param other current successor (B) - * @return non-null; an appropriately-constructed instance - */ - public SsaBasicBlock insertNewSuccessor(SsaBasicBlock other) { - SsaBasicBlock newSucc = parent.makeNewGotoBlock(); - - if (!successors.get(other.index)) { - throw new RuntimeException("Block " + other.getRopLabelString() - + " not successor of " + getRopLabelString()); - } - - // Update the new block - newSucc.predecessors.set(this.index); - newSucc.successors.set(other.index) ; - newSucc.successorList.add(other.index); - newSucc.primarySuccessor = other.index; - - // Update us - for (int i = successorList.size() - 1 ; i >= 0; i--) { - if(successorList.get(i) == other.index) { - successorList.set(i, newSucc.index); - } - } - - if (primarySuccessor == other.index) { - primarySuccessor = newSucc.index; - } - successors.clear(other.index); - successors.set(newSucc.index); - - // Update "other" - other.predecessors.set(newSucc.index); - other.predecessors.set(index, successors.get(other.index)); - - return newSucc; - } - - /** - * Replace an old successor with a new successor. - * Throws RuntimeException if oldIndex was not a successor. - * @param oldIndex index of old successor block - * @param newIndex index of new successor block. - */ - public void replaceSuccessor(int oldIndex, int newIndex) { - if (oldIndex == newIndex) { - return; - } - - // Update us - successors.set(newIndex); - - if (primarySuccessor == oldIndex) { - primarySuccessor = newIndex; - } - - for (int i = successorList.size() - 1 ; i >= 0; i--) { - if(successorList.get(i) == oldIndex) { - successorList.set(i, newIndex); - } - } - - successors.clear(oldIndex); - - // Update new successor - parent.getBlocks().get(newIndex).predecessors.set(index); - - // Update old successor - parent.getBlocks().get(oldIndex).predecessors.clear(index); - } - - - /** - * Attaches block to an exit block if necessary. If this block - * is not an exit predecessor or is the exit block, this block does - * nothing. For use by {@link com.android.dx.ssa.SsaMethod#makeExitBlock} - * - * @param exitBlock non-null; exit block - */ - public void exitBlockFixup(SsaBasicBlock exitBlock) { - if (this == exitBlock) { - return; - } - - if (successorList.size() == 0) { - /* - * This is an exit predecessor. - * Set the successor to the exit block - */ - successors.set(exitBlock.index); - successorList.add(exitBlock.index); - primarySuccessor = exitBlock.index; - exitBlock.predecessors.set(this.index); - } - } - - /** - * Adds a move instruction to the end of this basic block, just - * before the last instruction. If the result of the final instruction - * is the source in question, then the move is placed at the beginning of - * the primary successor block. This is for unversioned registers. - * @param result move destination - * @param source move source - */ - public void addMoveToEnd(RegisterSpec result, RegisterSpec source) { - - if (result.getReg() == source.getReg()) { - // Sometimes we end up with no-op moves. Ignore them here. - return; - } - - /* - * The last Insn has to be a normal SSA insn: a phi can't branch - * or return or cause an exception, etc. - */ - NormalSsaInsn lastInsn; - lastInsn = (NormalSsaInsn)insns.get(insns.size()-1); - - if (lastInsn.getResult() != null || lastInsn.getSources().size() > 0) { - /* - * The final insn in this block has a source or result register, - * and the moves we may need to place and schedule may interfere. - * We need to insert this instruction at the - * beginning of the primary successor block instead. We know - * this is safe, because when we edge-split earlier, we ensured - * that each successor has only us as a predecessor. - */ - - for (int i = successors.nextSetBit(0) - ; i >= 0 - ; i = successors.nextSetBit(i + 1)) { - - SsaBasicBlock succ; - - succ = parent.getBlocks().get(i); - succ.addMoveToBeginning(result, source); - } - } else { - /* - * We can safely add a move to the end of the block - * just before the last instruction because - * the final insn does not assign to anything. - */ - - RegisterSpecList sources; - sources = RegisterSpecList.make(source); - - NormalSsaInsn toAdd; - - toAdd = new NormalSsaInsn( - new PlainInsn(Rops.opMove(result.getType()), - SourcePosition.NO_INFO, result, sources), this); - - insns.add(insns.size() - 1, toAdd); - - movesFromPhisAtEnd++; - } - } - - /** - * Add a move instruction after the phi insn block. - * @param result move destination - * @param source move source - */ - public void addMoveToBeginning (RegisterSpec result, RegisterSpec source) { - - if (result.getReg() == source.getReg()) { - // Sometimes we end up with no-op moves. Ignore them here. - return; - } - - RegisterSpecList sources; - sources = RegisterSpecList.make(source); - - NormalSsaInsn toAdd; - - toAdd = new NormalSsaInsn( - new PlainInsn(Rops.opMove(result.getType()), - SourcePosition.NO_INFO, result, sources), this); - - insns.add(getCountPhiInsns(), toAdd); - movesFromPhisAtBeginning++; - } - - /** - * Sets the register as used in a bitset, taking into account its - * category/width. - * - * @param regsUsed set, indexed by register number - * @param rs register to mark as used - */ - private static void setRegsUsed (BitSet regsUsed, RegisterSpec rs) { - regsUsed.set(rs.getReg()); - if (rs.getCategory() > 1) { - regsUsed.set(rs.getReg() + 1); - } - } - - /** - * Checks to see if the register is used in a bitset, taking - * into account its category/width. - * - * @param regsUsed set, indexed by register number - * @param rs register to mark as used - * @return true if register is fully or partially (for the case of wide - * registers) used. - */ - private static boolean checkRegUsed (BitSet regsUsed, RegisterSpec rs) { - int reg = rs.getReg(); - int category = rs.getCategory(); - - return regsUsed.get(reg) - || (category == 2 ? regsUsed.get(reg + 1) : false); - } - - /** - * Ensures that all move operations in this block occur such that - * reads of any register happen before writes to that register. - * NOTE: caller is expected to returnSpareRegisters()! - * - * TODO See Briggs, et al "Practical Improvements to the Construction and - * Destruction of Static Single Assignment Form" section 5. a) This can - * be done in three passes. - * @param toSchedule List of instructions. Must consist only of moves. - */ - private void scheduleUseBeforeAssigned(List<SsaInsn> toSchedule) { - BitSet regsUsedAsSources = new BitSet(parent.getRegCount()); - // TODO get rid of this - BitSet regsUsedAsResults = new BitSet(parent.getRegCount()); - - int sz = toSchedule.size(); - - int insertPlace = 0; - - while (insertPlace < sz) { - int oldInsertPlace = insertPlace; - - // Record all registers used as sources in this block. - for (int i = insertPlace; i < sz; i++) { - setRegsUsed(regsUsedAsSources, - toSchedule.get(i).getSources().get(0)); - - setRegsUsed(regsUsedAsResults, - toSchedule.get(i).getResult()); - } - - /* - * If there are no circular dependencies, then there exists - * n instructions where n > 1 whose result is not used as a source. - */ - for (int i = insertPlace; i <sz; i++) { - SsaInsn insn = toSchedule.get(i); - - /* - * Move these n registers to the front, since they overwrite - * nothing. - */ - if (!checkRegUsed(regsUsedAsSources, insn.getResult())) { - Collections.swap(toSchedule, i, insertPlace++); - } - } - - // If we've made no progress in this iteration, there's a - // circular dependency. Split it using the temp reg. - if (oldInsertPlace == insertPlace) { - - SsaInsn insnToSplit = null; - - // Find an insn whose result is used as a source. - for (int i = insertPlace; i < sz; i++) { - SsaInsn insn = toSchedule.get(i); - if (checkRegUsed(regsUsedAsSources, insn.getResult()) - && checkRegUsed(regsUsedAsResults, - insn.getSources().get(0))) { - - insnToSplit = insn; - // We're going to split this insn--move it to the - // front - Collections.swap(toSchedule, insertPlace, i); - break; - } - } - - // At least one insn will be set above - - RegisterSpec result = insnToSplit.getResult(); - RegisterSpec tempSpec = result.withReg( - parent.borrowSpareRegister(result.getCategory())); - - NormalSsaInsn toAdd; - - toAdd = new NormalSsaInsn( - new PlainInsn(Rops.opMove(result.getType()), - SourcePosition.NO_INFO, - tempSpec, - insnToSplit.getSources()), this); - - toSchedule.add(insertPlace++, toAdd); - - NormalSsaInsn toReplace; - RegisterSpecList newSources; - - newSources = RegisterSpecList.make(tempSpec); - - toReplace = new NormalSsaInsn( - new PlainInsn(Rops.opMove(result.getType()), - SourcePosition.NO_INFO, - result, - newSources), this); - - toSchedule.set(insertPlace, toReplace); - - // size has changed - sz = toSchedule.size(); - } - - regsUsedAsSources.clear(); - regsUsedAsResults.clear(); - } - } - - /** - * Adds regV to the live-out list for this block. - * Called by the liveness analyzer. - * @param regV register that is live-out for this block. - */ - public void - addLiveOut (int regV) { - if (liveOut == null) { - liveOut = SetFactory.makeLivenessSet(parent.getRegCount()); - } - - liveOut.add(regV); - } - - /** - * Adds regV to the live-in list for this block. - * Called by the liveness analyzer. - * @param regV register that is live-in for this block. - */ - public void - addLiveIn (int regV) { - if (liveIn == null) { - liveIn = SetFactory.makeLivenessSet(parent.getRegCount()); - } - - liveIn.add(regV); - } - - /** - * Returns the set of live-in registers. Valid after register - * interference graph has been generated, otherwise empty. - * - * @return non-null; live-in register set. - */ - public IntSet getLiveInRegs() { - if (liveIn == null) { - liveIn = SetFactory.makeLivenessSet(parent.getRegCount()); - } - return liveIn; - } - - /** - * Returns the set of live-out registers. Valid after register - * interference graph has been generated, otherwise empty. - * - * @return non-null; live-out register set. - */ - public IntSet getLiveOutRegs() { - if (liveOut == null) { - liveOut = SetFactory.makeLivenessSet(parent.getRegCount()); - } - return liveOut; - } - - /** - * @return true if this is the one-and-only exit block for this method - */ - public boolean isExitBlock() { - return index == parent.getExitBlockIndex(); - } - - /** - * Returns true if this block is reachable (that is, it hasn't been - * unlinked from the control flow of this method). This currently tests - * that it's either the start block or it has predecessors, which suffices - * for all current control flow transformations. - * - * @return true if reachable - */ - public boolean isReachable() { - return index == parent.getEntryBlockIndex() - || predecessors.cardinality() > 0; - } - - /** - * Sorts move instructions added via <code>addMoveToEnd</code> during - * phi removal so that results don't overwrite sources that are used. - * For use after all phis have been removed and all calls to - * addMoveToEnd() have been made.<p> - * - * This is necessary because copy-propogation may have left us in a state - * where the same basic block has the same register as a phi operand - * and a result. In this case, the register in the phi operand always - * refers value before any other phis have executed. - */ - public void scheduleMovesFromPhis() { - - if (movesFromPhisAtBeginning > 1) { - List<SsaInsn> toSchedule; - - toSchedule = insns.subList(0, movesFromPhisAtBeginning); - - scheduleUseBeforeAssigned(toSchedule); - - SsaInsn firstNonPhiMoveInsn = insns.get(movesFromPhisAtBeginning); - - //TODO it's actually possible that this case never happens, - //because a move-exception block, having only one predecessor - //in SSA form, perhaps is never on a dominance frontier. - if (firstNonPhiMoveInsn.isMoveException()) { - if (true) { - /* - * We've yet to observe this case, and if it can - * occur the code written to handle it probably - * does not work. - */ - throw new RuntimeException( - "Unexpected: moves from " - +"phis before move-exception"); - } else { - - // A move-exception insn must be placed first in this block - // We need to move it there, and deal with possible - // interference. - boolean moveExceptionInterferes = false; - - int moveExceptionResult - = firstNonPhiMoveInsn.getResult().getReg(); - - // Does the move-exception result reg interfere with the - // phi moves? - for(SsaInsn insn: toSchedule) { - if (insn.isResultReg(moveExceptionResult) - || insn.isRegASource(moveExceptionResult)) { - moveExceptionInterferes = true; - break; - } - } - - if (!moveExceptionInterferes) { - // The easy case - insns.remove(movesFromPhisAtBeginning); - insns.add(0, firstNonPhiMoveInsn); - } else { - // We need to move the result to a spare reg and move it - // back. - - int spareRegister; - RegisterSpec originalResultSpec; - - originalResultSpec = firstNonPhiMoveInsn.getResult(); - spareRegister = parent.borrowSpareRegister( - originalResultSpec.getCategory()); - - // We now move it to a spare register - firstNonPhiMoveInsn.changeResultReg(spareRegister); - RegisterSpec tempSpec = firstNonPhiMoveInsn.getResult(); - - insns.add(0, firstNonPhiMoveInsn); - - // And here we move it back - - NormalSsaInsn toAdd; - - toAdd = new NormalSsaInsn( - new PlainInsn(Rops.opMove( - tempSpec.getType()), - SourcePosition.NO_INFO, - originalResultSpec, - RegisterSpecList.make(tempSpec)), - this); - - - // Place it immediately after the phi-moves, - // overwriting the move-exception that was there. - insns.set(movesFromPhisAtBeginning + 1, toAdd); - } - } - } - } - if (movesFromPhisAtEnd > 1) { - scheduleUseBeforeAssigned( - insns.subList(insns.size() - movesFromPhisAtEnd - 1, - insns.size() - 1)); - } - - // Return registers borrowed here and in scheduleUseBeforeAssigned() - parent.returnSpareRegisters(); - - } - - /** - * Visit all insns in this block - * @param visitor callback interface - */ - public void forEachInsn(SsaInsn.Visitor visitor) { - for (SsaInsn insn: insns) { - insn.accept(visitor); - } - } - - public String toString() { - return "{" + index + ":" + Hex.u2(ropLabel) + '}'; - } - - /** - * Visitor interface for basic blocks - */ - public interface Visitor { - - /** - * Indicates a block has been visited by an iterator method. - * @param v non-null; block visited - * @param parent null-ok; parent node if applicable. - */ - void visitBlock (SsaBasicBlock v, SsaBasicBlock parent); - } -} diff --git a/dx/src/com/android/dx/ssa/SsaConverter.java b/dx/src/com/android/dx/ssa/SsaConverter.java deleted file mode 100644 index a731fcb87..000000000 --- a/dx/src/com/android/dx/ssa/SsaConverter.java +++ /dev/null @@ -1,365 +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.android.dx.ssa; - -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.util.IntIterator; - -import java.util.ArrayList; -import java.util.BitSet; - -/** - * Converts ROP methods to SSA Methods - */ -public class SsaConverter { - public static boolean DEBUG = false; - - /** - * returns an SSA representation, edge-split and with phi functions placed - * @param rmeth input - * @param paramWidth the total width, in register-units, of the method's - * parameters - * @param isStatic true if this method has no 'this' - * pointer argument - * @return output in SSA form - */ - public static SsaMethod convertToSsaMethod(RopMethod rmeth, - int paramWidth, boolean isStatic) { - SsaMethod result; - - result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic); - - edgeSplit(result); - - LocalVariableInfo localInfo = LocalVariableExtractor.extract(result); - - placePhiFunctions(result, localInfo); - new SsaRenamer(result).run(); - - /* - * Exit block, added here, is not considered for edge splitting - * or phi placement since no actual control flows to it. - */ - result.makeExitBlock(); - - return result; - } - - /** - * Returns an SSA represention with only the edge-splitter run. - * @param rmeth method to process - * @param paramWidth width of all arguments in the method - * @param isStatic true if this method has no 'this' pointer argument - * @return an SSA represention with only the edge-splitter run. - */ - public static SsaMethod testEdgeSplit (RopMethod rmeth, int paramWidth, - boolean isStatic) { - SsaMethod result; - - result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic); - - edgeSplit(result); - return result; - } - - /** - * Returns an SSA represention with only the steps through the - * phi placement run. - * @param rmeth method to process - * @param paramWidth width of all arguments in the method - * @param isStatic true if this method has no 'this' pointer argument - * @return an SSA represention with only the edge-splitter run. - */ - public static SsaMethod testPhiPlacement (RopMethod rmeth, int paramWidth, - boolean isStatic) { - SsaMethod result; - - result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic); - - edgeSplit(result); - - LocalVariableInfo localInfo = LocalVariableExtractor.extract(result); - - placePhiFunctions(result, localInfo); - return result; - } - - /** - * See Appel section 19.1 - * Converts CFG into "edge-split" form, such that each node either a - * unique successor or unique predecessor.<p> - * - * In addition, the SSA form we use enforces a further constraint, - * requiring each block with a final instruction that returns a - * value to have a primary successor that has no other - * predecessor. This ensures move statements can always be - * inserted correctly when phi statements are removed. - * - * @param result method to process - */ - private static void edgeSplit(SsaMethod result) { - - edgeSplitPredecessors(result); - edgeSplitMoveExceptionsAndResults(result); - edgeSplitSuccessors(result); - } - - /** - * Inserts Z nodes as new predecessors for every node that has multiple - * successors and multiple predecessors. - * @param result non-null; method to process - */ - private static void edgeSplitPredecessors(SsaMethod result) { - ArrayList<SsaBasicBlock> blocks = result.getBlocks(); - - // New blocks are added to the end of the block list during - // this iteration - for (int i = blocks.size() - 1; i >= 0; i-- ) { - SsaBasicBlock block = blocks.get(i); - if (nodeNeedsUniquePredecessor(block)) { - block.insertNewPredecessor(); - } - } - } - - /** - * @param block non-null; block in question - * @return true if this node needs to have a unique predecessor created for - * it. - */ - private static boolean nodeNeedsUniquePredecessor(SsaBasicBlock block) { - - /* - * Any block with that has both multiple successors and multiple - * predecessors needs a new predecessor node. - */ - - int countPredecessors = block.getPredecessors().cardinality(); - int countSuccessors = block.getSuccessors().cardinality(); - - return (countPredecessors > 1 && countSuccessors > 1); - } - - /** - * In ROP form, move-exception must occur as the first insn in a block - * immediately succeeding the insn that could thrown an exception. - * We may need room to insert move insns later, so make sure to split - * any block that starts with a move-exception such that there is a - * unique move-exception block for each predecessor. - * @param ssaMeth method to process - */ - private static void edgeSplitMoveExceptionsAndResults(SsaMethod ssaMeth) { - ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks(); - - // New blocks are added to the end of the block list during - // this iteration - for (int i = blocks.size() - 1; i >= 0; i-- ) { - SsaBasicBlock block = blocks.get(i); - - // Any block that starts with a move-exception and has more than - // one predecessor... - if (!block.isExitBlock() - && block.getPredecessors().cardinality() > 1 - && block.getInsns().get(0).isMoveException()) { - - // block.getPredecessors() is changed in the loop below - BitSet preds = (BitSet)block.getPredecessors().clone(); - for (int j = preds.nextSetBit(0); j >= 0; - j = preds.nextSetBit(j + 1)) { - - SsaBasicBlock predecessor = blocks.get(j); - - SsaBasicBlock zNode = predecessor.insertNewSuccessor(block); - - // Make sure to place the move-exception as the - // first insn... - zNode.getInsns().add(0, block.getInsns().get(0).clone()); - } - - // remove the move-exception from the original block... - block.getInsns().remove(0); - } - } - } - - /** - * Inserts Z nodes for every node that needs a new - * successor. - * @param result non-null; method to process - */ - private static void edgeSplitSuccessors(SsaMethod result) { - ArrayList<SsaBasicBlock> blocks = result.getBlocks(); - - // New blocks are added to the end of the block list during - // this iteration - for (int i = blocks.size() - 1; i >= 0; i-- ) { - SsaBasicBlock block = blocks.get(i); - - // successors list is modified in loop below - BitSet successors = (BitSet)block.getSuccessors().clone(); - for(int j = successors.nextSetBit(0); - j >= 0; j = successors.nextSetBit(j+1)) { - - SsaBasicBlock succ = blocks.get(j); - - if (needsNewSuccessor(block, succ)) { - block.insertNewSuccessor(succ); - } - } - } - } - - /** - * Returns true if block and successor need a Z-node between them. - * Presently, this is true if the final instruction has any sources - * or results and the current successor block has more than one - * predecessor. - * @param block predecessor node - * @param succ successor node - * @return true if a Z node is needed - */ - private static boolean needsNewSuccessor(SsaBasicBlock block, - SsaBasicBlock succ) { - - ArrayList<SsaInsn> insns = block.getInsns(); - SsaInsn lastInsn = insns.get(insns.size() - 1); - - return ((lastInsn.getResult() != null) - || (lastInsn.getSources().size() > 0)) - && succ.getPredecessors().cardinality() > 1; - } - - /** - * See Appel algorithm 19.6 - * Place Phi functions in appropriate locations. - * - * @param ssaMeth non-null; method to process. Modifications made in-place - * @param localInfo non-null; Local variable info, used when placing phis - */ - private static void placePhiFunctions (SsaMethod ssaMeth, - LocalVariableInfo localInfo) { - ArrayList<SsaBasicBlock> ssaBlocks; - int regCount; - int blockCount; - - ssaBlocks = ssaMeth.getBlocks(); - blockCount = ssaBlocks.size(); - regCount = ssaMeth.getRegCount(); - - DomFront df = new DomFront(ssaMeth); - DomFront.DomInfo[] domInfos = df.run(); - - // Bit set of registers vs block index "definition sites" - BitSet[] defsites = new BitSet[regCount]; - - // Bit set of registers vs block index "phi placement sites" - BitSet[] phisites = new BitSet[regCount]; - - for (int i = 0; i < regCount; i++) { - defsites[i] = new BitSet(blockCount); - phisites[i] = new BitSet(blockCount); - } - - /* - * For each register, build a set of all basic blocks where - * containing an assignment to that register. - */ - for (int bi = 0, s = ssaBlocks.size(); bi < s; bi++) { - SsaBasicBlock b = ssaBlocks.get(bi); - - for (SsaInsn insn: b.getInsns()) { - - RegisterSpec rs = insn.getResult(); - - if (rs != null) { - defsites[rs.getReg()].set(bi); - } - } - } - - if (DEBUG) { - System.out.println("defsites"); - - for (int i = 0; i < regCount; i++) { - StringBuilder sb = new StringBuilder(); - - sb.append('v').append(i).append(": "); - - sb.append(defsites[i].toString()); - - System.out.println(sb); - } - } - - BitSet worklist; - - /* - * For each register, compute all locations for phi placement - * based on dominance-frontier algorithm. - */ - for (int reg = 0, s = ssaMeth.getRegCount() ; reg < s ; reg++ ) { - int workBlockIndex; - - /* Worklist set starts out with each node where reg is assigned */ - - worklist = (BitSet)(defsites[reg].clone()); - - while (0 <= (workBlockIndex = worklist.nextSetBit(0))) { - worklist.clear(workBlockIndex); - IntIterator dfIterator - = domInfos[workBlockIndex] - .dominanceFrontiers.iterator(); - - while (dfIterator.hasNext()) { - int dfBlockIndex = dfIterator.next(); - - if (!phisites[reg].get(dfBlockIndex)) { - phisites[reg].set(dfBlockIndex); - - RegisterSpec rs - = localInfo.getStarts(dfBlockIndex).get(reg); - - if (rs == null) { - ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(reg); - } else { - ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(rs); - } - - if (!defsites[reg].get(dfBlockIndex)) { - worklist.set(dfBlockIndex); - } - } - } - } - } - - if (DEBUG) { - System.out.println("phisites"); - - for (int i = 0; i < regCount; i++) { - StringBuilder sb = new StringBuilder(); - - sb.append('v').append(i).append(": "); - - sb.append(phisites[i].toString()); - - System.out.println(sb); - } - } - } -} diff --git a/dx/src/com/android/dx/ssa/SsaInsn.java b/dx/src/com/android/dx/ssa/SsaInsn.java deleted file mode 100644 index d9e33a0dc..000000000 --- a/dx/src/com/android/dx/ssa/SsaInsn.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.android.dx.ssa; - -import com.android.dx.rop.code.*; -import com.android.dx.util.ToHuman; - -/** - * An instruction in SSA form - */ -public abstract class SsaInsn implements ToHuman, Cloneable { - - protected RegisterSpec result; - protected final SsaBasicBlock block; - - /** - * Constructs an instance - * @param block block containing this insn. Can never change. - */ - protected SsaInsn(final SsaBasicBlock block) { - this.block = block; - } - - /** - * Makes a new SSA insn form a ROP insn - * - * @param insn non-null; rop insn - * @param block non-null; owning block - * @return non-null; an appropriately constructed instance - */ - public static SsaInsn makeFromRop(Insn insn, SsaBasicBlock block) { - return new NormalSsaInsn(insn, block); - } - - /** {@inheritDoc} */ - @Override - public SsaInsn clone() { - try { - return (SsaInsn)super.clone(); - } catch (CloneNotSupportedException ex) { - throw new RuntimeException ("unexpected", ex); - } - } - - /** - * Like {@link com.android.dx.rop.code.Insn getResult()}. - * @return result register - */ - public RegisterSpec getResult() { - return result; - } - - /** - * Like {@link com.android.dx.rop.code.Insn getSources()}. - * @return non-null; sources list - */ - abstract public RegisterSpecList getSources(); - - /** - * Gets the block to which this insn instance belongs. - * - * @return owning block - */ - public SsaBasicBlock getBlock() { - return block; - } - - /** - * is the specified reg the result reg? - * @param reg register to test - * @return true if there is a result and it is stored in the specified - * register - */ - public boolean isResultReg(int reg) { - return result != null && result.getReg() == reg; - } - - - /** - * Changes the result register if this insn has a result. - * Used during renaming. - * @param reg new result register. - */ - public void changeResultReg(int reg) { - if (result != null) { - result = result.withReg(reg); - } - } - - /** - * Sets the local association for the result of this insn. - * This is sometimes updated during the SsaRenamer process. - * - * @param local null-ok; New debug/local variable info. - */ - public final void setResultLocal(LocalItem local) { - LocalItem oldItem = result.getLocalItem(); - - if (local != oldItem && (local == null - || !local.equals(result.getLocalItem()))) { - result = RegisterSpec.makeLocalOptional( - result.getReg(), result.getType(), local); - } - } - - /** - * Map registers after register allocation. - * - * @param mapper - */ - public final void mapRegisters(RegisterMapper mapper) { - RegisterSpec oldResult = result; - result = mapper.map(result); - block.getParent().updateOneDefinition(this, oldResult); - mapSourceRegisters(mapper); - } - - /** - * Maps only source registers. - * - * @param mapper new mapping - */ - abstract public void mapSourceRegisters(RegisterMapper mapper); - - - /** - * Returns the Rop opcode for this insn, or null if this is a phi insn - * - * TODO move this up into NormalSsaInsn - * - * @return null-ok; Rop opcode if there is one. - */ - abstract public Rop getOpcode(); - - /** - * Returns the original Rop insn for this insn, or null if this is - * a phi insn. - * - * TODO move this up into NormalSsaInsn - * - * @return null-ok; Rop insn if there is one. - */ - abstract public Insn getOriginalRopInsn(); - - /** - * Gets the spec of a local variable assignment that occurs at this - * instruction, or null if no local variable assignment occurs. This - * may be the result register, or for <code>mark-local</code> insns - * it may be the source. - * - * @return null-ok; a local-associated register spec or null - * @see com.android.dx.rop.code.Insn#getLocalAssignment() - */ - public RegisterSpec getLocalAssignment() { - if (result != null && result.getLocalItem() != null) { - return result; - } - - return null; - } - - /** - * Indicates whether the specified register is amongst the registers - * used as sources for this instruction. - * @param reg The register in question - * @return true if the reg is a source - */ - public boolean isRegASource(int reg) { - return null != getSources().specForRegister(reg); - } - - /** - * Transform back to ROP form. - * - * TODO move this up into NormalSsaInsn - * - * @return non-null; a ROP representation of this instruction, with - * updated registers. - */ - public abstract Insn toRopInsn(); - - /** - * @return true if this is a PhiInsn or a normal move insn - */ - public abstract boolean isPhiOrMove(); - - /** - * Returns true if this insn is considered to have a side effect beyond - * that of assigning to the result reg. - * - * @return true if this insn is considered to have a side effect beyond - * that of assigning to the result reg. - */ - public abstract boolean hasSideEffect(); - - /** - * @return true if this is a move (but not a move-operand or move-exception) - * instruction - */ - public boolean isNormalMoveInsn() { - return false; - } - - /** - * @return true if this is a move-exception instruction. - * These instructions must immediately follow a preceeding invoke* - */ - public boolean isMoveException() { - return false; - } - - /** - * @return true if this instruction can throw. - */ - abstract public boolean canThrow(); - - /** - * accepts a visitor - * @param v visitor - */ - public abstract void accept(Visitor v); - - /** - * Visitor interface for this class. - */ - public static interface Visitor { - - /** - * Any non-phi move instruction - * @param insn non-null; the instruction to visit - */ - public void visitMoveInsn(NormalSsaInsn insn); - - /** - * Any phi insn - * @param insn non-null; the instruction to visit - */ - public void visitPhiInsn(PhiInsn insn); - - /** - * Any insn that isn't a move or a phi (which is also a move). - * @param insn non-null; the instruction to visit - */ - public void visitNonMoveInsn(NormalSsaInsn insn); - } -} diff --git a/dx/src/com/android/dx/ssa/SsaMethod.java b/dx/src/com/android/dx/ssa/SsaMethod.java deleted file mode 100644 index 49f8ea5f7..000000000 --- a/dx/src/com/android/dx/ssa/SsaMethod.java +++ /dev/null @@ -1,831 +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.android.dx.ssa; - -import com.android.dx.rop.code.BasicBlockList; -import com.android.dx.rop.code.PlainInsn; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.Rops; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.code.Insn; -import com.android.dx.rop.code.RegOps; -import com.android.dx.rop.code.Rop; -import com.android.dx.util.IntList; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Collections; -import java.util.List; -import java.util.Stack; -import java.util.Set; - -/** - * A method in SSA form - */ -public final class SsaMethod { - - /** basic blocks, indexed by block index */ - private ArrayList<SsaBasicBlock> blocks; - - /** Index of first executed block in method */ - private int entryBlockIndex; - - /** - * Index of exit block, which exists only in SSA form, - * or or -1 if there is none - */ - private int exitBlockIndex; - - private int registerCount; - private int spareRegisterBase; - private int borrowedSpareRegisters; - - /** really one greater than the max label */ - private int maxLabel; - - /** the total width, in register-units, of the method's parameters */ - private final int paramWidth; - - /** true if this method has no 'this' pointer argument */ - private final boolean isStatic; - - /** - * indexed by register: the insn where said register is defined or null - * if undefined. null until (lazily) created. - */ - private SsaInsn[] definitionList; - - /** indexed by register: the list of all insns that use a register */ - private ArrayList<SsaInsn>[] useList; - /** A version of useList with each List unmodifiable */ - private List<SsaInsn>[] unmodifiableUseList; - - /** - * "back-convert mode". Set during back-conversion when registers - * are about to be mapped into a non-SSA namespace. When true, - * use and def lists are unavailable. - * - * TODO remove this mode, plase the functionality elsewhere - */ - private boolean backMode = false; - - /** - * @param rmeth RopMethod to convert from - * @param paramWidth the total width, in register-units, of the - * method's parameters - * @param isStatic true if this method has no 'this' pointer argument - * @return SsaMethod representation - */ - static SsaMethod newFromRopMethod(RopMethod rmeth, int paramWidth, - boolean isStatic) { - SsaMethod result; - - result = new SsaMethod(paramWidth, isStatic); - - result.maxLabel = rmeth.getBlocks().getMaxLabel(); - result.registerCount = rmeth.getBlocks().getRegCount(); - result.spareRegisterBase = result.registerCount; - - result.convertRopToSsaBlocks(rmeth); - - return result; - } - - /** - * Builds a BitSet of block indices from a basic block list and a list - * of labels taken from Rop form - * @param blocks Rop blocks - * @param labelList list of rop block labels - * @return BitSet of block indices - */ - static BitSet bitSetFromLabelList(BasicBlockList blocks, - IntList labelList) { - - BitSet result; - - result = new BitSet(blocks.size()); - - for (int i = 0, sz = labelList.size() ; i < sz ; i++) { - result.set(blocks.indexOfLabel(labelList.get(i))); - } - - return result; - } - - /** - * Builds an IntList of block indices from a basic block list and a list - * of labels taken from Rop form - * @param ropBlocks Rop blocks - * @param labelList list of rop block labels - * @return IntList of block indices - */ - public static IntList indexListFromLabelList(BasicBlockList ropBlocks, - IntList labelList) { - - IntList result; - - result = new IntList(labelList.size()); - - for (int i = 0, sz = labelList.size() ; i < sz ; i++) { - result.add(ropBlocks.indexOfLabel(labelList.get(i))); - } - - return result; - } - - private void convertRopToSsaBlocks( - RopMethod rmeth) { - - BasicBlockList ropBlocks; - - ropBlocks = rmeth.getBlocks(); - - blocks = new ArrayList<SsaBasicBlock>(ropBlocks.size() + 2); - - for (int i = 0, sz = ropBlocks.size() ; i < sz ; i++) { - SsaBasicBlock sbb; - - sbb = SsaBasicBlock.newFromRop(rmeth, i, this); - - blocks.add(sbb); - } - - // Add an no-op entry block - int origEntryBlockIndex = rmeth.getBlocks() - .indexOfLabel(rmeth.getFirstLabel()); - - SsaBasicBlock entryBlock - = blocks.get(origEntryBlockIndex).insertNewPredecessor(); - - entryBlockIndex = entryBlock.getIndex(); - exitBlockIndex = -1; // this gets made later - - } - - - /** - * Creates an exit block and attaches it to the CFG if this method - * exits. Methods that never exit will not have an exit block. This - * is called after edge-splitting and phi insertion, since the edges - * going into the exit block should not be considered in those steps. - */ - void makeExitBlock() { - if (exitBlockIndex >= 0) { - throw new RuntimeException("must be called at most once"); - } - - exitBlockIndex = blocks.size(); - SsaBasicBlock exitBlock - = new SsaBasicBlock(exitBlockIndex, maxLabel++, this); - - blocks.add(exitBlock); - - for (SsaBasicBlock block: blocks) { - block.exitBlockFixup(exitBlock); - } - - if (exitBlock.getPredecessors().cardinality() == 0) { - // In cases where there is no exit... - blocks.remove(exitBlockIndex); - exitBlockIndex = -1; - maxLabel--; - } - } - - /** - * Constructor - * - * @param paramWidth the total width, in register-units, of the - * method's parameters - * @param isStatic true if this method has no 'this' pointer argument - */ - private SsaMethod(int paramWidth, boolean isStatic) { - this.paramWidth = paramWidth; - this.isStatic = isStatic; - } - - /** - * Gets a new GOTO insn. - * - * @param block block to which this GOTO will be added - * (not it's destination!) - * @return an appropriately-constructed instance. - */ - private static SsaInsn getGoto(SsaBasicBlock block) { - return new NormalSsaInsn ( - new PlainInsn(Rops.GOTO, SourcePosition.NO_INFO, - null, RegisterSpecList.EMPTY), block); - } - - /** - * Makes a new basic block for this method, - * which is empty besides a single <code>GOTO</code>. Successors and - * predecessors are not yet set. - * - * @return new block - */ - public SsaBasicBlock makeNewGotoBlock() { - int newIndex = blocks.size(); - SsaBasicBlock newBlock = new SsaBasicBlock(newIndex, maxLabel++, this); - - newBlock.getInsns().add(getGoto(newBlock)); - blocks.add(newBlock); - - return newBlock; - } - - /** - * @return block index of first execution block - */ - public int getEntryBlockIndex() { - return entryBlockIndex; - } - - /** - * @return first execution block - */ - public SsaBasicBlock getEntryBlock() { - return blocks.get(entryBlockIndex); - } - - /** - * @return block index of exit block or -1 if there is none - */ - public int getExitBlockIndex() { - return exitBlockIndex; - } - - /** - * @return null-ok; block of exit block or null if there is none - */ - public SsaBasicBlock getExitBlock() { - return exitBlockIndex < 0 ? null : blocks.get(exitBlockIndex); - } - - /** - * @param bi block index or -1 for none - * @return rop label or -1 if bi was -1 - */ - public int blockIndexToRopLabel(int bi) { - if (bi < 0) { - return -1; - } - return blocks.get(bi).getRopLabel(); - } - - /** - * @return count of registers used in this method - */ - public int getRegCount() { - return registerCount; - } - - /** - * @return the total width, in register units, of the method's - * parameters - */ - public int getParamWidth() { - return paramWidth; - } - - /** - * Returns true if this is a static method. - * - * @return true if this is a static method - */ - public boolean isStatic() { - return isStatic; - } - - /** - * Borrow a register to use as a temp. Used in the phi removal process. - * Call returnSpareRegisters() when done. - * @param category width (1 or 2) of the register - * @return register number to use - */ - public int borrowSpareRegister(int category) { - int result; - - result = spareRegisterBase + borrowedSpareRegisters; - - borrowedSpareRegisters += category; - - registerCount = Math.max(registerCount, result + category); - - return result; - } - - /** - * Returns all borrowed registers. - */ - public void returnSpareRegisters() { - borrowedSpareRegisters = 0; - } - - /** - * @return non-null; basic block list, do not modify. - */ - public ArrayList<SsaBasicBlock> getBlocks() { - return blocks; - } - - /** - * Returns the count of reachable blocks in this method: blocks that have - * predecessors (or are the start block) - * - * @return >= 0; number of reachable basic blocks - */ - public int getCountReachableBlocks() { - int ret = 0; - - for (SsaBasicBlock b: blocks) { - // Blocks that have been disconnected don't count. - if (b.isReachable()) { - ret++; - } - } - - return ret; - } - - /** - * Remaps unversioned registers. - * @param mapper maps old registers to new. - */ - public void mapRegisters(RegisterMapper mapper) { - - for (SsaBasicBlock block: getBlocks()) { - for (SsaInsn insn: block.getInsns()) { - insn.mapRegisters(mapper); - } - } - - registerCount = mapper.getNewRegisterCount(); - spareRegisterBase = registerCount; - } - - /** - * Returns the insn that defines the given register - * @param reg register in question - * @return insn (actual instance from code) that defined this reg or null - * if reg is not defined. - */ - public SsaInsn getDefinitionForRegister(int reg) { - if (backMode) { - throw new RuntimeException("No def list in back mode"); - } - - if (definitionList != null) { - return definitionList[reg]; - } - - definitionList = new SsaInsn[getRegCount()]; - - forEachInsn(new SsaInsn.Visitor() { - public void visitMoveInsn (NormalSsaInsn insn) { - definitionList[insn.getResult().getReg()] = insn; - } - public void visitPhiInsn (PhiInsn phi) { - definitionList[phi.getResult().getReg()] = phi; - } - public void visitNonMoveInsn (NormalSsaInsn insn) { - RegisterSpec result = insn.getResult(); - if (result != null) { - definitionList[insn.getResult().getReg()] = insn; - } - } - }); - - return definitionList[reg]; - } - - /** - * Builds useList and unmodifiableUseList. - */ - private void buildUseList() { - if (backMode) { - throw new RuntimeException("No use list in back mode"); - } - - useList = new ArrayList[registerCount]; - - for (int i = 0 ; i < registerCount; i++) { - useList[i] = new ArrayList(); - } - - forEachInsn(new SsaInsn.Visitor() { - /** {@inheritDoc} */ - public void visitMoveInsn (NormalSsaInsn insn) { - addToUses(insn); - } - /** {@inheritDoc} */ - public void visitPhiInsn (PhiInsn phi) { - addToUses(phi); - } - /** {@inheritDoc} */ - public void visitNonMoveInsn (NormalSsaInsn insn) { - addToUses(insn); - } - /** - * Adds specified insn to the uses list for all of its sources. - * @param insn non-null; insn to process - */ - private void addToUses(SsaInsn insn) { - RegisterSpecList rl = insn.getSources(); - int sz = rl.size(); - - for (int i = 0; i < sz; i++) { - useList[rl.get(i).getReg()].add(insn); - } - } - }); - - unmodifiableUseList = new List[registerCount]; - - for (int i = 0 ; i < registerCount; i++) { - unmodifiableUseList[i] = Collections.unmodifiableList(useList[i]); - } - } - - /** - * Updates the use list for a single change in source register. - * - * @param insn non-null; insn being changed - * @param oldSource null-ok; The source that was used, if applicable - * @param newSource non-null; the new source being used - */ - void onSourceChanged(SsaInsn insn, - RegisterSpec oldSource, RegisterSpec newSource) { - - if (useList == null) return; - - if (oldSource != null) { - int reg = oldSource.getReg(); - useList[reg].remove(insn); - } - - int reg = newSource.getReg(); - if (useList.length <= reg) { - useList = null; - return; - } - useList[reg].add(insn); - } - - /** - * Updates the use list for a source list change. - * - * @param insn insn non-null; insn being changed. insn.getSources() - * must return the new source list. - * @param oldSources null-ok; list of sources that were previously used. - */ - void onSourcesChanged(SsaInsn insn, RegisterSpecList oldSources) { - if (useList == null) return; - - if (oldSources != null) { - removeFromUseList(insn, oldSources); - } - - RegisterSpecList sources = insn.getSources(); - int szNew = sources.size(); - - for(int i = 0; i < szNew; i++) { - int reg = sources.get(i).getReg(); - useList[reg].add(insn); - } - } - - /** - * Removes a given <code>insn</code> from the use lists for the given - * <code>oldSources</code> (rather than the sources currently - * returned by insn.getSources()). - * - * @param insn non-null; insn in question - * @param oldSources null-ok; registers whose use lists <code>insn</code> - * should be removed form. - */ - private void removeFromUseList(SsaInsn insn, RegisterSpecList oldSources) { - if (oldSources == null) { - return; - } - int szNew = oldSources.size(); - for(int i = 0; i < szNew; i++) { - if (!useList[oldSources.get(i).getReg()].remove(insn)) { - throw new RuntimeException("use not found"); - } - } - } - - /** - * Adds an insn to both the use and def lists. For use when adding - * a new insn to the method. - * - * @param insn non-null; insn to add - */ - void onInsnAdded(SsaInsn insn) { - onSourcesChanged(insn, null); - updateOneDefinition(insn, null); - } - - /** - * Removes an instruction from use and def lists. For use during - * instruction removal. - * - * @param insn non-null; insn to remove. - */ - void onInsnRemoved(SsaInsn insn) { - if (useList != null) { - removeFromUseList(insn, insn.getSources()); - } - - RegisterSpec resultReg = insn.getResult(); - if (definitionList != null && resultReg != null) { - definitionList[resultReg.getReg()] = null; - } - } - - /** - * Indicates that the instruction list has changed or the SSA register - * count has increased, so that internal datastructures that rely on - * it should be rebuild. In general, the various other on* methods - * should be called in preference when changes occur if they are - * applicable. - */ - public void onInsnsChanged() { - // Definition list will need to be recomputed - definitionList = null; - - // Use list will need to be recomputed - useList = null; - unmodifiableUseList = null; - } - - /** - * Updates a single definition. - * - * @param insn non-null; insn who's result should be recorded as - * a definition - * @param oldResult null-ok; a previous result that should be no longer - * considered a definition by this insn - */ - void updateOneDefinition(SsaInsn insn, RegisterSpec oldResult) { - if (definitionList == null) return; - if (oldResult != null) { - int reg = oldResult.getReg(); - definitionList[reg] = null; - } - - RegisterSpec resultReg = insn.getResult(); - if (resultReg != null) { - int reg = resultReg.getReg(); - - if (definitionList[reg] != null) { - throw new RuntimeException("Duplicate add of insn"); - } else { - definitionList[resultReg.getReg()] = insn; - } - } - } - - /** - * Returns the list of all source uses (not results) for a register - * @param reg register in question - * @return unmodifiable instruction list - */ - public List<SsaInsn> getUseListForRegister(int reg) { - - if (unmodifiableUseList == null) { - buildUseList(); - } - - return unmodifiableUseList[reg]; - } - - /** - * Returns a modifiable copy of the register use list. - * @return modifiable copy of the use-list, indexed by register - */ - public ArrayList<SsaInsn>[] getUseListCopy() { - if (useList == null) { - buildUseList(); - } - - ArrayList<SsaInsn>[] useListCopy - = (ArrayList<SsaInsn>[])(new ArrayList[registerCount]); - - for (int i = 0; i < registerCount; i++) { - useListCopy[i] = (ArrayList<SsaInsn>)(new ArrayList(useList[i])); - } - - return useListCopy; - } - - /** - * Checks to see if the given SSA reg is ever associated with a local - * local variable. Each SSA reg may be associated with at most one - * local var. - * - * @param spec non-null; ssa reg - * @return true if reg is ever associated with a local - */ - public boolean isRegALocal(RegisterSpec spec) { - SsaInsn defn = getDefinitionForRegister(spec.getReg()); - - if (defn == null) { - // version 0 registers are never used as locals - return false; - } - - // Does the definition have a local associated with it? - if (defn.getLocalAssignment() != null) return true; - - // If not, is there a mark-local insn? - for (SsaInsn use: getUseListForRegister(spec.getReg())) { - Insn insn = use.getOriginalRopInsn(); - - if (insn != null - && insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) { - return true; - } - } - - return false; - } - - /** - * Sets the new register count after renaming. - * @param newRegCount new register count - */ - /*package*/ void setNewRegCount(int newRegCount) { - registerCount = newRegCount; - spareRegisterBase = registerCount; - onInsnsChanged(); - } - - /** - * Makes a new SSA register. For use after renaming has completed. - * - * @return >=0 new SSA register. - */ - public int makeNewSsaReg() { - int reg = registerCount++; - spareRegisterBase = registerCount; - onInsnsChanged(); - return reg; - } - - /** - * Visit all insns in this method - * @param visitor non-null; callback interface - */ - public void forEachInsn(SsaInsn.Visitor visitor) { - for (SsaBasicBlock block: blocks) { - block.forEachInsn(visitor); - } - } - - /** - * Visits each phi insn in this method - * @param v non-null; callback - */ - public void forEachPhiInsn(PhiInsn.Visitor v) { - for (SsaBasicBlock block: blocks) { - block.forEachPhiInsn(v); - } - } - - - /** - * Walk the basic block tree in depth-first order, calling the visitor - * method once for every block. This depth-first walk may be run forward - * from the method entry point or backwards from the method exit points. - * @param reverse true if this should walk backwards from the exit points - * @param v non-null; callback interface. <code>parent</code>is set - * unless this is the root node - */ - public void forEachBlockDepthFirst(boolean reverse, - SsaBasicBlock.Visitor v) { - BitSet visited = new BitSet(blocks.size()); - // We push the parent first, then the child on the stack - Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>(); - - SsaBasicBlock rootBlock = reverse ? getExitBlock() : getEntryBlock(); - - if (rootBlock == null) { - // in the case there's no exit block - return; - } - - stack.add(null); // start with null parent - stack.add(rootBlock); - - while (stack.size() > 0) { - SsaBasicBlock cur = stack.pop(); - SsaBasicBlock parent = stack.pop(); - - if (!visited.get(cur.getIndex())) { - BitSet children - = reverse ? cur.getPredecessors() : cur.getSuccessors(); - for (int i = children.nextSetBit(0); i >= 0 - ; i = children.nextSetBit(i + 1)) { - stack.add(cur); - stack.add(blocks.get(i)); - } - visited.set(cur.getIndex()); - v.visitBlock(cur, parent); - } - } - } - - /** - * Visits blocks in dom-tree order, starting at the current node. - * The <code>parent</code> parameter of the Visitor.visitBlock callback - * is currently always set to null. - * - * @param v non-null; callback interface - */ - public void forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v) { - BitSet visited = new BitSet(getBlocks().size()); - Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>(); - - stack.add(getEntryBlock()); - - while (stack.size() > 0) { - SsaBasicBlock cur = stack.pop(); - ArrayList<SsaBasicBlock> curDomChildren = cur.getDomChildren(); - - if (!visited.get(cur.getIndex())) { - // We walk the tree this way for historical reasons... - for (int i = curDomChildren.size() - 1; i >= 0; i--) { - SsaBasicBlock child = curDomChildren.get(i); - stack.add(child); - } - visited.set(cur.getIndex()); - v.visitBlock(cur, null); - } - } - } - - /** - * Deletes all insns in the set from this method - * - * @param deletedInsns non-null; insns to delete - */ - public void deleteInsns(Set<SsaInsn> deletedInsns) { - for (SsaBasicBlock block: getBlocks()) { - ArrayList<SsaInsn> insns = block.getInsns(); - - for (int i = insns.size() - 1; i >= 0; i--) { - SsaInsn insn = insns.get(i); - - if (deletedInsns.contains(insn)) { - onInsnRemoved(insn); - insns.remove(i); - } - } - - // Check to see if we need to add a GOTO - - int insnsSz = insns.size(); - SsaInsn lastInsn = (insnsSz == 0) ? null : insns.get(insnsSz - 1); - - if (block != getExitBlock() && (insnsSz == 0 - || lastInsn.getOriginalRopInsn() == null - || lastInsn.getOriginalRopInsn().getOpcode() - .getBranchingness() == Rop.BRANCH_NONE)) { - // We managed to eat a throwable insn - - Insn gotoInsn = new PlainInsn(Rops.GOTO, - SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY); - insns.add(SsaInsn.makeFromRop(gotoInsn, block)); - } - } - } - - /** - * Set "back-convert mode". Set during back-conversion when registers - * are about to be mapped into a non-SSA namespace. When true, - * use and def lists are unavailable. - */ - public void setBackMode() { - backMode = true; - useList = null; - definitionList = null; - } -} diff --git a/dx/src/com/android/dx/ssa/SsaRenamer.java b/dx/src/com/android/dx/ssa/SsaRenamer.java deleted file mode 100644 index 64bad2c88..000000000 --- a/dx/src/com/android/dx/ssa/SsaRenamer.java +++ /dev/null @@ -1,621 +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.android.dx.ssa; - -import com.android.dx.rop.code.*; -import com.android.dx.rop.type.Type; -import com.android.dx.util.IntList; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.HashSet; -import java.util.HashMap; - -/** - * Complete transformation to SSA form by renaming all registers accessed.<p> - * - * See Appel algorithm 19.7<p> - * - * Unlike the original algorithm presented in Appel, this renamer converts - * to a new flat (versionless) register space. The "version 0" registers, - * which represent the initial state of the Rop registers and should never - * actually be meaningfully accessed in a legal program, are represented - * as the first N registers in the SSA namespace. Subsequent assignments - * are assigned new unique names. Note that the incoming Rop representation - * has a concept of register widths, where 64-bit values are stored into - * two adjoining Rop registers. This adjoining register representation is - * ignored in SSA form conversion and while in SSA form, each register can be e - * either 32 or 64 bits wide depending on use. The adjoining-register - * represention is re-created later when converting back to Rop form. <p> - * - * But, please note, the SSA Renamer's ignoring of the adjoining-register ROP - * representation means that unaligned accesses to 64-bit registers are not - * supported. For example, you cannot do a 32-bit operation on a portion of - * a 64-bit register. This will never be observed to happen when coming - * from Java code, of course.<p> - * - * The implementation here, rather than keeping a single register version - * stack for the entire method as the dom tree is walked, instead keeps - * a mapping table for the current block being processed. Once the - * current block has been processed, this mapping table is then copied - * and used as the initial state for child blocks.<p> - */ -class SsaRenamer implements Runnable { - - private static final boolean DEBUG = false; - - /** Method we're processing */ - private final SsaMethod ssaMeth; - - /** next available SSA register */ - private int nextSsaReg; - - /** the number of original rop registers */ - private final int ropRegCount; - - /** - * Indexed by block index; register version state for each block start. - * This list is updated by each dom parent for its children. The only - * sub-arrays that exist at any one time are the start states for blocks - * yet to be processed by a <code>BlockRenamer</code> instance. - */ - private final RegisterSpec[][] startsForBlocks; - - /** map of SSA register number to debug (local var names) or null of n/a */ - private final ArrayList<LocalItem> ssaRegToLocalItems; - - /** - * Maps SSA registers back to the original rop number. - * Used for debug only. - */ - private IntList ssaRegToRopReg; - - /** - * Constructs an instance of the renamer - * - * @param ssaMeth non-null; un-renamed SSA method that will - * be renamed. - */ - SsaRenamer (final SsaMethod ssaMeth) { - ropRegCount = ssaMeth.getRegCount(); - - this.ssaMeth = ssaMeth; - /* - * Reserve the first N registers in the SSA register space for - * "version 0" registers - */ - nextSsaReg = ropRegCount; - startsForBlocks = new RegisterSpec[ssaMeth.getBlocks().size()][]; - - ssaRegToLocalItems = new ArrayList<LocalItem>(); - - if (DEBUG) { - ssaRegToRopReg = new IntList(ropRegCount); - } - - /* - * Appel 19.7 - * - * Initialization: - * for each variable a // register i - * Count[a] <- 0 // nextSsaReg, flattened - * Stack[a] <- 0 // versionStack - * push 0 onto Stack[a] - * - */ - - // top entry for the version stack is version 0 - RegisterSpec[] initialRegMapping = new RegisterSpec[ropRegCount]; - for (int i = 0; i < ropRegCount; i++) { - // everyone starts with a version 0 register - initialRegMapping[i] = RegisterSpec.make(i, Type.VOID); - - if (DEBUG) { - ssaRegToRopReg.add(i); - } - } - - // Initial state for entry block - startsForBlocks[ssaMeth.getEntryBlockIndex()] = initialRegMapping; - } - - /** - * Performs renaming transformation, modifying the method's instructions - * in-place. - */ - public void run() { - - // Rename each block in dom-tree DFS order. - ssaMeth.forEachBlockDepthFirstDom(new SsaBasicBlock.Visitor() { - public void visitBlock (SsaBasicBlock block, SsaBasicBlock unused) { - new BlockRenamer(block).process(); - } - }); - - ssaMeth.setNewRegCount(nextSsaReg); - ssaMeth.onInsnsChanged(); - - if (DEBUG) { - System.out.println("SSA\tRop"); - // We're going to compute the version of the rop register - // by keeping a running total of how many times the rop register - // has been mapped. - int[] versions = new int[ropRegCount]; - - int sz = ssaRegToRopReg.size(); - for(int i = 0; i < sz; i++) { - int ropReg = ssaRegToRopReg.get(i); - System.out.println(i +"\t" + ropReg + "[" - + versions[ropReg] + "]"); - versions[ropReg]++; - } - } - } - - /** - * Duplicates a RegisterSpec array - * @param orig non-null; array to duplicate - * @return non-null; new instance - */ - private static RegisterSpec[] dupArray(RegisterSpec[] orig) { - RegisterSpec[] copy = new RegisterSpec[orig.length]; - - System.arraycopy(orig, 0, copy, 0, orig.length); - - return copy; - } - - /** - * Gets a local variable item for a specified register. - * - * @param ssaReg register in SSA name space - * @return null-ok; Local variable name or null if none - */ - private LocalItem getLocalForNewReg(int ssaReg) { - if (ssaReg < ssaRegToLocalItems.size()) { - return ssaRegToLocalItems.get(ssaReg); - } else { - return null; - } - } - - /** - * Records a debug (local variable) name for a specified register. - * - * @param ssaReg non-null named register spec in SSA name space - */ - private void setNameForSsaReg(RegisterSpec ssaReg) { - int reg = ssaReg.getReg(); - LocalItem local = ssaReg.getLocalItem(); - - ssaRegToLocalItems.ensureCapacity(reg + 1); - while (ssaRegToLocalItems.size() <= reg) { - ssaRegToLocalItems.add(null); - } - - ssaRegToLocalItems.set(reg, local); - } - - /** - * Returns true if this SSA register is a "version 0" - * register. All version 0 registers are assigned the first N register - * numbers, where N is the count of original rop registers. - * - * @param ssaReg the SSA register in question - * @return true if it is a version 0 register. - */ - private boolean isVersionZeroRegister(int ssaReg) { - return ssaReg < ropRegCount; - } - - /** - * Returns true if a and b are equal or are both null - - * @param a null-ok - * @param b null-ok - * @return Returns true if a and b are equal or are both null - */ - private static boolean equalsHandlesNulls(Object a, Object b) { - return a == b || (a != null && a.equals(b)); - } - - /** - * Processes all insns in a block and renames their registers - * as appropriate. - */ - private class BlockRenamer implements SsaInsn.Visitor{ - /** non-null; block we're processing. */ - private final SsaBasicBlock block; - - /** - * non-null; indexed by old register name. The current top of the - * version stack as seen by this block. It's initialized from - * the ending state of its dom parent, updated as the block's - * instructions are processed, and then copied to each one of its - * dom children. - */ - private final RegisterSpec[] currentMapping; - - /** - * Contains the set of moves we need to keep - * to preserve local var info. All other moves will be deleted. - */ - private final HashSet<SsaInsn> movesToKeep; - - /** - * Maps the set of insns to replace after renaming is finished - * on the block. - */ - private final HashMap<SsaInsn, SsaInsn> insnsToReplace; - - private final RenamingMapper mapper; - - /** - * Constructs a block renamer instance. Call <code>process</code> - * to process. - * - * @param block non-null; block to process - */ - BlockRenamer(final SsaBasicBlock block) { - this.block = block; - currentMapping = startsForBlocks[block.getIndex()]; - movesToKeep = new HashSet<SsaInsn>(); - insnsToReplace = new HashMap<SsaInsn, SsaInsn>(); - mapper = new RenamingMapper(); - - // We don't need our own start state anymore - startsForBlocks[block.getIndex()] = null; - } - - /** - * Provides a register mapping between the old register space - * and the current renaming mapping. The mapping is updated - * as the current block's instructions are processed. - */ - private class RenamingMapper extends RegisterMapper { - - RenamingMapper() { - } - - /** {@inheritDoc} */ - @Override - public int getNewRegisterCount() { - return nextSsaReg; - } - - /** {@inheritDoc} */ - @Override - public RegisterSpec map(RegisterSpec registerSpec) { - if (registerSpec == null) return null; - - int reg = registerSpec.getReg(); - - // for debugging: assert that the mapped types are compatible - if(DEBUG) { - RegisterSpec newVersion = currentMapping[reg]; - if (newVersion.getBasicType() != Type.BT_VOID - && registerSpec.getBasicFrameType() - != newVersion.getBasicFrameType()) { - - throw new RuntimeException( - "mapping registers of incompatible types! " - + registerSpec - + " " + currentMapping[reg]); - } - } - - return registerSpec.withReg(currentMapping[reg].getReg()); - } - } - - /** - * Renames all the variables in this block and inserts appriopriate - * phis in successor blocks. - */ - public void process() { - /* - * From Appel: - * - * Rename(n) = - * for each statement S in block n // 'statement' in 'block' - */ - - block.forEachInsn(this); - - updateSuccessorPhis(); - - // Delete all move insns in this block - ArrayList<SsaInsn> insns = block.getInsns(); - int szInsns = insns.size(); - - for (int i = szInsns - 1; i >= 0 ; i--) { - SsaInsn insn = insns.get(i); - SsaInsn replaceInsn; - - replaceInsn = insnsToReplace.get(insn); - - if (replaceInsn != null) { - insns.set(i, replaceInsn); - } else if (insn.isNormalMoveInsn() - && !movesToKeep.contains(insn)) { - insns.remove(i); - } - } - - // Store the start states for our dom children - boolean first = true; - for (SsaBasicBlock child: block.getDomChildren()) { - if (child != block) { - RegisterSpec[] childStart; - - // don't bother duplicating the array for the first child - childStart = first ? currentMapping - : dupArray(currentMapping); - - startsForBlocks[child.getIndex()] = childStart; - first = false; - } - } - - // currentMapping is owned by a child now - } - - /** - * Enforces a few contraints when a register mapping is added. - * - * <ol> - * <li> Ensures that all new SSA registers specs in the mapping - * table with the same register number are identical. In effect, once - * an SSA register spec has received or lost a local variable name, - * then every old-namespace register that maps to it should gain or - * lose its local variable name as well. - * <li> Records the local name associated with the - * register so that a register is never associated with more than one - * local. - * <li> ensures that only one SSA register - * at a time is considered to be associated with a local variable. When - * <code>currentMapping</code> is updated and the newly added element - * is named, strip that name from any other SSA registers. - * </ol> - * - * @param ropReg >= 0 Rop register number - * @param ssaReg non-null; An SSA register that has just - * been added to <code>currentMapping</code> - */ - private void addMapping(int ropReg, RegisterSpec ssaReg) { - int ssaRegNum = ssaReg.getReg(); - LocalItem ssaRegLocal = ssaReg.getLocalItem(); - - currentMapping[ropReg] = ssaReg; - - /* - * Ensure all SSA register specs with the same reg are identical. - */ - for (int i = currentMapping.length - 1; i >= 0; i--) { - RegisterSpec cur = currentMapping[i]; - - if (ssaRegNum == cur.getReg()) { - currentMapping[i] = ssaReg; - } - } - - // All further steps are for registers with local information - if (ssaRegLocal == null) { - return; - } - - // Record that this SSA reg has been associated with a local - setNameForSsaReg(ssaReg); - - // Ensure that no other SSA regs are associated with this local - for (int i = currentMapping.length - 1; i >= 0; i--) { - RegisterSpec cur = currentMapping[i]; - - if (ssaRegNum != cur.getReg() - && ssaRegLocal.equals(cur.getLocalItem())) { - currentMapping[i] = cur.withLocalItem(null); - } - } - } - - /** - * {@inheritDoc} - * - * Phi insns have their result registers renamed. - * */ - public void visitPhiInsn(PhiInsn phi) { - /* don't process sources for phi's */ - processResultReg(phi); - } - - /** - * {@inheritDoc} - * - * Move insns are treated as a simple mapping operation, and - * will later be removed unless they represent a local variable - * assignment. If they represent a local variable assignement, they - * are preserved. - */ - public void visitMoveInsn(NormalSsaInsn insn) { - /* - * for moves: copy propogate the move if we can, but don't - * if we need to preserve local variable info and the - * result has a different name than the source. - */ - - RegisterSpec ropResult = insn.getResult(); - int ropResultReg = ropResult.getReg(); - int ropSourceReg = insn.getSources().get(0).getReg(); - - insn.mapSourceRegisters(mapper); - int ssaSourceReg = insn.getSources().get(0).getReg(); - - LocalItem sourceLocal = currentMapping[ropSourceReg].getLocalItem(); - LocalItem resultLocal = ropResult.getLocalItem(); - - /* - * A move from a register that's currently associated with a local - * to one that will not be associated with a local does not need - * to be preserved, but the local association should remain. - * Hence, we inherit the sourceLocal where the resultLocal is null. - */ - - LocalItem newLocal - = (resultLocal == null) ? sourceLocal : resultLocal; - - LocalItem associatedLocal = getLocalForNewReg(ssaSourceReg); - - // If we take the new local, will only one local have ever - // been associated with this SSA reg? - boolean onlyOneAssociatedLocal - = associatedLocal == null || newLocal == null - || newLocal.equals(associatedLocal); - - /* - * If we're going to copy-propogate, then the ssa register spec - * that's going to go into the mapping is made up of the - * source register number mapped from above, the type - * of the result, and the name either from the result (if - * specified) or inherited from the existing mapping. - * - * The move source has incomplete type information - * in null object cases, so the result type is used. - */ - RegisterSpec ssaReg - = RegisterSpec.makeLocalOptional( - ssaSourceReg, ropResult.getType(), newLocal); - - if (!Optimizer.getPreserveLocals() || (onlyOneAssociatedLocal - && equalsHandlesNulls(newLocal, sourceLocal))) { - /* - * We don't have to keep this move to preserve local - * information. Either the name is the same, or the result - * register spec is unnamed. - */ - - addMapping(ropResultReg, ssaReg); - } else if (onlyOneAssociatedLocal && sourceLocal == null) { - - /* - * The register was previously unnamed. This means that a - * local starts after it's first assignment in SSA form - */ - - RegisterSpecList ssaSources; - - ssaSources = RegisterSpecList.make( - RegisterSpec.make(ssaReg.getReg(), - ssaReg.getType(), newLocal)); - - SsaInsn newInsn - = SsaInsn.makeFromRop( - new PlainInsn(Rops.opMarkLocal(ssaReg), - SourcePosition.NO_INFO, null, ssaSources),block); - - insnsToReplace.put(insn, newInsn); - - // Just map as above - addMapping(ropResultReg, ssaReg); - } else { - /* - * Do not copy-propogate, since the two registers - * have two different local-variable names - */ - processResultReg(insn); - - movesToKeep.add(insn); - } - } - - /** - * {@inheritDoc} - * - * All insns that are not move or phi insns have their source registers - * mapped ot the current mapping. Their result registers are then - * renamed to a new SSA register which is then added to the current - * register mapping. - */ - public void visitNonMoveInsn(NormalSsaInsn insn) { - /* for each use of some variable X in S */ - insn.mapSourceRegisters(mapper); - - processResultReg(insn); - } - - /** - * Renames the result register of this insn and updates the - * current register mapping. Does nothing if this insn has no result. - * Applied to all non-move insns. - * - * @param insn insn to process. - */ - void processResultReg(SsaInsn insn) { - RegisterSpec ropResult = insn.getResult(); - - if (ropResult == null) { - return; - } - - int ropReg = ropResult.getReg(); - - insn.changeResultReg(nextSsaReg); - addMapping(ropReg, insn.getResult()); - - if (DEBUG) { - ssaRegToRopReg.add(ropReg); - } - - nextSsaReg++; - } - - /** - * Updates the phi insns in successor blocks with operands based - * on the current mapping of the rop register the phis represent. - */ - private void updateSuccessorPhis() { - PhiInsn.Visitor visitor = new PhiInsn.Visitor() { - public void visitPhiInsn (PhiInsn insn) { - int ropReg; - - ropReg = insn.getRopResultReg(); - - /* - * Never add a version 0 register as a phi operand. - * Version 0 registers represent the initial register state, - * and thus are never significant. Furthermore, - * the register liveness algorithm doesn't properly - * count them as "live in" at the beginning of the method. - */ - - RegisterSpec stackTop = currentMapping[ropReg]; - if (!isVersionZeroRegister(stackTop.getReg())) { - insn.addPhiOperand(stackTop, block); - } - } - }; - - BitSet successors = block.getSuccessors(); - for (int i = successors.nextSetBit(0); i >= 0; - i = successors.nextSetBit(i + 1)) { - - SsaBasicBlock successor = ssaMeth.getBlocks().get(i); - - successor.forEachPhiInsn(visitor); - } - } - } -} diff --git a/dx/src/com/android/dx/ssa/_tests/_DomFront.java b/dx/src/com/android/dx/ssa/_tests/_DomFront.java deleted file mode 100644 index 997da2143..000000000 --- a/dx/src/com/android/dx/ssa/_tests/_DomFront.java +++ /dev/null @@ -1,32 +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.android.dx.ssa._tests; - -import junit.framework.TestCase; - -/** - * Test the class <code>com.android.dx.ssa.DomFront</code>. - */ -public class _DomFront - extends TestCase { - - public void test_one() { - - } - - -} diff --git a/dx/src/com/android/dx/ssa/back/FirstFitAllocator.java b/dx/src/com/android/dx/ssa/back/FirstFitAllocator.java deleted file mode 100644 index d3ff7c78d..000000000 --- a/dx/src/com/android/dx/ssa/back/FirstFitAllocator.java +++ /dev/null @@ -1,152 +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.android.dx.ssa.back; - -import com.android.dx.rop.code.CstInsn; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.ssa.NormalSsaInsn; -import com.android.dx.ssa.BasicRegisterMapper; -import com.android.dx.ssa.RegisterMapper; -import com.android.dx.ssa.SsaMethod; -import com.android.dx.util.IntSet; -import com.android.dx.util.BitIntSet; - -import java.util.BitSet; -import java.util.ArrayList; - -/** - * Allocates registers via a naive n^2 register allocator. - * This allocator does not try to co-locate local variables or deal - * intelligently with different size register uses. - */ -public class FirstFitAllocator extends RegisterAllocator { - /** - * If true, allocator places parameters at the top of the frame - * in calling-convention order. - */ - private static final boolean PRESLOT_PARAMS = true; - - /** indexed by old reg; the set of old regs we've mapped */ - private final BitSet mapped; - - /** {@inheritDoc} */ - public FirstFitAllocator( - final SsaMethod ssaMeth, final InterferenceGraph interference) { - super(ssaMeth, interference); - - mapped = new BitSet(ssaMeth.getRegCount()); - } - - /** {@inheritDoc} */ - @Override - public boolean wantsParamsMovedHigh() { - return PRESLOT_PARAMS; - } - - /** {@inheritDoc} */ - @Override - public RegisterMapper allocateRegisters() { - int oldRegCount = ssaMeth.getRegCount(); - - BasicRegisterMapper mapper - = new BasicRegisterMapper(oldRegCount); - - int nextNewRegister = 0; - - if (PRESLOT_PARAMS) { - /* - * Reserve space for the params at the bottom of the register - * space. Later, we'll flip the params to the end of the register - * space. - */ - - nextNewRegister = ssaMeth.getParamWidth(); - } - - for (int i = 0; i < oldRegCount; i++) { - if (mapped.get(i)) { - // we already got this one - continue; - } - - int maxCategory = getCategoryForSsaReg(i); - IntSet current = new BitIntSet(oldRegCount); - - interference.mergeInterferenceSet(i, current); - - boolean isPreslotted = false; - int newReg = 0; - - if (PRESLOT_PARAMS && isDefinitionMoveParam(i)) { - // Any move-param definition must be a NormalSsaInsn - NormalSsaInsn defInsn = (NormalSsaInsn) - ssaMeth.getDefinitionForRegister(i); - - newReg = paramNumberFromMoveParam(defInsn); - - mapper.addMapping(i, newReg, maxCategory); - isPreslotted = true; - } else { - mapper.addMapping(i, nextNewRegister, maxCategory); - newReg = nextNewRegister; - } - - for (int j = i + 1; j < oldRegCount; j++) { - - if (mapped.get(j) || isDefinitionMoveParam(j)) { - continue; - } - - /* - * If reg j doesn't interfere with the current mapping. - * Also, if this is a pre-slotted method parameter, we - * can't use more than the original param width. - */ - if (!current.has(j) - && !(isPreslotted - && (maxCategory < getCategoryForSsaReg(j)))) { - - interference.mergeInterferenceSet(j, current); - - maxCategory = Math.max(maxCategory, - getCategoryForSsaReg(j)); - - mapper.addMapping(j, newReg, maxCategory); - mapped.set(j); - } - } - - mapped.set(i); - if (!isPreslotted) { - nextNewRegister += maxCategory; - } - } - - return mapper; - } - - /** - * Returns the parameter number that this move-param insn refers to - * @param ndefInsn a move-param insn (otherwise, exceptions will be thrown) - * @return parameter number (offset in the total parameter width) - */ - private int paramNumberFromMoveParam(NormalSsaInsn ndefInsn) { - CstInsn origInsn = (CstInsn) ndefInsn.getOriginalRopInsn(); - - return ((CstInteger) origInsn.getConstant()).getValue(); - } -} diff --git a/dx/src/com/android/dx/ssa/back/FirstFitLocalCombiningAllocator.java b/dx/src/com/android/dx/ssa/back/FirstFitLocalCombiningAllocator.java deleted file mode 100644 index 14eac9057..000000000 --- a/dx/src/com/android/dx/ssa/back/FirstFitLocalCombiningAllocator.java +++ /dev/null @@ -1,950 +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.android.dx.ssa.back; - -import com.android.dx.rop.code.*; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.ssa.InterferenceRegisterMapper; -import com.android.dx.ssa.RegisterMapper; -import com.android.dx.ssa.SsaInsn; -import com.android.dx.ssa.SsaMethod; -import com.android.dx.ssa.NormalSsaInsn; -import com.android.dx.ssa.PhiInsn; -import com.android.dx.ssa.Optimizer; -import com.android.dx.ssa.SsaBasicBlock; -import com.android.dx.util.IntSet; -import com.android.dx.util.IntIterator; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Map; -import java.util.TreeMap; - -/** - * Allocates registers in a first-fit fashion, with the bottom reserved for - * method parameters and all SSAregisters representing the same local variable - * kept together if possible. - */ -public class FirstFitLocalCombiningAllocator extends RegisterAllocator { - private static final boolean DEBUG = false; - - /** maps local variable to a list of associated SSA registers*/ - private final Map<LocalItem, ArrayList<RegisterSpec>> localVariables; - - /** list of move-result-pesudo instructions seen in this method */ - private final ArrayList<NormalSsaInsn> moveResultPseudoInsns; - - /** list of invoke-range instructions seen in this method */ - private final ArrayList<NormalSsaInsn> invokeRangeInsns; - - /** indexed by SSA reg; the set of SSA regs we've mapped */ - private final BitSet ssaRegsMapped; - - /** Register mapper which will be our result */ - private final InterferenceRegisterMapper mapper; - - /** end of rop registers range (starting at 0) reserved for parameters. */ - private final int paramRangeEnd; - - /** set of Rop registers reserved for parameters or local variables. */ - private final BitSet reservedRopRegs; - - /** set of Rop registers that have been used by anything.*/ - private final BitSet usedRopRegs; - - /** true if converter should take steps to minimize rop-form registers*/ - private final boolean minimizeRegisters; - - - /** - * Constructs instance. - * - * @param ssaMeth non-null; method to process - * @param interference non-null interference graph for SSA registers - * @param minimizeRegisters true if converter should take steps to - * minimize rop-form registers - */ - public FirstFitLocalCombiningAllocator( - final SsaMethod ssaMeth, InterferenceGraph interference, - boolean minimizeRegisters) { - super(ssaMeth, interference); - - ssaRegsMapped = new BitSet(ssaMeth.getRegCount()); - - mapper = new InterferenceRegisterMapper( - interference, ssaMeth.getRegCount()); - - this.minimizeRegisters = minimizeRegisters; - - /* - * Reserve space for the params at the bottom of the register - * space. Later, we'll flip the params to the end of the register - * space. - */ - - paramRangeEnd = ssaMeth.getParamWidth(); - - reservedRopRegs = new BitSet(paramRangeEnd * 2); - reservedRopRegs.set(0, paramRangeEnd); - usedRopRegs = new BitSet(paramRangeEnd * 2); - localVariables = new TreeMap<LocalItem, ArrayList<RegisterSpec>>(); - moveResultPseudoInsns = new ArrayList<NormalSsaInsn>(); - invokeRangeInsns = new ArrayList<NormalSsaInsn>(); - } - - /** {@inheritDoc} */ - @Override - public boolean wantsParamsMovedHigh() { - return true; - } - - /** {@inheritDoc} */ - @Override - public RegisterMapper allocateRegisters() { - - analyzeInstructions(); - - if (DEBUG) { - printLocalVars(); - } - - if(DEBUG) System.out.println("--->Mapping local-associated params"); - handleLocalAssociatedParams(); - - if(DEBUG) System.out.println("--->Mapping other params"); - handleUnassociatedParameters(); - - if(DEBUG) System.out.println("--->Mapping invoke-range"); - handleInvokeRangeInsns(); - - if(DEBUG) System.out.println("--->Mapping local-associated non-params"); - handleLocalAssociatedOther(); - - if(DEBUG) System.out.println("--->Mapping check-cast results"); - handleCheckCastResults(); - - if(DEBUG) System.out.println("--->Mapping others"); - handleNormalUnassociated(); - - return mapper; - } - - /** - * Dumps local variable table to stdout for debugging. - */ - private void printLocalVars() { - System.out.println("Printing local vars"); - for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> e: - localVariables.entrySet()) { - StringBuilder regs = new StringBuilder(); - - regs.append('{'); - regs.append(' '); - for(RegisterSpec reg: e.getValue()) { - regs.append('v'); - regs.append(reg.getReg()); - regs.append(' '); - } - regs.append('}'); - System.out.printf("Local: %s Registers: %s\n", e.getKey(), regs); - } - } - - /** - * Maps all local-associated parameters to Rop registers. - */ - private void handleLocalAssociatedParams() { - for (ArrayList<RegisterSpec> ssaRegs: localVariables.values()) { - int sz = ssaRegs.size(); - int paramIndex = -1; - int paramCategory = 0; - - // First, find out if this local variable is a parameter - for (int i = 0 ; i < sz ; i++) { - RegisterSpec ssaSpec = ssaRegs.get(i); - int ssaReg = ssaSpec.getReg(); - - paramIndex = getParameterIndexForReg(ssaReg); - - if (paramIndex >= 0) { - paramCategory = ssaSpec.getCategory(); - addMapping(ssaSpec, paramIndex); - break; - } - } - - if (paramIndex < 0) { - // this local wasn't a parameter - continue; - } - - // Any remaining local-associated registers will be mapped later - tryMapRegs(ssaRegs, paramIndex, paramCategory, true); - } - } - - /** - * Gets the parameter index for SSA registers that are method parameters. - * -1 is returned for non-parameter registers. - * - * @param ssaReg >=0 SSA register to look up - * @return parameter index or -1 if not a parameter - */ - private int getParameterIndexForReg(int ssaReg) { - SsaInsn defInsn = ssaMeth.getDefinitionForRegister(ssaReg); - if (defInsn == null) { - return -1; - } - - Rop opcode = defInsn.getOpcode(); - - // opcode == null for phi insns - if (opcode != null && opcode.getOpcode() == RegOps.MOVE_PARAM) { - CstInsn origInsn = (CstInsn) defInsn.getOriginalRopInsn(); - return ((CstInteger) origInsn.getConstant()).getValue(); - } - - return -1; - } - - /** - * Maps all local-associated registers that are not parameters. Tries to - * find an unreserved range that's wide enough for all of the SSA registers, - * and then tries to map them all to that range. If not all fit, - * a new range is tried until all registers have been fit. - */ - private void handleLocalAssociatedOther() { - for (ArrayList<RegisterSpec> specs: localVariables.values()) { - int ropReg = 0; - - boolean done; - do { - int maxCategory = 1; - - // compute max category for remaining unmapped registers - int sz = specs.size(); - for (int i = 0; i < sz; i++) { - RegisterSpec ssaSpec = specs.get(i); - int category = ssaSpec.getCategory(); - if (!ssaRegsMapped.get(ssaSpec.getReg()) - && category > maxCategory) { - maxCategory = category; - } - } - - ropReg = findRopRegForLocal(ropReg, maxCategory); - - done = tryMapRegs(specs, ropReg, maxCategory, true); - - // Increment for next call to findNext - ropReg++; - } while (!done); - } - } - - /** - * Tries to map a list of SSA registers into the a rop reg, marking - * used rop space as reserved. SSA registers that don't fit are left - * unmapped. - * - * @param specs non-null; SSA registers to attempt to map - * @param ropReg >=0 rop register to map to - * @param maxAllowedCategory 1 or 2, maximum category allowed in mapping. - * @param markReserved do so if true - * @return true if all registers wew mapped, false if some remain unmapped. - */ - private boolean tryMapRegs( - ArrayList<RegisterSpec> specs, int ropReg, - int maxAllowedCategory, boolean markReserved) { - boolean remaining = false; - for(RegisterSpec spec: specs) { - if (ssaRegsMapped.get(spec.getReg())) { - continue; - } - - boolean succeeded; - succeeded = tryMapReg(spec, ropReg, maxAllowedCategory); - remaining = !succeeded || remaining; - if (succeeded && markReserved) { - // This only needs to be called once really with - // the widest category used, but <shrug> - markReserved(ropReg, spec.getCategory()); - } - } - return !remaining; - } - - /** - * Tries to map an SSA register to a rop register. - * - * @param ssaSpec non-null; SSA register - * @param ropReg >=0 rop register - * @param maxAllowedCategory 1 or 2, the maximum category that the SSA - * register is allowed to be. - * @return true if map succeeded, false if not. - */ - private boolean tryMapReg(RegisterSpec ssaSpec, int ropReg, - int maxAllowedCategory) { - if (ssaSpec.getCategory() <= maxAllowedCategory - && !ssaRegsMapped.get(ssaSpec.getReg()) - && canMapReg(ssaSpec, ropReg)) { - addMapping(ssaSpec, ropReg); - return true; - } - - return false; - } - - /** - * Marks a range of Rop registers as "reserved for a local variable" - * - * @param ropReg >= 0 rop register to reserve - * @param category > 0 width to reserve - */ - private void markReserved(int ropReg, int category) { - reservedRopRegs.set(ropReg, ropReg + category, true); - } - - /** - * Checks to see if any Rop registers in the specified range are reserved - * for local variables or parameters - * - * @param ropRangeStart >= 0 lowest Rop register - * @param width > 0 number of Rop registers in range. - * @return true if any register in range is marked reserved - */ - private boolean rangeContainsReserved(int ropRangeStart, int width) { - for (int i = ropRangeStart; i < (ropRangeStart + width); i++) { - if (reservedRopRegs.get(i)) { - return true; - } - } - return false; - } - - /** - * Returns true if given rop register represents the "this" pointer - * for a non-static method - * - * @param startReg rop register - * @return true if the "this" pointer is located here. - */ - private boolean isThisPointerReg(int startReg) { - // "this" is always the first parameter - return startReg == 0 && !ssaMeth.isStatic(); - } - - /** - * Finds a range of unreserved Rop registers. - * - * @param startReg >= 0; a Rop register to start the search at - * @param width > 0; the width, in registers, required. - * @return >= 0; start of available register range. - */ - private int findNextUnreservedRopReg(int startReg, int width) { - if (minimizeRegisters && !isThisPointerReg(startReg)) { - return startReg; - } - - int reg; - - reg = reservedRopRegs.nextClearBit(startReg); - - while (true) { - int i = 1; - - while (i < width && !reservedRopRegs.get(reg + i)) { - i++; - } - - if (i == width) { - return reg; - } - - reg = reservedRopRegs.nextClearBit(reg + i); - } - } - - /** - * Finds a range of rop regs that can be used for local variables. - * If <code>MIX_LOCALS_AND_OTHER</code> is false, this means any - * rop register that has not yet been used. - * - * @param startReg >= 0; a Rop register to start the search at - * @param width > 0; the width, in registers, required. - * @return >= 0; start of available register range. - */ - private int findRopRegForLocal(int startReg, int width) { - if (minimizeRegisters && !isThisPointerReg(startReg)) { - return startReg; - } - - int reg; - - reg = usedRopRegs.nextClearBit(startReg); - - while (true) { - int i = 1; - - while (i < width && !usedRopRegs.get(reg + i)) { - i++; - } - - if (i == width) { - return reg; - } - - reg = usedRopRegs.nextClearBit(reg + i); - } - } - - /** - * Maps any parameter that isn't local-associated, which can happen - * in the case where there is no java debug info. - */ - private void handleUnassociatedParameters() { - int szSsaRegs = ssaMeth.getRegCount(); - for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) { - if (ssaRegsMapped.get(ssaReg)) { - // We already did this one above - continue; - } - - int paramIndex = getParameterIndexForReg(ssaReg); - - RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg); - if (paramIndex >= 0) { - addMapping(ssaSpec, paramIndex); - } - } - } - - /** - * Handles all insns that want a register range for their sources. - */ - private void handleInvokeRangeInsns() { - for(NormalSsaInsn insn: invokeRangeInsns) { - adjustAndMapSourceRangeRange(insn); - } - } - - /** - * Handles check cast results to reuse the same source register if possible - */ - private void handleCheckCastResults() { - for (NormalSsaInsn insn : moveResultPseudoInsns) { - RegisterSpec moveRegSpec = insn.getResult(); - int moveReg = moveRegSpec.getReg(); - BitSet predBlocks = insn.getBlock().getPredecessors(); - - // Expect one predecessor block only - if (predBlocks.cardinality() != 1) { - continue; - } - - SsaBasicBlock predBlock = - ssaMeth.getBlocks().get(predBlocks.nextSetBit(0)); - ArrayList<SsaInsn> insnList = predBlock.getInsns(); - - /** - * If the predecessor block has a check-cast, it will be the last - * instruction - */ - SsaInsn checkCastInsn = insnList.get(insnList.size() - 1); - if (checkCastInsn.getOpcode().getOpcode() != RegOps.CHECK_CAST) { - continue; - } - - RegisterSpec checkRegSpec = checkCastInsn.getSources().get(0); - int checkReg = checkRegSpec.getReg(); - - // Assume none of the register is mapped yet - int ropReg = 0; - - /** - * See if either register is already mapped. Most likely the move - * result will be mapped already since the cast result is stored - * in a local variable. - */ - if (ssaRegsMapped.get(moveReg)) { - ropReg = mapper.oldToNew(moveReg); - } else if (ssaRegsMapped.get(checkReg)) { - ropReg = mapper.oldToNew(checkReg); - } - - ArrayList<RegisterSpec> ssaRegs = new ArrayList<RegisterSpec>(2); - ssaRegs.add(moveRegSpec); - ssaRegs.add(checkRegSpec); - int category = checkRegSpec.getCategory(); - - while (!tryMapRegs(ssaRegs, ropReg, category, false)) { - ropReg = findNextUnreservedRopReg(ropReg + 1, category); - } - } - } - - /** - * Maps all non-parameter, non-local variable - * registers. - */ - private void handleNormalUnassociated() { - int szSsaRegs = ssaMeth.getRegCount(); - for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) { - if (ssaRegsMapped.get(ssaReg)) { - // We already did this one - continue; - } - - RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg); - - if (ssaSpec == null) continue; - - int category = ssaSpec.getCategory(); - // Find a rop reg that does not interfere - int ropReg = findNextUnreservedRopReg(0, category); - while (!canMapReg(ssaSpec, ropReg)) { - ropReg = findNextUnreservedRopReg(ropReg + 1, category); - } - - addMapping(ssaSpec, ropReg); - } - } - - /** - * Checks to see if <code>ssaSpec</code> can be mapped to - * <code>ropReg</code>. Checks interference graph and ensures - * the range does not cross the parameter range. - * - * @param ssaSpec non-null; SSA spec - * @param ropReg prosepctive new-namespace reg - * @return true if mapping is possible - */ - private boolean canMapReg(RegisterSpec ssaSpec, int ropReg) { - int category = ssaSpec.getCategory(); - return !(spansParamRange(ropReg, category) - || mapper.interferes(ssaSpec, ropReg)); - } - - /** - * Returns true if the specified Rop register + category - * will cross the boundry between the lower <code>paramWidth</code> - * registers reserved for method params and the upper registers. We cannot - * allocate a register that spans the param block and the normal block, - * because we will be moving the param block to high registers later. - * - * @param ssaReg register in new namespace - * @param category width that the register will have - * @return true in the case noted above. - */ - private boolean spansParamRange(int ssaReg, int category) { - return ((ssaReg < paramRangeEnd) - && ((ssaReg + category) > paramRangeEnd)); - } - - /** - * Analyze each instruction and find out all the local variable assignments - * and move-result-pseudo/invoke-range instrucitons. - */ - private void analyzeInstructions() { - ssaMeth.forEachInsn(new SsaInsn.Visitor() { - - /** {@inheritDoc} */ - public void visitMoveInsn(NormalSsaInsn insn) { - processInsn(insn); - } - - /** {@inheritDoc} */ - public void visitPhiInsn(PhiInsn insn) { - processInsn(insn); - } - - /** {@inheritDoc} */ - public void visitNonMoveInsn(NormalSsaInsn insn) { - processInsn(insn); - } - - /** - * This method collects three types of instructions: - * 1) Adds a local variable assignment to the - * <code>localVariables</code> map. - * 2) Add move-result-pseudo to the - * <code>moveResultPseudoInsns</code> list. - * 3) Add invoke-range to the - * <code>invokeRangeInsns</code> list. - * - * @param insn non-null; insn that may represent a local variable - * assignment. - */ - private void processInsn(SsaInsn insn) { - RegisterSpec assignment; - assignment = insn.getLocalAssignment(); - - if (assignment != null) { - LocalItem local = assignment.getLocalItem(); - - ArrayList<RegisterSpec> regList = localVariables.get(local); - - if (regList == null) { - regList = new ArrayList<RegisterSpec>(); - localVariables.put(local, regList); - } - - regList.add(assignment); - } - - if (insn instanceof NormalSsaInsn) { - if (insn.getOpcode().getOpcode() == - RegOps.MOVE_RESULT_PSEUDO) { - moveResultPseudoInsns.add((NormalSsaInsn) insn); - } else if (Optimizer.getAdvice().requiresSourcesInOrder( - insn.getOriginalRopInsn().getOpcode(), - insn.getSources())) { - invokeRangeInsns.add((NormalSsaInsn) insn); - } - } - - } - }); - } - - /** - * Adds a mapping from an SSA register to a Rop register. <code> - * canMapReg</code> should have already been called. - * - * @param ssaSpec non-null; SSA register to map from - * @param ropReg >=0; Rop register to map to - */ - private void addMapping(RegisterSpec ssaSpec, int ropReg) { - int ssaReg = ssaSpec.getReg(); - - // An assertion - if (ssaRegsMapped.get(ssaReg) || !canMapReg(ssaSpec, ropReg)) { - throw new RuntimeException( - "attempt to add invalid register mapping"); - } - - if (DEBUG) { - System.out.printf("Add mapping s%d -> v%d c:%d\n", - ssaSpec.getReg(), ropReg, ssaSpec.getCategory()); - - } - - int category = ssaSpec.getCategory(); - mapper.addMapping(ssaSpec.getReg(), ropReg, category); - ssaRegsMapped.set(ssaReg); - usedRopRegs.set(ropReg, ropReg + category); - } - - - /** - * Maps the source registers of the specified instruction such that they - * will fall in a contiguous range in Rop form. Moves are inserted as - * necessary to allow the range to be allocated. - * - * @param insn non-null; insn whos sources to process - */ - private void adjustAndMapSourceRangeRange(NormalSsaInsn insn) { - int newRegStart; - - newRegStart = findRangeAndAdjust(insn); - - RegisterSpecList sources = insn.getSources(); - int szSources = sources.size(); - int nextRopReg = newRegStart; - for (int i = 0; i < szSources; i++) { - RegisterSpec source = sources.get(i); - int sourceReg = source.getReg(); - int category = source.getCategory(); - int curRopReg = nextRopReg; - nextRopReg += category; - - if (ssaRegsMapped.get(sourceReg)) { - continue; - } - - LocalItem localItem = getLocalItemForReg(sourceReg); - addMapping(source, curRopReg); - - if (localItem != null) { - markReserved(curRopReg, category); - ArrayList<RegisterSpec> similarRegisters - = localVariables.get(localItem); - - int szSimilar = similarRegisters.size(); - - // Try to map all SSA registers also associated with this local - for (int j = 0; j < szSimilar; j++) { - RegisterSpec similarSpec = similarRegisters.get(j); - int similarReg = similarSpec.getReg(); - - // ...and don't map anything that's also a source... - if (-1 != sources.indexOfRegister(similarReg)) { - continue; - } - - // Registers left unmapped will get handled later - tryMapReg(similarSpec, curRopReg, category); - } - } - } - } - - /** - * Find a contiguous rop register range that fits the specified - * instruction's sources. First, try to center the range around - * sources that have already been mapped to Rop registers. If that fails, - * just find a new contiguous range that doesn't interfere. - - * @param insn non-null; the insn whose sources need to fit. Must be - * last insn in basic block. - * @return >= 0 rop register of start of range - */ - private int findRangeAndAdjust(NormalSsaInsn insn) { - RegisterSpecList sources = insn.getSources(); - int szSources = sources.size(); - // the category for each source index - int categoriesForIndex[] = new int[szSources]; - int rangeLength = 0; - - // Compute rangeLength and categoriesForIndex - for (int i = 0; i < szSources; i++) { - int category = sources.get(i).getCategory(); - categoriesForIndex[i] = category; - rangeLength += categoriesForIndex[i]; - } - - // The highest score of fits tried so far - int maxScore = Integer.MIN_VALUE; - // the high scoring range's start - int resultRangeStart = -1; - // by source index: set of sources needing moves in high scoring plan - BitSet resultMovesRequired = null; - - /* - * First, go through each source that's already been mapped. Try - * to center the range around the Rop register this source is mapped - * to. - */ - int rangeStartOffset = 0; - for (int i = 0; i < szSources; i++) { - int ssaCenterReg = sources.get(i).getReg(); - - if (i != 0) { - rangeStartOffset -= categoriesForIndex[i - 1]; - } - if (!ssaRegsMapped.get(ssaCenterReg)) { - continue; - } - - int rangeStart = mapper.oldToNew(ssaCenterReg) + rangeStartOffset; - - if (rangeStart < 0 || spansParamRange(rangeStart, rangeLength)) { - continue; - } - - BitSet curMovesRequired = new BitSet(szSources); - - int fitWidth - = fitPlanForRange(rangeStart, insn, categoriesForIndex, - curMovesRequired); - - if (fitWidth < 0) { - continue; - } - - int score = fitWidth - curMovesRequired.cardinality(); - - if (score > maxScore) { - maxScore = score; - resultRangeStart = rangeStart; - resultMovesRequired = curMovesRequired; - } - - if (fitWidth == rangeLength) { - // We can't do any better than this, so stop here - break; - } - } - - /* - * If we were unable to find a plan for a fit centered around - * an already-mapped source, just try to find a range of - * registers we can move the range into. - */ - - if (resultRangeStart == -1) { - resultMovesRequired = new BitSet(szSources); - - resultRangeStart = findAnyFittingRange(insn, rangeLength, - categoriesForIndex, resultMovesRequired); - } - - /* - * Now, insert any moves required - */ - - for (int i = resultMovesRequired.nextSetBit(0); i >= 0 - ; i = resultMovesRequired.nextSetBit(i+1)) { - insn.changeOneSource(i, - insertMoveBefore(insn, sources.get(i))); - } - - return resultRangeStart; - } - - /** - * Finds an unreserved range that will fit the sources of the - * specified instruction. Does not bother trying to center the range - * around an already-mapped source register; - * - * @param insn non-null; insn to build range for - * @param rangeLength >=0 length required in register units. - * @param categoriesForIndex non-null; indexed by source index; - * the category for each source. - * @param outMovesRequired non-null; an output parameter indexed by - * source index that will contain the set of sources which need - * moves inserted. - * @return the rop register that starts the fitting range. - */ - private int findAnyFittingRange(NormalSsaInsn insn, int rangeLength, - int[] categoriesForIndex, BitSet outMovesRequired) { - int rangeStart = 0; - while (true) { - rangeStart = findNextUnreservedRopReg(rangeStart, rangeLength); - int fitWidth - = fitPlanForRange(rangeStart, insn, - categoriesForIndex, outMovesRequired); - - if (fitWidth >= 0) { - break; - } - rangeStart++; - outMovesRequired.clear(); - } - return rangeStart; - } - - /** - * Attempts to build a plan for fitting a range of sources into rop - * registers. - * - * @param ropReg >=0 rop reg that begins range - * @param insn non-null; insn to plan range for - * @param categoriesForIndex non-null; indexed by source index; - * the category for each source. - * @param outMovesRequired non-null; an output parameter indexed by - * source index that will contain the set of sources which need - * moves inserted. - * @return the width of the fit that that does not involve added moves or - * -1 if "no fit possible" - */ - private int fitPlanForRange(int ropReg, NormalSsaInsn insn, - int[] categoriesForIndex, BitSet outMovesRequired) { - RegisterSpecList sources = insn.getSources(); - int szSources = sources.size(); - int fitWidth = 0; - IntSet liveOut = insn.getBlock().getLiveOutRegs(); - RegisterSpecList liveOutSpecs = ssaSetToSpecs(liveOut); - - // An SSA reg may only be mapped into a range once - BitSet seen = new BitSet(ssaMeth.getRegCount()); - - for (int i = 0; i < szSources ; i++) { - RegisterSpec ssaSpec = sources.get(i); - int ssaReg = ssaSpec.getReg(); - int category = categoriesForIndex[i]; - - if (i != 0) { - ropReg += categoriesForIndex[i-1]; - } - - if (ssaRegsMapped.get(ssaReg) - && mapper.oldToNew(ssaReg) == ropReg) { - // A register already mapped appropriately - fitWidth += category; - } else if (rangeContainsReserved(ropReg, category)) { - fitWidth = -1; - break; - } else if (!ssaRegsMapped.get(ssaReg) - && canMapReg(ssaSpec, ropReg) - && !seen.get(ssaReg)) { - // A register that can be mapped appropriately - fitWidth += category; - } else if (!mapper.areAnyPinned(liveOutSpecs, ropReg, category) - && !mapper.areAnyPinned(sources, ropReg, category)) { - /* - * A source that can be moved - * We can insert a move as long as: - * - * - no SSA register pinned to the desired rop reg - * is live out on the block - * - no SSA register pinned to desired rop reg is - * a source of this insn (since this may require - * overlapping moves, which we can't presently handle) - */ - - outMovesRequired.set(i); - } else { - fitWidth = -1; - break; - } - - seen.set(ssaReg); - } - return fitWidth; - } - - /** - * Converts a bit set of SSA registers into a RegisterSpecList containing - * the definition specs of all the registers. - * - * @param ssaSet non-null; set of SSA registers - * @return list of RegisterSpecs as noted above - */ - RegisterSpecList ssaSetToSpecs(IntSet ssaSet) { - RegisterSpecList result = new RegisterSpecList(ssaSet.elements()); - - IntIterator iter = ssaSet.iterator(); - - int i = 0; - while (iter.hasNext()) { - result.set(i++, getDefinitionSpecForSsaReg(iter.next())); - } - - return result; - } - - /** - * Gets a local item associated with an ssa register, if one exists - * - * @param ssaReg >= 0 SSA register - * @return null-ok; associated local item or null - */ - private LocalItem getLocalItemForReg(int ssaReg) { - for(Map.Entry<LocalItem, ArrayList<RegisterSpec>> entry: - localVariables.entrySet()) { - - for (RegisterSpec spec: entry.getValue()) { - if (spec.getReg() == ssaReg) { - return entry.getKey(); - } - } - } - - return null; - } -} diff --git a/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java b/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java deleted file mode 100644 index abc5fca78..000000000 --- a/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java +++ /dev/null @@ -1,174 +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.android.dx.ssa.back; - -import com.android.dx.rop.code.BasicBlock; -import com.android.dx.rop.code.BasicBlockList; -import com.android.dx.rop.code.CstInsn; -import com.android.dx.rop.code.Insn; -import com.android.dx.rop.code.InsnList; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.SwitchInsn; -import com.android.dx.util.IntList; - -import java.util.BitSet; - -/** - * Searches for basic blocks that all have the same successor and insns - * but different predecessors. These blocks are then combined into a single - * block and the now-unused blocks are deleted. These identical blocks - * frequently are created when catch blocks are edge-split. - */ -public class IdenticalBlockCombiner { - - private RopMethod ropMethod; - private BasicBlockList blocks; - private BasicBlockList newBlocks; - - /** - * Constructs instance. Call <code>process()</code> to run. - * @param rm instance to process - */ - public IdenticalBlockCombiner(RopMethod rm) { - ropMethod = rm; - blocks = ropMethod.getBlocks(); - newBlocks = blocks.getMutableCopy(); - } - - /** - * Runs algorithm. TODO: this is n^2, and could be made linear-ish with - * a hash. - * - * @return new method that has been processed - */ - public RopMethod process() { - int szBlocks = blocks.size(); - // indexed by label - BitSet toDelete = new BitSet(blocks.getMaxLabel()); - - // For each non-deleted block... - for (int bindex = 0; bindex < szBlocks; bindex++) { - BasicBlock b = blocks.get(bindex); - - if (toDelete.get(b.getLabel())) { - // doomed block - continue; - } - - IntList preds = ropMethod.labelToPredecessors(b.getLabel()); - - // ...look at all of it's predecessors that have only one succ... - int szPreds = preds.size(); - for (int i = 0; i < szPreds; i++) { - int iLabel = preds.get(i); - - BasicBlock iBlock = blocks.labelToBlock(iLabel); - - if (toDelete.get(iLabel) || iBlock.getSuccessors().size() > 1) { - continue; - } - - IntList toCombine = new IntList(); - - // ...and see if they can be combined with any other preds... - for (int j = i + 1; j <szPreds; j++) { - int jLabel = preds.get(j); - BasicBlock jBlock = blocks.labelToBlock(jLabel); - - if (jBlock.getSuccessors().size() == 1 - && compareInsns(iBlock, jBlock)) { - - toCombine.add(jLabel); - toDelete.set(jLabel); - } - } - - combineBlocks(iLabel, toCombine); - } - } - - for (int i = szBlocks - 1; i > 0; i--) { - if (toDelete.get(newBlocks.get(i).getLabel())) { - newBlocks.set(i, null); - } - } - - newBlocks.shrinkToFit(); - newBlocks.setImmutable(); - - return new RopMethod(newBlocks, ropMethod.getFirstLabel()); - } - - private boolean compareInsns(BasicBlock a, BasicBlock b) { - return a.getInsns().contentEquals(b.getInsns()); - } - - /** - * Combines blocks proven identical into one alpha block, re-writing - * all of the successor links that point to the beta blocks to point - * to the alpha block instead. - * - * @param alphaLabel block that will replace all the beta block - * @param betaLabels label list of blocks to combine - */ - private void combineBlocks(int alphaLabel, IntList betaLabels) { - int szBetas = betaLabels.size(); - - for (int i = 0; i < szBetas; i++) { - int betaLabel = betaLabels.get(i); - BasicBlock bb = blocks.labelToBlock(betaLabel); - - IntList preds; - - preds = ropMethod.labelToPredecessors(bb.getLabel()); - - int szPreds = preds.size(); - - for (int j = 0; j < szPreds; j++) { - BasicBlock predBlock = newBlocks.labelToBlock(preds.get(j)); - replaceSucc(predBlock, betaLabel, alphaLabel); - } - } - } - - /** - * Replaces one of a block's successors with a different label. Constructs - * an updated BasicBlock instance and places it in <code>newBlocks</code>. - * - * @param block block to replace - * @param oldLabel label of successor to replace - * @param newLabel label of new successor - */ - private void replaceSucc(BasicBlock block, int oldLabel, int newLabel) { - - IntList newSuccessors = block.getSuccessors().mutableCopy(); - int newPrimarySuccessor; - - newSuccessors.set(newSuccessors.indexOf(oldLabel), newLabel); - newPrimarySuccessor = block.getPrimarySuccessor(); - if (newPrimarySuccessor == oldLabel) { - newPrimarySuccessor = newLabel; - } - - newSuccessors.setImmutable(); - - BasicBlock newBB = new BasicBlock(block.getLabel(), - block.getInsns(), newSuccessors, newPrimarySuccessor); - - newBlocks.set(newBlocks.indexOfLabel(block.getLabel()), newBB); - } -} diff --git a/dx/src/com/android/dx/ssa/back/InterferenceGraph.java b/dx/src/com/android/dx/ssa/back/InterferenceGraph.java deleted file mode 100644 index 282420b8f..000000000 --- a/dx/src/com/android/dx/ssa/back/InterferenceGraph.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.android.dx.ssa.back; - -import com.android.dx.ssa.SsaMethod; -import com.android.dx.ssa.SsaBasicBlock; -import com.android.dx.ssa.SsaInsn; -import com.android.dx.ssa.PhiInsn; -import com.android.dx.ssa.SetFactory; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.util.IntSet; -import com.android.dx.util.BitIntSet; -import com.android.dx.util.ListIntSet; - -import java.util.BitSet; -import java.util.List; -import java.util.ArrayList; - -/** - * A register interference graph - */ -public class InterferenceGraph { - /** interference graph, indexed by register in both dimensions */ - private final ArrayList<IntSet> interference; - - /** - * Creates a new graph. - * - * @param countRegs >=0 the start count of registers in the namespace. - * New registers can be added subsequently. - */ - public InterferenceGraph(int countRegs) { - interference = new ArrayList<IntSet>(countRegs); - - for (int i = 0; i < countRegs; i++) { - interference.add(SetFactory.makeInterferenceSet(countRegs)); - } - } - - /** - * Adds a register pair to the interference/liveness graph. Parameter - * order is insignificant. - * - * @param regV one register index - * @param regW another register index - */ - public void add(int regV, int regW) { - ensureCapacity(Math.max(regV, regW) + 1); - - interference.get(regV).add(regW); - interference.get(regW).add(regV); - } - - /** - * Dumps interference graph to stdout for debugging. - */ - public void dumpToStdout() { - int oldRegCount = interference.size(); - - for (int i = 0; i < oldRegCount; i++) { - StringBuilder sb = new StringBuilder(); - - sb.append("Reg " + i + ":" + interference.get(i).toString()); - - System.out.println(sb.toString()); - } - } - - /** - * Merges the interference set for a register into a given bit set - * - * @param reg >=0 register - * @param set non-null; interference set; will be merged with set for - * given register - */ - public void mergeInterferenceSet(int reg, IntSet set) { - if (reg < interference.size()) { - set.merge(interference.get(reg)); - } - } - - /** - * Ensures that the interference graph is appropriately sized. - * - * @param size requested minumum size - */ - private void ensureCapacity(int size) { - int countRegs = interference.size(); - interference.ensureCapacity(size); - for (int i = countRegs ; i < size; i++) { - interference.add(SetFactory.makeInterferenceSet(size)); - } - } -} diff --git a/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java b/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java deleted file mode 100644 index 5ae6e074a..000000000 --- a/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java +++ /dev/null @@ -1,278 +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.android.dx.ssa.back; - -import com.android.dx.ssa.SsaMethod; -import com.android.dx.ssa.SsaBasicBlock; -import com.android.dx.ssa.SsaInsn; -import com.android.dx.ssa.PhiInsn; -import com.android.dx.rop.code.RegisterSpec; - -import java.util.BitSet; -import java.util.List; -import java.util.ArrayList; - -/** - * From Appel "Modern Compiler Implementation in Java" algorithm 19.17 - * Calculate the live ranges for register <code>reg</code>.<p> - * - * v = regV <p> - * s = insn <p> - * M = visitedBlocks <p> - */ -public class LivenessAnalyzer { - - /** - * non-null; index by basic block indexed set of basic blocks - * that have already been visited. "M" as written in the original Appel - * algorithm. - */ - private final BitSet visitedBlocks; - - /** - * non-null; set of blocks remaing to visit as "live out as block" - */ - private final BitSet liveOutBlocks; - - /** - * >=0; SSA register currently being analyzed. - * "v" in the original Appel algorithm. - */ - private final int regV; - - /** method to process */ - private final SsaMethod ssaMeth; - - /** interference graph being updated */ - private final InterferenceGraph interference; - - /** block "n" in Appel 19.17 */ - SsaBasicBlock blockN; - - /** index of statement <code>s</code> in <code>blockN</code>*/ - private int statementIndex; - - /** the next function to call. one of the four constants below */ - private int nextFunction; - - /** constants for nextFunction */ - static final int LIVE_IN_AT_STATEMENT = 1; - static final int LIVE_OUT_AT_STATEMENT = 2; - static final int LIVE_OUT_AT_BLOCK = 3; - static final int DONE = 4; - - /** - * Runs register liveness algorithm for a method, updating the - * live in/out information in <code>SsaBasicBlock</code> instances and - * returning an interference graph. - * - * @param ssaMeth non-null; Method to process. - * @return non-null; interference graph indexed by SSA registers in both - * directions. - */ - public static InterferenceGraph constructInterferenceGraph( - SsaMethod ssaMeth) { - int szRegs = ssaMeth.getRegCount(); - - InterferenceGraph interference = new InterferenceGraph(szRegs); - - for (int i = 0; i < szRegs; i++) { - new LivenessAnalyzer(ssaMeth, i, interference).run(); - } - - coInterferePhis(ssaMeth, interference); - - return interference; - } - - /** - * Makes liveness analyzer instance for specific register. - * - * @param ssaMeth non-null; method to process - * @param reg register whose liveness to analyze - * @param interference non-null; indexed by SSA reg in both dimensions; - * graph to update - * - */ - private LivenessAnalyzer(final SsaMethod ssaMeth, final int reg, - InterferenceGraph interference) { - this.ssaMeth = ssaMeth; - this.regV = reg; - visitedBlocks = new BitSet(ssaMeth.getBlocks().size()); - liveOutBlocks = new BitSet(ssaMeth.getBlocks().size()); - this.interference = interference; - } - - /** - * The algorithm in Appel is presented in - * partial tail-recursion form. Obviously, that's not - * efficient in java, so this function serves - * as the dispatcher instead. - */ - private void handleTailRecursion() { - while (nextFunction != DONE) { - switch (nextFunction) { - case LIVE_IN_AT_STATEMENT: - nextFunction = DONE; - liveInAtStatement(); - break; - - case LIVE_OUT_AT_STATEMENT: - nextFunction = DONE; - liveOutAtStatement(); - break; - - case LIVE_OUT_AT_BLOCK: - nextFunction = DONE; - liveOutAtBlock(); - break; - - default: - } - } - } - - /** - * From Appel algorithm 19.17 - */ - public void run() { - List<SsaInsn> useList = ssaMeth.getUseListForRegister(regV); - - for (SsaInsn insn: useList) { - nextFunction = DONE; - - if (insn instanceof PhiInsn) { - // If s is a phi-function with V as it's ith argument - PhiInsn phi = (PhiInsn) insn; - - for (SsaBasicBlock pred: phi.predBlocksForReg(regV, ssaMeth)) { - - blockN = pred; - - nextFunction = LIVE_OUT_AT_BLOCK; - handleTailRecursion(); - } - } else { - blockN = insn.getBlock(); - statementIndex = blockN.getInsns().indexOf(insn); - - if (statementIndex < 0) { - throw new RuntimeException( - "insn not found in it's own block"); - } - - nextFunction = LIVE_IN_AT_STATEMENT; - handleTailRecursion(); - } - } - - int nextLiveOutBlock; - while ((nextLiveOutBlock = liveOutBlocks.nextSetBit(0)) >= 0) { - blockN = ssaMeth.getBlocks().get(nextLiveOutBlock); - liveOutBlocks.clear(nextLiveOutBlock); - nextFunction = LIVE_OUT_AT_BLOCK; - handleTailRecursion(); - } - } - - /** - * "v is live-out at n" - */ - private void liveOutAtBlock() { - if (! visitedBlocks.get(blockN.getIndex())) { - visitedBlocks.set(blockN.getIndex()); - - blockN.addLiveOut(regV); - - ArrayList<SsaInsn> insns; - - insns = blockN.getInsns(); - - // Live out at last statement in blockN - statementIndex = insns.size() - 1; - nextFunction = LIVE_OUT_AT_STATEMENT; - } - } - - /** - * "v is live-in at s" - */ - private void liveInAtStatement() { - - // if s is the first statement in block N - if (statementIndex == 0) { - // v is live-in at n - blockN.addLiveIn(regV); - - BitSet preds = blockN.getPredecessors(); - - liveOutBlocks.or(preds); - } else { - // Let s' be the statement preceeding s - statementIndex -= 1; - nextFunction = LIVE_OUT_AT_STATEMENT; - } - } - - /** - * "v is live-out at s" - */ - private void liveOutAtStatement() { - - SsaInsn statement = blockN.getInsns().get(statementIndex); - RegisterSpec rs = statement.getResult(); - - if (!statement.isResultReg(regV)) { - if(rs != null) { - interference.add(regV, rs.getReg()); - } - nextFunction = LIVE_IN_AT_STATEMENT; - } - } - - /** - * Ensures that all the phi result registers for all the phis in the - * same basic block interfere with each other. This is needed since - * the dead code remover has allowed through "dead-end phis" whose - * results are not used except as local assignments. Without this step, - * a the result of a dead-end phi might be assigned the same register - * as the result of another phi, and the phi removal move scheduler may - * generate moves that over-write the live result. - * - * @param ssaMeth non-null; method to pricess - * @param interference non-null; interference graph - */ - private static void coInterferePhis(SsaMethod ssaMeth, - InterferenceGraph interference) { - for (SsaBasicBlock b: ssaMeth.getBlocks()) { - List<SsaInsn> phis = b.getPhiInsns(); - - int szPhis = phis.size(); - - for (int i = 0; i < szPhis; i++) { - for (int j = 0; j < szPhis; j++) { - if (i == j) { - continue; - } - - interference.add(phis.get(i).getResult().getReg(), - phis.get(j).getResult().getReg()); - } - } - } - } -} diff --git a/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java b/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java deleted file mode 100644 index cd3b2f1eb..000000000 --- a/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java +++ /dev/null @@ -1,61 +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.android.dx.ssa.back; - -import com.android.dx.ssa.BasicRegisterMapper; -import com.android.dx.ssa.RegisterMapper; -import com.android.dx.ssa.SsaMethod; - -import java.util.BitSet; -import java.util.ArrayList; - -/** - * A register allocator that maps SSA register n to Rop register 2*n, - * essentially preserving the original mapping and remaining agnostic - * about normal or wide categories. Used for debugging. - */ -public class NullRegisterAllocator extends RegisterAllocator { - - /** {@inheritDoc} */ - public NullRegisterAllocator( - final SsaMethod ssaMeth, final InterferenceGraph interference) { - - super(ssaMeth, interference); - } - - /** {@inheritDoc} */ - @Override - public boolean wantsParamsMovedHigh() { - // We're not smart enough for this. - return false; - } - - /** {@inheritDoc} */ - @Override - public RegisterMapper allocateRegisters() { - int oldRegCount = ssaMeth.getRegCount(); - - BasicRegisterMapper mapper - = new BasicRegisterMapper(oldRegCount); - - for (int i = 0; i < oldRegCount; i++) { - mapper.addMapping(i, i*2, 2); - } - - return mapper; - } -} diff --git a/dx/src/com/android/dx/ssa/back/RegisterAllocator.java b/dx/src/com/android/dx/ssa/back/RegisterAllocator.java deleted file mode 100644 index 764b03ac2..000000000 --- a/dx/src/com/android/dx/ssa/back/RegisterAllocator.java +++ /dev/null @@ -1,204 +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.android.dx.ssa.back; - -import com.android.dx.rop.code.RegOps; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.PlainInsn; -import com.android.dx.rop.code.Rops; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.ssa.NormalSsaInsn; -import com.android.dx.ssa.RegisterMapper; -import com.android.dx.ssa.SsaInsn; -import com.android.dx.ssa.SsaMethod; -import com.android.dx.ssa.SsaBasicBlock; -import com.android.dx.util.IntSet; -import com.android.dx.util.IntIterator; - -import java.util.BitSet; -import java.util.ArrayList; - -/** - * Base class of all register allocators - */ -public abstract class RegisterAllocator { - - /** method being processed */ - protected final SsaMethod ssaMeth; - - /** interference graph, indexed by register in both dimensions */ - protected final InterferenceGraph interference; - - /** - * Creates an instance. Call <code>allocateRegisters</code> to run. - * @param ssaMeth method to process. - * @param interference Interference graph, indexed by register in both - * dimensions. - */ - public RegisterAllocator( - final SsaMethod ssaMeth, final InterferenceGraph interference) { - this.ssaMeth = ssaMeth; - this.interference = interference; - } - - /** - * Indicates whether the method params were allocated at the bottom - * of the namespace, and thus should be moved up to the top of the - * namespace after phi removal. - * - * @return true if params should be moved from low to high. - */ - public abstract boolean wantsParamsMovedHigh(); - - /** - * Runs the algorithm. - * @return a register mapper to apply to the <code>SsaMethod</code> - */ - public abstract RegisterMapper allocateRegisters(); - - /** - * Returns the category (width) of the definition site of the register. - * Returns 1 for undefined registers. - * - * @param reg register - * @return 1 or 2 - */ - protected int getCategoryForSsaReg(int reg) { - SsaInsn definition; - definition = ssaMeth.getDefinitionForRegister(reg); - - if (definition == null) { - // an undefined reg - return 1; - } else { - return definition.getResult().getCategory(); - } - } - - /** - * Returns the RegisterSpec of the definition of the register. - * - * @param reg >= 0 SSA register - * @return definition spec of the register or null if it is never defined - * (for the case of "version 0" SSA registers). - */ - protected RegisterSpec getDefinitionSpecForSsaReg(int reg) { - SsaInsn definition; - definition = ssaMeth.getDefinitionForRegister(reg); - - return definition == null ? null : definition.getResult(); - } - - /** - * Returns true if the definition site of this register is a - * move-param (ie, this is a method parameter) - * @param reg register in question - * @return true if this is a method parameter - */ - protected boolean isDefinitionMoveParam(int reg) { - SsaInsn defInsn = ssaMeth.getDefinitionForRegister(reg); - if (defInsn instanceof NormalSsaInsn) { - NormalSsaInsn ndefInsn = (NormalSsaInsn) defInsn; - - return ndefInsn.getOpcode().getOpcode() == RegOps.MOVE_PARAM; - } - - return false; - } - - /** - * Inserts a move instruction for a specified SSA register before a - * specified instruction, creating a new SSA register and adjusting the - * interference graph in the process. The insn currently must be the - * last insn in a block. - * - * @param insn non-null; insn to insert move before, must be last insn - * in block. - * @param reg non-null; SSA register to duplicate - * @return non-null; spec of new SSA register created by move - */ - protected final RegisterSpec insertMoveBefore(SsaInsn insn, - RegisterSpec reg) { - - SsaBasicBlock block = insn.getBlock(); - ArrayList<SsaInsn> insns = block.getInsns(); - int insnIndex = insns.indexOf(insn); - - if (insnIndex < 0 ) { - throw new IllegalArgumentException ( - "specified insn is not in this block"); - } - - if (insnIndex != insns.size() - 1) { - /* - * Presently, the interference updater only works when - * adding before the last insn, and the last insn must have no - * result - */ - throw new IllegalArgumentException( - "Adding move here not supported:" + insn.toHuman()); - } - - /* - * Get new register and make new move instruction - */ - - // new result must not have associated local variable - RegisterSpec newRegSpec = RegisterSpec.make(ssaMeth.makeNewSsaReg(), - reg.getTypeBearer()); - - SsaInsn toAdd; - - toAdd = SsaInsn.makeFromRop( - new PlainInsn(Rops.opMove(newRegSpec.getType()), - SourcePosition.NO_INFO, newRegSpec, - RegisterSpecList.make(reg)), block); - - insns.add(insnIndex, toAdd); - - int newReg = newRegSpec.getReg(); - - /* - * Adjust interference graph based on what's live out of the current - * block and what's used by the final instruction. - */ - - IntSet liveOut = block.getLiveOutRegs(); - - RegisterSpec result = insn.getResult(); - int resultReg = (result == null) ? -1 : result.getReg(); - - IntIterator liveOutIter = liveOut.iterator(); - - while(liveOutIter.hasNext()) { - interference.add(newReg, liveOutIter.next()); - } - - // Everything that's a source in the last insn interferes - RegisterSpecList sources = insn.getSources(); - int szSources = sources.size(); - - for (int i = 0; i < szSources; i++) { - interference.add(newReg, sources.get(i).getReg()); - } - - ssaMeth.onInsnsChanged(); - - return newRegSpec; - } -} diff --git a/dx/src/com/android/dx/ssa/back/SsaToRop.java b/dx/src/com/android/dx/ssa/back/SsaToRop.java deleted file mode 100644 index 1c59549af..000000000 --- a/dx/src/com/android/dx/ssa/back/SsaToRop.java +++ /dev/null @@ -1,393 +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.android.dx.ssa.back; - -import com.android.dx.rop.code.BasicBlock; -import com.android.dx.rop.code.BasicBlockList; -import com.android.dx.rop.code.CstInsn; -import com.android.dx.rop.code.InsnList; -import com.android.dx.rop.code.RegOps; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.RegisterSpecList; -import com.android.dx.rop.code.RopMethod; -import com.android.dx.rop.code.Rops; -import com.android.dx.rop.code.Rop; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.ssa.NormalSsaInsn; -import com.android.dx.ssa.BasicRegisterMapper; -import com.android.dx.ssa.PhiInsn; -import com.android.dx.ssa.RegisterMapper; -import com.android.dx.ssa.SsaBasicBlock; -import com.android.dx.ssa.SsaInsn; -import com.android.dx.ssa.SsaMethod; -import com.android.dx.util.IntList; -import com.android.dx.util.Hex; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.HashMap; -import java.util.List; - -/** - * Converts a method in SSA form to ROP form. - */ -public class SsaToRop { - - private static final boolean DEBUG = false; - - /** non-null; method to process */ - private final SsaMethod ssaMeth; - - /** - * true if the converter should attempt to minimize - * the rop-form register count - */ - private final boolean minimizeRegisters; - - /** interference graph */ - private InterferenceGraph interference; - - /** - * Converts a method in SSA form to ROP form. - * @param ssaMeth input - * @return non-null; rop-form output - */ - public static RopMethod convertToRopMethod(SsaMethod ssaMeth, - boolean minimizeRegisters) { - return new SsaToRop(ssaMeth, minimizeRegisters).convert(); - } - - private SsaToRop(final SsaMethod ssaMethod, boolean minimizeRegisters) { - this.minimizeRegisters = minimizeRegisters; - this.ssaMeth = ssaMethod; - } - - private RopMethod convert() { - interference = LivenessAnalyzer.constructInterferenceGraph(ssaMeth); - - if (DEBUG) { - interference.dumpToStdout(); - } - - RegisterAllocator allocator; - RegisterMapper mapper; - - // These are other allocators for debugging or historical comparison - - //allocator = new NullRegisterAllocator(ssaMeth, interference); - //allocator = new FirstFitAllocator(ssaMeth, interference); - - allocator = new FirstFitLocalCombiningAllocator(ssaMeth, interference, - minimizeRegisters); - - mapper = allocator.allocateRegisters(); - - if (DEBUG) { - System.out.println("Printing reg map"); - System.out.println(((BasicRegisterMapper)mapper).toHuman()); - } - - ssaMeth.setBackMode(); - - ssaMeth.mapRegisters(mapper); - - removePhiFunctions(); - - if (allocator.wantsParamsMovedHigh()) { - moveParametersToHighRegisters(); - } - - removeEmptyGotos(); - - RopMethod ropMethod; - - ropMethod = convertToRop(); - - ropMethod = new IdenticalBlockCombiner(ropMethod).process(); - - return ropMethod; - } - - - /** - * Removes all blocks containing only GOTOs from the control flow. Although - * much of this work will be done later when converting from rop to dex, - * not all simplification cases can be handled there. Furthermore, any no-op - * block between the exit block and blocks containing the real return or - * throw statements must be removed. - */ - private void removeEmptyGotos() { - final ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks(); - - ssaMeth.forEachBlockDepthFirst(false, new SsaBasicBlock.Visitor() { - public void visitBlock(SsaBasicBlock b, SsaBasicBlock parent) { - ArrayList<SsaInsn> insns = b.getInsns(); - - if ((insns.size() == 1) - && (insns.get(0).getOpcode() == Rops.GOTO)) { - - BitSet preds = (BitSet)b.getPredecessors().clone(); - - for (int i = preds.nextSetBit(0); i >= 0; - i = preds.nextSetBit(i + 1)) { - SsaBasicBlock pb = blocks.get(i); - pb.replaceSuccessor(b.getIndex(), - b.getPrimarySuccessorIndex()); - } - } - } - }); - } - - /** - * This method is not presently used. - * @return a list of registers ordered by most-frequently-used - * to least-frequently-used. Each register is listed once and only once. - */ - public int[] getRegistersByFrequency() { - int regCount = ssaMeth.getRegCount(); - Integer[] ret = new Integer[ssaMeth.getRegCount()]; - - for (int i = 0; i < regCount; i++) { - ret[i] = i; - } - - java.util.Arrays.sort(ret, new java.util.Comparator<Integer>() { - public int compare (Integer o1, Integer o2) { - return ssaMeth.getUseListForRegister(o2).size() - - ssaMeth.getUseListForRegister(o1).size(); - } - - public boolean equals(Object o) { - return o == this; - } - }); - - int result[] = new int[regCount]; - - for (int i = 0; i < regCount; i++) { - result[i] = ret[i]; - } - - return result; - } - - /** - * See Appel 19.6 - * To remove the phi instructions in an edge-split SSA representation - * we know we can always insert a move in a predecessor block - */ - private void removePhiFunctions() { - for (SsaBasicBlock block: ssaMeth.getBlocks()) { - // Add moves in all the pred blocks for each phi insn` - block.forEachPhiInsn(new PhiVisitor(block)); - // Delete the phi insns - block.removeAllPhiInsns(); - } - - /* - * After all move insns have been added: sort them so they don't - * destructively interfere - */ - for (SsaBasicBlock block: ssaMeth.getBlocks()) { - block.scheduleMovesFromPhis(); - } - } - - /** - * PhiSuccessorUpdater for adding move instructions to predecessors based - * on phi insns. - */ - private class PhiVisitor implements PhiInsn.Visitor { - SsaBasicBlock block; - - PhiVisitor (final SsaBasicBlock block) { - this.block = block; - } - - public void visitPhiInsn (PhiInsn insn) { - RegisterSpecList sources; - RegisterSpec result; - ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks(); - - sources = insn.getSources(); - result = insn.getResult(); - - int sz = sources.size(); - - for (int i = 0; i <sz; i++) { - RegisterSpec source; - - source = sources.get(i); - - SsaBasicBlock predBlock; - - predBlock = blocks.get( - insn.predBlockIndexForSourcesIndex(i)); - - predBlock.addMoveToEnd(result, source); - } - } - } - - /** - * Moves the parameter registers, which allocateRegisters() places - * at the bottom of the frame, up to the top of the frame to match - * Dalvik calling convention. - */ - private void moveParametersToHighRegisters() { - - int paramWidth = ssaMeth.getParamWidth(); - - BasicRegisterMapper mapper - = new BasicRegisterMapper(ssaMeth.getRegCount()); - int regCount = ssaMeth.getRegCount(); - - for (int i = 0; i < regCount; i++) { - if (i < paramWidth) { - mapper.addMapping(i, regCount - paramWidth + i, 1); - } else { - mapper.addMapping(i, i - paramWidth, 1); - } - } - - if (DEBUG) { - System.out.printf("Moving %d registers from 0 to %d\n", - paramWidth, regCount - paramWidth); - } - - ssaMeth.mapRegisters(mapper); - } - - private RopMethod convertToRop() { - return new RopMethod(convertBasicBlocks(), - ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex())); - } - - /** - * @return rop-form basic block list - */ - private BasicBlockList convertBasicBlocks() { - ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks(); - // Exit block may be null - SsaBasicBlock exitBlock = ssaMeth.getExitBlock(); - - int ropBlockCount = ssaMeth.getCountReachableBlocks(); - - // Don't count the exit block, if it exists - ropBlockCount -= (exitBlock == null) ? 0 : 1; - - BasicBlockList result = new BasicBlockList(ropBlockCount); - - // Convert all the reachable blocks except the exit block - int ropBlockIndex = 0; - for(SsaBasicBlock b : blocks) { - if (b.isReachable() && b != exitBlock) { - result.set(ropBlockIndex++, convertBasicBlock(b)); - } - } - - // The exit block, which is discarded, must do nothing. - if (exitBlock != null && exitBlock.getInsns().size() != 0) { - throw new RuntimeException - ("Exit block must have no insns when leaving SSA form"); - } - - return result; - } - - /** - * Validates that a basic block is a valid end predecessor. It must - * end in a RETURN or a THROW. Throws a runtime exception on error. - * - * @param b non-null; block to validate - * @throws RuntimeException on error - */ - private void verifyValidExitPredecessor(SsaBasicBlock b) { - - ArrayList<SsaInsn> insns = b.getInsns(); - SsaInsn lastInsn = insns.get(insns.size() - 1); - Rop opcode = lastInsn.getOpcode(); - - if (opcode.getBranchingness() != Rop.BRANCH_RETURN - && opcode != Rops.THROW) { - throw new RuntimeException("Exit predecessor must end" - + " in valid exit statement."); - } - } - - /** - * Converts a single basic block to rop form. - * - * @param block SSA block to process - * @return ROP block - */ - private BasicBlock convertBasicBlock(SsaBasicBlock block) { - BasicBlock result; - IntList successorList = block.getRopLabelSuccessorList(); - int primarySuccessorLabel = block.getPrimarySuccessorRopLabel(); - // Filter out any reference to the SSA form's exit block - - // exit block may be null - SsaBasicBlock exitBlock = ssaMeth.getExitBlock(); - - int exitRopLabel = (exitBlock == null) ? -1 : exitBlock.getRopLabel(); - - if (successorList.contains(exitRopLabel)) { - if (successorList.size() > 1) { - throw new RuntimeException ( - "Exit predecessor must have no other successors" - + Hex.u2(block.getRopLabel())); - } else { - successorList = IntList.EMPTY; - primarySuccessorLabel = -1; - - verifyValidExitPredecessor(block); - } - } - - successorList.setImmutable(); - - result = new BasicBlock( - block.getRopLabel(), convertInsns(block.getInsns()), - successorList, - primarySuccessorLabel); - - return result; - } - - /** - * Converts an insn list to rop form - * @param ssaInsns non-null;old instructions - * @return non-null; immutable instruction list - */ - private InsnList convertInsns(ArrayList<SsaInsn> ssaInsns) { - InsnList result; - int insnCount; - - insnCount = ssaInsns.size(); - result = new InsnList (insnCount); - - for (int i = 0; i < insnCount; i++) { - result.set(i, ssaInsns.get(i).toRopInsn()); - } - - result.setImmutable(); - - return result; - } -} diff --git a/dx/src/com/android/dx/ssa/package-info.java b/dx/src/com/android/dx/ssa/package-info.java deleted file mode 100644 index 45d9ad6a3..000000000 --- a/dx/src/com/android/dx/ssa/package-info.java +++ /dev/null @@ -1,103 +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.android.dx.ssa; - -/** - * <h1>An introduction to SSA Form</h1> - * - * This package contains classes associated with dx's <code>SSA</code> - * intermediate form. This form is a static-single-assignment representation of - * Rop-form a method with Rop-form-like instructions (with the addition of a - * {@link PhiInsn phi instriction}. This form is intended to make it easy to - * implement basic optimization steps and register allocation so that a - * reasonably efficient register machine representation can be produced from a - * stack machine source bytecode.<p> - * - * <h2>Key Classes</h2> - * - * <h3>Classes related to conversion and lifetime</h3> - * <ul> - * <li> {@link Optimizer} is a singleton class containing methods for - * converting, optimizing, and then back-converting Rop-form methods. It's the - * typical gateway into the rest of the package. - * <li> {@link SsaConverter} converts a Rop-form method to SSA form. - * <li> {@link SsaToRop} converts an SSA-form method back to Rop form. - * </ul> - * - * <h3>Classes related to method representation</h3> - * <ul> - * <li> A {@link SsaMethod} instance represents a method. - * <li> A {@link SsaBasicBlock} instance represents a basic block, whose - * semantics are quite similar to basic blocks in - * {@link com.android.dx.rop Rop form}. - * <li> {@link PhiInsn} instances represent "phi" operators defined in SSA - * literature. They must be the first N instructions in a basic block. - * <li> {@link NormalSsaInsn} instances represent instructions that directly - * correspond to <code>Rop</code> form. - * </ul> - * - * <h3>Classes related to optimization steps</h3> - * <ul> - * <li> {@link MoveParamCombiner} is a simple step that ensures each method - * parameter is represented by at most one SSA register. - * <li> {@link SCCP} is a (partially implemented) sparse-conditional - * constant propogator. - * <li> {@link LiteralOpUpgrader} is a step that attempts to use constant - * information to convert math and comparison instructions into - * constant-bearing "literal ops" in cases where they can be represented in the - * output form (see {@link TranslationAdvice#hasConstantOperation}). - * <li> {@link ConstCollector} is a step that attempts to trade (modest) - * increased register space for decreased instruction count in cases where - * the same constant value is used repeatedly in a single method. - * <li> {@link DeadCodeRemover} is a dead code remover. This phase must - * always be run to remove unused phi instructions. - * </ul> - * - * <h2>SSA Lifetime</h2> - * The representation of a method in SSA form obeys slightly different - * constraints depending upon whether it is in the process of being converted - * into or out of SSA form. - * - * <h3>Conversion into SSA Form</h3> - * - * {@link SsaConverter#convertToSsaMethod} takes a <code>RopMethod</code> and - * returns a fully-converted <code>SsaMethod</code>. The conversion process - * is roughly as follows: - * - * <ol> - * <li> The Rop-form method, its blocks and their instructions are directly - * wrapped in <code>SsaMethod</code>, <code>SsaBasicBlock</code> and - * <code>SsaInsn</code> instances. Nothing else changes. - * <li> Critical control-flow graph edges are {@link SsaConverter#edgeSplit - * split} and new basic blocks inserted as required to meet the constraints - * necessary for the ultimate SSA representation. - * <li> A {@link LocalVariableExtractor} is run to produce a table of - * Rop registers to local variables necessary during phi placement. This - * step could also be done in Rop form and then updated through the preceding - * steps. - * <li> <code>Phi</code> instructions are {link SsaConverter#placePhiFunctions} - * placed in a semi-pruned fashion, which requires computation of {@link - * Dominators dominance graph} and each node's {@link DomFront - * dominance-frontier set}. - * <li> Finally, source and result registers for all instructions are {@link - * SsaRenamer renamed} such that each assignment is given a unique register - * number (register categories or widths, significant in Rop form, do not - * exist in SSA). Move instructions are eliminated except where necessary - * to preserve local variable assignments. - * </ol> - * - */ diff --git a/dx/src/com/android/dx/util/AnnotatedOutput.java b/dx/src/com/android/dx/util/AnnotatedOutput.java deleted file mode 100644 index 0d950414e..000000000 --- a/dx/src/com/android/dx/util/AnnotatedOutput.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.android.dx.util; - -/** - * Interface for a binary output destination that may be augmented - * with textual annotations. - */ -public interface AnnotatedOutput - extends Output { - /** - * Get whether this instance will actually keep annotations. - * - * @return <code>true</code> iff annotations are being kept - */ - public boolean annotates(); - - /** - * Get whether this instance is intended to keep verbose annotations. - * Annotators may use the result of calling this method to inform their - * annotation activity. - * - * @return <code>true</code> iff annotations are to be verbose - */ - public boolean isVerbose(); - - /** - * Add an annotation for the subsequent output. Any previously - * open annotation will be closed by this call, and the new - * annotation marks all subsequent output until another annotation - * call. - * - * @param msg non-null; the annotation message - */ - public void annotate(String msg); - - /** - * Add an annotation for a specified amount of subsequent - * output. Any previously open annotation will be closed by this - * call. If there is already pending annotation from one or more - * previous calls to this method, the new call "consumes" output - * after all the output covered by the previous calls. - * - * @param amt >= 0; the amount of output for this annotation to - * cover - * @param msg non-null; the annotation message - */ - public void annotate(int amt, String msg); - - /** - * End the most recent annotation. Subsequent output will be unannotated, - * until the next call to {@link #annotate}. - */ - public void endAnnotation(); - - /** - * Get the maximum width of the annotated output. This is advisory: - * Implementations of this interface are encouraged to deal with too-wide - * output, but annotaters are encouraged to attempt to avoid exceeding - * the indicated width. - * - * @return >= 1; the maximum width - */ - public int getAnnotationWidth(); -} diff --git a/dx/src/com/android/dx/util/BitIntSet.java b/dx/src/com/android/dx/util/BitIntSet.java deleted file mode 100644 index c8588f8c0..000000000 --- a/dx/src/com/android/dx/util/BitIntSet.java +++ /dev/null @@ -1,151 +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.android.dx.util; - -import java.util.NoSuchElementException; - -/** - * A set of integers, represented by a bit set - */ -public class BitIntSet implements IntSet { - - /** also accessed in ListIntSet */ - int[] bits; - - /** - * Constructs an instance. - * - * @param max the maximum value of ints in this set. - */ - public BitIntSet(int max) { - bits = Bits.makeBitSet(max); - } - - /** @inheritDoc */ - public void add(int value) { - ensureCapacity(value); - Bits.set(bits, value, true); - } - - /** - * Ensures that the bit set has the capacity to represent the given value. - * - * @param value >= 0 value to represent - */ - private void ensureCapacity(int value) { - if (value >= Bits.getMax(bits)) { - int[] newBits = Bits.makeBitSet( - Math.max(value + 1, 2 * Bits.getMax(bits))); - System.arraycopy(bits, 0, newBits, 0, bits.length); - bits = newBits; - } - } - - /** @inheritDoc */ - public void remove(int value) { - if (value < Bits.getMax(bits)) { - Bits.set(bits, value, false); - } - } - - /** @inheritDoc */ - public boolean has(int value) { - return (value < Bits.getMax(bits)) && Bits.get(bits, value); - } - - /** @inheritDoc */ - public void merge(IntSet other) { - if (other instanceof BitIntSet) { - BitIntSet o = (BitIntSet) other; - ensureCapacity(Bits.getMax(o.bits) + 1); - Bits.or(bits, o.bits); - } else if (other instanceof ListIntSet) { - ListIntSet o = (ListIntSet) other; - int sz = o.ints.size(); - - if (sz > 0) { - ensureCapacity(o.ints.get(sz - 1)); - } - for (int i = 0; i < o.ints.size(); i++) { - Bits.set(bits, o.ints.get(i), true); - } - } else { - IntIterator iter = other.iterator(); - while (iter.hasNext()) { - add(iter.next()); - } - } - } - - /** @inheritDoc */ - public int elements() { - return Bits.bitCount(bits); - } - - /** @inheritDoc */ - public IntIterator iterator() { - return new IntIterator() { - private int idx = Bits.findFirst(bits, 0); - - /** @inheritDoc */ - public boolean hasNext() { - return idx >= 0; - } - - /** @inheritDoc */ - public int next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - - int ret = idx; - - idx = Bits.findFirst(bits, idx+1); - - return ret; - } - - /** @inheritDoc */ - public void remove() { - BitIntSet.this.remove(idx); - idx = Bits.findFirst(bits, idx+1); - } - }; - } - - /** @inheritDoc */ - public String toString() { - StringBuilder sb = new StringBuilder(); - - sb.append('{'); - - boolean first = true; - for (int i = Bits.findFirst(bits, 0) - ; i >= 0 - ; i = Bits.findFirst(bits, i + 1)) { - if (!first) { - sb.append(", "); - } - first = false; - sb.append(i); - } - - sb.append('}'); - - return sb.toString(); - } -} diff --git a/dx/src/com/android/dx/util/Bits.java b/dx/src/com/android/dx/util/Bits.java deleted file mode 100644 index 0bc124c89..000000000 --- a/dx/src/com/android/dx/util/Bits.java +++ /dev/null @@ -1,236 +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.android.dx.util; - -/** - * Utilities for treating <code>int[]</code>s as bit sets. - */ -public final class Bits { - /** - * This class is uninstantiable. - */ - private Bits() { - // This space intentionally left blank. - } - - /** - * Constructs a bit set to contain bits up to the given index (exclusive). - * - * @param max >= 0; the maximum bit index (exclusive) - * @return non-null; an appropriately-constructed instance - */ - public static int[] makeBitSet(int max) { - int size = (max + 0x1f) >> 5; - return new int[size]; - } - - /** - * Gets the maximum index (exclusive) for the given bit set. - * - * @param bits non-null; bit set in question - * @return >= 0; the maximum index (exclusive) that may be set - */ - public static int getMax(int[] bits) { - return bits.length * 0x20; - } - - /** - * Gets the value of the bit at the given index. - * - * @param bits non-null; bit set to operate on - * @param idx >= 0, < getMax(set); which bit - * @return the value of the indicated bit - */ - public static boolean get(int[] bits, int idx) { - int arrayIdx = idx >> 5; - int bit = 1 << (idx & 0x1f); - return (bits[arrayIdx] & bit) != 0; - } - - /** - * Sets the given bit to the given value. - * - * @param bits non-null; bit set to operate on - * @param idx >= 0, < getMax(set); which bit - * @param value the new value for the bit - */ - public static void set(int[] bits, int idx, boolean value) { - int arrayIdx = idx >> 5; - int bit = 1 << (idx & 0x1f); - - if (value) { - bits[arrayIdx] |= bit; - } else { - bits[arrayIdx] &= ~bit; - } - } - - /** - * Sets the given bit to <code>true</code>. - * - * @param bits non-null; bit set to operate on - * @param idx >= 0, < getMax(set); which bit - */ - public static void set(int[] bits, int idx) { - int arrayIdx = idx >> 5; - int bit = 1 << (idx & 0x1f); - bits[arrayIdx] |= bit; - } - - /** - * Sets the given bit to <code>false</code>. - * - * @param bits non-null; bit set to operate on - * @param idx >= 0, < getMax(set); which bit - */ - public static void clear(int[] bits, int idx) { - int arrayIdx = idx >> 5; - int bit = 1 << (idx & 0x1f); - bits[arrayIdx] &= ~bit; - } - - /** - * Returns whether or not the given bit set is empty, that is, whether - * no bit is set to <code>true</code>. - * - * @param bits non-null; bit set to operate on - * @return <code>true</code> iff all bits are <code>false</code> - */ - public static boolean isEmpty(int[] bits) { - int len = bits.length; - - for (int i = 0; i < len; i++) { - if (bits[i] != 0) { - return false; - } - } - - return true; - } - - /** - * Gets the number of bits set to <code>true</code> in the given bit set. - * - * @param bits non-null; bit set to operate on - * @return >= 0; the bit count (aka population count) of the set - */ - public static int bitCount(int[] bits) { - int len = bits.length; - int count = 0; - - for (int i = 0; i < len; i++) { - count += Integer.bitCount(bits[i]); - } - - return count; - } - - /** - * Returns whether any bits are set to <code>true</code> in the - * specified range. - * - * @param bits non-null; bit set to operate on - * @param start >= 0; index of the first bit in the range (inclusive) - * @param end >= 0; index of the last bit in the range (exclusive) - * @return <code>true</code> if any bit is set to <code>true</code> in - * the indicated range - */ - public static boolean anyInRange(int[] bits, int start, int end) { - int idx = findFirst(bits, start); - return (idx >= 0) && (idx < end); - } - - /** - * Finds the lowest-order bit set at or after the given index in the - * given bit set. - * - * @param bits non-null; bit set to operate on - * @param idx >= 0; minimum index to return - * @return >= -1; lowest-order bit set at or after <code>idx</code>, - * or <code>-1</code> if there is no appropriate bit index to return - */ - public static int findFirst(int[] bits, int idx) { - int len = bits.length; - int minBit = idx & 0x1f; - - for (int arrayIdx = idx >> 5; arrayIdx < len; arrayIdx++) { - int word = bits[arrayIdx]; - if (word != 0) { - int bitIdx = findFirst(word, minBit); - if (bitIdx >= 0) { - return (arrayIdx << 5) + bitIdx; - } - } - minBit = 0; - } - - return -1; - } - - /** - * Finds the lowest-order bit set at or after the given index in the - * given <code>int</code>. - * - * @param value the value in question - * @param idx 0..31 the minimum bit index to return - * @return >= -1; lowest-order bit set at or after <code>idx</code>, - * or <code>-1</code> if there is no appropriate bit index to return - */ - public static int findFirst(int value, int idx) { - value &= ~((1 << idx) - 1); // Mask off too-low bits. - int result = Integer.numberOfTrailingZeros(value); - return (result == 32) ? -1 : result; - } - - /** - * Ors bit array <code>b</code> into bit array <code>a</code>. - * <code>a.length</code> must be greater than or equal to - * <code>b.length</code>. - * - * @param a non-null; int array to be ored with other argument. This - * argument is modified. - * @param b non-null; int array to be ored into <code>a</code>. This - * argument is not modified. - */ - public static void or(int[] a, int[] b) { - for (int i = 0; i < b.length; i++) { - a[i] |= b[i]; - } - } - - public static String toHuman(int[] bits) { - StringBuilder sb = new StringBuilder(); - - boolean needsComma = false; - - sb.append('{'); - - int bitsLength = 32 * bits.length; - for (int i = 0; i < bitsLength; i++) { - if (Bits.get(bits, i)) { - if (needsComma) { - sb.append(','); - } - needsComma = true; - sb.append(i); - } - } - sb.append('}'); - - return sb.toString(); - } -} diff --git a/dx/src/com/android/dx/util/ByteArray.java b/dx/src/com/android/dx/util/ByteArray.java deleted file mode 100644 index 3fcf29362..000000000 --- a/dx/src/com/android/dx/util/ByteArray.java +++ /dev/null @@ -1,379 +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.android.dx.util; - -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Wrapper for a <code>byte[]</code>, which provides read-only access and - * can "reveal" a partial slice of the underlying array. - * - * <b>Note:</b> Multibyte accessors all use big-endian order. - */ -public final class ByteArray { - /** non-null; underlying array */ - private final byte[] bytes; - - /** <code>>= 0</code>; start index of the slice (inclusive) */ - private final int start; - - /** <code>>= 0, <= bytes.length</code>; size computed as - * <code>end - start</code> (in the constructor) */ - private final int size; - - /** - * Constructs an instance. - * - * @param bytes non-null; the underlying array - * @param start <code>>= 0</code>; start index of the slice (inclusive) - * @param end <code>>= start, <= bytes.length</code>; end index of - * the slice (exclusive) - */ - public ByteArray(byte[] bytes, int start, int end) { - if (bytes == null) { - throw new NullPointerException("bytes == null"); - } - - if (start < 0) { - throw new IllegalArgumentException("start < 0"); - } - - if (end < start) { - throw new IllegalArgumentException("end < start"); - } - - if (end > bytes.length) { - throw new IllegalArgumentException("end > bytes.length"); - } - - this.bytes = bytes; - this.start = start; - this.size = end - start; - } - - /** - * Constructs an instance from an entire <code>byte[]</code>. - * - * @param bytes non-null; the underlying array - */ - public ByteArray(byte[] bytes) { - this(bytes, 0, bytes.length); - } - - /** - * Gets the size of the array, in bytes. - * - * @return >= 0; the size - */ - public int size() { - return size; - } - - /** - * Returns a slice (that is, a sub-array) of this instance. - * - * @param start <code>>= 0</code>; start index of the slice (inclusive) - * @param end <code>>= start, <= size()</code>; end index of - * the slice (exclusive) - * @return non-null; the slice - */ - public ByteArray slice(int start, int end) { - checkOffsets(start, end); - return new ByteArray(bytes, start + this.start, end + this.start); - } - - /** - * Returns the offset into the given array represented by the given - * offset into this instance. - * - * @param offset offset into this instance - * @param bytes non-null; (alleged) underlying array - * @return corresponding offset into <code>bytes</code> - * @throws IllegalArgumentException thrown if <code>bytes</code> is - * not the underlying array of this instance - */ - public int underlyingOffset(int offset, byte[] bytes) { - if (bytes != this.bytes) { - throw new IllegalArgumentException("wrong bytes"); - } - - return start + offset; - } - - /** - * Gets the <code>signed byte</code> value at a particular offset. - * - * @param off <code>>= 0, < size(); offset to fetch - * @return <code>signed byte</code> at that offset - */ - public int getByte(int off) { - checkOffsets(off, off + 1); - return getByte0(off); - } - - /** - * Gets the <code>signed short</code> value at a particular offset. - * - * @param off <code>>= 0, < (size() - 1); offset to fetch - * @return <code>signed short</code> at that offset - */ - public int getShort(int off) { - checkOffsets(off, off + 2); - return (getByte0(off) << 8) | getUnsignedByte0(off + 1); - } - - /** - * Gets the <code>signed int</code> value at a particular offset. - * - * @param off <code>>= 0, < (size() - 3); offset to fetch - * @return <code>signed int</code> at that offset - */ - public int getInt(int off) { - checkOffsets(off, off + 4); - return (getByte0(off) << 24) | - (getUnsignedByte0(off + 1) << 16) | - (getUnsignedByte0(off + 2) << 8) | - getUnsignedByte0(off + 3); - } - - /** - * Gets the <code>signed long</code> value at a particular offset. - * - * @param off <code>>= 0, < (size() - 7); offset to fetch - * @return <code>signed int</code> at that offset - */ - public long getLong(int off) { - checkOffsets(off, off + 8); - int part1 = (getByte0(off) << 24) | - (getUnsignedByte0(off + 1) << 16) | - (getUnsignedByte0(off + 2) << 8) | - getUnsignedByte0(off + 3); - int part2 = (getByte0(off + 4) << 24) | - (getUnsignedByte0(off + 5) << 16) | - (getUnsignedByte0(off + 6) << 8) | - getUnsignedByte0(off + 7); - - return (part2 & 0xffffffffL) | ((long) part1) << 32; - } - - /** - * Gets the <code>unsigned byte</code> value at a particular offset. - * - * @param off <code>>= 0, < size(); offset to fetch - * @return <code>unsigned byte</code> at that offset - */ - public int getUnsignedByte(int off) { - checkOffsets(off, off + 1); - return getUnsignedByte0(off); - } - - /** - * Gets the <code>unsigned short</code> value at a particular offset. - * - * @param off <code>>= 0, < (size() - 1); offset to fetch - * @return <code>unsigned short</code> at that offset - */ - public int getUnsignedShort(int off) { - checkOffsets(off, off + 2); - return (getUnsignedByte0(off) << 8) | getUnsignedByte0(off + 1); - } - - /** - * Copies the contents of this instance into the given raw - * <code>byte[]</code> at the given offset. The given array must be - * large enough. - * - * @param out non-null; array to hold the output - * @param offset non-null; index into <code>out</code> for the first - * byte of output - */ - public void getBytes(byte[] out, int offset) { - if ((out.length - offset) < size) { - throw new IndexOutOfBoundsException("(out.length - offset) < " + - "size()"); - } - - System.arraycopy(bytes, start, out, offset, size); - } - - /** - * Checks a range of offsets for validity, throwing if invalid. - * - * @param s start offset (inclusive) - * @param e end offset (exclusive) - */ - private void checkOffsets(int s, int e) { - if ((s < 0) || (e < s) || (e > size)) { - throw new IllegalArgumentException("bad range: " + s + ".." + e + - "; actual size " + size); - } - } - - /** - * Gets the <code>signed byte</code> value at the given offset, - * without doing any argument checking. - * - * @param off offset to fetch - * @return byte at that offset - */ - private int getByte0(int off) { - return bytes[start + off]; - } - - /** - * Gets the <code>unsigned byte</code> value at the given offset, - * without doing any argument checking. - * - * @param off offset to fetch - * @return byte at that offset - */ - private int getUnsignedByte0(int off) { - return bytes[start + off] & 0xff; - } - - /** - * Gets a <code>DataInputStream</code> that reads from this instance, - * with the cursor starting at the beginning of this instance's data. - * <b>Note:</b> The returned instance may be cast to {@link #GetCursor} - * if needed. - * - * @return non-null; an appropriately-constructed - * <code>DataInputStream</code> instance - */ - public MyDataInputStream makeDataInputStream() { - return new MyDataInputStream(makeInputStream()); - } - - /** - * Gets a <code>InputStream</code> that reads from this instance, - * with the cursor starting at the beginning of this instance's data. - * <b>Note:</b> The returned instance may be cast to {@link #GetCursor} - * if needed. - * - * @return non-null; an appropriately-constructed - * <code>InputStream</code> instancex - */ - public MyInputStream makeInputStream() { - return new MyInputStream(); - } - - /** - * Helper interface that allows one to get the cursor (of a stream). - */ - public interface GetCursor { - /** - * Gets the current cursor. - * - * @return 0..size(); the cursor - */ - public int getCursor(); - } - - /** - * Helper class for {@link #makeInputStream}, which implements the - * stream functionality. - */ - public class MyInputStream extends InputStream { - /** 0..size; the cursor */ - private int cursor; - - /** 0..size; the mark */ - private int mark; - - public MyInputStream() { - cursor = 0; - mark = 0; - } - - public int read() throws IOException { - if (cursor >= size) { - return -1; - } - - int result = getUnsignedByte0(cursor); - cursor++; - return result; - } - - public int read(byte[] arr, int offset, int length) { - if ((offset + length) > arr.length) { - length = arr.length - offset; - } - - int maxLength = size - cursor; - if (length > maxLength) { - length = maxLength; - } - - System.arraycopy(bytes, cursor, arr, offset, length); - cursor += length; - return length; - } - - public int available() { - return size - cursor; - } - - public void mark(int reserve) { - mark = cursor; - } - - public void reset() { - cursor = mark; - } - - public boolean markSupported() { - return true; - } - - /** - * Gets the current cursor. - * - * @return 0..size(); the cursor - */ - public int getCursor() { - return cursor; - } - } - - /** - * Helper class for {@link #makeDataInputStream}. This is used - * simply so that the cursor of a wrapped {@link #MyInputStream} - * instance may be easily determined. - */ - public class MyDataInputStream extends DataInputStream { - /** non-null; the underlying {@link #MyInputStream} */ - private final MyInputStream wrapped; - - public MyDataInputStream(MyInputStream wrapped) { - super(wrapped); - - this.wrapped = wrapped; - } - - /** - * Gets the current cursor. - * - * @return 0..size(); the cursor - */ - public int getCursor() { - return wrapped.getCursor(); - } - } -} diff --git a/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java b/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java deleted file mode 100644 index 457a603c5..000000000 --- a/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java +++ /dev/null @@ -1,639 +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.android.dx.util; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; - -/** - * Implementation of {@link AnnotatedOutput} which stores the written data - * into a <code>byte[]</code>. - * - * <p><b>Note:</b> As per the {@link Output} interface, multi-byte - * writes all use little-endian order.</p> - */ -public final class ByteArrayAnnotatedOutput - implements AnnotatedOutput { - /** default size for stretchy instances */ - private static final int DEFAULT_SIZE = 1000; - - /** - * whether the instance is stretchy, that is, whether its array - * may be resized to increase capacity - */ - private final boolean stretchy; - - /** non-null; the data itself */ - private byte[] data; - - /** >= 0; current output cursor */ - private int cursor; - - /** whether annotations are to be verbose */ - private boolean verbose; - - /** - * null-ok; list of annotations, or <code>null</code> if this instance - * isn't keeping them - */ - private ArrayList<Annotation> annotations; - - /** >= 40 (if used); the desired maximum annotation width */ - private int annotationWidth; - - /** - * >= 8 (if used); the number of bytes of hex output to use - * in annotations - */ - private int hexCols; - - /** - * Constructs an instance with a fixed maximum size. Note that the - * given array is the only one that will be used to store data. In - * particular, no reallocation will occur in order to expand the - * capacity of the resulting instance. Also, the constructed - * instance does not keep annotations by default. - * - * @param data non-null; data array to use for output - */ - public ByteArrayAnnotatedOutput(byte[] data) { - this(data, false); - } - - /** - * Constructs a "stretchy" instance. The underlying array may be - * reallocated. The constructed instance does not keep annotations - * by default. - */ - public ByteArrayAnnotatedOutput() { - this(new byte[DEFAULT_SIZE], true); - } - - /** - * Internal constructor. - * - * @param data non-null; data array to use for output - * @param stretchy whether the instance is to be stretchy - */ - private ByteArrayAnnotatedOutput(byte[] data, boolean stretchy) { - if (data == null) { - throw new NullPointerException("data == null"); - } - - this.stretchy = stretchy; - this.data = data; - this.cursor = 0; - this.verbose = false; - this.annotations = null; - this.annotationWidth = 0; - this.hexCols = 0; - } - - /** - * Gets the underlying <code>byte[]</code> of this instance, which - * may be larger than the number of bytes written - * - * @see #toByteArray - * - * @return non-null; the <code>byte[]</code> - */ - public byte[] getArray() { - return data; - } - - /** - * Constructs and returns a new <code>byte[]</code> that contains - * the written contents exactly (that is, with no extra unwritten - * bytes at the end). - * - * @see #getArray - * - * @return non-null; an appropriately-constructed array - */ - public byte[] toByteArray() { - byte[] result = new byte[cursor]; - System.arraycopy(data, 0, result, 0, cursor); - return result; - } - - /** {@inheritDoc} */ - public int getCursor() { - return cursor; - } - - /** {@inheritDoc} */ - public void assertCursor(int expectedCursor) { - if (cursor != expectedCursor) { - throw new ExceptionWithContext("expected cursor " + - expectedCursor + "; actual value: " + cursor); - } - } - - /** {@inheritDoc} */ - public void writeByte(int value) { - int writeAt = cursor; - int end = writeAt + 1; - - if (stretchy) { - ensureCapacity(end); - } else if (end > data.length) { - throwBounds(); - return; - } - - data[writeAt] = (byte) value; - cursor = end; - } - - /** {@inheritDoc} */ - public void writeShort(int value) { - int writeAt = cursor; - int end = writeAt + 2; - - if (stretchy) { - ensureCapacity(end); - } else if (end > data.length) { - throwBounds(); - return; - } - - data[writeAt] = (byte) value; - data[writeAt + 1] = (byte) (value >> 8); - cursor = end; - } - - /** {@inheritDoc} */ - public void writeInt(int value) { - int writeAt = cursor; - int end = writeAt + 4; - - if (stretchy) { - ensureCapacity(end); - } else if (end > data.length) { - throwBounds(); - return; - } - - data[writeAt] = (byte) value; - data[writeAt + 1] = (byte) (value >> 8); - data[writeAt + 2] = (byte) (value >> 16); - data[writeAt + 3] = (byte) (value >> 24); - cursor = end; - } - - /** {@inheritDoc} */ - public void writeLong(long value) { - int writeAt = cursor; - int end = writeAt + 8; - - if (stretchy) { - ensureCapacity(end); - } else if (end > data.length) { - throwBounds(); - return; - } - - int half = (int) value; - data[writeAt] = (byte) half; - data[writeAt + 1] = (byte) (half >> 8); - data[writeAt + 2] = (byte) (half >> 16); - data[writeAt + 3] = (byte) (half >> 24); - - half = (int) (value >> 32); - data[writeAt + 4] = (byte) half; - data[writeAt + 5] = (byte) (half >> 8); - data[writeAt + 6] = (byte) (half >> 16); - data[writeAt + 7] = (byte) (half >> 24); - - cursor = end; - } - - /** {@inheritDoc} */ - public int writeUnsignedLeb128(int value) { - int remaining = value >> 7; - int count = 0; - - while (remaining != 0) { - writeByte((value & 0x7f) | 0x80); - value = remaining; - remaining >>= 7; - count++; - } - - writeByte(value & 0x7f); - return count + 1; - } - - /** {@inheritDoc} */ - public int writeSignedLeb128(int value) { - int remaining = value >> 7; - int count = 0; - boolean hasMore = true; - int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1; - - while (hasMore) { - hasMore = (remaining != end) - || ((remaining & 1) != ((value >> 6) & 1)); - - writeByte((value & 0x7f) | (hasMore ? 0x80 : 0)); - value = remaining; - remaining >>= 7; - count++; - } - - return count; - } - - /** {@inheritDoc} */ - public void write(ByteArray bytes) { - int blen = bytes.size(); - int writeAt = cursor; - int end = writeAt + blen; - - if (stretchy) { - ensureCapacity(end); - } else if (end > data.length) { - throwBounds(); - return; - } - - bytes.getBytes(data, writeAt); - cursor = end; - } - - /** {@inheritDoc} */ - public void write(byte[] bytes, int offset, int length) { - int writeAt = cursor; - int end = writeAt + length; - int bytesEnd = offset + length; - - // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0) - if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) { - throw new IndexOutOfBoundsException("bytes.length " + - bytes.length + "; " + - offset + "..!" + end); - } - - if (stretchy) { - ensureCapacity(end); - } else if (end > data.length) { - throwBounds(); - return; - } - - System.arraycopy(bytes, offset, data, writeAt, length); - cursor = end; - } - - /** {@inheritDoc} */ - public void write(byte[] bytes) { - write(bytes, 0, bytes.length); - } - - /** {@inheritDoc} */ - public void writeZeroes(int count) { - if (count < 0) { - throw new IllegalArgumentException("count < 0"); - } - - int end = cursor + count; - - if (stretchy) { - ensureCapacity(end); - } else if (end > data.length) { - throwBounds(); - return; - } - - /* - * There is no need to actually write zeroes, since the array is - * already preinitialized with zeroes. - */ - - cursor = end; - } - - /** {@inheritDoc} */ - public void alignTo(int alignment) { - int mask = alignment - 1; - - if ((alignment < 0) || ((mask & alignment) != 0)) { - throw new IllegalArgumentException("bogus alignment"); - } - - int end = (cursor + mask) & ~mask; - - if (stretchy) { - ensureCapacity(end); - } else if (end > data.length) { - throwBounds(); - return; - } - - /* - * There is no need to actually write zeroes, since the array is - * already preinitialized with zeroes. - */ - - cursor = end; - } - - /** {@inheritDoc} */ - public boolean annotates() { - return (annotations != null); - } - - /** {@inheritDoc} */ - public boolean isVerbose() { - return verbose; - } - - /** {@inheritDoc} */ - public void annotate(String msg) { - if (annotations == null) { - return; - } - - endAnnotation(); - annotations.add(new Annotation(cursor, msg)); - } - - /** {@inheritDoc} */ - public void annotate(int amt, String msg) { - if (annotations == null) { - return; - } - - endAnnotation(); - - int asz = annotations.size(); - int lastEnd = (asz == 0) ? 0 : annotations.get(asz - 1).getEnd(); - int startAt; - - if (lastEnd <= cursor) { - startAt = cursor; - } else { - startAt = lastEnd; - } - - annotations.add(new Annotation(startAt, startAt + amt, msg)); - } - - /** {@inheritDoc} */ - public void endAnnotation() { - if (annotations == null) { - return; - } - - int sz = annotations.size(); - - if (sz != 0) { - annotations.get(sz - 1).setEndIfUnset(cursor); - } - } - - /** {@inheritDoc} */ - public int getAnnotationWidth() { - int leftWidth = 8 + (hexCols * 2) + (hexCols / 2); - - return annotationWidth - leftWidth; - } - - /** - * Indicates that this instance should keep annotations. This method may - * be called only once per instance, and only before any data has been - * written to the it. - * - * @param annotationWidth >= 40; the desired maximum annotation width - * @param verbose whether or not to indicate verbose annotations - */ - public void enableAnnotations(int annotationWidth, boolean verbose) { - if ((annotations != null) || (cursor != 0)) { - throw new RuntimeException("cannot enable annotations"); - } - - if (annotationWidth < 40) { - throw new IllegalArgumentException("annotationWidth < 40"); - } - - int hexCols = (((annotationWidth - 7) / 15) + 1) & ~1; - if (hexCols < 6) { - hexCols = 6; - } else if (hexCols > 10) { - hexCols = 10; - } - - this.annotations = new ArrayList<Annotation>(1000); - this.annotationWidth = annotationWidth; - this.hexCols = hexCols; - this.verbose = verbose; - } - - /** - * Finishes up annotation processing. This closes off any open - * annotations and removes annotations that don't refer to written - * data. - */ - public void finishAnnotating() { - // Close off the final annotation, if any. - endAnnotation(); - - // Remove annotations that refer to unwritten data. - if (annotations != null) { - int asz = annotations.size(); - while (asz > 0) { - Annotation last = annotations.get(asz - 1); - if (last.getStart() > cursor) { - annotations.remove(asz - 1); - asz--; - } else if (last.getEnd() > cursor) { - last.setEnd(cursor); - break; - } else { - break; - } - } - } - } - - /** - * Writes the annotated content of this instance to the given writer. - * - * @param out non-null; where to write to - */ - public void writeAnnotationsTo(Writer out) throws IOException { - int width2 = getAnnotationWidth(); - int width1 = annotationWidth - width2 - 1; - - TwoColumnOutput twoc = new TwoColumnOutput(out, width1, width2, "|"); - Writer left = twoc.getLeft(); - Writer right = twoc.getRight(); - int leftAt = 0; // left-hand byte output cursor - int rightAt = 0; // right-hand annotation index - int rightSz = annotations.size(); - - while ((leftAt < cursor) && (rightAt < rightSz)) { - Annotation a = annotations.get(rightAt); - int start = a.getStart(); - int end; - String text; - - if (leftAt < start) { - // This is an area with no annotation. - end = start; - start = leftAt; - text = ""; - } else { - // This is an area with an annotation. - end = a.getEnd(); - text = a.getText(); - rightAt++; - } - - left.write(Hex.dump(data, start, end - start, start, hexCols, 6)); - right.write(text); - twoc.flush(); - leftAt = end; - } - - if (leftAt < cursor) { - // There is unannotated output at the end. - left.write(Hex.dump(data, leftAt, cursor - leftAt, leftAt, - hexCols, 6)); - } - - while (rightAt < rightSz) { - // There are zero-byte annotations at the end. - right.write(annotations.get(rightAt).getText()); - rightAt++; - } - - twoc.flush(); - } - - /** - * Throws the excpetion for when an attempt is made to write past the - * end of the instance. - */ - private static void throwBounds() { - throw new IndexOutOfBoundsException("attempt to write past the end"); - } - - /** - * Reallocates the underlying array if necessary. Calls to this method - * should be guarded by a test of {@link #stretchy}. - * - * @param desiredSize >= 0; the desired minimum total size of the array - */ - private void ensureCapacity(int desiredSize) { - if (data.length < desiredSize) { - byte[] newData = new byte[desiredSize * 2 + 1000]; - System.arraycopy(data, 0, newData, 0, cursor); - data = newData; - } - } - - /** - * Annotation on output. - */ - private static class Annotation { - /** >= 0; start of annotated range (inclusive) */ - private final int start; - - /** - * >= 0; end of annotated range (exclusive); - * <code>Integer.MAX_VALUE</code> if unclosed - */ - private int end; - - /** non-null; annotation text */ - private final String text; - - /** - * Constructs an instance. - * - * @param start >= 0; start of annotated range - * @param end >= start; end of annotated range (exclusive) or - * <code>Integer.MAX_VALUE</code> if unclosed - * @param text non-null; annotation text - */ - public Annotation(int start, int end, String text) { - this.start = start; - this.end = end; - this.text = text; - } - - /** - * Constructs an instance. It is initally unclosed. - * - * @param start >= 0; start of annotated range - * @param text non-null; annotation text - */ - public Annotation(int start, String text) { - this(start, Integer.MAX_VALUE, text); - } - - /** - * Sets the end as given, but only if the instance is unclosed; - * otherwise, do nothing. - * - * @param end >= start; the end - */ - public void setEndIfUnset(int end) { - if (this.end == Integer.MAX_VALUE) { - this.end = end; - } - } - - /** - * Sets the end as given. - * - * @param end >= start; the end - */ - public void setEnd(int end) { - this.end = end; - } - - /** - * Gets the start. - * - * @return the start - */ - public int getStart() { - return start; - } - - /** - * Gets the end. - * - * @return the end - */ - public int getEnd() { - return end; - } - - /** - * Gets the text. - * - * @return non-null; the text - */ - public String getText() { - return text; - } - } -} diff --git a/dx/src/com/android/dx/util/ExceptionWithContext.java b/dx/src/com/android/dx/util/ExceptionWithContext.java deleted file mode 100644 index 035546ed9..000000000 --- a/dx/src/com/android/dx/util/ExceptionWithContext.java +++ /dev/null @@ -1,149 +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.android.dx.util; - -import java.io.PrintStream; -import java.io.PrintWriter; - -/** - * Exception which carries around structured context. - */ -public class ExceptionWithContext - extends RuntimeException { - /** 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 non-null; the exception to augment - * @param str non-null; context to add - * @return 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 null-ok; exception that caused this one - */ - public ExceptionWithContext(Throwable cause) { - this(null, cause); - } - - /** - * Constructs an instance. - * - * @param message human-oriented message - * @param cause 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 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 non-null; the context - */ - public String getContext() { - return context.toString(); - } - - /** - * Prints the message and context. - * - * @param out non-null; where to print to - */ - public void printContext(PrintStream out) { - out.println(getMessage()); - out.print(context); - } - - /** - * Prints the message and context. - * - * @param out non-null; where to print to - */ - public void printContext(PrintWriter out) { - out.println(getMessage()); - out.print(context); - } -} diff --git a/dx/src/com/android/dx/util/FileUtils.java b/dx/src/com/android/dx/util/FileUtils.java deleted file mode 100644 index 07a7c7e8d..000000000 --- a/dx/src/com/android/dx/util/FileUtils.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.android.dx.util; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; - -/** - * File I/O utilities. - */ -public final class FileUtils { - /** - * This class is uninstantiable. - */ - private FileUtils() { - // This space intentionally left blank. - } - - /** - * Reads the named file, translating {@link IOException} to a - * {@link RuntimeException} of some sort. - * - * @param fileName non-null; name of the file to read - * @return 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 non-null; the file to read - * @return 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; - } -} diff --git a/dx/src/com/android/dx/util/FixedSizeList.java b/dx/src/com/android/dx/util/FixedSizeList.java deleted file mode 100644 index 7b7d32521..000000000 --- a/dx/src/com/android/dx/util/FixedSizeList.java +++ /dev/null @@ -1,276 +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.android.dx.util; - -import java.util.Arrays; - -/** - * Simple (mostly) fixed-size list of objects, which may be made immutable. - */ -public class FixedSizeList - extends MutabilityControl implements ToHuman { - /** non-null; array of elements */ - private Object[] arr; - - /** - * Constructs an instance. All indices initially contain <code>null</code>. - * - * @param size the size of the list - */ - public FixedSizeList(int size) { - super(size != 0); - - try { - arr = new Object[size]; - } catch (NegativeArraySizeException ex) { - // Translate the exception. - throw new IllegalArgumentException("size < 0"); - } - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (this == other) { - // Easy out. - return true; - } - - if ((other == null) || (getClass() != other.getClass())) { - // Another easy out. - return false; - } - - FixedSizeList list = (FixedSizeList) other; - return Arrays.equals(arr, list.arr); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return Arrays.hashCode(arr); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - String name = getClass().getName(); - - return toString0(name.substring(name.lastIndexOf('.') + 1) + '{', - ", ", - "}", - false); - } - - /** - * {@inheritDoc} - * - * This method will only work if every element of the list - * implements {@link ToHuman}. - */ - public String toHuman() { - String name = getClass().getName(); - - return toString0(name.substring(name.lastIndexOf('.') + 1) + '{', - ", ", - "}", - true); - } - - /** - * Gets a customized string form for this instance. - * - * @param prefix null-ok; prefix for the start of the result - * @param separator null-ok; separator to insert between each item - * @param suffix null-ok; suffix for the end of the result - * @return non-null; the custom string - */ - public String toString(String prefix, String separator, String suffix) { - return toString0(prefix, separator, suffix, false); - } - - /** - * Gets a customized human string for this instance. This method will - * only work if every element of the list implements {@link - * ToHuman}. - * - * @param prefix null-ok; prefix for the start of the result - * @param separator null-ok; separator to insert between each item - * @param suffix null-ok; suffix for the end of the result - * @return non-null; the custom string - */ - public String toHuman(String prefix, String separator, String suffix) { - return toString0(prefix, separator, suffix, true); - } - - /** - * Gets the number of elements in this list. - */ - public final int size() { - return arr.length; - } - - /** - * Shrinks this instance to fit, by removing any unset - * (<code>null</code>) elements, leaving the remaining elements in - * their original order. - */ - public void shrinkToFit() { - int sz = arr.length; - int newSz = 0; - - for (int i = 0; i < sz; i++) { - if (arr[i] != null) { - newSz++; - } - } - - if (sz == newSz) { - return; - } - - throwIfImmutable(); - - Object[] newa = new Object[newSz]; - int at = 0; - - for (int i = 0; i < sz; i++) { - Object one = arr[i]; - if (one != null) { - newa[at] = one; - at++; - } - } - - arr = newa; - if (newSz == 0) { - setImmutable(); - } - } - - /** - * 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</code>. This method is - * protected so that subclasses may offer a safe type-checked - * public interface to their clients. - * - * @param n >= 0, < size(); which element - * @return non-null; the indicated element - */ - protected final Object get0(int n) { - try { - Object result = arr[n]; - - if (result == null) { - throw new NullPointerException("unset: " + n); - } - - return result; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - return throwIndex(n); - } - } - - /** - * Gets the indicated element, allowing <code>null</code>s to be - * returned. This method is protected so that subclasses may - * (optionally) offer a safe type-checked public interface to - * their clients. - * - * @param n >= 0, < size(); which element - * @return null-ok; the indicated element - */ - protected final Object getOrNull0(int n) { - return arr[n]; - } - - /** - * Sets the element at the given index, but without doing any type - * checks on the element. This method is protected so that - * subclasses may offer a safe type-checked public interface to - * their clients. - * - * @param n >= 0, < size(); which element - * @param obj null-ok; the value to store - */ - protected final void set0(int n, Object obj) { - throwIfImmutable(); - - try { - arr[n] = obj; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - throwIndex(n); - } - } - - /** - * Throws the appropriate exception for the given index value. - * - * @param n the index value - * @return never - * @throws IndexOutOfBoundsException always thrown - */ - private Object throwIndex(int n) { - if (n < 0) { - throw new IndexOutOfBoundsException("n < 0"); - } - - throw new IndexOutOfBoundsException("n >= size()"); - } - - /** - * Helper for {@link #toString} and {@link #toHuman}, which both of - * those call to pretty much do everything. - * - * @param prefix null-ok; prefix for the start of the result - * @param separator null-ok; separator to insert between each item - * @param suffix null-ok; suffix for the end of the result - * @param human whether the output is to be human - * @return non-null; the custom string - */ - private String toString0(String prefix, String separator, String suffix, - boolean human) { - int len = arr.length; - StringBuffer sb = new StringBuffer(len * 10 + 10); - - if (prefix != null) { - sb.append(prefix); - } - - for (int i = 0; i < len; i++) { - if ((i != 0) && (separator != null)) { - sb.append(separator); - } - - if (human) { - sb.append(((ToHuman) arr[i]).toHuman()); - } else { - sb.append(arr[i]); - } - } - - if (suffix != null) { - sb.append(suffix); - } - - return sb.toString(); - } - -} diff --git a/dx/src/com/android/dx/util/Hex.java b/dx/src/com/android/dx/util/Hex.java deleted file mode 100644 index cf4c130d2..000000000 --- a/dx/src/com/android/dx/util/Hex.java +++ /dev/null @@ -1,303 +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.android.dx.util; - -/** - * Utilities for formatting numbers as hexadecimal. - */ -public final class Hex { - /** - * This class is uninstantiable. - */ - private Hex() { - // This space intentionally left blank. - } - - /** - * Formats a <code>long</code> as an 8-byte unsigned hex value. - * - * @param v value to format - * @return non-null; formatted form - */ - public static String u8(long v) { - char[] result = new char[16]; - for (int i = 0; i < 16; i++) { - result[15 - i] = Character.forDigit((int) v & 0x0f, 16); - v >>= 4; - } - - return new String(result); - } - - /** - * Formats an <code>int</code> as a 4-byte unsigned hex value. - * - * @param v value to format - * @return non-null; formatted form - */ - public static String u4(int v) { - char[] result = new char[8]; - for (int i = 0; i < 8; i++) { - result[7 - i] = Character.forDigit(v & 0x0f, 16); - v >>= 4; - } - - return new String(result); - } - - /** - * Formats an <code>int</code> as a 3-byte unsigned hex value. - * - * @param v value to format - * @return non-null; formatted form - */ - public static String u3(int v) { - char[] result = new char[6]; - for (int i = 0; i < 6; i++) { - result[5 - i] = Character.forDigit(v & 0x0f, 16); - v >>= 4; - } - - return new String(result); - } - - /** - * Formats an <code>int</code> as a 2-byte unsigned hex value. - * - * @param v value to format - * @return non-null; formatted form - */ - public static String u2(int v) { - char[] result = new char[4]; - for (int i = 0; i < 4; i++) { - result[3 - i] = Character.forDigit(v & 0x0f, 16); - v >>= 4; - } - - return new String(result); - } - - /** - * Formats an <code>int</code> as either a 2-byte unsigned hex value - * (if the value is small enough) or a 4-byte unsigned hex value (if - * not). - * - * @param v value to format - * @return non-null; formatted form - */ - public static String u2or4(int v) { - if (v == (char) v) { - return u2(v); - } else { - return u4(v); - } - } - - /** - * Formats an <code>int</code> as a 1-byte unsigned hex value. - * - * @param v value to format - * @return non-null; formatted form - */ - public static String u1(int v) { - char[] result = new char[2]; - for (int i = 0; i < 2; i++) { - result[1 - i] = Character.forDigit(v & 0x0f, 16); - v >>= 4; - } - - return new String(result); - } - - /** - * Formats an <code>int</code> as a 4-bit unsigned hex nibble. - * - * @param v value to format - * @return non-null; formatted form - */ - public static String uNibble(int v) { - char[] result = new char[1]; - - result[0] = Character.forDigit(v & 0x0f, 16); - return new String(result); - } - - /** - * Formats a <code>long</code> as an 8-byte signed hex value. - * - * @param v value to format - * @return non-null; formatted form - */ - public static String s8(long v) { - char[] result = new char[17]; - - if (v < 0) { - result[0] = '-'; - v = -v; - } else { - result[0] = '+'; - } - - for (int i = 0; i < 16; i++) { - result[16 - i] = Character.forDigit((int) v & 0x0f, 16); - v >>= 4; - } - - return new String(result); - } - - /** - * Formats an <code>int</code> as a 4-byte signed hex value. - * - * @param v value to format - * @return non-null; formatted form - */ - public static String s4(int v) { - char[] result = new char[9]; - - if (v < 0) { - result[0] = '-'; - v = -v; - } else { - result[0] = '+'; - } - - for (int i = 0; i < 8; i++) { - result[8 - i] = Character.forDigit(v & 0x0f, 16); - v >>= 4; - } - - return new String(result); - } - - /** - * Formats an <code>int</code> as a 2-byte signed hex value. - * - * @param v value to format - * @return non-null; formatted form - */ - public static String s2(int v) { - char[] result = new char[5]; - - if (v < 0) { - result[0] = '-'; - v = -v; - } else { - result[0] = '+'; - } - - for (int i = 0; i < 4; i++) { - result[4 - i] = Character.forDigit(v & 0x0f, 16); - v >>= 4; - } - - return new String(result); - } - - /** - * Formats an <code>int</code> as a 1-byte signed hex value. - * - * @param v value to format - * @return non-null; formatted form - */ - public static String s1(int v) { - char[] result = new char[3]; - - if (v < 0) { - result[0] = '-'; - v = -v; - } else { - result[0] = '+'; - } - - for (int i = 0; i < 2; i++) { - result[2 - i] = Character.forDigit(v & 0x0f, 16); - v >>= 4; - } - - return new String(result); - } - - /** - * Formats a hex dump of a portion of a <code>byte[]</code>. The result - * is always newline-terminated, unless the passed-in length was zero, - * in which case the result is always the empty string (<code>""</code>). - * - * @param arr non-null; array to format - * @param offset >= 0; offset to the part to dump - * @param length >= 0; number of bytes to dump - * @param outOffset >= 0; first output offset to print - * @param bpl >= 0; number of bytes of output per line - * @param addressLength {2,4,6,8}; number of characters for each address - * header - * @return non-null; a string of the dump - */ - public static String dump(byte[] arr, int offset, int length, - int outOffset, int bpl, int addressLength) { - int end = offset + length; - - // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0) - if (((offset | length | end) < 0) || (end > arr.length)) { - throw new IndexOutOfBoundsException("arr.length " + - arr.length + "; " + - offset + "..!" + end); - } - - if (outOffset < 0) { - throw new IllegalArgumentException("outOffset < 0"); - } - - if (length == 0) { - return ""; - } - - StringBuffer sb = new StringBuffer(length * 4 + 6); - boolean bol = true; - int col = 0; - - while (length > 0) { - if (col == 0) { - String astr; - switch (addressLength) { - case 2: astr = Hex.u1(outOffset); break; - case 4: astr = Hex.u2(outOffset); break; - case 6: astr = Hex.u3(outOffset); break; - default: astr = Hex.u4(outOffset); break; - } - sb.append(astr); - sb.append(": "); - } else if ((col & 1) == 0) { - sb.append(' '); - } - sb.append(Hex.u1(arr[offset])); - outOffset++; - offset++; - col++; - if (col == bpl) { - sb.append('\n'); - col = 0; - } - length--; - } - - if (col != 0) { - sb.append('\n'); - } - - return sb.toString(); - } -} diff --git a/dx/src/com/android/dx/util/HexParser.java b/dx/src/com/android/dx/util/HexParser.java deleted file mode 100644 index 4b6b7b2f7..000000000 --- a/dx/src/com/android/dx/util/HexParser.java +++ /dev/null @@ -1,145 +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.android.dx.util; - -/** - * Utilities for parsing hexadecimal text. - */ -public final class HexParser { - /** - * This class is uninstantiable. - */ - private HexParser() { - // This space intentionally left blank. - } - - /** - * Parses the given text as hex, returning a <code>byte[]</code> - * corresponding to the text. The format is simple: Each line may - * start with a hex offset followed by a colon (which is verified - * and presumably used just as a comment), and then consists of - * hex digits freely interspersed with whitespace. If a pound sign - * is encountered, it and the rest of the line are ignored as a - * comment. If a double quote is encountered, then the ASCII value - * of the subsequent characters is used, until the next double - * quote. Quoted strings may not span multiple lines. - * - * @param src non-null; the source string - * @return non-null; the parsed form - */ - public static byte[] parse(String src) { - int len = src.length(); - byte[] result = new byte[len / 2]; - int at = 0; - int outAt = 0; - - while (at < len) { - int nlAt = src.indexOf('\n', at); - if (nlAt < 0) { - nlAt = len; - } - int poundAt = src.indexOf('#', at); - - String line; - if ((poundAt >= 0) && (poundAt < nlAt)) { - line = src.substring(at, poundAt); - } else { - line = src.substring(at, nlAt); - } - at = nlAt + 1; - - int colonAt = line.indexOf(':'); - - atCheck: - if (colonAt != -1) { - int quoteAt = line.indexOf('\"'); - if ((quoteAt != -1) && (quoteAt < colonAt)) { - break atCheck; - } - - String atStr = line.substring(0, colonAt).trim(); - line = line.substring(colonAt + 1); - int alleged = Integer.parseInt(atStr, 16); - if (alleged != outAt) { - throw new RuntimeException("bogus offset marker: " + - atStr); - } - } - - int lineLen = line.length(); - int value = -1; - boolean quoteMode = false; - - for (int i = 0; i < lineLen; i++) { - char c = line.charAt(i); - - if (quoteMode) { - if (c == '\"') { - quoteMode = false; - } else { - result[outAt] = (byte) c; - outAt++; - } - continue; - } - - if (c <= ' ') { - continue; - } - if (c == '\"') { - if (value != -1) { - throw new RuntimeException("spare digit around " + - "offset " + Hex.u4(outAt)); - } - quoteMode = true; - continue; - } - - int digVal = Character.digit(c, 16); - if (digVal == -1) { - throw new RuntimeException("bogus digit character: \"" + - c + "\""); - } - if (value == -1) { - value = digVal; - } else { - result[outAt] = (byte) ((value << 4) | digVal); - outAt++; - value = -1; - } - } - - if (value != -1) { - throw new RuntimeException("spare digit around offset " + - Hex.u4(outAt)); - } - - if (quoteMode) { - throw new RuntimeException("unterminated quote around " + - "offset " + Hex.u4(outAt)); - } - } - - if (outAt < result.length) { - byte[] newr = new byte[outAt]; - System.arraycopy(result, 0, newr, 0, outAt); - result = newr; - } - - return result; - } -} diff --git a/dx/src/com/android/dx/util/IndentingWriter.java b/dx/src/com/android/dx/util/IndentingWriter.java deleted file mode 100644 index db4e0a2ad..000000000 --- a/dx/src/com/android/dx/util/IndentingWriter.java +++ /dev/null @@ -1,169 +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.android.dx.util; - -import java.io.FilterWriter; -import java.io.IOException; -import java.io.Writer; - -/** - * Writer that wraps another writer and passes width-limited and - * optionally-prefixed output to its subordinate. When lines are - * wrapped they are automatically indented based on the start of the - * line. - */ -public final class IndentingWriter extends FilterWriter { - /** null-ok; optional prefix for every line */ - private final String prefix; - - /** > 0; the maximum output width */ - private final int width; - - /** > 0; the maximum indent */ - private final int maxIndent; - - /** >= 0; current output column (zero-based) */ - private int column; - - /** whether indent spaces are currently being collected */ - private boolean collectingIndent; - - /** >= 0; current indent amount */ - private int indent; - - /** - * Constructs an instance. - * - * @param out non-null; writer to send final output to - * @param width >= 0; the maximum output width (not including - * <code>prefix</code>), or <code>0</code> for no maximum - * @param prefix non-null; the prefix for each line - */ - public IndentingWriter(Writer out, int width, String prefix) { - super(out); - - if (out == null) { - throw new NullPointerException("out == null"); - } - - if (width < 0) { - throw new IllegalArgumentException("width < 0"); - } - - if (prefix == null) { - throw new NullPointerException("prefix == null"); - } - - this.width = (width != 0) ? width : Integer.MAX_VALUE; - this.maxIndent = width >> 1; - this.prefix = (prefix.length() == 0) ? null : prefix; - - bol(); - } - - /** - * Constructs a no-prefix instance. - * - * @param out non-null; writer to send final output to - * @param width >= 0; the maximum output width (not including - * <code>prefix</code>), or <code>0</code> for no maximum - */ - public IndentingWriter(Writer out, int width) { - this(out, width, ""); - } - - /** {@inheritDoc} */ - @Override - public void write(int c) throws IOException { - synchronized (lock) { - if (collectingIndent) { - if (c == ' ') { - indent++; - if (indent >= maxIndent) { - indent = maxIndent; - collectingIndent = false; - } - } else { - collectingIndent = false; - } - } - - if ((column == width) && (c != '\n')) { - out.write('\n'); - column = 0; - /* - * Note: No else, so this should fall through to the next - * if statement. - */ - } - - if (column == 0) { - if (prefix != null) { - out.write(prefix); - } - - if (!collectingIndent) { - for (int i = 0; i < indent; i++) { - out.write(' '); - } - column = indent; - } - } - - out.write(c); - - if (c == '\n') { - bol(); - } else { - column++; - } - } - } - - /** {@inheritDoc} */ - @Override - public void write(char[] cbuf, int off, int len) throws IOException { - synchronized (lock) { - while (len > 0) { - write(cbuf[off]); - off++; - len--; - } - } - } - - /** {@inheritDoc} */ - @Override - public void write(String str, int off, int len) throws IOException { - synchronized (lock) { - while (len > 0) { - write(str.charAt(off)); - off++; - len--; - } - } - } - - /** - * Indicates that output is at the beginning of a line. - */ - private void bol() { - column = 0; - collectingIndent = (maxIndent != 0); - indent = 0; - } -} diff --git a/dx/src/com/android/dx/util/IntIterator.java b/dx/src/com/android/dx/util/IntIterator.java deleted file mode 100644 index 88181b52e..000000000 --- a/dx/src/com/android/dx/util/IntIterator.java +++ /dev/null @@ -1,44 +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.android.dx.util; - -/** - * An iterator for a list of ints. - */ -public interface IntIterator { - - /** - * Checks to see if the iterator has a next value. - * - * @return true if next() will succeed - */ - boolean hasNext(); - - /** - * Returns the next value in the iterator. - * - * @return next value - * @throws java.util.NoSuchElementException if no next element exists - */ - int next(); - - /** - * Removes a value from the collection underlying this iterator. - * May throw UnsupportedOperationException(). - */ -// void remove(); -} diff --git a/dx/src/com/android/dx/util/IntList.java b/dx/src/com/android/dx/util/IntList.java deleted file mode 100644 index f60bbb5e2..000000000 --- a/dx/src/com/android/dx/util/IntList.java +++ /dev/null @@ -1,452 +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.android.dx.util; - -import java.util.Arrays; - -/** - * Simple list of <code>int</code>s. - */ -public final class IntList extends MutabilityControl { - /** non-null; immutable, no-element instance */ - public static final IntList EMPTY = new IntList(0); - - /** non-null; array of elements */ - private int[] values; - - /** >= 0; current size of the list */ - private int size; - - /** whether the values are currently sorted */ - private boolean sorted; - - static { - EMPTY.setImmutable(); - } - - /** - * Constructs a new immutable instance with the given element. - * - * @param value the sole value in the list - */ - public static IntList makeImmutable(int value) { - IntList result = new IntList(1); - - result.add(value); - result.setImmutable(); - - return result; - } - - /** - * Constructs a new immutable instance with the given elements. - * - * @param value0 the first value in the list - * @param value1 the second value in the list - */ - public static IntList makeImmutable(int value0, int value1) { - IntList result = new IntList(2); - - result.add(value0); - result.add(value1); - result.setImmutable(); - - return result; - } - - /** - * Constructs an empty instance with a default initial capacity. - */ - public IntList() { - this(4); - } - - /** - * Constructs an empty instance. - * - * @param initialCapacity >= 0; initial capacity of the list - */ - public IntList(int initialCapacity) { - super(true); - - try { - values = new int[initialCapacity]; - } catch (NegativeArraySizeException ex) { - // Translate the exception. - throw new IllegalArgumentException("size < 0"); - } - - size = 0; - sorted = true; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int result = 0; - - for (int i = 0; i < size; i++) { - result = (result * 31) + values[i]; - } - - return result; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (other == this) { - return true; - } - - if (! (other instanceof IntList)) { - return false; - } - - IntList otherList = (IntList) other; - - if (sorted != otherList.sorted) { - return false; - } - - if (size != otherList.size) { - return false; - } - - for (int i = 0; i < size; i++) { - if (values[i] != otherList.values[i]) { - return false; - } - } - - return true; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(size * 5 + 10); - - sb.append('{'); - - for (int i = 0; i < size; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(values[i]); - } - - sb.append('}'); - - return sb.toString(); - } - - /** - * Gets the number of elements in this list. - */ - public int size() { - return size; - } - - /** - * Gets the indicated value. - * - * @param n >= 0, < size(); which element - * @return the indicated element's value - */ - public int get(int n) { - if (n >= size) { - throw new IndexOutOfBoundsException("n >= size()"); - } - - try { - return values[n]; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate exception. - throw new IndexOutOfBoundsException("n < 0"); - } - } - - /** - * Sets the value at the given index. - * - * @param n >= 0, < size(); which element - * @param value value to store - */ - public void set(int n, int value) { - throwIfImmutable(); - - if (n >= size) { - throw new IndexOutOfBoundsException("n >= size()"); - } - - try { - values[n] = value; - sorted = false; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - if (n < 0) { - throw new IllegalArgumentException("n < 0"); - } - } - } - - /** - * Adds an element to the end of the list. This will increase the - * list's capacity if necessary. - * - * @param value the value to add - */ - public void add(int value) { - throwIfImmutable(); - - growIfNeeded(); - - values[size++] = value; - - if (sorted && (size > 1)) { - sorted = (value >= values[size - 2]); - } - } - - /** - * Inserts element into specified index, moving elements at and above - * that index up one. May not be used to insert at an index beyond the - * current size (that is, insertion as a last element is legal but - * no further). - * - * @param n >=0 <=size(); index of where to insert - * @param value value to insert - */ - public void insert(int n, int value) { - if (n > size) { - throw new IndexOutOfBoundsException("n > size()"); - } - - growIfNeeded(); - - System.arraycopy (values, n, values, n+1, size - n); - values[n] = value; - size++; - - sorted = sorted - && (n == 0 || value > values[n-1]) - && (n == (size - 1) || value < values[n+1]); - } - - /** - * Removes an element at a given index, shifting elements at greater - * indicies down one. - * - * @param n >=0 < size(); index of element to remove - */ - public void removeIndex(int n) { - if (n >= size) { - throw new IndexOutOfBoundsException("n >= size()"); - } - - System.arraycopy (values, n + 1, values, n, size - n - 1); - size--; - - // sort status is unchanged - } - - /** - * Increases size of array if needed - */ - private void growIfNeeded() { - if (size == values.length) { - // Resize. - int[] newv = new int[size * 3 / 2 + 10]; - System.arraycopy(values, 0, newv, 0, size); - values = newv; - } - } - - /** - * Returns the last element in the array without modifying the array - * - * @return last value in the array. - * @exception IndexOutOfBoundsException if stack is empty. - */ - public int top() { - return get(size - 1); - } - - /** - * Pops an element off the end of the list and decreasing the size by one. - * - * @return value from what was the last element. - * @exception IndexOutOfBoundsException if stack is empty. - */ - public int pop() { - throwIfImmutable(); - - int result; - - result = get(size-1); - size--; - - return result; - } - - /** - * Pops N elements off the end of the list and decreasing the size by N. - * - * @param n >= 0; number of elements to remove from end. - * @exception IndexOutOfBoundsException if stack is smaller than N - */ - public void pop(int n) { - throwIfImmutable(); - - size -= n; - } - - /** - * Shrinks the size of the list. - * - * @param newSize >= 0; the new size - */ - public void shrink(int newSize) { - if (newSize < 0) { - throw new IllegalArgumentException("newSize < 0"); - } - - if (newSize > size) { - throw new IllegalArgumentException("newSize > size"); - } - - throwIfImmutable(); - - size = newSize; - } - - /** - * Makes and returns a mutable copy of the list. - * - * @return non-null; an appropriately-constructed instance - */ - public IntList mutableCopy() { - int sz = size; - IntList result = new IntList(sz); - - for (int i = 0; i < sz; i++) { - result.add(values[i]); - } - - return result; - } - - /** - * Sorts the elements in the list in-place. - */ - public void sort() { - throwIfImmutable(); - - if (!sorted) { - Arrays.sort(values, 0, size); - sorted = true; - } - } - - /** - * Returns the index of the given value, or -1 if the value does not - * appear in the list. This will do a binary search if the list is - * sorted or a linear search if not. - * @param value value to find - * @return index of value or -1 - */ - public int indexOf(int value) { - int ret = binarysearch(value); - - return ret >= 0 ? ret : -1; - - } - - /** - * Performs a binary search on a sorted list, returning the index of - * the given value if it is present or - * <code>(-(insertion point) - 1)</code> if the value is not present. - * If the list is not sorted, then reverts to linear search and returns - * <code>-size()</code> if the element is not found. - * - * @param value value to find - * @return index of value or <code>(-(insertion point) - 1)</code> if the - * value is not present - */ - public int binarysearch(int value) { - int sz = size; - - if (!sorted) { - // Linear search. - for (int i = 0; i < sz; i++) { - if (values[i] == value) { - return i; - } - } - - return -sz; - } - - /* - * Binary search. This variant does only one value comparison - * per iteration but does one more iteration on average than - * the variant that includes a value equality check per - * iteration. - */ - - int min = -1; - int max = sz; - - while (max > (min + 1)) { - /* - * The guessIdx calculation is equivalent to ((min + max) - * / 2) but won't go wonky when min and max are close to - * Integer.MAX_VALUE. - */ - int guessIdx = min + ((max - min) >> 1); - int guess = values[guessIdx]; - - if (value <= guess) { - max = guessIdx; - } else { - min = guessIdx; - } - } - - if ((max != sz)) { - return (value == values[max]) ? max : (-max - 1); - } else { - return -sz - 1; - } - } - - - /** - * Returns whether or not the given value appears in the list. - * This will do a binary search if the list is sorted or a linear - * search if not. - * - * @see #sort - * - * @param value value to look for - * @return whether the list contains the given value - */ - public boolean contains(int value) { - return indexOf(value) >= 0; - } -} diff --git a/dx/src/com/android/dx/util/IntSet.java b/dx/src/com/android/dx/util/IntSet.java deleted file mode 100644 index 10b6ee047..000000000 --- a/dx/src/com/android/dx/util/IntSet.java +++ /dev/null @@ -1,67 +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.android.dx.util; - -/** - * A set of integers - */ -public interface IntSet { - - /** - * Adds an int to a set - * - * @param value int to add - */ - void add(int value); - - /** - * Removes an int from a set. - * - * @param value int to remove - */ - void remove(int value); - - /** - * Checks to see if a value is in the set - * - * @param value int to check - * @return true if in set - */ - boolean has(int value); - - /** - * Merges <code>other</code> into this set, so this set becomes the - * union of the two. - * - * @param other non-null; other set to merge with. - */ - void merge(IntSet other); - - /** - * Returns the count of unique elements in this set. - * - * @return > = 0; count of unique elements - */ - int elements(); - - /** - * Iterates the set - * - * @return non-null; a set iterator - */ - IntIterator iterator(); -} diff --git a/dx/src/com/android/dx/util/LabeledItem.java b/dx/src/com/android/dx/util/LabeledItem.java deleted file mode 100644 index cc6a0d252..000000000 --- a/dx/src/com/android/dx/util/LabeledItem.java +++ /dev/null @@ -1,30 +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.android.dx.util; - -/** - * An item that has an integer label. - */ -public interface LabeledItem { - - /* - * Gets the label of this block. - * - * @return >= 0; the label - */ - public int getLabel(); -} diff --git a/dx/src/com/android/dx/util/LabeledList.java b/dx/src/com/android/dx/util/LabeledList.java deleted file mode 100644 index 3168a38d0..000000000 --- a/dx/src/com/android/dx/util/LabeledList.java +++ /dev/null @@ -1,161 +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.android.dx.util; - -import com.android.dx.cf.code.ByteBlock; - -/** - * A list of labeled items, allowing easy lookup by label. - */ -public class LabeledList extends FixedSizeList { - - /** - * Sparse array indexed by label to FixedSizeList index. - * -1 = invalid label. - */ - private final IntList labelToIndex; - - /** @inheritDoc */ - public LabeledList(int size) { - super(size); - - labelToIndex = new IntList(size); - } - - /** - * Constructs a new instance that is a copy of the old instance. - * - * @param old instance to copy - */ - protected LabeledList(LabeledList old) { - super(old.size()); - labelToIndex = old.labelToIndex.mutableCopy(); - - int sz = old.size(); - - for (int i = 0; i < sz; i++) { - Object one = old.get0(i); - if (one != null) { - set0(i, one); - } - } - } - - /** - * Gets the maximum label (exclusive) of any block added to this instance. - * - * @return >= 0; the maximum label - */ - public int getMaxLabel() { - int sz = labelToIndex.size(); - - // Gobble any deleted labels that may be at the end... - int i; - for (i = sz - 1; (i >= 0) && (labelToIndex.get(i) < 0); i--) - ; - - int newSize = i+1; - - labelToIndex.shrink(newSize); - - return newSize; - } - - /** - * Removes a label from the label-to-index mapping - * @param oldLabel label to remove - */ - protected void removeLabel(int oldLabel) { - labelToIndex.set(oldLabel, -1); - } - - /** - * Adds a label and index to the label-to-index mapping - * @param label new label - * @param index index of block. - */ - protected void addLabelIndex(int label, int index) { - int origSz = labelToIndex.size(); - - for (int i = 0; i <= (label - origSz); i++) { - labelToIndex.add(-1); - } - - labelToIndex.set(label, index); - } - - /** - * Gets the index of the first item in the list with the given - * label, if any. - * - * @param label >= 0; the label to look for - * @return >= -1; the index of the so-labelled item, or <code>-1</code> - * if none is found - */ - public int indexOfLabel(int label) { - if (label >= labelToIndex.size()) { - return -1; - } else { - return labelToIndex.get(label); - } - } - - /** @inheritDoc */ - @Override - public void shrinkToFit() { - super.shrinkToFit(); - - rebuildLabelToIndex(); - } - - /** - * Rebuilds the label-to-index mapping after a shrinkToFit(). - * Note: assumes that the labels that are in the list are the same - * although the indicies may have changed. - */ - protected void rebuildLabelToIndex() { - int szItems = size(); - - for (int i = 0; i < szItems; i++) { - LabeledItem li = (LabeledItem)get0(i); - - if (li != null) { - labelToIndex.set(li.getLabel(), i); - } - } - } - - /** - * Sets the element at the given index. - * - * @param n >= 0, < size(); which element - * @param item null-ok; the value to store - */ - protected void set(int n, LabeledItem item) { - LabeledItem old = (LabeledItem) getOrNull0(n); - - set0(n, item); - - if (old != null) { - removeLabel(old.getLabel()); - } - - if (item != null) { - addLabelIndex(item.getLabel(), n); - } - } -} diff --git a/dx/src/com/android/dx/util/Leb128Utils.java b/dx/src/com/android/dx/util/Leb128Utils.java deleted file mode 100644 index dfd416f6b..000000000 --- a/dx/src/com/android/dx/util/Leb128Utils.java +++ /dev/null @@ -1,78 +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.android.dx.util; - -/** - * LEB128 (little-endian base 128) utilities. - */ -public final class Leb128Utils { - /** - * This class is uninstantiable. - */ - private Leb128Utils() { - // This space intentionally left blank. - } - - /** - * 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) { - value = remaining; - remaining >>= 7; - count++; - } - - return count + 1; - } - - /** - * Gets the number of bytes in the signed LEB128 encoding of the - * given value. - * - * @param value the value in question - * @return its write size, in bytes - */ - public static int signedLeb128Size(int value) { - // TODO: This could be much cleverer. - - int remaining = value >> 7; - int count = 0; - boolean hasMore = true; - int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1; - - while (hasMore) { - hasMore = (remaining != end) - || ((remaining & 1) != ((value >> 6) & 1)); - - value = remaining; - remaining >>= 7; - count++; - } - - return count; - } -} diff --git a/dx/src/com/android/dx/util/ListIntSet.java b/dx/src/com/android/dx/util/ListIntSet.java deleted file mode 100644 index a9f79afea..000000000 --- a/dx/src/com/android/dx/util/ListIntSet.java +++ /dev/null @@ -1,137 +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.android.dx.util; - -import java.util.NoSuchElementException; - -/** - * A set of integers, represented by a list - */ -public class ListIntSet implements IntSet { - - /** also accessed in BitIntSet */ - final IntList ints; - - /** - * Constructs an instance - */ - public ListIntSet() { - ints = new IntList(); - ints.sort(); - } - - /** @inheritDoc */ - public void add(int value) { - int index = ints.binarysearch(value); - - if (index < 0) { - ints.insert(-(index + 1), value); - } - } - - /** @inheritDoc */ - public void remove(int value) { - int index = ints.indexOf(value); - - if (index >= 0) { - ints.removeIndex(index); - } - } - - /** @inheritDoc */ - public boolean has(int value) { - return ints.indexOf(value) >= 0; - } - - /** @inheritDoc */ - public void merge(IntSet other) { - if (other instanceof ListIntSet) { - ListIntSet o = (ListIntSet) other; - int szThis = ints.size(); - int szOther = o.ints.size(); - - int i = 0; - int j = 0; - - while (j < szOther && i < szThis) { - while (j < szOther && o.ints.get(j) < ints.get(i)) { - add(o.ints.get(j++)); - } - if (j == szOther) { - break; - } - while (i < szThis && o.ints.get(j) >= ints.get(i)) { - i++; - } - } - - while (j < szOther) { - add(o.ints.get(j++)); - } - - ints.sort(); - } else if (other instanceof BitIntSet) { - BitIntSet o = (BitIntSet) other; - - for (int i = 0; i >= 0; i = Bits.findFirst(o.bits, i + 1)) { - ints.add(i); - } - ints.sort(); - } else { - IntIterator iter = other.iterator(); - while (iter.hasNext()) { - add(iter.next()); - } - } - } - - /** @inheritDoc */ - public int elements() { - return ints.size(); - } - - /** @inheritDoc */ - public IntIterator iterator() { - return new IntIterator() { - private int idx = 0; - - /** @inheritDoc */ - public boolean hasNext() { - return idx < ints.size(); - } - - /** @inheritDoc */ - public int next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - - return ints.get(idx++); - } - - /** @inheritDoc */ - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - /** @inheritDoc */ - public String toString() { - return ints.toString(); - } -} diff --git a/dx/src/com/android/dx/util/MutabilityControl.java b/dx/src/com/android/dx/util/MutabilityControl.java deleted file mode 100644 index 8b3383b73..000000000 --- a/dx/src/com/android/dx/util/MutabilityControl.java +++ /dev/null @@ -1,89 +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.android.dx.util; - -/** - * Very simple base class that implements a flag to control the mutability - * of instances. This class just provides the flag and a utility to check - * and throw the right exception, but it is up to subclasses to place calls - * to the checker in all the right places. - */ -public class MutabilityControl { - /** whether this instance is mutable */ - private boolean mutable; - - /** - * Constructs an instance. It is initially mutable. - */ - public MutabilityControl() { - mutable = true; - } - - /** - * Constructs an instance, explicitly indicating the mutability. - * - * @param mutable <code>true</code> iff this instance is mutable - */ - public MutabilityControl(boolean mutable) { - this.mutable = mutable; - } - - /** - * Makes this instance immutable. - */ - public void setImmutable() { - mutable = false; - } - - /** - * Checks to see whether or not this instance is immutable. This is the - * same as calling <code>!isMutable()</code>. - * - * @return <code>true</code> iff this instance is immutable - */ - public final boolean isImmutable() { - return !mutable; - } - - /** - * Checks to see whether or not this instance is mutable. - * - * @return <code>true</code> iff this instance is mutable - */ - public final boolean isMutable() { - return mutable; - } - - /** - * Throws {@link MutabilityException} if this instance is - * immutable. - */ - public final void throwIfImmutable() { - if (!mutable) { - throw new MutabilityException("immutable instance"); - } - } - - /** - * Throws {@link MutabilityException} if this instance is mutable. - */ - public final void throwIfMutable() { - if (mutable) { - throw new MutabilityException("mutable instance"); - } - } -} diff --git a/dx/src/com/android/dx/util/MutabilityException.java b/dx/src/com/android/dx/util/MutabilityException.java deleted file mode 100644 index bd21651b2..000000000 --- a/dx/src/com/android/dx/util/MutabilityException.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.android.dx.util; - -/** - * Exception due to a mutability problem. - */ -public class MutabilityException - extends ExceptionWithContext { - public MutabilityException(String message) { - super(message); - } - - public MutabilityException(Throwable cause) { - super(cause); - } - - public MutabilityException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/dx/src/com/android/dx/util/Output.java b/dx/src/com/android/dx/util/Output.java deleted file mode 100644 index b3c37472b..000000000 --- a/dx/src/com/android/dx/util/Output.java +++ /dev/null @@ -1,129 +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.android.dx.util; - -/** - * Interface for a sink for binary output. This is similar to - * <code>java.util.DataOutput</code>, but no <code>IOExceptions</code> - * are declared, and multibyte output is defined to be little-endian. - */ -public interface Output { - /** - * Gets the current cursor position. This is the same as the number of - * bytes written to this instance. - * - * @return >= 0; the cursor position - */ - public int getCursor(); - - /** - * Asserts that the cursor is the given value. - * - * @param expectedCursor the expected cursor value - * @throws RuntimeException thrown if <code>getCursor() != - * expectedCursor</code> - */ - public void assertCursor(int expectedCursor); - - /** - * Writes a <code>byte</code> to this instance. - * - * @param value the value to write; all but the low 8 bits are ignored - */ - public void writeByte(int value); - - /** - * Writes a <code>short</code> to this instance. - * - * @param value the value to write; all but the low 16 bits are ignored - */ - public void writeShort(int value); - - /** - * Writes an <code>int</code> to this instance. - * - * @param value the value to write - */ - public void writeInt(int value); - - /** - * Writes a <code>long</code> to this instance. - * - * @param value the value to write - */ - public void writeLong(long value); - - /** - * Writes a DWARFv3-style unsigned LEB128 integer. For details, - * see the "Dalvik Executable Format" document or DWARF v3 section - * 7.6. - * - * @param value value to write, treated as an unsigned value - * @return 1..5; the number of bytes actually written - */ - public int writeUnsignedLeb128(int value); - - /** - * Writes a DWARFv3-style unsigned LEB128 integer. For details, - * see the "Dalvik Executable Format" document or DWARF v3 section - * 7.6. - * - * @param value value to write - * @return 1..5; the number of bytes actually written - */ - public int writeSignedLeb128(int value); - - /** - * Writes a {@link ByteArray} to this instance. - * - * @param bytes non-null; the array to write - */ - public void write(ByteArray bytes); - - /** - * Writes a portion of a <code>byte[]</code> to this instance. - * - * @param bytes non-null; the array to write - * @param offset >= 0; offset into <code>bytes</code> for the first - * byte to write - * @param length >= 0; number of bytes to write - */ - public void write(byte[] bytes, int offset, int length); - - /** - * Writes a <code>byte[]</code> to this instance. This is just - * a convenient shorthand for <code>write(bytes, 0, bytes.length)</code>. - * - * @param bytes non-null; the array to write - */ - public void write(byte[] bytes); - - /** - * Writes the given number of <code>0</code> bytes. - * - * @param count >= 0; the number of zeroes to write - */ - public void writeZeroes(int count); - - /** - * Adds extra bytes if necessary (with value <code>0</code>) to - * force alignment of the output cursor as given. - * - * @param alignment > 0; the alignment; must be a power of two - */ - public void alignTo(int alignment); -} diff --git a/dx/src/com/android/dx/util/ToHuman.java b/dx/src/com/android/dx/util/ToHuman.java deleted file mode 100644 index 89bf4f735..000000000 --- a/dx/src/com/android/dx/util/ToHuman.java +++ /dev/null @@ -1,31 +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.android.dx.util; - -/** - * Simple interface for objects that can return a "human" (as opposed to - * a complete but often hard to read) string form. - */ -public interface ToHuman { - /** - * Return the "human" string form of this instance. This is - * generally less "debuggy" than <code>toString()</code>. - * - * @return non-null; the human string form - */ - public String toHuman(); -} diff --git a/dx/src/com/android/dx/util/TwoColumnOutput.java b/dx/src/com/android/dx/util/TwoColumnOutput.java deleted file mode 100644 index cc9f7d4c6..000000000 --- a/dx/src/com/android/dx/util/TwoColumnOutput.java +++ /dev/null @@ -1,254 +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.android.dx.util; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.StringWriter; -import java.io.Writer; - -/** - * Class that takes a combined output destination and provides two - * output writers, one of which ends up writing to the left column and - * one which goes on the right. - */ -public final class TwoColumnOutput { - /** non-null; underlying writer for final output */ - private final Writer out; - - /** > 0; the left column width */ - private final int leftWidth; - - /** non-null; pending left column output */ - private final StringBuffer leftBuf; - - /** non-null; pending right column output */ - private final StringBuffer rightBuf; - - /** non-null; left column writer */ - private final IndentingWriter leftColumn; - - /** non-null; right column writer */ - private final IndentingWriter rightColumn; - - /** - * Turns the given two strings (with widths) and spacer into a formatted - * two-column string. - * - * @param s1 non-null; first string - * @param width1 > 0; width of the first column - * @param spacer non-null; spacer string - * @param s2 non-null; second string - * @param width2 > 0; width of the second column - * @return non-null; an appropriately-formatted string - */ - public static String toString(String s1, int width1, String spacer, - String s2, int width2) { - int len1 = s1.length(); - int len2 = s2.length(); - - StringWriter sw = new StringWriter((len1 + len2) * 3); - TwoColumnOutput twoOut = - new TwoColumnOutput(sw, width1, width2, spacer); - - try { - twoOut.getLeft().write(s1); - twoOut.getRight().write(s2); - } catch (IOException ex) { - throw new RuntimeException("shouldn't happen", ex); - } - - twoOut.flush(); - return sw.toString(); - } - - /** - * Constructs an instance. - * - * @param out non-null; writer to send final output to - * @param leftWidth > 0; width of the left column, in characters - * @param rightWidth > 0; width of the right column, in characters - * @param spacer non-null; spacer string to sit between the two columns - */ - public TwoColumnOutput(Writer out, int leftWidth, int rightWidth, - String spacer) { - if (out == null) { - throw new NullPointerException("out == null"); - } - - if (leftWidth < 1) { - throw new IllegalArgumentException("leftWidth < 1"); - } - - if (rightWidth < 1) { - throw new IllegalArgumentException("rightWidth < 1"); - } - - if (spacer == null) { - throw new NullPointerException("spacer == null"); - } - - StringWriter leftWriter = new StringWriter(1000); - StringWriter rightWriter = new StringWriter(1000); - - this.out = out; - this.leftWidth = leftWidth; - this.leftBuf = leftWriter.getBuffer(); - this.rightBuf = rightWriter.getBuffer(); - this.leftColumn = new IndentingWriter(leftWriter, leftWidth); - this.rightColumn = - new IndentingWriter(rightWriter, rightWidth, spacer); - } - - /** - * Constructs an instance. - * - * @param out non-null; stream to send final output to - * @param leftWidth >= 1; width of the left column, in characters - * @param rightWidth >= 1; width of the right column, in characters - * @param spacer non-null; spacer string to sit between the two columns - */ - public TwoColumnOutput(OutputStream out, int leftWidth, int rightWidth, - String spacer) { - this(new OutputStreamWriter(out), leftWidth, rightWidth, spacer); - } - - /** - * Gets the writer to use to write to the left column. - * - * @return non-null; the left column writer - */ - public Writer getLeft() { - return leftColumn; - } - - /** - * Gets the writer to use to write to the right column. - * - * @return non-null; the right column writer - */ - public Writer getRight() { - return rightColumn; - } - - /** - * Flushes the output. If there are more lines of pending output in one - * column, then the other column will get filled with blank lines. - */ - public void flush() { - try { - appendNewlineIfNecessary(leftBuf, leftColumn); - appendNewlineIfNecessary(rightBuf, rightColumn); - outputFullLines(); - flushLeft(); - flushRight(); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - /** - * Outputs to the final destination as many full line pairs as - * there are in the pending output, removing those lines from - * their respective buffers. This method terminates when at - * least one of the two column buffers is empty. - */ - private void outputFullLines() throws IOException { - for (;;) { - int leftLen = leftBuf.indexOf("\n"); - if (leftLen < 0) { - return; - } - - int rightLen = rightBuf.indexOf("\n"); - if (rightLen < 0) { - return; - } - - if (leftLen != 0) { - out.write(leftBuf.substring(0, leftLen)); - } - - if (rightLen != 0) { - writeSpaces(out, leftWidth - leftLen); - out.write(rightBuf.substring(0, rightLen)); - } - - out.write('\n'); - - leftBuf.delete(0, leftLen + 1); - rightBuf.delete(0, rightLen + 1); - } - } - - /** - * Flushes the left column buffer, printing it and clearing the buffer. - * If the buffer is already empty, this does nothing. - */ - private void flushLeft() throws IOException { - appendNewlineIfNecessary(leftBuf, leftColumn); - - while (leftBuf.length() != 0) { - rightColumn.write('\n'); - outputFullLines(); - } - } - - /** - * Flushes the right column buffer, printing it and clearing the buffer. - * If the buffer is already empty, this does nothing. - */ - private void flushRight() throws IOException { - appendNewlineIfNecessary(rightBuf, rightColumn); - - while (rightBuf.length() != 0) { - leftColumn.write('\n'); - outputFullLines(); - } - } - - /** - * Appends a newline to the given buffer via the given writer, but - * only if it isn't empty and doesn't already end with one. - * - * @param buf non-null; the buffer in question - * @param out non-null; the writer to use - */ - private static void appendNewlineIfNecessary(StringBuffer buf, - Writer out) - throws IOException { - int len = buf.length(); - - if ((len != 0) && (buf.charAt(len - 1) != '\n')) { - out.write('\n'); - } - } - - /** - * Writes the given number of spaces to the given writer. - * - * @param out non-null; where to write - * @param amt >= 0; the number of spaces to write - */ - private static void writeSpaces(Writer out, int amt) throws IOException { - while (amt > 0) { - out.write(' '); - amt--; - } - } -} diff --git a/dx/src/com/android/dx/util/Warning.java b/dx/src/com/android/dx/util/Warning.java deleted file mode 100644 index 3c23c7cdc..000000000 --- a/dx/src/com/android/dx/util/Warning.java +++ /dev/null @@ -1,31 +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.android.dx.util; - -/** - * Exception which is meant to indicate a non-fatal warning. - */ -public class Warning extends RuntimeException { - /** - * Constructs an instance. - * - * @param message human-oriented message - */ - public Warning(String message) { - super(message); - } -} diff --git a/dx/src/com/android/dx/util/Writers.java b/dx/src/com/android/dx/util/Writers.java deleted file mode 100644 index f10e400af..000000000 --- a/dx/src/com/android/dx/util/Writers.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.android.dx.util; - -import java.io.PrintWriter; -import java.io.Writer; - -/** - * Utilities for dealing with <code>Writer</code>s. - */ -public final class Writers { - /** - * This class is uninstantiable. - */ - private Writers() { - // This space intentionally left blank. - } - - /** - * Makes a <code>PrintWriter</code> for the given <code>Writer</code>, - * returning the given writer if it already happens to be the right - * class. - * - * @param writer non-null; writer to (possibly) wrap - * @return non-null; an appropriate instance - */ - public static PrintWriter printWriterFor(Writer writer) { - if (writer instanceof PrintWriter) { - return (PrintWriter) writer; - } - - return new PrintWriter(writer); - } -} diff --git a/dx/src/com/android/dx/util/_tests/_BitIntSet.java b/dx/src/com/android/dx/util/_tests/_BitIntSet.java deleted file mode 100644 index e26d7a4f5..000000000 --- a/dx/src/com/android/dx/util/_tests/_BitIntSet.java +++ /dev/null @@ -1,211 +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.android.dx.util._tests; - -import com.android.dx.util.BitIntSet; -import com.android.dx.util.IntIterator; -import com.android.dx.util.ListIntSet; - -import junit.framework.TestCase; - -import java.util.NoSuchElementException; - -public class _BitIntSet extends TestCase { - public void test_basic() { - BitIntSet set = new BitIntSet(32); - - assertEquals(0, set.elements()); - - set.add(0); - set.add(1); - set.add(31); - - assertTrue(set.has(0)); - assertTrue(set.has(1)); - assertTrue(set.has(31)); - - assertEquals(3, set.elements()); - - assertFalse(set.has(2)); - assertFalse(set.has(7)); - assertFalse(set.has(30)); - } - - public void test_iterator() { - BitIntSet set = new BitIntSet(32); - - set.add(0); - set.add(0); - set.add(1); - set.add(1); - set.add(31); - set.add(31); - - IntIterator iter = set.iterator(); - - assertTrue(iter.hasNext()); - assertEquals(iter.next(), 0); - assertTrue(iter.hasNext()); - assertEquals(iter.next(), 1); - assertTrue(iter.hasNext()); - assertEquals(iter.next(), 31); - - assertFalse(iter.hasNext()); - - try { - iter.next(); - fail(); - } catch (NoSuchElementException ex) { - // exception excepted - } - } - - public void test_remove() { - BitIntSet set = new BitIntSet(32); - - set.add(0); - set.add(1); - set.add(31); - - assertTrue(set.has(0)); - assertTrue(set.has(1)); - assertTrue(set.has(31)); - - assertFalse(set.has(2)); - assertFalse(set.has(7)); - assertFalse(set.has(30)); - - set.remove(0); - - assertFalse(set.has(0)); - - assertTrue(set.has(1)); - assertTrue(set.has(31)); - } - - /** - * Tests the auto-expansion of the set - */ - public void test_expand() { - BitIntSet set = new BitIntSet(32); - int[] values = {0, 1, 31, 32, 128}; - - for (int i = 0; i < values.length; i++) { - set.add(values[i]); - } - - IntIterator iter = set.iterator(); - - for (int i = 0; i < values.length; i++) { - assertTrue(iter.hasNext()); - assertEquals(values[i], iter.next()); - } - assertFalse(iter.hasNext()); - } - - public void test_merge() { - BitIntSet setA = new BitIntSet(32); - int[] valuesA = {0, 1, 31}; - - for (int i = 0; i < valuesA.length; i++) { - setA.add(valuesA[i]); - } - - BitIntSet setB = new BitIntSet(32); - int[] valuesB = {0, 5, 6, 8, 31}; - - for (int i = 0; i < valuesB.length; i++) { - setB.add(valuesB[i]); - } - - setA.merge(setB); - - for (int i = 0; i < valuesA.length; i++) { - assertTrue(setA.has(valuesA[i])); - } - - for (int i = 0; i < valuesB.length; i++) { - assertTrue(setA.has(valuesB[i])); - } - } - - public void test_mergeWithListIntSet() { - BitIntSet setA = new BitIntSet(32); - int[] valuesA = {0, 1, 31}; - - for (int i = 0; i < valuesA.length; i++) { - setA.add(valuesA[i]); - } - - ListIntSet setB = new ListIntSet(); - int[] valuesB = {0, 5, 6, 8, 31}; - - for (int i = 0; i < valuesB.length; i++) { - setB.add(valuesB[i]); - } - - setA.merge(setB); - - for (int i = 0; i < valuesA.length; i++) { - assertTrue(setA.has(valuesA[i])); - } - - for (int i = 0; i < valuesB.length; i++) { - assertTrue(setA.has(valuesB[i])); - } - } - - public void test_mergeAndExpand() { - BitIntSet setA = new BitIntSet(32); - int[] valuesA = {0, 1, 31}; - - for (int i = 0; i < valuesA.length; i++) { - setA.add(valuesA[i]); - } - - BitIntSet setB = new BitIntSet(32); - int[] valuesB = {0, 5, 6, 32, 127}; - - for (int i = 0; i < valuesB.length; i++) { - setB.add(valuesB[i]); - } - - setA.merge(setB); - - for (int i = 0; i < valuesA.length; i++) { - assertTrue(setA.has(valuesA[i])); - } - - for (int i = 0; i < valuesB.length; i++) { - assertTrue(setA.has(valuesB[i])); - } - } - - public void test_toString() { - BitIntSet set = new BitIntSet(32); - - assertEquals(set.toString(), "{}"); - - set.add(1); - - assertEquals(set.toString(), "{1}"); - - set.add(2); - - assertEquals(set.toString(), "{1, 2}"); - } -} diff --git a/dx/src/com/android/dx/util/_tests/_Bits.java b/dx/src/com/android/dx/util/_tests/_Bits.java deleted file mode 100644 index e529b505f..000000000 --- a/dx/src/com/android/dx/util/_tests/_Bits.java +++ /dev/null @@ -1,351 +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.android.dx.util._tests; - -import com.android.dx.util.Bits; - -import junit.framework.TestCase; - -/** - * Test the class <code>com.android.dx.util.Bits</code>. - */ -public class _Bits - extends TestCase { - public void test_makeBitSet() { - assertEquals(label(0), 0, Bits.makeBitSet(0).length); - - for (int i = 1; i <= 32; i++) { - assertEquals(label(i), 1, Bits.makeBitSet(i).length); - } - - for (int i = 33; i <= 64; i++) { - assertEquals(label(i), 2, Bits.makeBitSet(i).length); - } - - for (int i = 65; i < 4000; i += 101) { - int expect = i >> 5; - if ((expect * 32) < i) { - expect++; - } - assertEquals(label(i), expect, Bits.makeBitSet(i).length); - } - } - - public void test_getMax() { - for (int i = 0; i < 4000; i += 59) { - int expect = i >> 5; - if ((expect * 32) < i) { - expect++; - } - assertEquals(label(i), expect * 32, - Bits.getMax(new int[expect])); - } - } - - public void test1_get() { - int[] bits = Bits.makeBitSet(100); - - for (int i = 0; i < 100; i++) { - assertFalse(label(i), Bits.get(bits, i)); - } - } - - public void test2_get() { - int[] bits = Bits.makeBitSet(100); - for (int i = 0; i < bits.length; i++) { - bits[i] = -1; - } - - for (int i = 0; i < 100; i++) { - assertTrue(label(i), Bits.get(bits, i)); - } - } - - public void test3_get() { - int[] bits = Bits.makeBitSet(100); - - for (int i = 0; i < 100; i++) { - Bits.set(bits, i, (i % 5) == 0); - } - - for (int i = 0; i < 100; i++) { - boolean expect = (i % 5) == 0; - assertTrue(label(i), Bits.get(bits, i) == expect); - } - } - - public void test1_set1() { - int[] bits = Bits.makeBitSet(50); - bits[1] = -1; - - Bits.set(bits, 0, true); - Bits.set(bits, 3, true); - Bits.set(bits, 6, true); - Bits.set(bits, 3, false); - Bits.set(bits, 35, false); - Bits.set(bits, 38, false); - Bits.set(bits, 42, false); - Bits.set(bits, 38, true); - - assertEquals(label(1), 0x41, bits[0]); - assertEquals(label(2), 0xfffffbf7, bits[1]); - } - - public void test2_set1() { - int[] bits = Bits.makeBitSet(100); - - for (int i = 0; i < 100; i++) { - if ((i % 3) == 0) { - Bits.set(bits, i, true); - } - } - - for (int i = 0; i < 100; i++) { - if ((i % 5) == 0) { - Bits.set(bits, i, false); - } - } - - for (int i = 0; i < 100; i++) { - if ((i % 7) == 0) { - Bits.set(bits, i, true); - } - } - - for (int i = 0; i < 100; i++) { - boolean expect = ((i % 7) == 0) || - (((i % 3) == 0) && ((i % 5) != 0)); - assertTrue(label(i), Bits.get(bits, i) == expect); - } - } - - public void test_set2() { - int[] bits = Bits.makeBitSet(100); - - for (int i = 0; i < 100; i++) { - if ((i % 11) == 0) { - Bits.set(bits, i); - } - } - - for (int i = 0; i < 100; i++) { - boolean expect = (i % 11) == 0; - assertTrue(label(i), Bits.get(bits, i) == expect); - } - } - - public void test_clear() { - int[] bits = Bits.makeBitSet(100); - for (int i = 0; i < bits.length; i++) { - bits[i] = -1; - } - - for (int i = 0; i < 100; i++) { - if ((i % 5) == 0) { - Bits.clear(bits, i); - } - } - - for (int i = 0; i < 100; i++) { - boolean expect = (i % 5) != 0; - assertTrue(label(i), Bits.get(bits, i) == expect); - } - } - - public void test1_isEmpty() { - for (int i = 0; i < 10; i++) { - assertTrue(label(i), Bits.isEmpty(new int[i])); - } - } - - public void test2_isEmpty() { - for (int i = 1; i < 1000; i += 11) { - int[] bits = Bits.makeBitSet(i); - for (int j = i % 11; j >= 0; j--) { - int x = i - 1 - (j * 13); - if (x >= 0) { - Bits.set(bits, x); - } - } - assertFalse(label(i), Bits.isEmpty(bits)); - } - } - - public void test1_bitCount() { - for (int i = 0; i < 10; i++) { - assertEquals(label(i), 0, Bits.bitCount(new int[i])); - } - } - - public void test2_bitCount() { - for (int i = 1; i < 1000; i += 13) { - int[] bits = Bits.makeBitSet(i); - int count = 0; - for (int j = 0; j < i; j += 20) { - Bits.set(bits, j); - count++; - } - for (int j = 7; j < i; j += 11) { - if (!Bits.get(bits, j)) { - Bits.set(bits, j); - count++; - } - } - for (int j = 3; j < i; j += 17) { - if (!Bits.get(bits, j)) { - Bits.set(bits, j); - count++; - } - } - assertEquals(label(i), count, Bits.bitCount(bits)); - } - } - - public void test1_anyInRange() { - int[] bits = new int[100]; - - for (int i = 0; i < 100; i += 11) { - assertFalse(label(i), Bits.anyInRange(bits, 0, i)); - } - } - - public void test2_anyInRange() { - int[] bits = new int[100]; - - for (int i = 0; i < 100; i += 11) { - assertFalse(label(i), Bits.anyInRange(bits, i, 100)); - } - } - - public void test3_anyInRange() { - int[] bits = new int[100]; - - for (int i = 0; i < 50; i += 7) { - assertFalse(label(i), Bits.anyInRange(bits, i, 100 - i)); - } - } - - public void test4_anyInRange() { - int[] bits = new int[100]; - for (int i = 0; i < bits.length; i++) { - bits[i] = -1; - } - - for (int i = 1; i < 100; i += 11) { - assertTrue(label(i), Bits.anyInRange(bits, 0, i)); - } - } - - public void test5_anyInRange() { - int[] bits = new int[100]; - for (int i = 0; i < bits.length; i++) { - bits[i] = -1; - } - - for (int i = 1; i < 100; i += 11) { - assertTrue(label(i), Bits.anyInRange(bits, i, 100)); - } - } - - public void test6_anyInRange() { - int[] bits = new int[100]; - for (int i = 0; i < bits.length; i++) { - bits[i] = -1; - } - - for (int i = 0; i < 50; i += 7) { - assertTrue(label(i), Bits.anyInRange(bits, i, 100 - i)); - } - } - - public void test1_findFirst1() { - int[] bits = new int[100]; - - for (int i = 0; i < 100; i++) { - assertEquals(label(i), -1, Bits.findFirst(bits, i)); - } - } - - public void test2_findFirst1() { - int[] bits = new int[100]; - for (int i = 0; i < bits.length; i++) { - bits[i] = -1; - } - - for (int i = 0; i < 100; i++) { - assertEquals(label(i), i, Bits.findFirst(bits, i)); - } - } - - public void test3_findFirst1() { - int[] bits = new int[100]; - - for (int i = 25; i < 80; i++) { - for (int j = 0; j < bits.length; j++) { - bits[j] = 0; - } - - Bits.set(bits, i - 5); - Bits.set(bits, i + 5); - Bits.set(bits, i + 10); - Bits.set(bits, i + 20); - assertEquals(label(i), i + 5, Bits.findFirst(bits, i)); - } - } - - public void test1_findFirst2() { - for (int i = 0; i < 32; i++) { - assertEquals(label(i), -1, Bits.findFirst(0, i)); - } - } - - public void test2_findFirst2() { - for (int i = 0; i < 32; i++) { - assertEquals(label(i), i, Bits.findFirst(-1, i)); - } - } - - public void test3_findFirst2() { - for (int i = 0; i < 32; i++) { - assertEquals(label(i), -1, Bits.findFirst((1 << i) >>> 1, i)); - } - } - - public void test4_findFirst2() { - for (int i = 0; i < 32; i++) { - assertEquals(label(i), i, Bits.findFirst(1 << i, i)); - } - } - - public void test5_findFirst2() { - for (int i = 0; i < 31; i++) { - assertEquals(label(i), i + 1, Bits.findFirst(1 << (i + 1), i)); - } - } - - public void test6_findFirst2() { - for (int i = 0; i < 32; i++) { - int value = (1 << i); - value |= (value >>> 1); - assertEquals(label(i), i, Bits.findFirst(value, i)); - } - } - - private static String label(int n) { - return "(" + n + ")"; - } -} diff --git a/dx/src/com/android/dx/util/_tests/_IntList.java b/dx/src/com/android/dx/util/_tests/_IntList.java deleted file mode 100644 index 241e8be78..000000000 --- a/dx/src/com/android/dx/util/_tests/_IntList.java +++ /dev/null @@ -1,72 +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.android.dx.util._tests; - -import com.android.dx.util.IntList; - -import junit.framework.TestCase; - -/** - * Test the class <code>com.android.dx.util.IntList</code>. - */ -public class _IntList - extends TestCase { - // TODO: Add tests for the rest of the methods. - - public void test_contains() { - for (int sz = 0; sz < 100; sz++) { - IntList list = new IntList(sz); - for (int i = 0; i < sz; i++) { - list.add(i * 2); - } - for (int i = (sz * 2) - 1; i >= 0; i--) { - boolean contains = list.contains(i); - if ((i & 1) == 0) { - assertTrue(label(sz, i), contains); - } else { - assertFalse(label(sz, i), contains); - } - } - assertFalse(label(sz, -1), list.contains(-1)); - assertFalse(label(sz, sz * 2), list.contains(sz * 2)); - } - } - - public void test_addSorted() { - IntList list = new IntList(2); - - list.add(9); - list.add(12); - - assertTrue(list.contains(9)); - assertTrue(list.contains(12)); - } - - public void test_addUnsorted() { - IntList list = new IntList(2); - - list.add(12); - list.add(9); - - assertTrue(list.contains(12)); - assertTrue(list.contains(9)); - } - - private static String label(int n, int m) { - return "(" + n + "/" + m + ")"; - } -} diff --git a/dx/src/com/android/dx/util/_tests/_ListIntSet.java b/dx/src/com/android/dx/util/_tests/_ListIntSet.java deleted file mode 100644 index aed79b0c1..000000000 --- a/dx/src/com/android/dx/util/_tests/_ListIntSet.java +++ /dev/null @@ -1,203 +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.android.dx.util._tests; - -import com.android.dx.util.BitIntSet; -import com.android.dx.util.ListIntSet; -import com.android.dx.util.IntIterator; - -import junit.framework.TestCase; - -import java.util.NoSuchElementException; - -public class _ListIntSet extends TestCase { - public void test_basic() { - ListIntSet set = new ListIntSet(); - - assertEquals(0, set.elements()); - - set.add(31); - set.add(0); - set.add(1); - - assertTrue(set.has(0)); - assertTrue(set.has(1)); - assertTrue(set.has(31)); - - assertEquals(3, set.elements()); - - assertFalse(set.has(2)); - assertFalse(set.has(7)); - assertFalse(set.has(30)); - } - - public void test_iterator() { - ListIntSet set = new ListIntSet(); - - set.add(0); - set.add(0); - set.add(1); - set.add(1); - set.add(31); - set.add(31); - - IntIterator iter = set.iterator(); - - assertTrue(iter.hasNext()); - assertEquals(iter.next(), 0); - assertTrue(iter.hasNext()); - assertEquals(iter.next(), 1); - assertTrue(iter.hasNext()); - assertEquals(iter.next(), 31); - - assertFalse(iter.hasNext()); - - try { - iter.next(); - fail(); - } catch (NoSuchElementException ex) { - // exception excepted - } - } - - public void test_empty() { - ListIntSet set = new ListIntSet(); - - IntIterator iter = set.iterator(); - - assertFalse(iter.hasNext()); - } - - public void test_remove() { - ListIntSet set = new ListIntSet(); - - set.add(0); - set.add(1); - set.add(31); - - assertTrue(set.has(0)); - assertTrue(set.has(1)); - assertTrue(set.has(31)); - - assertFalse(set.has(2)); - assertFalse(set.has(7)); - assertFalse(set.has(30)); - - set.remove(0); - - assertFalse(set.has(0)); - - assertTrue(set.has(1)); - assertTrue(set.has(31)); - } - - public void test_mergeA() { - ListIntSet setA = new ListIntSet(); - int[] valuesA = {0, 1, 31}; - - for (int i = 0; i < valuesA.length; i++) { - setA.add(valuesA[i]); - } - - ListIntSet setB = new ListIntSet(); - int[] valuesB = {0, 5, 6, 32, 127, 128}; - - for (int i = 0; i < valuesB.length; i++) { - setB.add(valuesB[i]); - } - - setA.merge(setB); - - for (int i = 0; i < valuesA.length; i++) { - assertTrue(setA.has(valuesA[i])); - } - - for (int i = 0; i < valuesB.length; i++) { - assertTrue(setA.has(valuesB[i])); - } - - } - - public void test_mergeB() { - ListIntSet setA = new ListIntSet(); - int[] valuesA = {0, 1, 31, 129, 130}; - - for (int i = 0; i < valuesA.length; i++) { - setA.add(valuesA[i]); - } - - ListIntSet setB = new ListIntSet(); - int[] valuesB = {0, 5, 6, 32, 127,128}; - - for (int i = 0; i < valuesB.length; i++) { - setB.add(valuesB[i]); - } - - setA.merge(setB); - - for (int i = 0; i < valuesA.length; i++) { - assertTrue(setA.has(valuesA[i])); - } - - for (int i = 0; i < valuesB.length; i++) { - assertTrue(setA.has(valuesB[i])); - } - - } - - public void test_mergeWithBitIntSet() { - ListIntSet setA = new ListIntSet(); - int[] valuesA = {0, 1, 31, 129, 130}; - - for (int i = 0; i < valuesA.length; i++) { - setA.add(valuesA[i]); - } - - BitIntSet setB = new BitIntSet(129); - int[] valuesB = {0, 5, 6, 32, 127,128}; - - for (int i = 0; i < valuesB.length; i++) { - setB.add(valuesB[i]); - } - - setA.merge(setB); - - for (int i = 0; i < valuesA.length; i++) { - assertTrue(setA.has(valuesA[i])); - } - - for (int i = 0; i < valuesB.length; i++) { - assertTrue(setA.has(valuesB[i])); - } - - } - - public void test_toString() { - ListIntSet set = new ListIntSet(); - - assertEquals(set.toString(), "{}"); - - set.add(1); - - assertEquals(set.toString(), "{1}"); - - set.add(2); - - assertEquals(set.toString(), "{1, 2}"); - } - -} diff --git a/dx/src/com/android/dx/util/package.html b/dx/src/com/android/dx/util/package.html deleted file mode 100644 index 8e81e947f..000000000 --- a/dx/src/com/android/dx/util/package.html +++ /dev/null @@ -1,3 +0,0 @@ -<body> -<p>Utility classes for class file access/manipulation.</p> -</body> diff --git a/dx/src/junit/extensions/ActiveTestSuite.java b/dx/src/junit/extensions/ActiveTestSuite.java deleted file mode 100644 index 1a3f163ec..000000000 --- a/dx/src/junit/extensions/ActiveTestSuite.java +++ /dev/null @@ -1,64 +0,0 @@ -package junit.extensions; - -import junit.framework.*; - -/** - * A TestSuite for active Tests. It runs each - * test in a separate thread and waits until all - * threads have terminated. - * -- Aarhus Radisson Scandinavian Center 11th floor - */ -public class ActiveTestSuite extends TestSuite { - private volatile int fActiveTestDeathCount; - - public ActiveTestSuite() { - } - - public ActiveTestSuite(Class theClass) { - super(theClass); - } - - public ActiveTestSuite(String name) { - super (name); - } - - public ActiveTestSuite(Class theClass, String name) { - super(theClass, name); - } - - public void run(TestResult result) { - fActiveTestDeathCount= 0; - super.run(result); - waitUntilFinished(); - } - - public void runTest(final Test test, final TestResult result) { - Thread t= new Thread() { - public void run() { - try { - // inlined due to limitation in VA/Java - //ActiveTestSuite.super.runTest(test, result); - test.run(result); - } finally { - ActiveTestSuite.this.runFinished(test); - } - } - }; - t.start(); - } - - synchronized void waitUntilFinished() { - while (fActiveTestDeathCount < testCount()) { - try { - wait(); - } catch (InterruptedException e) { - return; // ignore - } - } - } - - synchronized public void runFinished(Test test) { - fActiveTestDeathCount++; - notifyAll(); - } -} diff --git a/dx/src/junit/extensions/ExceptionTestCase.java b/dx/src/junit/extensions/ExceptionTestCase.java deleted file mode 100644 index fae574625..000000000 --- a/dx/src/junit/extensions/ExceptionTestCase.java +++ /dev/null @@ -1,46 +0,0 @@ -package junit.extensions; - -import junit.framework.*; - -/** - * A TestCase that expects an Exception of class fExpected to be thrown. - * The other way to check that an expected exception is thrown is: - * <pre> - * try { - * shouldThrow(); - * } - * catch (SpecialException e) { - * return; - * } - * fail("Expected SpecialException"); - * </pre> - * - * To use ExceptionTestCase, create a TestCase like: - * <pre> - * new ExceptionTestCase("testShouldThrow", SpecialException.class); - * </pre> - */ -public class ExceptionTestCase extends TestCase { - Class<?> fExpected; - - public ExceptionTestCase(String name, Class exception) { - super(name); - fExpected= exception; - } - /** - * Execute the test method expecting that an Exception of - * class fExpected or one of its subclasses will be thrown - */ - protected void runTest() throws Throwable { - try { - super.runTest(); - } - catch (Exception e) { - if (fExpected.isAssignableFrom(e.getClass())) - return; - else - throw e; - } - fail("Expected exception " + fExpected); - } -} diff --git a/dx/src/junit/extensions/RepeatedTest.java b/dx/src/junit/extensions/RepeatedTest.java deleted file mode 100644 index ebce77547..000000000 --- a/dx/src/junit/extensions/RepeatedTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package junit.extensions; - -import junit.framework.*; - -/** - * A Decorator that runs a test repeatedly. - * - */ -public class RepeatedTest extends TestDecorator { - private int fTimesRepeat; - - public RepeatedTest(Test test, int repeat) { - super(test); - if (repeat < 0) - throw new IllegalArgumentException("Repetition count must be > 0"); - fTimesRepeat= repeat; - } - public int countTestCases() { - return super.countTestCases()*fTimesRepeat; - } - public void run(TestResult result) { - for (int i= 0; i < fTimesRepeat; i++) { - if (result.shouldStop()) - break; - super.run(result); - } - } - public String toString() { - return super.toString()+"(repeated)"; - } -} diff --git a/dx/src/junit/extensions/TestDecorator.java b/dx/src/junit/extensions/TestDecorator.java deleted file mode 100644 index a8e9e7d46..000000000 --- a/dx/src/junit/extensions/TestDecorator.java +++ /dev/null @@ -1,38 +0,0 @@ -package junit.extensions; - -import junit.framework.*; - -/** - * A Decorator for Tests. Use TestDecorator as the base class - * for defining new test decorators. Test decorator subclasses - * can be introduced to add behaviour before or after a test - * is run. - * - */ -public class TestDecorator extends Assert implements Test { - protected Test fTest; - - public TestDecorator(Test test) { - fTest= test; - } - /** - * The basic run behaviour. - */ - public void basicRun(TestResult result) { - fTest.run(result); - } - public int countTestCases() { - return fTest.countTestCases(); - } - public void run(TestResult result) { - basicRun(result); - } - - public String toString() { - return fTest.toString(); - } - - public Test getTest() { - return fTest; - } -} diff --git a/dx/src/junit/extensions/TestSetup.java b/dx/src/junit/extensions/TestSetup.java deleted file mode 100644 index f1c25face..000000000 --- a/dx/src/junit/extensions/TestSetup.java +++ /dev/null @@ -1,37 +0,0 @@ -package junit.extensions; - -import junit.framework.*; - -/** - * A Decorator to set up and tear down additional fixture state. - * Subclass TestSetup and insert it into your tests when you want - * to set up additional state once before the tests are run. - */ -public class TestSetup extends TestDecorator { - - public TestSetup(Test test) { - super(test); - } - public void run(final TestResult result) { - Protectable p= new Protectable() { - public void protect() throws Exception { - setUp(); - basicRun(result); - tearDown(); - } - }; - result.runProtected(this, p); - } - /** - * Sets up the fixture. Override to set up additional fixture - * state. - */ - protected void setUp() throws Exception { - } - /** - * Tears down the fixture. Override to tear down the additional - * fixture state. - */ - protected void tearDown() throws Exception { - } -} diff --git a/dx/src/junit/framework/Assert.java b/dx/src/junit/framework/Assert.java deleted file mode 100644 index eb5d96042..000000000 --- a/dx/src/junit/framework/Assert.java +++ /dev/null @@ -1,291 +0,0 @@ -package junit.framework; - -/** - * A set of assert methods. Messages are only displayed when an assert fails. - */ - -public class Assert { - /** - * Protect constructor since it is a static only class - */ - protected Assert() { - } - - /** - * Asserts that a condition is true. If it isn't it throws - * an AssertionFailedError with the given message. - */ - static public void assertTrue(String message, boolean condition) { - if (!condition) - fail(message); - } - /** - * Asserts that a condition is true. If it isn't it throws - * an AssertionFailedError. - */ - static public void assertTrue(boolean condition) { - assertTrue(null, condition); - } - /** - * Asserts that a condition is false. If it isn't it throws - * an AssertionFailedError with the given message. - */ - static public void assertFalse(String message, boolean condition) { - assertTrue(message, !condition); - } - /** - * Asserts that a condition is false. If it isn't it throws - * an AssertionFailedError. - */ - static public void assertFalse(boolean condition) { - assertFalse(null, condition); - } - /** - * Fails a test with the given message. - */ - static public void fail(String message) { - throw new AssertionFailedError(message); - } - /** - * Fails a test with no message. - */ - static public void fail() { - fail(null); - } - /** - * Asserts that two objects are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, Object expected, Object actual) { - if (expected == null && actual == null) - return; - if (expected != null && expected.equals(actual)) - return; - failNotEquals(message, expected, actual); - } - /** - * Asserts that two objects are equal. If they are not - * an AssertionFailedError is thrown. - */ - static public void assertEquals(Object expected, Object actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two Strings are equal. - */ - static public void assertEquals(String message, String expected, String actual) { - if (expected == null && actual == null) - return; - if (expected != null && expected.equals(actual)) - return; - throw new ComparisonFailure(message, expected, actual); - } - /** - * Asserts that two Strings are equal. - */ - static public void assertEquals(String expected, String actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two doubles are equal concerning a delta. If they are not - * an AssertionFailedError is thrown with the given message. If the expected - * value is infinity then the delta value is ignored. - */ - static public void assertEquals(String message, double expected, double actual, double delta) { - // handle infinity specially since subtracting to infinite values gives NaN and the - // the following test fails - if (Double.isInfinite(expected)) { - if (!(expected == actual)) - failNotEquals(message, new Double(expected), new Double(actual)); - } else if (!(Math.abs(expected-actual) <= delta)) // Because comparison with NaN always returns false - failNotEquals(message, new Double(expected), new Double(actual)); - } - /** - * Asserts that two doubles are equal concerning a delta. If the expected - * value is infinity then the delta value is ignored. - */ - static public void assertEquals(double expected, double actual, double delta) { - assertEquals(null, expected, actual, delta); - } - /** - * Asserts that two floats are equal concerning a delta. If they are not - * an AssertionFailedError is thrown with the given message. If the expected - * value is infinity then the delta value is ignored. - */ - static public void assertEquals(String message, float expected, float actual, float delta) { - // handle infinity specially since subtracting to infinite values gives NaN and the - // the following test fails - if (Float.isInfinite(expected)) { - if (!(expected == actual)) - failNotEquals(message, new Float(expected), new Float(actual)); - } else if (!(Math.abs(expected-actual) <= delta)) - failNotEquals(message, new Float(expected), new Float(actual)); - } - /** - * Asserts that two floats are equal concerning a delta. If the expected - * value is infinity then the delta value is ignored. - */ - static public void assertEquals(float expected, float actual, float delta) { - assertEquals(null, expected, actual, delta); - } - /** - * Asserts that two longs are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, long expected, long actual) { - assertEquals(message, new Long(expected), new Long(actual)); - } - /** - * Asserts that two longs are equal. - */ - static public void assertEquals(long expected, long actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two booleans are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, boolean expected, boolean actual) { - assertEquals(message, new Boolean(expected), new Boolean(actual)); - } - /** - * Asserts that two booleans are equal. - */ - static public void assertEquals(boolean expected, boolean actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two bytes are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, byte expected, byte actual) { - assertEquals(message, new Byte(expected), new Byte(actual)); - } - /** - * Asserts that two bytes are equal. - */ - static public void assertEquals(byte expected, byte actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two chars are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, char expected, char actual) { - assertEquals(message, new Character(expected), new Character(actual)); - } - /** - * Asserts that two chars are equal. - */ - static public void assertEquals(char expected, char actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two shorts are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, short expected, short actual) { - assertEquals(message, new Short(expected), new Short(actual)); - } - /** - * Asserts that two shorts are equal. - */ - static public void assertEquals(short expected, short actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two ints are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, int expected, int actual) { - assertEquals(message, new Integer(expected), new Integer(actual)); - } - /** - * Asserts that two ints are equal. - */ - static public void assertEquals(int expected, int actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that an object isn't null. - */ - static public void assertNotNull(Object object) { - assertNotNull(null, object); - } - /** - * Asserts that an object isn't null. If it is - * an AssertionFailedError is thrown with the given message. - */ - static public void assertNotNull(String message, Object object) { - assertTrue(message, object != null); - } - /** - * Asserts that an object is null. - */ - static public void assertNull(Object object) { - assertNull(null, object); - } - /** - * Asserts that an object is null. If it is not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertNull(String message, Object object) { - assertTrue(message, object == null); - } - /** - * Asserts that two objects refer to the same object. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertSame(String message, Object expected, Object actual) { - if (expected == actual) - return; - failNotSame(message, expected, actual); - } - /** - * Asserts that two objects refer to the same object. If they are not - * the same an AssertionFailedError is thrown. - */ - static public void assertSame(Object expected, Object actual) { - assertSame(null, expected, actual); - } - /** - * Asserts that two objects refer to the same object. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertNotSame(String message, Object expected, Object actual) { - if (expected == actual) - failSame(message); - } - /** - * Asserts that two objects refer to the same object. If they are not - * the same an AssertionFailedError is thrown. - */ - static public void assertNotSame(Object expected, Object actual) { - assertNotSame(null, expected, actual); - } - - static private void failSame(String message) { - String formatted= ""; - if (message != null) - formatted= message+" "; - fail(formatted+"expected not same"); - } - - static private void failNotSame(String message, Object expected, Object actual) { - String formatted= ""; - if (message != null) - formatted= message+" "; - fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">"); - } - - static private void failNotEquals(String message, Object expected, Object actual) { - fail(format(message, expected, actual)); - } - - static String format(String message, Object expected, Object actual) { - String formatted= ""; - if (message != null) - formatted= message+" "; - return formatted+"expected:<"+expected+"> but was:<"+actual+">"; - } -} diff --git a/dx/src/junit/framework/AssertionFailedError.java b/dx/src/junit/framework/AssertionFailedError.java deleted file mode 100644 index 9aee0018f..000000000 --- a/dx/src/junit/framework/AssertionFailedError.java +++ /dev/null @@ -1,13 +0,0 @@ -package junit.framework; - -/** - * Thrown when an assertion failed. - */ -public class AssertionFailedError extends Error { - - public AssertionFailedError () { - } - public AssertionFailedError (String message) { - super (message); - } -} diff --git a/dx/src/junit/framework/ComparisonFailure.java b/dx/src/junit/framework/ComparisonFailure.java deleted file mode 100644 index 1bfe591c5..000000000 --- a/dx/src/junit/framework/ComparisonFailure.java +++ /dev/null @@ -1,68 +0,0 @@ -package junit.framework; - -/** - * Thrown when an assert equals for Strings failed. - * - * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com - */ -public class ComparisonFailure extends AssertionFailedError { - private String fExpected; - private String fActual; - - /** - * Constructs a comparison failure. - * @param message the identifying message or null - * @param expected the expected string value - * @param actual the actual string value - */ - public ComparisonFailure (String message, String expected, String actual) { - super (message); - fExpected= expected; - fActual= actual; - } - - /** - * Returns "..." in place of common prefix and "..." in - * place of common suffix between expected and actual. - * - * @see java.lang.Throwable#getMessage() - */ - public String getMessage() { - if (fExpected == null || fActual == null) - return Assert.format(super.getMessage(), fExpected, fActual); - - int end= Math.min(fExpected.length(), fActual.length()); - - int i= 0; - for(; i < end; i++) { - if (fExpected.charAt(i) != fActual.charAt(i)) - break; - } - int j= fExpected.length()-1; - int k= fActual.length()-1; - for (; k >= i && j >= i; k--,j--) { - if (fExpected.charAt(j) != fActual.charAt(k)) - break; - } - String actual, expected; - - // equal strings - if (j < i && k < i) { - expected= fExpected; - actual= fActual; - } else { - expected= fExpected.substring(i, j+1); - actual= fActual.substring(i, k+1); - if (i <= end && i > 0) { - expected= "..."+expected; - actual= "..."+actual; - } - - if (j < fExpected.length()-1) - expected= expected+"..."; - if (k < fActual.length()-1) - actual= actual+"..."; - } - return Assert.format(super.getMessage(), expected, actual); - } -} diff --git a/dx/src/junit/framework/Protectable.java b/dx/src/junit/framework/Protectable.java deleted file mode 100644 index 8243555a1..000000000 --- a/dx/src/junit/framework/Protectable.java +++ /dev/null @@ -1,14 +0,0 @@ -package junit.framework; - -/** - * A <em>Protectable</em> can be run and can throw a Throwable. - * - * @see TestResult - */ -public interface Protectable { - - /** - * Run the the following method protected. - */ - public abstract void protect() throws Throwable; -} diff --git a/dx/src/junit/framework/Test.java b/dx/src/junit/framework/Test.java deleted file mode 100644 index 1c6d57b36..000000000 --- a/dx/src/junit/framework/Test.java +++ /dev/null @@ -1,17 +0,0 @@ -package junit.framework; - -/** - * A <em>Test</em> can be run and collect its results. - * - * @see TestResult - */ -public interface Test { - /** - * Counts the number of test cases that will be run by this test. - */ - public abstract int countTestCases(); - /** - * Runs a test and collects its result in a TestResult instance. - */ - public abstract void run(TestResult result); -} diff --git a/dx/src/junit/framework/TestCase.java b/dx/src/junit/framework/TestCase.java deleted file mode 100644 index 8988c45ef..000000000 --- a/dx/src/junit/framework/TestCase.java +++ /dev/null @@ -1,197 +0,0 @@ -package junit.framework; - -import java.lang.reflect.*; - -/** - * A test case defines the fixture to run multiple tests. To define a test case<br> - * 1) implement a subclass of TestCase<br> - * 2) define instance variables that store the state of the fixture<br> - * 3) initialize the fixture state by overriding <code>setUp</code><br> - * 4) clean-up after a test by overriding <code>tearDown</code>.<br> - * Each test runs in its own fixture so there - * can be no side effects among test runs. - * Here is an example: - * <pre> - * public class MathTest extends TestCase { - * protected double fValue1; - * protected double fValue2; - * - * protected void setUp() { - * fValue1= 2.0; - * fValue2= 3.0; - * } - * } - * </pre> - * - * For each test implement a method which interacts - * with the fixture. Verify the expected results with assertions specified - * by calling <code>assertTrue</code> with a boolean. - * <pre> - * public void testAdd() { - * double result= fValue1 + fValue2; - * assertTrue(result == 5.0); - * } - * </pre> - * Once the methods are defined you can run them. The framework supports - * both a static type safe and more dynamic way to run a test. - * In the static way you override the runTest method and define the method to - * be invoked. A convenient way to do so is with an anonymous inner class. - * <pre> - * TestCase test= new MathTest("add") { - * public void runTest() { - * testAdd(); - * } - * }; - * test.run(); - * </pre> - * The dynamic way uses reflection to implement <code>runTest</code>. It dynamically finds - * and invokes a method. - * In this case the name of the test case has to correspond to the test method - * to be run. - * <pre> - * TestCase= new MathTest("testAdd"); - * test.run(); - * </pre> - * The tests to be run can be collected into a TestSuite. JUnit provides - * different <i>test runners</i> which can run a test suite and collect the results. - * A test runner either expects a static method <code>suite</code> as the entry - * point to get a test to run or it will extract the suite automatically. - * <pre> - * public static Test suite() { - * suite.addTest(new MathTest("testAdd")); - * suite.addTest(new MathTest("testDivideByZero")); - * return suite; - * } - * </pre> - * @see TestResult - * @see TestSuite - */ - -public abstract class TestCase extends Assert implements Test { - /** - * the name of the test case - */ - private String fName; - - /** - * No-arg constructor to enable serialization. This method - * is not intended to be used by mere mortals without calling setName(). - */ - public TestCase() { - fName= null; - } - /** - * Constructs a test case with the given name. - */ - public TestCase(String name) { - fName= name; - } - /** - * Counts the number of test cases executed by run(TestResult result). - */ - public int countTestCases() { - return 1; - } - /** - * Creates a default TestResult object - * - * @see TestResult - */ - protected TestResult createResult() { - return new TestResult(); - } - /** - * A convenience method to run this test, collecting the results with a - * default TestResult object. - * - * @see TestResult - */ - public TestResult run() { - TestResult result= createResult(); - run(result); - return result; - } - /** - * Runs the test case and collects the results in TestResult. - */ - public void run(TestResult result) { - result.run(this); - } - /** - * Runs the bare test sequence. - * @exception Throwable if any exception is thrown - */ - public void runBare() throws Throwable { - setUp(); - try { - runTest(); - } - finally { - tearDown(); - } - } - /** - * Override to run the test and assert its state. - * @exception Throwable if any exception is thrown - */ - protected void runTest() throws Throwable { - assertNotNull(fName); - Method runMethod= null; - try { - // use getMethod to get all public inherited - // methods. getDeclaredMethods returns all - // methods of this class but excludes the - // inherited ones. - runMethod= getClass().getMethod(fName, (Class[]) null); - } catch (NoSuchMethodException e) { - fail("Method \""+fName+"\" not found"); - } - if (!Modifier.isPublic(runMethod.getModifiers())) { - fail("Method \""+fName+"\" should be public"); - } - - try { - runMethod.invoke(this, (Object[]) new Class[0]); - } - catch (InvocationTargetException e) { - e.fillInStackTrace(); - throw e.getTargetException(); - } - catch (IllegalAccessException e) { - e.fillInStackTrace(); - throw e; - } - } - /** - * Sets up the fixture, for example, open a network connection. - * This method is called before a test is executed. - */ - protected void setUp() throws Exception { - } - /** - * Tears down the fixture, for example, close a network connection. - * This method is called after a test is executed. - */ - protected void tearDown() throws Exception { - } - /** - * Returns a string representation of the test case - */ - public String toString() { - return getName() + "(" + getClass().getName() + ")"; - } - /** - * Gets the name of a TestCase - * @return returns a String - */ - public String getName() { - return fName; - } - /** - * Sets the name of a TestCase - * @param name The name to set - */ - public void setName(String name) { - fName= name; - } -} diff --git a/dx/src/junit/framework/TestFailure.java b/dx/src/junit/framework/TestFailure.java deleted file mode 100644 index 664747d81..000000000 --- a/dx/src/junit/framework/TestFailure.java +++ /dev/null @@ -1,57 +0,0 @@ -package junit.framework; - -import java.io.PrintWriter; -import java.io.StringWriter; - - -/** - * A <code>TestFailure</code> collects a failed test together with - * the caught exception. - * @see TestResult - */ -public class TestFailure extends Object { - protected Test fFailedTest; - protected Throwable fThrownException; - - - /** - * Constructs a TestFailure with the given test and exception. - */ - public TestFailure(Test failedTest, Throwable thrownException) { - fFailedTest= failedTest; - fThrownException= thrownException; - } - /** - * Gets the failed test. - */ - public Test failedTest() { - return fFailedTest; - } - /** - * Gets the thrown exception. - */ - public Throwable thrownException() { - return fThrownException; - } - /** - * Returns a short description of the failure. - */ - public String toString() { - StringBuffer buffer= new StringBuffer(); - buffer.append(fFailedTest+": "+fThrownException.getMessage()); - return buffer.toString(); - } - public String trace() { - StringWriter stringWriter= new StringWriter(); - PrintWriter writer= new PrintWriter(stringWriter); - thrownException().printStackTrace(writer); - StringBuffer buffer= stringWriter.getBuffer(); - return buffer.toString(); - } - public String exceptionMessage() { - return thrownException().getMessage(); - } - public boolean isFailure() { - return thrownException() instanceof AssertionFailedError; - } -} diff --git a/dx/src/junit/framework/TestListener.java b/dx/src/junit/framework/TestListener.java deleted file mode 100644 index 755818752..000000000 --- a/dx/src/junit/framework/TestListener.java +++ /dev/null @@ -1,23 +0,0 @@ -package junit.framework; - -/** - * A Listener for test progress - */ -public interface TestListener { - /** - * An error occurred. - */ - public void addError(Test test, Throwable t); - /** - * A failure occurred. - */ - public void addFailure(Test test, AssertionFailedError t); - /** - * A test ended. - */ - public void endTest(Test test); - /** - * A test started. - */ - public void startTest(Test test); -} diff --git a/dx/src/junit/framework/TestResult.java b/dx/src/junit/framework/TestResult.java deleted file mode 100644 index 4b1a7e2ed..000000000 --- a/dx/src/junit/framework/TestResult.java +++ /dev/null @@ -1,166 +0,0 @@ -package junit.framework; - -import java.util.Vector; -import java.util.Enumeration; - -/** - * A <code>TestResult</code> collects the results of executing - * a test case. It is an instance of the Collecting Parameter pattern. - * The test framework distinguishes between <i>failures</i> and <i>errors</i>. - * A failure is anticipated and checked for with assertions. Errors are - * unanticipated problems like an <code>ArrayIndexOutOfBoundsException</code>. - * - * @see Test - */ -public class TestResult extends Object { - protected Vector<TestFailure> fFailures; - protected Vector<TestFailure> fErrors; - protected Vector<TestListener> fListeners; - protected int fRunTests; - private boolean fStop; - - public TestResult() { - fFailures= new Vector<TestFailure>(); - fErrors= new Vector<TestFailure>(); - fListeners= new Vector<TestListener>(); - fRunTests= 0; - fStop= false; - } - /** - * Adds an error to the list of errors. The passed in exception - * caused the error. - */ - public synchronized void addError(Test test, Throwable t) { - fErrors.addElement(new TestFailure(test, t)); - for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { - ((TestListener)e.nextElement()).addError(test, t); - } - } - /** - * Adds a failure to the list of failures. The passed in exception - * caused the failure. - */ - public synchronized void addFailure(Test test, AssertionFailedError t) { - fFailures.addElement(new TestFailure(test, t)); - for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { - ((TestListener)e.nextElement()).addFailure(test, t); - } - } - /** - * Registers a TestListener - */ - public synchronized void addListener(TestListener listener) { - fListeners.addElement(listener); - } - /** - * Unregisters a TestListener - */ - public synchronized void removeListener(TestListener listener) { - fListeners.removeElement(listener); - } - /** - * Returns a copy of the listeners. - */ - private synchronized Vector cloneListeners() { - return (Vector)fListeners.clone(); - } - /** - * Informs the result that a test was completed. - */ - public void endTest(Test test) { - for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { - ((TestListener)e.nextElement()).endTest(test); - } - } - /** - * Gets the number of detected errors. - */ - public synchronized int errorCount() { - return fErrors.size(); - } - /** - * Returns an Enumeration for the errors - */ - public synchronized Enumeration errors() { - return fErrors.elements(); - } - /** - * Gets the number of detected failures. - */ - public synchronized int failureCount() { - return fFailures.size(); - } - /** - * Returns an Enumeration for the failures - */ - public synchronized Enumeration failures() { - return fFailures.elements(); - } - /** - * Runs a TestCase. - */ - protected void run(final TestCase test) { - startTest(test); - Protectable p= new Protectable() { - public void protect() throws Throwable { - test.runBare(); - } - }; - runProtected(test, p); - - endTest(test); - } - /** - * Gets the number of run tests. - */ - public synchronized int runCount() { - return fRunTests; - } - /** - * Runs a TestCase. - */ - public void runProtected(final Test test, Protectable p) { - try { - p.protect(); - } - catch (AssertionFailedError e) { - addFailure(test, e); - } - catch (ThreadDeath e) { // don't catch ThreadDeath by accident - throw e; - } - catch (Throwable e) { - addError(test, e); - } - } - /** - * Checks whether the test run should stop - */ - public synchronized boolean shouldStop() { - return fStop; - } - /** - * Informs the result that a test will be started. - */ - public void startTest(Test test) { - final int count= test.countTestCases(); - synchronized(this) { - fRunTests+= count; - } - for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { - ((TestListener)e.nextElement()).startTest(test); - } - } - /** - * Marks that the test run should stop. - */ - public synchronized void stop() { - fStop= true; - } - /** - * Returns whether the entire test was successful or not. - */ - public synchronized boolean wasSuccessful() { - return failureCount() == 0 && errorCount() == 0; - } -} diff --git a/dx/src/junit/framework/TestSuite.java b/dx/src/junit/framework/TestSuite.java deleted file mode 100644 index 2987ad12c..000000000 --- a/dx/src/junit/framework/TestSuite.java +++ /dev/null @@ -1,265 +0,0 @@ -package junit.framework; - -import java.util.Vector; -import java.util.Enumeration; -import java.io.PrintWriter;import java.io.StringWriter;import java.lang.reflect.*; -import java.lang.reflect.Constructor; - -/** - * A <code>TestSuite</code> is a <code>Composite</code> of Tests. - * It runs a collection of test cases. Here is an example using - * the dynamic test definition. - * <pre> - * TestSuite suite= new TestSuite(); - * suite.addTest(new MathTest("testAdd")); - * suite.addTest(new MathTest("testDivideByZero")); - * </pre> - * Alternatively, a TestSuite can extract the tests to be run automatically. - * To do so you pass the class of your TestCase class to the - * TestSuite constructor. - * <pre> - * TestSuite suite= new TestSuite(MathTest.class); - * </pre> - * This constructor creates a suite with all the methods - * starting with "test" that take no arguments. - * - * @see Test - */ -public class TestSuite implements Test { - - private Vector<Test> fTests= new Vector<Test>(10); - private String fName; - - /** - * Constructs an empty TestSuite. - */ - public TestSuite() { - } - - /** - * Constructs a TestSuite from the given class with the given name. - * @see TestSuite#TestSuite(Class) - */ - public TestSuite(Class theClass, String name) { - this(theClass); - setName(name); - } - - /** - * Constructs a TestSuite from the given class. Adds all the methods - * starting with "test" as test cases to the suite. - * Parts of this method was written at 2337 meters in the Huffihutte, - * Kanton Uri - */ - public TestSuite(final Class theClass) { - fName= theClass.getName(); - try { - getTestConstructor(theClass); // Avoid generating multiple error messages - } catch (NoSuchMethodException e) { - addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()")); - return; - } - - if (!Modifier.isPublic(theClass.getModifiers())) { - addTest(warning("Class "+theClass.getName()+" is not public")); - return; - } - - Class superClass= theClass; - Vector<String> names= new Vector<String>(); - while (Test.class.isAssignableFrom(superClass)) { - Method[] methods= superClass.getDeclaredMethods(); - for (int i= 0; i < methods.length; i++) { - addTestMethod(methods[i], names, theClass); - } - superClass= superClass.getSuperclass(); - } - if (fTests.size() == 0) - addTest(warning("No tests found in "+theClass.getName())); - } - - /** - * Constructs an empty TestSuite. - */ - public TestSuite(String name) { - setName(name); - } - - /** - * Adds a test to the suite. - */ - public void addTest(Test test) { - fTests.addElement(test); - } - - /** - * Adds the tests from the given class to the suite - */ - public void addTestSuite(Class testClass) { - addTest(new TestSuite(testClass)); - } - - private void addTestMethod(Method m, Vector<String> names, Class theClass) { - String name= m.getName(); - if (names.contains(name)) - return; - if (! isPublicTestMethod(m)) { - if (isTestMethod(m)) - addTest(warning("Test method isn't public: "+m.getName())); - return; - } - names.addElement(name); - addTest(createTest(theClass, name)); - } - - /** - * ...as the moon sets over the early morning Merlin, Oregon - * mountains, our intrepid adventurers type... - */ - static public Test createTest(Class theClass, String name) { - Constructor constructor; - try { - constructor= getTestConstructor(theClass); - } catch (NoSuchMethodException e) { - return warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()"); - } - Object test; - try { - if (constructor.getParameterTypes().length == 0) { - test= constructor.newInstance(new Object[0]); - if (test instanceof TestCase) - ((TestCase) test).setName(name); - } else { - test= constructor.newInstance(new Object[]{name}); - } - } catch (InstantiationException e) { - return(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")")); - } catch (InvocationTargetException e) { - return(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")")); - } catch (IllegalAccessException e) { - return(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")")); - } - return (Test) test; - } - - /** - * Converts the stack trace into a string - */ - private static String exceptionToString(Throwable t) { - StringWriter stringWriter= new StringWriter(); - PrintWriter writer= new PrintWriter(stringWriter); - t.printStackTrace(writer); - return stringWriter.toString(); - - } - - /** - * Counts the number of test cases that will be run by this test. - */ - public int countTestCases() { - int count= 0; - for (Enumeration e= tests(); e.hasMoreElements(); ) { - Test test= (Test)e.nextElement(); - count= count + test.countTestCases(); - } - return count; - } - - /** - * Gets a constructor which takes a single String as - * its argument or a no arg constructor. - */ - public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException { - Class[] args= { String.class }; - try { - return theClass.getConstructor(args); - } catch (NoSuchMethodException e) { - // fall through - } - return theClass.getConstructor(new Class[0]); - } - - private boolean isPublicTestMethod(Method m) { - return isTestMethod(m) && Modifier.isPublic(m.getModifiers()); - } - - private boolean isTestMethod(Method m) { - String name= m.getName(); - Class[] parameters= m.getParameterTypes(); - Class returnType= m.getReturnType(); - return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE); - } - - /** - * Runs the tests and collects their result in a TestResult. - */ - public void run(TestResult result) { - for (Enumeration e= tests(); e.hasMoreElements(); ) { - if (result.shouldStop() ) - break; - Test test= (Test)e.nextElement(); - runTest(test, result); - } - } - - public void runTest(Test test, TestResult result) { - test.run(result); - } - - /** - * Returns the test at the given index - */ - public Test testAt(int index) { - return (Test)fTests.elementAt(index); - } - - /** - * Returns the number of tests in this suite - */ - public int testCount() { - return fTests.size(); - } - - /** - * Returns the tests as an enumeration - */ - public Enumeration tests() { - return fTests.elements(); - } - - /** - */ - public String toString() { - if (getName() != null) - return getName(); - return super.toString(); - } - - /** - * Sets the name of the suite. - * @param name The name to set - */ - public void setName(String name) { - fName= name; - } - - /** - * Returns the name of the suite. Not all - * test suites have a name and this method - * can return null. - */ - public String getName() { - return fName; - } - - /** - * Returns a test which will fail and log a warning message. - */ - private static Test warning(final String message) { - return new TestCase("warning") { - protected void runTest() { - fail(message); - } - }; - } -} diff --git a/dx/src/junit/runner/BaseTestRunner.java b/dx/src/junit/runner/BaseTestRunner.java deleted file mode 100644 index 39c8c2f98..000000000 --- a/dx/src/junit/runner/BaseTestRunner.java +++ /dev/null @@ -1,323 +0,0 @@ -package junit.runner; - -import junit.framework.*; -import java.lang.reflect.*; -import java.text.NumberFormat; -import java.io.*; -import java.util.*; - -/** - * Base class for all test runners. - * This class was born live on stage in Sardinia during XP2000. - */ -public abstract class BaseTestRunner implements TestListener { - public static final String SUITE_METHODNAME= "suite"; - - private static Properties fPreferences; - static int fgMaxMessageLength= 500; - static boolean fgFilterStack= true; - boolean fLoading= true; - - /* - * Implementation of TestListener - */ - public synchronized void startTest(Test test) { - testStarted(test.toString()); - } - - protected static void setPreferences(Properties preferences) { - fPreferences= preferences; - } - - protected static Properties getPreferences() { - if (fPreferences == null) { - fPreferences= new Properties(); - fPreferences.put("loading", "true"); - fPreferences.put("filterstack", "true"); - readPreferences(); - } - return fPreferences; - } - - public static void savePreferences() throws IOException { - FileOutputStream fos= new FileOutputStream(getPreferencesFile()); - try { - getPreferences().store(fos, ""); - } finally { - fos.close(); - } - } - - public void setPreference(String key, String value) { - getPreferences().setProperty(key, value); - } - - public synchronized void endTest(Test test) { - testEnded(test.toString()); - } - - public synchronized void addError(final Test test, final Throwable t) { - testFailed(TestRunListener.STATUS_ERROR, test, t); - } - - public synchronized void addFailure(final Test test, final AssertionFailedError t) { - testFailed(TestRunListener.STATUS_FAILURE, test, t); - } - - // TestRunListener implementation - - public abstract void testStarted(String testName); - - public abstract void testEnded(String testName); - - public abstract void testFailed(int status, Test test, Throwable t); - - /** - * Returns the Test corresponding to the given suite. This is - * a template method, subclasses override runFailed(), clearStatus(). - */ - public Test getTest(String suiteClassName) { - if (suiteClassName.length() <= 0) { - clearStatus(); - return null; - } - Class testClass= null; - try { - testClass= loadSuiteClass(suiteClassName); - } catch (ClassNotFoundException e) { - String clazz= e.getMessage(); - if (clazz == null) - clazz= suiteClassName; - runFailed("Class not found \""+clazz+"\""); - return null; - } catch(Exception e) { - runFailed("Error: "+e.toString()); - return null; - } - Method suiteMethod= null; - try { - suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]); - } catch(Exception e) { - // try to extract a test suite automatically - clearStatus(); - return new TestSuite(testClass); - } - if (! Modifier.isStatic(suiteMethod.getModifiers())) { - runFailed("Suite() method must be static"); - return null; - } - Test test= null; - try { - test= (Test)suiteMethod.invoke(null, (Object[]) new Class[0]); // static method - if (test == null) - return test; - } - catch (InvocationTargetException e) { - runFailed("Failed to invoke suite():" + e.getTargetException().toString()); - return null; - } - catch (IllegalAccessException e) { - runFailed("Failed to invoke suite():" + e.toString()); - return null; - } - - clearStatus(); - return test; - } - - /** - * Returns the formatted string of the elapsed time. - */ - public String elapsedTimeAsString(long runTime) { - return NumberFormat.getInstance().format((double)runTime/1000); - } - - /** - * Processes the command line arguments and - * returns the name of the suite class to run or null - */ - protected String processArguments(String[] args) { - String suiteName= null; - for (int i= 0; i < args.length; i++) { - if (args[i].equals("-noloading")) { - setLoading(false); - } else if (args[i].equals("-nofilterstack")) { - fgFilterStack= false; - } else if (args[i].equals("-c")) { - if (args.length > i+1) - suiteName= extractClassName(args[i+1]); - else - System.out.println("Missing Test class name"); - i++; - } else { - suiteName= args[i]; - } - } - return suiteName; - } - - /** - * Sets the loading behaviour of the test runner - */ - public void setLoading(boolean enable) { - fLoading= enable; - } - /** - * Extract the class name from a String in VA/Java style - */ - public String extractClassName(String className) { - if(className.startsWith("Default package for")) - return className.substring(className.lastIndexOf(".")+1); - return className; - } - - /** - * Truncates a String to the maximum length. - */ - public static String truncate(String s) { - if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength) - s= s.substring(0, fgMaxMessageLength)+"..."; - return s; - } - - /** - * Override to define how to handle a failed loading of - * a test suite. - */ - protected abstract void runFailed(String message); - - /** - * Returns the loaded Class for a suite name. - */ - protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException { - return getLoader().load(suiteClassName); - } - - /** - * Clears the status message. - */ - protected void clearStatus() { // Belongs in the GUI TestRunner class - } - - /** - * Returns the loader to be used. - */ - public TestSuiteLoader getLoader() { - if (useReloadingTestSuiteLoader()) - return new ReloadingTestSuiteLoader(); - return new StandardTestSuiteLoader(); - } - - protected boolean useReloadingTestSuiteLoader() { - return getPreference("loading").equals("true") && !inVAJava() && fLoading; - } - - private static File getPreferencesFile() { - String home= System.getProperty("user.home"); - return new File(home, "junit.properties"); - } - - private static void readPreferences() { - InputStream is= null; - try { - is= new FileInputStream(getPreferencesFile()); - setPreferences(new Properties(getPreferences())); - getPreferences().load(is); - } catch (IOException e) { - try { - if (is != null) - is.close(); - } catch (IOException e1) { - } - } - } - - public static String getPreference(String key) { - return getPreferences().getProperty(key); - } - - public static int getPreference(String key, int dflt) { - String value= getPreference(key); - int intValue= dflt; - if (value == null) - return intValue; - try { - intValue= Integer.parseInt(value); - } catch (NumberFormatException ne) { - } - return intValue; - } - - public static boolean inVAJava() { - try { - Class.forName("com.ibm.uvm.tools.DebugSupport"); - } - catch (Exception e) { - return false; - } - return true; - } - - /** - * Returns a filtered stack trace - */ - public static String getFilteredTrace(Throwable t) { - StringWriter stringWriter= new StringWriter(); - PrintWriter writer= new PrintWriter(stringWriter); - t.printStackTrace(writer); - StringBuffer buffer= stringWriter.getBuffer(); - String trace= buffer.toString(); - return BaseTestRunner.getFilteredTrace(trace); - } - - /** - * Filters stack frames from internal JUnit classes - */ - public static String getFilteredTrace(String stack) { - if (showStackRaw()) - return stack; - - StringWriter sw= new StringWriter(); - PrintWriter pw= new PrintWriter(sw); - StringReader sr= new StringReader(stack); - BufferedReader br= new BufferedReader(sr); - - String line; - try { - while ((line= br.readLine()) != null) { - if (!filterLine(line)) - pw.println(line); - } - } catch (Exception IOException) { - return stack; // return the stack unfiltered - } - return sw.toString(); - } - - protected static boolean showStackRaw() { - return !getPreference("filterstack").equals("true") || fgFilterStack == false; - } - - static boolean filterLine(String line) { - String[] patterns= new String[] { - "junit.framework.TestCase", - "junit.framework.TestResult", - "junit.framework.TestSuite", - "junit.framework.Assert.", // don't filter AssertionFailure - "junit.swingui.TestRunner", - "junit.awtui.TestRunner", - "junit.textui.TestRunner", - "java.lang.reflect.Method.invoke(" - }; - for (int i= 0; i < patterns.length; i++) { - if (line.indexOf(patterns[i]) > 0) - return true; - } - return false; - } - - static { - fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength); - } - -} diff --git a/dx/src/junit/runner/ClassPathTestCollector.java b/dx/src/junit/runner/ClassPathTestCollector.java deleted file mode 100644 index 24bf1e998..000000000 --- a/dx/src/junit/runner/ClassPathTestCollector.java +++ /dev/null @@ -1,80 +0,0 @@ -package junit.runner; - -import java.util.*; -import java.io.*; - -/** - * An implementation of a TestCollector that consults the - * class path. It considers all classes on the class path - * excluding classes in JARs. It leaves it up to subclasses - * to decide whether a class is a runnable Test. - * - * @see TestCollector - */ -public abstract class ClassPathTestCollector implements TestCollector { - - static final int SUFFIX_LENGTH= ".class".length(); - - public ClassPathTestCollector() { - } - - public Enumeration collectTests() { - String classPath= System.getProperty("java.class.path"); - Hashtable result = collectFilesInPath(classPath); - return result.elements(); - } - - public Hashtable collectFilesInPath(String classPath) { - Hashtable result= collectFilesInRoots(splitClassPath(classPath)); - return result; - } - - Hashtable collectFilesInRoots(Vector roots) { - Hashtable<String,String> result= new Hashtable<String,String>(100); - Enumeration e= roots.elements(); - while (e.hasMoreElements()) - gatherFiles(new File((String)e.nextElement()), "", result); - return result; - } - - void gatherFiles(File classRoot, String classFileName, Hashtable<String,String> result) { - File thisRoot= new File(classRoot, classFileName); - if (thisRoot.isFile()) { - if (isTestClass(classFileName)) { - String className= classNameFromFile(classFileName); - result.put(className, className); - } - return; - } - String[] contents= thisRoot.list(); - if (contents != null) { - for (int i= 0; i < contents.length; i++) - gatherFiles(classRoot, classFileName+File.separatorChar+contents[i], result); - } - } - - Vector splitClassPath(String classPath) { - Vector<String> result= new Vector<String>(); - String separator= System.getProperty("path.separator"); - StringTokenizer tokenizer= new StringTokenizer(classPath, separator); - while (tokenizer.hasMoreTokens()) - result.addElement(tokenizer.nextToken()); - return result; - } - - protected boolean isTestClass(String classFileName) { - return - classFileName.endsWith(".class") && - classFileName.indexOf('$') < 0 && - classFileName.indexOf("Test") > 0; - } - - protected String classNameFromFile(String classFileName) { - // convert /a/b.class to a.b - String s= classFileName.substring(0, classFileName.length()-SUFFIX_LENGTH); - String s2= s.replace(File.separatorChar, '.'); - if (s2.startsWith(".")) - return s2.substring(1); - return s2; - } -} diff --git a/dx/src/junit/runner/FailureDetailView.java b/dx/src/junit/runner/FailureDetailView.java deleted file mode 100644 index 762326b3f..000000000 --- a/dx/src/junit/runner/FailureDetailView.java +++ /dev/null @@ -1,23 +0,0 @@ -package junit.runner; - -import java.awt.Component; - -import junit.framework.*; - -/** - * A view to show a details about a failure - */ -public interface FailureDetailView { - /** - * Returns the component used to present the TraceView - */ - public Component getComponent(); - /** - * Shows details of a TestFailure - */ - public void showFailure(TestFailure failure); - /** - * Clears the view - */ - public void clear(); -} diff --git a/dx/src/junit/runner/LoadingTestCollector.java b/dx/src/junit/runner/LoadingTestCollector.java deleted file mode 100644 index b13835930..000000000 --- a/dx/src/junit/runner/LoadingTestCollector.java +++ /dev/null @@ -1,69 +0,0 @@ -package junit.runner; - -import java.lang.reflect.*; -import junit.runner.*; -import junit.framework.*; - -/** - * An implementation of a TestCollector that loads - * all classes on the class path and tests whether - * it is assignable from Test or provides a static suite method. - * @see TestCollector - */ -public class LoadingTestCollector extends ClassPathTestCollector { - - TestCaseClassLoader fLoader; - - public LoadingTestCollector() { - fLoader= new TestCaseClassLoader(); - } - - protected boolean isTestClass(String classFileName) { - try { - if (classFileName.endsWith(".class")) { - Class testClass= classFromFile(classFileName); - return (testClass != null) && isTestClass(testClass); - } - } - catch (ClassNotFoundException expected) { - } - catch (NoClassDefFoundError notFatal) { - } - return false; - } - - Class classFromFile(String classFileName) throws ClassNotFoundException { - String className= classNameFromFile(classFileName); - if (!fLoader.isExcluded(className)) - return fLoader.loadClass(className, false); - return null; - } - - boolean isTestClass(Class testClass) { - if (hasSuiteMethod(testClass)) - return true; - if (Test.class.isAssignableFrom(testClass) && - Modifier.isPublic(testClass.getModifiers()) && - hasPublicConstructor(testClass)) - return true; - return false; - } - - boolean hasSuiteMethod(Class testClass) { - try { - testClass.getMethod(BaseTestRunner.SUITE_METHODNAME, new Class[0]); - } catch(Exception e) { - return false; - } - return true; - } - - boolean hasPublicConstructor(Class testClass) { - try { - TestSuite.getTestConstructor(testClass); - } catch(NoSuchMethodException e) { - return false; - } - return true; - } -} diff --git a/dx/src/junit/runner/ReloadingTestSuiteLoader.java b/dx/src/junit/runner/ReloadingTestSuiteLoader.java deleted file mode 100644 index f7ef919cc..000000000 --- a/dx/src/junit/runner/ReloadingTestSuiteLoader.java +++ /dev/null @@ -1,19 +0,0 @@ -package junit.runner; - -/** - * A TestSuite loader that can reload classes. - */ -public class ReloadingTestSuiteLoader implements TestSuiteLoader { - - public Class load(String suiteClassName) throws ClassNotFoundException { - return createLoader().loadClass(suiteClassName, true); - } - - public Class reload(Class aClass) throws ClassNotFoundException { - return createLoader().loadClass(aClass.getName(), true); - } - - protected TestCaseClassLoader createLoader() { - return new TestCaseClassLoader(); - } -} diff --git a/dx/src/junit/runner/SimpleTestCollector.java b/dx/src/junit/runner/SimpleTestCollector.java deleted file mode 100644 index 9d1956ad2..000000000 --- a/dx/src/junit/runner/SimpleTestCollector.java +++ /dev/null @@ -1,20 +0,0 @@ -package junit.runner; - -/** - * An implementation of a TestCollector that considers - * a class to be a test class when it contains the - * pattern "Test" in its name - * @see TestCollector - */ -public class SimpleTestCollector extends ClassPathTestCollector { - - public SimpleTestCollector() { - } - - protected boolean isTestClass(String classFileName) { - return - classFileName.endsWith(".class") && - classFileName.indexOf('$') < 0 && - classFileName.indexOf("Test") > 0; - } -} diff --git a/dx/src/junit/runner/Sorter.java b/dx/src/junit/runner/Sorter.java deleted file mode 100644 index e614ab47e..000000000 --- a/dx/src/junit/runner/Sorter.java +++ /dev/null @@ -1,38 +0,0 @@ -package junit.runner; - -import java.util.*; - -import junit.runner.*; - -/** - * A custom quick sort with support to customize the swap behaviour. - * NOTICE: We can't use the the sorting support from the JDK 1.2 collection - * classes because of the JDK 1.1.7 compatibility. - */ -public class Sorter { - public static interface Swapper { - public void swap(Vector values, int left, int right); - } - - public static void sortStrings(Vector values , int left, int right, Swapper swapper) { - int oleft= left; - int oright= right; - String mid= (String)values.elementAt((left + right) / 2); - do { - while (((String)(values.elementAt(left))).compareTo(mid) < 0) - left++; - while (mid.compareTo((String)(values.elementAt(right))) < 0) - right--; - if (left <= right) { - swapper.swap(values, left, right); - left++; - right--; - } - } while (left <= right); - - if (oleft < right) - sortStrings(values, oleft, right, swapper); - if (left < oright) - sortStrings(values, left, oright, swapper); - } -} diff --git a/dx/src/junit/runner/StandardTestSuiteLoader.java b/dx/src/junit/runner/StandardTestSuiteLoader.java deleted file mode 100644 index e2bd765ee..000000000 --- a/dx/src/junit/runner/StandardTestSuiteLoader.java +++ /dev/null @@ -1,19 +0,0 @@ -package junit.runner; - -/** - * The standard test suite loader. It can only load the same class once. - */ -public class StandardTestSuiteLoader implements TestSuiteLoader { - /** - * Uses the system class loader to load the test class - */ - public Class load(String suiteClassName) throws ClassNotFoundException { - return Class.forName(suiteClassName); - } - /** - * Uses the system class loader to load the test class - */ - public Class reload(Class aClass) throws ClassNotFoundException { - return aClass; - } -} diff --git a/dx/src/junit/runner/TestCaseClassLoader.java b/dx/src/junit/runner/TestCaseClassLoader.java deleted file mode 100644 index 543641a85..000000000 --- a/dx/src/junit/runner/TestCaseClassLoader.java +++ /dev/null @@ -1,226 +0,0 @@ -package junit.runner; - -import java.util.*; -import java.io.*; -import java.net.URL; -import java.util.zip.*; - -/** - * A custom class loader which enables the reloading - * of classes for each test run. The class loader - * can be configured with a list of package paths that - * should be excluded from loading. The loading - * of these packages is delegated to the system class - * loader. They will be shared across test runs. - * <p> - * The list of excluded package paths is specified in - * a properties file "excluded.properties" that is located in - * the same place as the TestCaseClassLoader class. - * <p> - * <b>Known limitation:</b> the TestCaseClassLoader cannot load classes - * from jar files. - */ - - -public class TestCaseClassLoader extends ClassLoader { - /** scanned class path */ - private Vector<String> fPathItems; - /** default excluded paths */ - private String[] defaultExclusions= { - "junit.framework.", - "junit.extensions.", - "junit.runner." - }; - /** name of excluded properties file */ - static final String EXCLUDED_FILE= "excluded.properties"; - /** excluded paths */ - private Vector<String> fExcluded; - - /** - * Constructs a TestCaseLoader. It scans the class path - * and the excluded package paths - */ - public TestCaseClassLoader() { - this(System.getProperty("java.class.path")); - } - - /** - * Constructs a TestCaseLoader. It scans the class path - * and the excluded package paths - */ - public TestCaseClassLoader(String classPath) { - scanPath(classPath); - readExcludedPackages(); - } - - private void scanPath(String classPath) { - String separator= System.getProperty("path.separator"); - fPathItems= new Vector<String>(10); - StringTokenizer st= new StringTokenizer(classPath, separator); - while (st.hasMoreTokens()) { - fPathItems.addElement(st.nextToken()); - } - } - - public URL getResource(String name) { - return ClassLoader.getSystemResource(name); - } - - public InputStream getResourceAsStream(String name) { - return ClassLoader.getSystemResourceAsStream(name); - } - - public boolean isExcluded(String name) { - for (int i= 0; i < fExcluded.size(); i++) { - if (name.startsWith((String) fExcluded.elementAt(i))) { - return true; - } - } - return false; - } - - public synchronized Class loadClass(String name, boolean resolve) - throws ClassNotFoundException { - - Class c= findLoadedClass(name); - if (c != null) - return c; - // - // Delegate the loading of excluded classes to the - // standard class loader. - // - if (isExcluded(name)) { - try { - c= findSystemClass(name); - return c; - } catch (ClassNotFoundException e) { - // keep searching - } - } - if (c == null) { - byte[] data= lookupClassData(name); - if (data == null) - throw new ClassNotFoundException(); - c= defineClass(name, data, 0, data.length); - } - if (resolve) - resolveClass(c); - return c; - } - - private byte[] lookupClassData(String className) throws ClassNotFoundException { - byte[] data= null; - for (int i= 0; i < fPathItems.size(); i++) { - String path= (String) fPathItems.elementAt(i); - String fileName= className.replace('.', '/')+".class"; - if (isJar(path)) { - data= loadJarData(path, fileName); - } else { - data= loadFileData(path, fileName); - } - if (data != null) - return data; - } - throw new ClassNotFoundException(className); - } - - boolean isJar(String pathEntry) { - return pathEntry.endsWith(".jar") || - pathEntry.endsWith(".zip") || - pathEntry.endsWith(".apk"); - } - - private byte[] loadFileData(String path, String fileName) { - File file= new File(path, fileName); - if (file.exists()) { - return getClassData(file); - } - return null; - } - - private byte[] getClassData(File f) { - try { - FileInputStream stream= new FileInputStream(f); - ByteArrayOutputStream out= new ByteArrayOutputStream(1000); - byte[] b= new byte[1000]; - int n; - while ((n= stream.read(b)) != -1) - out.write(b, 0, n); - stream.close(); - out.close(); - return out.toByteArray(); - - } catch (IOException e) { - } - return null; - } - - private byte[] loadJarData(String path, String fileName) { - ZipFile zipFile= null; - InputStream stream= null; - File archive= new File(path); - if (!archive.exists()) - return null; - try { - zipFile= new ZipFile(archive); - } catch(IOException io) { - return null; - } - ZipEntry entry= zipFile.getEntry(fileName); - if (entry == null) - return null; - int size= (int) entry.getSize(); - try { - stream= zipFile.getInputStream(entry); - byte[] data= new byte[size]; - int pos= 0; - while (pos < size) { - int n= stream.read(data, pos, data.length - pos); - pos += n; - } - zipFile.close(); - return data; - } catch (IOException e) { - } finally { - try { - if (stream != null) - stream.close(); - } catch (IOException e) { - } - } - return null; - } - - private void readExcludedPackages() { - fExcluded= new Vector<String>(10); - for (int i= 0; i < defaultExclusions.length; i++) - fExcluded.addElement(defaultExclusions[i]); - - InputStream is= getClass().getResourceAsStream(EXCLUDED_FILE); - if (is == null) - return; - Properties p= new Properties(); - try { - p.load(is); - } - catch (IOException e) { - return; - } finally { - try { - is.close(); - } catch (IOException e) { - } - } - for (Enumeration e= p.propertyNames(); e.hasMoreElements(); ) { - String key= (String)e.nextElement(); - if (key.startsWith("excluded.")) { - String path= p.getProperty(key); - path= path.trim(); - if (path.endsWith("*")) - path= path.substring(0, path.length()-1); - if (path.length() > 0) - fExcluded.addElement(path); - } - } - } -} diff --git a/dx/src/junit/runner/TestCollector.java b/dx/src/junit/runner/TestCollector.java deleted file mode 100644 index 73efb4e39..000000000 --- a/dx/src/junit/runner/TestCollector.java +++ /dev/null @@ -1,16 +0,0 @@ -package junit.runner; - -import java.util.*; - - -/** - * Collects Test class names to be presented - * by the TestSelector. - * @see TestSelector - */ -public interface TestCollector { - /** - * Returns an enumeration of Strings with qualified class names - */ - public Enumeration collectTests(); -} diff --git a/dx/src/junit/runner/TestRunListener.java b/dx/src/junit/runner/TestRunListener.java deleted file mode 100644 index b11ef0744..000000000 --- a/dx/src/junit/runner/TestRunListener.java +++ /dev/null @@ -1,19 +0,0 @@ -package junit.runner; -/** - * A listener interface for observing the - * execution of a test run. Unlike TestListener, - * this interface using only primitive objects, - * making it suitable for remote test execution. - */ - public interface TestRunListener { - /* test status constants*/ - public static final int STATUS_ERROR= 1; - public static final int STATUS_FAILURE= 2; - - public void testRunStarted(String testSuiteName, int testCount); - public void testRunEnded(long elapsedTime); - public void testRunStopped(long elapsedTime); - public void testStarted(String testName); - public void testEnded(String testName); - public void testFailed(int status, String testName, String trace); -} diff --git a/dx/src/junit/runner/TestSuiteLoader.java b/dx/src/junit/runner/TestSuiteLoader.java deleted file mode 100644 index 39a4cf79a..000000000 --- a/dx/src/junit/runner/TestSuiteLoader.java +++ /dev/null @@ -1,9 +0,0 @@ -package junit.runner; - -/** - * An interface to define how a test suite should be loaded. - */ -public interface TestSuiteLoader { - abstract public Class load(String suiteClassName) throws ClassNotFoundException; - abstract public Class reload(Class aClass) throws ClassNotFoundException; -} diff --git a/dx/src/junit/runner/Version.java b/dx/src/junit/runner/Version.java deleted file mode 100644 index b4541abde..000000000 --- a/dx/src/junit/runner/Version.java +++ /dev/null @@ -1,14 +0,0 @@ -package junit.runner; - -/** - * This class defines the current version of JUnit - */ -public class Version { - private Version() { - // don't instantiate - } - - public static String id() { - return "3.8.1"; - } -} diff --git a/dx/src/junit/runner/excluded.properties b/dx/src/junit/runner/excluded.properties deleted file mode 100644 index 32846283e..000000000 --- a/dx/src/junit/runner/excluded.properties +++ /dev/null @@ -1,12 +0,0 @@ -# -# The list of excluded package paths for the TestCaseClassLoader -# -excluded.0=sun.* -excluded.1=com.sun.* -excluded.2=org.omg.* -excluded.3=javax.* -excluded.4=sunw.* -excluded.5=java.* -excluded.6=org.w3c.dom.* -excluded.7=org.xml.sax.* -excluded.8=net.jini.* diff --git a/dx/src/junit/runner/logo.gif b/dx/src/junit/runner/logo.gif Binary files differdeleted file mode 100644 index d0e154738..000000000 --- a/dx/src/junit/runner/logo.gif +++ /dev/null diff --git a/dx/src/junit/runner/smalllogo.gif b/dx/src/junit/runner/smalllogo.gif Binary files differdeleted file mode 100644 index 7b25eaf6a..000000000 --- a/dx/src/junit/runner/smalllogo.gif +++ /dev/null diff --git a/dx/src/junit/textui/ResultPrinter.java b/dx/src/junit/textui/ResultPrinter.java deleted file mode 100644 index 1ebb7a178..000000000 --- a/dx/src/junit/textui/ResultPrinter.java +++ /dev/null @@ -1,139 +0,0 @@ - -package junit.textui; - -import java.io.PrintStream; -import java.text.NumberFormat; -import java.util.Enumeration; - -import junit.framework.AssertionFailedError; -import junit.framework.Test; -import junit.framework.TestFailure; -import junit.framework.TestListener; -import junit.framework.TestResult; -import junit.runner.BaseTestRunner; - -public class ResultPrinter implements TestListener { - PrintStream fWriter; - int fColumn= 0; - - public ResultPrinter(PrintStream writer) { - fWriter= writer; - } - - /* API for use by textui.TestRunner - */ - - synchronized void print(TestResult result, long runTime) { - printHeader(runTime); - printErrors(result); - printFailures(result); - printFooter(result); - } - - void printWaitPrompt() { - getWriter().println(); - getWriter().println("<RETURN> to continue"); - } - - /* Internal methods - */ - - protected void printHeader(long runTime) { - getWriter().println(); - getWriter().println("Time: "+elapsedTimeAsString(runTime)); - } - - protected void printErrors(TestResult result) { - printDefects(result.errors(), result.errorCount(), "error"); - } - - protected void printFailures(TestResult result) { - printDefects(result.failures(), result.failureCount(), "failure"); - } - - protected void printDefects(Enumeration booBoos, int count, String type) { - if (count == 0) return; - if (count == 1) - getWriter().println("There was " + count + " " + type + ":"); - else - getWriter().println("There were " + count + " " + type + "s:"); - for (int i= 1; booBoos.hasMoreElements(); i++) { - printDefect((TestFailure) booBoos.nextElement(), i); - } - } - - public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes - printDefectHeader(booBoo, count); - printDefectTrace(booBoo); - } - - protected void printDefectHeader(TestFailure booBoo, int count) { - // I feel like making this a println, then adding a line giving the throwable a chance to print something - // before we get to the stack trace. - getWriter().print(count + ") " + booBoo.failedTest()); - } - - protected void printDefectTrace(TestFailure booBoo) { - getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace())); - } - - protected void printFooter(TestResult result) { - if (result.wasSuccessful()) { - getWriter().println(); - getWriter().print("OK"); - getWriter().println (" (" + result.runCount() + " test" + (result.runCount() == 1 ? "": "s") + ")"); - - } else { - getWriter().println(); - getWriter().println("FAILURES!!!"); - getWriter().println("Tests run: "+result.runCount()+ - ", Failures: "+result.failureCount()+ - ", Errors: "+result.errorCount()); - } - getWriter().println(); - } - - - /** - * Returns the formatted string of the elapsed time. - * Duplicated from BaseTestRunner. Fix it. - */ - protected String elapsedTimeAsString(long runTime) { - return NumberFormat.getInstance().format((double)runTime/1000); - } - - public PrintStream getWriter() { - return fWriter; - } - /** - * @see junit.framework.TestListener#addError(Test, Throwable) - */ - public void addError(Test test, Throwable t) { - getWriter().print("E"); - } - - /** - * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError) - */ - public void addFailure(Test test, AssertionFailedError t) { - getWriter().print("F"); - } - - /** - * @see junit.framework.TestListener#endTest(Test) - */ - public void endTest(Test test) { - } - - /** - * @see junit.framework.TestListener#startTest(Test) - */ - public void startTest(Test test) { - getWriter().print("."); - if (fColumn++ >= 40) { - getWriter().println(); - fColumn= 0; - } - } - -} diff --git a/dx/src/junit/textui/TestRunner.java b/dx/src/junit/textui/TestRunner.java deleted file mode 100644 index 8bdc3258a..000000000 --- a/dx/src/junit/textui/TestRunner.java +++ /dev/null @@ -1,189 +0,0 @@ -package junit.textui; - - -import java.io.PrintStream; - -import junit.framework.*; -import junit.runner.*; - -/** - * A command line based tool to run tests. - * <pre> - * java junit.textui.TestRunner [-wait] TestCaseClass - * </pre> - * TestRunner expects the name of a TestCase class as argument. - * If this class defines a static <code>suite</code> method it - * will be invoked and the returned test is run. Otherwise all - * the methods starting with "test" having no arguments are run. - * <p> - * When the wait command line argument is given TestRunner - * waits until the users types RETURN. - * <p> - * TestRunner prints a trace as the tests are executed followed by a - * summary at the end. - */ -public class TestRunner extends BaseTestRunner { - private ResultPrinter fPrinter; - - public static final int SUCCESS_EXIT= 0; - public static final int FAILURE_EXIT= 1; - public static final int EXCEPTION_EXIT= 2; - - /** - * Constructs a TestRunner. - */ - public TestRunner() { - this(System.out); - } - - /** - * Constructs a TestRunner using the given stream for all the output - */ - public TestRunner(PrintStream writer) { - this(new ResultPrinter(writer)); - } - - /** - * Constructs a TestRunner using the given ResultPrinter all the output - */ - public TestRunner(ResultPrinter printer) { - fPrinter= printer; - } - - /** - * Runs a suite extracted from a TestCase subclass. - */ - static public void run(Class testClass) { - run(new TestSuite(testClass)); - } - - /** - * Runs a single test and collects its results. - * This method can be used to start a test run - * from your program. - * <pre> - * public static void main (String[] args) { - * test.textui.TestRunner.run(suite()); - * } - * </pre> - */ - static public TestResult run(Test test) { - TestRunner runner= new TestRunner(); - return runner.doRun(test); - } - - /** - * Runs a single test and waits until the user - * types RETURN. - */ - static public void runAndWait(Test suite) { - TestRunner aTestRunner= new TestRunner(); - aTestRunner.doRun(suite, true); - } - - /** - * Always use the StandardTestSuiteLoader. Overridden from - * BaseTestRunner. - */ - public TestSuiteLoader getLoader() { - return new StandardTestSuiteLoader(); - } - - public void testFailed(int status, Test test, Throwable t) { - } - - public void testStarted(String testName) { - } - - public void testEnded(String testName) { - } - - /** - * Creates the TestResult to be used for the test run. - */ - protected TestResult createTestResult() { - return new TestResult(); - } - - public TestResult doRun(Test test) { - return doRun(test, false); - } - - public TestResult doRun(Test suite, boolean wait) { - TestResult result= createTestResult(); - result.addListener(fPrinter); - long startTime= System.currentTimeMillis(); - suite.run(result); - long endTime= System.currentTimeMillis(); - long runTime= endTime-startTime; - fPrinter.print(result, runTime); - - pause(wait); - return result; - } - - protected void pause(boolean wait) { - if (!wait) return; - fPrinter.printWaitPrompt(); - try { - System.in.read(); - } - catch(Exception e) { - } - } - - public static void main(String args[]) { - TestRunner aTestRunner= new TestRunner(); - try { - TestResult r= aTestRunner.start(args); - if (!r.wasSuccessful()) - System.exit(FAILURE_EXIT); - System.exit(SUCCESS_EXIT); - } catch(Exception e) { - System.err.println(e.getMessage()); - System.exit(EXCEPTION_EXIT); - } - } - - /** - * Starts a test run. Analyzes the command line arguments - * and runs the given test suite. - */ - protected TestResult start(String args[]) throws Exception { - String testCase= ""; - boolean wait= false; - - for (int i= 0; i < args.length; i++) { - if (args[i].equals("-wait")) - wait= true; - else if (args[i].equals("-c")) - testCase= extractClassName(args[++i]); - else if (args[i].equals("-v")) - System.err.println("JUnit "+Version.id()+" by Kent Beck and Erich Gamma"); - else - testCase= args[i]; - } - - if (testCase.equals("")) - throw new Exception("Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class"); - - try { - Test suite= getTest(testCase); - return doRun(suite, wait); - } - catch(Exception e) { - throw new Exception("Could not create and run test suite: "+e); - } - } - - protected void runFailed(String message) { - System.err.println(message); - System.exit(FAILURE_EXIT); - } - - public void setPrinter(ResultPrinter printer) { - fPrinter= printer; - } - - -} |
