am 707ebe9f: Fix alignment when recompacting a DexMerger result. do not merge.
* commit '707ebe9f1984f7b1ed2e3465012c7c0eb3ef2bd6':
Fix alignment when recompacting a DexMerger result. do not merge.
diff --git a/NOTICE b/NOTICE
index c5b1efa..4760004 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,3 +1,8 @@
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for the Android-specific code. ==
+ =========================================================================
Copyright (c) 2005-2008, The Android Open Source Project
@@ -188,3 +193,31 @@
END OF TERMS AND CONDITIONS
+ =========================================================================
+ == NOTICE file for the x86 JIT libenc subdirectory. ==
+ =========================================================================
+
+Apache Harmony
+Copyright 2006, 2010 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+Portions of Harmony were originally developed by
+Intel Corporation and are licensed to the Apache Software
+Foundation under the "Software Grant and Corporate Contribution
+License Agreement" and for which the following copyright notices
+apply
+ (C) Copyright 2005 Intel Corporation
+ (C) Copyright 2005-2006 Intel Corporation
+ (C) Copyright 2006 Intel Corporation
+
+Portions of the Apache Portable Runtime used by DRLVM were
+developed at the National Center for Supercomputing Applications
+(NCSA) at the University of Illinois at Urbana-Champaign.
+
+This software contains code derived from the RSA Data Security
+Inc. MD5 Message-Digest Algorithm.
+
+This software contains code derived from UNIX V7, Copyright(C)
+Caldera International Inc.
diff --git a/dexdump/DexDump.cpp b/dexdump/DexDump.cpp
index bd2f17c..6ecf671 100644
--- a/dexdump/DexDump.cpp
+++ b/dexdump/DexDump.cpp
@@ -764,12 +764,21 @@
width, index);
break;
case kIndexTypeRef:
- outSize = snprintf(buf, bufSize, "%s // type@%0*x",
- getClassDescriptor(pDexFile, index), width, index);
+ if (index < pDexFile->pHeader->typeIdsSize) {
+ outSize = snprintf(buf, bufSize, "%s // type@%0*x",
+ getClassDescriptor(pDexFile, index), width, index);
+ } else {
+ outSize = snprintf(buf, bufSize, "<type?> // type@%0*x", width, index);
+ }
break;
case kIndexStringRef:
- outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x",
- dexStringById(pDexFile, index), width, index);
+ if (index < pDexFile->pHeader->stringIdsSize) {
+ outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x",
+ dexStringById(pDexFile, index), width, index);
+ } else {
+ outSize = snprintf(buf, bufSize, "<string?> // string@%0*x",
+ width, index);
+ }
break;
case kIndexMethodRef:
{
@@ -1518,7 +1527,7 @@
*/
static inline const u1* align32(const u1* ptr)
{
- return (u1*) (((int) ptr + 3) & ~0x03);
+ return (u1*) (((uintptr_t) ptr + 3) & ~0x03);
}
diff --git a/dx/junit-tests/Android.mk b/dx/junit-tests/Android.mk
index e1f3c41..3f2c611 100644
--- a/dx/junit-tests/Android.mk
+++ b/dx/junit-tests/Android.mk
@@ -5,6 +5,5 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_JAVA_LIBRARIES := dx junit
LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_TAGS := tests
LOCAL_MODULE:= dx-tests
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/dx/src/com/android/dx/dex/code/CodeAddress.java b/dx/src/com/android/dx/dex/code/CodeAddress.java
index 5d26bd1..b31e31c 100644
--- a/dx/src/com/android/dx/dex/code/CodeAddress.java
+++ b/dx/src/com/android/dx/dex/code/CodeAddress.java
@@ -27,6 +27,9 @@
* human-oriented or binary file).
*/
public final class CodeAddress extends ZeroSizeInsn {
+ /** If this address should bind closely to the following real instruction */
+ private final boolean bindsClosely;
+
/**
* Constructs an instance. The output address of this instance is initially
* unknown ({@code -1}).
@@ -34,7 +37,20 @@
* @param position {@code non-null;} source position
*/
public CodeAddress(SourcePosition position) {
+ this(position, false);
+ }
+
+ /**
+ * Constructs an instance. The output address of this instance is initially
+ * unknown ({@code -1}).
+ *
+ * @param position {@code non-null;} source position
+ * @param bindsClosely if the address should bind closely to the following
+ * real instruction.
+ */
+ public CodeAddress(SourcePosition position, boolean bindsClosely) {
super(position);
+ this.bindsClosely = bindsClosely;
}
/** {@inheritDoc} */
@@ -54,4 +70,22 @@
protected String listingString0(boolean noteIndices) {
return "code-address";
}
+
+ /**
+ * Gets whether this address binds closely to the following "real"
+ * (non-zero-length) instruction.
+ *
+ * When a prefix is added to an instruction (for example, to move a value
+ * from a high register to a low register), this determines whether this
+ * {@code CodeAddress} will point to the prefix, or to the instruction
+ * itself.
+ *
+ * If bindsClosely is true, the address will point to the instruction
+ * itself, otherwise it will point to the prefix (if any)
+ *
+ * @return true if this address binds closely to the next real instruction
+ */
+ public boolean getBindsClosely() {
+ return bindsClosely;
+ }
}
diff --git a/dx/src/com/android/dx/dex/code/OutputFinisher.java b/dx/src/com/android/dx/dex/code/OutputFinisher.java
index 13b8e86..c9387fa 100644
--- a/dx/src/com/android/dx/dex/code/OutputFinisher.java
+++ b/dx/src/com/android/dx/dex/code/OutputFinisher.java
@@ -601,6 +601,8 @@
int size = insns.size();
ArrayList<DalvInsn> result = new ArrayList<DalvInsn>(size * 2);
+ ArrayList<CodeAddress> closelyBoundAddresses = new ArrayList<CodeAddress>();
+
for (int i = 0; i < size; i++) {
DalvInsn insn = insns.get(i);
Dop originalOpcode = insn.getOpcode();
@@ -624,10 +626,28 @@
insn = insn.expandedVersion(compatRegs);
}
+ if (insn instanceof CodeAddress) {
+ // If we have a closely bound address, don't add it yet,
+ // because we need to add it after the prefix for the
+ // instruction it is bound to.
+ if (((CodeAddress) insn).getBindsClosely()) {
+ closelyBoundAddresses.add((CodeAddress)insn);
+ continue;
+ }
+ }
+
if (prefix != null) {
result.add(prefix);
}
+ // Add any pending closely bound addresses
+ if (!(insn instanceof ZeroSizeInsn) && closelyBoundAddresses.size() > 0) {
+ for (CodeAddress codeAddress: closelyBoundAddresses) {
+ result.add(codeAddress);
+ }
+ closelyBoundAddresses.clear();
+ }
+
if (currentOpcode != originalOpcode) {
insn = insn.withOpcode(currentOpcode);
}
diff --git a/dx/src/com/android/dx/dex/code/RopTranslator.java b/dx/src/com/android/dx/dex/code/RopTranslator.java
index 3d24c4f..46ed811 100644
--- a/dx/src/com/android/dx/dex/code/RopTranslator.java
+++ b/dx/src/com/android/dx/dex/code/RopTranslator.java
@@ -641,14 +641,17 @@
}
CodeAddress dataAddress = new CodeAddress(pos);
+ // make a new address that binds closely to the switch instruction
+ CodeAddress switchAddress =
+ new CodeAddress(lastAddress.getPosition(), true);
SwitchData dataInsn =
- new SwitchData(pos, lastAddress, cases, switchTargets);
+ new SwitchData(pos, switchAddress, cases, switchTargets);
Dop opcode = dataInsn.isPacked() ?
Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH;
TargetInsn switchInsn =
new TargetInsn(opcode, pos, getRegs(insn), dataAddress);
- addOutput(lastAddress);
+ addOutput(switchAddress);
addOutput(switchInsn);
addOutputSuffix(new OddSpacer(pos));
diff --git a/dx/tests/122-switch-with-high-register/Blort.java b/dx/tests/122-switch-with-high-register/Blort.java
new file mode 100644
index 0000000..c0fb1d0
--- /dev/null
+++ b/dx/tests/122-switch-with-high-register/Blort.java
@@ -0,0 +1,30 @@
+class Blort {
+
+ public static int switchWithHighRegister(
+ int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, int param10, int param11, int param12, int param13, int param14, int param15, int param16, int param17, int param18, int param19, int param20, int param21, int param22, int param23, int param24, int param25, int param26, int param27, int param28, int param29, int param30, int param31, int param32, int param33, int param34, int param35, int param36, int param37, int param38, int param39, int param40, int param41, int param42, int param43, int param44, int param45, int param46, int param47, int param48, int param49, int param50, int param51, int param52, int param53, int param54, int param55, int param56, int param57, int param58, int param59, int param60, int param61, int param62, int param63, int param64, int param65, int param66, int param67, int param68, int param69, int param70, int param71, int param72, int param73, int param74, int param75, int param76, int param77, int param78, int param79, int param80, int param81, int param82, int param83, int param84, int param85, int param86, int param87, int param88, int param89, int param90, int param91, int param92, int param93, int param94, int param95, int param96, int param97, int param98, int param99, int param100, int param101, int param102, int param103, int param104, int param105, int param106, int param107, int param108, int param109, int param110, int param111, int param112, int param113, int param114, int param115, int param116, int param117, int param118, int param119, int param120, int param121, int param122, int param123, int param124, int param125, int param126, int param127, int param128, int param129, int param130, int param131, int param132, int param133, int param134, int param135, int param136, int param137, int param138, int param139, int param140, int param141, int param142, int param143, int param144, int param145, int param146, int param147, int param148, int param149, int param150, int param151, int param152, int param153, int param154, int param155, int param156, int param157, int param158, int param159, int param160, int param161, int param162, int param163, int param164, int param165, int param166, int param167, int param168, int param169, int param170, int param171, int param172, int param173, int param174, int param175, int param176, int param177, int param178, int param179, int param180, int param181, int param182, int param183, int param184, int param185, int param186, int param187, int param188, int param189, int param190, int param191, int param192, int param193, int param194, int param195, int param196, int param197, int param198, int param199, int param200, int param201, int param202, int param203, int param204, int param205, int param206, int param207, int param208, int param209, int param210, int param211, int param212, int param213, int param214, int param215, int param216, int param217, int param218, int param219, int param220, int param221, int param222, int param223, int param224, int param225, int param226, int param227, int param228, int param229, int param230, int param231, int param232, int param233, int param234, int param235, int param236, int param237, int param238, int param239, int param240, int param241, int param242, int param243, int param244, int param245, int param246, int param247, int param248, int param249, int param250, int param251, int param252, int param253, int param254,
+ int param255) {
+
+ // this should add a new non-parameter register, and force the register
+ // for param255 over v255
+ int i=1;
+
+ // make sure that it can't re-use one of the parameter registers for i
+ System.out.println(Integer.toString(i+param1+param2+param3+param4+param5+param6+param7+param8+param9+param10+param11+param12+param13+param14+param15+param16+param17+param18+param19+param20+param21+param22+param23+param24+param25+param26+param27+param28+param29+param30+param31+param32+param33+param34+param35+param36+param37+param38+param39+param40+param41+param42+param43+param44+param45+param46+param47+param48+param49+param50+param51+param52+param53+param54+param55+param56+param57+param58+param59+param60+param61+param62+param63+param64+param65+param66+param67+param68+param69+param70+param71+param72+param73+param74+param75+param76+param77+param78+param79+param80+param81+param82+param83+param84+param85+param86+param87+param88+param89+param90+param91+param92+param93+param94+param95+param96+param97+param98+param99+param100+param101+param102+param103+param104+param105+param106+param107+param108+param109+param110+param111+param112+param113+param114+param115+param116+param117+param118+param119+param120+param121+param122+param123+param124+param125+param126+param127+param128+param129+param130+param131+param132+param133+param134+param135+param136+param137+param138+param139+param140+param141+param142+param143+param144+param145+param146+param147+param148+param149+param150+param151+param152+param153+param154+param155+param156+param157+param158+param159+param160+param161+param162+param163+param164+param165+param166+param167+param168+param169+param170+param171+param172+param173+param174+param175+param176+param177+param178+param179+param180+param181+param182+param183+param184+param185+param186+param187+param188+param189+param190+param191+param192+param193+param194+param195+param196+param197+param198+param199+param200+param201+param202+param203+param204+param205+param206+param207+param208+param209+param210+param211+param212+param213+param214+param215+param216+param217+param218+param219+param220+param221+param222+param223+param224+param225+param226+param227+param228+param229+param230+param231+param232+param233+param234+param235+param236+param237+param238+param239+param240+param241+param242+param243+param244+param245+param246+param247+param248+param249+param250+param251+param252+param253+param254));
+
+ // the register for param255 should be greater than v255, forcing dx
+ // to generate a move instruction to move it to a lower register
+ switch (param255) {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ return 2;
+ case 3:
+ return 3;
+ case 4:
+ return 4;
+ }
+ return -1;
+ }
+}
diff --git a/dx/tests/122-switch-with-high-register/expected.txt b/dx/tests/122-switch-with-high-register/expected.txt
new file mode 100644
index 0000000..7f09421
--- /dev/null
+++ b/dx/tests/122-switch-with-high-register/expected.txt
@@ -0,0 +1,1117 @@
+Blort.switchWithHighRegister:(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)I:
+regs: 0102; ins: 00ff; outs: 0002
+ 0000: const/4 v1, #int 1 // #1
+ 0001: sget-object v2, java.lang.System.out:Ljava/io/PrintStream;
+ 0003: add-int/2addr v1, v3
+ 0004: add-int/2addr v1, v4
+ 0005: add-int/2addr v1, v5
+ 0006: add-int/2addr v1, v6
+ 0007: add-int/2addr v1, v7
+ 0008: add-int/2addr v1, v8
+ 0009: add-int/2addr v1, v9
+ 000a: add-int/2addr v1, v10
+ 000b: add-int/2addr v1, v11
+ 000c: add-int/2addr v1, v12
+ 000d: add-int/2addr v1, v13
+ 000e: add-int/2addr v1, v14
+ 000f: add-int/2addr v1, v15
+ 0010: add-int v1, v1, v16
+ 0012: add-int v1, v1, v17
+ 0014: add-int v1, v1, v18
+ 0016: add-int v1, v1, v19
+ 0018: add-int v1, v1, v20
+ 001a: add-int v1, v1, v21
+ 001c: add-int v1, v1, v22
+ 001e: add-int v1, v1, v23
+ 0020: add-int v1, v1, v24
+ 0022: add-int v1, v1, v25
+ 0024: add-int v1, v1, v26
+ 0026: add-int v1, v1, v27
+ 0028: add-int v1, v1, v28
+ 002a: add-int v1, v1, v29
+ 002c: add-int v1, v1, v30
+ 002e: add-int v1, v1, v31
+ 0030: add-int v1, v1, v32
+ 0032: add-int v1, v1, v33
+ 0034: add-int v1, v1, v34
+ 0036: add-int v1, v1, v35
+ 0038: add-int v1, v1, v36
+ 003a: add-int v1, v1, v37
+ 003c: add-int v1, v1, v38
+ 003e: add-int v1, v1, v39
+ 0040: add-int v1, v1, v40
+ 0042: add-int v1, v1, v41
+ 0044: add-int v1, v1, v42
+ 0046: add-int v1, v1, v43
+ 0048: add-int v1, v1, v44
+ 004a: add-int v1, v1, v45
+ 004c: add-int v1, v1, v46
+ 004e: add-int v1, v1, v47
+ 0050: add-int v1, v1, v48
+ 0052: add-int v1, v1, v49
+ 0054: add-int v1, v1, v50
+ 0056: add-int v1, v1, v51
+ 0058: add-int v1, v1, v52
+ 005a: add-int v1, v1, v53
+ 005c: add-int v1, v1, v54
+ 005e: add-int v1, v1, v55
+ 0060: add-int v1, v1, v56
+ 0062: add-int v1, v1, v57
+ 0064: add-int v1, v1, v58
+ 0066: add-int v1, v1, v59
+ 0068: add-int v1, v1, v60
+ 006a: add-int v1, v1, v61
+ 006c: add-int v1, v1, v62
+ 006e: add-int v1, v1, v63
+ 0070: add-int v1, v1, v64
+ 0072: add-int v1, v1, v65
+ 0074: add-int v1, v1, v66
+ 0076: add-int v1, v1, v67
+ 0078: add-int v1, v1, v68
+ 007a: add-int v1, v1, v69
+ 007c: add-int v1, v1, v70
+ 007e: add-int v1, v1, v71
+ 0080: add-int v1, v1, v72
+ 0082: add-int v1, v1, v73
+ 0084: add-int v1, v1, v74
+ 0086: add-int v1, v1, v75
+ 0088: add-int v1, v1, v76
+ 008a: add-int v1, v1, v77
+ 008c: add-int v1, v1, v78
+ 008e: add-int v1, v1, v79
+ 0090: add-int v1, v1, v80
+ 0092: add-int v1, v1, v81
+ 0094: add-int v1, v1, v82
+ 0096: add-int v1, v1, v83
+ 0098: add-int v1, v1, v84
+ 009a: add-int v1, v1, v85
+ 009c: add-int v1, v1, v86
+ 009e: add-int v1, v1, v87
+ 00a0: add-int v1, v1, v88
+ 00a2: add-int v1, v1, v89
+ 00a4: add-int v1, v1, v90
+ 00a6: add-int v1, v1, v91
+ 00a8: add-int v1, v1, v92
+ 00aa: add-int v1, v1, v93
+ 00ac: add-int v1, v1, v94
+ 00ae: add-int v1, v1, v95
+ 00b0: add-int v1, v1, v96
+ 00b2: add-int v1, v1, v97
+ 00b4: add-int v1, v1, v98
+ 00b6: add-int v1, v1, v99
+ 00b8: add-int v1, v1, v100
+ 00ba: add-int v1, v1, v101
+ 00bc: add-int v1, v1, v102
+ 00be: add-int v1, v1, v103
+ 00c0: add-int v1, v1, v104
+ 00c2: add-int v1, v1, v105
+ 00c4: add-int v1, v1, v106
+ 00c6: add-int v1, v1, v107
+ 00c8: add-int v1, v1, v108
+ 00ca: add-int v1, v1, v109
+ 00cc: add-int v1, v1, v110
+ 00ce: add-int v1, v1, v111
+ 00d0: add-int v1, v1, v112
+ 00d2: add-int v1, v1, v113
+ 00d4: add-int v1, v1, v114
+ 00d6: add-int v1, v1, v115
+ 00d8: add-int v1, v1, v116
+ 00da: add-int v1, v1, v117
+ 00dc: add-int v1, v1, v118
+ 00de: add-int v1, v1, v119
+ 00e0: add-int v1, v1, v120
+ 00e2: add-int v1, v1, v121
+ 00e4: add-int v1, v1, v122
+ 00e6: add-int v1, v1, v123
+ 00e8: add-int v1, v1, v124
+ 00ea: add-int v1, v1, v125
+ 00ec: add-int v1, v1, v126
+ 00ee: add-int v1, v1, v127
+ 00f0: add-int v1, v1, v128
+ 00f2: add-int v1, v1, v129
+ 00f4: add-int v1, v1, v130
+ 00f6: add-int v1, v1, v131
+ 00f8: add-int v1, v1, v132
+ 00fa: add-int v1, v1, v133
+ 00fc: add-int v1, v1, v134
+ 00fe: add-int v1, v1, v135
+ 0100: add-int v1, v1, v136
+ 0102: add-int v1, v1, v137
+ 0104: add-int v1, v1, v138
+ 0106: add-int v1, v1, v139
+ 0108: add-int v1, v1, v140
+ 010a: add-int v1, v1, v141
+ 010c: add-int v1, v1, v142
+ 010e: add-int v1, v1, v143
+ 0110: add-int v1, v1, v144
+ 0112: add-int v1, v1, v145
+ 0114: add-int v1, v1, v146
+ 0116: add-int v1, v1, v147
+ 0118: add-int v1, v1, v148
+ 011a: add-int v1, v1, v149
+ 011c: add-int v1, v1, v150
+ 011e: add-int v1, v1, v151
+ 0120: add-int v1, v1, v152
+ 0122: add-int v1, v1, v153
+ 0124: add-int v1, v1, v154
+ 0126: add-int v1, v1, v155
+ 0128: add-int v1, v1, v156
+ 012a: add-int v1, v1, v157
+ 012c: add-int v1, v1, v158
+ 012e: add-int v1, v1, v159
+ 0130: add-int v1, v1, v160
+ 0132: add-int v1, v1, v161
+ 0134: add-int v1, v1, v162
+ 0136: add-int v1, v1, v163
+ 0138: add-int v1, v1, v164
+ 013a: add-int v1, v1, v165
+ 013c: add-int v1, v1, v166
+ 013e: add-int v1, v1, v167
+ 0140: add-int v1, v1, v168
+ 0142: add-int v1, v1, v169
+ 0144: add-int v1, v1, v170
+ 0146: add-int v1, v1, v171
+ 0148: add-int v1, v1, v172
+ 014a: add-int v1, v1, v173
+ 014c: add-int v1, v1, v174
+ 014e: add-int v1, v1, v175
+ 0150: add-int v1, v1, v176
+ 0152: add-int v1, v1, v177
+ 0154: add-int v1, v1, v178
+ 0156: add-int v1, v1, v179
+ 0158: add-int v1, v1, v180
+ 015a: add-int v1, v1, v181
+ 015c: add-int v1, v1, v182
+ 015e: add-int v1, v1, v183
+ 0160: add-int v1, v1, v184
+ 0162: add-int v1, v1, v185
+ 0164: add-int v1, v1, v186
+ 0166: add-int v1, v1, v187
+ 0168: add-int v1, v1, v188
+ 016a: add-int v1, v1, v189
+ 016c: add-int v1, v1, v190
+ 016e: add-int v1, v1, v191
+ 0170: add-int v1, v1, v192
+ 0172: add-int v1, v1, v193
+ 0174: add-int v1, v1, v194
+ 0176: add-int v1, v1, v195
+ 0178: add-int v1, v1, v196
+ 017a: add-int v1, v1, v197
+ 017c: add-int v1, v1, v198
+ 017e: add-int v1, v1, v199
+ 0180: add-int v1, v1, v200
+ 0182: add-int v1, v1, v201
+ 0184: add-int v1, v1, v202
+ 0186: add-int v1, v1, v203
+ 0188: add-int v1, v1, v204
+ 018a: add-int v1, v1, v205
+ 018c: add-int v1, v1, v206
+ 018e: add-int v1, v1, v207
+ 0190: add-int v1, v1, v208
+ 0192: add-int v1, v1, v209
+ 0194: add-int v1, v1, v210
+ 0196: add-int v1, v1, v211
+ 0198: add-int v1, v1, v212
+ 019a: add-int v1, v1, v213
+ 019c: add-int v1, v1, v214
+ 019e: add-int v1, v1, v215
+ 01a0: add-int v1, v1, v216
+ 01a2: add-int v1, v1, v217
+ 01a4: add-int v1, v1, v218
+ 01a6: add-int v1, v1, v219
+ 01a8: add-int v1, v1, v220
+ 01aa: add-int v1, v1, v221
+ 01ac: add-int v1, v1, v222
+ 01ae: add-int v1, v1, v223
+ 01b0: add-int v1, v1, v224
+ 01b2: add-int v1, v1, v225
+ 01b4: add-int v1, v1, v226
+ 01b6: add-int v1, v1, v227
+ 01b8: add-int v1, v1, v228
+ 01ba: add-int v1, v1, v229
+ 01bc: add-int v1, v1, v230
+ 01be: add-int v1, v1, v231
+ 01c0: add-int v1, v1, v232
+ 01c2: add-int v1, v1, v233
+ 01c4: add-int v1, v1, v234
+ 01c6: add-int v1, v1, v235
+ 01c8: add-int v1, v1, v236
+ 01ca: add-int v1, v1, v237
+ 01cc: add-int v1, v1, v238
+ 01ce: add-int v1, v1, v239
+ 01d0: add-int v1, v1, v240
+ 01d2: add-int v1, v1, v241
+ 01d4: add-int v1, v1, v242
+ 01d6: add-int v1, v1, v243
+ 01d8: add-int v1, v1, v244
+ 01da: add-int v1, v1, v245
+ 01dc: add-int v1, v1, v246
+ 01de: add-int v1, v1, v247
+ 01e0: add-int v1, v1, v248
+ 01e2: add-int v1, v1, v249
+ 01e4: add-int v1, v1, v250
+ 01e6: add-int v1, v1, v251
+ 01e8: add-int v1, v1, v252
+ 01ea: add-int v1, v1, v253
+ 01ec: add-int v1, v1, v254
+ 01ee: add-int v1, v1, v255
+ 01f0: move/from16 v0, v256
+ 01f2: add-int/2addr v1, v0
+ 01f3: invoke-static {v1}, java.lang.Integer.toString:(I)Ljava/lang/String;
+ 01f6: move-result-object v1
+ 01f7: invoke-virtual {v2, v1}, java.io.PrintStream.println:(Ljava/lang/String;)V
+ 01fa: move/from16 v0, v257
+ 01fc: packed-switch v0, 020c // +0010
+ 01ff: const/4 v1, #int -1 // #f
+ 0200: return v1
+ 0201: const/4 v1, #int 0 // #0
+ 0202: goto 0200 // -0002
+ 0203: const/4 v1, #int 1 // #1
+ 0204: goto 0200 // -0004
+ 0205: const/4 v1, #int 2 // #2
+ 0206: goto 0200 // -0006
+ 0207: const/4 v1, #int 3 // #3
+ 0208: goto 0200 // -0008
+ 0209: const/4 v1, #int 4 // #4
+ 020a: goto 0200 // -000a
+ 020b: nop // spacer
+ 020c: packed-switch-payload // for switch @ 01fc
+ 0: 00000201 // +00000005
+ 1: 00000203 // +00000007
+ 2: 00000205 // +00000009
+ 3: 00000207 // +0000000b
+ 4: 00000209 // +0000000d
+ debug info
+ line_start: 9
+ parameters_size: 00ff
+ parameter <unnamed> v3
+ parameter <unnamed> v4
+ parameter <unnamed> v5
+ parameter <unnamed> v6
+ parameter <unnamed> v7
+ parameter <unnamed> v8
+ parameter <unnamed> v9
+ parameter <unnamed> v10
+ parameter <unnamed> v11
+ parameter <unnamed> v12
+ parameter <unnamed> v13
+ parameter <unnamed> v14
+ parameter <unnamed> v15
+ parameter <unnamed> v16
+ parameter <unnamed> v17
+ parameter <unnamed> v18
+ parameter <unnamed> v19
+ parameter <unnamed> v20
+ parameter <unnamed> v21
+ parameter <unnamed> v22
+ parameter <unnamed> v23
+ parameter <unnamed> v24
+ parameter <unnamed> v25
+ parameter <unnamed> v26
+ parameter <unnamed> v27
+ parameter <unnamed> v28
+ parameter <unnamed> v29
+ parameter <unnamed> v30
+ parameter <unnamed> v31
+ parameter <unnamed> v32
+ parameter <unnamed> v33
+ parameter <unnamed> v34
+ parameter <unnamed> v35
+ parameter <unnamed> v36
+ parameter <unnamed> v37
+ parameter <unnamed> v38
+ parameter <unnamed> v39
+ parameter <unnamed> v40
+ parameter <unnamed> v41
+ parameter <unnamed> v42
+ parameter <unnamed> v43
+ parameter <unnamed> v44
+ parameter <unnamed> v45
+ parameter <unnamed> v46
+ parameter <unnamed> v47
+ parameter <unnamed> v48
+ parameter <unnamed> v49
+ parameter <unnamed> v50
+ parameter <unnamed> v51
+ parameter <unnamed> v52
+ parameter <unnamed> v53
+ parameter <unnamed> v54
+ parameter <unnamed> v55
+ parameter <unnamed> v56
+ parameter <unnamed> v57
+ parameter <unnamed> v58
+ parameter <unnamed> v59
+ parameter <unnamed> v60
+ parameter <unnamed> v61
+ parameter <unnamed> v62
+ parameter <unnamed> v63
+ parameter <unnamed> v64
+ parameter <unnamed> v65
+ parameter <unnamed> v66
+ parameter <unnamed> v67
+ parameter <unnamed> v68
+ parameter <unnamed> v69
+ parameter <unnamed> v70
+ parameter <unnamed> v71
+ parameter <unnamed> v72
+ parameter <unnamed> v73
+ parameter <unnamed> v74
+ parameter <unnamed> v75
+ parameter <unnamed> v76
+ parameter <unnamed> v77
+ parameter <unnamed> v78
+ parameter <unnamed> v79
+ parameter <unnamed> v80
+ parameter <unnamed> v81
+ parameter <unnamed> v82
+ parameter <unnamed> v83
+ parameter <unnamed> v84
+ parameter <unnamed> v85
+ parameter <unnamed> v86
+ parameter <unnamed> v87
+ parameter <unnamed> v88
+ parameter <unnamed> v89
+ parameter <unnamed> v90
+ parameter <unnamed> v91
+ parameter <unnamed> v92
+ parameter <unnamed> v93
+ parameter <unnamed> v94
+ parameter <unnamed> v95
+ parameter <unnamed> v96
+ parameter <unnamed> v97
+ parameter <unnamed> v98
+ parameter <unnamed> v99
+ parameter <unnamed> v100
+ parameter <unnamed> v101
+ parameter <unnamed> v102
+ parameter <unnamed> v103
+ parameter <unnamed> v104
+ parameter <unnamed> v105
+ parameter <unnamed> v106
+ parameter <unnamed> v107
+ parameter <unnamed> v108
+ parameter <unnamed> v109
+ parameter <unnamed> v110
+ parameter <unnamed> v111
+ parameter <unnamed> v112
+ parameter <unnamed> v113
+ parameter <unnamed> v114
+ parameter <unnamed> v115
+ parameter <unnamed> v116
+ parameter <unnamed> v117
+ parameter <unnamed> v118
+ parameter <unnamed> v119
+ parameter <unnamed> v120
+ parameter <unnamed> v121
+ parameter <unnamed> v122
+ parameter <unnamed> v123
+ parameter <unnamed> v124
+ parameter <unnamed> v125
+ parameter <unnamed> v126
+ parameter <unnamed> v127
+ parameter <unnamed> v128
+ parameter <unnamed> v129
+ parameter <unnamed> v130
+ parameter <unnamed> v131
+ parameter <unnamed> v132
+ parameter <unnamed> v133
+ parameter <unnamed> v134
+ parameter <unnamed> v135
+ parameter <unnamed> v136
+ parameter <unnamed> v137
+ parameter <unnamed> v138
+ parameter <unnamed> v139
+ parameter <unnamed> v140
+ parameter <unnamed> v141
+ parameter <unnamed> v142
+ parameter <unnamed> v143
+ parameter <unnamed> v144
+ parameter <unnamed> v145
+ parameter <unnamed> v146
+ parameter <unnamed> v147
+ parameter <unnamed> v148
+ parameter <unnamed> v149
+ parameter <unnamed> v150
+ parameter <unnamed> v151
+ parameter <unnamed> v152
+ parameter <unnamed> v153
+ parameter <unnamed> v154
+ parameter <unnamed> v155
+ parameter <unnamed> v156
+ parameter <unnamed> v157
+ parameter <unnamed> v158
+ parameter <unnamed> v159
+ parameter <unnamed> v160
+ parameter <unnamed> v161
+ parameter <unnamed> v162
+ parameter <unnamed> v163
+ parameter <unnamed> v164
+ parameter <unnamed> v165
+ parameter <unnamed> v166
+ parameter <unnamed> v167
+ parameter <unnamed> v168
+ parameter <unnamed> v169
+ parameter <unnamed> v170
+ parameter <unnamed> v171
+ parameter <unnamed> v172
+ parameter <unnamed> v173
+ parameter <unnamed> v174
+ parameter <unnamed> v175
+ parameter <unnamed> v176
+ parameter <unnamed> v177
+ parameter <unnamed> v178
+ parameter <unnamed> v179
+ parameter <unnamed> v180
+ parameter <unnamed> v181
+ parameter <unnamed> v182
+ parameter <unnamed> v183
+ parameter <unnamed> v184
+ parameter <unnamed> v185
+ parameter <unnamed> v186
+ parameter <unnamed> v187
+ parameter <unnamed> v188
+ parameter <unnamed> v189
+ parameter <unnamed> v190
+ parameter <unnamed> v191
+ parameter <unnamed> v192
+ parameter <unnamed> v193
+ parameter <unnamed> v194
+ parameter <unnamed> v195
+ parameter <unnamed> v196
+ parameter <unnamed> v197
+ parameter <unnamed> v198
+ parameter <unnamed> v199
+ parameter <unnamed> v200
+ parameter <unnamed> v201
+ parameter <unnamed> v202
+ parameter <unnamed> v203
+ parameter <unnamed> v204
+ parameter <unnamed> v205
+ parameter <unnamed> v206
+ parameter <unnamed> v207
+ parameter <unnamed> v208
+ parameter <unnamed> v209
+ parameter <unnamed> v210
+ parameter <unnamed> v211
+ parameter <unnamed> v212
+ parameter <unnamed> v213
+ parameter <unnamed> v214
+ parameter <unnamed> v215
+ parameter <unnamed> v216
+ parameter <unnamed> v217
+ parameter <unnamed> v218
+ parameter <unnamed> v219
+ parameter <unnamed> v220
+ parameter <unnamed> v221
+ parameter <unnamed> v222
+ parameter <unnamed> v223
+ parameter <unnamed> v224
+ parameter <unnamed> v225
+ parameter <unnamed> v226
+ parameter <unnamed> v227
+ parameter <unnamed> v228
+ parameter <unnamed> v229
+ parameter <unnamed> v230
+ parameter <unnamed> v231
+ parameter <unnamed> v232
+ parameter <unnamed> v233
+ parameter <unnamed> v234
+ parameter <unnamed> v235
+ parameter <unnamed> v236
+ parameter <unnamed> v237
+ parameter <unnamed> v238
+ parameter <unnamed> v239
+ parameter <unnamed> v240
+ parameter <unnamed> v241
+ parameter <unnamed> v242
+ parameter <unnamed> v243
+ parameter <unnamed> v244
+ parameter <unnamed> v245
+ parameter <unnamed> v246
+ parameter <unnamed> v247
+ parameter <unnamed> v248
+ parameter <unnamed> v249
+ parameter <unnamed> v250
+ parameter <unnamed> v251
+ parameter <unnamed> v252
+ parameter <unnamed> v253
+ parameter <unnamed> v254
+ parameter <unnamed> v255
+ parameter <unnamed> v256
+ parameter <unnamed> v257
+ 0000: prologue end
+ 0000: line 9
+ 0001: line 12
+ 01fa: advance pc
+ 01fa: line 16
+ line = 28
+ 01ff: line 28
+ line = 18
+ 0201: line 18
+ 0203: line 20
+ 0205: line 22
+ 0207: line 24
+ 0209: line 26
+ line = 16
+ 020b: line 16
+ end sequence
+ source file: "Blort.java"
+Blort.switchWithHighRegister:(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)I:
+regs: 0103; ins: 00ff; outs: 0002
+ 0000: const/4 v1, #int 1 // #1
+ 0001: sget-object v2, java.lang.System.out:Ljava/io/PrintStream;
+ 0003: add-int v3, v1, v4
+ 0005: add-int/2addr v3, v5
+ 0006: add-int/2addr v3, v6
+ 0007: add-int/2addr v3, v7
+ 0008: add-int/2addr v3, v8
+ 0009: add-int/2addr v3, v9
+ 000a: add-int/2addr v3, v10
+ 000b: add-int/2addr v3, v11
+ 000c: add-int/2addr v3, v12
+ 000d: add-int/2addr v3, v13
+ 000e: add-int/2addr v3, v14
+ 000f: add-int/2addr v3, v15
+ 0010: add-int v3, v3, v16
+ 0012: add-int v3, v3, v17
+ 0014: add-int v3, v3, v18
+ 0016: add-int v3, v3, v19
+ 0018: add-int v3, v3, v20
+ 001a: add-int v3, v3, v21
+ 001c: add-int v3, v3, v22
+ 001e: add-int v3, v3, v23
+ 0020: add-int v3, v3, v24
+ 0022: add-int v3, v3, v25
+ 0024: add-int v3, v3, v26
+ 0026: add-int v3, v3, v27
+ 0028: add-int v3, v3, v28
+ 002a: add-int v3, v3, v29
+ 002c: add-int v3, v3, v30
+ 002e: add-int v3, v3, v31
+ 0030: add-int v3, v3, v32
+ 0032: add-int v3, v3, v33
+ 0034: add-int v3, v3, v34
+ 0036: add-int v3, v3, v35
+ 0038: add-int v3, v3, v36
+ 003a: add-int v3, v3, v37
+ 003c: add-int v3, v3, v38
+ 003e: add-int v3, v3, v39
+ 0040: add-int v3, v3, v40
+ 0042: add-int v3, v3, v41
+ 0044: add-int v3, v3, v42
+ 0046: add-int v3, v3, v43
+ 0048: add-int v3, v3, v44
+ 004a: add-int v3, v3, v45
+ 004c: add-int v3, v3, v46
+ 004e: add-int v3, v3, v47
+ 0050: add-int v3, v3, v48
+ 0052: add-int v3, v3, v49
+ 0054: add-int v3, v3, v50
+ 0056: add-int v3, v3, v51
+ 0058: add-int v3, v3, v52
+ 005a: add-int v3, v3, v53
+ 005c: add-int v3, v3, v54
+ 005e: add-int v3, v3, v55
+ 0060: add-int v3, v3, v56
+ 0062: add-int v3, v3, v57
+ 0064: add-int v3, v3, v58
+ 0066: add-int v3, v3, v59
+ 0068: add-int v3, v3, v60
+ 006a: add-int v3, v3, v61
+ 006c: add-int v3, v3, v62
+ 006e: add-int v3, v3, v63
+ 0070: add-int v3, v3, v64
+ 0072: add-int v3, v3, v65
+ 0074: add-int v3, v3, v66
+ 0076: add-int v3, v3, v67
+ 0078: add-int v3, v3, v68
+ 007a: add-int v3, v3, v69
+ 007c: add-int v3, v3, v70
+ 007e: add-int v3, v3, v71
+ 0080: add-int v3, v3, v72
+ 0082: add-int v3, v3, v73
+ 0084: add-int v3, v3, v74
+ 0086: add-int v3, v3, v75
+ 0088: add-int v3, v3, v76
+ 008a: add-int v3, v3, v77
+ 008c: add-int v3, v3, v78
+ 008e: add-int v3, v3, v79
+ 0090: add-int v3, v3, v80
+ 0092: add-int v3, v3, v81
+ 0094: add-int v3, v3, v82
+ 0096: add-int v3, v3, v83
+ 0098: add-int v3, v3, v84
+ 009a: add-int v3, v3, v85
+ 009c: add-int v3, v3, v86
+ 009e: add-int v3, v3, v87
+ 00a0: add-int v3, v3, v88
+ 00a2: add-int v3, v3, v89
+ 00a4: add-int v3, v3, v90
+ 00a6: add-int v3, v3, v91
+ 00a8: add-int v3, v3, v92
+ 00aa: add-int v3, v3, v93
+ 00ac: add-int v3, v3, v94
+ 00ae: add-int v3, v3, v95
+ 00b0: add-int v3, v3, v96
+ 00b2: add-int v3, v3, v97
+ 00b4: add-int v3, v3, v98
+ 00b6: add-int v3, v3, v99
+ 00b8: add-int v3, v3, v100
+ 00ba: add-int v3, v3, v101
+ 00bc: add-int v3, v3, v102
+ 00be: add-int v3, v3, v103
+ 00c0: add-int v3, v3, v104
+ 00c2: add-int v3, v3, v105
+ 00c4: add-int v3, v3, v106
+ 00c6: add-int v3, v3, v107
+ 00c8: add-int v3, v3, v108
+ 00ca: add-int v3, v3, v109
+ 00cc: add-int v3, v3, v110
+ 00ce: add-int v3, v3, v111
+ 00d0: add-int v3, v3, v112
+ 00d2: add-int v3, v3, v113
+ 00d4: add-int v3, v3, v114
+ 00d6: add-int v3, v3, v115
+ 00d8: add-int v3, v3, v116
+ 00da: add-int v3, v3, v117
+ 00dc: add-int v3, v3, v118
+ 00de: add-int v3, v3, v119
+ 00e0: add-int v3, v3, v120
+ 00e2: add-int v3, v3, v121
+ 00e4: add-int v3, v3, v122
+ 00e6: add-int v3, v3, v123
+ 00e8: add-int v3, v3, v124
+ 00ea: add-int v3, v3, v125
+ 00ec: add-int v3, v3, v126
+ 00ee: add-int v3, v3, v127
+ 00f0: add-int v3, v3, v128
+ 00f2: add-int v3, v3, v129
+ 00f4: add-int v3, v3, v130
+ 00f6: add-int v3, v3, v131
+ 00f8: add-int v3, v3, v132
+ 00fa: add-int v3, v3, v133
+ 00fc: add-int v3, v3, v134
+ 00fe: add-int v3, v3, v135
+ 0100: add-int v3, v3, v136
+ 0102: add-int v3, v3, v137
+ 0104: add-int v3, v3, v138
+ 0106: add-int v3, v3, v139
+ 0108: add-int v3, v3, v140
+ 010a: add-int v3, v3, v141
+ 010c: add-int v3, v3, v142
+ 010e: add-int v3, v3, v143
+ 0110: add-int v3, v3, v144
+ 0112: add-int v3, v3, v145
+ 0114: add-int v3, v3, v146
+ 0116: add-int v3, v3, v147
+ 0118: add-int v3, v3, v148
+ 011a: add-int v3, v3, v149
+ 011c: add-int v3, v3, v150
+ 011e: add-int v3, v3, v151
+ 0120: add-int v3, v3, v152
+ 0122: add-int v3, v3, v153
+ 0124: add-int v3, v3, v154
+ 0126: add-int v3, v3, v155
+ 0128: add-int v3, v3, v156
+ 012a: add-int v3, v3, v157
+ 012c: add-int v3, v3, v158
+ 012e: add-int v3, v3, v159
+ 0130: add-int v3, v3, v160
+ 0132: add-int v3, v3, v161
+ 0134: add-int v3, v3, v162
+ 0136: add-int v3, v3, v163
+ 0138: add-int v3, v3, v164
+ 013a: add-int v3, v3, v165
+ 013c: add-int v3, v3, v166
+ 013e: add-int v3, v3, v167
+ 0140: add-int v3, v3, v168
+ 0142: add-int v3, v3, v169
+ 0144: add-int v3, v3, v170
+ 0146: add-int v3, v3, v171
+ 0148: add-int v3, v3, v172
+ 014a: add-int v3, v3, v173
+ 014c: add-int v3, v3, v174
+ 014e: add-int v3, v3, v175
+ 0150: add-int v3, v3, v176
+ 0152: add-int v3, v3, v177
+ 0154: add-int v3, v3, v178
+ 0156: add-int v3, v3, v179
+ 0158: add-int v3, v3, v180
+ 015a: add-int v3, v3, v181
+ 015c: add-int v3, v3, v182
+ 015e: add-int v3, v3, v183
+ 0160: add-int v3, v3, v184
+ 0162: add-int v3, v3, v185
+ 0164: add-int v3, v3, v186
+ 0166: add-int v3, v3, v187
+ 0168: add-int v3, v3, v188
+ 016a: add-int v3, v3, v189
+ 016c: add-int v3, v3, v190
+ 016e: add-int v3, v3, v191
+ 0170: add-int v3, v3, v192
+ 0172: add-int v3, v3, v193
+ 0174: add-int v3, v3, v194
+ 0176: add-int v3, v3, v195
+ 0178: add-int v3, v3, v196
+ 017a: add-int v3, v3, v197
+ 017c: add-int v3, v3, v198
+ 017e: add-int v3, v3, v199
+ 0180: add-int v3, v3, v200
+ 0182: add-int v3, v3, v201
+ 0184: add-int v3, v3, v202
+ 0186: add-int v3, v3, v203
+ 0188: add-int v3, v3, v204
+ 018a: add-int v3, v3, v205
+ 018c: add-int v3, v3, v206
+ 018e: add-int v3, v3, v207
+ 0190: add-int v3, v3, v208
+ 0192: add-int v3, v3, v209
+ 0194: add-int v3, v3, v210
+ 0196: add-int v3, v3, v211
+ 0198: add-int v3, v3, v212
+ 019a: add-int v3, v3, v213
+ 019c: add-int v3, v3, v214
+ 019e: add-int v3, v3, v215
+ 01a0: add-int v3, v3, v216
+ 01a2: add-int v3, v3, v217
+ 01a4: add-int v3, v3, v218
+ 01a6: add-int v3, v3, v219
+ 01a8: add-int v3, v3, v220
+ 01aa: add-int v3, v3, v221
+ 01ac: add-int v3, v3, v222
+ 01ae: add-int v3, v3, v223
+ 01b0: add-int v3, v3, v224
+ 01b2: add-int v3, v3, v225
+ 01b4: add-int v3, v3, v226
+ 01b6: add-int v3, v3, v227
+ 01b8: add-int v3, v3, v228
+ 01ba: add-int v3, v3, v229
+ 01bc: add-int v3, v3, v230
+ 01be: add-int v3, v3, v231
+ 01c0: add-int v3, v3, v232
+ 01c2: add-int v3, v3, v233
+ 01c4: add-int v3, v3, v234
+ 01c6: add-int v3, v3, v235
+ 01c8: add-int v3, v3, v236
+ 01ca: add-int v3, v3, v237
+ 01cc: add-int v3, v3, v238
+ 01ce: add-int v3, v3, v239
+ 01d0: add-int v3, v3, v240
+ 01d2: add-int v3, v3, v241
+ 01d4: add-int v3, v3, v242
+ 01d6: add-int v3, v3, v243
+ 01d8: add-int v3, v3, v244
+ 01da: add-int v3, v3, v245
+ 01dc: add-int v3, v3, v246
+ 01de: add-int v3, v3, v247
+ 01e0: add-int v3, v3, v248
+ 01e2: add-int v3, v3, v249
+ 01e4: add-int v3, v3, v250
+ 01e6: add-int v3, v3, v251
+ 01e8: add-int v3, v3, v252
+ 01ea: add-int v3, v3, v253
+ 01ec: add-int v3, v3, v254
+ 01ee: add-int v3, v3, v255
+ 01f0: move/from16 v0, v256
+ 01f2: add-int/2addr v3, v0
+ 01f3: move/from16 v0, v257
+ 01f5: add-int/2addr v3, v0
+ 01f6: invoke-static {v3}, java.lang.Integer.toString:(I)Ljava/lang/String;
+ 01f9: move-result-object v3
+ 01fa: invoke-virtual {v2, v3}, java.io.PrintStream.println:(Ljava/lang/String;)V
+ 01fd: move/from16 v0, v258
+ 01ff: packed-switch v0, 020e // +000f
+ 0202: const/4 v2, #int -1 // #f
+ 0203: return v2
+ 0204: const/4 v2, #int 0 // #0
+ 0205: goto 0203 // -0002
+ 0206: const/4 v2, #int 1 // #1
+ 0207: goto 0203 // -0004
+ 0208: const/4 v2, #int 2 // #2
+ 0209: goto 0203 // -0006
+ 020a: const/4 v2, #int 3 // #3
+ 020b: goto 0203 // -0008
+ 020c: const/4 v2, #int 4 // #4
+ 020d: goto 0203 // -000a
+ 020e: packed-switch-payload // for switch @ 01ff
+ 0: 00000204 // +00000005
+ 1: 00000206 // +00000007
+ 2: 00000208 // +00000009
+ 3: 0000020a // +0000000b
+ 4: 0000020c // +0000000d
+ debug info
+ line_start: 9
+ parameters_size: 00ff
+ parameter param1 v4
+ parameter param2 v5
+ parameter param3 v6
+ parameter param4 v7
+ parameter param5 v8
+ parameter param6 v9
+ parameter param7 v10
+ parameter param8 v11
+ parameter param9 v12
+ parameter param10 v13
+ parameter param11 v14
+ parameter param12 v15
+ parameter param13 v16
+ parameter param14 v17
+ parameter param15 v18
+ parameter param16 v19
+ parameter param17 v20
+ parameter param18 v21
+ parameter param19 v22
+ parameter param20 v23
+ parameter param21 v24
+ parameter param22 v25
+ parameter param23 v26
+ parameter param24 v27
+ parameter param25 v28
+ parameter param26 v29
+ parameter param27 v30
+ parameter param28 v31
+ parameter param29 v32
+ parameter param30 v33
+ parameter param31 v34
+ parameter param32 v35
+ parameter param33 v36
+ parameter param34 v37
+ parameter param35 v38
+ parameter param36 v39
+ parameter param37 v40
+ parameter param38 v41
+ parameter param39 v42
+ parameter param40 v43
+ parameter param41 v44
+ parameter param42 v45
+ parameter param43 v46
+ parameter param44 v47
+ parameter param45 v48
+ parameter param46 v49
+ parameter param47 v50
+ parameter param48 v51
+ parameter param49 v52
+ parameter param50 v53
+ parameter param51 v54
+ parameter param52 v55
+ parameter param53 v56
+ parameter param54 v57
+ parameter param55 v58
+ parameter param56 v59
+ parameter param57 v60
+ parameter param58 v61
+ parameter param59 v62
+ parameter param60 v63
+ parameter param61 v64
+ parameter param62 v65
+ parameter param63 v66
+ parameter param64 v67
+ parameter param65 v68
+ parameter param66 v69
+ parameter param67 v70
+ parameter param68 v71
+ parameter param69 v72
+ parameter param70 v73
+ parameter param71 v74
+ parameter param72 v75
+ parameter param73 v76
+ parameter param74 v77
+ parameter param75 v78
+ parameter param76 v79
+ parameter param77 v80
+ parameter param78 v81
+ parameter param79 v82
+ parameter param80 v83
+ parameter param81 v84
+ parameter param82 v85
+ parameter param83 v86
+ parameter param84 v87
+ parameter param85 v88
+ parameter param86 v89
+ parameter param87 v90
+ parameter param88 v91
+ parameter param89 v92
+ parameter param90 v93
+ parameter param91 v94
+ parameter param92 v95
+ parameter param93 v96
+ parameter param94 v97
+ parameter param95 v98
+ parameter param96 v99
+ parameter param97 v100
+ parameter param98 v101
+ parameter param99 v102
+ parameter param100 v103
+ parameter param101 v104
+ parameter param102 v105
+ parameter param103 v106
+ parameter param104 v107
+ parameter param105 v108
+ parameter param106 v109
+ parameter param107 v110
+ parameter param108 v111
+ parameter param109 v112
+ parameter param110 v113
+ parameter param111 v114
+ parameter param112 v115
+ parameter param113 v116
+ parameter param114 v117
+ parameter param115 v118
+ parameter param116 v119
+ parameter param117 v120
+ parameter param118 v121
+ parameter param119 v122
+ parameter param120 v123
+ parameter param121 v124
+ parameter param122 v125
+ parameter param123 v126
+ parameter param124 v127
+ parameter param125 v128
+ parameter param126 v129
+ parameter param127 v130
+ parameter param128 v131
+ parameter param129 v132
+ parameter param130 v133
+ parameter param131 v134
+ parameter param132 v135
+ parameter param133 v136
+ parameter param134 v137
+ parameter param135 v138
+ parameter param136 v139
+ parameter param137 v140
+ parameter param138 v141
+ parameter param139 v142
+ parameter param140 v143
+ parameter param141 v144
+ parameter param142 v145
+ parameter param143 v146
+ parameter param144 v147
+ parameter param145 v148
+ parameter param146 v149
+ parameter param147 v150
+ parameter param148 v151
+ parameter param149 v152
+ parameter param150 v153
+ parameter param151 v154
+ parameter param152 v155
+ parameter param153 v156
+ parameter param154 v157
+ parameter param155 v158
+ parameter param156 v159
+ parameter param157 v160
+ parameter param158 v161
+ parameter param159 v162
+ parameter param160 v163
+ parameter param161 v164
+ parameter param162 v165
+ parameter param163 v166
+ parameter param164 v167
+ parameter param165 v168
+ parameter param166 v169
+ parameter param167 v170
+ parameter param168 v171
+ parameter param169 v172
+ parameter param170 v173
+ parameter param171 v174
+ parameter param172 v175
+ parameter param173 v176
+ parameter param174 v177
+ parameter param175 v178
+ parameter param176 v179
+ parameter param177 v180
+ parameter param178 v181
+ parameter param179 v182
+ parameter param180 v183
+ parameter param181 v184
+ parameter param182 v185
+ parameter param183 v186
+ parameter param184 v187
+ parameter param185 v188
+ parameter param186 v189
+ parameter param187 v190
+ parameter param188 v191
+ parameter param189 v192
+ parameter param190 v193
+ parameter param191 v194
+ parameter param192 v195
+ parameter param193 v196
+ parameter param194 v197
+ parameter param195 v198
+ parameter param196 v199
+ parameter param197 v200
+ parameter param198 v201
+ parameter param199 v202
+ parameter param200 v203
+ parameter param201 v204
+ parameter param202 v205
+ parameter param203 v206
+ parameter param204 v207
+ parameter param205 v208
+ parameter param206 v209
+ parameter param207 v210
+ parameter param208 v211
+ parameter param209 v212
+ parameter param210 v213
+ parameter param211 v214
+ parameter param212 v215
+ parameter param213 v216
+ parameter param214 v217
+ parameter param215 v218
+ parameter param216 v219
+ parameter param217 v220
+ parameter param218 v221
+ parameter param219 v222
+ parameter param220 v223
+ parameter param221 v224
+ parameter param222 v225
+ parameter param223 v226
+ parameter param224 v227
+ parameter param225 v228
+ parameter param226 v229
+ parameter param227 v230
+ parameter param228 v231
+ parameter param229 v232
+ parameter param230 v233
+ parameter param231 v234
+ parameter param232 v235
+ parameter param233 v236
+ parameter param234 v237
+ parameter param235 v238
+ parameter param236 v239
+ parameter param237 v240
+ parameter param238 v241
+ parameter param239 v242
+ parameter param240 v243
+ parameter param241 v244
+ parameter param242 v245
+ parameter param243 v246
+ parameter param244 v247
+ parameter param245 v248
+ parameter param246 v249
+ parameter param247 v250
+ parameter param248 v251
+ parameter param249 v252
+ parameter param250 v253
+ parameter param251 v254
+ parameter param252 v255
+ parameter param253 v256
+ parameter param254 v257
+ parameter param255 v258
+ 0000: prologue end
+ 0000: line 9
+ 0001: line 12
+ 0001: +local v1 i int
+ 01fd: advance pc
+ 01fd: line 16
+ line = 28
+ 0202: line 28
+ line = 18
+ 0204: line 18
+ 0206: line 20
+ 0208: line 22
+ 020a: line 24
+ 020c: line 26
+ line = 16
+ 020e: line 16
+ end sequence
+ source file: "Blort.java"
diff --git a/dx/tests/122-switch-with-high-register/info.txt b/dx/tests/122-switch-with-high-register/info.txt
new file mode 100644
index 0000000..ca2a795
--- /dev/null
+++ b/dx/tests/122-switch-with-high-register/info.txt
@@ -0,0 +1,6 @@
+This test ensures that dx correctly handles switches on data in a high
+register (>v255)
+
+This test compares emitted code against a known-good (via eyeballing)
+version, so it is possible for this test to spuriously fail if other
+aspects of conversion end up altering the output in innocuous ways.
diff --git a/dx/tests/122-switch-with-high-register/run b/dx/tests/122-switch-with-high-register/run
new file mode 100644
index 0000000..2b6eb66
--- /dev/null
+++ b/dx/tests/122-switch-with-high-register/run
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+$JAVAC -d . *.java
+dx --debug --dex --dump-method=Blort.switchWithHighRegister Blort.class
+$JAVAC -g -d . *.java
+dx --debug --dex --dump-method=Blort.switchWithHighRegister Blort.class
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
index 38e6eca..809d450 100644
--- a/libdex/DexFile.h
+++ b/libdex/DexFile.h
@@ -756,7 +756,7 @@
const u2* insnsEnd = &pCode->insns[pCode->insnsSize];
// Round to four bytes.
- if ((((u4) insnsEnd) & 3) != 0) {
+ if ((((uintptr_t) insnsEnd) & 3) != 0) {
insnsEnd++;
}
@@ -809,14 +809,15 @@
DEX_INLINE const DexAnnotationSetItem* dexGetAnnotationSetItem(
const DexFile* pDexFile, u4 offset)
{
+ if (offset == 0) {
+ return NULL;
+ }
return (const DexAnnotationSetItem*) (pDexFile->baseAddr + offset);
}
/* get the class' annotation set */
DEX_INLINE const DexAnnotationSetItem* dexGetClassAnnotationSet(
const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir)
{
- if (pAnnoDir->classAnnotationsOff == 0)
- return NULL;
return dexGetAnnotationSetItem(pDexFile, pAnnoDir->classAnnotationsOff);
}
@@ -903,16 +904,19 @@
DEX_INLINE const DexAnnotationSetRefList* dexGetParameterAnnotationSetRefList(
const DexFile* pDexFile, const DexParameterAnnotationsItem* pItem)
{
- return (const DexAnnotationSetRefList*)
- (pDexFile->baseAddr + pItem->annotationsOff);
+ if (pItem->annotationsOff == 0) {
+ return NULL;
+ }
+ return (const DexAnnotationSetRefList*) (pDexFile->baseAddr + pItem->annotationsOff);
}
/* get method annotation list size */
DEX_INLINE int dexGetParameterAnnotationSetRefSize(const DexFile* pDexFile,
const DexParameterAnnotationsItem* pItem)
{
- if (pItem->annotationsOff == 0)
+ if (pItem->annotationsOff == 0) {
return 0;
+ }
return dexGetParameterAnnotationSetRefList(pDexFile, pItem)->size;
}
@@ -943,8 +947,11 @@
DEX_INLINE const DexAnnotationItem* dexGetAnnotationItem(
const DexFile* pDexFile, const DexAnnotationSetItem* pAnnoSet, u4 idx)
{
- return (const DexAnnotationItem*)
- (pDexFile->baseAddr + dexGetAnnotationOff(pAnnoSet, idx));
+ u4 offset = dexGetAnnotationOff(pAnnoSet, idx);
+ if (offset == 0) {
+ return NULL;
+ }
+ return (const DexAnnotationItem*) (pDexFile->baseAddr + offset);
}
/*
diff --git a/libdex/DexOptData.cpp b/libdex/DexOptData.cpp
index b859d63..dd41751 100644
--- a/libdex/DexOptData.cpp
+++ b/libdex/DexOptData.cpp
@@ -30,7 +30,7 @@
*/
static bool isValidPointer(const void* ptr, const void* start, const void* end)
{
- return (ptr >= start) && (ptr < end) && (((u4) ptr & 7) == 0);
+ return (ptr >= start) && (ptr < end) && (((uintptr_t) ptr & 7) == 0);
}
/* (documented in header file) */
diff --git a/libdex/DexSwapVerify.cpp b/libdex/DexSwapVerify.cpp
index 1835e9b..24a86f9 100644
--- a/libdex/DexSwapVerify.cpp
+++ b/libdex/DexSwapVerify.cpp
@@ -1842,7 +1842,7 @@
if (item->triesSize == 0) {
ptr = insns;
} else {
- if ((((u4) insns) & 3) != 0) {
+ if ((((uintptr_t) insns) & 3) != 0) {
// Four-byte alignment for the tries. Verify the spacer is a 0.
if (*insns != 0) {
ALOGE("Non-zero padding: %#x", (u4) *insns);
diff --git a/libdex/SysUtil.cpp b/libdex/SysUtil.cpp
index a412a12..456d26e 100644
--- a/libdex/SysUtil.cpp
+++ b/libdex/SysUtil.cpp
@@ -331,7 +331,7 @@
* (The address must be page-aligned, the length doesn't need to be,
* but we do need to ensure we cover the same range.)
*/
- u1* alignAddr = (u1*) ((int) addr & ~(SYSTEM_PAGE_SIZE-1));
+ u1* alignAddr = (u1*) ((uintptr_t) addr & ~(SYSTEM_PAGE_SIZE-1));
size_t alignLength = length + ((u1*) addr - alignAddr);
//ALOGI("%p/%zd --> %p/%zd", addr, length, alignAddr, alignLength);
diff --git a/tests/063-process-manager/src/Main.java b/tests/063-process-manager/src/Main.java
index c94b8ad..68bf878 100644
--- a/tests/063-process-manager/src/Main.java
+++ b/tests/063-process-manager/src/Main.java
@@ -14,7 +14,7 @@
static private void child() throws Exception {
System.out.println("spawning child");
- ProcessBuilder pb = new ProcessBuilder("/system/bin/sleep", "5");
+ ProcessBuilder pb = new ProcessBuilder("sleep", "5");
Process proc = pb.start();
Thread.sleep(1000);
checkManager();
diff --git a/tests/083-jit-regressions/expected.txt b/tests/083-jit-regressions/expected.txt
index 4b9ad5b..7f9f14c 100644
--- a/tests/083-jit-regressions/expected.txt
+++ b/tests/083-jit-regressions/expected.txt
@@ -2,3 +2,5 @@
b2302318 passes
b2487514 passes
b5884080 passes
+longDivTest passes
+longModTest passes
diff --git a/tests/083-jit-regressions/src/Main.java b/tests/083-jit-regressions/src/Main.java
index 3b596db..68bfa37 100644
--- a/tests/083-jit-regressions/src/Main.java
+++ b/tests/083-jit-regressions/src/Main.java
@@ -25,6 +25,7 @@
b2302318Test();
b2487514Test();
b5884080Test();
+ zeroTest();
}
static void b2296099Test() throws Exception {
@@ -111,13 +112,12 @@
int vA = 1;
int l = 0;
- do
- {
+ do {
int k = 0;
do
vA += 1;
while(++k < 100);
- } while(++l < 1000);
+ } while (++l < 1000);
if (vA == 100001) {
System.out.println("b5884080 passes");
}
@@ -126,6 +126,20 @@
" (expecting 100001)");
}
}
+
+ static void zeroTest() throws Exception {
+ ZeroTests zt = new ZeroTests();
+ try {
+ zt.longDivTest();
+ } catch (Throwable th) {
+ th.printStackTrace();
+ }
+ try {
+ zt.longModTest();
+ } catch (Throwable th) {
+ th.printStackTrace();
+ }
+ }
}
class SpinThread extends Thread {
diff --git a/tests/083-jit-regressions/src/ZeroTests.java b/tests/083-jit-regressions/src/ZeroTests.java
new file mode 100644
index 0000000..57ca151
--- /dev/null
+++ b/tests/083-jit-regressions/src/ZeroTests.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.Random;
+
+/**
+ * Tests long division by zero for both / and %.
+ */
+public class ZeroTests {
+ public void longDivTest() throws Exception {
+ longTest("longDivTest", true);
+ }
+
+ public void longModTest() throws Exception {
+ longTest("longModTest", false);
+ }
+
+ private static void longTest(String name, boolean divide) throws Exception {
+ // Warm up JIT.
+ for (int i = 0; i < 10000; ++i) {
+ try {
+ // We won't JIT code that hasn't completed successfully, so rhs can't be 0 here!
+ if (divide) {
+ longDiv(1, 1);
+ } else {
+ longMod(1, 1);
+ }
+ } catch (ArithmeticException expected) {
+ throw new AssertionError(name + " threw during warmup");
+ }
+ }
+
+ // Boom?
+ int catchCount = 0;
+ for (int i = 0; i < 10000; ++i) {
+ try {
+ if (divide) {
+ longDiv(1, 0);
+ } else {
+ longMod(1, 0);
+ }
+ throw new AssertionError(name + " failed to throw: " + i);
+ } catch (ArithmeticException expected) {
+ ++catchCount;
+ }
+ }
+ if (catchCount != 10000) throw new AssertionError(name + " failed: " + catchCount);
+
+ System.out.println(name + " passes");
+ }
+
+ private static long longDiv(long lhs, long rhs) {
+ return lhs / rhs;
+ }
+
+ private static long longMod(long lhs, long rhs) {
+ return lhs % rhs;
+ }
+}
diff --git a/tests/096-array-copy-concurrent-gc/expected.txt b/tests/096-array-copy-concurrent-gc/expected.txt
new file mode 100644
index 0000000..23b9dab
--- /dev/null
+++ b/tests/096-array-copy-concurrent-gc/expected.txt
@@ -0,0 +1,3 @@
+Initializing...
+Starting the test
+Test OK
diff --git a/tests/096-array-copy-concurrent-gc/info.txt b/tests/096-array-copy-concurrent-gc/info.txt
new file mode 100644
index 0000000..37dd8be
--- /dev/null
+++ b/tests/096-array-copy-concurrent-gc/info.txt
@@ -0,0 +1,2 @@
+This is a test to verify that System.arraycopy works nice together with
+the concurrent gc.
diff --git a/tests/096-array-copy-concurrent-gc/src/Main.java b/tests/096-array-copy-concurrent-gc/src/Main.java
new file mode 100644
index 0000000..c8e538b
--- /dev/null
+++ b/tests/096-array-copy-concurrent-gc/src/Main.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Running concurrent gc and doing some System.arraycopy
+ * Several threads is created in order to increase the probability
+ * of thread switches at critical points. Without creating several
+ * threads the test case usually passed even when there were bugs.
+ * Size of array and amount of garbage created is based on experimental
+ * numbers and is a tradeoff between time that the test takes when
+ * it succeeds and the probability that the test discovers a problem.
+ */
+public class Main {
+ public static void main(String args[]) {
+ new ObjectCreatorThread(true).start();
+ new ObjectCreatorThread(false).start();
+ new ObjectCreatorThread(false).start();
+ }
+
+ static class ObjectCreatorThread extends Thread {
+ boolean mDoLog;
+ public ObjectCreatorThread(boolean doLog) {
+ mDoLog = doLog;
+ }
+
+ @Override
+ public void run() {
+ new Main().stressArray(mDoLog);
+ }
+ }
+
+ Object [] array = new Object[10000];
+
+ void stressArray(boolean doLog) {
+ // We want many references in the array
+ // We also want elements close to each other to have large
+ // diff in address so lets skip every 2:nd address so it is null
+ if (doLog) {
+ System.out.println("Initializing...");
+ }
+ for (int i = 0; i < array.length; i+=2) {
+ array[i] = new String("Creating some garbage" + i);
+ }
+
+ if (doLog) {
+ System.out.println("Starting the test");
+ }
+
+ for (int j = 0; j < array.length; j++) {
+ Object obj = array[array.length - 1];
+ System.arraycopy(array, 0, array, 1, array.length - 1);
+ array[0] = obj;
+ new String("Creating some garbage" + Math.random());
+ new String("Creating some garbage" + Math.random());
+ new String("Creating some garbage" + Math.random());
+ new String("Creating some garbage" + Math.random());
+ }
+
+ for (int j = 0; j < array.length; j++) {
+ Object obj = array[0];
+ System.arraycopy(array, 1, array, 0, array.length - 1);
+ array[array.length - 1] = obj;
+ new String("Creating some garbage" + Math.random());
+ new String("Creating some garbage" + Math.random());
+ new String("Creating some garbage" + Math.random());
+ new String("Creating some garbage" + Math.random());
+ }
+
+ if (doLog) {
+ System.out.println("Test OK");
+ }
+ }
+}
diff --git a/tests/300-package-override/expected.txt b/tests/300-package-override/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/tests/300-package-override/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/tests/300-package-override/info.txt b/tests/300-package-override/info.txt
new file mode 100644
index 0000000..0ed59eb
--- /dev/null
+++ b/tests/300-package-override/info.txt
@@ -0,0 +1,2 @@
+Tests a dalvik bug where we'd allow subclasses to override package-protected
+methods.
\ No newline at end of file
diff --git a/tests/300-package-override/src/Main.java b/tests/300-package-override/src/Main.java
new file mode 100644
index 0000000..ad7eaaf
--- /dev/null
+++ b/tests/300-package-override/src/Main.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String args[]) throws Exception {
+ p1.BaseClass c = new p2.DerivedClass();
+ c.run();
+ }
+}
diff --git a/tests/300-package-override/src/p1/BaseClass.java b/tests/300-package-override/src/p1/BaseClass.java
new file mode 100644
index 0000000..1c048ac
--- /dev/null
+++ b/tests/300-package-override/src/p1/BaseClass.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package p1;
+
+public class BaseClass {
+ public void run() { foo(); }
+ void foo() { System.out.println("passed"); } // It should not be possible to override this.
+}
diff --git a/tests/300-package-override/src/p2/DerivedClass.java b/tests/300-package-override/src/p2/DerivedClass.java
new file mode 100644
index 0000000..860f50c
--- /dev/null
+++ b/tests/300-package-override/src/p2/DerivedClass.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package p2;
+
+public class DerivedClass extends p1.BaseClass {
+ void foo() { System.out.println("DerivedClass overrode package-private method!"); } // This should not override BaseClass.foo.
+}
diff --git a/tests/etc/host-run-test-jar b/tests/etc/host-run-test-jar
index d3c0fd5..c85c419 100755
--- a/tests/etc/host-run-test-jar
+++ b/tests/etc/host-run-test-jar
@@ -78,8 +78,8 @@
done
if [ "x$INTERP" = "x" ]; then
- INTERP="fast"
- msg "Using fast interpreter by default"
+ INTERP="jit"
+ msg "Using jit by default"
fi
if [ "$OPTIMIZE" = "y" ]; then
diff --git a/tests/etc/push-and-run-test-jar b/tests/etc/push-and-run-test-jar
index e2fde42..b64f6a6 100755
--- a/tests/etc/push-and-run-test-jar
+++ b/tests/etc/push-and-run-test-jar
@@ -78,8 +78,8 @@
if [ "$ZYGOTE" = "n" ]; then
if [ "x$INTERP" = "x" ]; then
- INTERP="fast"
- msg "Using fast interpreter by default"
+ INTERP="jit"
+ msg "Using jit by default"
fi
if [ "$OPTIMIZE" = "y" ]; then
diff --git a/tests/run-test b/tests/run-test
index fb758d7..406e424 100755
--- a/tests/run-test
+++ b/tests/run-test
@@ -146,8 +146,8 @@
echo ' Omitting the test name or specifying "-" will use the' \
"current directory."
echo " Runtime Options:"
- echo " --fast Use the fast interpreter (the default)."
- echo " --jit Use the jit."
+ echo " --fast Use the fast interpreter."
+ echo " --jit Use the jit (the default)."
echo " --portable Use the portable interpreter."
echo " --debug Wait for a debugger to attach."
#echo " --gdb Run under gdb; incompatible with some tests."
diff --git a/vm/Android.mk b/vm/Android.mk
index 0990260..64e4aaf 100644
--- a/vm/Android.mk
+++ b/vm/Android.mk
@@ -71,6 +71,7 @@
LOCAL_MODULE := libdvm_assert
include $(BUILD_SHARED_LIBRARY)
+ ifneq ($(dvm_arch),mips) # MIPS support for self-verification is incomplete
# Derivation #2
# Enable assert and self-verification
include $(LOCAL_PATH)/ReconfigureDvm.mk
@@ -80,6 +81,7 @@
-DWITH_SELF_VERIFICATION $(target_smp_flag)
LOCAL_MODULE := libdvm_sv
include $(BUILD_SHARED_LIBRARY)
+ endif # dvm_arch!=mips
# Derivation #3
# Compile out the JIT
@@ -90,6 +92,10 @@
LOCAL_MODULE := libdvm_interp
include $(BUILD_SHARED_LIBRARY)
+ ifeq ($(dvm_arch),x86) # For x86, we enable JIT on host too
+ # restore WITH_JIT = true for host dalvik build
+ WITH_JIT := true
+ endif # dvm_arch==x86
endif
#
@@ -106,7 +112,11 @@
# Note: HOST_ARCH_VARIANT isn't defined.
dvm_arch_variant := $(HOST_ARCH)
- WITH_JIT := false
+ # We always want the x86 JIT.
+ ifeq ($(dvm_arch),x86)
+ WITH_JIT := true
+ endif
+
include $(LOCAL_PATH)/Dvm.mk
LOCAL_SHARED_LIBRARIES += libcrypto libssl libicuuc libicui18n
diff --git a/vm/Atomic.cpp b/vm/Atomic.cpp
index f53a7e4..bd2255b 100644
--- a/vm/Atomic.cpp
+++ b/vm/Atomic.cpp
@@ -18,75 +18,41 @@
#include <cutils/atomic.h>
-/*
- * Quasi-atomic 64-bit operations, for platforms that lack the real thing.
- *
- * TODO: unify ARMv6/x86/sh implementations using the to-be-written
- * spin lock implementation. We don't want to rely on mutex innards,
- * and it would be great if all platforms were running the same code.
- */
-
-#if defined(HAVE_MACOSX_IPC)
-
-#include <libkern/OSAtomic.h>
-
-#if defined(__ppc__) \
- || defined(__PPC__) \
- || defined(__powerpc__) \
- || defined(__powerpc) \
- || defined(__POWERPC__) \
- || defined(_M_PPC) \
- || defined(__PPC)
-#define NEED_QUASIATOMICS 1
-#else
-
-int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
- volatile int64_t* addr)
-{
- return OSAtomicCompareAndSwap64Barrier(oldvalue, newvalue,
- (int64_t*)addr) == 0;
-}
-
-
-static inline int64_t dvmQuasiAtomicSwap64Body(int64_t value,
- volatile int64_t* addr)
-{
- int64_t oldValue;
- do {
- oldValue = *addr;
- } while (dvmQuasiAtomicCas64(oldValue, value, addr));
- return oldValue;
-}
-
-int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr)
-{
- return dvmQuasiAtomicSwap64Body(value, addr);
-}
-
-int64_t dvmQuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr)
-{
- int64_t oldValue;
- ANDROID_MEMBAR_STORE();
- oldValue = dvmQuasiAtomicSwap64Body(value, addr);
- /* TUNING: barriers can be avoided on some architectures */
- ANDROID_MEMBAR_FULL();
- return oldValue;
-}
-
-int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
-{
- return OSAtomicAdd64Barrier(0, addr);
-}
+#if defined(__arm__)
+#include <machine/cpu-features.h>
#endif
+/*****************************************************************************/
+
+#if defined(HAVE_MACOSX_IPC)
+#define NEED_MAC_QUASI_ATOMICS 1
+
#elif defined(__i386__) || defined(__x86_64__)
-#define NEED_QUASIATOMICS 1
+#define NEED_PTHREADS_QUASI_ATOMICS 1
-#elif __arm__
-#include <machine/cpu-features.h>
+#elif defined(__mips__)
+#define NEED_PTHREADS_QUASI_ATOMICS 1
-// Clang can not process this assembly at the moment.
+#elif defined(__arm__)
+
+// TODO: Clang can not process our inline assembly at the moment.
#if defined(__ARM_HAVE_LDREXD) && !defined(__clang__)
+#define NEED_ARM_LDREXD_QUASI_ATOMICS 1
+#else
+#define NEED_PTHREADS_QUASI_ATOMICS 1
+#endif
+
+#elif defined(__sh__)
+#define NEED_PTHREADS_QUASI_ATOMICS 1
+
+#else
+#error "Unsupported atomic operations for this platform"
+#endif
+
+/*****************************************************************************/
+
+#if NEED_ARM_LDREXD_QUASI_ATOMICS
+
static inline int64_t dvmQuasiAtomicSwap64Body(int64_t newvalue,
volatile int64_t* addr)
{
@@ -145,37 +111,95 @@
: "r" (addr));
return value;
}
+#endif
-#else
+/*****************************************************************************/
-// on the device, we implement the 64-bit atomic operations through
-// mutex locking. normally, this is bad because we must initialize
-// a pthread_mutex_t before being able to use it, and this means
-// having to do an initialization check on each function call, and
-// that's where really ugly things begin...
-//
-// BUT, as a special twist, we take advantage of the fact that in our
-// pthread library, a mutex is simply a volatile word whose value is always
-// initialized to 0. In other words, simply declaring a static mutex
-// object initializes it !
-//
+#if NEED_MAC_QUASI_ATOMICS
+
+#include <libkern/OSAtomic.h>
+
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+ volatile int64_t* addr)
+{
+ return OSAtomicCompareAndSwap64Barrier(oldvalue, newvalue,
+ (int64_t*)addr) == 0;
+}
+
+
+static inline int64_t dvmQuasiAtomicSwap64Body(int64_t value,
+ volatile int64_t* addr)
+{
+ int64_t oldValue;
+ do {
+ oldValue = *addr;
+ } while (dvmQuasiAtomicCas64(oldValue, value, addr));
+ return oldValue;
+}
+
+int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr)
+{
+ return dvmQuasiAtomicSwap64Body(value, addr);
+}
+
+int64_t dvmQuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr)
+{
+ int64_t oldValue;
+ ANDROID_MEMBAR_STORE();
+ oldValue = dvmQuasiAtomicSwap64Body(value, addr);
+ /* TUNING: barriers can be avoided on some architectures */
+ ANDROID_MEMBAR_FULL();
+ return oldValue;
+}
+
+int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
+{
+ return OSAtomicAdd64Barrier(0, addr);
+}
+#endif
+
+/*****************************************************************************/
+
+#if NEED_PTHREADS_QUASI_ATOMICS
+
+// In the absence of a better implementation, we implement the 64-bit atomic
+// operations through mutex locking.
+
// another twist is that we use a small array of mutexes to dispatch
// the contention locks from different memory addresses
-//
#include <pthread.h>
-#define SWAP_LOCK_COUNT 32U
-static pthread_mutex_t _swap_locks[SWAP_LOCK_COUNT];
+static const size_t kSwapLockCount = 32;
+static pthread_mutex_t* gSwapLocks[kSwapLockCount];
-#define SWAP_LOCK(addr) \
- &_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT]
+void dvmQuasiAtomicsStartup() {
+ for (size_t i = 0; i < kSwapLockCount; ++i) {
+ pthread_mutex_t* m = new pthread_mutex_t;
+ dvmInitMutex(m);
+ gSwapLocks[i] = m;
+ }
+}
+void dvmQuasiAtomicsShutdown() {
+ for (size_t i = 0; i < kSwapLockCount; ++i) {
+ pthread_mutex_t* m = gSwapLocks[i];
+ gSwapLocks[i] = NULL;
+ if (m != NULL) {
+ dvmDestroyMutex(m);
+ }
+ delete m;
+ }
+}
+
+static inline pthread_mutex_t* GetSwapLock(const volatile int64_t* addr) {
+ return gSwapLocks[((unsigned)(void*)(addr) >> 3U) % kSwapLockCount];
+}
int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr)
{
int64_t oldValue;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
+ pthread_mutex_t* lock = GetSwapLock(addr);
pthread_mutex_lock(lock);
@@ -196,7 +220,7 @@
volatile int64_t* addr)
{
int result;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
+ pthread_mutex_t* lock = GetSwapLock(addr);
pthread_mutex_lock(lock);
@@ -213,7 +237,7 @@
int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
{
int64_t result;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
+ pthread_mutex_t* lock = GetSwapLock(addr);
pthread_mutex_lock(lock);
result = *addr;
@@ -221,107 +245,10 @@
return result;
}
-#endif /*__ARM_HAVE_LDREXD*/
-
-/*****************************************************************************/
-#elif __sh__
-#define NEED_QUASIATOMICS 1
-
#else
-#error "Unsupported atomic operations for this platform"
-#endif
+// The other implementations don't need any special setup.
+void dvmQuasiAtomicsStartup() {}
+void dvmQuasiAtomicsShutdown() {}
-#if NEED_QUASIATOMICS
-
-/* Note that a spinlock is *not* a good idea in general
- * since they can introduce subtle issues. For example,
- * a real-time thread trying to acquire a spinlock already
- * acquired by another thread will never yeld, making the
- * CPU loop endlessly!
- *
- * However, this code is only used on the Linux simulator
- * so it's probably ok for us.
- *
- * The alternative is to use a pthread mutex, but
- * these must be initialized before being used, and
- * then you have the problem of lazily initializing
- * a mutex without any other synchronization primitive.
- *
- * TODO: these currently use sched_yield(), which is not guaranteed to
- * do anything at all. We need to use dvmIterativeSleep or a wait /
- * notify mechanism if the initial attempt fails.
- */
-
-/* global spinlock for all 64-bit quasiatomic operations */
-static int32_t quasiatomic_spinlock = 0;
-
-int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
- volatile int64_t* addr)
-{
- int result;
-
- while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
-#ifdef HAVE_WIN32_THREADS
- Sleep(0);
-#else
- sched_yield();
-#endif
- }
-
- if (*addr == oldvalue) {
- *addr = newvalue;
- result = 0;
- } else {
- result = 1;
- }
-
- android_atomic_release_store(0, &quasiatomic_spinlock);
-
- return result;
-}
-
-int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
-{
- int64_t result;
-
- while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
-#ifdef HAVE_WIN32_THREADS
- Sleep(0);
-#else
- sched_yield();
-#endif
- }
-
- result = *addr;
- android_atomic_release_store(0, &quasiatomic_spinlock);
-
- return result;
-}
-
-int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr)
-{
- int64_t result;
-
- while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
-#ifdef HAVE_WIN32_THREADS
- Sleep(0);
-#else
- sched_yield();
-#endif
- }
-
- result = *addr;
- *addr = value;
- android_atomic_release_store(0, &quasiatomic_spinlock);
-
- return result;
-}
-
-/* Same as dvmQuasiAtomicSwap64 - syscall handles barrier */
-int64_t dvmQuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr)
-{
- return dvmQuasiAtomicSwap64(value, addr);
-}
-
-#endif /*NEED_QUASIATOMICS*/
+#endif /*NEED_PTHREADS_QUASI_ATOMICS*/
diff --git a/vm/Atomic.h b/vm/Atomic.h
index 6f7100b..becbeeb 100644
--- a/vm/Atomic.h
+++ b/vm/Atomic.h
@@ -23,6 +23,9 @@
#include <cutils/atomic.h> /* use common Android atomic ops */
#include <cutils/atomic-inline.h> /* and some uncommon ones */
+void dvmQuasiAtomicsStartup();
+void dvmQuasiAtomicsShutdown();
+
/*
* NOTE: Two "quasiatomic" operations on the exact same memory address
* are guaranteed to operate atomically with respect to each other,
diff --git a/vm/Common.h b/vm/Common.h
index abab423..af31b97 100644
--- a/vm/Common.h
+++ b/vm/Common.h
@@ -102,6 +102,7 @@
struct Object;
union JValue {
+#if defined(HAVE_LITTLE_ENDIAN)
u1 z;
s1 b;
u2 c;
@@ -111,6 +112,30 @@
float f;
double d;
Object* l;
+#endif
+#if defined(HAVE_BIG_ENDIAN)
+ struct {
+ u1 _z[3];
+ u1 z;
+ };
+ struct {
+ s1 _b[3];
+ s1 b;
+ };
+ struct {
+ u2 _c;
+ u2 c;
+ };
+ struct {
+ s2 _s;
+ s2 s;
+ };
+ s4 i;
+ s8 j;
+ float f;
+ double d;
+ void* l;
+#endif
};
#define OFFSETOF_MEMBER(t, f) \
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index 4aa054d..2f53391 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -185,7 +185,7 @@
test/TestIndirectRefTable.cpp
# TODO: this is the wrong test, but what's the right one?
-ifeq ($(dvm_arch),arm)
+ifneq ($(filter arm mips,$(dvm_arch)),)
LOCAL_SRC_FILES += os/android.cpp
else
LOCAL_SRC_FILES += os/linux.cpp
@@ -199,6 +199,7 @@
alloc/Copying.cpp.arm
else
LOCAL_SRC_FILES += \
+ alloc/DlMalloc.cpp \
alloc/HeapSource.cpp \
alloc/MarkSweep.cpp.arm
endif
@@ -256,35 +257,73 @@
endif
endif
+ifeq ($(dvm_arch),mips)
+ MTERP_ARCH_KNOWN := true
+ LOCAL_C_INCLUDES += external/libffi/$(TARGET_OS)-$(TARGET_ARCH)
+ LOCAL_SHARED_LIBRARIES += libffi
+ LOCAL_SRC_FILES += \
+ arch/mips/CallO32.S \
+ arch/mips/HintsO32.cpp \
+ arch/generic/Call.cpp \
+ mterp/out/InterpC-mips.cpp \
+ mterp/out/InterpAsm-mips.S
+
+ ifeq ($(WITH_JIT),true)
+ dvm_arch_variant := mips
+ LOCAL_SRC_FILES += \
+ compiler/codegen/mips/RallocUtil.cpp \
+ compiler/codegen/mips/$(dvm_arch_variant)/Codegen.cpp \
+ compiler/codegen/mips/$(dvm_arch_variant)/CallingConvention.S \
+ compiler/codegen/mips/Assemble.cpp \
+ compiler/codegen/mips/ArchUtility.cpp \
+ compiler/codegen/mips/LocalOptimizations.cpp \
+ compiler/codegen/mips/GlobalOptimizations.cpp \
+ compiler/template/out/CompilerTemplateAsm-$(dvm_arch_variant).S
+ endif
+endif
+
ifeq ($(dvm_arch),x86)
ifeq ($(dvm_os),linux)
MTERP_ARCH_KNOWN := true
- LOCAL_CFLAGS += -DDVM_JMP_TABLE_MTERP=1
+ LOCAL_CFLAGS += -DDVM_JMP_TABLE_MTERP=1 \
+ -DMTERP_STUB
LOCAL_SRC_FILES += \
arch/$(dvm_arch_variant)/Call386ABI.S \
arch/$(dvm_arch_variant)/Hints386ABI.cpp \
mterp/out/InterpC-$(dvm_arch_variant).cpp \
mterp/out/InterpAsm-$(dvm_arch_variant).S
ifeq ($(WITH_JIT),true)
+ LOCAL_CFLAGS += -DARCH_IA32
LOCAL_SRC_FILES += \
- compiler/codegen/x86/Assemble.cpp \
- compiler/codegen/x86/ArchUtility.cpp \
- compiler/codegen/x86/ia32/Codegen.cpp \
- compiler/codegen/x86/ia32/CallingConvention.S \
- compiler/template/out/CompilerTemplateAsm-ia32.S
+ compiler/codegen/x86/LowerAlu.cpp \
+ compiler/codegen/x86/LowerConst.cpp \
+ compiler/codegen/x86/LowerMove.cpp \
+ compiler/codegen/x86/Lower.cpp \
+ compiler/codegen/x86/LowerHelper.cpp \
+ compiler/codegen/x86/LowerJump.cpp \
+ compiler/codegen/x86/LowerObject.cpp \
+ compiler/codegen/x86/AnalysisO1.cpp \
+ compiler/codegen/x86/BytecodeVisitor.cpp \
+ compiler/codegen/x86/NcgAot.cpp \
+ compiler/codegen/x86/CodegenInterface.cpp \
+ compiler/codegen/x86/LowerInvoke.cpp \
+ compiler/codegen/x86/LowerReturn.cpp \
+ compiler/codegen/x86/NcgHelper.cpp \
+ compiler/codegen/x86/LowerGetPut.cpp
+
+ # need apache harmony x86 encoder/decoder
+ LOCAL_C_INCLUDES += \
+ dalvik/vm/compiler/codegen/x86/libenc
+ LOCAL_SRC_FILES += \
+ compiler/codegen/x86/libenc/enc_base.cpp \
+ compiler/codegen/x86/libenc/dec_base.cpp \
+ compiler/codegen/x86/libenc/enc_wrapper.cpp \
+ compiler/codegen/x86/libenc/enc_tabl.cpp
+
endif
endif
endif
-ifeq ($(dvm_arch),sh)
- MTERP_ARCH_KNOWN := true
- LOCAL_SRC_FILES += \
- arch/sh/CallSH4ABI.S \
- arch/generic/Hints.cpp \
- mterp/out/InterpC-allstubs.cpp \
- mterp/out/InterpAsm-allstubs.S
-endif
-
ifeq ($(MTERP_ARCH_KNOWN),false)
# unknown architecture, try to use FFI
LOCAL_C_INCLUDES += external/libffi/$(dvm_os)-$(dvm_arch)
diff --git a/vm/DvmDex.cpp b/vm/DvmDex.cpp
index 79c81f3..035c598 100644
--- a/vm/DvmDex.cpp
+++ b/vm/DvmDex.cpp
@@ -74,7 +74,7 @@
pDvmDex->pResFields = (struct Field**)blob;
ALOGV("+++ DEX %p: allocateAux (%d+%d+%d+%d)*4 = %d bytes",
- pDvmDex, stringSizei/4, classSize/4, methodSize/4, fieldSize/4,
+ pDvmDex, stringSize/4, classSize/4, methodSize/4, fieldSize/4,
stringSize + classSize + methodSize + fieldSize);
pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE);
diff --git a/vm/Globals.h b/vm/Globals.h
index c656206..3bef865 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -155,6 +155,9 @@
ExecutionMode executionMode;
+ bool commonInit; /* whether common stubs are generated */
+ bool constInit; /* whether global constants are initialized */
+
/*
* VM init management.
*/
@@ -870,15 +873,28 @@
/* true/false: compile/reject methods specified in the -Xjitmethod list */
bool includeSelectedMethod;
+ /* true/false: compile/reject traces with offset specified in the -Xjitoffset list */
+ bool includeSelectedOffset;
+
/* Disable JIT for selected opcodes - one bit for each opcode */
char opList[(kNumPackedOpcodes+7)/8];
/* Disable JIT for selected methods */
HashTable *methodTable;
+ /* Disable JIT for selected classes */
+ HashTable *classTable;
+
+ /* Disable JIT for selected offsets */
+ unsigned int pcTable[COMPILER_PC_OFFSET_SIZE];
+ int num_entries_pcTable;
+
/* Flag to dump all compiled code */
bool printMe;
+ /* Flag to dump compiled binary code in bytes */
+ bool printBinary;
+
/* Per-process debug flag toggled when receiving a SIGUSR2 */
bool receivedSIGUSR2;
@@ -948,6 +964,10 @@
u8 maxCompilerThreadBlockGCTime;
#endif
+#if defined(ARCH_IA32)
+ JitOptLevel optLevel;
+#endif
+
/* Place arrays at the end to ease the display in gdb sessions */
/* Work order queue for compilations */
diff --git a/vm/Init.cpp b/vm/Init.cpp
index 48cc6c1..5e3711e 100644
--- a/vm/Init.cpp
+++ b/vm/Init.cpp
@@ -31,6 +31,10 @@
#include "mterp/Mterp.h"
#include "Hash.h"
+#if defined(WITH_JIT)
+#include "compiler/codegen/Optimizer.h"
+#endif
+
#define kMinHeapStartSize (1*1024*1024)
#define kMinHeapSize (2*1024*1024)
#define kMaxHeapSize (1*1024*1024*1024)
@@ -133,6 +137,9 @@
dvmFprintf(stderr, " -Xjitblocking\n");
dvmFprintf(stderr, " -Xjitmethod:signature[,signature]* "
"(eg Ljava/lang/String\\;replace)\n");
+ dvmFprintf(stderr, " -Xjitclass:classname[,classname]*\n");
+ dvmFprintf(stderr, " -Xjitoffset:offset[,offset]\n");
+ dvmFprintf(stderr, " -Xjitconfig:filename\n");
dvmFprintf(stderr, " -Xjitcheckcg\n");
dvmFprintf(stderr, " -Xjitverbose\n");
dvmFprintf(stderr, " -Xjitprofile\n");
@@ -229,16 +236,16 @@
* Returns 0 (a useless size) if "s" is malformed or specifies a low or
* non-evenly-divisible value.
*/
-static size_t parseMemOption(const char *s, size_t div)
+static size_t parseMemOption(const char* s, size_t div)
{
/* strtoul accepts a leading [+-], which we don't want,
* so make sure our string starts with a decimal digit.
*/
if (isdigit(*s)) {
- const char *s2;
+ const char* s2;
size_t val;
- val = strtoul(s, (char **)&s2, 10);
+ val = strtoul(s, (char* *)&s2, 10);
if (s2 != s) {
/* s2 should be pointing just after the number.
* If this is the end of the string, the user
@@ -549,11 +556,11 @@
#if defined(WITH_JIT)
/* Parse -Xjitop to selectively turn on/off certain opcodes for JIT */
-static void processXjitop(const char *opt)
+static void processXjitop(const char* opt)
{
if (opt[7] == ':') {
- const char *startPtr = &opt[8];
- char *endPtr = NULL;
+ const char* startPtr = &opt[8];
+ char* endPtr = NULL;
do {
long startValue, endValue;
@@ -602,15 +609,50 @@
}
}
-/* Parse -Xjitmethod to selectively turn on/off certain methods for JIT */
-static void processXjitmethod(const char *opt)
-{
- char *buf = strdup(&opt[12]);
- char *start, *end;
-
- gDvmJit.methodTable = dvmHashTableCreate(8, NULL);
-
+/* Parse -Xjitoffset to selectively turn on/off traces with certain offsets for JIT */
+static void processXjitoffset(const char* opt) {
+ gDvmJit.num_entries_pcTable = 0;
+ char* buf = strdup(opt);
+ char* start, *end;
start = buf;
+ int idx = 0;
+ do {
+ end = strchr(start, ',');
+ if (end) {
+ *end = 0;
+ }
+
+ dvmFprintf(stderr, "processXjitoffset start = %s\n", start);
+ char* tmp = strdup(start);
+ gDvmJit.pcTable[idx++] = atoi(tmp);
+ free(tmp);
+ if (idx >= COMPILER_PC_OFFSET_SIZE) {
+ dvmFprintf(stderr, "processXjitoffset: ignore entries beyond %d\n", COMPILER_PC_OFFSET_SIZE);
+ break;
+ }
+ if (end) {
+ start = end + 1;
+ } else {
+ break;
+ }
+ } while (1);
+ gDvmJit.num_entries_pcTable = idx;
+ free(buf);
+}
+
+/* Parse -Xjitmethod to selectively turn on/off certain methods for JIT */
+static void processXjitmethod(const char* opt, bool isMethod) {
+ char* buf = strdup(opt);
+
+ if (isMethod && gDvmJit.methodTable == NULL) {
+ gDvmJit.methodTable = dvmHashTableCreate(8, NULL);
+ }
+ if (!isMethod && gDvmJit.classTable == NULL) {
+ gDvmJit.classTable = dvmHashTableCreate(8, NULL);
+ }
+
+ char* start = buf;
+ char* end;
/*
* Break comma-separated method signatures and enter them into the hash
* table individually.
@@ -624,10 +666,9 @@
}
hashValue = dvmComputeUtf8Hash(start);
+ dvmHashTableLookup(isMethod ? gDvmJit.methodTable : gDvmJit.classTable,
+ hashValue, strdup(start), (HashCompareFunc) strcmp, true);
- dvmHashTableLookup(gDvmJit.methodTable, hashValue,
- strdup(start),
- (HashCompareFunc) strcmp, true);
if (end) {
start = end + 1;
} else {
@@ -636,6 +677,88 @@
} while (1);
free(buf);
}
+
+/* The format of jit_config.list:
+ EXCLUDE or INCLUDE
+ CLASS
+ prefix1 ...
+ METHOD
+ prefix 1 ...
+ OFFSET
+ index ... //each pair is a range, if pcOff falls into a range, JIT
+*/
+static int processXjitconfig(const char* opt) {
+ FILE* fp = fopen(opt, "r");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ char fLine[500];
+ bool startClass = false, startMethod = false, startOffset = false;
+ gDvmJit.num_entries_pcTable = 0;
+ int idx = 0;
+
+ while (fgets(fLine, 500, fp) != NULL) {
+ char* curLine = strtok(fLine, " \t\r\n");
+ /* handles keyword CLASS, METHOD, INCLUDE, EXCLUDE */
+ if (!strncmp(curLine, "CLASS", 5)) {
+ startClass = true;
+ startMethod = false;
+ startOffset = false;
+ continue;
+ }
+ if (!strncmp(curLine, "METHOD", 6)) {
+ startMethod = true;
+ startClass = false;
+ startOffset = false;
+ continue;
+ }
+ if (!strncmp(curLine, "OFFSET", 6)) {
+ startOffset = true;
+ startMethod = false;
+ startClass = false;
+ continue;
+ }
+ if (!strncmp(curLine, "EXCLUDE", 7)) {
+ gDvmJit.includeSelectedMethod = false;
+ continue;
+ }
+ if (!strncmp(curLine, "INCLUDE", 7)) {
+ gDvmJit.includeSelectedMethod = true;
+ continue;
+ }
+ if (!startMethod && !startClass && !startOffset) {
+ continue;
+ }
+
+ int hashValue = dvmComputeUtf8Hash(curLine);
+ if (startMethod) {
+ if (gDvmJit.methodTable == NULL) {
+ gDvmJit.methodTable = dvmHashTableCreate(8, NULL);
+ }
+ dvmHashTableLookup(gDvmJit.methodTable, hashValue,
+ strdup(curLine),
+ (HashCompareFunc) strcmp, true);
+ } else if (startClass) {
+ if (gDvmJit.classTable == NULL) {
+ gDvmJit.classTable = dvmHashTableCreate(8, NULL);
+ }
+ dvmHashTableLookup(gDvmJit.classTable, hashValue,
+ strdup(curLine),
+ (HashCompareFunc) strcmp, true);
+ } else if (startOffset) {
+ int tmpInt = atoi(curLine);
+ gDvmJit.pcTable[idx++] = tmpInt;
+ if (idx >= COMPILER_PC_OFFSET_SIZE) {
+ printf("processXjitoffset: ignore entries beyond %d\n", COMPILER_PC_OFFSET_SIZE);
+ break;
+ }
+ }
+ }
+ gDvmJit.num_entries_pcTable = idx;
+ fclose(fp);
+ return 0;
+}
#endif
/*
@@ -954,8 +1077,14 @@
#ifdef WITH_JIT
} else if (strncmp(argv[i], "-Xjitop", 7) == 0) {
processXjitop(argv[i]);
- } else if (strncmp(argv[i], "-Xjitmethod", 11) == 0) {
- processXjitmethod(argv[i]);
+ } else if (strncmp(argv[i], "-Xjitmethod:", 12) == 0) {
+ processXjitmethod(argv[i] + strlen("-Xjitmethod:"), true);
+ } else if (strncmp(argv[i], "-Xjitclass:", 11) == 0) {
+ processXjitmethod(argv[i] + strlen("-Xjitclass:"), false);
+ } else if (strncmp(argv[i], "-Xjitoffset:", 12) == 0) {
+ processXjitoffset(argv[i] + strlen("-Xjitoffset:"));
+ } else if (strncmp(argv[i], "-Xjitconfig:", 12) == 0) {
+ processXjitconfig(argv[i] + strlen("-Xjitconfig:"));
} else if (strncmp(argv[i], "-Xjitblocking", 13) == 0) {
gDvmJit.blockingMode = true;
} else if (strncmp(argv[i], "-Xjitthreshold:", 15) == 0) {
@@ -968,6 +1097,8 @@
gDvmJit.checkCallGraph = true;
/* Need to enable blocking mode due to stack crawling */
gDvmJit.blockingMode = true;
+ } else if (strncmp(argv[i], "-Xjitdumpbin", 12) == 0) {
+ gDvmJit.printBinary = true;
} else if (strncmp(argv[i], "-Xjitverbose", 12) == 0) {
gDvmJit.printMe = true;
} else if (strncmp(argv[i], "-Xjitprofile", 12) == 0) {
@@ -1099,6 +1230,15 @@
*/
#if defined(WITH_JIT)
gDvm.executionMode = kExecutionModeJit;
+ gDvmJit.num_entries_pcTable = 0;
+ gDvmJit.includeSelectedMethod = false;
+ gDvmJit.includeSelectedOffset = false;
+ gDvmJit.methodTable = NULL;
+ gDvmJit.classTable = NULL;
+
+ gDvm.constInit = false;
+ gDvm.commonInit = false;
+ gDvmJit.disableOpt = 1<<kMethodInlining;
#else
gDvm.executionMode = kExecutionModeInterpFast;
#endif
@@ -1250,6 +1390,7 @@
/*
* Initialize components.
*/
+ dvmQuasiAtomicsStartup();
if (!dvmAllocTrackerStartup()) {
return "dvmAllocTrackerStartup failed";
}
@@ -1745,6 +1886,8 @@
freeAssertionCtrl();
+ dvmQuasiAtomicsShutdown();
+
/*
* We want valgrind to report anything we forget to free as "definitely
* lost". If there's a pointer in the global chunk, it would be reported
diff --git a/vm/InlineNative.cpp b/vm/InlineNative.cpp
index 80d522a..00c1e95 100644
--- a/vm/InlineNative.cpp
+++ b/vm/InlineNative.cpp
@@ -732,51 +732,41 @@
"Lorg/apache/harmony/dalvik/NativeTestTarget;",
"emptyInlineMethod", "()V" },
- { javaLangString_charAt,
- "Ljava/lang/String;", "charAt", "(I)C" },
- { javaLangString_compareTo,
- "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" },
- { javaLangString_equals,
- "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" },
- { javaLangString_fastIndexOf_II,
- "Ljava/lang/String;", "fastIndexOf", "(II)I" },
- { javaLangString_isEmpty,
- "Ljava/lang/String;", "isEmpty", "()Z" },
- { javaLangString_length,
- "Ljava/lang/String;", "length", "()I" },
+ { javaLangString_charAt, "Ljava/lang/String;", "charAt", "(I)C" },
+ { javaLangString_compareTo, "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" },
+ { javaLangString_equals, "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" },
+ { javaLangString_fastIndexOf_II, "Ljava/lang/String;", "fastIndexOf", "(II)I" },
+ { javaLangString_isEmpty, "Ljava/lang/String;", "isEmpty", "()Z" },
+ { javaLangString_length, "Ljava/lang/String;", "length", "()I" },
- { javaLangMath_abs_int,
- "Ljava/lang/Math;", "abs", "(I)I" },
- { javaLangMath_abs_long,
- "Ljava/lang/Math;", "abs", "(J)J" },
- { javaLangMath_abs_float,
- "Ljava/lang/Math;", "abs", "(F)F" },
- { javaLangMath_abs_double,
- "Ljava/lang/Math;", "abs", "(D)D" },
- { javaLangMath_min_int,
- "Ljava/lang/Math;", "min", "(II)I" },
- { javaLangMath_max_int,
- "Ljava/lang/Math;", "max", "(II)I" },
- { javaLangMath_sqrt,
- "Ljava/lang/Math;", "sqrt", "(D)D" },
- { javaLangMath_cos,
- "Ljava/lang/Math;", "cos", "(D)D" },
- { javaLangMath_sin,
- "Ljava/lang/Math;", "sin", "(D)D" },
+ { javaLangMath_abs_int, "Ljava/lang/Math;", "abs", "(I)I" },
+ { javaLangMath_abs_long, "Ljava/lang/Math;", "abs", "(J)J" },
+ { javaLangMath_abs_float, "Ljava/lang/Math;", "abs", "(F)F" },
+ { javaLangMath_abs_double, "Ljava/lang/Math;", "abs", "(D)D" },
+ { javaLangMath_min_int, "Ljava/lang/Math;", "min", "(II)I" },
+ { javaLangMath_max_int, "Ljava/lang/Math;", "max", "(II)I" },
+ { javaLangMath_sqrt, "Ljava/lang/Math;", "sqrt", "(D)D" },
+ { javaLangMath_cos, "Ljava/lang/Math;", "cos", "(D)D" },
+ { javaLangMath_sin, "Ljava/lang/Math;", "sin", "(D)D" },
- { javaLangFloat_floatToIntBits,
- "Ljava/lang/Float;", "floatToIntBits", "(F)I" },
- { javaLangFloat_floatToRawIntBits,
- "Ljava/lang/Float;", "floatToRawIntBits", "(F)I" },
- { javaLangFloat_intBitsToFloat,
- "Ljava/lang/Float;", "intBitsToFloat", "(I)F" },
+ { javaLangFloat_floatToIntBits, "Ljava/lang/Float;", "floatToIntBits", "(F)I" },
+ { javaLangFloat_floatToRawIntBits, "Ljava/lang/Float;", "floatToRawIntBits", "(F)I" },
+ { javaLangFloat_intBitsToFloat, "Ljava/lang/Float;", "intBitsToFloat", "(I)F" },
- { javaLangDouble_doubleToLongBits,
- "Ljava/lang/Double;", "doubleToLongBits", "(D)J" },
- { javaLangDouble_doubleToRawLongBits,
- "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J" },
- { javaLangDouble_longBitsToDouble,
- "Ljava/lang/Double;", "longBitsToDouble", "(J)D" },
+ { javaLangDouble_doubleToLongBits, "Ljava/lang/Double;", "doubleToLongBits", "(D)J" },
+ { javaLangDouble_doubleToRawLongBits, "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J" },
+ { javaLangDouble_longBitsToDouble, "Ljava/lang/Double;", "longBitsToDouble", "(J)D" },
+
+ // These are implemented exactly the same in Math and StrictMath,
+ // so we can make the StrictMath calls fast too. Note that this
+ // isn't true in general!
+ { javaLangMath_abs_int, "Ljava/lang/StrictMath;", "abs", "(I)I" },
+ { javaLangMath_abs_long, "Ljava/lang/StrictMath;", "abs", "(J)J" },
+ { javaLangMath_abs_float, "Ljava/lang/StrictMath;", "abs", "(F)F" },
+ { javaLangMath_abs_double, "Ljava/lang/StrictMath;", "abs", "(D)D" },
+ { javaLangMath_min_int, "Ljava/lang/StrictMath;", "min", "(II)I" },
+ { javaLangMath_max_int, "Ljava/lang/StrictMath;", "max", "(II)I" },
+ { javaLangMath_sqrt, "Ljava/lang/StrictMath;", "sqrt", "(D)D" },
};
/*
diff --git a/vm/InlineNative.h b/vm/InlineNative.h
index 101ddd1..fe14f8b 100644
--- a/vm/InlineNative.h
+++ b/vm/InlineNative.h
@@ -53,7 +53,7 @@
};
/*
- * Must be kept in sync w/ gDvmInlineOpsTable in InlineNative.c
+ * Must be kept in sync w/ gDvmInlineOpsTable in InlineNative.cpp
*
* You should also add a test to libcore's IntrinsicTest.
*/
@@ -80,6 +80,13 @@
INLINE_DOUBLE_TO_LONG_BITS = 19,
INLINE_DOUBLE_TO_RAW_LONG_BITS = 20,
INLINE_LONG_BITS_TO_DOUBLE = 21,
+ INLINE_STRICT_MATH_ABS_INT = 22,
+ INLINE_STRICT_MATH_ABS_LONG = 23,
+ INLINE_STRICT_MATH_ABS_FLOAT = 24,
+ INLINE_STRICT_MATH_ABS_DOUBLE = 25,
+ INLINE_STRICT_MATH_MIN_INT = 26,
+ INLINE_STRICT_MATH_MAX_INT = 27,
+ INLINE_STRICT_MATH_SQRT = 28,
};
/*
diff --git a/vm/Jni.cpp b/vm/Jni.cpp
index 8593505..6decaed 100644
--- a/vm/Jni.cpp
+++ b/vm/Jni.cpp
@@ -2306,7 +2306,7 @@
if (obj != NULL && !dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
obj->clazz->descriptor, obj,
- arrayObj->obj.clazz->descriptor, arrayObj);
+ arrayObj->clazz->descriptor, arrayObj);
dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
return;
}
diff --git a/vm/Misc.cpp b/vm/Misc.cpp
index 1299c22..1f01c2f 100644
--- a/vm/Misc.cpp
+++ b/vm/Misc.cpp
@@ -512,7 +512,12 @@
*/
bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime)
{
- const int minSleep = 10000;
+ /*
+ * Minimum sleep is one millisecond, it is important to keep this value
+ * low to ensure short GC pauses since dvmSuspendAllThreads() uses this
+ * function.
+ */
+ const int minSleep = 1000;
u8 curTime;
int curDelay;
@@ -694,8 +699,10 @@
char* cp = strchr(lineBuf, ')');
if (cp == NULL)
goto parse_fail;
- cp++;
- for (i = 2; i < 13; i++) {
+ cp += 2;
+ pData->state = *cp++;
+
+ for (i = 3; i < 13; i++) {
cp = strchr(cp+1, ' ');
if (cp == NULL)
goto parse_fail;
diff --git a/vm/Misc.h b/vm/Misc.h
index 86e0a71..4c42576 100644
--- a/vm/Misc.h
+++ b/vm/Misc.h
@@ -300,6 +300,7 @@
* Get some per-thread stats from /proc/self/task/N/stat.
*/
struct ProcStatData {
+ char state; /* process state, e.g. 'R', 'S', 'D' */
unsigned long utime; /* number of jiffies scheduled in user mode */
unsigned long stime; /* number of jiffies scheduled in kernel mode */
int processor; /* number of CPU that last executed thread */
diff --git a/vm/ReconfigureDvm.mk b/vm/ReconfigureDvm.mk
index dd13482..34eb0a4 100644
--- a/vm/ReconfigureDvm.mk
+++ b/vm/ReconfigureDvm.mk
@@ -19,15 +19,16 @@
dvm_arch := $(TARGET_ARCH)
dvm_arch_variant := $(TARGET_ARCH_VARIANT)
-# for now, disable x86-atom variant
-ifeq ($(dvm_arch_variant),x86-atom)
-dvm_arch_variant := x86
-endif
-
include $(LOCAL_PATH)/Dvm.mk
LOCAL_SHARED_LIBRARIES += liblog libcutils libnativehelper libz libdl libcorkscrew
+ifeq ($(HAVE_SELINUX),true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_SHARED_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
LOCAL_STATIC_LIBRARIES += libdex
LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
diff --git a/vm/Sync.cpp b/vm/Sync.cpp
index 8a3803e..810107d 100644
--- a/vm/Sync.cpp
+++ b/vm/Sync.cpp
@@ -276,6 +276,11 @@
size_t len;
int fd;
+ /* When a thread is being destroyed it is normal that the frame depth is zero */
+ if (self->interpSave.curFrame == NULL) {
+ return;
+ }
+
saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
meth = saveArea->method;
cp = eventBuffer;
diff --git a/vm/Thread.cpp b/vm/Thread.cpp
index d82f15a..7f6f583 100644
--- a/vm/Thread.cpp
+++ b/vm/Thread.cpp
@@ -3236,9 +3236,9 @@
/* show what we got */
dvmPrintDebugMessage(target,
- " | schedstat=( %s ) utm=%lu stm=%lu core=%d\n",
- schedstatBuf, procStatData.utime, procStatData.stime,
- procStatData.processor);
+ " | state=%c schedstat=( %s ) utm=%lu stm=%lu core=%d\n",
+ procStatData.state, schedstatBuf, procStatData.utime,
+ procStatData.stime, procStatData.processor);
#endif
}
@@ -3344,7 +3344,15 @@
dumpSchedStat(target, thread->systemTid);
- /* grab the native stack, if possible */
+ /*
+ * Grab the native stack, if possible.
+ *
+ * The native thread is still running, even if the Dalvik side is
+ * suspended. This means the thread can move itself out of NATIVE state
+ * while we're in here, shifting to SUSPENDED after a brief moment at
+ * RUNNING. At that point the native stack isn't all that interesting,
+ * though, so if we fail to dump it there's little lost.
+ */
if (thread->status == THREAD_NATIVE || thread->status == THREAD_VMWAIT) {
dvmDumpNativeStack(target, thread->systemTid);
}
@@ -3540,15 +3548,25 @@
* The target thread can continue to execute between the two signals.
* (The first just causes debuggerd to attach to it.)
*/
- ALOGD("threadid=%d: sending two SIGSTKFLTs to threadid=%d (tid=%d) to"
- " cause debuggerd dump",
- dvmThreadSelf()->threadId, thread->threadId, thread->systemTid);
- killResult = pthread_kill(thread->handle, SIGSTKFLT);
+#ifdef SIGSTKFLT
+#define SIG SIGSTKFLT
+#define SIGNAME "SIGSTKFLT"
+#elif defined(SIGEMT)
+#define SIG SIGEMT
+#define SIGNAME "SIGEMT"
+#else
+#error No signal available for dvmNukeThread
+#endif
+
+ ALOGD("threadid=%d: sending two " SIGNAME "s to threadid=%d (tid=%d) to"
+ " cause debuggerd dump",
+ dvmThreadSelf()->threadId, thread->threadId, thread->systemTid);
+ killResult = pthread_kill(thread->handle, SIG);
if (killResult != 0) {
ALOGD("NOTE: pthread_kill #1 failed: %s", strerror(killResult));
}
usleep(2 * 1000 * 1000); // TODO: timed-wait until debuggerd attaches
- killResult = pthread_kill(thread->handle, SIGSTKFLT);
+ killResult = pthread_kill(thread->handle, SIG);
if (killResult != 0) {
ALOGD("NOTE: pthread_kill #2 failed: %s", strerror(killResult));
}
diff --git a/vm/Thread.h b/vm/Thread.h
index 7f14ce5..8deef6e 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -92,7 +92,7 @@
#ifndef DVM_NO_ASM_INTERP
void* curHandlerTable;
#else
- void* unused;
+ int32_t unused1;
#endif
} ctl;
};
@@ -303,6 +303,10 @@
pthread_mutex_t callbackMutex;
SafePointCallback callback;
void* callbackArg;
+
+#if defined(ARCH_IA32) && defined(WITH_JIT)
+ u4 spillRegion[MAX_SPILL_JIT_IA];
+#endif
};
/* start point for an internal thread; mimics pthread args */
diff --git a/vm/alloc/Copying.cpp b/vm/alloc/Copying.cpp
index ad5b8fc..77cdac3 100644
--- a/vm/alloc/Copying.cpp
+++ b/vm/alloc/Copying.cpp
@@ -731,9 +731,8 @@
/* do nothing */
}
-void dvmHeapSourceWalk(void (*callback)(const void *chunkptr, size_t chunklen,
- const void *userptr, size_t userlen,
- void *arg),
+void dvmHeapSourceWalk(void(*callback)(void* start, void* end,
+ size_t used_bytes, void* arg),
void *arg)
{
assert(!"implemented");
diff --git a/vm/alloc/DdmHeap.cpp b/vm/alloc/DdmHeap.cpp
index ffe4cae..45b0a26 100644
--- a/vm/alloc/DdmHeap.cpp
+++ b/vm/alloc/DdmHeap.cpp
@@ -23,6 +23,7 @@
#include "alloc/Heap.h"
#include "alloc/HeapInternal.h"
#include "alloc/DdmHeap.h"
+#include "alloc/DlMalloc.h"
#include "alloc/HeapSource.h"
#define DEFAULT_HEAP_ID 1
@@ -173,6 +174,7 @@
((u1)((((kind) & 0x7) << 3) | ((solidity) & 0x7)))
struct HeapChunkContext {
+ void* startOfNextMemoryChunk;
u1 *buf;
u1 *p;
u1 *pieceLenField;
@@ -205,36 +207,25 @@
ctx->pieceLenField = NULL;
}
-static void heap_chunk_callback(const void *chunkptr, size_t chunklen,
- const void *userptr, size_t userlen, void *arg)
-{
- HeapChunkContext *ctx = (HeapChunkContext *)arg;
- u1 state;
-
- UNUSED_PARAMETER(userlen);
-
- assert((chunklen & (ALLOCATION_UNIT_SIZE-1)) == 0);
-
+static void append_chunk(HeapChunkContext *ctx, u1 state, void* ptr, size_t length) {
/* Make sure there's enough room left in the buffer.
* We need to use two bytes for every fractional 256
- * allocation units used by the chunk.
+ * allocation units used by the chunk and 17 bytes for
+ * any header.
*/
{
- size_t needed = (((chunklen/ALLOCATION_UNIT_SIZE + 255) / 256) * 2);
+ size_t needed = (((length/ALLOCATION_UNIT_SIZE + 255) / 256) * 2) + 17;
size_t bytesLeft = ctx->bufLen - (size_t)(ctx->p - ctx->buf);
if (bytesLeft < needed) {
flush_hpsg_chunk(ctx);
}
-
bytesLeft = ctx->bufLen - (size_t)(ctx->p - ctx->buf);
if (bytesLeft < needed) {
- ALOGW("chunk is too big to transmit (chunklen=%zd, %zd bytes)",
- chunklen, needed);
+ ALOGW("chunk is too big to transmit (length=%zd, %zd bytes)",
+ length, needed);
return;
}
}
-
-//TODO: notice when there's a gap and start a new heap, or at least a new range.
if (ctx->needHeader) {
/*
* Start a new HPSx chunk.
@@ -247,7 +238,7 @@
*ctx->p++ = 8;
/* [u4]: virtual address of segment start */
- set4BE(ctx->p, (uintptr_t)chunkptr); ctx->p += 4;
+ set4BE(ctx->p, (uintptr_t)ptr); ctx->p += 4;
/* [u4]: offset of this piece (relative to the virtual address) */
set4BE(ctx->p, 0); ctx->p += 4;
@@ -261,80 +252,123 @@
ctx->needHeader = false;
}
-
- /* Determine the type of this chunk.
- */
- if (userptr == NULL) {
- /* It's a free chunk.
- */
- state = HPSG_STATE(SOLIDITY_FREE, 0);
- } else {
- const Object *obj = (const Object *)userptr;
- /* If we're looking at the native heap, we'll just return
- * (SOLIDITY_HARD, KIND_NATIVE) for all allocated chunks
- */
- bool native = ctx->type == CHUNK_TYPE("NHSG");
-
- /* It's an allocated chunk. Figure out what it is.
- */
-//TODO: if ctx.merge, see if this chunk is different from the last chunk.
-// If it's the same, we should combine them.
- if (!native && dvmIsValidObject(obj)) {
- ClassObject *clazz = obj->clazz;
- if (clazz == NULL) {
- /* The object was probably just created
- * but hasn't been initialized yet.
- */
- state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
- } else if (dvmIsTheClassClass(clazz)) {
- state = HPSG_STATE(SOLIDITY_HARD, KIND_CLASS_OBJECT);
- } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
- if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
- state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
- } else {
- switch (clazz->elementClass->primitiveType) {
- case PRIM_BOOLEAN:
- case PRIM_BYTE:
- state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_1);
- break;
- case PRIM_CHAR:
- case PRIM_SHORT:
- state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_2);
- break;
- case PRIM_INT:
- case PRIM_FLOAT:
- state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
- break;
- case PRIM_DOUBLE:
- case PRIM_LONG:
- state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_8);
- break;
- default:
- assert(!"Unknown GC heap object type");
- state = HPSG_STATE(SOLIDITY_HARD, KIND_UNKNOWN);
- break;
- }
- }
- } else {
- state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
- }
- } else {
- obj = NULL; // it's not actually an object
- state = HPSG_STATE(SOLIDITY_HARD, KIND_NATIVE);
- }
- }
-
/* Write out the chunk description.
*/
- chunklen /= ALLOCATION_UNIT_SIZE; // convert to allocation units
- ctx->totalAllocationUnits += chunklen;
- while (chunklen > 256) {
+ length /= ALLOCATION_UNIT_SIZE; // convert to allocation units
+ ctx->totalAllocationUnits += length;
+ while (length > 256) {
*ctx->p++ = state | HPSG_PARTIAL;
*ctx->p++ = 255; // length - 1
- chunklen -= 256;
+ length -= 256;
}
*ctx->p++ = state;
- *ctx->p++ = chunklen - 1;
+ *ctx->p++ = length - 1;
+}
+
+/*
+ * Called by dlmalloc_inspect_all. If used_bytes != 0 then start is
+ * the start of a malloc-ed piece of memory of size used_bytes. If
+ * start is 0 then start is the beginning of any free space not
+ * including dlmalloc's book keeping and end the start of the next
+ * dlmalloc chunk. Regions purely containing book keeping don't
+ * callback.
+ */
+static void heap_chunk_callback(void* start, void* end, size_t used_bytes,
+ void* arg)
+{
+ u1 state;
+ HeapChunkContext *ctx = (HeapChunkContext *)arg;
+ UNUSED_PARAMETER(end);
+
+ if (used_bytes == 0) {
+ if (start == NULL) {
+ // Reset for start of new heap.
+ ctx->startOfNextMemoryChunk = NULL;
+ flush_hpsg_chunk(ctx);
+ }
+ // Only process in use memory so that free region information
+ // also includes dlmalloc book keeping.
+ return;
+ }
+
+ /* If we're looking at the native heap, we'll just return
+ * (SOLIDITY_HARD, KIND_NATIVE) for all allocated chunks
+ */
+ bool native = ctx->type == CHUNK_TYPE("NHSG");
+
+ if (ctx->startOfNextMemoryChunk != NULL) {
+ // Transmit any pending free memory. Native free memory of
+ // over kMaxFreeLen could be because of the use of mmaps, so
+ // don't report. If not free memory then start a new segment.
+ bool flush = true;
+ if (start > ctx->startOfNextMemoryChunk) {
+ const size_t kMaxFreeLen = 2 * SYSTEM_PAGE_SIZE;
+ void* freeStart = ctx->startOfNextMemoryChunk;
+ void* freeEnd = start;
+ size_t freeLen = (char*)freeEnd - (char*)freeStart;
+ if (!native || freeLen < kMaxFreeLen) {
+ append_chunk(ctx, HPSG_STATE(SOLIDITY_FREE, 0),
+ freeStart, freeLen);
+ flush = false;
+ }
+ }
+ if (flush) {
+ ctx->startOfNextMemoryChunk = NULL;
+ flush_hpsg_chunk(ctx);
+ }
+ }
+ const Object *obj = (const Object *)start;
+
+ /* It's an allocated chunk. Figure out what it is.
+ */
+//TODO: if ctx.merge, see if this chunk is different from the last chunk.
+// If it's the same, we should combine them.
+ if (!native && dvmIsValidObject(obj)) {
+ ClassObject *clazz = obj->clazz;
+ if (clazz == NULL) {
+ /* The object was probably just created
+ * but hasn't been initialized yet.
+ */
+ state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
+ } else if (dvmIsTheClassClass(clazz)) {
+ state = HPSG_STATE(SOLIDITY_HARD, KIND_CLASS_OBJECT);
+ } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
+ if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
+ state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
+ } else {
+ switch (clazz->elementClass->primitiveType) {
+ case PRIM_BOOLEAN:
+ case PRIM_BYTE:
+ state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_1);
+ break;
+ case PRIM_CHAR:
+ case PRIM_SHORT:
+ state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_2);
+ break;
+ case PRIM_INT:
+ case PRIM_FLOAT:
+ state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
+ break;
+ case PRIM_DOUBLE:
+ case PRIM_LONG:
+ state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_8);
+ break;
+ default:
+ assert(!"Unknown GC heap object type");
+ state = HPSG_STATE(SOLIDITY_HARD, KIND_UNKNOWN);
+ break;
+ }
+ }
+ } else {
+ state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
+ }
+ } else {
+ obj = NULL; // it's not actually an object
+ state = HPSG_STATE(SOLIDITY_HARD, KIND_NATIVE);
+ }
+ append_chunk(ctx, state, start, used_bytes + HEAP_SOURCE_CHUNK_OVERHEAD);
+ ctx->startOfNextMemoryChunk =
+ (char*)start + used_bytes + HEAP_SOURCE_CHUNK_OVERHEAD;
}
enum HpsgWhen {
@@ -353,8 +387,6 @@
*/
#define HPSx_CHUNK_SIZE (16384 - 16)
-extern "C" void dlmalloc_walk_heap(void(*)(const void*, size_t, const void*, size_t, void*),void*);
-
static void walkHeap(bool merge, bool native)
{
HeapChunkContext ctx;
@@ -380,7 +412,7 @@
ctx.p = ctx.buf;
ctx.needHeader = true;
if (native) {
- dlmalloc_walk_heap(heap_chunk_callback, (void *)&ctx);
+ dlmalloc_inspect_all(heap_chunk_callback, (void*)&ctx);
} else {
dvmHeapSourceWalk(heap_chunk_callback, (void *)&ctx);
}
diff --git a/vm/alloc/DlMalloc.cpp b/vm/alloc/DlMalloc.cpp
new file mode 100644
index 0000000..1571801
--- /dev/null
+++ b/vm/alloc/DlMalloc.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DlMalloc.h"
+
+#include <stdint.h>
+#include "Common.h"
+
+/* Dalvik specific morecore implementation defined in HeapSource.cpp. */
+#define MORECORE(x) dvmHeapSourceMorecore(m, x)
+extern void* dvmHeapSourceMorecore(void* mspace, intptr_t increment);
+
+/* Custom heap error handling. */
+#define PROCEED_ON_ERROR 0
+static void heap_error(const char* msg, const char* function, void* p);
+#define CORRUPTION_ERROR_ACTION(m) \
+ heap_error("HEAP MEMORY CORRUPTION", __FUNCTION__, NULL)
+#define USAGE_ERROR_ACTION(m,p) \
+ heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p)
+
+/*
+ * Ugly inclusion of C file so that Dalvik specific #defines configure
+ * dlmalloc for our use for mspaces (regular dlmalloc is still declared
+ * in bionic).
+ */
+#include "../../../bionic/libc/upstream-dlmalloc/malloc.c"
+
+
+static void heap_error(const char* msg, const char* function, void* p) {
+ ALOG(LOG_FATAL, LOG_TAG, "@@@ ABORTING: DALVIK: %s IN %s addr=%p", msg,
+ function, p);
+ /* So that we can get a memory dump around p */
+ *((int **) 0xdeadbaad) = (int *) p;
+}
diff --git a/vm/alloc/DlMalloc.h b/vm/alloc/DlMalloc.h
new file mode 100644
index 0000000..f076656
--- /dev/null
+++ b/vm/alloc/DlMalloc.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DALVIK_VM_ALLOC_DLMALLOC_H_
+#define DALVIK_VM_ALLOC_DLMALLOC_H_
+
+/* Configure dlmalloc for mspaces. */
+#define HAVE_MMAP 0
+#define HAVE_MREMAP 0
+#define HAVE_MORECORE 1
+#define MSPACES 1
+#define NO_MALLINFO 1
+#define ONLY_MSPACES 1
+#define MALLOC_INSPECT_ALL 1
+
+/* Include the proper definitions. */
+#include "../../../bionic/libc/upstream-dlmalloc/malloc.h"
+
+/*
+ * Define dlmalloc routines from bionic that cannot be included
+ * directly because of redefining symbols from the include above.
+ */
+extern "C" void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
+ void* arg);
+extern "C" int dlmalloc_trim(size_t);
+extern "C" void* dlmem2chunk(void* mem);
+
+#endif // DALVIK_VM_ALLOC_DLMALLOC_H_
diff --git a/vm/alloc/Heap.cpp b/vm/alloc/Heap.cpp
index 1d06dfe..9bbe8a5 100644
--- a/vm/alloc/Heap.cpp
+++ b/vm/alloc/Heap.cpp
@@ -179,17 +179,6 @@
{
void *ptr;
- /* Don't try too hard if there's no way the allocation is
- * going to succeed. We have to collect SoftReferences before
- * throwing an OOME, though.
- */
- if (size >= gDvm.heapGrowthLimit) {
- ALOGW("%zd byte allocation exceeds the %zd byte maximum heap size",
- size, gDvm.heapGrowthLimit);
- ptr = NULL;
- goto collect_soft_refs;
- }
-
//TODO: figure out better heuristics
// There will be a lot of churn if someone allocates a bunch of
// big objects in a row, and we hit the frag case each time.
@@ -215,17 +204,13 @@
* lock, wait for the GC to complete, and retrying allocating.
*/
dvmWaitForConcurrentGcToComplete();
- ptr = dvmHeapSourceAlloc(size);
- if (ptr != NULL) {
- return ptr;
- }
+ } else {
+ /*
+ * Try a foreground GC since a concurrent GC is not currently running.
+ */
+ gcForMalloc(false);
}
- /*
- * Another failure. Our thread was starved or there may be too
- * many live objects. Try a foreground GC. This will have no
- * effect if the concurrent GC is already running.
- */
- gcForMalloc(false);
+
ptr = dvmHeapSourceAlloc(size);
if (ptr != NULL) {
return ptr;
@@ -255,7 +240,6 @@
* been collected and cleared before throwing an OOME.
*/
//TODO: wait for the finalizers from the previous GC to finish
-collect_soft_refs:
LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation",
size);
gcForMalloc(true);
@@ -713,8 +697,9 @@
* suspend when the GC thread calls dvmUnlockHeap before dvmResumeAllThreads,
* but there's no risk of deadlock.)
*/
-void dvmWaitForConcurrentGcToComplete()
+bool dvmWaitForConcurrentGcToComplete()
{
+ bool waited = gDvm.gcHeap->gcRunning;
Thread *self = dvmThreadSelf();
assert(self != NULL);
u4 start = dvmGetRelativeTimeMsec();
@@ -724,5 +709,8 @@
dvmChangeStatus(self, oldStatus);
}
u4 end = dvmGetRelativeTimeMsec();
- ALOGD("WAIT_FOR_CONCURRENT_GC blocked %ums", end - start);
+ if (end - start > 0) {
+ ALOGD("WAIT_FOR_CONCURRENT_GC blocked %ums", end - start);
+ }
+ return waited;
}
diff --git a/vm/alloc/Heap.h b/vm/alloc/Heap.h
index 9875951..19e48cd 100644
--- a/vm/alloc/Heap.h
+++ b/vm/alloc/Heap.h
@@ -92,7 +92,7 @@
* re-acquires the heap lock. After returning, no garbage collection
* will be in progress and the heap lock will be held by the caller.
*/
-void dvmWaitForConcurrentGcToComplete(void);
+bool dvmWaitForConcurrentGcToComplete(void);
/*
* Returns true iff <obj> points to a valid allocated object.
diff --git a/vm/alloc/HeapSource.cpp b/vm/alloc/HeapSource.cpp
index 2815577..cd2f4df 100644
--- a/vm/alloc/HeapSource.cpp
+++ b/vm/alloc/HeapSource.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <cutils/mspace.h>
#include <stdint.h>
#include <sys/mman.h>
#include <errno.h>
@@ -22,16 +21,13 @@
#define SIZE_MAX UINT_MAX // TODO: get SIZE_MAX from stdint.h
#include "Dalvik.h"
+#include "alloc/DlMalloc.h"
#include "alloc/Heap.h"
#include "alloc/HeapInternal.h"
#include "alloc/HeapSource.h"
#include "alloc/HeapBitmap.h"
#include "alloc/HeapBitmapInlines.h"
-// TODO: find a real header file for these.
-extern "C" int dlmalloc_trim(size_t);
-extern "C" void dlmalloc_walk_free_pages(void(*)(void*, void*, void*), void*);
-
static void snapIdealFootprint();
static void setIdealFootprint(size_t max);
static size_t getMaximumSize(const HeapSource *hs);
@@ -97,6 +93,12 @@
* The highest address of this heap, exclusive.
*/
char *limit;
+
+ /*
+ * If the heap has an mspace, the current high water mark in
+ * allocations requested via dvmHeapSourceMorecore.
+ */
+ char *brk;
};
struct HeapSource {
@@ -201,7 +203,7 @@
if (isSoftLimited(hs)) {
return hs->softLimit;
} else {
- return mspace_max_allowed_footprint(hs2heap(hs)->msp);
+ return mspace_footprint_limit(hs2heap(hs)->msp);
}
}
@@ -258,7 +260,7 @@
{
assert(heap->bytesAllocated < mspace_footprint(heap->msp));
- heap->bytesAllocated += mspace_usable_size(heap->msp, ptr) +
+ heap->bytesAllocated += mspace_usable_size(ptr) +
HEAP_SOURCE_CHUNK_OVERHEAD;
heap->objectsAllocated++;
HeapSource* hs = gDvm.gcHeap->heapSource;
@@ -269,7 +271,7 @@
static void countFree(Heap *heap, const void *ptr, size_t *numBytes)
{
- size_t delta = mspace_usable_size(heap->msp, ptr) + HEAP_SOURCE_CHUNK_OVERHEAD;
+ size_t delta = mspace_usable_size(ptr) + HEAP_SOURCE_CHUNK_OVERHEAD;
assert(delta > 0);
if (delta < heap->bytesAllocated) {
heap->bytesAllocated -= delta;
@@ -286,38 +288,65 @@
static HeapSource *gHs = NULL;
-static mspace createMspace(void *base, size_t startSize, size_t maximumSize)
+static mspace createMspace(void* begin, size_t morecoreStart, size_t startingSize)
{
- /* Create an unlocked dlmalloc mspace to use as
- * a heap source.
- *
- * We start off reserving startSize / 2 bytes but
- * letting the heap grow to startSize. This saves
- * memory in the case where a process uses even less
- * than the starting size.
- */
- LOGV_HEAP("Creating VM heap of size %zu", startSize);
+ // Clear errno to allow strerror on error.
errno = 0;
-
- mspace msp = create_contiguous_mspace_with_base(startSize/2,
- maximumSize, /*locked=*/false, base);
+ // Allow access to inital pages that will hold mspace.
+ mprotect(begin, morecoreStart, PROT_READ | PROT_WRITE);
+ // Create mspace using our backing storage starting at begin and with a footprint of
+ // morecoreStart. Don't use an internal dlmalloc lock. When morecoreStart bytes of memory are
+ // exhausted morecore will be called.
+ mspace msp = create_mspace_with_base(begin, morecoreStart, false /*locked*/);
if (msp != NULL) {
- /* Don't let the heap grow past the starting size without
- * our intervention.
- */
- mspace_set_max_allowed_footprint(msp, startSize);
+ // Do not allow morecore requests to succeed beyond the starting size of the heap.
+ mspace_set_footprint_limit(msp, startingSize);
} else {
- /* There's no guarantee that errno has meaning when the call
- * fails, but it often does.
- */
- LOGE_HEAP("Can't create VM heap of size (%zu,%zu): %s",
- startSize/2, maximumSize, strerror(errno));
+ ALOGE("create_mspace_with_base failed %s", strerror(errno));
}
-
return msp;
}
/*
+ * Service request from DlMalloc to increase heap size.
+ */
+void* dvmHeapSourceMorecore(void* mspace, intptr_t increment)
+{
+ Heap* heap = NULL;
+ for (size_t i = 0; i < gHs->numHeaps; i++) {
+ if (gHs->heaps[i].msp == mspace) {
+ heap = &gHs->heaps[i];
+ break;
+ }
+ }
+ if (heap == NULL) {
+ ALOGE("Failed to find heap for mspace %p", mspace);
+ dvmAbort();
+ }
+ char* original_brk = heap->brk;
+ if (increment != 0) {
+ char* new_brk = original_brk + increment;
+ if (increment > 0) {
+ // Should never be asked to increase the allocation beyond the capacity of the space.
+ // Enforced by mspace_set_footprint_limit.
+ assert(new_brk <= heap->limit);
+ mprotect(original_brk, increment, PROT_READ | PROT_WRITE);
+ } else {
+ // Should never be asked for negative footprint (ie before base).
+ assert(original_brk + increment > heap->base);
+ // Advise we don't need the pages and protect them.
+ size_t size = -increment;
+ madvise(new_brk, size, MADV_DONTNEED);
+ mprotect(new_brk, size, PROT_NONE);
+ }
+ // Update brk.
+ heap->brk = new_brk;
+ }
+ return original_brk;
+}
+
+const size_t kInitialMorecoreStart = SYSTEM_PAGE_SIZE;
+/*
* Add the initial heap. Returns false if the initial heap was
* already added to the heap source.
*/
@@ -332,7 +361,8 @@
hs->heaps[0].maximumSize = maximumSize;
hs->heaps[0].concurrentStartBytes = SIZE_MAX;
hs->heaps[0].base = hs->heapBase;
- hs->heaps[0].limit = hs->heapBase + hs->heaps[0].maximumSize;
+ hs->heaps[0].limit = hs->heapBase + maximumSize;
+ hs->heaps[0].brk = hs->heapBase + kInitialMorecoreStart;
hs->numHeaps = 1;
return true;
}
@@ -359,8 +389,7 @@
* Heap storage comes from a common virtual memory reservation.
* The new heap will start on the page after the old heap.
*/
- void *sbrk0 = contiguous_mspace_sbrk0(hs->heaps[0].msp);
- char *base = (char *)ALIGN_UP_TO_PAGE_SIZE(sbrk0);
+ char *base = hs->heaps[0].brk;
size_t overhead = base - hs->heaps[0].base;
assert(((size_t)hs->heaps[0].base & (SYSTEM_PAGE_SIZE - 1)) == 0);
@@ -370,12 +399,13 @@
overhead, hs->maximumSize);
return false;
}
-
+ size_t morecoreStart = SYSTEM_PAGE_SIZE;
heap.maximumSize = hs->growthLimit - overhead;
heap.concurrentStartBytes = HEAP_MIN_FREE - CONCURRENT_START;
heap.base = base;
heap.limit = heap.base + heap.maximumSize;
- heap.msp = createMspace(base, HEAP_MIN_FREE, hs->maximumSize - overhead);
+ heap.brk = heap.base + morecoreStart;
+ heap.msp = createMspace(base, morecoreStart, HEAP_MIN_FREE);
if (heap.msp == NULL) {
return false;
}
@@ -384,8 +414,7 @@
*/
hs->heaps[0].maximumSize = overhead;
hs->heaps[0].limit = base;
- mspace msp = hs->heaps[0].msp;
- mspace_set_max_allowed_footprint(msp, mspace_footprint(msp));
+ mspace_set_footprint_limit(hs->heaps[0].msp, overhead);
/* Put the new heap in the list, at heaps[0].
* Shift existing heaps down.
@@ -530,7 +559,7 @@
/* Create an unlocked dlmalloc mspace to use as
* a heap source.
*/
- msp = createMspace(base, startSize, maximumSize);
+ msp = createMspace(base, kInitialMorecoreStart, startSize);
if (msp == NULL) {
goto fail;
}
@@ -610,6 +639,9 @@
assert(gDvm.zygote);
if (!gDvm.newZygoteHeapAllocated) {
+ /* Ensure heaps are trimmed to minimize footprint pre-fork.
+ */
+ trimHeaps();
/* Create a new heap for post-fork zygote allocations. We only
* try once, even if it fails.
*/
@@ -657,6 +689,25 @@
}
/*
+ * Returns a high water mark, between base and limit all objects must have been
+ * allocated.
+ */
+void *dvmHeapSourceGetLimit()
+{
+ HeapSource *hs = gHs;
+ void *max_brk = hs->heaps[0].brk;
+
+#ifndef NDEBUG
+ for (size_t i = 1; i < hs->numHeaps; i++) {
+ Heap *const heap = &hs->heaps[i];
+ void *heap_brk = heap->brk;
+ assert (max_brk > heap_brk);
+ }
+#endif
+ return max_brk;
+}
+
+/*
* Returns the requested value. If the per-heap stats are requested, fill
* them as well.
*
@@ -677,10 +728,11 @@
switch (spec) {
case HS_FOOTPRINT:
- value = mspace_footprint(heap->msp);
+ value = heap->brk - heap->base;
+ assert(value == mspace_footprint(heap->msp));
break;
case HS_ALLOWED_FOOTPRINT:
- value = mspace_max_allowed_footprint(heap->msp);
+ value = mspace_footprint_limit(heap->msp);
break;
case HS_BYTES_ALLOCATED:
value = heap->bytesAllocated;
@@ -837,14 +889,14 @@
*/
size_t max = heap->maximumSize;
- mspace_set_max_allowed_footprint(heap->msp, max);
+ mspace_set_footprint_limit(heap->msp, max);
void* ptr = dvmHeapSourceAlloc(n);
/* Shrink back down as small as possible. Our caller may
* readjust max_allowed to a more appropriate value.
*/
- mspace_set_max_allowed_footprint(heap->msp,
- mspace_footprint(heap->msp));
+ mspace_set_footprint_limit(heap->msp,
+ mspace_footprint(heap->msp));
return ptr;
}
@@ -923,41 +975,14 @@
// mspace_free, but on the other heaps we only do some
// accounting.
if (heap == gHs->heaps) {
- // mspace_merge_objects takes two allocated objects, and
- // if the second immediately follows the first, will merge
- // them, returning a larger object occupying the same
- // memory. This is a local operation, and doesn't require
- // dlmalloc to manipulate any freelists. It's pretty
- // inexpensive compared to free().
-
- // ptrs is an array of objects all in memory order, and if
- // client code has been allocating lots of short-lived
- // objects, this is likely to contain runs of objects all
- // now garbage, and thus highly amenable to this optimization.
-
- // Unroll the 0th iteration around the loop below,
- // countFree ptrs[0] and initializing merged.
- assert(ptrs[0] != NULL);
- assert(ptr2heap(gHs, ptrs[0]) == heap);
- countFree(heap, ptrs[0], &numBytes);
- void *merged = ptrs[0];
- for (size_t i = 1; i < numPtrs; i++) {
- assert(merged != NULL);
+ // Count freed objects.
+ for (size_t i = 0; i < numPtrs; i++) {
assert(ptrs[i] != NULL);
- assert((intptr_t)merged < (intptr_t)ptrs[i]);
assert(ptr2heap(gHs, ptrs[i]) == heap);
countFree(heap, ptrs[i], &numBytes);
- // Try to merge. If it works, merged now includes the
- // memory of ptrs[i]. If it doesn't, free merged, and
- // see if ptrs[i] starts a new run of adjacent
- // objects to merge.
- if (mspace_merge_objects(msp, merged, ptrs[i]) == NULL) {
- mspace_free(msp, merged);
- merged = ptrs[i];
- }
}
- assert(merged != NULL);
- mspace_free(msp, merged);
+ // Bulk free ptrs.
+ mspace_bulk_free(msp, ptrs, numPtrs);
} else {
// This is not an 'active heap'. Only do the accounting.
for (size_t i = 0; i < numPtrs; i++) {
@@ -977,7 +1002,7 @@
{
HS_BOILERPLATE();
- return (dvmHeapBitmapCoversAddress(&gHs->liveBits, ptr));
+ return (dvmHeapSourceGetBase() <= ptr) && (ptr <= dvmHeapSourceGetLimit());
}
/*
@@ -1024,7 +1049,7 @@
Heap* heap = ptr2heap(gHs, ptr);
if (heap != NULL) {
- return mspace_usable_size(heap->msp, ptr);
+ return mspace_usable_size(ptr);
}
return 0;
}
@@ -1122,13 +1147,13 @@
if (softLimit < currentHeapSize) {
/* Don't let the heap grow any more, and impose a soft limit.
*/
- mspace_set_max_allowed_footprint(msp, currentHeapSize);
+ mspace_set_footprint_limit(msp, currentHeapSize);
hs->softLimit = softLimit;
} else {
/* Let the heap grow to the requested max, and remove any
* soft limit, if set.
*/
- mspace_set_max_allowed_footprint(msp, softLimit);
+ mspace_set_footprint_limit(msp, softLimit);
hs->softLimit = SIZE_MAX;
}
}
@@ -1284,17 +1309,22 @@
* Return free pages to the system.
* TODO: move this somewhere else, especially the native heap part.
*/
-static void releasePagesInRange(void *start, void *end, void *nbytes)
+static void releasePagesInRange(void* start, void* end, size_t used_bytes,
+ void* releasedBytes)
{
- /* Linux requires that the madvise() start address is page-aligned.
- * We also align the end address.
- */
- start = (void *)ALIGN_UP_TO_PAGE_SIZE(start);
- end = (void *)((size_t)end & ~(SYSTEM_PAGE_SIZE - 1));
- if (start < end) {
- size_t length = (char *)end - (char *)start;
- madvise(start, length, MADV_DONTNEED);
- *(size_t *)nbytes += length;
+ if (used_bytes == 0) {
+ /*
+ * We have a range of memory we can try to madvise()
+ * back. Linux requires that the madvise() start address is
+ * page-aligned. We also align the end address.
+ */
+ start = (void *)ALIGN_UP_TO_PAGE_SIZE(start);
+ end = (void *)((size_t)end & ~(SYSTEM_PAGE_SIZE - 1));
+ if (end > start) {
+ size_t length = (char *)end - (char *)start;
+ madvise(start, length, MADV_DONTNEED);
+ *(size_t *)releasedBytes += length;
+ }
}
}
@@ -1310,20 +1340,17 @@
for (size_t i = 0; i < hs->numHeaps; i++) {
Heap *heap = &hs->heaps[i];
- /* Return the wilderness chunk to the system.
- */
+ /* Return the wilderness chunk to the system. */
mspace_trim(heap->msp, 0);
- /* Return any whole free pages to the system.
- */
- mspace_walk_free_pages(heap->msp, releasePagesInRange, &heapBytes);
+ /* Return any whole free pages to the system. */
+ mspace_inspect_all(heap->msp, releasePagesInRange, &heapBytes);
}
- /* Same for the native heap.
- */
+ /* Same for the native heap. */
dlmalloc_trim(0);
size_t nativeBytes = 0;
- dlmalloc_walk_free_pages(releasePagesInRange, &nativeBytes);
+ dlmalloc_inspect_all(releasePagesInRange, &nativeBytes);
LOGD_HEAP("madvised %zd (GC) + %zd (native) = %zd total bytes",
heapBytes, nativeBytes, heapBytes + nativeBytes);
@@ -1333,9 +1360,8 @@
* Walks over the heap source and passes every allocated and
* free chunk to the callback.
*/
-void dvmHeapSourceWalk(void(*callback)(const void *chunkptr, size_t chunklen,
- const void *userptr, size_t userlen,
- void *arg),
+void dvmHeapSourceWalk(void(*callback)(void* start, void* end,
+ size_t used_bytes, void* arg),
void *arg)
{
HS_BOILERPLATE();
@@ -1345,7 +1371,8 @@
//TODO: do this in address order
HeapSource *hs = gHs;
for (size_t i = hs->numHeaps; i > 0; --i) {
- mspace_walk_heap(hs->heaps[i-1].msp, callback, arg);
+ mspace_inspect_all(hs->heaps[i-1].msp, callback, arg);
+ callback(NULL, NULL, 0, arg); // Indicate end of a heap.
}
}
diff --git a/vm/alloc/HeapSource.h b/vm/alloc/HeapSource.h
index 66f2a6a..e1f6820 100644
--- a/vm/alloc/HeapSource.h
+++ b/vm/alloc/HeapSource.h
@@ -22,7 +22,6 @@
/* dlmalloc uses one size_t per allocated chunk.
*/
#define HEAP_SOURCE_CHUNK_OVERHEAD (1 * sizeof (size_t))
-#define HEAP_SOURCE_WORST_CHUNK_OVERHEAD (32 * sizeof (size_t))
/* The largest number of separate heaps we can handle.
*/
@@ -93,6 +92,12 @@
void *dvmHeapSourceGetBase(void);
/*
+ * Returns a high water mark, between base and limit all objects must have been
+ * allocated.
+ */
+void *dvmHeapSourceGetLimit(void);
+
+/*
* Returns the requested value. If the per-heap stats are requested, fill
* them as well.
*/
@@ -157,9 +162,8 @@
* Walks over the heap source and passes every allocated and
* free chunk to the callback.
*/
-void dvmHeapSourceWalk(void(*callback)(const void *chunkptr, size_t chunklen,
- const void *userptr, size_t userlen,
- void *arg),
+void dvmHeapSourceWalk(void(*callback)(void* start, void* end,
+ size_t used_bytes, void* arg),
void *arg);
/*
* Gets the number of heaps available in the heap source.
diff --git a/vm/alloc/MarkSweep.cpp b/vm/alloc/MarkSweep.cpp
index d4f4669..268d880 100644
--- a/vm/alloc/MarkSweep.cpp
+++ b/vm/alloc/MarkSweep.cpp
@@ -560,7 +560,7 @@
footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
base = &h->cardTableBase[0];
- limit = dvmCardFromAddr((u1 *)dvmHeapSourceGetBase() + footprint);
+ limit = dvmCardFromAddr((u1 *)dvmHeapSourceGetLimit());
assert(limit <= &h->cardTableBase[h->cardTableLength]);
ptr = base;
diff --git a/vm/analysis/CodeVerify.cpp b/vm/analysis/CodeVerify.cpp
index 4a0d3d7..56a9fbd 100644
--- a/vm/analysis/CodeVerify.cpp
+++ b/vm/analysis/CodeVerify.cpp
@@ -3737,7 +3737,7 @@
if (instr == kPackedSwitchSignature ||
instr == kSparseSwitchSignature ||
instr == kArrayDataSignature ||
- (instr == OP_NOP &&
+ (instr == OP_NOP && (insnIdx + 1 < insnsSize) &&
(meth->insns[insnIdx+1] == kPackedSwitchSignature ||
meth->insns[insnIdx+1] == kSparseSwitchSignature ||
meth->insns[insnIdx+1] == kArrayDataSignature)))
diff --git a/vm/arch/generic/Call.cpp b/vm/arch/generic/Call.cpp
index ed239d4..3d7cbef 100644
--- a/vm/arch/generic/Call.cpp
+++ b/vm/arch/generic/Call.cpp
@@ -47,6 +47,14 @@
}
}
+/* We will call this generic function if there are no hints */
+#ifdef __mips__
+#define dvmPlatformInvoke dvmPlatformInvokeFFI
+
+extern "C" void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo,
+ int argc, const u4* argv, const char* signature, void* func, JValue* pResult);
+#endif
+
/*
* Call "func" with the specified arguments.
*
diff --git a/vm/arch/mips/CallO32.S b/vm/arch/mips/CallO32.S
new file mode 100644
index 0000000..e436d1e
--- /dev/null
+++ b/vm/arch/mips/CallO32.S
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+/*
+ * JNI method invocation. This is used to call a C/C++ JNI method. The
+ * argument list has to be pushed onto the native stack according to
+ * local calling conventions.
+ *
+ * This version supports the MIPS O32 ABI.
+ */
+
+/*
+Function prototype:
+
+void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
+ const u4* argv, const char* signature, void* func, JValue* pReturn)
+
+The method we are calling has the form:
+
+ return_type func(JNIEnv* pEnv, ClassObject* clazz, ...)
+ -or-
+ return_type func(JNIEnv* pEnv, Object* this, ...)
+
+We receive a collection of 32-bit values which correspond to arguments from
+the interpreter (e.g. float occupies one, double occupies two). It's up to
+us to convert these into local calling conventions.
+
+Please notice that argc in dvmPlatformInvoke does NOT include pEnv and clazz/this.
+*/
+
+ .text
+ .align 2
+ .globl dvmPlatformInvoke
+ .ent dvmPlatformInvoke
+/*
+ * On entry:
+ * a0 JNIEnv (can be left alone)
+ * a1 clazz (NULL for virtual method calls, non-NULL for static)
+ * a2 argInfo
+ * a3 argc (number of 32-bit values in argv)
+ * MIPS reservers 16 bytes on stack even if the first 4 args are passed by
+ * reg a0-a3. That's different from ARM.
+ * [sp + 16] argv
+ * [sp + 20] short signature
+ * [sp + 24] func
+ * [sp + 28] pReturn
+ *
+ * For a virtual method call, the "this" reference is in argv[0].
+ *
+ * argInfo (32-bit int) layout:
+ * SRRRLLLL FFFFFFFF FFFFFFFF FFFFFFFF
+ *
+ * S - if set, do things the hard way (scan the signature)
+ * R - return type enumeration, really only important for hardware FP
+ * L - number of double-words (64 bits!) of storage required on stack (0-30 words)
+ * F - pad flag -- if set, write a pad word to the stack
+ *
+ * With this arrangement we can efficiently push up to 24 words of arguments
+ * onto the stack. Anything requiring more than that -- which should happen
+ * rarely to never -- can do the slow signature scan.
+ *
+ * (We could pack the Fs more efficiently -- we know we never push two pads
+ * in a row, and the first word can never be a pad -- but there's really
+ * no need for it.)
+ *
+ * NOTE: if the called function has more than 4 words of arguments, gdb
+ * will not be able to unwind the stack past this method. The only way
+ * around this is to convince gdb to respect an explicit frame pointer.
+ */
+
+ /* Stack:
+ * High
+ * ____________
+ * |__28______| pReturn
+ * |__24______| func
+ * |__20______| short signature
+ * |__16______| argv
+ * |__12______| reserved (a3: argc)
+ * |__8_______| reserved (a2: arg)
+ * |__4_______| reserved (a1: clazz)
+ *__sp on entry_->_|__0_______|_reserved (a0: JNIenv)
+ * |__________| saved ra
+ * |__________| saved fp
+ * |__________| saved s0
+ * |__________| spare
+ * |__________| saved s2
+ *"framepointer"->_|__________| pad for 8 bytes aligned
+ * |__________| other argv or pad
+ * |__________| other argv or pad
+ * |__________| other argv or pad
+ * |__________| other argv or pad
+ * |__________| other argv or pad
+ * |__________| other argv or pad
+ * |__________| reserved for a3
+ * |__________| reserved for a2
+ * |__________| reserved for a1
+ *_____new sp___-> |__________| reserved for a0
+ * (new sp: sp when call native method)
+ */
+
+ /* Register usage:
+ *
+ * s0: pReturn
+ * s2: Return type
+ * These registers should be saved to and restored from stack.
+ *
+ * t0: argv
+ * t9: func
+ * These registers do not need to be saved.
+ *
+ * We put the stack size into register s1 because we can not know the size
+ * of stack at the beginning. This size can be calculated with the help
+ * of hints in jniarginfo.
+ *
+ */
+
+dvmPlatformInvoke:
+ .set noreorder
+ .cpload $t9
+ .set reorder
+
+ /* Do we have arg padding flags in "argInfo"? Check bit 31 */
+ bltz $a2,.Lno_arginfo
+
+ /* Fast path. We have hints. */
+ /* save fp and ra to stack */
+#define FSIZE 24
+ subu $sp,FSIZE
+ sw $ra,20($sp)
+ sw $fp,16($sp)
+ sw $s0,12($sp)
+ sw $s2,4($sp)
+ move $fp,$sp
+
+ lw $t0,FSIZE+16($sp) /* t0 <- argv */
+ lw $t9,FSIZE+24($sp) /* t9 <- func */
+ lw $s0,FSIZE+28($sp) /* s0 <- pReturn */
+
+ /* Is the method static? */
+ bnez $a1,1f
+ /* Not static: a1 <- *argv++ ("this"), argc-- */
+ lw $a1,($t0)
+ addiu $t0,4
+ addiu $a3,-1
+1:
+ /* expand the stack for args */
+ srl $s2,$a2,28 /* s2 <- returnType */
+ srl $t1,$a2,21
+ andi $t1,0x78 /* t1 <- stackSize in bytes */
+
+ addiu $t1,16 /* include space for a0/a1/a2/a3 */
+ subu $sp,$t1
+ addiu $t1,$sp,8
+
+ /*
+ * t0 :argv
+ * t1 :sp+8(first arg position in stack except pEnv and clazz/this)
+ * a2 :argInfo
+ * a3 :argc
+ * sp :new stack bottom
+ */
+
+ /* first two args or one args and pad */
+ blez $a3,.Largs_done
+ lw $t2,($t0)
+ addiu $t0,4
+ addiu $a3,-1
+ sw $t2,($t1)
+ addiu $t1,4
+ srl $a2,1
+ blez $a3,.Largs_done
+
+ andi $t3,$a2,0x1 /* the second position is a pad? */
+ bnez $t3,.Lpad0
+
+ lw $t2,($t0)
+ addiu $t0,4
+ addiu $a3,-1
+ sw $t2,($t1)
+.Lpad0:
+ addiu $t1,4
+ srl $a2,1
+ blez $a3,.Largs_done
+
+.Lloop1:
+ /* copy other args
+ * $fp: sp top for args
+ * $t1: sp for next arg
+ */
+ beq $t1,$fp,.Largs_done
+ andi $t3,$a2,0x1
+ srl $a2,1
+ bnez $t3,.Lpad
+ lw $t2,($t0)
+ addiu $t0,4
+ sw $t2,($t1)
+.Lpad:
+ addiu $t1,4
+ b .Lloop1
+
+.Largs_done:
+
+ /*
+ * We have copied args into stacks. Then copy argv[0]/argv[1] into
+ * reg a2/a3. You may find that if argv[0] is 32 bits and argv[1]
+ * is 64 bits, then we do not need to set reg a3 since it is a pad.
+ * However, copy a3 from argv is harmless. We do not need to set
+ * a0(pEnv)/a1(clazz/this) since they are already there.
+ */
+
+ /*
+ * sp: new stack
+ * s0: pReturn
+ * s2: Return type
+ *
+ */
+ lw $a2,8($sp)
+ lw $a3,12($sp)
+
+ /* Linux/PIC needs $t9 points to function address.
+ * call the function
+ */
+ jalr $t9
+
+ /* function call return */
+ /* 1. check the return type
+ * 2. if the return type is not DALVIK_JNI_RETURN_VOID then copy v0/v1
+ * to pReturn
+ */
+ beqz $s2,.Lend /* don't set result if return type is void */
+
+#ifdef __mips_hard_float
+ mfc1 $t0,$f0 /* Get float ($f0) or double ($f1$f0) result */
+ mfc1 $t1,$f1
+ sltiu $t2,$s2,3 /* set t2 if return type is float or double */
+#ifdef HAVE_LITTLE_ENDIAN
+ /* Note: for little endian, the double result is in $v1:$v0 and float result is in $v0 */
+ movn $v0,$t0,$t2 /* If the result type is float or double overwrite $v1/$v0 */
+ movn $v1,$t1,$t2
+#else
+ /* Note: for big endian, the double result is in $v0:$v1 and float result is in $v0 */
+ movn $v1,$t0,$t2 /* If the result type is float or double overwrite $v0/$v1 */
+ movn $v0,$t1,$t2
+ sltiu $t3,$s2,2 /* set t3 if return type is float */
+ movn $v0,$t0,$t3 /* If the result type is float overwrite $v0 */
+#endif
+#endif
+
+ /* Store the result */
+ sw $v0,0($s0)
+ sw $v1,4($s0)
+
+.Lend:
+ /* restore saved registers */
+ move $sp,$fp
+ lw $ra,20($sp)
+ lw $fp,16($sp)
+ lw $s0,12($sp)
+ lw $s2,4($sp)
+ addiu $sp,FSIZE
+ jr $ra
+
+/* Slow path - just tail call the generic routine */
+.Lno_arginfo:
+
+ la $t9,dvmPlatformInvokeFFI
+ j $t9
+
+.end dvmPlatformInvoke
diff --git a/vm/arch/mips/HintsO32.cpp b/vm/arch/mips/HintsO32.cpp
new file mode 100644
index 0000000..77fdfd4
--- /dev/null
+++ b/vm/arch/mips/HintsO32.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+/*
+ * JNI method invocation. This is used to call a C/C++ JNI method. The
+ * argument list has to be pushed onto the native stack according to
+ * local calling conventions.
+ *
+ * This version supports the MIPS O32 ABI.
+ */
+
+/* TODO: this is candidate for consolidation of similar code from ARM. */
+
+#include "Dalvik.h"
+#include "libdex/DexClass.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/stat.h>
+
+
+/*
+ * The class loader will associate with each method a 32-bit info word
+ * (jniArgInfo) to support JNI calls. The high order 4 bits of this word
+ * are the same for all targets, while the lower 28 are used for hints to
+ * allow accelerated JNI bridge transfers.
+ *
+ * jniArgInfo (32-bit int) layout:
+ *
+ * SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
+ *
+ * S - if set, ignore the hints and do things the hard way (scan signature)
+ * R - return-type enumeration
+ * H - target-specific hints (see below for details)
+ *
+ * This function produces mips-specific hints - specifically a description
+ * of padding required to keep all 64-bit parameters properly aligned.
+ *
+ * MIPS JNI hint format(Same as ARM)
+ *
+ * LLLL FFFFFFFF FFFFFFFF FFFFFFFF
+ *
+ * L - number of double-words of storage required on the stack (0-30 words)
+ * F - pad flag -- if set, the stack increases 8 bytes, else the stack increases 4 bytes
+ * after copying 32 bits args into stack. (little different from ARM)
+ *
+ * If there are too many arguments to construct valid hints, this function will
+ * return a result with the S bit set.
+ */
+u4 dvmPlatformInvokeHints(const DexProto* proto)
+{
+
+ const char* sig = dexProtoGetShorty(proto);
+ int padFlags, jniHints;
+ char sigByte;
+ int stackOffset, padMask, hints;
+
+ stackOffset = padFlags = 0;
+ padMask = 0x00000001;
+
+ /* Skip past the return type */
+ sig++;
+
+ while (true) {
+ sigByte = *(sig++);
+
+ if (sigByte == '\0')
+ break;
+
+ if (sigByte == 'D' || sigByte == 'J') {
+ if ((stackOffset & 1) != 0) {
+ padFlags |= padMask;
+ stackOffset++;
+ padMask <<= 1;
+ }
+ stackOffset += 2;
+ padMask <<= 2;
+ } else {
+ stackOffset++;
+ padMask <<= 1;
+ }
+ }
+
+ jniHints = 0;
+
+ if (stackOffset > DALVIK_JNI_COUNT_SHIFT) {
+ /* too big for "fast" version */
+ jniHints = DALVIK_JNI_NO_ARG_INFO;
+ } else {
+ assert((padFlags & (0xffffffff << DALVIK_JNI_COUNT_SHIFT)) == 0);
+ /*
+ * StackOffset includes the space for a2/a3. However we have reserved
+ * 16 bytes on stack in CallO32.S, so we should subtract 2 from stackOffset.
+ */
+ stackOffset -= 2;
+ if (stackOffset < 0)
+ stackOffset = 0;
+ jniHints |= ((stackOffset+1) / 2) << DALVIK_JNI_COUNT_SHIFT;
+ jniHints |= padFlags;
+ }
+
+ return jniHints;
+}
diff --git a/vm/arch/sh/CallSH4ABI.S b/vm/arch/sh/CallSH4ABI.S
deleted file mode 100644
index f8b2ddc..0000000
--- a/vm/arch/sh/CallSH4ABI.S
+++ /dev/null
@@ -1,400 +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.
- */
-/*
- * Invoking JNI native method via SH4 ABI.
- * This inplementation follows the spec found in following URL.
- * http://www.ecos.sourceware.org/docs-1.3.1/ref/gnupro-ref/sh/SH_ch01.html#pgfId-461254
-
- * This version supports SH4A little endian.
- */
- .text
- .align 4
- .type dvmPlatformInvoke, #function
- .globl dvmPlatformInvoke
-
-/*
- * @param r4 void* pEnv (used as scrach after invoking method)
- * @param r5 ClassObject* clazz
- * @param r6 int argInfo
- * @param r7 int argc
- * @param r15[0] const u4 * argv
- * @param r15[1] const char * shorty
- * @param r15[2] void * func
- * @param r15[3] JValue * pReturn
- *
- * @remark r0,r1 Scratch before invoking method.
- * Return value after invoking method.
- * @remark r2 shorty pointer
- * @remark r3 argv pointer before invoking method.
- * pReturn after invoking method.
- * @remark r8-11 Don't touch.
- * @remark r12 status of r5-7
- * @remark r13 status of fr4-11
- * @remark r14 Keep stack pointer.
- */
-dvmPlatformInvoke:
- ## save preserved regsiters
- mov.l r14, @-r15
- mov r15, r14
- add #4, r14 /* r14 = original r15 = stack pointer */
- mov.l r13, @-r15
- mov.l r12, @-r15
- sts.l pr, @-r15
-
- # fetch arguments
- mov.l @r14, r3 /* argv */
- mov.l @(4,r14), r2 /* shorty for argumnets */
- mov #1, r0 /* shorty's 1st byte specify ret value type. */
- add r0, r2
-
-### initialize local variables
-
- ## r12 ... status of r6, and r7
- ## bit 1 << 0 : if r6 is available, it contains 1.
- ## bit 1 << 1 : if r7 is available, it contains 1.
- ## Note : r4 is always used to pass pEnv.
- ## r5 is always used for clazz or object
- mov #3, r12 /* b0000-0111 : r5-7 avialble. */
-
- ## r13 ... status of fr4-fr11
- ## bit 1 << 0 : if fr4 is available, it contains 1.
- ## bit 1 << 1 : if fr5 is available, it contains 1.
- ## ...
- ## bit 1 << 7 : if fr11 is available, it contains 1.
- mov #0xFF, r13 /* b1111-1111 : fr4-11 avialble. */
-
-### put arguments
-
- ## ... keep pEnv in r4 as is.
-
- ## check clazz
- mov #0, r0
- cmp/eq r0, r5
- bf arg_loop /* if r5 has clazz, keep it as is */
- mov.l @r3+, r5 /* put object arg in r5 */
-
- ## other args
-arg_loop:
-one_arg_handled:
- mov.b @r2+, r0
- cmp/eq #0, r0 /* if (*shorty == '\0) */
- bf process_one_arg
- bra arg_end /* no argument left */
- nop
-
-process_one_arg:
-
- ## check arg type
-
- cmp/eq #'F', r0
- bt jfloat_arg
-
- cmp/eq #'D', r0
- bt jdouble_arg
-
- cmp/eq #'J', r0
- bt jlong_arg
-
- ## other 32bit arg types
- mov r12, r0
- cmp/eq #0, r0
- bt put_32bit_on_stack /* r6-7 not available */
-
- tst #1, r0
- bt j32_arg_1
- mov.l @r3+, r6 /* put one arg in r6 */
- mov #1, r0 /* r6 is not available now. */
- not r0, r0
- and r0, r12
- bra one_arg_handled
- nop
-j32_arg_1:
- tst #2, r0
- bt j32_arg_fatal_error
- mov.l @r3+, r7 /* put one arg in r7 */
- mov #2, r0 /* r7 is not available now. */
- not r0, r0
- and r0, r12
- bra one_arg_handled
- nop
-
-j32_arg_fatal_error:
- bra j32_arg_fatal_error
- nop
-
-jlong_arg:
- mov r12, r0
- cmp/eq #0, r0
- bt put_64bit_on_stack /* r6-7 not available */
-
- and #3, r0
- cmp/eq #3, r0
- bf put_64bit_on_stack /* consequent two registers not available. */
- mov.l @r3+, r6 /* put one arg in r6 and r7 */
- mov.l @r3+, r7
- mov #3, r0 /* r6 and r7 are not available now. */
- not r0, r0
- and r0, r12
- bra one_arg_handled
- nop
-
- # utility routines are placed here make short range jumps available.
-put_32bit_on_stack:
- mov.l @r3+, r0
- mov.l r0, @-r15
- bra one_arg_handled
- nop
-
-put_64bit_on_stack:
- mov.l @r3+, r0
- mov.l r0, @-r15 /* Pay attention that the endianness is */
- mov.l @r3+, r0 /* once reversed. It is corrected when the */
- mov.l r0, @-r15 /* arguments on stack are revesred before */
- bra one_arg_handled /* jni call */
- nop
-
-jdouble_arg:
- mov r13, r0
- cmp/eq #0, r0
- bt put_64bit_on_stack /* fr4-11 not available */
-
- and #3, r0
- cmp/eq #3, r0
- bf jdouble_arg_1
-
- fmov.s @r3+, fr5 /* put one arg to drX */
- fmov.s @r3+, fr4
- mov #3, r0 /* fr4-frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jdouble_arg_1:
- mov r13, r0
- and #12, r0
- cmp/eq #12, r0
- bf jdouble_arg_2
-
- fmov.s @r3+, fr7 /* put one arg to drX */
- fmov.s @r3+, fr6
- mov #15, r0 /* fr4-frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jdouble_arg_2:
- mov r13, r0
- and #48, r0
- cmp/eq #48, r0
- bf jdouble_arg_3
- fmov.s @r3+, fr9 /* put one arg to drX */
- fmov.s @r3+, fr8
- mov #63, r0 /* fr4-frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jdouble_arg_3:
- mov r13, r0
- and #192, r0
- cmp/eq #192, r0
- bf put_64bit_on_stack
- fmov.s @r3+, fr11 /* put one arg to drX */
- fmov.s @r3+, fr10
- mov #0, r13 /* fr4-fr11 all not available now. */
- bra one_arg_handled
- nop
-
-jfloat_arg:
- mov r13, r0
- cmp/eq #0, r0
- bt put_32bit_on_stack /* fr4-11 not available */
-
- tst #2, r0
- bt jfloat_arg_1
- fmov.s @r3+, fr5 /* put one arg to frX */
- mov #2, r0 /* frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jfloat_arg_1:
- tst #1, r0
- bt jfloat_arg_2
- fmov.s @r3+, fr4 /* put one arg to frX */
- mov #1, r0 /* frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jfloat_arg_2:
- tst #8, r0
- bt jfloat_arg_3
- fmov.s @r3+, fr7 /* put one arg to frX */
- mov #8, r0 /* frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jfloat_arg_3:
- tst #4, r0
- bt jfloat_arg_4
- fmov.s @r3+, fr6 /* put one arg to frX */
- mov #4, r0 /* frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jfloat_arg_4:
- tst #32, r0
- bt jfloat_arg_5
- fmov.s @r3+, fr9 /* put one arg to frX */
- mov #32, r0 /* frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jfloat_arg_5:
- tst #16, r0
- bt jfloat_arg_6
- fmov.s @r3+, fr8 /* put one arg to frX */
- mov #16, r0 /* frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jfloat_arg_6:
- tst #128, r0
- bt jfloat_arg_7
- fmov.s @r3+, fr11 /* put one arg to frX */
- mov #127, r0 /* frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jfloat_arg_7:
- tst #64, r0
- bt jfloat_fatal_error
- fmov.s @r3+, fr10 /* put one arg to frX */
- mov #64, r0 /* frX not available now. */
- not r0, r0
- and r0, r13
- bra one_arg_handled
- nop
-
-jfloat_fatal_error:
- bra jfloat_fatal_error:
- nop
-
-arg_end:
-
-
-### reverse the variables on stack
- mov r14, r12 /* points to first arg on stack */
- add #-20, r12
- mov r15, r13 /* points to last arg on stack */
-arg_rev_loop:
- cmp/hs r12, r13 /* When r13 >= r12 (unsigned), 1->T */
- bt arg_rev_end
- mov.l @r12, r0
- mov.l @r13, r1
- mov.l r0, @r13
- mov.l r1, @r12
- add #-4, r12
- add #4, r13
- bra arg_rev_loop
- nop
-
-arg_rev_end:
-
-### invoke the JNI function.
-
- mov.l @(8,r14), r0
- jsr @r0
- nop
-
-### pass the return value
-
- /*
- * r0 and r1 keep return value.
- */
-
- ## fetch data
- mov.l @(4,r14), r2 /* reload shorty */
- mov.b @r2, r2 /* first byte specifyes return value type. */
- mov.l @(12,r14), r3 /* pReturn */
-
- ## check return value types
-
- mov #'V', r4
- cmp/eq r4, r2
- bt end
-
- mov #'F', r4
- cmp/eq r4, r2
- bt jfloat_ret
-
- mov #'D', r4
- cmp/eq r4, r2
- bt jdouble_ret
-
- mov #'J', r4
- cmp/eq r4, r2
- bt jlong_ret
-
- ## fall-through for other 32 bit java types.
-
- ## load return values
-j32_ret:
- bra end
- mov.l r0, @r3 /* delay slot */
-
-jfloat_ret:
- bra end
- fmov.s fr0, @r3 /* delay slot */
-
-jdouble_ret:
- fmov.s fr1, @r3
- mov #4, r0
- bra end
- fmov.s fr0, @(r0,r3) /* delay slot */
-
-jlong_ret:
- mov.l r0, @r3
- bra end
- mov.l r1, @(4,r3) /* delay slot */
-
-end:
- ## restore preserved registers
- mov r14, r15
- add #-16, r15
- lds.l @r15+, pr
- mov.l @r15+, r12
- mov.l @r15+, r13
- mov.l @r15+, r14
-
- rts /* dvmPlatformInvoke returns void. */
- nop
diff --git a/vm/arch/x86-atom/Call386ABI.S b/vm/arch/x86-atom/Call386ABI.S
deleted file mode 100644
index f996168..0000000
--- a/vm/arch/x86-atom/Call386ABI.S
+++ /dev/null
@@ -1,189 +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.
- */
-
- /*
- * File: CallABI.S
- *
- * Code: facilitates call to native code C and C++ routines.
- *
- */
-
- /*
- * Function prototype:
- *
- * void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
- * const u4* argv, const char* signature, void* func, JValue* pReturn)
- *
- * The method we are calling has the form:
- *
- * return_type func(JNIEnv* pEnv, ClassObject* clazz, ...)
- * -or-
- * return_type func(JNIEnv* pEnv, Object* this, ...)
- *
- * We receive a collection of 32-bit values which correspond to arguments from
- * the interpreter (e.g. float occupies one, double occupies two). It's up to
- * us to convert these into local calling conventions.
- */
-
- /*
- * On entry:
- * 4(%sp) JNIEnv (can be left alone)
- * 8(%esp) clazz (NULL for virtual method calls, non-NULL for static)
- * 12(%esp) arg info
- * 16(%esp) argc (number of 32-bit values in argv)
- * 20(%esp) argv
- * 24(%esp) short signature
- * 28(%esp) func
- * 32(%esp) pReturn
- *
- * For a virtual method call, the "this" reference is in argv[0].
- *
- * argInfo (32-bit int) layout:
- *
- * SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
- *
- * S - if set, argInfo hints are invalid
- * R - return type enumeration (see jniInternal.h)
- * VOID -> 0
- * FLOAT -> 1
- * DOUBLE -> 2
- * S8 -> 3
- * S4 -> 4
- * H - target-specific hints (see below for details)
- *
- * IA32 ABI JNI hint format
- *
- * ZZZZ ZZZZZZZZ AAAAAAAA AAAAAAAA
- *
- * Z - reserved
- * A - size of the variable argument block in 32-bit words
- */
-
- .text
- .align 4
- .global dvmPlatformInvoke
- .type dvmPlatformInvoke, %function
-
-
-dvmPlatformInvoke:
-CallABI_ENTER:
-
- /*
- * Save registers.
- */
-
- movl %ebp, -4(%esp)
- movl %ebx, -8(%esp) # save %ebx
- movl %esi, -12(%esp) # save %esi
- movl %edi, -16(%esp) # save %edi
- lea (%esp), %ebp
-
- /*
- * Check if argInfo is valid. Is always valid so should remove this check?
- */
-
- movzwl 12(%ebp), %ecx # %ecx<- argsize in words
- movl 12(%ebp), %ebx # %ebx<- argInfo
-
- shl $2, %ecx # %ecx<- argsize in bytes
- subl %ecx, %esp # %esp<- expanded for arg region
-
- /*
- * Prepare for 16 byte alignment
- */
-
- and $0xfffffff0, %esp
- subl $24, %esp
-
-
- movl 8(%ebp), %eax # %eax<- clazz
- cmpl $0, %eax # Check virtual or static
- movl 4(%ebp), %ecx # %ecx<- JNIEnv
- movl 20(%ebp), %esi # %esi<- argV
- jne 1f # Branch if static
- movl (%esi), %eax # get the this pointer
- addl $4, %esi # %esi<- update past this
-
-1:
- movl %ecx, -8(%esp) # push JNIEnv as arg #1
- movl %eax, -4(%esp) # push clazz or this as arg #2
- lea -8(%esp), %esp
-
- /*
- * Copy arguments
- */
-
- movzwl %bx, %ecx # %ecx<- %bx; argsize in words
- lea 8(%esp), %edi # %edi<- stack location for arguments
- cld
- rep movsl # move %ecx arguments to 8(%esp)
- call *28(%ebp)
- sarl $28, %ebx # %ebx<- SRRR (low 4 bits)
- je CallABI_EXIT # exit call
- cmpl $2, %ebx
- movl 32(%ebp), %ecx # %ecx<- return pointer
- je 2f # handle double return
- jl 1f # handle float return
-
- /*
- * If a native function returns a result smaller than 8-bytes
- * then higher bytes may contain garbage.
- * This code does type-checking based on size of return result.
- * We zero higher bytes instead of allowing the garbage to go through.
- */
-
- cmpl $3,%ebx
- je S8
- cmpl $4,%ebx
- je S4
- cmpl $7,%ebx
- je S1
- cmpl $6,%ebx
- jne S2
-U2:
- movzwl %ax, %eax
- movl %eax, (%ecx) # save 32-bit return
- jmp CallABI_EXIT # exit call
-
-S1:
- movsbl %al, %eax
- movl %eax, (%ecx) # save 32-bit return
- jmp CallABI_EXIT # exit call
-S2:
- movswl %ax, %eax
- movl %eax, (%ecx) # save 32-bit return
- jmp CallABI_EXIT # exit call
-S4:
- cltd
- movl %eax, (%ecx) # save 32-bit return
- jmp CallABI_EXIT # exit call
-S8:
- movl %edx, 4(%ecx) # save 64-bit return
- movl %eax, (%ecx) # save 32-bit return
- jmp CallABI_EXIT # exit call
-
-2:
- fstpl (%ecx) # save double return
- jmp CallABI_EXIT # exit call
-1:
- fstps (%ecx) # save float return
-
-CallABI_EXIT:
- lea (%ebp), %esp
- movl -16(%ebp), %edi # restore %edi
- movl -12(%ebp), %esi # restore %esi
- movl -8(%ebp), %ebx # restore %ebx
- movl -4(%ebp), %ebp # restore caller base pointer
- ret # return
diff --git a/vm/arch/x86-atom/Hints386ABI.cpp b/vm/arch/x86-atom/Hints386ABI.cpp
deleted file mode 100644
index dd2fc69..0000000
--- a/vm/arch/x86-atom/Hints386ABI.cpp
+++ /dev/null
@@ -1,79 +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.
- */
-
- /*
- * The class loader will associate with each method a 32-bit info word
- * (jniArgInfo) to support JNI calls. The high order 4 bits of this word
- * are the same for all targets, while the lower 28 are used for hints to
- * allow accelerated JNI bridge transfers.
- *
- * jniArgInfo (32-bit int) layout:
- *
- * SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
- *
- * S - if set, ignore the hints and do things the hard way (scan signature)
- * R - return-type enumeration
- * H - target-specific hints (see below for details)
- *
- * This function produces IA32-specific hints for the standard 32-bit 386 ABI.
- * All arguments have 32-bit alignment. Padding is not an issue.
- *
- * IA32 ABI JNI hint format
- *
- * ZZZZ ZZZZZZZZ AAAAAAAA AAAAAAAA
- *
- * Z - reserved, must be 0
- * A - size of variable argument block in 32-bit words (note - does not
- * include JNIEnv or clazz)
- *
- * For the 386 ABI, valid hints should always be generated.
- */
-
-
-#include "Dalvik.h"
-#include "libdex/DexClass.h"
-#include <stdlib.h>
-#include <stddef.h>
-#include <sys/stat.h>
-
-u4 dvmPlatformInvokeHints(const DexProto* proto) {
-
-const char* sig = dexProtoGetShorty(proto);
-unsigned int wordCount = 0;
-char sigByte;
-
- while (1) {
-
- /*
- * Move past return type; dereference sigByte
- */
-
- sigByte = *(++sig);
- if (sigByte == '\0') { break; }
- ++wordCount;
-
- if (sigByte == 'D' || sigByte == 'J') {
- ++wordCount;
- }
- }
-
-/*
- * Check for Dex file limitation and return
- */
-
- if (wordCount > 0xFFFF) { return DALVIK_JNI_NO_ARG_INFO; }
- return wordCount;
-
-}
diff --git a/vm/arch/x86/Call386ABI.S b/vm/arch/x86/Call386ABI.S
index 39a0e93..766aff7 100644
--- a/vm/arch/x86/Call386ABI.S
+++ b/vm/arch/x86/Call386ABI.S
@@ -55,6 +55,7 @@
*/
.text
+ .align 4
.global dvmPlatformInvoke
.type dvmPlatformInvoke, @function
diff --git a/vm/compiler/Compiler.cpp b/vm/compiler/Compiler.cpp
index b9b3105..cdd62cc 100644
--- a/vm/compiler/Compiler.cpp
+++ b/vm/compiler/Compiler.cpp
@@ -21,6 +21,10 @@
#include "Dalvik.h"
#include "interp/Jit.h"
#include "CompilerInternals.h"
+#ifdef ARCH_IA32
+#include "codegen/x86/Translator.h"
+#include "codegen/x86/Lower.h"
+#endif
extern "C" void dvmCompilerTemplateStart(void);
extern "C" void dmvCompilerTemplateEnd(void);
@@ -187,6 +191,7 @@
/* This can be found through "dalvik-jit-code-cache" in /proc/<pid>/maps */
// ALOGD("Code cache starts at %p", gDvmJit.codeCache);
+#ifndef ARCH_IA32
/* Copy the template code into the beginning of the code cache */
int templateSize = (intptr_t) dmvCompilerTemplateEnd -
(intptr_t) dvmCompilerTemplateStart;
@@ -216,6 +221,16 @@
ALOGE("Failed to remove the write permission for the code cache");
dvmAbort();
}
+#else
+ gDvmJit.codeCacheByteUsed = 0;
+ stream = (char*)gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
+ ALOGV("codeCache = %p stream = %p before initJIT", gDvmJit.codeCache, stream);
+ streamStart = stream;
+ initJIT(NULL, NULL);
+ gDvmJit.templateSize = (stream - streamStart);
+ gDvmJit.codeCacheByteUsed = (stream - streamStart);
+ ALOGV("stream = %p after initJIT", stream);
+#endif
return true;
}
@@ -313,9 +328,9 @@
* Wipe out the code cache content to force immediate crashes if
* stale JIT'ed code is invoked.
*/
- memset((char *) gDvmJit.codeCache + gDvmJit.templateSize,
- 0,
- gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
+ dvmCompilerCacheClear((char *) gDvmJit.codeCache + gDvmJit.templateSize,
+ gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
+
dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache,
(intptr_t) gDvmJit.codeCache +
gDvmJit.codeCacheByteUsed, 0);
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index fc23254..7af2809 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -27,6 +27,7 @@
#define COMPILER_WORK_QUEUE_SIZE 100
#define COMPILER_IC_PATCH_QUEUE_SIZE 64
+#define COMPILER_PC_OFFSET_SIZE 100
/* Architectural-independent parameters for predicted chains */
#define PREDICTED_CHAIN_CLAZZ_INIT 0
@@ -74,7 +75,8 @@
DALVIK_JIT_ARM,
DALVIK_JIT_THUMB,
DALVIK_JIT_THUMB2,
- DALVIK_JIT_IA32
+ DALVIK_JIT_IA32,
+ DALVIK_JIT_MIPS
} JitInstructionSetType;
/* Description of a compiled trace. */
@@ -107,6 +109,11 @@
/* Chain cell for predicted method invocation */
typedef struct PredictedChainingCell {
u4 branch; /* Branch to chained destination */
+#ifdef __mips__
+ u4 delay_slot; /* nop goes here */
+#elif defined(ARCH_IA32)
+ u4 branch2; /* IA32 branch instr may be > 32 bits */
+#endif
const ClassObject *clazz; /* key for prediction */
const Method *method; /* to lookup native PC from dalvik PC */
const ClassObject *stagedClazz; /* possible next key for prediction */
@@ -241,5 +248,6 @@
JitInstructionSetType dvmCompilerGetInterpretTemplateSet();
u8 dvmGetRegResourceMask(int reg);
void dvmDumpCFG(struct CompilationUnit *cUnit, const char *dirPrefix);
+bool dvmIsOpcodeSupportedByJit(Opcode opcode);
#endif // DALVIK_VM_COMPILER_H_
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index 23dea33..73efad8 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -18,6 +18,9 @@
#define DALVIK_VM_COMPILER_IR_H_
#include "codegen/Optimizer.h"
+#ifdef ARCH_IA32
+#include "CompilerUtility.h"
+#endif
typedef enum RegisterClass {
kCoreReg,
@@ -199,6 +202,9 @@
int numBlocks;
GrowableList blockList;
const Method *method;
+#ifdef ARCH_IA32
+ int exceptionBlockId; // the block corresponding to exception handling
+#endif
const JitTraceDescription *traceDesc;
LIR *firstLIRInsn;
LIR *lastLIRInsn;
diff --git a/vm/compiler/CompilerUtility.h b/vm/compiler/CompilerUtility.h
index 8a674b8..faca03d 100644
--- a/vm/compiler/CompilerUtility.h
+++ b/vm/compiler/CompilerUtility.h
@@ -73,7 +73,8 @@
void dvmDumpBlockBitVector(const GrowableList *blocks, char *msg,
const BitVector *bv, int length);
void dvmGetBlockName(struct BasicBlock *bb, char *name);
-int dvmCompilerCacheFlush(long start, long end, long flags);
+void dvmCompilerCacheFlush(long start, long end, long flags);
+void dvmCompilerCacheClear(char *start, size_t size);
#endif // DALVIK_COMPILER_UTILITY_H_
diff --git a/vm/compiler/Frontend.cpp b/vm/compiler/Frontend.cpp
index e0226e9..47c1898 100644
--- a/vm/compiler/Frontend.cpp
+++ b/vm/compiler/Frontend.cpp
@@ -1314,10 +1314,12 @@
/* Perform SSA transformation for the whole method */
dvmCompilerMethodSSATransformation(&cUnit);
+#ifndef ARCH_IA32
dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
/* Allocate Registers using simple local allocation scheme */
dvmCompilerLocalRegAlloc(&cUnit);
+#endif
/* Convert MIR to LIR, etc. */
dvmCompilerMethodMIR2LIR(&cUnit);
@@ -1536,6 +1538,10 @@
*/
dvmCompilerInsertBackwardChaining(cUnit);
+#if defined(ARCH_IA32)
+ /* Convert MIR to LIR, etc. */
+ dvmCompilerMIR2LIR(cUnit, info);
+#else
dvmCompilerInitializeRegAlloc(cUnit);
/* Allocate Registers using simple local allocation scheme */
@@ -1543,6 +1549,7 @@
/* Convert MIR to LIR, etc. */
dvmCompilerMIR2LIR(cUnit);
+#endif
/* Loop contains never executed blocks / heavy instructions */
if (cUnit->quitLoopMode) {
@@ -1604,6 +1611,23 @@
optHints | JIT_OPT_NO_LOOP);
}
+static bool searchClassTablePrefix(const Method* method) {
+ if (gDvmJit.classTable == NULL) {
+ return false;
+ }
+ HashIter iter;
+ HashTable* pTab = gDvmJit.classTable;
+ for (dvmHashIterBegin(pTab, &iter); !dvmHashIterDone(&iter);
+ dvmHashIterNext(&iter))
+ {
+ const char* str = (const char*) dvmHashIterData(&iter);
+ if (strncmp(method->clazz->descriptor, str, strlen(str)) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
/*
* Main entry point to start trace compilation. Basic blocks are constructed
* first and they will be passed to the codegen routines to convert Dalvik
@@ -1674,6 +1698,12 @@
dvmInitGrowableList(blockList, 8);
/* Identify traces that we don't want to compile */
+ if (gDvmJit.classTable) {
+ bool classFound = searchClassTablePrefix(desc->method);
+ if (gDvmJit.classTable && gDvmJit.includeSelectedMethod != classFound) {
+ return false;
+ }
+ }
if (gDvmJit.methodTable) {
int len = strlen(desc->method->clazz->descriptor) +
strlen(desc->method->name) + 1;
@@ -1734,8 +1764,12 @@
* 2) If includeSelectedMethod == true, the method does not match the
* full and partial signature stored in the hash table.
*/
- if (gDvmJit.includeSelectedMethod != methodFound) {
+ if (gDvmJit.methodTable && gDvmJit.includeSelectedMethod != methodFound) {
+#ifdef ARCH_IA32
+ return false;
+#else
cUnit.allSingleStep = true;
+#endif
} else {
/* Compile the trace as normal */
@@ -1746,6 +1780,22 @@
}
}
+ // Each pair is a range, check whether curOffset falls into a range.
+ bool includeOffset = (gDvmJit.num_entries_pcTable < 2);
+ for (int pcOff = 0; pcOff < gDvmJit.num_entries_pcTable; ) {
+ if (pcOff+1 >= gDvmJit.num_entries_pcTable) {
+ break;
+ }
+ if (curOffset >= gDvmJit.pcTable[pcOff] && curOffset <= gDvmJit.pcTable[pcOff+1]) {
+ includeOffset = true;
+ break;
+ }
+ pcOff += 2;
+ }
+ if (!includeOffset) {
+ return false;
+ }
+
/* Allocate the entry block */
curBB = dvmCompilerNewBB(kEntryBlock, numBlocks++);
dvmInsertGrowableList(blockList, (intptr_t) curBB);
@@ -2056,17 +2106,24 @@
dvmCompilerNonLoopAnalysis(&cUnit);
+#ifndef ARCH_IA32
dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
+#endif
if (cUnit.printMe) {
dvmCompilerDumpCompilationUnit(&cUnit);
}
+#ifndef ARCH_IA32
/* Allocate Registers using simple local allocation scheme */
dvmCompilerLocalRegAlloc(&cUnit);
/* Convert MIR to LIR, etc. */
dvmCompilerMIR2LIR(&cUnit);
+#else /* ARCH_IA32 */
+ /* Convert MIR to LIR, etc. */
+ dvmCompilerMIR2LIR(&cUnit, info);
+#endif
/* Convert LIR into machine code. Loop for recoverable retries */
do {
diff --git a/vm/compiler/Loop.cpp b/vm/compiler/Loop.cpp
index 7090360..f826686 100644
--- a/vm/compiler/Loop.cpp
+++ b/vm/compiler/Loop.cpp
@@ -728,12 +728,15 @@
* code will be generated along the backward branch to honor the suspend
* requests.
*/
+#ifndef ARCH_IA32
#if !defined(WITH_SELF_VERIFICATION)
if (gDvmJit.profileMode != kTraceProfilingContinuous &&
gDvmJit.profileMode != kTraceProfilingPeriodicOn) {
return;
}
#endif
+#endif
+
/*
* In self-verification or profiling mode, the backward branch is altered
* to go to the backward chaining cell. Without using the backward chaining
diff --git a/vm/compiler/codegen/CompilerCodegen.h b/vm/compiler/codegen/CompilerCodegen.h
index 6495d07..f2b36a3 100644
--- a/vm/compiler/codegen/CompilerCodegen.h
+++ b/vm/compiler/codegen/CompilerCodegen.h
@@ -26,7 +26,11 @@
bool dvmCompilerDoWork(CompilerWorkOrder *work);
/* Lower middle-level IR to low-level IR */
+#ifndef ARCH_IA32
void dvmCompilerMIR2LIR(CompilationUnit *cUnit);
+#else /* ARCH_IA32 */
+void dvmCompilerMIR2LIR(CompilationUnit *cUnit, JitTranslationInfo* info);
+#endif
/* Lower middle-level IR to low-level IR for the whole method */
void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit);
diff --git a/vm/compiler/codegen/arm/ArchUtility.cpp b/vm/compiler/codegen/arm/ArchUtility.cpp
index e6075e8..9f87b7f 100644
--- a/vm/compiler/codegen/arm/ArchUtility.cpp
+++ b/vm/compiler/codegen/arm/ArchUtility.cpp
@@ -421,7 +421,18 @@
}
/* Target-specific cache flushing */
-int dvmCompilerCacheFlush(long start, long end, long flags)
+void dvmCompilerCacheFlush(long start, long end, long flags)
{
- return cacheflush(start, end, flags);
+ cacheflush(start, end, flags);
+}
+
+/* Target-specific cache clearing */
+void dvmCompilerCacheClear(char *start, size_t size)
+{
+ /*
+ * de is an invalid opcode for arm.
+ * From gdb disassembly: <UNDEFINED> instruction: 0xdede
+ */
+
+ memset(start, 0xde, size);
}
diff --git a/vm/compiler/codegen/arm/Assemble.cpp b/vm/compiler/codegen/arm/Assemble.cpp
index 9842eaf..d1ecd97 100644
--- a/vm/compiler/codegen/arm/Assemble.cpp
+++ b/vm/compiler/codegen/arm/Assemble.cpp
@@ -1955,14 +1955,13 @@
{
u4* lowAddress = NULL;
u4* highAddress = NULL;
- unsigned int i;
if (gDvmJit.pJitEntryTable != NULL) {
COMPILER_TRACE_CHAINING(LOGD("Jit Runtime: unchaining all"));
dvmLockMutex(&gDvmJit.tableLock);
UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
- for (i = 0; i < gDvmJit.jitTableSize; i++) {
+ for (size_t i = 0; i < gDvmJit.jitTableSize; i++) {
if (gDvmJit.pJitEntryTable[i].dPC &&
!gDvmJit.pJitEntryTable[i].u.info.isMethodEntry &&
gDvmJit.pJitEntryTable[i].codeAddress &&
diff --git a/vm/compiler/codegen/arm/CodegenDriver.cpp b/vm/compiler/codegen/arm/CodegenDriver.cpp
index 40fc964..7346c83 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.cpp
+++ b/vm/compiler/codegen/arm/CodegenDriver.cpp
@@ -670,6 +670,7 @@
OpKind firstOp = kOpBkpt;
OpKind secondOp = kOpBkpt;
bool callOut = false;
+ bool checkZero = false;
void *callTgt;
int retReg = r0;
@@ -700,6 +701,7 @@
case OP_DIV_LONG_2ADDR:
callOut = true;
retReg = r0;
+ checkZero = true;
callTgt = (void*)__aeabi_ldivmod;
break;
/* NOTE - result is in r2/r3 instead of r0/r1 */
@@ -708,6 +710,7 @@
callOut = true;
callTgt = (void*)__aeabi_ldivmod;
retReg = r2;
+ checkZero = true;
break;
case OP_AND_LONG_2ADDR:
case OP_AND_LONG:
@@ -746,9 +749,14 @@
} else {
// Adjust return regs in to handle case of rem returning r2/r3
dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
+ loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
LOAD_FUNC_ADDR(cUnit, r14lr, (int) callTgt);
- loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+ if (checkZero) {
+ int tReg = r12; // Using fixed registers during call sequence
+ opRegRegReg(cUnit, kOpOr, tReg, r2, r3);
+ genRegImmCheck(cUnit, kArmCondEq, tReg, 0, mir->offset, NULL);
+ }
opReg(cUnit, kOpBlx, r14lr);
dvmCompilerClobberCallRegs(cUnit);
if (retReg == r0)
@@ -3637,30 +3645,40 @@
return false; /* Nop */
/* These ones we potentially JIT inline. */
+
+ case INLINE_STRING_CHARAT:
+ return genInlinedStringCharAt(cUnit, mir);
case INLINE_STRING_LENGTH:
return genInlinedStringLength(cUnit, mir);
case INLINE_STRING_IS_EMPTY:
return genInlinedStringIsEmpty(cUnit, mir);
- case INLINE_MATH_ABS_INT:
- return genInlinedAbsInt(cUnit, mir);
- case INLINE_MATH_ABS_LONG:
- return genInlinedAbsLong(cUnit, mir);
- case INLINE_MATH_MIN_INT:
- return genInlinedMinMaxInt(cUnit, mir, true);
- case INLINE_MATH_MAX_INT:
- return genInlinedMinMaxInt(cUnit, mir, false);
- case INLINE_STRING_CHARAT:
- return genInlinedStringCharAt(cUnit, mir);
- case INLINE_MATH_SQRT:
- return genInlineSqrt(cUnit, mir);
- case INLINE_MATH_ABS_FLOAT:
- return genInlinedAbsFloat(cUnit, mir);
- case INLINE_MATH_ABS_DOUBLE:
- return genInlinedAbsDouble(cUnit, mir);
case INLINE_STRING_COMPARETO:
return genInlinedCompareTo(cUnit, mir);
case INLINE_STRING_FASTINDEXOF_II:
return genInlinedFastIndexOf(cUnit, mir);
+
+ case INLINE_MATH_ABS_INT:
+ case INLINE_STRICT_MATH_ABS_INT:
+ return genInlinedAbsInt(cUnit, mir);
+ case INLINE_MATH_ABS_LONG:
+ case INLINE_STRICT_MATH_ABS_LONG:
+ return genInlinedAbsLong(cUnit, mir);
+ case INLINE_MATH_MIN_INT:
+ case INLINE_STRICT_MATH_MIN_INT:
+ return genInlinedMinMaxInt(cUnit, mir, true);
+ case INLINE_MATH_MAX_INT:
+ case INLINE_STRICT_MATH_MAX_INT:
+ return genInlinedMinMaxInt(cUnit, mir, false);
+ case INLINE_MATH_SQRT:
+ case INLINE_STRICT_MATH_SQRT:
+ return genInlineSqrt(cUnit, mir);
+ case INLINE_MATH_ABS_FLOAT:
+ case INLINE_STRICT_MATH_ABS_FLOAT:
+ return genInlinedAbsFloat(cUnit, mir);
+ case INLINE_MATH_ABS_DOUBLE:
+ case INLINE_STRICT_MATH_ABS_DOUBLE:
+ return genInlinedAbsDouble(cUnit, mir);
+
case INLINE_FLOAT_TO_RAW_INT_BITS:
case INLINE_INT_BITS_TO_FLOAT:
return genInlinedIntFloatConversion(cUnit, mir);
diff --git a/vm/compiler/codegen/mips/ArchUtility.cpp b/vm/compiler/codegen/mips/ArchUtility.cpp
new file mode 100644
index 0000000..1f6d593
--- /dev/null
+++ b/vm/compiler/codegen/mips/ArchUtility.cpp
@@ -0,0 +1,356 @@
+/*
+ * 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.
+ */
+
+#include "../../CompilerInternals.h"
+#include "libdex/DexOpcodes.h"
+#include "MipsLIR.h"
+
+/* For dumping instructions */
+#define MIPS_REG_COUNT 32
+static const char *mipsRegName[MIPS_REG_COUNT] = {
+ "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
+};
+
+/*
+ * Interpret a format string and build a string no longer than size
+ * See format key in Assemble.c.
+ */
+static void buildInsnString(const char *fmt, MipsLIR *lir, char* buf,
+ unsigned char *baseAddr, int size)
+{
+ int i;
+ char *bufEnd = &buf[size-1];
+ const char *fmtEnd = &fmt[strlen(fmt)];
+ char tbuf[256];
+ char nc;
+ while (fmt < fmtEnd) {
+ int operand;
+ if (*fmt == '!') {
+ fmt++;
+ assert(fmt < fmtEnd);
+ nc = *fmt++;
+ if (nc=='!') {
+ strcpy(tbuf, "!");
+ } else {
+ assert(fmt < fmtEnd);
+ assert((unsigned)(nc-'0') < 4);
+ operand = lir->operands[nc-'0'];
+ switch(*fmt++) {
+ case 'b':
+ strcpy(tbuf,"0000");
+ for (i=3; i>= 0; i--) {
+ tbuf[i] += operand & 1;
+ operand >>= 1;
+ }
+ break;
+ case 's':
+ sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
+ break;
+ case 'S':
+ assert(((operand & FP_REG_MASK) & 1) == 0);
+ sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
+ break;
+ case 'h':
+ sprintf(tbuf,"%04x", operand);
+ break;
+ case 'M':
+ case 'd':
+ sprintf(tbuf,"%d", operand);
+ break;
+ case 'D':
+ sprintf(tbuf,"%d", operand+1);
+ break;
+ case 'E':
+ sprintf(tbuf,"%d", operand*4);
+ break;
+ case 'F':
+ sprintf(tbuf,"%d", operand*2);
+ break;
+ case 'c':
+ switch (operand) {
+ case kMipsCondEq:
+ strcpy(tbuf, "eq");
+ break;
+ case kMipsCondNe:
+ strcpy(tbuf, "ne");
+ break;
+ case kMipsCondLt:
+ strcpy(tbuf, "lt");
+ break;
+ case kMipsCondGe:
+ strcpy(tbuf, "ge");
+ break;
+ case kMipsCondGt:
+ strcpy(tbuf, "gt");
+ break;
+ case kMipsCondLe:
+ strcpy(tbuf, "le");
+ break;
+ case kMipsCondCs:
+ strcpy(tbuf, "cs");
+ break;
+ case kMipsCondMi:
+ strcpy(tbuf, "mi");
+ break;
+ default:
+ strcpy(tbuf, "");
+ break;
+ }
+ break;
+ case 't':
+ sprintf(tbuf,"0x%08x (L%p)",
+ (int) baseAddr + lir->generic.offset + 4 +
+ (operand << 2),
+ lir->generic.target);
+ break;
+ case 'T':
+ sprintf(tbuf,"0x%08x",
+ (int) (operand << 2));
+ break;
+ case 'u': {
+ int offset_1 = lir->operands[0];
+ int offset_2 = NEXT_LIR(lir)->operands[0];
+ intptr_t target =
+ ((((intptr_t) baseAddr + lir->generic.offset + 4) &
+ ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
+ 0xfffffffc;
+ sprintf(tbuf, "%p", (void *) target);
+ break;
+ }
+
+ /* Nothing to print for BLX_2 */
+ case 'v':
+ strcpy(tbuf, "see above");
+ break;
+ case 'r':
+ assert(operand >= 0 && operand < MIPS_REG_COUNT);
+ strcpy(tbuf, mipsRegName[operand]);
+ break;
+ default:
+ strcpy(tbuf,"DecodeError");
+ break;
+ }
+ if (buf+strlen(tbuf) <= bufEnd) {
+ strcpy(buf, tbuf);
+ buf += strlen(tbuf);
+ } else {
+ break;
+ }
+ }
+ } else {
+ *buf++ = *fmt++;
+ }
+ if (buf == bufEnd)
+ break;
+ }
+ *buf = 0;
+}
+
+void dvmDumpResourceMask(LIR *lir, u8 mask, const char *prefix)
+{
+ char buf[256];
+ buf[0] = 0;
+ MipsLIR *mipsLIR = (MipsLIR *) lir;
+
+ if (mask == ENCODE_ALL) {
+ strcpy(buf, "all");
+ } else {
+ char num[8];
+ int i;
+
+ for (i = 0; i < kRegEnd; i++) {
+ if (mask & (1ULL << i)) {
+ sprintf(num, "%d ", i);
+ strcat(buf, num);
+ }
+ }
+
+ if (mask & ENCODE_CCODE) {
+ strcat(buf, "cc ");
+ }
+ if (mask & ENCODE_FP_STATUS) {
+ strcat(buf, "fpcc ");
+ }
+ /* Memory bits */
+ if (mipsLIR && (mask & ENCODE_DALVIK_REG)) {
+ sprintf(buf + strlen(buf), "dr%d%s", mipsLIR->aliasInfo & 0xffff,
+ (mipsLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
+ }
+ if (mask & ENCODE_LITERAL) {
+ strcat(buf, "lit ");
+ }
+
+ if (mask & ENCODE_HEAP_REF) {
+ strcat(buf, "heap ");
+ }
+ if (mask & ENCODE_MUST_NOT_ALIAS) {
+ strcat(buf, "noalias ");
+ }
+ }
+ if (buf[0]) {
+ ALOGD("%s: %s", prefix, buf);
+ }
+}
+
+/*
+ * Debugging macros
+ */
+#define DUMP_RESOURCE_MASK(X)
+#define DUMP_SSA_REP(X)
+
+/* Pretty-print a LIR instruction */
+void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
+{
+ MipsLIR *lir = (MipsLIR *) arg;
+ char buf[256];
+ char opName[256];
+ int offset = lir->generic.offset;
+ int dest = lir->operands[0];
+ const bool dumpNop = false;
+
+ /* Handle pseudo-ops individually, and all regular insns as a group */
+ switch(lir->opcode) {
+ case kMipsChainingCellBottom:
+ ALOGD("-------- end of chaining cells (0x%04x)", offset);
+ break;
+ case kMipsPseudoBarrier:
+ ALOGD("-------- BARRIER");
+ break;
+ case kMipsPseudoExtended:
+ /* intentional fallthrough */
+ case kMipsPseudoSSARep:
+ DUMP_SSA_REP(ALOGD("-------- %s", (char *) dest));
+ break;
+ case kMipsPseudoChainingCellBackwardBranch:
+ ALOGD("L%p:", lir);
+ ALOGD("-------- chaining cell (backward branch): 0x%04x", dest);
+ break;
+ case kMipsPseudoChainingCellNormal:
+ ALOGD("L%p:", lir);
+ ALOGD("-------- chaining cell (normal): 0x%04x", dest);
+ break;
+ case kMipsPseudoChainingCellHot:
+ ALOGD("L%p:", lir);
+ ALOGD("-------- chaining cell (hot): 0x%04x", dest);
+ break;
+ case kMipsPseudoChainingCellInvokePredicted:
+ ALOGD("L%p:", lir);
+ ALOGD("-------- chaining cell (predicted): %s%s",
+ dest ? ((Method *) dest)->clazz->descriptor : "",
+ dest ? ((Method *) dest)->name : "N/A");
+ break;
+ case kMipsPseudoChainingCellInvokeSingleton:
+ ALOGD("L%p:", lir);
+ ALOGD("-------- chaining cell (invoke singleton): %s%s/%p",
+ ((Method *)dest)->clazz->descriptor,
+ ((Method *)dest)->name,
+ ((Method *)dest)->insns);
+ break;
+ case kMipsPseudoEntryBlock:
+ ALOGD("-------- entry offset: 0x%04x", dest);
+ break;
+ case kMipsPseudoDalvikByteCodeBoundary:
+ ALOGD("-------- dalvik offset: 0x%04x @ %s", dest,
+ (char *) lir->operands[1]);
+ break;
+ case kMipsPseudoExitBlock:
+ ALOGD("-------- exit offset: 0x%04x", dest);
+ break;
+ case kMipsPseudoPseudoAlign4:
+ ALOGD("%p (%04x): .align4", baseAddr + offset, offset);
+ break;
+ case kMipsPseudoPCReconstructionCell:
+ ALOGD("L%p:", lir);
+ ALOGD("-------- reconstruct dalvik PC : 0x%04x @ +0x%04x", dest,
+ lir->operands[1]);
+ break;
+ case kMipsPseudoPCReconstructionBlockLabel:
+ /* Do nothing */
+ break;
+ case kMipsPseudoEHBlockLabel:
+ ALOGD("Exception_Handling:");
+ break;
+ case kMipsPseudoTargetLabel:
+ case kMipsPseudoNormalBlockLabel:
+ ALOGD("L%p:", lir);
+ break;
+ default:
+ if (lir->flags.isNop && !dumpNop) {
+ break;
+ }
+ buildInsnString(EncodingMap[lir->opcode].name, lir, opName,
+ baseAddr, 256);
+ buildInsnString(EncodingMap[lir->opcode].fmt, lir, buf, baseAddr,
+ 256);
+ ALOGD("%p (%04x): %08x %-9s%s%s",
+ baseAddr + offset, offset, *(u4 *)(baseAddr + offset), opName, buf,
+ lir->flags.isNop ? "(nop)" : "");
+ break;
+ }
+
+ if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
+ DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
+ lir->useMask, "use"));
+ }
+ if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
+ DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
+ lir->defMask, "def"));
+ }
+}
+
+/* Dump instructions and constant pool contents */
+void dvmCompilerCodegenDump(CompilationUnit *cUnit)
+{
+ ALOGD("Dumping LIR insns");
+ LIR *lirInsn;
+ MipsLIR *mipsLIR;
+
+ ALOGD("installed code is at %p", cUnit->baseAddr);
+ ALOGD("total size is %d bytes", cUnit->totalSize);
+ for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
+ dvmDumpLIRInsn(lirInsn, (unsigned char *) cUnit->baseAddr);
+ }
+ for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
+ mipsLIR = (MipsLIR *) lirInsn;
+ ALOGD("%p (%04x): .class (%s)",
+ (char*)cUnit->baseAddr + mipsLIR->generic.offset,
+ mipsLIR->generic.offset,
+ ((CallsiteInfo *) mipsLIR->operands[0])->classDescriptor);
+ }
+ for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
+ mipsLIR = (MipsLIR *) lirInsn;
+ ALOGD("%p (%04x): .word (%#x)",
+ (char*)cUnit->baseAddr + mipsLIR->generic.offset,
+ mipsLIR->generic.offset,
+ mipsLIR->operands[0]);
+ }
+}
+
+/* Target-specific cache flushing */
+void dvmCompilerCacheFlush(long start, long end, long flags)
+{
+ cacheflush(start, end, flags);
+}
+
+/* Target-specific cache clearing */
+void dvmCompilerCacheClear(char *start, size_t size)
+{
+ /* 0x66 is an invalid opcode for mips. */
+ memset(start, 0x66, size);
+}
diff --git a/vm/compiler/codegen/mips/Assemble.cpp b/vm/compiler/codegen/mips/Assemble.cpp
new file mode 100644
index 0000000..713bced
--- /dev/null
+++ b/vm/compiler/codegen/mips/Assemble.cpp
@@ -0,0 +1,2324 @@
+/*
+ * 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.
+ */
+
+#include "Dalvik.h"
+#include "libdex/DexOpcodes.h"
+
+#include "../../CompilerInternals.h"
+#include "MipsLIR.h"
+#include "Codegen.h"
+#include <unistd.h> /* for cacheflush */
+#include <sys/mman.h> /* for protection change */
+
+#define MAX_ASSEMBLER_RETRIES 10
+
+/*
+ * opcode: MipsOpCode enum
+ * skeleton: pre-designated bit-pattern for this opcode
+ * k0: key to applying ds/de
+ * ds: dest start bit position
+ * de: dest end bit position
+ * k1: key to applying s1s/s1e
+ * s1s: src1 start bit position
+ * s1e: src1 end bit position
+ * k2: key to applying s2s/s2e
+ * s2s: src2 start bit position
+ * s2e: src2 end bit position
+ * operands: number of operands (for sanity check purposes)
+ * name: mnemonic name
+ * fmt: for pretty-printing
+ */
+#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
+ k3, k3s, k3e, flags, name, fmt, size) \
+ {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
+ {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
+
+/* Instruction dump string format keys: !pf, where "!" is the start
+ * of the key, "p" is which numeric operand to use and "f" is the
+ * print format.
+ *
+ * [p]ositions:
+ * 0 -> operands[0] (dest)
+ * 1 -> operands[1] (src1)
+ * 2 -> operands[2] (src2)
+ * 3 -> operands[3] (extra)
+ *
+ * [f]ormats:
+ * h -> 4-digit hex
+ * d -> decimal
+ * E -> decimal*4
+ * F -> decimal*2
+ * c -> branch condition (beq, bne, etc.)
+ * t -> pc-relative target
+ * T -> pc-region target
+ * u -> 1st half of bl[x] target
+ * v -> 2nd half ob bl[x] target
+ * R -> register list
+ * s -> single precision floating point register
+ * S -> double precision floating point register
+ * m -> Thumb2 modified immediate
+ * n -> complimented Thumb2 modified immediate
+ * M -> Thumb2 16-bit zero-extended immediate
+ * b -> 4-digit binary
+ *
+ * [!] escape. To insert "!", use "!!"
+ */
+/* NOTE: must be kept in sync with enum MipsOpcode from MipsLIR.h */
+MipsEncodingMap EncodingMap[kMipsLast] = {
+ ENCODING_MAP(kMips32BitData, 0x00000000,
+ kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP,
+ "data", "0x!0h(!0d)", 2),
+ ENCODING_MAP(kMipsAddiu, 0x24000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+ "addiu", "!0r,!1r,0x!2h(!2d)", 2),
+ ENCODING_MAP(kMipsAddu, 0x00000021,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "addu", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsAnd, 0x00000024,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "and", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsAndi, 0x30000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+ "andi", "!0r,!1r,0x!2h(!2d)", 2),
+ ENCODING_MAP(kMipsB, 0x10000000,
+ kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
+ "b", "!0t", 2),
+ ENCODING_MAP(kMipsBal, 0x04110000,
+ kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
+ "bal", "!0t", 2),
+ ENCODING_MAP(kMipsBeq, 0x10000000,
+ kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
+ kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
+ "beq", "!0r,!1r,!2t", 2),
+ ENCODING_MAP(kMipsBeqz, 0x10000000, /* same as beq above with t = $zero */
+ kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+ "beqz", "!0r,!1t", 2),
+ ENCODING_MAP(kMipsBgez, 0x04010000,
+ kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+ "bgez", "!0r,!1t", 2),
+ ENCODING_MAP(kMipsBgtz, 0x1C000000,
+ kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+ "bgtz", "!0r,!1t", 2),
+ ENCODING_MAP(kMipsBlez, 0x18000000,
+ kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+ "blez", "!0r,!1t", 2),
+ ENCODING_MAP(kMipsBltz, 0x04000000,
+ kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+ "bltz", "!0r,!1t", 2),
+ ENCODING_MAP(kMipsBnez, 0x14000000, /* same as bne below with t = $zero */
+ kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+ "bnez", "!0r,!1t", 2),
+ ENCODING_MAP(kMipsBne, 0x14000000,
+ kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
+ kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
+ "bne", "!0r,!1r,!2t", 2),
+ ENCODING_MAP(kMipsDiv, 0x0000001a,
+ kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
+ kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
+ "div", "!2r,!3r", 2),
+#if __mips_isa_rev>=2
+ ENCODING_MAP(kMipsExt, 0x7c000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 10, 6,
+ kFmtBitBlt, 15, 11, IS_QUAD_OP | REG_DEF0 | REG_USE1,
+ "ext", "!0r,!1r,!2d,!3D", 2),
+#endif
+ ENCODING_MAP(kMipsJal, 0x0c000000,
+ kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
+ "jal", "!0T(!0E)", 2),
+ ENCODING_MAP(kMipsJalr, 0x00000009,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF0_USE1,
+ "jalr", "!0r,!1r", 2),
+ ENCODING_MAP(kMipsJr, 0x00000008,
+ kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+ "jr", "!0r", 2),
+ ENCODING_MAP(kMipsLahi, 0x3C000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+ "lahi/lui", "!0r,0x!1h(!1d)", 2),
+ ENCODING_MAP(kMipsLalo, 0x34000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+ "lalo/ori", "!0r,!1r,0x!2h(!2d)", 2),
+ ENCODING_MAP(kMipsLui, 0x3C000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+ "lui", "!0r,0x!1h(!1d)", 2),
+ ENCODING_MAP(kMipsLb, 0x80000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+ "lb", "!0r,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsLbu, 0x90000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+ "lbu", "!0r,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsLh, 0x84000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+ "lh", "!0r,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsLhu, 0x94000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+ "lhu", "!0r,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsLw, 0x8C000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+ "lw", "!0r,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsMfhi, 0x00000010,
+ kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "mfhi", "!0r", 2),
+ ENCODING_MAP(kMipsMflo, 0x00000012,
+ kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "mflo", "!0r", 2),
+ ENCODING_MAP(kMipsMove, 0x00000025, /* or using zero reg */
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "move", "!0r,!1r", 2),
+ ENCODING_MAP(kMipsMovz, 0x0000000a,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "movz", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsMul, 0x70000002,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "mul", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsNop, 0x00000000,
+ kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, NO_OPERAND,
+ "nop", "", 2),
+ ENCODING_MAP(kMipsNor, 0x00000027, /* used for "not" too */
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "nor", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsOr, 0x00000025,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "or", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsOri, 0x34000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+ "ori", "!0r,!1r,0x!2h(!2d)", 2),
+ ENCODING_MAP(kMipsPref, 0xCC000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE2,
+ "pref", "!0d,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsSb, 0xA0000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+ "sb", "!0r,!1d(!2r)", 2),
+#if __mips_isa_rev>=2
+ ENCODING_MAP(kMipsSeb, 0x7c000420,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "seb", "!0r,!1r", 2),
+ ENCODING_MAP(kMipsSeh, 0x7c000620,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "seh", "!0r,!1r", 2),
+#endif
+ ENCODING_MAP(kMipsSh, 0xA4000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+ "sh", "!0r,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsSll, 0x00000000,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+ "sll", "!0r,!1r,0x!2h(!2d)", 2),
+ ENCODING_MAP(kMipsSllv, 0x00000004,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "sllv", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsSlt, 0x0000002a,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "slt", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsSlti, 0x28000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+ "slti", "!0r,!1r,0x!2h(!2d)", 2),
+ ENCODING_MAP(kMipsSltu, 0x0000002b,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "sltu", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsSra, 0x00000003,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+ "sra", "!0r,!1r,0x!2h(!2d)", 2),
+ ENCODING_MAP(kMipsSrav, 0x00000007,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "srav", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsSrl, 0x00000002,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+ "srl", "!0r,!1r,0x!2h(!2d)", 2),
+ ENCODING_MAP(kMipsSrlv, 0x00000006,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "srlv", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsSubu, 0x00000023, /* used for "neg" too */
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "subu", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsSw, 0xAC000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+ "sw", "!0r,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsXor, 0x00000026,
+ kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "xor", "!0r,!1r,!2r", 2),
+ ENCODING_MAP(kMipsXori, 0x38000000,
+ kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+ "xori", "!0r,!1r,0x!2h(!2d)", 2),
+#ifdef __mips_hard_float
+ ENCODING_MAP(kMipsFadds, 0x46000000,
+ kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "add.s", "!0s,!1s,!2s", 2),
+ ENCODING_MAP(kMipsFsubs, 0x46000001,
+ kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "sub.s", "!0s,!1s,!2s", 2),
+ ENCODING_MAP(kMipsFmuls, 0x46000002,
+ kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "mul.s", "!0s,!1s,!2s", 2),
+ ENCODING_MAP(kMipsFdivs, 0x46000003,
+ kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "div.s", "!0s,!1s,!2s", 2),
+ ENCODING_MAP(kMipsFaddd, 0x46200000,
+ kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "add.d", "!0S,!1S,!2S", 2),
+ ENCODING_MAP(kMipsFsubd, 0x46200001,
+ kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "sub.d", "!0S,!1S,!2S", 2),
+ ENCODING_MAP(kMipsFmuld, 0x46200002,
+ kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "mul.d", "!0S,!1S,!2S", 2),
+ ENCODING_MAP(kMipsFdivd, 0x46200003,
+ kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+ "div.d", "!0S,!1S,!2S", 2),
+ ENCODING_MAP(kMipsFcvtsd, 0x46200020,
+ kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "cvt.s.d", "!0s,!1S", 2),
+ ENCODING_MAP(kMipsFcvtsw, 0x46800020,
+ kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "cvt.s.w", "!0s,!1s", 2),
+ ENCODING_MAP(kMipsFcvtds, 0x46000021,
+ kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "cvt.d.s", "!0S,!1s", 2),
+ ENCODING_MAP(kMipsFcvtdw, 0x46800021,
+ kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "cvt.d.w", "!0S,!1s", 2),
+ ENCODING_MAP(kMipsFcvtws, 0x46000024,
+ kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "cvt.w.s", "!0s,!1s", 2),
+ ENCODING_MAP(kMipsFcvtwd, 0x46200024,
+ kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "cvt.w.d", "!0s,!1S", 2),
+ ENCODING_MAP(kMipsFmovs, 0x46000006,
+ kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "mov.s", "!0s,!1s", 2),
+ ENCODING_MAP(kMipsFmovd, 0x46200006,
+ kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "mov.d", "!0S,!1S", 2),
+ ENCODING_MAP(kMipsFlwc1, 0xC4000000,
+ kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+ "lwc1", "!0s,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsFldc1, 0xD4000000,
+ kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+ "ldc1", "!0S,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsFswc1, 0xE4000000,
+ kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+ "swc1", "!0s,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsFsdc1, 0xF4000000,
+ kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+ kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+ "sdc1", "!0S,!1d(!2r)", 2),
+ ENCODING_MAP(kMipsMfc1, 0x44000000,
+ kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+ "mfc1", "!0r,!1s", 2),
+ ENCODING_MAP(kMipsMtc1, 0x44800000,
+ kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
+ "mtc1", "!0r,!1s", 2),
+#endif
+ ENCODING_MAP(kMipsUndefined, 0x64000000,
+ kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+ kFmtUnused, -1, -1, NO_OPERAND,
+ "undefined", "", 2),
+};
+
+/* Track the number of times that the code cache is patched */
+#if defined(WITH_JIT_TUNING)
+#define UPDATE_CODE_CACHE_PATCHES() (gDvmJit.codeCachePatches++)
+#else
+#define UPDATE_CODE_CACHE_PATCHES()
+#endif
+
+/* Write the numbers in the constant and class pool to the output stream */
+static void installLiteralPools(CompilationUnit *cUnit)
+{
+ int *dataPtr = (int *) ((char *) cUnit->baseAddr + cUnit->dataOffset);
+ /* Install number of class pointer literals */
+ *dataPtr++ = cUnit->numClassPointers;
+ MipsLIR *dataLIR = (MipsLIR *) cUnit->classPointerList;
+ while (dataLIR) {
+ /*
+ * Install the callsiteinfo pointers into the cells for now. They will
+ * be converted into real pointers in dvmJitInstallClassObjectPointers.
+ */
+ *dataPtr++ = dataLIR->operands[0];
+ dataLIR = NEXT_LIR(dataLIR);
+ }
+ dataLIR = (MipsLIR *) cUnit->literalList;
+ while (dataLIR) {
+ *dataPtr++ = dataLIR->operands[0];
+ dataLIR = NEXT_LIR(dataLIR);
+ }
+}
+
+/*
+ * Assemble the LIR into binary instruction format. Note that we may
+ * discover that pc-relative displacements may not fit the selected
+ * instruction. In those cases we will try to substitute a new code
+ * sequence or request that the trace be shortened and retried.
+ */
+static AssemblerStatus assembleInstructions(CompilationUnit *cUnit,
+ intptr_t startAddr)
+{
+ int *bufferAddr = (int *) cUnit->codeBuffer;
+ MipsLIR *lir;
+
+ for (lir = (MipsLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
+ if (lir->opcode < 0) {
+ continue;
+ }
+
+
+ if (lir->flags.isNop) {
+ continue;
+ }
+
+ if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
+ MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+ intptr_t pc = lir->generic.offset + 4;
+ intptr_t target = targetLIR->generic.offset;
+ int delta = target - pc;
+ if (delta & 0x3) {
+ ALOGE("PC-rel distance is not multiple of 4: %d", delta);
+ dvmAbort();
+ }
+ if (delta > 131068 || delta < -131069) {
+ ALOGE("Unconditional branch distance out of range: %d", delta);
+ dvmAbort();
+ }
+ lir->operands[0] = delta >> 2;
+ } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
+ MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+ intptr_t pc = lir->generic.offset + 4;
+ intptr_t target = targetLIR->generic.offset;
+ int delta = target - pc;
+ if (delta & 0x3) {
+ ALOGE("PC-rel distance is not multiple of 4: %d", delta);
+ dvmAbort();
+ }
+ if (delta > 131068 || delta < -131069) {
+ ALOGE("Conditional branch distance out of range: %d", delta);
+ dvmAbort();
+ }
+ lir->operands[1] = delta >> 2;
+ } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
+ MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+ intptr_t pc = lir->generic.offset + 4;
+ intptr_t target = targetLIR->generic.offset;
+ int delta = target - pc;
+ if (delta & 0x3) {
+ ALOGE("PC-rel distance is not multiple of 4: %d", delta);
+ dvmAbort();
+ }
+ if (delta > 131068 || delta < -131069) {
+ ALOGE("Conditional branch distance out of range: %d", delta);
+ dvmAbort();
+ }
+ lir->operands[2] = delta >> 2;
+ } else if (lir->opcode == kMipsJal) {
+ intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3;
+ intptr_t target = lir->operands[0];
+ /* ensure PC-region branch can be used */
+ assert((curPC & 0xF0000000) == (target & 0xF0000000));
+ if (target & 0x3) {
+ ALOGE("Jump target is not multiple of 4: %d", target);
+ dvmAbort();
+ }
+ lir->operands[0] = target >> 2;
+ } else if (lir->opcode == kMipsLahi) { /* load address hi (via lui) */
+ MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+ intptr_t target = startAddr + targetLIR->generic.offset;
+ lir->operands[1] = target >> 16;
+ } else if (lir->opcode == kMipsLalo) { /* load address lo (via ori) */
+ MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+ intptr_t target = startAddr + targetLIR->generic.offset;
+ lir->operands[2] = lir->operands[2] + target;
+ }
+
+
+ MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
+ u4 bits = encoder->skeleton;
+ int i;
+ for (i = 0; i < 4; i++) {
+ u4 operand;
+ u4 value;
+ operand = lir->operands[i];
+ switch(encoder->fieldLoc[i].kind) {
+ case kFmtUnused:
+ break;
+ case kFmtBitBlt:
+ if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) {
+ value = operand;
+ } else {
+ value = (operand << encoder->fieldLoc[i].start) &
+ ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+ }
+ bits |= value;
+ break;
+ case kFmtDfp: {
+ assert(DOUBLEREG(operand));
+ assert((operand & 0x1) == 0);
+ value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
+ ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+ bits |= value;
+ break;
+ }
+ case kFmtSfp:
+ assert(SINGLEREG(operand));
+ value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
+ ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+ bits |= value;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ assert(encoder->size == 2);
+ *bufferAddr++ = bits;
+ }
+ return kSuccess;
+}
+
+static int assignLiteralOffsetCommon(LIR *lir, int offset)
+{
+ for (;lir != NULL; lir = lir->next) {
+ lir->offset = offset;
+ offset += 4;
+ }
+ return offset;
+}
+
+/* Determine the offset of each literal field */
+static int assignLiteralOffset(CompilationUnit *cUnit, int offset)
+{
+ /* Reserved for the size field of class pointer pool */
+ offset += 4;
+ offset = assignLiteralOffsetCommon(cUnit->classPointerList, offset);
+ offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
+ return offset;
+}
+
+/*
+ * Translation layout in the code cache. Note that the codeAddress pointer
+ * in JitTable will point directly to the code body (field codeAddress). The
+ * chain cell offset codeAddress - 4, and the address of the trace profile
+ * counter is at codeAddress - 8.
+ *
+ * +----------------------------+
+ * | Trace Profile Counter addr | -> 4 bytes (PROF_COUNTER_ADDR_SIZE)
+ * +----------------------------+
+ * +--| Offset to chain cell counts| -> 4 bytes (CHAIN_CELL_OFFSET_SIZE)
+ * | +----------------------------+
+ * | | Trace profile code | <- entry point when profiling
+ * | . - - - - - - - .
+ * | | Code body | <- entry point when not profiling
+ * | . .
+ * | | |
+ * | +----------------------------+
+ * | | Chaining Cells | -> 16/20 bytes, 4 byte aligned
+ * | . .
+ * | . .
+ * | | |
+ * | +----------------------------+
+ * | | Gap for large switch stmt | -> # cases >= MAX_CHAINED_SWITCH_CASES
+ * | +----------------------------+
+ * +->| Chaining cell counts | -> 8 bytes, chain cell counts by type
+ * +----------------------------+
+ * | Trace description | -> variable sized
+ * . .
+ * | |
+ * +----------------------------+
+ * | # Class pointer pool size | -> 4 bytes
+ * +----------------------------+
+ * | Class pointer pool | -> 4-byte aligned, variable size
+ * . .
+ * . .
+ * | |
+ * +----------------------------+
+ * | Literal pool | -> 4-byte aligned, variable size
+ * . .
+ * . .
+ * | |
+ * +----------------------------+
+ *
+ */
+
+#define PROF_COUNTER_ADDR_SIZE 4
+#define CHAIN_CELL_OFFSET_SIZE 4
+
+/*
+ * Utility functions to navigate various parts in a trace. If we change the
+ * layout/offset in the future, we just modify these functions and we don't need
+ * to propagate the changes to all the use cases.
+ */
+static inline char *getTraceBase(const JitEntry *p)
+{
+ return (char*)p->codeAddress -
+ (PROF_COUNTER_ADDR_SIZE + CHAIN_CELL_OFFSET_SIZE);
+}
+
+/* Handy function to retrieve the profile count */
+static inline JitTraceCounter_t getProfileCount(const JitEntry *entry)
+{
+ if (entry->dPC == 0 || entry->codeAddress == 0 ||
+ entry->codeAddress == dvmCompilerGetInterpretTemplate())
+ return 0;
+
+ JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry);
+
+ return **p;
+}
+
+/* Handy function to reset the profile count */
+static inline void resetProfileCount(const JitEntry *entry)
+{
+ if (entry->dPC == 0 || entry->codeAddress == 0 ||
+ entry->codeAddress == dvmCompilerGetInterpretTemplate())
+ return;
+
+ JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry);
+
+ **p = 0;
+}
+
+/* Get the pointer of the chain cell count */
+static inline ChainCellCounts* getChainCellCountsPointer(const char *base)
+{
+ /* 4 is the size of the profile count */
+ u4 *chainCellOffsetP = (u4 *) (base + PROF_COUNTER_ADDR_SIZE);
+ u4 chainCellOffset = *chainCellOffsetP;
+ return (ChainCellCounts *) ((char *) chainCellOffsetP + chainCellOffset);
+}
+
+/* Get the size of all chaining cells */
+static inline u4 getChainCellSize(const ChainCellCounts* pChainCellCounts)
+{
+ int cellSize = 0;
+ int i;
+
+ /* Get total count of chain cells */
+ for (i = 0; i < kChainingCellGap; i++) {
+ if (i != kChainingCellInvokePredicted) {
+ cellSize += pChainCellCounts->u.count[i] *
+ (CHAIN_CELL_NORMAL_SIZE >> 2);
+ } else {
+ cellSize += pChainCellCounts->u.count[i] *
+ (CHAIN_CELL_PREDICTED_SIZE >> 2);
+ }
+ }
+ return cellSize;
+}
+
+/* Get the starting pointer of the trace description section */
+static JitTraceDescription* getTraceDescriptionPointer(const char *base)
+{
+ ChainCellCounts* pCellCounts = getChainCellCountsPointer(base);
+ return (JitTraceDescription*) ((char*)pCellCounts + sizeof(*pCellCounts));
+}
+
+/* Get the size of a trace description */
+static int getTraceDescriptionSize(const JitTraceDescription *desc)
+{
+ int runCount;
+ /* Trace end is always of non-meta type (ie isCode == true) */
+ for (runCount = 0; ; runCount++) {
+ if (desc->trace[runCount].isCode &&
+ desc->trace[runCount].info.frag.runEnd)
+ break;
+ }
+ return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun));
+}
+
+#if defined(SIGNATURE_BREAKPOINT)
+/* Inspect the assembled instruction stream to find potential matches */
+static void matchSignatureBreakpoint(const CompilationUnit *cUnit,
+ unsigned int size)
+{
+ unsigned int i, j;
+ u4 *ptr = (u4 *) cUnit->codeBuffer;
+
+ for (i = 0; i < size - gDvmJit.signatureBreakpointSize + 1; i++) {
+ if (ptr[i] == gDvmJit.signatureBreakpoint[0]) {
+ for (j = 1; j < gDvmJit.signatureBreakpointSize; j++) {
+ if (ptr[i+j] != gDvmJit.signatureBreakpoint[j]) {
+ break;
+ }
+ }
+ if (j == gDvmJit.signatureBreakpointSize) {
+ ALOGD("Signature match starting from offset %#x (%d words)",
+ i*4, gDvmJit.signatureBreakpointSize);
+ int descSize = getTraceDescriptionSize(cUnit->traceDesc);
+ JitTraceDescription *newCopy =
+ (JitTraceDescription *) malloc(descSize);
+ memcpy(newCopy, cUnit->traceDesc, descSize);
+ dvmCompilerWorkEnqueue(NULL, kWorkOrderTraceDebug, newCopy);
+ break;
+ }
+ }
+ }
+}
+#endif
+
+/*
+ * Go over each instruction in the list and calculate the offset from the top
+ * before sending them off to the assembler. If out-of-range branch distance is
+ * seen rearrange the instructions a bit to correct it.
+ */
+void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
+{
+ MipsLIR *mipsLIR;
+ int offset = 0;
+ int i;
+ ChainCellCounts chainCellCounts;
+ int descSize = (cUnit->jitMode == kJitMethod) ?
+ 0 : getTraceDescriptionSize(cUnit->traceDesc);
+ int chainingCellGap = 0;
+
+ info->instructionSet = cUnit->instructionSet;
+
+ /* Beginning offset needs to allow space for chain cell offset */
+ for (mipsLIR = (MipsLIR *) cUnit->firstLIRInsn;
+ mipsLIR;
+ mipsLIR = NEXT_LIR(mipsLIR)) {
+ mipsLIR->generic.offset = offset;
+ if (mipsLIR->opcode >= 0 && !mipsLIR->flags.isNop) {
+ mipsLIR->flags.size = EncodingMap[mipsLIR->opcode].size * 2;
+ offset += mipsLIR->flags.size;
+ }
+ /* Pseudo opcodes don't consume space */
+ }
+
+ /* Const values have to be word aligned */
+ offset = (offset + 3) & ~3;
+
+ u4 chainCellOffset = offset;
+ MipsLIR *chainCellOffsetLIR = NULL;
+
+ if (cUnit->jitMode != kJitMethod) {
+ /*
+ * Get the gap (# of u4) between the offset of chaining cell count and
+ * the bottom of real chaining cells. If the translation has chaining
+ * cells, the gap is guaranteed to be multiples of 4.
+ */
+ chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2;
+
+ /* Add space for chain cell counts & trace description */
+ chainCellOffsetLIR = (MipsLIR *) cUnit->chainCellOffsetLIR;
+ assert(chainCellOffsetLIR);
+ assert(chainCellOffset < 0x10000);
+ assert(chainCellOffsetLIR->opcode == kMips32BitData &&
+ chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG);
+
+ /*
+ * Adjust the CHAIN_CELL_OFFSET_TAG LIR's offset to remove the
+ * space occupied by the pointer to the trace profiling counter.
+ */
+ chainCellOffsetLIR->operands[0] = chainCellOffset - 4;
+
+ offset += sizeof(chainCellCounts) + descSize;
+
+ assert((offset & 0x3) == 0); /* Should still be word aligned */
+ }
+
+ /* Set up offsets for literals */
+ cUnit->dataOffset = offset;
+
+ /*
+ * Assign each class pointer/constant an offset from the beginning of the
+ * compilation unit.
+ */
+ offset = assignLiteralOffset(cUnit, offset);
+
+ cUnit->totalSize = offset;
+
+ if (gDvmJit.codeCacheByteUsed + cUnit->totalSize > gDvmJit.codeCacheSize) {
+ gDvmJit.codeCacheFull = true;
+ info->discardResult = true;
+ return;
+ }
+
+ /* Allocate enough space for the code block */
+ cUnit->codeBuffer = (unsigned char *)dvmCompilerNew(chainCellOffset, true);
+ if (cUnit->codeBuffer == NULL) {
+ ALOGE("Code buffer allocation failure");
+ info->discardResult = true;
+ return;
+ }
+
+ /*
+ * Attempt to assemble the trace. Note that assembleInstructions
+ * may rewrite the code sequence and request a retry.
+ */
+ cUnit->assemblerStatus = assembleInstructions(cUnit,
+ (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed);
+
+ switch(cUnit->assemblerStatus) {
+ case kSuccess:
+ break;
+ case kRetryAll:
+ if (cUnit->assemblerRetries < MAX_ASSEMBLER_RETRIES) {
+ if (cUnit->jitMode != kJitMethod) {
+ /* Restore pristine chain cell marker on retry */
+ chainCellOffsetLIR->operands[0] = CHAIN_CELL_OFFSET_TAG;
+ }
+ return;
+ }
+ /* Too many retries - reset and try cutting the trace in half */
+ cUnit->assemblerRetries = 0;
+ cUnit->assemblerStatus = kRetryHalve;
+ return;
+ case kRetryHalve:
+ return;
+ default:
+ ALOGE("Unexpected assembler status: %d", cUnit->assemblerStatus);
+ dvmAbort();
+ }
+
+#if defined(SIGNATURE_BREAKPOINT)
+ if (info->discardResult == false && gDvmJit.signatureBreakpoint != NULL &&
+ chainCellOffset/4 >= gDvmJit.signatureBreakpointSize) {
+ matchSignatureBreakpoint(cUnit, chainCellOffset/4);
+ }
+#endif
+
+ /* Don't go all the way if the goal is just to get the verbose output */
+ if (info->discardResult) return;
+
+ /*
+ * The cache might disappear - acquire lock and check version
+ * Continue holding lock until translation cache update is complete.
+ * These actions are required here in the compiler thread because
+ * it is unaffected by suspend requests and doesn't know if a
+ * translation cache flush is in progress.
+ */
+ dvmLockMutex(&gDvmJit.compilerLock);
+ if (info->cacheVersion != gDvmJit.cacheVersion) {
+ /* Cache changed - discard current translation */
+ info->discardResult = true;
+ info->codeAddress = NULL;
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+ return;
+ }
+
+ cUnit->baseAddr = (char *) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
+ gDvmJit.codeCacheByteUsed += offset;
+
+ UNPROTECT_CODE_CACHE(cUnit->baseAddr, offset);
+
+ /* Install the code block */
+ memcpy((char*)cUnit->baseAddr, cUnit->codeBuffer, chainCellOffset);
+ gDvmJit.numCompilations++;
+
+ if (cUnit->jitMode != kJitMethod) {
+ /* Install the chaining cell counts */
+ for (i=0; i< kChainingCellGap; i++) {
+ chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
+ }
+
+ /* Set the gap number in the chaining cell count structure */
+ chainCellCounts.u.count[kChainingCellGap] = chainingCellGap;
+
+ memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
+ sizeof(chainCellCounts));
+
+ /* Install the trace description */
+ memcpy((char*) cUnit->baseAddr + chainCellOffset +
+ sizeof(chainCellCounts),
+ cUnit->traceDesc, descSize);
+ }
+
+ /* Write the literals directly into the code cache */
+ installLiteralPools(cUnit);
+
+ /* Flush dcache and invalidate the icache to maintain coherence */
+ dvmCompilerCacheFlush((long)cUnit->baseAddr,
+ (long)((char *) cUnit->baseAddr + offset), 0);
+
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(cUnit->baseAddr, offset);
+
+ /* Translation cache update complete - release lock */
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+
+ /* Record code entry point and instruction set */
+ info->codeAddress = (char*)cUnit->baseAddr + cUnit->headerSize;
+ /* transfer the size of the profiling code */
+ info->profileCodeSize = cUnit->profileCodeSize;
+}
+
+/*
+ * Returns the skeleton bit pattern associated with an opcode. All
+ * variable fields are zeroed.
+ */
+static u4 getSkeleton(MipsOpCode op)
+{
+ return EncodingMap[op].skeleton;
+}
+
+static u4 assembleChainingBranch(int branchOffset, bool thumbTarget)
+{
+ return getSkeleton(kMipsJal) | ((branchOffset & 0x0FFFFFFF) >> 2);
+}
+
+/*
+ * Perform translation chain operation.
+ * For MIPS, we'll use a JAL instruction to generate an
+ * unconditional chaining branch of up to 256M. The JAL
+ * instruction also has a restriction that the jump target
+ * must be in the same 256M page as the JAL instruction's
+ * delay slot address.
+ * If the target is out of JAL's range, don't chain.
+ * If one or more threads is suspended, don't chain.
+ */
+void* dvmJitChain(void* tgtAddr, u4* branchAddr)
+{
+ u4 newInst;
+
+ /*
+ * Only chain translations when there is no urge to ask all threads to
+ * suspend themselves via the interpreter.
+ */
+ if ((gDvmJit.pProfTable != NULL) && (gDvm.sumThreadSuspendCount == 0) &&
+ (gDvmJit.codeCacheFull == false) &&
+ ((((int) tgtAddr) & 0xF0000000) == (((int) branchAddr+4) & 0xF0000000))) {
+ gDvmJit.translationChains++;
+
+ COMPILER_TRACE_CHAINING(
+ ALOGD("Jit Runtime: chaining 0x%x to 0x%x",
+ (int) branchAddr, (int) tgtAddr & -2));
+
+ newInst = assembleChainingBranch((int) tgtAddr & -2, 0);
+
+ UNPROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
+
+ *branchAddr = newInst;
+ dvmCompilerCacheFlush((long)branchAddr, (long)branchAddr + 4, 0);
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
+
+ gDvmJit.hasNewChain = true;
+ }
+
+ return tgtAddr;
+}
+
+#if !defined(WITH_SELF_VERIFICATION)
+/*
+ * Attempt to enqueue a work order to patch an inline cache for a predicted
+ * chaining cell for virtual/interface calls.
+ */
+static void inlineCachePatchEnqueue(PredictedChainingCell *cellAddr,
+ PredictedChainingCell *newContent)
+{
+ /*
+ * Make sure only one thread gets here since updating the cell (ie fast
+ * path and queueing the request (ie the queued path) have to be done
+ * in an atomic fashion.
+ */
+ dvmLockMutex(&gDvmJit.compilerICPatchLock);
+
+ /* Fast path for uninitialized chaining cell */
+ if (cellAddr->clazz == NULL &&
+ cellAddr->branch == PREDICTED_CHAIN_BX_PAIR_INIT) {
+
+ UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+ cellAddr->method = newContent->method;
+ cellAddr->branch = newContent->branch;
+
+ /*
+ * The update order matters - make sure clazz is updated last since it
+ * will bring the uninitialized chaining cell to life.
+ */
+ android_atomic_release_store((int32_t)newContent->clazz,
+ (volatile int32_t *)(void*) &cellAddr->clazz);
+ dvmCompilerCacheFlush((long) cellAddr, (long) (cellAddr+1), 0);
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchInit++;
+#endif
+ /* Check if this is a frequently missed clazz */
+ } else if (cellAddr->stagedClazz != newContent->clazz) {
+ /* Not proven to be frequent yet - build up the filter cache */
+ UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+ cellAddr->stagedClazz = newContent->clazz;
+
+ UPDATE_CODE_CACHE_PATCHES();
+ PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchRejected++;
+#endif
+ /*
+ * Different classes but same method implementation - it is safe to just
+ * patch the class value without the need to stop the world.
+ */
+ } else if (cellAddr->method == newContent->method) {
+ UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+ cellAddr->clazz = newContent->clazz;
+ /* No need to flush the cache here since the branch is not patched */
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchLockFree++;
+#endif
+ /*
+ * Cannot patch the chaining cell inline - queue it until the next safe
+ * point.
+ */
+ } else if (gDvmJit.compilerICPatchIndex < COMPILER_IC_PATCH_QUEUE_SIZE) {
+ int index = gDvmJit.compilerICPatchIndex++;
+ const ClassObject *clazz = newContent->clazz;
+
+ gDvmJit.compilerICPatchQueue[index].cellAddr = cellAddr;
+ gDvmJit.compilerICPatchQueue[index].cellContent = *newContent;
+ gDvmJit.compilerICPatchQueue[index].classDescriptor = clazz->descriptor;
+ gDvmJit.compilerICPatchQueue[index].classLoader = clazz->classLoader;
+ /* For verification purpose only */
+ gDvmJit.compilerICPatchQueue[index].serialNumber = clazz->serialNumber;
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchQueued++;
+#endif
+ } else {
+ /* Queue is full - just drop this patch request */
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchDropped++;
+#endif
+ }
+
+ dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
+}
+#endif
+
+/*
+ * This method is called from the invoke templates for virtual and interface
+ * methods to speculatively setup a chain to the callee. The templates are
+ * written in assembly and have setup method, cell, and clazz at r0, r2, and
+ * r3 respectively, so there is a unused argument in the list. Upon return one
+ * of the following three results may happen:
+ * 1) Chain is not setup because the callee is native. Reset the rechain
+ * count to a big number so that it will take a long time before the next
+ * rechain attempt to happen.
+ * 2) Chain is not setup because the callee has not been created yet. Reset
+ * the rechain count to a small number and retry in the near future.
+ * 3) Ask all other threads to stop before patching this chaining cell.
+ * This is required because another thread may have passed the class check
+ * but hasn't reached the chaining cell yet to follow the chain. If we
+ * patch the content before halting the other thread, there could be a
+ * small window for race conditions to happen that it may follow the new
+ * but wrong chain to invoke a different method.
+ */
+const Method *dvmJitToPatchPredictedChain(const Method *method,
+ Thread *self,
+ PredictedChainingCell *cell,
+ const ClassObject *clazz)
+{
+ int newRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
+#if defined(WITH_SELF_VERIFICATION)
+ newRechainCount = PREDICTED_CHAIN_COUNTER_AVOID;
+ goto done;
+#else
+ PredictedChainingCell newCell;
+ int baseAddr, tgtAddr;
+ if (dvmIsNativeMethod(method)) {
+ UNPROTECT_CODE_CACHE(cell, sizeof(*cell));
+
+ /*
+ * Put a non-zero/bogus value in the clazz field so that it won't
+ * trigger immediate patching and will continue to fail to match with
+ * a real clazz pointer.
+ */
+ cell->clazz = (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ;
+
+ UPDATE_CODE_CACHE_PATCHES();
+ PROTECT_CODE_CACHE(cell, sizeof(*cell));
+ goto done;
+ }
+
+ tgtAddr = (int) dvmJitGetTraceAddr(method->insns);
+ baseAddr = (int) cell + 4; // PC is cur_addr + 4
+
+ if ((baseAddr & 0xF0000000) != (tgtAddr & 0xF0000000)) {
+ COMPILER_TRACE_CHAINING(
+ ALOGD("Jit Runtime: predicted chain %p to distant target %s ignored",
+ cell, method->name));
+ goto done;
+ }
+
+ /*
+ * Compilation not made yet for the callee. Reset the counter to a small
+ * value and come back to check soon.
+ */
+ if ((tgtAddr == 0) ||
+ ((void*)tgtAddr == dvmCompilerGetInterpretTemplate())) {
+ COMPILER_TRACE_CHAINING(
+ ALOGD("Jit Runtime: predicted chain %p to method %s%s delayed",
+ cell, method->clazz->descriptor, method->name));
+ goto done;
+ }
+
+ if (cell->clazz == NULL) {
+ newRechainCount = self->icRechainCount;
+ }
+
+ newCell.branch = assembleChainingBranch(tgtAddr, true);
+ newCell.delay_slot = getSkeleton(kMipsNop);
+ newCell.clazz = clazz;
+ newCell.method = method;
+ newCell.stagedClazz = NULL;
+
+ /*
+ * Enter the work order to the queue and the chaining cell will be patched
+ * the next time a safe point is entered.
+ *
+ * If the enqueuing fails reset the rechain count to a normal value so that
+ * it won't get indefinitely delayed.
+ */
+ inlineCachePatchEnqueue(cell, &newCell);
+#endif
+done:
+ self->icRechainCount = newRechainCount;
+ return method;
+}
+
+/*
+ * Patch the inline cache content based on the content passed from the work
+ * order.
+ */
+void dvmCompilerPatchInlineCache(void)
+{
+ int i;
+ PredictedChainingCell *minAddr, *maxAddr;
+
+ /* Nothing to be done */
+ if (gDvmJit.compilerICPatchIndex == 0) return;
+
+ /*
+ * Since all threads are already stopped we don't really need to acquire
+ * the lock. But race condition can be easily introduced in the future w/o
+ * paying attention so we still acquire the lock here.
+ */
+ dvmLockMutex(&gDvmJit.compilerICPatchLock);
+
+ UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+ //ALOGD("Number of IC patch work orders: %d", gDvmJit.compilerICPatchIndex);
+
+ /* Initialize the min/max address range */
+ minAddr = (PredictedChainingCell *)
+ ((char *) gDvmJit.codeCache + gDvmJit.codeCacheSize);
+ maxAddr = (PredictedChainingCell *) gDvmJit.codeCache;
+
+ for (i = 0; i < gDvmJit.compilerICPatchIndex; i++) {
+ ICPatchWorkOrder *workOrder = &gDvmJit.compilerICPatchQueue[i];
+ PredictedChainingCell *cellAddr = workOrder->cellAddr;
+ PredictedChainingCell *cellContent = &workOrder->cellContent;
+ ClassObject *clazz = dvmFindClassNoInit(workOrder->classDescriptor,
+ workOrder->classLoader);
+
+ assert(clazz->serialNumber == workOrder->serialNumber);
+
+ /* Use the newly resolved clazz pointer */
+ cellContent->clazz = clazz;
+
+ COMPILER_TRACE_CHAINING(
+ ALOGD("Jit Runtime: predicted chain %p from %s to %s (%s) "
+ "patched",
+ cellAddr,
+ cellAddr->clazz->descriptor,
+ cellContent->clazz->descriptor,
+ cellContent->method->name));
+
+ /* Patch the chaining cell */
+ *cellAddr = *cellContent;
+ minAddr = (cellAddr < minAddr) ? cellAddr : minAddr;
+ maxAddr = (cellAddr > maxAddr) ? cellAddr : maxAddr;
+ }
+
+ /* Then synchronize the I/D cache */
+ dvmCompilerCacheFlush((long) minAddr, (long) (maxAddr+1), 0);
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+ gDvmJit.compilerICPatchIndex = 0;
+ dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
+}
+
+/*
+ * Unchain a trace given the starting address of the translation
+ * in the code cache. Refer to the diagram in dvmCompilerAssembleLIR.
+ * Returns the address following the last cell unchained. Note that
+ * the incoming codeAddr is a thumb code address, and therefore has
+ * the low bit set.
+ */
+static u4* unchainSingle(JitEntry *trace)
+{
+ const char *base = getTraceBase(trace);
+ ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
+ int cellSize = getChainCellSize(pChainCellCounts);
+ u4* pChainCells;
+ int i,j;
+ PredictedChainingCell *predChainCell;
+
+ if (cellSize == 0)
+ return (u4 *) pChainCellCounts;
+
+ /* Locate the beginning of the chain cell region */
+ pChainCells = ((u4 *) pChainCellCounts) - cellSize -
+ pChainCellCounts->u.count[kChainingCellGap];
+
+ /* The cells are sorted in order - walk through them and reset */
+ for (i = 0; i < kChainingCellGap; i++) {
+ int elemSize = CHAIN_CELL_NORMAL_SIZE >> 2; /* In 32-bit words */
+ if (i == kChainingCellInvokePredicted) {
+ elemSize = CHAIN_CELL_PREDICTED_SIZE >> 2;
+ }
+
+ for (j = 0; j < pChainCellCounts->u.count[i]; j++) {
+ int targetOffset;
+ switch(i) {
+ case kChainingCellNormal:
+ targetOffset = offsetof(Thread,
+ jitToInterpEntries.dvmJitToInterpNormal);
+ break;
+ case kChainingCellHot:
+ case kChainingCellInvokeSingleton:
+ targetOffset = offsetof(Thread,
+ jitToInterpEntries.dvmJitToInterpTraceSelect);
+ break;
+ case kChainingCellInvokePredicted:
+ targetOffset = 0;
+ predChainCell = (PredictedChainingCell *) pChainCells;
+ /*
+ * There could be a race on another mutator thread to use
+ * this particular predicted cell and the check has passed
+ * the clazz comparison. So we cannot safely wipe the
+ * method and branch but it is safe to clear the clazz,
+ * which serves as the key.
+ */
+ predChainCell->clazz = PREDICTED_CHAIN_CLAZZ_INIT;
+ break;
+#if defined(WITH_SELF_VERIFICATION)
+ case kChainingCellBackwardBranch:
+ targetOffset = offsetof(Thread,
+ jitToInterpEntries.dvmJitToInterpBackwardBranch);
+ break;
+#else
+ case kChainingCellBackwardBranch:
+ targetOffset = offsetof(Thread,
+ jitToInterpEntries.dvmJitToInterpNormal);
+ break;
+#endif
+ default:
+ targetOffset = 0; // make gcc happy
+ ALOGE("Unexpected chaining type: %d", i);
+ dvmAbort(); // dvmAbort OK here - can't safely recover
+ }
+ COMPILER_TRACE_CHAINING(
+ ALOGD("Jit Runtime: unchaining %#x", (int)pChainCells));
+ /*
+ * Code sequence for a chaining cell is:
+ * lw a0, offset(rSELF)
+ * jalr ra, a0
+ */
+ if (i != kChainingCellInvokePredicted) {
+ *pChainCells = getSkeleton(kMipsLw) | (r_A0 << 16) |
+ targetOffset | (rSELF << 21);
+ *(pChainCells+1) = getSkeleton(kMipsJalr) | (r_RA << 11) |
+ (r_A0 << 21);
+ }
+ pChainCells += elemSize; /* Advance by a fixed number of words */
+ }
+ }
+ return pChainCells;
+}
+
+/* Unchain all translation in the cache. */
+void dvmJitUnchainAll()
+{
+ u4* lowAddress = NULL;
+ u4* highAddress = NULL;
+ unsigned int i;
+ if (gDvmJit.pJitEntryTable != NULL) {
+ COMPILER_TRACE_CHAINING(ALOGD("Jit Runtime: unchaining all"));
+ dvmLockMutex(&gDvmJit.tableLock);
+
+ UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+ for (i = 0; i < gDvmJit.jitTableSize; i++) {
+ if (gDvmJit.pJitEntryTable[i].dPC &&
+ !gDvmJit.pJitEntryTable[i].u.info.isMethodEntry &&
+ gDvmJit.pJitEntryTable[i].codeAddress &&
+ (gDvmJit.pJitEntryTable[i].codeAddress !=
+ dvmCompilerGetInterpretTemplate())) {
+ u4* lastAddress;
+ lastAddress = unchainSingle(&gDvmJit.pJitEntryTable[i]);
+ if (lowAddress == NULL ||
+ (u4*)gDvmJit.pJitEntryTable[i].codeAddress < lowAddress)
+ lowAddress = (u4*)gDvmJit.pJitEntryTable[i].codeAddress;
+ if (lastAddress > highAddress)
+ highAddress = lastAddress;
+ }
+ }
+
+ if (lowAddress && highAddress)
+ dvmCompilerCacheFlush((long)lowAddress, (long)highAddress, 0);
+
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+ dvmUnlockMutex(&gDvmJit.tableLock);
+ gDvmJit.translationChains = 0;
+ }
+ gDvmJit.hasNewChain = false;
+}
+
+typedef struct jitProfileAddrToLine {
+ u4 lineNum;
+ u4 bytecodeOffset;
+} jitProfileAddrToLine;
+
+
+/* Callback function to track the bytecode offset/line number relationiship */
+static int addrToLineCb (void *cnxt, u4 bytecodeOffset, u4 lineNum)
+{
+ jitProfileAddrToLine *addrToLine = (jitProfileAddrToLine *) cnxt;
+
+ /* Best match so far for this offset */
+ if (addrToLine->bytecodeOffset >= bytecodeOffset) {
+ addrToLine->lineNum = lineNum;
+ }
+ return 0;
+}
+
+/* Dumps profile info for a single trace */
+static int dumpTraceProfile(JitEntry *p, bool silent, bool reset,
+ unsigned long sum)
+{
+ int idx;
+
+ if (p->codeAddress == NULL) {
+ if (!silent)
+ ALOGD("TRACEPROFILE NULL");
+ return 0;
+ }
+ if (p->codeAddress == dvmCompilerGetInterpretTemplate()) {
+ if (!silent)
+ ALOGD("TRACEPROFILE INTERPRET_ONLY");
+ return 0;
+ }
+
+ JitTraceCounter_t count = getProfileCount(p);
+ if (reset) {
+ resetProfileCount(p);
+ }
+ if (silent) {
+ return count;
+ }
+ JitTraceDescription *desc = getTraceDescriptionPointer(getTraceBase(p));
+ const Method *method = desc->method;
+ char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype);
+ jitProfileAddrToLine addrToLine = {0, desc->trace[0].info.frag.startOffset};
+
+ /*
+ * We may end up decoding the debug information for the same method
+ * multiple times, but the tradeoff is we don't need to allocate extra
+ * space to store the addr/line mapping. Since this is a debugging feature
+ * and done infrequently so the slower but simpler mechanism should work
+ * just fine.
+ */
+ dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile,
+ dvmGetMethodCode(method),
+ method->clazz->descriptor,
+ method->prototype.protoIdx,
+ method->accessFlags,
+ addrToLineCb, NULL, &addrToLine);
+
+ ALOGD("TRACEPROFILE 0x%08x % 10d %5.2f%% [%#x(+%d), %d] %s%s;%s",
+ (int) getTraceBase(p),
+ count,
+ ((float ) count) / sum * 100.0,
+ desc->trace[0].info.frag.startOffset,
+ desc->trace[0].info.frag.numInsts,
+ addrToLine.lineNum,
+ method->clazz->descriptor, method->name, methodDesc);
+ free(methodDesc);
+
+ /* Find the last fragment (ie runEnd is set) */
+ for (idx = 0;
+ desc->trace[idx].isCode && !desc->trace[idx].info.frag.runEnd;
+ idx++) {
+ }
+
+ /*
+ * runEnd must comes with a JitCodeDesc frag. If isCode is false it must
+ * be a meta info field (only used by callsite info for now).
+ */
+ if (!desc->trace[idx].isCode) {
+ const Method *method = (const Method *)
+ desc->trace[idx+JIT_TRACE_CUR_METHOD-1].info.meta;
+ char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype);
+ /* Print the callee info in the trace */
+ ALOGD(" -> %s%s;%s", method->clazz->descriptor, method->name,
+ methodDesc);
+ }
+
+ return count;
+}
+
+/* Create a copy of the trace descriptor of an existing compilation */
+JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
+ const JitEntry *knownEntry)
+{
+ const JitEntry *jitEntry = knownEntry ? knownEntry
+ : dvmJitFindEntry(pc, false);
+ if ((jitEntry == NULL) || (jitEntry->codeAddress == 0))
+ return NULL;
+
+ JitTraceDescription *desc =
+ getTraceDescriptionPointer(getTraceBase(jitEntry));
+
+ /* Now make a copy and return */
+ int descSize = getTraceDescriptionSize(desc);
+ JitTraceDescription *newCopy = (JitTraceDescription *) malloc(descSize);
+ memcpy(newCopy, desc, descSize);
+ return newCopy;
+}
+
+/* qsort callback function */
+static int sortTraceProfileCount(const void *entry1, const void *entry2)
+{
+ const JitEntry *jitEntry1 = (const JitEntry *)entry1;
+ const JitEntry *jitEntry2 = (const JitEntry *)entry2;
+
+ JitTraceCounter_t count1 = getProfileCount(jitEntry1);
+ JitTraceCounter_t count2 = getProfileCount(jitEntry2);
+ return (count1 == count2) ? 0 : ((count1 > count2) ? -1 : 1);
+}
+
+/* Sort the trace profile counts and dump them */
+void dvmCompilerSortAndPrintTraceProfiles()
+{
+ JitEntry *sortedEntries;
+ int numTraces = 0;
+ unsigned long sum = 0;
+ unsigned int i;
+
+ /* Make sure that the table is not changing */
+ dvmLockMutex(&gDvmJit.tableLock);
+
+ /* Sort the entries by descending order */
+ sortedEntries = (JitEntry *)malloc(sizeof(JitEntry) * gDvmJit.jitTableSize);
+ if (sortedEntries == NULL)
+ goto done;
+ memcpy(sortedEntries, gDvmJit.pJitEntryTable,
+ sizeof(JitEntry) * gDvmJit.jitTableSize);
+ qsort(sortedEntries, gDvmJit.jitTableSize, sizeof(JitEntry),
+ sortTraceProfileCount);
+
+ /* Analyze the sorted entries */
+ for (i=0; i < gDvmJit.jitTableSize; i++) {
+ if (sortedEntries[i].dPC != 0) {
+ sum += dumpTraceProfile(&sortedEntries[i],
+ true /* silent */,
+ false /* reset */,
+ 0);
+ numTraces++;
+ }
+ }
+ if (numTraces == 0)
+ numTraces = 1;
+ if (sum == 0) {
+ sum = 1;
+ }
+
+ ALOGD("JIT: Average execution count -> %d",(int)(sum / numTraces));
+
+ /* Dump the sorted entries. The count of each trace will be reset to 0. */
+ for (i=0; i < gDvmJit.jitTableSize; i++) {
+ if (sortedEntries[i].dPC != 0) {
+ dumpTraceProfile(&sortedEntries[i],
+ false /* silent */,
+ true /* reset */,
+ sum);
+ }
+ }
+
+ for (i=0; i < gDvmJit.jitTableSize && i < 10; i++) {
+ /* Stip interpreter stubs */
+ if (sortedEntries[i].codeAddress == dvmCompilerGetInterpretTemplate()) {
+ continue;
+ }
+ JitTraceDescription* desc =
+ dvmCopyTraceDescriptor(NULL, &sortedEntries[i]);
+ if (desc) {
+ dvmCompilerWorkEnqueue(sortedEntries[i].dPC,
+ kWorkOrderTraceDebug, desc);
+ }
+ }
+
+ free(sortedEntries);
+done:
+ dvmUnlockMutex(&gDvmJit.tableLock);
+ return;
+}
+
+static void findClassPointersSingleTrace(char *base, void (*callback)(void *))
+{
+ unsigned int chainTypeIdx, chainIdx;
+ ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
+ int cellSize = getChainCellSize(pChainCellCounts);
+ /* Scan the chaining cells */
+ if (cellSize) {
+ /* Locate the beginning of the chain cell region */
+ u4 *pChainCells = ((u4 *) pChainCellCounts) - cellSize -
+ pChainCellCounts->u.count[kChainingCellGap];
+ /* The cells are sorted in order - walk through them */
+ for (chainTypeIdx = 0; chainTypeIdx < kChainingCellGap;
+ chainTypeIdx++) {
+ if (chainTypeIdx != kChainingCellInvokePredicted) {
+ /* In 32-bit words */
+ pChainCells += (CHAIN_CELL_NORMAL_SIZE >> 2) *
+ pChainCellCounts->u.count[chainTypeIdx];
+ continue;
+ }
+ for (chainIdx = 0;
+ chainIdx < pChainCellCounts->u.count[chainTypeIdx];
+ chainIdx++) {
+ PredictedChainingCell *cell =
+ (PredictedChainingCell *) pChainCells;
+ /*
+ * Report the cell if it contains a sane class
+ * pointer.
+ */
+ if (cell->clazz != NULL &&
+ cell->clazz !=
+ (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ) {
+ callback(&cell->clazz);
+ }
+ pChainCells += CHAIN_CELL_PREDICTED_SIZE >> 2;
+ }
+ }
+ }
+
+ /* Scan the class pointer pool */
+ JitTraceDescription *desc = getTraceDescriptionPointer(base);
+ int descSize = getTraceDescriptionSize(desc);
+ int *classPointerP = (int *) ((char *) desc + descSize);
+ int numClassPointers = *classPointerP++;
+ for (; numClassPointers; numClassPointers--, classPointerP++) {
+ callback(classPointerP);
+ }
+}
+
+/*
+ * Scan class pointers in each translation and pass its address to the callback
+ * function. Currently such a pointers can be found in the pointer pool and the
+ * clazz field in the predicted chaining cells.
+ */
+void dvmJitScanAllClassPointers(void (*callback)(void *))
+{
+ UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+ /* Handle the inflight compilation first */
+ if (gDvmJit.inflightBaseAddr)
+ findClassPointersSingleTrace((char *) gDvmJit.inflightBaseAddr,
+ callback);
+
+ if (gDvmJit.pJitEntryTable != NULL) {
+ unsigned int traceIdx;
+ dvmLockMutex(&gDvmJit.tableLock);
+ for (traceIdx = 0; traceIdx < gDvmJit.jitTableSize; traceIdx++) {
+ const JitEntry *entry = &gDvmJit.pJitEntryTable[traceIdx];
+ if (entry->dPC &&
+ !entry->u.info.isMethodEntry &&
+ entry->codeAddress &&
+ (entry->codeAddress != dvmCompilerGetInterpretTemplate())) {
+ char *base = getTraceBase(entry);
+ findClassPointersSingleTrace(base, callback);
+ }
+ }
+ dvmUnlockMutex(&gDvmJit.tableLock);
+ }
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+}
+
+/*
+ * Provide the final touch on the class object pointer pool to install the
+ * actual pointers. The thread has to be in the running state.
+ */
+void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit, char *codeAddress)
+{
+ char *base = codeAddress - cUnit->headerSize;
+
+ /* Scan the class pointer pool */
+ JitTraceDescription *desc = getTraceDescriptionPointer(base);
+ int descSize = getTraceDescriptionSize(desc);
+ intptr_t *classPointerP = (int *) ((char *) desc + descSize);
+ int numClassPointers = *(int *)classPointerP++;
+ intptr_t *startClassPointerP = classPointerP;
+
+ /*
+ * Change the thread state to VM_RUNNING so that GC won't be happening
+ * when the assembler looks up the class pointers. May suspend the current
+ * thread if there is a pending request before the state is actually
+ * changed to RUNNING.
+ */
+ dvmChangeStatus(gDvmJit.compilerThread, THREAD_RUNNING);
+
+ /*
+ * Unprotecting the code cache will need to acquire the code cache
+ * protection lock first. Doing so after the state change may increase the
+ * time spent in the RUNNING state (which may delay the next GC request
+ * should there be contention on codeCacheProtectionLock). In practice
+ * this is probably not going to happen often since a GC is just served.
+ * More importantly, acquiring the lock before the state change will
+ * cause deadlock (b/4192964).
+ */
+ UNPROTECT_CODE_CACHE(startClassPointerP,
+ numClassPointers * sizeof(intptr_t));
+#if defined(WITH_JIT_TUNING)
+ u8 startTime = dvmGetRelativeTimeUsec();
+#endif
+ for (;numClassPointers; numClassPointers--) {
+ CallsiteInfo *callsiteInfo = (CallsiteInfo *) *classPointerP;
+ ClassObject *clazz = dvmFindClassNoInit(
+ callsiteInfo->classDescriptor, callsiteInfo->classLoader);
+ assert(!strcmp(clazz->descriptor, callsiteInfo->classDescriptor));
+ *classPointerP++ = (intptr_t) clazz;
+ }
+
+ /*
+ * Register the base address so that if GC kicks in after the thread state
+ * has been changed to VMWAIT and before the compiled code is registered
+ * in the JIT table, its content can be patched if class objects are
+ * moved.
+ */
+ gDvmJit.inflightBaseAddr = base;
+
+#if defined(WITH_JIT_TUNING)
+ u8 blockTime = dvmGetRelativeTimeUsec() - startTime;
+ gDvmJit.compilerThreadBlockGCTime += blockTime;
+ if (blockTime > gDvmJit.maxCompilerThreadBlockGCTime)
+ gDvmJit.maxCompilerThreadBlockGCTime = blockTime;
+ gDvmJit.numCompilerThreadBlockGC++;
+#endif
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(startClassPointerP, numClassPointers * sizeof(intptr_t));
+
+ /* Change the thread state back to VMWAIT */
+ dvmChangeStatus(gDvmJit.compilerThread, THREAD_VMWAIT);
+}
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * The following are used to keep compiled loads and stores from modifying
+ * memory during self verification mode.
+ *
+ * Stores do not modify memory. Instead, the address and value pair are stored
+ * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
+ * than a word, the word containing the address is loaded first before being
+ * updated.
+ *
+ * Loads check heapSpace first and return data from there if an entry exists.
+ * Otherwise, data is loaded from memory as usual.
+ */
+
+/* Used to specify sizes of memory operations */
+enum {
+ kSVByte,
+ kSVSignedByte,
+ kSVHalfword,
+ kSVSignedHalfword,
+ kSVWord,
+ kSVDoubleword,
+ kSVVariable,
+};
+
+/* Load the value of a decoded register from the stack */
+static int selfVerificationMemRegLoad(int* sp, int reg)
+{
+assert(0); /* MIPSTODO retarg func */
+ return *(sp + reg);
+}
+
+/* Load the value of a decoded doubleword register from the stack */
+static s8 selfVerificationMemRegLoadDouble(int* sp, int reg)
+{
+assert(0); /* MIPSTODO retarg func */
+ return *((s8*)(sp + reg));
+}
+
+/* Store the value of a decoded register out to the stack */
+static void selfVerificationMemRegStore(int* sp, int data, int reg)
+{
+assert(0); /* MIPSTODO retarg func */
+ *(sp + reg) = data;
+}
+
+/* Store the value of a decoded doubleword register out to the stack */
+static void selfVerificationMemRegStoreDouble(int* sp, s8 data, int reg)
+{
+assert(0); /* MIPSTODO retarg func */
+ *((s8*)(sp + reg)) = data;
+}
+
+/*
+ * Load the specified size of data from the specified address, checking
+ * heapSpace first if Self Verification mode wrote to it previously, and
+ * falling back to actual memory otherwise.
+ */
+static int selfVerificationLoad(int addr, int size)
+{
+assert(0); /* MIPSTODO retarg func */
+ Thread *self = dvmThreadSelf();
+ ShadowSpace *shadowSpace = self->shadowSpace;
+ ShadowHeap *heapSpacePtr;
+
+ int data;
+ int maskedAddr = addr & 0xFFFFFFFC;
+ int alignment = addr & 0x3;
+
+ for (heapSpacePtr = shadowSpace->heapSpace;
+ heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+ if (heapSpacePtr->addr == maskedAddr) {
+ addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
+ break;
+ }
+ }
+
+ switch (size) {
+ case kSVByte:
+ data = *((u1*) addr);
+ break;
+ case kSVSignedByte:
+ data = *((s1*) addr);
+ break;
+ case kSVHalfword:
+ data = *((u2*) addr);
+ break;
+ case kSVSignedHalfword:
+ data = *((s2*) addr);
+ break;
+ case kSVWord:
+ data = *((u4*) addr);
+ break;
+ default:
+ ALOGE("*** ERROR: BAD SIZE IN selfVerificationLoad: %d", size);
+ data = 0;
+ dvmAbort();
+ }
+
+ //ALOGD("*** HEAP LOAD: Addr: %#x Data: %#x Size: %d", addr, data, size);
+ return data;
+}
+
+/* Like selfVerificationLoad, but specifically for doublewords */
+static s8 selfVerificationLoadDoubleword(int addr)
+{
+assert(0); /* MIPSTODO retarg func */
+ Thread *self = dvmThreadSelf();
+ ShadowSpace* shadowSpace = self->shadowSpace;
+ ShadowHeap* heapSpacePtr;
+
+ int addr2 = addr+4;
+ unsigned int data = *((unsigned int*) addr);
+ unsigned int data2 = *((unsigned int*) addr2);
+
+ for (heapSpacePtr = shadowSpace->heapSpace;
+ heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+ if (heapSpacePtr->addr == addr) {
+ data = heapSpacePtr->data;
+ } else if (heapSpacePtr->addr == addr2) {
+ data2 = heapSpacePtr->data;
+ }
+ }
+
+ //ALOGD("*** HEAP LOAD DOUBLEWORD: Addr: %#x Data: %#x Data2: %#x",
+ // addr, data, data2);
+ return (((s8) data2) << 32) | data;
+}
+
+/*
+ * Handles a store of a specified size of data to a specified address.
+ * This gets logged as an addr/data pair in heapSpace instead of modifying
+ * memory. Addresses in heapSpace are unique, and accesses smaller than a
+ * word pull the entire word from memory first before updating.
+ */
+static void selfVerificationStore(int addr, int data, int size)
+{
+assert(0); /* MIPSTODO retarg func */
+ Thread *self = dvmThreadSelf();
+ ShadowSpace *shadowSpace = self->shadowSpace;
+ ShadowHeap *heapSpacePtr;
+
+ int maskedAddr = addr & 0xFFFFFFFC;
+ int alignment = addr & 0x3;
+
+ //ALOGD("*** HEAP STORE: Addr: %#x Data: %#x Size: %d", addr, data, size);
+
+ for (heapSpacePtr = shadowSpace->heapSpace;
+ heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+ if (heapSpacePtr->addr == maskedAddr) break;
+ }
+
+ if (heapSpacePtr == shadowSpace->heapSpaceTail) {
+ heapSpacePtr->addr = maskedAddr;
+ heapSpacePtr->data = *((unsigned int*) maskedAddr);
+ shadowSpace->heapSpaceTail++;
+ }
+
+ addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
+ switch (size) {
+ case kSVByte:
+ *((u1*) addr) = data;
+ break;
+ case kSVSignedByte:
+ *((s1*) addr) = data;
+ break;
+ case kSVHalfword:
+ *((u2*) addr) = data;
+ break;
+ case kSVSignedHalfword:
+ *((s2*) addr) = data;
+ break;
+ case kSVWord:
+ *((u4*) addr) = data;
+ break;
+ default:
+ ALOGE("*** ERROR: BAD SIZE IN selfVerificationSave: %d", size);
+ dvmAbort();
+ }
+}
+
+/* Like selfVerificationStore, but specifically for doublewords */
+static void selfVerificationStoreDoubleword(int addr, s8 double_data)
+{
+assert(0); /* MIPSTODO retarg func */
+ Thread *self = dvmThreadSelf();
+ ShadowSpace *shadowSpace = self->shadowSpace;
+ ShadowHeap *heapSpacePtr;
+
+ int addr2 = addr+4;
+ int data = double_data;
+ int data2 = double_data >> 32;
+ bool store1 = false, store2 = false;
+
+ //ALOGD("*** HEAP STORE DOUBLEWORD: Addr: %#x Data: %#x, Data2: %#x",
+ // addr, data, data2);
+
+ for (heapSpacePtr = shadowSpace->heapSpace;
+ heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+ if (heapSpacePtr->addr == addr) {
+ heapSpacePtr->data = data;
+ store1 = true;
+ } else if (heapSpacePtr->addr == addr2) {
+ heapSpacePtr->data = data2;
+ store2 = true;
+ }
+ }
+
+ if (!store1) {
+ shadowSpace->heapSpaceTail->addr = addr;
+ shadowSpace->heapSpaceTail->data = data;
+ shadowSpace->heapSpaceTail++;
+ }
+ if (!store2) {
+ shadowSpace->heapSpaceTail->addr = addr2;
+ shadowSpace->heapSpaceTail->data = data2;
+ shadowSpace->heapSpaceTail++;
+ }
+}
+
+/*
+ * Decodes the memory instruction at the address specified in the link
+ * register. All registers (r0-r12,lr) and fp registers (d0-d15) are stored
+ * consecutively on the stack beginning at the specified stack pointer.
+ * Calls the proper Self Verification handler for the memory instruction and
+ * updates the link register to point past the decoded memory instruction.
+ */
+void dvmSelfVerificationMemOpDecode(int lr, int* sp)
+{
+assert(0); /* MIPSTODO retarg func */
+ enum {
+ kMemOpLdrPcRel = 0x09, // ldr(3) [01001] rd[10..8] imm_8[7..0]
+ kMemOpRRR = 0x0A, // Full opcode is 7 bits
+ kMemOp2Single = 0x0A, // Used for Vstrs and Vldrs
+ kMemOpRRR2 = 0x0B, // Full opcode is 7 bits
+ kMemOp2Double = 0x0B, // Used for Vstrd and Vldrd
+ kMemOpStrRRI5 = 0x0C, // str(1) [01100] imm_5[10..6] rn[5..3] rd[2..0]
+ kMemOpLdrRRI5 = 0x0D, // ldr(1) [01101] imm_5[10..6] rn[5..3] rd[2..0]
+ kMemOpStrbRRI5 = 0x0E, // strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0]
+ kMemOpLdrbRRI5 = 0x0F, // ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0]
+ kMemOpStrhRRI5 = 0x10, // strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0]
+ kMemOpLdrhRRI5 = 0x11, // ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0]
+ kMemOpLdrSpRel = 0x13, // ldr(4) [10011] rd[10..8] imm_8[7..0]
+ kMemOpStmia = 0x18, // stmia [11000] rn[10..8] reglist [7..0]
+ kMemOpLdmia = 0x19, // ldmia [11001] rn[10..8] reglist [7..0]
+ kMemOpStrRRR = 0x28, // str(2) [0101000] rm[8..6] rn[5..3] rd[2..0]
+ kMemOpStrhRRR = 0x29, // strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0]
+ kMemOpStrbRRR = 0x2A, // strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0]
+ kMemOpLdrsbRRR = 0x2B, // ldrsb [0101011] rm[8..6] rn[5..3] rd[2..0]
+ kMemOpLdrRRR = 0x2C, // ldr(2) [0101100] rm[8..6] rn[5..3] rd[2..0]
+ kMemOpLdrhRRR = 0x2D, // ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0]
+ kMemOpLdrbRRR = 0x2E, // ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0]
+ kMemOpLdrshRRR = 0x2F, // ldrsh [0101111] rm[8..6] rn[5..3] rd[2..0]
+ kMemOp2Stmia = 0xE88, // stmia [111010001000[ rn[19..16] mask[15..0]
+ kMemOp2Ldmia = 0xE89, // ldmia [111010001001[ rn[19..16] mask[15..0]
+ kMemOp2Stmia2 = 0xE8A, // stmia [111010001010[ rn[19..16] mask[15..0]
+ kMemOp2Ldmia2 = 0xE8B, // ldmia [111010001011[ rn[19..16] mask[15..0]
+ kMemOp2Vstr = 0xED8, // Used for Vstrs and Vstrd
+ kMemOp2Vldr = 0xED9, // Used for Vldrs and Vldrd
+ kMemOp2Vstr2 = 0xEDC, // Used for Vstrs and Vstrd
+ kMemOp2Vldr2 = 0xEDD, // Used for Vstrs and Vstrd
+ kMemOp2StrbRRR = 0xF80, /* str rt,[rn,rm,LSL #imm] [111110000000]
+ rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+ kMemOp2LdrbRRR = 0xF81, /* ldrb rt,[rn,rm,LSL #imm] [111110000001]
+ rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+ kMemOp2StrhRRR = 0xF82, /* str rt,[rn,rm,LSL #imm] [111110000010]
+ rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+ kMemOp2LdrhRRR = 0xF83, /* ldrh rt,[rn,rm,LSL #imm] [111110000011]
+ rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+ kMemOp2StrRRR = 0xF84, /* str rt,[rn,rm,LSL #imm] [111110000100]
+ rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+ kMemOp2LdrRRR = 0xF85, /* ldr rt,[rn,rm,LSL #imm] [111110000101]
+ rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+ kMemOp2StrbRRI12 = 0xF88, /* strb rt,[rn,#imm12] [111110001000]
+ rt[15..12] rn[19..16] imm12[11..0] */
+ kMemOp2LdrbRRI12 = 0xF89, /* ldrb rt,[rn,#imm12] [111110001001]
+ rt[15..12] rn[19..16] imm12[11..0] */
+ kMemOp2StrhRRI12 = 0xF8A, /* strh rt,[rn,#imm12] [111110001010]
+ rt[15..12] rn[19..16] imm12[11..0] */
+ kMemOp2LdrhRRI12 = 0xF8B, /* ldrh rt,[rn,#imm12] [111110001011]
+ rt[15..12] rn[19..16] imm12[11..0] */
+ kMemOp2StrRRI12 = 0xF8C, /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
+ rn[19..16] rt[15..12] imm12[11..0] */
+ kMemOp2LdrRRI12 = 0xF8D, /* ldr(Imm,T3) rd,[rn,#imm12] [111110001101]
+ rn[19..16] rt[15..12] imm12[11..0] */
+ kMemOp2LdrsbRRR = 0xF91, /* ldrsb rt,[rn,rm,LSL #imm] [111110010001]
+ rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+ kMemOp2LdrshRRR = 0xF93, /* ldrsh rt,[rn,rm,LSL #imm] [111110010011]
+ rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+ kMemOp2LdrsbRRI12 = 0xF99, /* ldrsb rt,[rn,#imm12] [111110011001]
+ rt[15..12] rn[19..16] imm12[11..0] */
+ kMemOp2LdrshRRI12 = 0xF9B, /* ldrsh rt,[rn,#imm12] [111110011011]
+ rt[15..12] rn[19..16] imm12[11..0] */
+ kMemOp2 = 0xE000, // top 3 bits set indicates Thumb2
+ };
+
+ int addr, offset, data;
+ long long double_data;
+ int size = kSVWord;
+ bool store = false;
+ unsigned int *lr_masked = (unsigned int *) (lr & 0xFFFFFFFE);
+ unsigned int insn = *lr_masked;
+
+ int old_lr;
+ old_lr = selfVerificationMemRegLoad(sp, 13);
+
+ if ((insn & kMemOp2) == kMemOp2) {
+ insn = (insn << 16) | (insn >> 16);
+ //ALOGD("*** THUMB2 - Addr: %#x Insn: %#x", lr, insn);
+
+ int opcode12 = (insn >> 20) & 0xFFF;
+ int opcode6 = (insn >> 6) & 0x3F;
+ int opcode4 = (insn >> 8) & 0xF;
+ int imm2 = (insn >> 4) & 0x3;
+ int imm8 = insn & 0xFF;
+ int imm12 = insn & 0xFFF;
+ int rd = (insn >> 12) & 0xF;
+ int rm = insn & 0xF;
+ int rn = (insn >> 16) & 0xF;
+ int rt = (insn >> 12) & 0xF;
+ bool wBack = true;
+
+ // Update the link register
+ selfVerificationMemRegStore(sp, old_lr+4, 13);
+
+ // Determine whether the mem op is a store or load
+ switch (opcode12) {
+ case kMemOp2Stmia:
+ case kMemOp2Stmia2:
+ case kMemOp2Vstr:
+ case kMemOp2Vstr2:
+ case kMemOp2StrbRRR:
+ case kMemOp2StrhRRR:
+ case kMemOp2StrRRR:
+ case kMemOp2StrbRRI12:
+ case kMemOp2StrhRRI12:
+ case kMemOp2StrRRI12:
+ store = true;
+ }
+
+ // Determine the size of the mem access
+ switch (opcode12) {
+ case kMemOp2StrbRRR:
+ case kMemOp2LdrbRRR:
+ case kMemOp2StrbRRI12:
+ case kMemOp2LdrbRRI12:
+ size = kSVByte;
+ break;
+ case kMemOp2LdrsbRRR:
+ case kMemOp2LdrsbRRI12:
+ size = kSVSignedByte;
+ break;
+ case kMemOp2StrhRRR:
+ case kMemOp2LdrhRRR:
+ case kMemOp2StrhRRI12:
+ case kMemOp2LdrhRRI12:
+ size = kSVHalfword;
+ break;
+ case kMemOp2LdrshRRR:
+ case kMemOp2LdrshRRI12:
+ size = kSVSignedHalfword;
+ break;
+ case kMemOp2Vstr:
+ case kMemOp2Vstr2:
+ case kMemOp2Vldr:
+ case kMemOp2Vldr2:
+ if (opcode4 == kMemOp2Double) size = kSVDoubleword;
+ break;
+ case kMemOp2Stmia:
+ case kMemOp2Ldmia:
+ case kMemOp2Stmia2:
+ case kMemOp2Ldmia2:
+ size = kSVVariable;
+ break;
+ }
+
+ // Load the value of the address
+ addr = selfVerificationMemRegLoad(sp, rn);
+
+ // Figure out the offset
+ switch (opcode12) {
+ case kMemOp2Vstr:
+ case kMemOp2Vstr2:
+ case kMemOp2Vldr:
+ case kMemOp2Vldr2:
+ offset = imm8 << 2;
+ if (opcode4 == kMemOp2Single) {
+ rt = rd << 1;
+ if (insn & 0x400000) rt |= 0x1;
+ } else if (opcode4 == kMemOp2Double) {
+ if (insn & 0x400000) rt |= 0x10;
+ rt = rt << 1;
+ } else {
+ ALOGE("*** ERROR: UNRECOGNIZED VECTOR MEM OP: %x", opcode4);
+ dvmAbort();
+ }
+ rt += 14;
+ break;
+ case kMemOp2StrbRRR:
+ case kMemOp2LdrbRRR:
+ case kMemOp2StrhRRR:
+ case kMemOp2LdrhRRR:
+ case kMemOp2StrRRR:
+ case kMemOp2LdrRRR:
+ case kMemOp2LdrsbRRR:
+ case kMemOp2LdrshRRR:
+ offset = selfVerificationMemRegLoad(sp, rm) << imm2;
+ break;
+ case kMemOp2StrbRRI12:
+ case kMemOp2LdrbRRI12:
+ case kMemOp2StrhRRI12:
+ case kMemOp2LdrhRRI12:
+ case kMemOp2StrRRI12:
+ case kMemOp2LdrRRI12:
+ case kMemOp2LdrsbRRI12:
+ case kMemOp2LdrshRRI12:
+ offset = imm12;
+ break;
+ case kMemOp2Stmia:
+ case kMemOp2Ldmia:
+ wBack = false;
+ case kMemOp2Stmia2:
+ case kMemOp2Ldmia2:
+ offset = 0;
+ break;
+ default:
+ ALOGE("*** ERROR: UNRECOGNIZED THUMB2 MEM OP: %x", opcode12);
+ offset = 0;
+ dvmAbort();
+ }
+
+ // Handle the decoded mem op accordingly
+ if (store) {
+ if (size == kSVVariable) {
+ ALOGD("*** THUMB2 STMIA CURRENTLY UNUSED (AND UNTESTED)");
+ int i;
+ int regList = insn & 0xFFFF;
+ for (i = 0; i < 16; i++) {
+ if (regList & 0x1) {
+ data = selfVerificationMemRegLoad(sp, i);
+ selfVerificationStore(addr, data, kSVWord);
+ addr += 4;
+ }
+ regList = regList >> 1;
+ }
+ if (wBack) selfVerificationMemRegStore(sp, addr, rn);
+ } else if (size == kSVDoubleword) {
+ double_data = selfVerificationMemRegLoadDouble(sp, rt);
+ selfVerificationStoreDoubleword(addr+offset, double_data);
+ } else {
+ data = selfVerificationMemRegLoad(sp, rt);
+ selfVerificationStore(addr+offset, data, size);
+ }
+ } else {
+ if (size == kSVVariable) {
+ ALOGD("*** THUMB2 LDMIA CURRENTLY UNUSED (AND UNTESTED)");
+ int i;
+ int regList = insn & 0xFFFF;
+ for (i = 0; i < 16; i++) {
+ if (regList & 0x1) {
+ data = selfVerificationLoad(addr, kSVWord);
+ selfVerificationMemRegStore(sp, data, i);
+ addr += 4;
+ }
+ regList = regList >> 1;
+ }
+ if (wBack) selfVerificationMemRegStore(sp, addr, rn);
+ } else if (size == kSVDoubleword) {
+ double_data = selfVerificationLoadDoubleword(addr+offset);
+ selfVerificationMemRegStoreDouble(sp, double_data, rt);
+ } else {
+ data = selfVerificationLoad(addr+offset, size);
+ selfVerificationMemRegStore(sp, data, rt);
+ }
+ }
+ } else {
+ //ALOGD("*** THUMB - Addr: %#x Insn: %#x", lr, insn);
+
+ // Update the link register
+ selfVerificationMemRegStore(sp, old_lr+2, 13);
+
+ int opcode5 = (insn >> 11) & 0x1F;
+ int opcode7 = (insn >> 9) & 0x7F;
+ int imm = (insn >> 6) & 0x1F;
+ int rd = (insn >> 8) & 0x7;
+ int rm = (insn >> 6) & 0x7;
+ int rn = (insn >> 3) & 0x7;
+ int rt = insn & 0x7;
+
+ // Determine whether the mem op is a store or load
+ switch (opcode5) {
+ case kMemOpRRR:
+ switch (opcode7) {
+ case kMemOpStrRRR:
+ case kMemOpStrhRRR:
+ case kMemOpStrbRRR:
+ store = true;
+ }
+ break;
+ case kMemOpStrRRI5:
+ case kMemOpStrbRRI5:
+ case kMemOpStrhRRI5:
+ case kMemOpStmia:
+ store = true;
+ }
+
+ // Determine the size of the mem access
+ switch (opcode5) {
+ case kMemOpRRR:
+ case kMemOpRRR2:
+ switch (opcode7) {
+ case kMemOpStrbRRR:
+ case kMemOpLdrbRRR:
+ size = kSVByte;
+ break;
+ case kMemOpLdrsbRRR:
+ size = kSVSignedByte;
+ break;
+ case kMemOpStrhRRR:
+ case kMemOpLdrhRRR:
+ size = kSVHalfword;
+ break;
+ case kMemOpLdrshRRR:
+ size = kSVSignedHalfword;
+ break;
+ }
+ break;
+ case kMemOpStrbRRI5:
+ case kMemOpLdrbRRI5:
+ size = kSVByte;
+ break;
+ case kMemOpStrhRRI5:
+ case kMemOpLdrhRRI5:
+ size = kSVHalfword;
+ break;
+ case kMemOpStmia:
+ case kMemOpLdmia:
+ size = kSVVariable;
+ break;
+ }
+
+ // Load the value of the address
+ if (opcode5 == kMemOpLdrPcRel)
+ addr = selfVerificationMemRegLoad(sp, 4);
+ else if (opcode5 == kMemOpStmia || opcode5 == kMemOpLdmia)
+ addr = selfVerificationMemRegLoad(sp, rd);
+ else
+ addr = selfVerificationMemRegLoad(sp, rn);
+
+ // Figure out the offset
+ switch (opcode5) {
+ case kMemOpLdrPcRel:
+ offset = (insn & 0xFF) << 2;
+ rt = rd;
+ break;
+ case kMemOpRRR:
+ case kMemOpRRR2:
+ offset = selfVerificationMemRegLoad(sp, rm);
+ break;
+ case kMemOpStrRRI5:
+ case kMemOpLdrRRI5:
+ offset = imm << 2;
+ break;
+ case kMemOpStrhRRI5:
+ case kMemOpLdrhRRI5:
+ offset = imm << 1;
+ break;
+ case kMemOpStrbRRI5:
+ case kMemOpLdrbRRI5:
+ offset = imm;
+ break;
+ case kMemOpStmia:
+ case kMemOpLdmia:
+ offset = 0;
+ break;
+ default:
+ ALOGE("*** ERROR: UNRECOGNIZED THUMB MEM OP: %x", opcode5);
+ offset = 0;
+ dvmAbort();
+ }
+
+ // Handle the decoded mem op accordingly
+ if (store) {
+ if (size == kSVVariable) {
+ int i;
+ int regList = insn & 0xFF;
+ for (i = 0; i < 8; i++) {
+ if (regList & 0x1) {
+ data = selfVerificationMemRegLoad(sp, i);
+ selfVerificationStore(addr, data, kSVWord);
+ addr += 4;
+ }
+ regList = regList >> 1;
+ }
+ selfVerificationMemRegStore(sp, addr, rd);
+ } else {
+ data = selfVerificationMemRegLoad(sp, rt);
+ selfVerificationStore(addr+offset, data, size);
+ }
+ } else {
+ if (size == kSVVariable) {
+ bool wBack = true;
+ int i;
+ int regList = insn & 0xFF;
+ for (i = 0; i < 8; i++) {
+ if (regList & 0x1) {
+ if (i == rd) wBack = false;
+ data = selfVerificationLoad(addr, kSVWord);
+ selfVerificationMemRegStore(sp, data, i);
+ addr += 4;
+ }
+ regList = regList >> 1;
+ }
+ if (wBack) selfVerificationMemRegStore(sp, addr, rd);
+ } else {
+ data = selfVerificationLoad(addr+offset, size);
+ selfVerificationMemRegStore(sp, data, rt);
+ }
+ }
+ }
+}
+#endif
diff --git a/vm/compiler/codegen/mips/CalloutHelper.h b/vm/compiler/codegen/mips/CalloutHelper.h
new file mode 100644
index 0000000..8534361
--- /dev/null
+++ b/vm/compiler/codegen/mips/CalloutHelper.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DALVIK_VM_COMPILER_CODEGEN_MIPS_CALLOUT_HELPER_H_
+#define DALVIK_VM_COMPILER_CODEGEN_MIPS_CALLOUT_HELPER_H_
+
+#include "Dalvik.h"
+
+/*
+ * Declare/comment prototypes of all native callout functions invoked by the
+ * JIT'ed code here and use the LOAD_FUNC_ADDR macro to load the address into
+ * a register. In this way we have a centralized place to find out all native
+ * helper functions and we can grep for LOAD_FUNC_ADDR to find out all the
+ * callsites.
+ */
+
+/* Load a statically compiled function address as a constant */
+#define LOAD_FUNC_ADDR(cUnit, reg, addr) loadConstant(cUnit, reg, addr)
+
+/* Conversions */
+extern "C" float __floatsisf(int op1); // OP_INT_TO_FLOAT
+extern "C" int __fixsfsi(float op1); // OP_FLOAT_TO_INT
+extern "C" float __truncdfsf2(double op1); // OP_DOUBLE_TO_FLOAT
+extern "C" double __extendsfdf2(float op1); // OP_FLOAT_TO_DOUBLE
+extern "C" double __floatsidf(int op1); // OP_INT_TO_DOUBLE
+extern "C" int __fixdfsi(double op1); // OP_DOUBLE_TO_INT
+extern "C" float __floatdisf(long long op1); // OP_LONG_TO_FLOAT
+extern "C" double __floatdidf(long long op1); // OP_LONG_TO_DOUBLE
+extern "C" long long __fixsfdi(float op1); // OP_FLOAT_TO_LONG
+extern "C" long long __fixdfdi(double op1); // OP_DOUBLE_TO_LONG
+
+/* Single-precision FP arithmetics */
+extern "C" float __addsf3(float a, float b); // OP_ADD_FLOAT[_2ADDR]
+extern "C" float __subsf3(float a, float b); // OP_SUB_FLOAT[_2ADDR]
+extern "C" float __divsf3(float a, float b); // OP_DIV_FLOAT[_2ADDR]
+extern "C" float __mulsf3(float a, float b); // OP_MUL_FLOAT[_2ADDR]
+extern "C" float fmodf(float a, float b); // OP_REM_FLOAT[_2ADDR]
+
+/* Double-precision FP arithmetics */
+extern "C" double __adddf3(double a, double b); // OP_ADD_DOUBLE[_2ADDR]
+extern "C" double __subdf3(double a, double b); // OP_SUB_DOUBLE[_2ADDR]
+extern "C" double __divdf3(double a, double b); // OP_DIV_DOUBLE[_2ADDR]
+extern "C" double __muldf3(double a, double b); // OP_MUL_DOUBLE[_2ADDR]
+extern "C" double fmod(double a, double b); // OP_REM_DOUBLE[_2ADDR]
+
+/* Long long arithmetics - OP_REM_LONG[_2ADDR] & OP_DIV_LONG[_2ADDR] */
+extern "C" long long __divdi3(long long op1, long long op2);
+extern "C" long long __moddi3(long long op1, long long op2);
+
+/* Originally declared in Sync.h */
+bool dvmUnlockObject(struct Thread* self, struct Object* obj); //OP_MONITOR_EXIT
+
+/* Originally declared in oo/TypeCheck.h */
+bool dvmCanPutArrayElement(const ClassObject* elemClass, // OP_APUT_OBJECT
+ const ClassObject* arrayClass);
+int dvmInstanceofNonTrivial(const ClassObject* instance, // OP_CHECK_CAST &&
+ const ClassObject* clazz); // OP_INSTANCE_OF
+
+/* Originally declared in oo/Array.h */
+ArrayObject* dvmAllocArrayByClass(ClassObject* arrayClass, // OP_NEW_ARRAY
+ size_t length, int allocFlags);
+
+/* Originally declared in interp/InterpDefs.h */
+bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,// OP_FILL_ARRAY_DATA
+ const u2* arrayData);
+
+/* Originally declared in compiler/codegen/mips/Assemble.c */
+const Method *dvmJitToPatchPredictedChain(const Method *method,
+ Thread *self,
+ PredictedChainingCell *cell,
+ const ClassObject *clazz);
+
+/*
+ * Resolve interface callsites - OP_INVOKE_INTERFACE & OP_INVOKE_INTERFACE_RANGE
+ *
+ * Originally declared in mterp/common/FindInterface.h and only comment it here
+ * due to the INLINE attribute.
+ *
+ * INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
+ * u4 methodIdx, const Method* method, DvmDex* methodClassDex)
+ */
+
+/* Originally declared in alloc/Alloc.h */
+Object* dvmAllocObject(ClassObject* clazz, int flags); // OP_NEW_INSTANCE
+
+/*
+ * Functions declared in gDvmInlineOpsTable[] are used for
+ * OP_EXECUTE_INLINE & OP_EXECUTE_INLINE_RANGE.
+ */
+extern "C" double sqrt(double x); // INLINE_MATH_SQRT
+
+/*
+ * The following functions are invoked through the compiler templates (declared
+ * in compiler/template/armv5te/footer.S:
+ *
+ * __aeabi_cdcmple // CMPG_DOUBLE
+ * __aeabi_cfcmple // CMPG_FLOAT
+ * dvmLockObject // MONITOR_ENTER
+ */
+
+#endif // DALVIK_VM_COMPILER_CODEGEN_MIPS_CALLOUT_HELPER_H_
diff --git a/vm/compiler/codegen/mips/Codegen.h b/vm/compiler/codegen/mips/Codegen.h
new file mode 100644
index 0000000..107fa86
--- /dev/null
+++ b/vm/compiler/codegen/mips/Codegen.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains register alloction support and is intended to be
+ * included by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "compiler/CompilerIR.h"
+#include "CalloutHelper.h"
+
+#if defined(_CODEGEN_C)
+/*
+ * loadConstant() sometimes needs to add a small imm to a pre-existing constant
+ */
+static MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+ int value);
+static MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+ int rSrc2);
+
+/* Forward-declare the portable versions due to circular dependency */
+static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2);
+
+static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2);
+
+static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir);
+
+static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir);
+
+static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir);
+
+
+#endif
+
+#if defined(WITH_SELF_VERIFICATION)
+/* Self Verification memory instruction decoder */
+extern "C" void dvmSelfVerificationMemOpDecode(int lr, int* sp);
+#endif
+
+/*
+ * Architecture-dependent register allocation routines implemented in
+ * Mips/Ralloc.c
+ */
+extern int dvmCompilerAllocTypedTempPair(CompilationUnit *cUnit,
+ bool fpHint, int regClass);
+
+extern int dvmCompilerAllocTypedTemp(CompilationUnit *cUnit, bool fpHint,
+ int regClass);
+
+extern MipsLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest,
+ int rSrc);
+
+extern MipsLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
+
+extern void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo,
+ int destHi, int srcLo, int srcHi);
+
+extern void dvmCompilerSetupResourceMasks(MipsLIR *lir);
+
+extern void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc, OpSize size);
+
+extern void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrcLo,
+ int rSrcHi);
diff --git a/vm/compiler/codegen/mips/CodegenCommon.cpp b/vm/compiler/codegen/mips/CodegenCommon.cpp
new file mode 100644
index 0000000..0622fb8
--- /dev/null
+++ b/vm/compiler/codegen/mips/CodegenCommon.cpp
@@ -0,0 +1,437 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen and support common to all supported
+ * Mips variants. It is included by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ * which combines this common code with specific support found in the
+ * applicable directory below this one.
+ */
+
+#include "compiler/Loop.h"
+
+/* Array holding the entry offset of each template relative to the first one */
+static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
+
+/* Track exercised opcodes */
+static int opcodeCoverage[256];
+
+static void setMemRefType(MipsLIR *lir, bool isLoad, int memType)
+{
+ /* MIPSTODO simplify setMemRefType() */
+ u8 *maskPtr;
+ u8 mask = ENCODE_MEM;;
+ assert(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
+
+ if (isLoad) {
+ maskPtr = &lir->useMask;
+ } else {
+ maskPtr = &lir->defMask;
+ }
+ /* Clear out the memref flags */
+ *maskPtr &= ~mask;
+ /* ..and then add back the one we need */
+ switch(memType) {
+ case kLiteral:
+ assert(isLoad);
+ *maskPtr |= ENCODE_LITERAL;
+ break;
+ case kDalvikReg:
+ *maskPtr |= ENCODE_DALVIK_REG;
+ break;
+ case kHeapRef:
+ *maskPtr |= ENCODE_HEAP_REF;
+ break;
+ case kMustNotAlias:
+ /* Currently only loads can be marked as kMustNotAlias */
+ assert(!(EncodingMap[lir->opcode].flags & IS_STORE));
+ *maskPtr |= ENCODE_MUST_NOT_ALIAS;
+ break;
+ default:
+ ALOGE("Jit: invalid memref kind - %d", memType);
+ assert(0); // Bail if debug build, set worst-case in the field
+ *maskPtr |= ENCODE_ALL;
+ }
+}
+
+/*
+ * Mark load/store instructions that access Dalvik registers through rFP +
+ * offset.
+ */
+static void annotateDalvikRegAccess(MipsLIR *lir, int regId, bool isLoad)
+{
+ /* MIPSTODO simplify annotateDalvikRegAccess() */
+ setMemRefType(lir, isLoad, kDalvikReg);
+
+ /*
+ * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
+ * access.
+ */
+ lir->aliasInfo = regId;
+ if (DOUBLEREG(lir->operands[0])) {
+ lir->aliasInfo |= 0x80000000;
+ }
+}
+
+/*
+ * Decode the register id
+ */
+static inline u8 getRegMaskCommon(int reg)
+{
+ u8 seed;
+ int shift;
+ int regId = reg & 0x1f;
+
+ /*
+ * Each double register is equal to a pair of single-precision FP registers
+ */
+ if (!DOUBLEREG(reg)) {
+ seed = 1;
+ } else {
+ assert((regId & 1) == 0); /* double registers must be even */
+ seed = 3;
+ }
+
+ if (FPREG(reg)) {
+ assert(regId < 16); /* only 16 fp regs */
+ shift = kFPReg0;
+ } else if (EXTRAREG(reg)) {
+ assert(regId < 3); /* only 3 extra regs */
+ shift = kFPRegEnd;
+ } else {
+ shift = 0;
+ }
+
+ /* Expand the double register id into single offset */
+ shift += regId;
+ return (seed << shift);
+}
+
+/* External version of getRegMaskCommon */
+u8 dvmGetRegResourceMask(int reg)
+{
+ return getRegMaskCommon(reg);
+}
+
+/*
+ * Mark the corresponding bit(s).
+ */
+static inline void setupRegMask(u8 *mask, int reg)
+{
+ *mask |= getRegMaskCommon(reg);
+}
+
+/*
+ * Set up the proper fields in the resource mask
+ */
+static void setupResourceMasks(MipsLIR *lir)
+{
+ /* MIPSTODO simplify setupResourceMasks() */
+ int opcode = lir->opcode;
+ int flags;
+
+ if (opcode <= 0) {
+ lir->useMask = lir->defMask = 0;
+ return;
+ }
+
+ flags = EncodingMap[lir->opcode].flags;
+
+ /* Set up the mask for resources that are updated */
+ if (flags & (IS_LOAD | IS_STORE)) {
+ /* Default to heap - will catch specialized classes later */
+ setMemRefType(lir, flags & IS_LOAD, kHeapRef);
+ }
+
+ /*
+ * Conservatively assume the branch here will call out a function that in
+ * turn will trash everything.
+ */
+ if (flags & IS_BRANCH) {
+ lir->defMask = lir->useMask = ENCODE_ALL;
+ return;
+ }
+
+ if (flags & REG_DEF0) {
+ setupRegMask(&lir->defMask, lir->operands[0]);
+ }
+
+ if (flags & REG_DEF1) {
+ setupRegMask(&lir->defMask, lir->operands[1]);
+ }
+
+ if (flags & REG_DEF_SP) {
+ lir->defMask |= ENCODE_REG_SP;
+ }
+
+ if (flags & REG_DEF_LR) {
+ lir->defMask |= ENCODE_REG_LR;
+ }
+
+ if (flags & REG_DEF_LIST0) {
+ lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
+ }
+
+ if (flags & REG_DEF_LIST1) {
+ lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
+ }
+
+ if (flags & SETS_CCODES) {
+ lir->defMask |= ENCODE_CCODE;
+ }
+
+ /* Conservatively treat the IT block */
+ if (flags & IS_IT) {
+ lir->defMask = ENCODE_ALL;
+ }
+
+ if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (flags & (1 << (kRegUse0 + i))) {
+ setupRegMask(&lir->useMask, lir->operands[i]);
+ }
+ }
+ }
+
+ if (flags & REG_USE_PC) {
+ lir->useMask |= ENCODE_REG_PC;
+ }
+
+ if (flags & REG_USE_SP) {
+ lir->useMask |= ENCODE_REG_SP;
+ }
+
+ if (flags & REG_USE_LIST0) {
+ lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
+ }
+
+ if (flags & REG_USE_LIST1) {
+ lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
+ }
+
+ if (flags & USES_CCODES) {
+ lir->useMask |= ENCODE_CCODE;
+ }
+}
+
+/*
+ * Set up the accurate resource mask for branch instructions
+ */
+static void relaxBranchMasks(MipsLIR *lir)
+{
+ int flags = EncodingMap[lir->opcode].flags;
+
+ /* Make sure only branch instructions are passed here */
+ assert(flags & IS_BRANCH);
+
+ lir->defMask |= ENCODE_REG_PC;
+ lir->useMask |= ENCODE_REG_PC;
+
+
+ if (flags & REG_DEF_LR) {
+ lir->defMask |= ENCODE_REG_LR;
+ }
+
+ if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (flags & (1 << (kRegUse0 + i))) {
+ setupRegMask(&lir->useMask, lir->operands[i]);
+ }
+ }
+ }
+
+ if (flags & USES_CCODES) {
+ lir->useMask |= ENCODE_CCODE;
+ }
+}
+
+/*
+ * The following are building blocks to construct low-level IRs with 0 - 4
+ * operands.
+ */
+static MipsLIR *newLIR0(CompilationUnit *cUnit, MipsOpCode opcode)
+{
+ MipsLIR *insn = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ assert(isPseudoOpCode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
+ insn->opcode = opcode;
+ setupResourceMasks(insn);
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static MipsLIR *newLIR1(CompilationUnit *cUnit, MipsOpCode opcode,
+ int dest)
+{
+ MipsLIR *insn = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ assert(isPseudoOpCode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
+ insn->opcode = opcode;
+ insn->operands[0] = dest;
+ setupResourceMasks(insn);
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static MipsLIR *newLIR2(CompilationUnit *cUnit, MipsOpCode opcode,
+ int dest, int src1)
+{
+ MipsLIR *insn = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ assert(isPseudoOpCode(opcode) ||
+ (EncodingMap[opcode].flags & IS_BINARY_OP));
+ insn->opcode = opcode;
+ insn->operands[0] = dest;
+ insn->operands[1] = src1;
+ setupResourceMasks(insn);
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static MipsLIR *newLIR3(CompilationUnit *cUnit, MipsOpCode opcode,
+ int dest, int src1, int src2)
+{
+ MipsLIR *insn = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ if (!(EncodingMap[opcode].flags & IS_TERTIARY_OP)) {
+ ALOGE("Bad LIR3: %s[%d]",EncodingMap[opcode].name,opcode);
+ }
+ assert(isPseudoOpCode(opcode) ||
+ (EncodingMap[opcode].flags & IS_TERTIARY_OP));
+ insn->opcode = opcode;
+ insn->operands[0] = dest;
+ insn->operands[1] = src1;
+ insn->operands[2] = src2;
+ setupResourceMasks(insn);
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static MipsLIR *newLIR4(CompilationUnit *cUnit, MipsOpCode opcode,
+ int dest, int src1, int src2, int info)
+{
+ MipsLIR *insn = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ assert(isPseudoOpCode(opcode) ||
+ (EncodingMap[opcode].flags & IS_QUAD_OP));
+ insn->opcode = opcode;
+ insn->operands[0] = dest;
+ insn->operands[1] = src1;
+ insn->operands[2] = src2;
+ insn->operands[3] = info;
+ setupResourceMasks(insn);
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+/*
+ * If the next instruction is a move-result or move-result-long,
+ * return the target Dalvik sReg[s] and convert the next to a
+ * nop. Otherwise, return INVALID_SREG. Used to optimize method inlining.
+ */
+static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
+ bool fpHint)
+{
+ if (mir->next &&
+ ((mir->next->dalvikInsn.opcode == OP_MOVE_RESULT) ||
+ (mir->next->dalvikInsn.opcode == OP_MOVE_RESULT_OBJECT))) {
+ mir->next->dalvikInsn.opcode = OP_NOP;
+ return dvmCompilerGetDest(cUnit, mir->next, 0);
+ } else {
+ RegLocation res = LOC_DALVIK_RETURN_VAL;
+ res.fp = fpHint;
+ return res;
+ }
+}
+
+/*
+ * The following are building blocks to insert constants into the pool or
+ * instruction streams.
+ */
+
+/* Add a 32-bit constant either in the constant pool or mixed with code */
+static MipsLIR *addWordData(CompilationUnit *cUnit, LIR **constantListP,
+ int value)
+{
+ /* Add the constant to the literal pool */
+ if (constantListP) {
+ MipsLIR *newValue = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ newValue->operands[0] = value;
+ newValue->generic.next = *constantListP;
+ *constantListP = (LIR *) newValue;
+ return newValue;
+ } else {
+ /* Add the constant in the middle of code stream */
+ newLIR1(cUnit, kMips32BitData, value);
+ }
+ return NULL;
+}
+
+static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
+ bool fpHint)
+{
+ if (mir->next &&
+ (mir->next->dalvikInsn.opcode == OP_MOVE_RESULT_WIDE)) {
+ mir->next->dalvikInsn.opcode = OP_NOP;
+ return dvmCompilerGetDestWide(cUnit, mir->next, 0, 1);
+ } else {
+ RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
+ res.fp = fpHint;
+ return res;
+ }
+}
+
+
+/*
+ * Generate an kMipsPseudoBarrier marker to indicate the boundary of special
+ * blocks.
+ */
+static void genBarrier(CompilationUnit *cUnit)
+{
+ MipsLIR *barrier = newLIR0(cUnit, kMipsPseudoBarrier);
+ /* Mark all resources as being clobbered */
+ barrier->defMask = -1;
+}
+
+/* Create the PC reconstruction slot if not already done */
+extern MipsLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
+ MipsLIR *branch,
+ MipsLIR *pcrLabel)
+{
+ /* Forget all def info (because we might rollback here. Bug #2367397 */
+ dvmCompilerResetDefTracking(cUnit);
+
+ /* Set up the place holder to reconstruct this Dalvik PC */
+ if (pcrLabel == NULL) {
+ int dPC = (int) (cUnit->method->insns + dOffset);
+ pcrLabel = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ pcrLabel->opcode = kMipsPseudoPCReconstructionCell;
+ pcrLabel->operands[0] = dPC;
+ pcrLabel->operands[1] = dOffset;
+ /* Insert the place holder to the growable list */
+ dvmInsertGrowableList(&cUnit->pcReconstructionList,
+ (intptr_t) pcrLabel);
+ }
+ /* Branch to the PC reconstruction code */
+ branch->generic.target = (LIR *) pcrLabel;
+
+ /* Clear the conservative flags for branches that punt to the interpreter */
+ relaxBranchMasks(branch);
+
+ return pcrLabel;
+}
diff --git a/vm/compiler/codegen/mips/CodegenDriver.cpp b/vm/compiler/codegen/mips/CodegenDriver.cpp
new file mode 100644
index 0000000..fea1d1e
--- /dev/null
+++ b/vm/compiler/codegen/mips/CodegenDriver.cpp
@@ -0,0 +1,4860 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen and support common to all supported
+ * Mips variants. It is included by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ * which combines this common code with specific support found in the
+ * applicable directory below this one.
+ */
+
+/*
+ * Mark garbage collection card. Skip if the value we're storing is null.
+ */
+static void markCard(CompilationUnit *cUnit, int valReg, int tgtAddrReg)
+{
+ int regCardBase = dvmCompilerAllocTemp(cUnit);
+ int regCardNo = dvmCompilerAllocTemp(cUnit);
+ MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBeq, valReg, r_ZERO);
+ loadWordDisp(cUnit, rSELF, offsetof(Thread, cardTable),
+ regCardBase);
+ opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
+ storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
+ kUnsignedByte);
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branchOver->generic.target = (LIR *)target;
+ dvmCompilerFreeTemp(cUnit, regCardBase);
+ dvmCompilerFreeTemp(cUnit, regCardNo);
+}
+
+static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
+ int srcSize, int tgtSize)
+{
+ /*
+ * Don't optimize the register usage since it calls out to template
+ * functions
+ */
+ RegLocation rlSrc;
+ RegLocation rlDest;
+ int srcReg = 0;
+ int srcRegHi = 0;
+ dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
+
+ if (srcSize == kWord) {
+ srcReg = r_A0;
+ } else if (srcSize == kSingle) {
+#ifdef __mips_hard_float
+ srcReg = r_F12;
+#else
+ srcReg = r_A0;
+#endif
+ } else if (srcSize == kLong) {
+ srcReg = r_ARG0;
+ srcRegHi = r_ARG1;
+ } else if (srcSize == kDouble) {
+#ifdef __mips_hard_float
+ srcReg = r_FARG0;
+ srcRegHi = r_FARG1;
+#else
+ srcReg = r_ARG0;
+ srcRegHi = r_ARG1;
+#endif
+ }
+ else {
+ assert(0);
+ }
+
+ if (srcSize == kWord || srcSize == kSingle) {
+ rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ loadValueDirectFixed(cUnit, rlSrc, srcReg);
+ } else {
+ rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ loadValueDirectWideFixed(cUnit, rlSrc, srcReg, srcRegHi);
+ }
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)funct);
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+ if (tgtSize == kWord || tgtSize == kSingle) {
+ RegLocation rlResult;
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+#ifdef __mips_hard_float
+ if (tgtSize == kSingle)
+ rlResult = dvmCompilerGetReturnAlt(cUnit);
+ else
+ rlResult = dvmCompilerGetReturn(cUnit);
+#else
+ rlResult = dvmCompilerGetReturn(cUnit);
+#endif
+ storeValue(cUnit, rlDest, rlResult);
+ } else {
+ RegLocation rlResult;
+ rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+#ifdef __mips_hard_float
+ if (tgtSize == kDouble)
+ rlResult = dvmCompilerGetReturnWideAlt(cUnit);
+ else
+ rlResult = dvmCompilerGetReturnWide(cUnit);
+#else
+ rlResult = dvmCompilerGetReturnWide(cUnit);
+#endif
+ storeValueWide(cUnit, rlDest, rlResult);
+ }
+ return false;
+}
+
+
+static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ void* funct;
+
+ switch (mir->dalvikInsn.opcode) {
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_ADD_FLOAT:
+ funct = (void*) __addsf3;
+ break;
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_SUB_FLOAT:
+ funct = (void*) __subsf3;
+ break;
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_DIV_FLOAT:
+ funct = (void*) __divsf3;
+ break;
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_MUL_FLOAT:
+ funct = (void*) __mulsf3;
+ break;
+ case OP_REM_FLOAT_2ADDR:
+ case OP_REM_FLOAT:
+ funct = (void*) fmodf;
+ break;
+ case OP_NEG_FLOAT: {
+ genNegFloat(cUnit, rlDest, rlSrc1);
+ return false;
+ }
+ default:
+ return true;
+ }
+
+ dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
+#ifdef __mips_hard_float
+ loadValueDirectFixed(cUnit, rlSrc1, r_F12);
+ loadValueDirectFixed(cUnit, rlSrc2, r_F14);
+#else
+ loadValueDirectFixed(cUnit, rlSrc1, r_A0);
+ loadValueDirectFixed(cUnit, rlSrc2, r_A1);
+#endif
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)funct);
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+#ifdef __mips_hard_float
+ rlResult = dvmCompilerGetReturnAlt(cUnit);
+#else
+ rlResult = dvmCompilerGetReturn(cUnit);
+#endif
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ void* funct;
+
+ switch (mir->dalvikInsn.opcode) {
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_ADD_DOUBLE:
+ funct = (void*) __adddf3;
+ break;
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE:
+ funct = (void*) __subdf3;
+ break;
+ case OP_DIV_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE:
+ funct = (void*) __divsf3;
+ break;
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE:
+ funct = (void*) __muldf3;
+ break;
+ case OP_REM_DOUBLE_2ADDR:
+ case OP_REM_DOUBLE:
+ funct = (void*) (double (*)(double, double)) fmod;
+ break;
+ case OP_NEG_DOUBLE: {
+ genNegDouble(cUnit, rlDest, rlSrc1);
+ return false;
+ }
+ default:
+ return true;
+ }
+ dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)funct);
+#ifdef __mips_hard_float
+ loadValueDirectWideFixed(cUnit, rlSrc1, r_F12, r_F13);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r_F14, r_F15);
+#else
+ loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
+#endif
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+#ifdef __mips_hard_float
+ rlResult = dvmCompilerGetReturnWideAlt(cUnit);
+#else
+ rlResult = dvmCompilerGetReturnWide(cUnit);
+#endif
+ storeValueWide(cUnit, rlDest, rlResult);
+#if defined(WITH_SELF_VERIFICATION)
+ cUnit->usesLinkRegister = true;
+#endif
+ return false;
+}
+
+static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode opcode = mir->dalvikInsn.opcode;
+
+ switch (opcode) {
+ case OP_INT_TO_FLOAT:
+ return genConversionCall(cUnit, mir, (void*)__floatsisf, kWord, kSingle);
+ case OP_FLOAT_TO_INT:
+ return genConversionCall(cUnit, mir, (void*)__fixsfsi, kSingle, kWord);
+ case OP_DOUBLE_TO_FLOAT:
+ return genConversionCall(cUnit, mir, (void*)__truncdfsf2, kDouble, kSingle);
+ case OP_FLOAT_TO_DOUBLE:
+ return genConversionCall(cUnit, mir, (void*)__extendsfdf2, kSingle, kDouble);
+ case OP_INT_TO_DOUBLE:
+ return genConversionCall(cUnit, mir, (void*)__floatsidf, kWord, kDouble);
+ case OP_DOUBLE_TO_INT:
+ return genConversionCall(cUnit, mir, (void*)__fixdfsi, kDouble, kWord);
+ case OP_FLOAT_TO_LONG:
+ return genConversionCall(cUnit, mir, (void*)__fixsfdi, kSingle, kLong);
+ case OP_LONG_TO_FLOAT:
+ return genConversionCall(cUnit, mir, (void*)__floatdisf, kLong, kSingle);
+ case OP_DOUBLE_TO_LONG:
+ return genConversionCall(cUnit, mir, (void*)__fixdfdi, kDouble, kLong);
+ case OP_LONG_TO_DOUBLE:
+ return genConversionCall(cUnit, mir, (void*)__floatdidf, kLong, kDouble);
+ default:
+ return true;
+ }
+ return false;
+}
+
+#if defined(WITH_SELF_VERIFICATION)
+static void selfVerificationBranchInsert(LIR *currentLIR, Mipsopcode opcode,
+ int dest, int src1)
+{
+assert(0); /* MIPSTODO port selfVerificationBranchInsert() */
+ MipsLIR *insn = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ insn->opcode = opcode;
+ insn->operands[0] = dest;
+ insn->operands[1] = src1;
+ setupResourceMasks(insn);
+ dvmCompilerInsertLIRBefore(currentLIR, (LIR *) insn);
+}
+
+/*
+ * Example where r14 (LR) is preserved around a heap access under
+ * self-verification mode in Thumb2:
+ *
+ * D/dalvikvm( 1538): 0x59414c5e (0026): ldr r14, [r15pc, #220] <-hoisted
+ * D/dalvikvm( 1538): 0x59414c62 (002a): mla r4, r0, r8, r4
+ * D/dalvikvm( 1538): 0x59414c66 (002e): adds r3, r4, r3
+ * D/dalvikvm( 1538): 0x59414c6a (0032): push <r5, r14> ---+
+ * D/dalvikvm( 1538): 0x59414c6c (0034): blx_1 0x5940f494 |
+ * D/dalvikvm( 1538): 0x59414c6e (0036): blx_2 see above <-MEM_OP_DECODE
+ * D/dalvikvm( 1538): 0x59414c70 (0038): ldr r10, [r9, #0] |
+ * D/dalvikvm( 1538): 0x59414c74 (003c): pop <r5, r14> ---+
+ * D/dalvikvm( 1538): 0x59414c78 (0040): mov r11, r10
+ * D/dalvikvm( 1538): 0x59414c7a (0042): asr r12, r11, #31
+ * D/dalvikvm( 1538): 0x59414c7e (0046): movs r0, r2
+ * D/dalvikvm( 1538): 0x59414c80 (0048): movs r1, r3
+ * D/dalvikvm( 1538): 0x59414c82 (004a): str r2, [r5, #16]
+ * D/dalvikvm( 1538): 0x59414c84 (004c): mov r2, r11
+ * D/dalvikvm( 1538): 0x59414c86 (004e): str r3, [r5, #20]
+ * D/dalvikvm( 1538): 0x59414c88 (0050): mov r3, r12
+ * D/dalvikvm( 1538): 0x59414c8a (0052): str r11, [r5, #24]
+ * D/dalvikvm( 1538): 0x59414c8e (0056): str r12, [r5, #28]
+ * D/dalvikvm( 1538): 0x59414c92 (005a): blx r14 <-use of LR
+ *
+ */
+static void selfVerificationBranchInsertPass(CompilationUnit *cUnit)
+{
+assert(0); /* MIPSTODO port selfVerificationBranchInsertPass() */
+ MipsLIR *thisLIR;
+ Templateopcode opcode = TEMPLATE_MEM_OP_DECODE;
+
+ for (thisLIR = (MipsLIR *) cUnit->firstLIRInsn;
+ thisLIR != (MipsLIR *) cUnit->lastLIRInsn;
+ thisLIR = NEXT_LIR(thisLIR)) {
+ if (!thisLIR->flags.isNop && thisLIR->flags.insertWrapper) {
+ /*
+ * Push r5(FP) and r14(LR) onto stack. We need to make sure that
+ * SP is 8-byte aligned, and we use r5 as a temp to restore LR
+ * for Thumb-only target since LR cannot be directly accessed in
+ * Thumb mode. Another reason to choose r5 here is it is the Dalvik
+ * frame pointer and cannot be the target of the emulated heap
+ * load.
+ */
+ if (cUnit->usesLinkRegister) {
+ genSelfVerificationPreBranch(cUnit, thisLIR);
+ }
+
+ /* Branch to mem op decode template */
+ selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx1,
+ (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
+ (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+ selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx2,
+ (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
+ (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+
+ /* Restore LR */
+ if (cUnit->usesLinkRegister) {
+ genSelfVerificationPostBranch(cUnit, thisLIR);
+ }
+ }
+ }
+}
+#endif
+
+/* Generate conditional branch instructions */
+static MipsLIR *genConditionalBranchMips(CompilationUnit *cUnit,
+ MipsOpCode opc, int rs, int rt,
+ MipsLIR *target)
+{
+ MipsLIR *branch = opCompareBranch(cUnit, opc, rs, rt);
+ branch->generic.target = (LIR *) target;
+ return branch;
+}
+
+/* Generate a unconditional branch to go to the interpreter */
+static inline MipsLIR *genTrap(CompilationUnit *cUnit, int dOffset,
+ MipsLIR *pcrLabel)
+{
+ MipsLIR *branch = opNone(cUnit, kOpUncondBr);
+ return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+}
+
+/* Load a wide field from an object instance */
+static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
+{
+ RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ RegLocation rlResult;
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ int regPtr = dvmCompilerAllocTemp(cUnit);
+
+ assert(rlDest.wide);
+
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+ opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+
+ HEAP_ACCESS_SHADOW(true);
+ loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
+ HEAP_ACCESS_SHADOW(false);
+
+ dvmCompilerFreeTemp(cUnit, regPtr);
+ storeValueWide(cUnit, rlDest, rlResult);
+}
+
+/* Store a wide field to an object instance */
+static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
+{
+ RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 2);
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ int regPtr;
+ rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+ regPtr = dvmCompilerAllocTemp(cUnit);
+ opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
+
+ HEAP_ACCESS_SHADOW(true);
+ storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
+ HEAP_ACCESS_SHADOW(false);
+
+ dvmCompilerFreeTemp(cUnit, regPtr);
+}
+
+/*
+ * Load a field from an object instance
+ *
+ */
+static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
+ int fieldOffset, bool isVolatile)
+{
+ RegLocation rlResult;
+ RegisterClass regClass = dvmCompilerRegClassBySize(size);
+ RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+
+ HEAP_ACCESS_SHADOW(true);
+ loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
+ size, rlObj.sRegLow);
+ HEAP_ACCESS_SHADOW(false);
+ if (isVolatile) {
+ dvmCompilerGenMemBarrier(cUnit, 0);
+ }
+
+ storeValue(cUnit, rlDest, rlResult);
+}
+
+/*
+ * Store a field to an object instance
+ *
+ */
+static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
+ int fieldOffset, bool isObject, bool isVolatile)
+{
+ RegisterClass regClass = dvmCompilerRegClassBySize(size);
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 1);
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ rlSrc = loadValue(cUnit, rlSrc, regClass);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+
+ if (isVolatile) {
+ dvmCompilerGenMemBarrier(cUnit, 0);
+ }
+ HEAP_ACCESS_SHADOW(true);
+ storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
+ HEAP_ACCESS_SHADOW(false);
+ if (isVolatile) {
+ dvmCompilerGenMemBarrier(cUnit, 0);
+ }
+ if (isObject) {
+ /* NOTE: marking card based on object head */
+ markCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
+ }
+}
+
+
+/*
+ * Generate array load
+ */
+static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
+ RegLocation rlArray, RegLocation rlIndex,
+ RegLocation rlDest, int scale)
+{
+ RegisterClass regClass = dvmCompilerRegClassBySize(size);
+ int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+ int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
+ RegLocation rlResult;
+ rlArray = loadValue(cUnit, rlArray, kCoreReg);
+ rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
+ int regPtr;
+
+ /* null object? */
+ MipsLIR * pcrLabel = NULL;
+
+ if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
+ pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
+ rlArray.lowReg, mir->offset, NULL);
+ }
+
+ regPtr = dvmCompilerAllocTemp(cUnit);
+
+ assert(IS_SIMM16(dataOffset));
+ if (scale) {
+ opRegRegImm(cUnit, kOpLsl, regPtr, rlIndex.lowReg, scale);
+ }
+
+ if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ int regLen = dvmCompilerAllocTemp(cUnit);
+ /* Get len */
+ loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
+ genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
+ pcrLabel);
+ dvmCompilerFreeTemp(cUnit, regLen);
+ }
+
+ if (scale) {
+ opRegReg(cUnit, kOpAdd, regPtr, rlArray.lowReg);
+ } else {
+ opRegRegReg(cUnit, kOpAdd, regPtr, rlArray.lowReg, rlIndex.lowReg);
+ }
+
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
+ if ((size == kLong) || (size == kDouble)) {
+ HEAP_ACCESS_SHADOW(true);
+ loadBaseDispWide(cUnit, mir, regPtr, dataOffset, rlResult.lowReg,
+ rlResult.highReg, INVALID_SREG);
+ HEAP_ACCESS_SHADOW(false);
+ dvmCompilerFreeTemp(cUnit, regPtr);
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else {
+ HEAP_ACCESS_SHADOW(true);
+ loadBaseDisp(cUnit, mir, regPtr, dataOffset, rlResult.lowReg,
+ size, INVALID_SREG);
+ HEAP_ACCESS_SHADOW(false);
+ dvmCompilerFreeTemp(cUnit, regPtr);
+ storeValue(cUnit, rlDest, rlResult);
+ }
+}
+
+/*
+ * Generate array store
+ *
+ */
+static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
+ RegLocation rlArray, RegLocation rlIndex,
+ RegLocation rlSrc, int scale)
+{
+ RegisterClass regClass = dvmCompilerRegClassBySize(size);
+ int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+ int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
+
+ int regPtr;
+ rlArray = loadValue(cUnit, rlArray, kCoreReg);
+ rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
+
+ if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) {
+ dvmCompilerClobber(cUnit, rlArray.lowReg);
+ regPtr = rlArray.lowReg;
+ } else {
+ regPtr = dvmCompilerAllocTemp(cUnit);
+ genRegCopy(cUnit, regPtr, rlArray.lowReg);
+ }
+
+ /* null object? */
+ MipsLIR * pcrLabel = NULL;
+
+ if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
+ pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
+ mir->offset, NULL);
+ }
+
+ assert(IS_SIMM16(dataOffset));
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ if (scale) {
+ opRegRegImm(cUnit, kOpLsl, tReg, rlIndex.lowReg, scale);
+ }
+
+ if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ int regLen = dvmCompilerAllocTemp(cUnit);
+ //NOTE: max live temps(4) here.
+ /* Get len */
+ loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
+ genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
+ pcrLabel);
+ dvmCompilerFreeTemp(cUnit, regLen);
+ }
+
+ if (scale) {
+ opRegReg(cUnit, kOpAdd, tReg, rlArray.lowReg);
+ } else {
+ opRegRegReg(cUnit, kOpAdd, tReg, rlArray.lowReg, rlIndex.lowReg);
+ }
+
+ /* at this point, tReg points to array, 2 live temps */
+ if ((size == kLong) || (size == kDouble)) {
+ rlSrc = loadValueWide(cUnit, rlSrc, regClass);
+ HEAP_ACCESS_SHADOW(true);
+ storeBaseDispWide(cUnit, tReg, dataOffset, rlSrc.lowReg, rlSrc.highReg)
+ HEAP_ACCESS_SHADOW(false);
+ dvmCompilerFreeTemp(cUnit, tReg);
+ dvmCompilerFreeTemp(cUnit, regPtr);
+ } else {
+ rlSrc = loadValue(cUnit, rlSrc, regClass);
+ HEAP_ACCESS_SHADOW(true);
+ storeBaseDisp(cUnit, tReg, dataOffset, rlSrc.lowReg, size);
+ dvmCompilerFreeTemp(cUnit, tReg);
+ HEAP_ACCESS_SHADOW(false);
+ }
+}
+
+/*
+ * Generate array object store
+ * Must use explicit register allocation here because of
+ * call-out to dvmCanPutArrayElement
+ */
+static void genArrayObjectPut(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlArray, RegLocation rlIndex,
+ RegLocation rlSrc, int scale)
+{
+ int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+ int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
+
+ int regLen = r_A0;
+ int regPtr = r_S0; /* Preserved across call */
+ int regArray = r_A1;
+ int regIndex = r_S4; /* Preserved across call */
+
+ dvmCompilerFlushAllRegs(cUnit);
+ // moved lock for r_S0 and r_S4 here from below since genBoundsCheck
+ // allocates a temporary that can result in clobbering either of them
+ dvmCompilerLockTemp(cUnit, regPtr); // r_S0
+ dvmCompilerLockTemp(cUnit, regIndex); // r_S4
+
+ loadValueDirectFixed(cUnit, rlArray, regArray);
+ loadValueDirectFixed(cUnit, rlIndex, regIndex);
+
+ /* null object? */
+ MipsLIR * pcrLabel = NULL;
+
+ if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
+ pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, regArray,
+ mir->offset, NULL);
+ }
+
+ if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ /* Get len */
+ loadWordDisp(cUnit, regArray, lenOffset, regLen);
+ /* regPtr -> array data */
+ opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset);
+ genBoundsCheck(cUnit, regIndex, regLen, mir->offset,
+ pcrLabel);
+ } else {
+ /* regPtr -> array data */
+ opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset);
+ }
+
+ /* Get object to store */
+ loadValueDirectFixed(cUnit, rlSrc, r_A0);
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmCanPutArrayElement);
+
+ /* Are we storing null? If so, avoid check */
+ MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBeqz, r_A0, -1);
+
+ /* Make sure the types are compatible */
+ loadWordDisp(cUnit, regArray, offsetof(Object, clazz), r_A1);
+ loadWordDisp(cUnit, r_A0, offsetof(Object, clazz), r_A0);
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+
+ /*
+ * Using fixed registers here, and counting on r_S0 and r_S4 being
+ * preserved across the above call. Tell the register allocation
+ * utilities about the regs we are using directly
+ */
+ dvmCompilerLockTemp(cUnit, r_A0);
+ dvmCompilerLockTemp(cUnit, r_A1);
+
+ /* Bad? - roll back and re-execute if so */
+ genRegImmCheck(cUnit, kMipsCondEq, r_V0, 0, mir->offset, pcrLabel);
+
+ /* Resume here - must reload element & array, regPtr & index preserved */
+ loadValueDirectFixed(cUnit, rlSrc, r_A0);
+ loadValueDirectFixed(cUnit, rlArray, r_A1);
+
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branchOver->generic.target = (LIR *) target;
+
+ HEAP_ACCESS_SHADOW(true);
+ storeBaseIndexed(cUnit, regPtr, regIndex, r_A0,
+ scale, kWord);
+ HEAP_ACCESS_SHADOW(false);
+
+ dvmCompilerFreeTemp(cUnit, regPtr);
+ dvmCompilerFreeTemp(cUnit, regIndex);
+
+ /* NOTE: marking card here based on object head */
+ markCard(cUnit, r_A0, r_A1);
+}
+
+static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlShift)
+{
+ /*
+ * Don't mess with the regsiters here as there is a particular calling
+ * convention to the out-of-line handler.
+ */
+ RegLocation rlResult;
+
+ loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+ loadValueDirect(cUnit, rlShift, r_A2);
+ switch( mir->dalvikInsn.opcode) {
+ case OP_SHL_LONG:
+ case OP_SHL_LONG_2ADDR:
+ genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
+ break;
+ case OP_SHR_LONG:
+ case OP_SHR_LONG_2ADDR:
+ genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
+ break;
+ case OP_USHR_LONG:
+ case OP_USHR_LONG_2ADDR:
+ genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
+ break;
+ default:
+ return true;
+ }
+ rlResult = dvmCompilerGetReturnWide(cUnit);
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ OpKind firstOp = kOpBkpt;
+ OpKind secondOp = kOpBkpt;
+ bool callOut = false;
+ void *callTgt;
+
+ switch (mir->dalvikInsn.opcode) {
+ case OP_NOT_LONG:
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
+ opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+ break;
+ case OP_ADD_LONG:
+ case OP_ADD_LONG_2ADDR:
+ firstOp = kOpAdd;
+ secondOp = kOpAdc;
+ break;
+ case OP_SUB_LONG:
+ case OP_SUB_LONG_2ADDR:
+ firstOp = kOpSub;
+ secondOp = kOpSbc;
+ break;
+ case OP_MUL_LONG:
+ case OP_MUL_LONG_2ADDR:
+ genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
+ return false;
+ case OP_DIV_LONG:
+ case OP_DIV_LONG_2ADDR:
+ callOut = true;
+ callTgt = (void*)__divdi3;
+ break;
+ case OP_REM_LONG:
+ case OP_REM_LONG_2ADDR:
+ callOut = true;
+ callTgt = (void*)__moddi3;
+ break;
+ case OP_AND_LONG_2ADDR:
+ case OP_AND_LONG:
+ firstOp = kOpAnd;
+ secondOp = kOpAnd;
+ break;
+ case OP_OR_LONG:
+ case OP_OR_LONG_2ADDR:
+ firstOp = kOpOr;
+ secondOp = kOpOr;
+ break;
+ case OP_XOR_LONG:
+ case OP_XOR_LONG_2ADDR:
+ firstOp = kOpXor;
+ secondOp = kOpXor;
+ break;
+ case OP_NEG_LONG: {
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ newLIR3(cUnit, kMipsSubu, rlResult.lowReg, r_ZERO, rlSrc2.lowReg);
+ newLIR3(cUnit, kMipsSubu, tReg, r_ZERO, rlSrc2.highReg);
+ newLIR3(cUnit, kMipsSltu, rlResult.highReg, r_ZERO, rlResult.lowReg);
+ newLIR3(cUnit, kMipsSubu, rlResult.highReg, tReg, rlResult.highReg);
+ dvmCompilerFreeTemp(cUnit, tReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+ break;
+ }
+ default:
+ ALOGE("Invalid long arith op");
+ dvmCompilerAbort(cUnit);
+ }
+ if (!callOut) {
+ genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
+ } else {
+ dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
+ loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int) callTgt);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+ rlResult = dvmCompilerGetReturnWide(cUnit);
+ storeValueWide(cUnit, rlDest, rlResult);
+#if defined(WITH_SELF_VERIFICATION)
+ cUnit->usesLinkRegister = true;
+#endif
+ }
+ return false;
+}
+
+static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ OpKind op = kOpBkpt;
+ bool checkZero = false;
+ bool unary = false;
+ RegLocation rlResult;
+ bool shiftOp = false;
+ int isDivRem = false;
+ MipsOpCode opc;
+ int divReg;
+
+ switch (mir->dalvikInsn.opcode) {
+ case OP_NEG_INT:
+ op = kOpNeg;
+ unary = true;
+ break;
+ case OP_NOT_INT:
+ op = kOpMvn;
+ unary = true;
+ break;
+ case OP_ADD_INT:
+ case OP_ADD_INT_2ADDR:
+ op = kOpAdd;
+ break;
+ case OP_SUB_INT:
+ case OP_SUB_INT_2ADDR:
+ op = kOpSub;
+ break;
+ case OP_MUL_INT:
+ case OP_MUL_INT_2ADDR:
+ op = kOpMul;
+ break;
+ case OP_DIV_INT:
+ case OP_DIV_INT_2ADDR:
+ isDivRem = true;
+ checkZero = true;
+ opc = kMipsMflo;
+ divReg = r_LO;
+ break;
+ case OP_REM_INT:
+ case OP_REM_INT_2ADDR:
+ isDivRem = true;
+ checkZero = true;
+ opc = kMipsMfhi;
+ divReg = r_HI;
+ break;
+ case OP_AND_INT:
+ case OP_AND_INT_2ADDR:
+ op = kOpAnd;
+ break;
+ case OP_OR_INT:
+ case OP_OR_INT_2ADDR:
+ op = kOpOr;
+ break;
+ case OP_XOR_INT:
+ case OP_XOR_INT_2ADDR:
+ op = kOpXor;
+ break;
+ case OP_SHL_INT:
+ case OP_SHL_INT_2ADDR:
+ shiftOp = true;
+ op = kOpLsl;
+ break;
+ case OP_SHR_INT:
+ case OP_SHR_INT_2ADDR:
+ shiftOp = true;
+ op = kOpAsr;
+ break;
+ case OP_USHR_INT:
+ case OP_USHR_INT_2ADDR:
+ shiftOp = true;
+ op = kOpLsr;
+ break;
+ default:
+ ALOGE("Invalid word arith op: %#x(%d)",
+ mir->dalvikInsn.opcode, mir->dalvikInsn.opcode);
+ dvmCompilerAbort(cUnit);
+ }
+
+ rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+ if (unary) {
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegReg(cUnit, op, rlResult.lowReg,
+ rlSrc1.lowReg);
+ } else if (isDivRem) {
+ rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+ if (checkZero) {
+ genNullCheck(cUnit, rlSrc2.sRegLow, rlSrc2.lowReg, mir->offset, NULL);
+ }
+ newLIR4(cUnit, kMipsDiv, r_HI, r_LO, rlSrc1.lowReg, rlSrc2.lowReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ newLIR2(cUnit, opc, rlResult.lowReg, divReg);
+ } else {
+ rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+ if (shiftOp) {
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegRegReg(cUnit, op, rlResult.lowReg,
+ rlSrc1.lowReg, tReg);
+ dvmCompilerFreeTemp(cUnit, tReg);
+ } else {
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegRegReg(cUnit, op, rlResult.lowReg,
+ rlSrc1.lowReg, rlSrc2.lowReg);
+ }
+ }
+ storeValue(cUnit, rlDest, rlResult);
+
+ return false;
+}
+
+static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode opcode = mir->dalvikInsn.opcode;
+ RegLocation rlDest;
+ RegLocation rlSrc1;
+ RegLocation rlSrc2;
+ /* Deduce sizes of operands */
+ if (mir->ssaRep->numUses == 2) {
+ rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
+ rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
+ } else if (mir->ssaRep->numUses == 3) {
+ rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
+ } else {
+ rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
+ assert(mir->ssaRep->numUses == 4);
+ }
+ if (mir->ssaRep->numDefs == 1) {
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ } else {
+ assert(mir->ssaRep->numDefs == 2);
+ rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ }
+
+ if ((opcode >= OP_ADD_LONG_2ADDR) && (opcode <= OP_XOR_LONG_2ADDR)) {
+ return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ }
+ if ((opcode >= OP_ADD_LONG) && (opcode <= OP_XOR_LONG)) {
+ return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ }
+ if ((opcode >= OP_SHL_LONG_2ADDR) && (opcode <= OP_USHR_LONG_2ADDR)) {
+ return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ }
+ if ((opcode >= OP_SHL_LONG) && (opcode <= OP_USHR_LONG)) {
+ return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ }
+ if ((opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_USHR_INT_2ADDR)) {
+ return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ }
+ if ((opcode >= OP_ADD_INT) && (opcode <= OP_USHR_INT)) {
+ return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ }
+ if ((opcode >= OP_ADD_FLOAT_2ADDR) && (opcode <= OP_REM_FLOAT_2ADDR)) {
+ return genArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ }
+ if ((opcode >= OP_ADD_FLOAT) && (opcode <= OP_REM_FLOAT)) {
+ return genArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+ }
+ if ((opcode >= OP_ADD_DOUBLE_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) {
+ return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ }
+ if ((opcode >= OP_ADD_DOUBLE) && (opcode <= OP_REM_DOUBLE)) {
+ return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ }
+ return true;
+}
+
+/* Generate unconditional branch instructions */
+static MipsLIR *genUnconditionalBranch(CompilationUnit *cUnit, MipsLIR *target)
+{
+ MipsLIR *branch = opNone(cUnit, kOpUncondBr);
+ branch->generic.target = (LIR *) target;
+ return branch;
+}
+
+/* Perform the actual operation for OP_RETURN_* */
+void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
+{
+ genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+ TEMPLATE_RETURN_PROF : TEMPLATE_RETURN);
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.returnOp++;
+#endif
+ int dPC = (int) (cUnit->method->insns + mir->offset);
+ /* Insert branch, but defer setting of target */
+ MipsLIR *branch = genUnconditionalBranch(cUnit, NULL);
+ /* Set up the place holder to reconstruct this Dalvik PC */
+ MipsLIR *pcrLabel = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ pcrLabel->opcode = kMipsPseudoPCReconstructionCell;
+ pcrLabel->operands[0] = dPC;
+ pcrLabel->operands[1] = mir->offset;
+ /* Insert the place holder to the growable list */
+ dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel);
+ /* Branch to the PC reconstruction code */
+ branch->generic.target = (LIR *) pcrLabel;
+}
+
+static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
+ DecodedInstruction *dInsn,
+ MipsLIR **pcrLabel)
+{
+ unsigned int i;
+ unsigned int regMask = 0;
+ RegLocation rlArg;
+ int numDone = 0;
+
+ /*
+ * Load arguments to r_A0..r_T0. Note that these registers may contain
+ * live values, so we clobber them immediately after loading to prevent
+ * them from being used as sources for subsequent loads.
+ */
+ dvmCompilerLockAllTemps(cUnit);
+ for (i = 0; i < dInsn->vA; i++) {
+ regMask |= 1 << i;
+ rlArg = dvmCompilerGetSrc(cUnit, mir, numDone++);
+ loadValueDirectFixed(cUnit, rlArg, i+r_A0); /* r_A0 thru r_T0 */
+ }
+ if (regMask) {
+ /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
+ opRegRegImm(cUnit, kOpSub, r_S4, rFP,
+ sizeof(StackSaveArea) + (dInsn->vA << 2));
+ /* generate null check */
+ if (pcrLabel) {
+ *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r_A0,
+ mir->offset, NULL);
+ }
+ storeMultiple(cUnit, r_S4, regMask);
+ }
+}
+
+static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
+ DecodedInstruction *dInsn,
+ MipsLIR **pcrLabel)
+{
+ int srcOffset = dInsn->vC << 2;
+ int numArgs = dInsn->vA;
+ int regMask;
+
+ /*
+ * Note: here, all promoted registers will have been flushed
+ * back to the Dalvik base locations, so register usage restrictins
+ * are lifted. All parms loaded from original Dalvik register
+ * region - even though some might conceivably have valid copies
+ * cached in a preserved register.
+ */
+ dvmCompilerLockAllTemps(cUnit);
+
+ /*
+ * r4PC : &rFP[vC]
+ * r_S4: &newFP[0]
+ */
+ opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
+ /* load [r_A0 up to r_A3)] */
+ regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
+ /*
+ * Protect the loadMultiple instruction from being reordered with other
+ * Dalvik stack accesses.
+ */
+ if (numArgs != 0) loadMultiple(cUnit, r4PC, regMask);
+
+ opRegRegImm(cUnit, kOpSub, r_S4, rFP,
+ sizeof(StackSaveArea) + (numArgs << 2));
+ /* generate null check */
+ if (pcrLabel) {
+ *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r_A0,
+ mir->offset, NULL);
+ }
+
+ /*
+ * Handle remaining 4n arguments:
+ * store previously loaded 4 values and load the next 4 values
+ */
+ if (numArgs >= 8) {
+ MipsLIR *loopLabel = NULL;
+ /*
+ * r_A0 contains "this" and it will be used later, so push it to the stack
+ * first. Pushing r_S1 (rFP) is just for stack alignment purposes.
+ */
+
+ newLIR2(cUnit, kMipsMove, r_T0, r_A0);
+ newLIR2(cUnit, kMipsMove, r_T1, r_S1);
+
+ /* No need to generate the loop structure if numArgs <= 11 */
+ if (numArgs > 11) {
+ loadConstant(cUnit, rFP, ((numArgs - 4) >> 2) << 2);
+ loopLabel = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ loopLabel->defMask = ENCODE_ALL;
+ }
+ storeMultiple(cUnit, r_S4, regMask);
+ /*
+ * Protect the loadMultiple instruction from being reordered with other
+ * Dalvik stack accesses.
+ */
+ loadMultiple(cUnit, r4PC, regMask);
+ /* No need to generate the loop structure if numArgs <= 11 */
+ if (numArgs > 11) {
+ opRegImm(cUnit, kOpSub, rFP, 4);
+ genConditionalBranchMips(cUnit, kMipsBne, rFP, r_ZERO, loopLabel);
+ }
+ }
+
+ /* Save the last batch of loaded values */
+ if (numArgs != 0) storeMultiple(cUnit, r_S4, regMask);
+
+ /* Generate the loop epilogue - don't use r_A0 */
+ if ((numArgs > 4) && (numArgs % 4)) {
+ regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
+ /*
+ * Protect the loadMultiple instruction from being reordered with other
+ * Dalvik stack accesses.
+ */
+ loadMultiple(cUnit, r4PC, regMask);
+ }
+ if (numArgs >= 8) {
+ newLIR2(cUnit, kMipsMove, r_A0, r_T0);
+ newLIR2(cUnit, kMipsMove, r_S1, r_T1);
+ }
+
+ /* Save the modulo 4 arguments */
+ if ((numArgs > 4) && (numArgs % 4)) {
+ storeMultiple(cUnit, r_S4, regMask);
+ }
+}
+
+/*
+ * Generate code to setup the call stack then jump to the chaining cell if it
+ * is not a native method.
+ */
+static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
+ BasicBlock *bb, MipsLIR *labelList,
+ MipsLIR *pcrLabel,
+ const Method *calleeMethod)
+{
+ /*
+ * Note: all Dalvik register state should be flushed to
+ * memory by the point, so register usage restrictions no
+ * longer apply. All temp & preserved registers may be used.
+ */
+ dvmCompilerLockAllTemps(cUnit);
+ MipsLIR *retChainingCell = &labelList[bb->fallThrough->id];
+
+ /* r_A1 = &retChainingCell */
+ dvmCompilerLockTemp(cUnit, r_A1);
+ MipsLIR *addrRetChain = newLIR2(cUnit, kMipsLahi, r_A1, 0);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+ addrRetChain = newLIR3(cUnit, kMipsLalo, r_A1, r_A1, 0);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+
+ /* r4PC = dalvikCallsite */
+ loadConstant(cUnit, r4PC,
+ (int) (cUnit->method->insns + mir->offset));
+ /*
+ * r_A0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
+ * r_A1 = &ChainingCell
+ * r4PC = callsiteDPC
+ */
+ if (dvmIsNativeMethod(calleeMethod)) {
+ genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+ TEMPLATE_INVOKE_METHOD_NATIVE_PROF :
+ TEMPLATE_INVOKE_METHOD_NATIVE);
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokeNative++;
+#endif
+ } else {
+ genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+ TEMPLATE_INVOKE_METHOD_CHAIN_PROF :
+ TEMPLATE_INVOKE_METHOD_CHAIN);
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokeMonomorphic++;
+#endif
+ /* Branch to the chaining cell */
+ genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
+ }
+ /* Handle exceptions using the interpreter */
+ genTrap(cUnit, mir->offset, pcrLabel);
+}
+
+/*
+ * Generate code to check the validity of a predicted chain and take actions
+ * based on the result.
+ *
+ * 0x2f1304c4 : lui s0,0x2d22(11554) # s0 <- dalvikPC
+ * 0x2f1304c8 : ori s0,s0,0x2d22848c(757236876)
+ * 0x2f1304cc : lahi/lui a1,0x2f13(12051) # a1 <- &retChainingCell
+ * 0x2f1304d0 : lalo/ori a1,a1,0x2f13055c(789775708)
+ * 0x2f1304d4 : lahi/lui a2,0x2f13(12051) # a2 <- &predictedChainingCell
+ * 0x2f1304d8 : lalo/ori a2,a2,0x2f13056c(789775724)
+ * 0x2f1304dc : jal 0x2f12d1ec(789762540) # call TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
+ * 0x2f1304e0 : nop
+ * 0x2f1304e4 : b 0x2f13056c (L0x11ec10) # off to the predicted chain
+ * 0x2f1304e8 : nop
+ * 0x2f1304ec : b 0x2f13054c (L0x11fc80) # punt to the interpreter
+ * 0x2f1304f0 : lui a0,0x2d22(11554)
+ * 0x2f1304f4 : lw a0,156(s4) # a0 <- this->class->vtable[methodIdx]
+ * 0x2f1304f8 : bgtz a1,0x2f13051c (L0x11fa40) # if >0 don't rechain
+ * 0x2f1304fc : nop
+ * 0x2f130500 : lui t9,0x2aba(10938)
+ * 0x2f130504 : ori t9,t9,0x2abae3f8(716891128)
+ * 0x2f130508 : move a1,s2
+ * 0x2f13050c : jalr ra,t9 # call dvmJitToPatchPredictedChain
+ * 0x2f130510 : nop
+ * 0x2f130514 : lw gp,84(sp)
+ * 0x2f130518 : move a0,v0
+ * 0x2f13051c : lahi/lui a1,0x2f13(12051) # a1 <- &retChainingCell
+ * 0x2f130520 : lalo/ori a1,a1,0x2f13055c(789775708)
+ * 0x2f130524 : jal 0x2f12d0c4(789762244) # call TEMPLATE_INVOKE_METHOD_NO_OPT
+ * 0x2f130528 : nop
+ */
+static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
+ int methodIndex,
+ MipsLIR *retChainingCell,
+ MipsLIR *predChainingCell,
+ MipsLIR *pcrLabel)
+{
+ /*
+ * Note: all Dalvik register state should be flushed to
+ * memory by the point, so register usage restrictions no
+ * longer apply. Lock temps to prevent them from being
+ * allocated by utility routines.
+ */
+ dvmCompilerLockAllTemps(cUnit);
+
+ /*
+ * For verbose printing, store the method pointer in operands[1] first as
+ * operands[0] will be clobbered in dvmCompilerMIR2LIR.
+ */
+ predChainingCell->operands[1] = (int) mir->meta.callsiteInfo->method;
+
+ /* "this" is already left in r_A0 by genProcessArgs* */
+
+ /* r4PC = dalvikCallsite */
+ loadConstant(cUnit, r4PC,
+ (int) (cUnit->method->insns + mir->offset));
+
+ /* r_A1 = &retChainingCell */
+ MipsLIR *addrRetChain = newLIR2(cUnit, kMipsLahi, r_A1, 0);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+ addrRetChain = newLIR3(cUnit, kMipsLalo, r_A1, r_A1, 0);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+
+ /* r_A2 = &predictedChainingCell */
+ MipsLIR *predictedChainingCell = newLIR2(cUnit, kMipsLahi, r_A2, 0);
+ predictedChainingCell->generic.target = (LIR *) predChainingCell;
+ predictedChainingCell = newLIR3(cUnit, kMipsLalo, r_A2, r_A2, 0);
+ predictedChainingCell->generic.target = (LIR *) predChainingCell;
+
+ genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF :
+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
+
+ /* return through ra - jump to the chaining cell */
+ genUnconditionalBranch(cUnit, predChainingCell);
+
+ /*
+ * null-check on "this" may have been eliminated, but we still need a PC-
+ * reconstruction label for stack overflow bailout.
+ */
+ if (pcrLabel == NULL) {
+ int dPC = (int) (cUnit->method->insns + mir->offset);
+ pcrLabel = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ pcrLabel->opcode = kMipsPseudoPCReconstructionCell;
+ pcrLabel->operands[0] = dPC;
+ pcrLabel->operands[1] = mir->offset;
+ /* Insert the place holder to the growable list */
+ dvmInsertGrowableList(&cUnit->pcReconstructionList,
+ (intptr_t) pcrLabel);
+ }
+
+ /* return through ra+8 - punt to the interpreter */
+ genUnconditionalBranch(cUnit, pcrLabel);
+
+ /*
+ * return through ra+16 - fully resolve the callee method.
+ * r_A1 <- count
+ * r_A2 <- &predictedChainCell
+ * r_A3 <- this->class
+ * r4 <- dPC
+ * r_S4 <- this->class->vtable
+ */
+
+ /* r_A0 <- calleeMethod */
+ loadWordDisp(cUnit, r_S4, methodIndex * 4, r_A0);
+
+ /* Check if rechain limit is reached */
+ MipsLIR *bypassRechaining = opCompareBranch(cUnit, kMipsBgtz, r_A1, -1);
+
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int) dvmJitToPatchPredictedChain);
+
+ genRegCopy(cUnit, r_A1, rSELF);
+
+ /*
+ * r_A0 = calleeMethod
+ * r_A2 = &predictedChainingCell
+ * r_A3 = class
+ *
+ * &returnChainingCell has been loaded into r_A1 but is not needed
+ * when patching the chaining cell and will be clobbered upon
+ * returning so it will be reconstructed again.
+ */
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ newLIR2(cUnit, kMipsMove, r_A0, r_V0);
+
+ /* r_A1 = &retChainingCell */
+ addrRetChain = newLIR2(cUnit, kMipsLahi, r_A1, 0);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+ bypassRechaining->generic.target = (LIR *) addrRetChain;
+ addrRetChain = newLIR3(cUnit, kMipsLalo, r_A1, r_A1, 0);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+
+ /*
+ * r_A0 = calleeMethod,
+ * r_A1 = &ChainingCell,
+ * r4PC = callsiteDPC,
+ */
+ genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+ TEMPLATE_INVOKE_METHOD_NO_OPT_PROF :
+ TEMPLATE_INVOKE_METHOD_NO_OPT);
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokePolymorphic++;
+#endif
+ /* Handle exceptions using the interpreter */
+ genTrap(cUnit, mir->offset, pcrLabel);
+}
+
+/* "this" pointer is already in r0 */
+static void genInvokeVirtualWholeMethod(CompilationUnit *cUnit,
+ MIR *mir,
+ void *calleeAddr,
+ MipsLIR *retChainingCell)
+{
+ CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
+ dvmCompilerLockAllTemps(cUnit);
+
+ loadClassPointer(cUnit, r_A1, (int) callsiteInfo);
+
+ loadWordDisp(cUnit, r_A0, offsetof(Object, clazz), r_A2);
+ /*
+ * Set the misPredBranchOver target so that it will be generated when the
+ * code for the non-optimized invoke is generated.
+ */
+ /* Branch to the slow path if classes are not equal */
+ MipsLIR *classCheck = opCompareBranch(cUnit, kMipsBne, r_A1, r_A2);
+
+ /* a0 = the Dalvik PC of the callsite */
+ loadConstant(cUnit, r_A0, (int) (cUnit->method->insns + mir->offset));
+
+ newLIR1(cUnit, kMipsJal, (int) calleeAddr);
+ genUnconditionalBranch(cUnit, retChainingCell);
+
+ /* Target of slow path */
+ MipsLIR *slowPathLabel = newLIR0(cUnit, kMipsPseudoTargetLabel);
+
+ slowPathLabel->defMask = ENCODE_ALL;
+ classCheck->generic.target = (LIR *) slowPathLabel;
+
+ // FIXME
+ cUnit->printMe = true;
+}
+
+static void genInvokeSingletonWholeMethod(CompilationUnit *cUnit,
+ MIR *mir,
+ void *calleeAddr,
+ MipsLIR *retChainingCell)
+{
+ /* a0 = the Dalvik PC of the callsite */
+ loadConstant(cUnit, r_A0, (int) (cUnit->method->insns + mir->offset));
+
+ newLIR1(cUnit, kMipsJal, (int) calleeAddr);
+ genUnconditionalBranch(cUnit, retChainingCell);
+
+ // FIXME
+ cUnit->printMe = true;
+}
+
+/* Geneate a branch to go back to the interpreter */
+static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
+{
+ /* a0 = dalvik pc */
+ dvmCompilerFlushAllRegs(cUnit);
+ loadConstant(cUnit, r_A0, (int) (cUnit->method->insns + offset));
+#if 0 /* MIPSTODO tempoary workaround unaligned access on sigma hardware
+ this can removed when we're not punting to genInterpSingleStep
+ for opcodes that haven't been activated yet */
+ loadWordDisp(cUnit, r_A0, offsetof(Object, clazz), r_A3);
+#endif
+ loadWordDisp(cUnit, rSELF, offsetof(Thread,
+ jitToInterpEntries.dvmJitToInterpPunt), r_A1);
+
+ opReg(cUnit, kOpBlx, r_A1);
+}
+
+/*
+ * Attempt to single step one instruction using the interpreter and return
+ * to the compiled code for the next Dalvik instruction
+ */
+static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
+{
+ int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode);
+ int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn;
+
+ // Single stepping is considered loop mode breaker
+ if (cUnit->jitMode == kJitLoop) {
+ cUnit->quitLoopMode = true;
+ return;
+ }
+
+ //If already optimized out, just ignore
+ if (mir->dalvikInsn.opcode == OP_NOP)
+ return;
+
+ //Ugly, but necessary. Flush all Dalvik regs so Interp can find them
+ dvmCompilerFlushAllRegs(cUnit);
+
+ if ((mir->next == NULL) || (flags & flagsToCheck)) {
+ genPuntToInterp(cUnit, mir->offset);
+ return;
+ }
+ int entryAddr = offsetof(Thread,
+ jitToInterpEntries.dvmJitToInterpSingleStep);
+ loadWordDisp(cUnit, rSELF, entryAddr, r_A2);
+ /* a0 = dalvik pc */
+ loadConstant(cUnit, r_A0, (int) (cUnit->method->insns + mir->offset));
+ /* a1 = dalvik pc of following instruction */
+ loadConstant(cUnit, r_A1, (int) (cUnit->method->insns + mir->next->offset));
+ opReg(cUnit, kOpBlx, r_A2);
+}
+
+/*
+ * To prevent a thread in a monitor wait from blocking the Jit from
+ * resetting the code cache, heavyweight monitor lock will not
+ * be allowed to return to an existing translation. Instead, we will
+ * handle them by branching to a handler, which will in turn call the
+ * runtime lock routine and then branch directly back to the
+ * interpreter main loop. Given the high cost of the heavyweight
+ * lock operation, this additional cost should be slight (especially when
+ * considering that we expect the vast majority of lock operations to
+ * use the fast-path thin lock bypass).
+ */
+static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir)
+{
+ bool isEnter = (mir->dalvikInsn.opcode == OP_MONITOR_ENTER);
+ genExportPC(cUnit, mir);
+ dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ loadValueDirectFixed(cUnit, rlSrc, r_A1);
+ genRegCopy(cUnit, r_A0, rSELF);
+ genNullCheck(cUnit, rlSrc.sRegLow, r_A1, mir->offset, NULL);
+ if (isEnter) {
+ /* Get dPC of next insn */
+ loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset +
+ dexGetWidthFromOpcode(OP_MONITOR_ENTER)));
+ genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER);
+ } else {
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmUnlockObject);
+ /* Do the call */
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ /* Did we throw? */
+ MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
+ loadConstant(cUnit, r_A0,
+ (int) (cUnit->method->insns + mir->offset +
+ dexGetWidthFromOpcode(OP_MONITOR_EXIT)));
+ genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branchOver->generic.target = (LIR *) target;
+ dvmCompilerClobberCallRegs(cUnit);
+ }
+}
+/*#endif*/
+
+/*
+ * Fetch *self->info.breakFlags. If the breakFlags are non-zero,
+ * punt to the interpreter.
+ */
+static void genSuspendPoll(CompilationUnit *cUnit, MIR *mir)
+{
+ int rTemp = dvmCompilerAllocTemp(cUnit);
+ MipsLIR *ld;
+ ld = loadBaseDisp(cUnit, NULL, rSELF,
+ offsetof(Thread, interpBreak.ctl.breakFlags),
+ rTemp, kUnsignedByte, INVALID_SREG);
+ setMemRefType(ld, true /* isLoad */, kMustNotAlias);
+ genRegImmCheck(cUnit, kMipsCondNe, rTemp, 0, mir->offset, NULL);
+}
+
+/*
+ * The following are the first-level codegen routines that analyze the format
+ * of each bytecode then either dispatch special purpose codegen routines
+ * or produce corresponding Thumb instructions directly.
+ */
+
+static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
+ BasicBlock *bb, MipsLIR *labelList)
+{
+ /* backward branch? */
+ bool backwardBranch = (bb->taken->startOffset <= mir->offset);
+
+ if (backwardBranch &&
+ (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
+ genSuspendPoll(cUnit, mir);
+ }
+
+ int numPredecessors = dvmCountSetBits(bb->taken->predecessors);
+ /*
+ * Things could be hoisted out of the taken block into the predecessor, so
+ * make sure it is dominated by the predecessor.
+ */
+ if (numPredecessors == 1 && bb->taken->visited == false &&
+ bb->taken->blockType == kDalvikByteCode) {
+ cUnit->nextCodegenBlock = bb->taken;
+ } else {
+ /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
+ genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
+ }
+ return false;
+}
+
+static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ if ((dalvikOpcode >= OP_UNUSED_3E) && (dalvikOpcode <= OP_UNUSED_43)) {
+ ALOGE("Codegen: got unused opcode %#x",dalvikOpcode);
+ return true;
+ }
+ switch (dalvikOpcode) {
+ case OP_RETURN_VOID_BARRIER:
+ dvmCompilerGenMemBarrier(cUnit, 0);
+ // Intentional fallthrough
+ case OP_RETURN_VOID:
+ genReturnCommon(cUnit,mir);
+ break;
+ case OP_UNUSED_73:
+ case OP_UNUSED_79:
+ case OP_UNUSED_7A:
+ case OP_UNUSED_FF:
+ ALOGE("Codegen: got unused opcode %#x",dalvikOpcode);
+ return true;
+ case OP_NOP:
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlDest;
+ RegLocation rlResult;
+ if (mir->ssaRep->numDefs == 2) {
+ rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ } else {
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ }
+
+ switch (mir->dalvikInsn.opcode) {
+ case OP_CONST:
+ case OP_CONST_4: {
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+ loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ }
+ case OP_CONST_WIDE_32: {
+ //TUNING: single routine to load constant pair for support doubles
+ //TUNING: load 0/-1 separately to avoid load dependency
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
+ opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
+ rlResult.lowReg, 31);
+ storeValueWide(cUnit, rlDest, rlResult);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlDest;
+ RegLocation rlResult;
+ if (mir->ssaRep->numDefs == 2) {
+ rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ } else {
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ }
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+
+ switch (mir->dalvikInsn.opcode) {
+ case OP_CONST_HIGH16: {
+ loadConstantNoClobber(cUnit, rlResult.lowReg,
+ mir->dalvikInsn.vB << 16);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ }
+ case OP_CONST_WIDE_HIGH16: {
+ loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
+ 0, mir->dalvikInsn.vB << 16);
+ storeValueWide(cUnit, rlDest, rlResult);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
+{
+ /* For OP_THROW_VERIFICATION_ERROR */
+ genInterpSingleStep(cUnit, mir);
+ return false;
+}
+
+static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlResult;
+ RegLocation rlDest;
+ RegLocation rlSrc;
+
+ switch (mir->dalvikInsn.opcode) {
+ case OP_CONST_STRING_JUMBO:
+ case OP_CONST_STRING: {
+ void *strPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
+
+ if (strPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ ALOGE("Unexpected null string");
+ dvmAbort();
+ }
+
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr );
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ }
+ case OP_CONST_CLASS: {
+ void *classPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
+
+ if (classPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ ALOGE("Unexpected null class");
+ dvmAbort();
+ }
+
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr );
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ }
+ case OP_SGET:
+ case OP_SGET_VOLATILE:
+ case OP_SGET_OBJECT:
+ case OP_SGET_OBJECT_VOLATILE:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_CHAR:
+ case OP_SGET_BYTE:
+ case OP_SGET_SHORT: {
+ int valOffset = OFFSETOF_MEMBER(StaticField, value);
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ bool isVolatile;
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
+ void *fieldPtr = (void*)
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+ if (fieldPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ ALOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
+ /*
+ * On SMP systems, Dalvik opcodes found to be referencing
+ * volatile fields are rewritten to their _VOLATILE variant.
+ * However, this does not happen on non-SMP systems. The JIT
+ * still needs to know about volatility to avoid unsafe
+ * optimizations so we determine volatility based on either
+ * the opcode or the field access flags.
+ */
+#if ANDROID_SMP != 0
+ Opcode opcode = mir->dalvikInsn.opcode;
+ isVolatile = (opcode == OP_SGET_VOLATILE) ||
+ (opcode == OP_SGET_OBJECT_VOLATILE);
+ assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
+#else
+ isVolatile = dvmIsVolatileField((Field *) fieldPtr);
+#endif
+
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+ loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
+
+ if (isVolatile) {
+ dvmCompilerGenMemBarrier(cUnit, 0);
+ }
+ HEAP_ACCESS_SHADOW(true);
+ loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
+ HEAP_ACCESS_SHADOW(false);
+
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ }
+ case OP_SGET_WIDE: {
+ int valOffset = OFFSETOF_MEMBER(StaticField, value);
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
+ void *fieldPtr = (void*)
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+ if (fieldPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ ALOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+ loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
+
+ HEAP_ACCESS_SHADOW(true);
+ loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
+ HEAP_ACCESS_SHADOW(false);
+
+ storeValueWide(cUnit, rlDest, rlResult);
+ break;
+ }
+ case OP_SPUT:
+ case OP_SPUT_VOLATILE:
+ case OP_SPUT_OBJECT:
+ case OP_SPUT_OBJECT_VOLATILE:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_SHORT: {
+ int valOffset = OFFSETOF_MEMBER(StaticField, value);
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ int objHead = 0;
+ bool isVolatile;
+ bool isSputObject;
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
+ void *fieldPtr = (void*)
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+ Opcode opcode = mir->dalvikInsn.opcode;
+
+ if (fieldPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ ALOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
+#if ANDROID_SMP != 0
+ isVolatile = (opcode == OP_SPUT_VOLATILE) ||
+ (opcode == OP_SPUT_OBJECT_VOLATILE);
+ assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
+#else
+ isVolatile = dvmIsVolatileField((Field *) fieldPtr);
+#endif
+
+ isSputObject = (opcode == OP_SPUT_OBJECT) ||
+ (opcode == OP_SPUT_OBJECT_VOLATILE);
+
+ rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+ loadConstant(cUnit, tReg, (int) fieldPtr);
+ if (isSputObject) {
+ objHead = dvmCompilerAllocTemp(cUnit);
+ loadWordDisp(cUnit, tReg, OFFSETOF_MEMBER(Field, clazz), objHead);
+ }
+ if (isVolatile) {
+ dvmCompilerGenMemBarrier(cUnit, 0);
+ }
+ HEAP_ACCESS_SHADOW(true);
+ storeWordDisp(cUnit, tReg, valOffset ,rlSrc.lowReg);
+ dvmCompilerFreeTemp(cUnit, tReg);
+ HEAP_ACCESS_SHADOW(false);
+ if (isVolatile) {
+ dvmCompilerGenMemBarrier(cUnit, 0);
+ }
+ if (isSputObject) {
+ /* NOTE: marking card based sfield->clazz */
+ markCard(cUnit, rlSrc.lowReg, objHead);
+ dvmCompilerFreeTemp(cUnit, objHead);
+ }
+
+ break;
+ }
+ case OP_SPUT_WIDE: {
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ int valOffset = OFFSETOF_MEMBER(StaticField, value);
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
+ void *fieldPtr = (void*)
+ (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+ if (fieldPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ ALOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
+ rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+ loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
+
+ HEAP_ACCESS_SHADOW(true);
+ storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
+ HEAP_ACCESS_SHADOW(false);
+ break;
+ }
+ case OP_NEW_INSTANCE: {
+ /*
+ * Obey the calling convention and don't mess with the register
+ * usage.
+ */
+ ClassObject *classPtr = (ClassObject *)
+ (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
+
+ if (classPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ ALOGE("Unexpected null class");
+ dvmAbort();
+ }
+
+ /*
+ * If it is going to throw, it should not make to the trace to begin
+ * with. However, Alloc might throw, so we need to genExportPC()
+ */
+ assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
+ dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
+ genExportPC(cUnit, mir);
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmAllocObject);
+ loadConstant(cUnit, r_A0, (int) classPtr);
+ loadConstant(cUnit, r_A1, ALLOC_DONT_TRACK);
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+ /* generate a branch over if allocation is successful */
+ MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
+
+ /*
+ * OOM exception needs to be thrown here and cannot re-execute
+ */
+ loadConstant(cUnit, r_A0,
+ (int) (cUnit->method->insns + mir->offset));
+ genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+ /* noreturn */
+
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branchOver->generic.target = (LIR *) target;
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ rlResult = dvmCompilerGetReturn(cUnit);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ }
+ case OP_CHECK_CAST: {
+ /*
+ * Obey the calling convention and don't mess with the register
+ * usage.
+ */
+ ClassObject *classPtr =
+ (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
+ /*
+ * Note: It is possible that classPtr is NULL at this point,
+ * even though this instruction has been successfully interpreted.
+ * If the previous interpretation had a null source, the
+ * interpreter would not have bothered to resolve the clazz.
+ * Bail out to the interpreter in this case, and log it
+ * so that we can tell if it happens frequently.
+ */
+ if (classPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ LOGVV("null clazz in OP_CHECK_CAST, single-stepping");
+ genInterpSingleStep(cUnit, mir);
+ return false;
+ }
+ dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
+ loadConstant(cUnit, r_A1, (int) classPtr );
+ rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ MipsLIR *branch1 = opCompareBranch(cUnit, kMipsBeqz, rlSrc.lowReg, -1);
+ /*
+ * rlSrc.lowReg now contains object->clazz. Note that
+ * it could have been allocated r_A0, but we're okay so long
+ * as we don't do anything desctructive until r_A0 is loaded
+ * with clazz.
+ */
+ /* r_A0 now contains object->clazz */
+ loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r_A0);
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmInstanceofNonTrivial);
+ MipsLIR *branch2 = opCompareBranch(cUnit, kMipsBeq, r_A0, r_A1);
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+ /*
+ * If null, check cast failed - punt to the interpreter. Because
+ * interpreter will be the one throwing, we don't need to
+ * genExportPC() here.
+ */
+ genRegCopy(cUnit, r_A0, r_V0);
+ genZeroCheck(cUnit, r_V0, mir->offset, NULL);
+ /* check cast passed - branch target here */
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branch1->generic.target = (LIR *)target;
+ branch2->generic.target = (LIR *)target;
+ break;
+ }
+ case OP_SGET_WIDE_VOLATILE:
+ case OP_SPUT_WIDE_VOLATILE:
+ genInterpSingleStep(cUnit, mir);
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ RegLocation rlResult;
+ switch (dalvikOpcode) {
+ case OP_MOVE_EXCEPTION: {
+ int exOffset = offsetof(Thread, exception);
+ int resetReg = dvmCompilerAllocTemp(cUnit);
+ RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
+ loadConstant(cUnit, resetReg, 0);
+ storeWordDisp(cUnit, rSELF, exOffset, resetReg);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ }
+ case OP_MOVE_RESULT:
+ case OP_MOVE_RESULT_OBJECT: {
+ /* An inlined move result is effectively no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ break;
+ RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
+ rlSrc.fp = rlDest.fp;
+ storeValue(cUnit, rlDest, rlSrc);
+ break;
+ }
+ case OP_MOVE_RESULT_WIDE: {
+ /* An inlined move result is effectively no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ break;
+ RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
+ rlSrc.fp = rlDest.fp;
+ storeValueWide(cUnit, rlDest, rlSrc);
+ break;
+ }
+ case OP_RETURN_WIDE: {
+ RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
+ rlDest.fp = rlSrc.fp;
+ storeValueWide(cUnit, rlDest, rlSrc);
+ genReturnCommon(cUnit,mir);
+ break;
+ }
+ case OP_RETURN:
+ case OP_RETURN_OBJECT: {
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
+ rlDest.fp = rlSrc.fp;
+ storeValue(cUnit, rlDest, rlSrc);
+ genReturnCommon(cUnit, mir);
+ break;
+ }
+ case OP_MONITOR_EXIT:
+ case OP_MONITOR_ENTER:
+ genMonitor(cUnit, mir);
+ break;
+ case OP_THROW:
+ genInterpSingleStep(cUnit, mir);
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode opcode = mir->dalvikInsn.opcode;
+ RegLocation rlDest;
+ RegLocation rlSrc;
+ RegLocation rlResult;
+
+ if ( (opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) {
+ return genArithOp( cUnit, mir );
+ }
+
+ if (mir->ssaRep->numUses == 2)
+ rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ else
+ rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ if (mir->ssaRep->numDefs == 2)
+ rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ else
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+
+ switch (opcode) {
+ case OP_DOUBLE_TO_INT:
+ case OP_INT_TO_FLOAT:
+ case OP_FLOAT_TO_INT:
+ case OP_DOUBLE_TO_FLOAT:
+ case OP_FLOAT_TO_DOUBLE:
+ case OP_INT_TO_DOUBLE:
+ case OP_FLOAT_TO_LONG:
+ case OP_LONG_TO_FLOAT:
+ case OP_DOUBLE_TO_LONG:
+ case OP_LONG_TO_DOUBLE:
+ return genConversion(cUnit, mir);
+ case OP_NEG_INT:
+ case OP_NOT_INT:
+ return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
+ case OP_NEG_LONG:
+ case OP_NOT_LONG:
+ return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
+ case OP_NEG_FLOAT:
+ return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
+ case OP_NEG_DOUBLE:
+ return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
+ case OP_MOVE_WIDE:
+ storeValueWide(cUnit, rlDest, rlSrc);
+ break;
+ case OP_INT_TO_LONG:
+ rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ //TUNING: shouldn't loadValueDirect already check for phys reg?
+ if (rlSrc.location == kLocPhysReg) {
+ genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+ } else {
+ loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
+ }
+ opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
+ rlResult.lowReg, 31);
+ storeValueWide(cUnit, rlDest, rlResult);
+ break;
+ case OP_LONG_TO_INT:
+ rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
+ rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc);
+ // Intentional fallthrough
+ case OP_MOVE:
+ case OP_MOVE_OBJECT:
+ storeValue(cUnit, rlDest, rlSrc);
+ break;
+ case OP_INT_TO_BYTE:
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ case OP_INT_TO_SHORT:
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ case OP_INT_TO_CHAR:
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ case OP_ARRAY_LENGTH: {
+ int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
+ mir->offset, NULL);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
+ rlResult.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ RegLocation rlDest;
+ RegLocation rlResult;
+ int BBBB = mir->dalvikInsn.vB;
+ if (dalvikOpcode == OP_CONST_WIDE_16) {
+ rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
+ //TUNING: do high separately to avoid load dependency
+ opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else if (dalvikOpcode == OP_CONST_16) {
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+ loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
+ storeValue(cUnit, rlDest, rlResult);
+ } else
+ return true;
+ return false;
+}
+
+/* Compare agaist zero */
+static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+ MipsLIR *labelList)
+{
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ MipsOpCode opc = kMipsNop;
+ int rt = -1;
+ /* backward branch? */
+ bool backwardBranch = (bb->taken->startOffset <= mir->offset);
+
+ if (backwardBranch &&
+ (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
+ genSuspendPoll(cUnit, mir);
+ }
+
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+
+ switch (dalvikOpcode) {
+ case OP_IF_EQZ:
+ opc = kMipsBeqz;
+ break;
+ case OP_IF_NEZ:
+ opc = kMipsBne;
+ rt = r_ZERO;
+ break;
+ case OP_IF_LTZ:
+ opc = kMipsBltz;
+ break;
+ case OP_IF_GEZ:
+ opc = kMipsBgez;
+ break;
+ case OP_IF_GTZ:
+ opc = kMipsBgtz;
+ break;
+ case OP_IF_LEZ:
+ opc = kMipsBlez;
+ break;
+ default:
+ ALOGE("Unexpected opcode (%d) for Fmt21t", dalvikOpcode);
+ dvmCompilerAbort(cUnit);
+ }
+ genConditionalBranchMips(cUnit, opc, rlSrc.lowReg, rt, &labelList[bb->taken->id]);
+ /* This mostly likely will be optimized away in a later phase */
+ genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+ return false;
+}
+
+static bool isPowerOfTwo(int x)
+{
+ return (x & (x - 1)) == 0;
+}
+
+// Returns true if no more than two bits are set in 'x'.
+static bool isPopCountLE2(unsigned int x)
+{
+ x &= x - 1;
+ return (x & (x - 1)) == 0;
+}
+
+// Returns the index of the lowest set bit in 'x'.
+static int lowestSetBit(unsigned int x) {
+ int bit_posn = 0;
+ while ((x & 0xf) == 0) {
+ bit_posn += 4;
+ x >>= 4;
+ }
+ while ((x & 1) == 0) {
+ bit_posn++;
+ x >>= 1;
+ }
+ return bit_posn;
+}
+
+// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
+// and store the result in 'rlDest'.
+static bool handleEasyDivide(CompilationUnit *cUnit, Opcode dalvikOpcode,
+ RegLocation rlSrc, RegLocation rlDest, int lit)
+{
+ if (lit < 2 || !isPowerOfTwo(lit)) {
+ return false;
+ }
+ int k = lowestSetBit(lit);
+ if (k >= 30) {
+ // Avoid special cases.
+ return false;
+ }
+ bool div = (dalvikOpcode == OP_DIV_INT_LIT8 || dalvikOpcode == OP_DIV_INT_LIT16);
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ if (div) {
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ if (lit == 2) {
+ // Division by 2 is by far the most common division by constant.
+ opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
+ opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
+ } else {
+ opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
+ opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
+ opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
+ }
+ } else {
+ int cReg = dvmCompilerAllocTemp(cUnit);
+ loadConstant(cUnit, cReg, lit - 1);
+ int tReg1 = dvmCompilerAllocTemp(cUnit);
+ int tReg2 = dvmCompilerAllocTemp(cUnit);
+ if (lit == 2) {
+ opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
+ opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
+ opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
+ } else {
+ opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
+ opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
+ opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
+ opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
+ }
+ }
+ storeValue(cUnit, rlDest, rlResult);
+ return true;
+}
+
+// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
+// and store the result in 'rlDest'.
+static bool handleEasyMultiply(CompilationUnit *cUnit,
+ RegLocation rlSrc, RegLocation rlDest, int lit)
+{
+ // Can we simplify this multiplication?
+ bool powerOfTwo = false;
+ bool popCountLE2 = false;
+ bool powerOfTwoMinusOne = false;
+ if (lit < 2) {
+ // Avoid special cases.
+ return false;
+ } else if (isPowerOfTwo(lit)) {
+ powerOfTwo = true;
+ } else if (isPopCountLE2(lit)) {
+ popCountLE2 = true;
+ } else if (isPowerOfTwo(lit + 1)) {
+ powerOfTwoMinusOne = true;
+ } else {
+ return false;
+ }
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ if (powerOfTwo) {
+ // Shift.
+ opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
+ lowestSetBit(lit));
+ } else if (popCountLE2) {
+ // Shift and add and shift.
+ int firstBit = lowestSetBit(lit);
+ int secondBit = lowestSetBit(lit ^ (1 << firstBit));
+ genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
+ firstBit, secondBit);
+ } else {
+ // Reverse subtract: (src << (shift + 1)) - src.
+ assert(powerOfTwoMinusOne);
+ // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1)
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
+ opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
+ }
+ storeValue(cUnit, rlDest, rlResult);
+ return true;
+}
+
+static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ RegLocation rlResult;
+ int lit = mir->dalvikInsn.vC;
+ OpKind op = (OpKind)0; /* Make gcc happy */
+ int shiftOp = false;
+
+ switch (dalvikOpcode) {
+ case OP_RSUB_INT_LIT8:
+ case OP_RSUB_INT: {
+ int tReg;
+ //TUNING: add support for use of Arm rsub op
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ tReg = dvmCompilerAllocTemp(cUnit);
+ loadConstant(cUnit, tReg, lit);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
+ tReg, rlSrc.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+ break;
+ }
+
+ case OP_ADD_INT_LIT8:
+ case OP_ADD_INT_LIT16:
+ op = kOpAdd;
+ break;
+ case OP_MUL_INT_LIT8:
+ case OP_MUL_INT_LIT16: {
+ if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
+ return false;
+ }
+ op = kOpMul;
+ break;
+ }
+ case OP_AND_INT_LIT8:
+ case OP_AND_INT_LIT16:
+ op = kOpAnd;
+ break;
+ case OP_OR_INT_LIT8:
+ case OP_OR_INT_LIT16:
+ op = kOpOr;
+ break;
+ case OP_XOR_INT_LIT8:
+ case OP_XOR_INT_LIT16:
+ op = kOpXor;
+ break;
+ case OP_SHL_INT_LIT8:
+ lit &= 31;
+ shiftOp = true;
+ op = kOpLsl;
+ break;
+ case OP_SHR_INT_LIT8:
+ lit &= 31;
+ shiftOp = true;
+ op = kOpAsr;
+ break;
+ case OP_USHR_INT_LIT8:
+ lit &= 31;
+ shiftOp = true;
+ op = kOpLsr;
+ break;
+
+ case OP_DIV_INT_LIT8:
+ case OP_DIV_INT_LIT16:
+ case OP_REM_INT_LIT8:
+ case OP_REM_INT_LIT16: {
+ if (lit == 0) {
+ /* Let the interpreter deal with div by 0 */
+ genInterpSingleStep(cUnit, mir);
+ return false;
+ }
+ if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
+ return false;
+ }
+
+ MipsOpCode opc;
+ int divReg;
+
+ if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
+ (dalvikOpcode == OP_DIV_INT_LIT16)) {
+ opc = kMipsMflo;
+ divReg = r_LO;
+ } else {
+ opc = kMipsMfhi;
+ divReg = r_HI;
+ }
+
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ newLIR3(cUnit, kMipsAddiu, tReg, r_ZERO, lit);
+ newLIR4(cUnit, kMipsDiv, r_HI, r_LO, rlSrc.lowReg, tReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ newLIR2(cUnit, opc, rlResult.lowReg, divReg);
+ dvmCompilerFreeTemp(cUnit, tReg);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+ break;
+ }
+ default:
+ return true;
+ }
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ // Avoid shifts by literal 0 - no support in Thumb. Change to copy
+ if (shiftOp && (lit == 0)) {
+ genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+ } else {
+ opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
+ }
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ int fieldOffset = -1;
+ bool isVolatile = false;
+ switch (dalvikOpcode) {
+ /*
+ * Wide volatiles currently handled via single step.
+ * Add them here if generating in-line code.
+ * case OP_IGET_WIDE_VOLATILE:
+ * case OP_IPUT_WIDE_VOLATILE:
+ */
+ case OP_IGET_VOLATILE:
+ case OP_IGET_OBJECT_VOLATILE:
+ case OP_IPUT_VOLATILE:
+ case OP_IPUT_OBJECT_VOLATILE:
+#if ANDROID_SMP != 0
+ isVolatile = true;
+ // NOTE: intentional fallthrough
+#endif
+ case OP_IGET:
+ case OP_IGET_WIDE:
+ case OP_IGET_OBJECT:
+ case OP_IGET_BOOLEAN:
+ case OP_IGET_BYTE:
+ case OP_IGET_CHAR:
+ case OP_IGET_SHORT:
+ case OP_IPUT:
+ case OP_IPUT_WIDE:
+ case OP_IPUT_OBJECT:
+ case OP_IPUT_BOOLEAN:
+ case OP_IPUT_BYTE:
+ case OP_IPUT_CHAR:
+ case OP_IPUT_SHORT: {
+ const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+ mir->meta.calleeMethod : cUnit->method;
+ Field *fieldPtr =
+ method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
+
+ if (fieldPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ ALOGE("Unexpected null instance field");
+ dvmAbort();
+ }
+#if ANDROID_SMP != 0
+ assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
+#else
+ isVolatile = dvmIsVolatileField((Field *) fieldPtr);
+#endif
+ fieldOffset = ((InstField *)fieldPtr)->byteOffset;
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch (dalvikOpcode) {
+ case OP_NEW_ARRAY: {
+#if 0 /* 080 triggers assert in Interp.c:1290 for out of memory exception.
+ i think the assert is in error and should be disabled. With
+ asserts disabled, 080 passes. */
+genInterpSingleStep(cUnit, mir);
+return false;
+#endif
+ // Generates a call - use explicit registers
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ RegLocation rlResult;
+ void *classPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
+
+ if (classPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ ALOGE("Unexpected null class");
+ dvmAbort();
+ }
+
+ dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
+ genExportPC(cUnit, mir);
+ loadValueDirectFixed(cUnit, rlSrc, r_A1); /* Len */
+ loadConstant(cUnit, r_A0, (int) classPtr );
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmAllocArrayByClass);
+ /*
+ * "len < 0": bail to the interpreter to re-execute the
+ * instruction
+ */
+ genRegImmCheck(cUnit, kMipsCondMi, r_A1, 0, mir->offset, NULL);
+ loadConstant(cUnit, r_A2, ALLOC_DONT_TRACK);
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+ /* generate a branch over if allocation is successful */
+ MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
+ /*
+ * OOM exception needs to be thrown here and cannot re-execute
+ */
+ loadConstant(cUnit, r_A0,
+ (int) (cUnit->method->insns + mir->offset));
+ genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+ /* noreturn */
+
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branchOver->generic.target = (LIR *) target;
+ rlResult = dvmCompilerGetReturn(cUnit);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ }
+ case OP_INSTANCE_OF: {
+ // May generate a call - use explicit registers
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ RegLocation rlResult;
+ ClassObject *classPtr =
+ (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
+ /*
+ * Note: It is possible that classPtr is NULL at this point,
+ * even though this instruction has been successfully interpreted.
+ * If the previous interpretation had a null source, the
+ * interpreter would not have bothered to resolve the clazz.
+ * Bail out to the interpreter in this case, and log it
+ * so that we can tell if it happens frequently.
+ */
+ if (classPtr == NULL) {
+ BAIL_LOOP_COMPILATION();
+ ALOGD("null clazz in OP_INSTANCE_OF, single-stepping");
+ genInterpSingleStep(cUnit, mir);
+ break;
+ }
+ dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
+ loadValueDirectFixed(cUnit, rlSrc, r_V0); /* Ref */
+ loadConstant(cUnit, r_A2, (int) classPtr );
+ /* When taken r_V0 has NULL which can be used for store directly */
+ MipsLIR *branch1 = opCompareBranch(cUnit, kMipsBeqz, r_V0, -1);
+ /* r_A1 now contains object->clazz */
+ loadWordDisp(cUnit, r_V0, offsetof(Object, clazz), r_A1);
+ /* r_A1 now contains object->clazz */
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmInstanceofNonTrivial);
+ loadConstant(cUnit, r_V0, 1); /* Assume true */
+ MipsLIR *branch2 = opCompareBranch(cUnit, kMipsBeq, r_A1, r_A2);
+ genRegCopy(cUnit, r_A0, r_A1);
+ genRegCopy(cUnit, r_A1, r_A2);
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+ /* branch target here */
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ rlResult = dvmCompilerGetReturn(cUnit);
+ storeValue(cUnit, rlDest, rlResult);
+ branch1->generic.target = (LIR *)target;
+ branch2->generic.target = (LIR *)target;
+ break;
+ }
+ case OP_IGET_WIDE:
+ genIGetWide(cUnit, mir, fieldOffset);
+ break;
+ case OP_IGET_VOLATILE:
+ case OP_IGET_OBJECT_VOLATILE:
+ case OP_IGET:
+ case OP_IGET_OBJECT:
+ case OP_IGET_BOOLEAN:
+ case OP_IGET_BYTE:
+ case OP_IGET_CHAR:
+ case OP_IGET_SHORT:
+ genIGet(cUnit, mir, kWord, fieldOffset, isVolatile);
+ break;
+ case OP_IPUT_WIDE:
+ genIPutWide(cUnit, mir, fieldOffset);
+ break;
+ case OP_IPUT_VOLATILE:
+ case OP_IPUT:
+ case OP_IPUT_BOOLEAN:
+ case OP_IPUT_BYTE:
+ case OP_IPUT_CHAR:
+ case OP_IPUT_SHORT:
+ genIPut(cUnit, mir, kWord, fieldOffset, false, isVolatile);
+ break;
+ case OP_IPUT_OBJECT_VOLATILE:
+ case OP_IPUT_OBJECT:
+ genIPut(cUnit, mir, kWord, fieldOffset, true, isVolatile);
+ break;
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IPUT_WIDE_VOLATILE:
+ genInterpSingleStep(cUnit, mir);
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ int fieldOffset = mir->dalvikInsn.vC;
+ switch (dalvikOpcode) {
+ case OP_IGET_QUICK:
+ case OP_IGET_OBJECT_QUICK:
+ genIGet(cUnit, mir, kWord, fieldOffset, false);
+ break;
+ case OP_IPUT_QUICK:
+ genIPut(cUnit, mir, kWord, fieldOffset, false, false);
+ break;
+ case OP_IPUT_OBJECT_QUICK:
+ genIPut(cUnit, mir, kWord, fieldOffset, true, false);
+ break;
+ case OP_IGET_WIDE_QUICK:
+ genIGetWide(cUnit, mir, fieldOffset);
+ break;
+ case OP_IPUT_WIDE_QUICK:
+ genIPutWide(cUnit, mir, fieldOffset);
+ break;
+ default:
+ return true;
+ }
+ return false;
+
+}
+
+/* Compare against zero */
+static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+ MipsLIR *labelList)
+{
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ MipsConditionCode cond;
+ MipsOpCode opc = kMipsNop;
+ MipsLIR * test = NULL;
+ /* backward branch? */
+ bool backwardBranch = (bb->taken->startOffset <= mir->offset);
+
+ if (backwardBranch &&
+ (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
+ genSuspendPoll(cUnit, mir);
+ }
+
+ RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
+ rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+ rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+ int reg1 = rlSrc1.lowReg;
+ int reg2 = rlSrc2.lowReg;
+ int tReg;
+
+ switch (dalvikOpcode) {
+ case OP_IF_EQ:
+ opc = kMipsBeq;
+ break;
+ case OP_IF_NE:
+ opc = kMipsBne;
+ break;
+ case OP_IF_LT:
+ opc = kMipsBne;
+ tReg = dvmCompilerAllocTemp(cUnit);
+ test = newLIR3(cUnit, kMipsSlt, tReg, reg1, reg2);
+ reg1 = tReg;
+ reg2 = r_ZERO;
+ break;
+ case OP_IF_LE:
+ opc = kMipsBeqz;
+ tReg = dvmCompilerAllocTemp(cUnit);
+ test = newLIR3(cUnit, kMipsSlt, tReg, reg2, reg1);
+ reg1 = tReg;
+ reg2 = -1;
+ break;
+ case OP_IF_GT:
+ opc = kMipsBne;
+ tReg = dvmCompilerAllocTemp(cUnit);
+ test = newLIR3(cUnit, kMipsSlt, tReg, reg2, reg1);
+ reg1 = tReg;
+ reg2 = r_ZERO;
+ break;
+ case OP_IF_GE:
+ opc = kMipsBeqz;
+ tReg = dvmCompilerAllocTemp(cUnit);
+ test = newLIR3(cUnit, kMipsSlt, tReg, reg1, reg2);
+ reg1 = tReg;
+ reg2 = -1;
+ break;
+ default:
+ cond = (MipsConditionCode)0;
+ ALOGE("Unexpected opcode (%d) for Fmt22t", dalvikOpcode);
+ dvmCompilerAbort(cUnit);
+ }
+
+ genConditionalBranchMips(cUnit, opc, reg1, reg2, &labelList[bb->taken->id]);
+ /* This mostly likely will be optimized away in a later phase */
+ genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+ return false;
+}
+
+static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode opcode = mir->dalvikInsn.opcode;
+
+ switch (opcode) {
+ case OP_MOVE_16:
+ case OP_MOVE_OBJECT_16:
+ case OP_MOVE_FROM16:
+ case OP_MOVE_OBJECT_FROM16: {
+ storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0),
+ dvmCompilerGetSrc(cUnit, mir, 0));
+ break;
+ }
+ case OP_MOVE_WIDE_16:
+ case OP_MOVE_WIDE_FROM16: {
+ storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1),
+ dvmCompilerGetSrcWide(cUnit, mir, 0, 1));
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode opcode = mir->dalvikInsn.opcode;
+ RegLocation rlSrc1;
+ RegLocation rlSrc2;
+ RegLocation rlDest;
+
+ if ((opcode >= OP_ADD_INT) && (opcode <= OP_REM_DOUBLE)) {
+ return genArithOp( cUnit, mir );
+ }
+
+ /* APUTs have 3 sources and no targets */
+ if (mir->ssaRep->numDefs == 0) {
+ if (mir->ssaRep->numUses == 3) {
+ rlDest = dvmCompilerGetSrc(cUnit, mir, 0);
+ rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1);
+ rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
+ } else {
+ assert(mir->ssaRep->numUses == 4);
+ rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2);
+ rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3);
+ }
+ } else {
+ /* Two sources and 1 dest. Deduce the operand sizes */
+ if (mir->ssaRep->numUses == 4) {
+ rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
+ } else {
+ assert(mir->ssaRep->numUses == 2);
+ rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
+ rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
+ }
+ if (mir->ssaRep->numDefs == 2) {
+ rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ } else {
+ assert(mir->ssaRep->numDefs == 1);
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ }
+ }
+
+ switch (opcode) {
+ case OP_CMPL_FLOAT:
+ case OP_CMPG_FLOAT:
+ case OP_CMPL_DOUBLE:
+ case OP_CMPG_DOUBLE:
+ return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+ case OP_CMP_LONG:
+ genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+ break;
+ case OP_AGET_WIDE:
+ genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
+ break;
+ case OP_AGET:
+ case OP_AGET_OBJECT:
+ genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
+ break;
+ case OP_AGET_BOOLEAN:
+ genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
+ break;
+ case OP_AGET_BYTE:
+ genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
+ break;
+ case OP_AGET_CHAR:
+ genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
+ break;
+ case OP_AGET_SHORT:
+ genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
+ break;
+ case OP_APUT_WIDE:
+ genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
+ break;
+ case OP_APUT:
+ genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
+ break;
+ case OP_APUT_OBJECT:
+ genArrayObjectPut(cUnit, mir, rlSrc1, rlSrc2, rlDest, 2);
+ break;
+ case OP_APUT_SHORT:
+ case OP_APUT_CHAR:
+ genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
+ break;
+ case OP_APUT_BYTE:
+ case OP_APUT_BOOLEAN:
+ genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Find the matching case.
+ *
+ * return values:
+ * r_RESULT0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
+ * including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
+ * r_RESULT1 (high 32-bit): the branch offset of the matching case (only for indexes
+ * above MAX_CHAINED_SWITCH_CASES).
+ *
+ * Instructions around the call are:
+ *
+ * jalr &findPackedSwitchIndex
+ * nop
+ * lw gp, 84(sp) |
+ * addu | 20 bytes for these 5 instructions
+ * move | (NOTE: if this sequence is shortened or lengthened, then
+ * jr | the 20 byte offset added below in 3 places must be changed
+ * nop | accordingly.)
+ * chaining cell for case 0 [16 bytes]
+ * chaining cell for case 1 [16 bytes]
+ * :
+ * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [16 bytes]
+ * chaining cell for case default [16 bytes]
+ * noChain exit
+ */
+static u8 findPackedSwitchIndex(const u2* switchData, int testVal)
+{
+ int size;
+ int firstKey;
+ const int *entries;
+ int index;
+ int jumpIndex;
+ uintptr_t caseDPCOffset = 0;
+
+ /*
+ * Packed switch data format:
+ * ushort ident = 0x0100 magic value
+ * ushort size number of entries in the table
+ * int first_key first (and lowest) switch case value
+ * int targets[size] branch targets, relative to switch opcode
+ *
+ * Total size is (4+size*2) 16-bit code units.
+ */
+ size = switchData[1];
+ assert(size > 0);
+
+ firstKey = switchData[2];
+ firstKey |= switchData[3] << 16;
+
+
+ /* The entries are guaranteed to be aligned on a 32-bit boundary;
+ * we can treat them as a native int array.
+ */
+ entries = (const int*) &switchData[4];
+ assert(((u4)entries & 0x3) == 0);
+
+ index = testVal - firstKey;
+
+ /* Jump to the default cell */
+ if (index < 0 || index >= size) {
+ jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
+ /* Jump to the non-chaining exit point */
+ } else if (index >= MAX_CHAINED_SWITCH_CASES) {
+ jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
+#ifdef HAVE_LITTLE_ENDIAN
+ caseDPCOffset = entries[index];
+#else
+ caseDPCOffset = (unsigned int)entries[index] >> 16 | entries[index] << 16;
+#endif
+ /* Jump to the inline chaining cell */
+ } else {
+ jumpIndex = index;
+ }
+
+ return (((u8) caseDPCOffset) << 32) | (u8) (jumpIndex * CHAIN_CELL_NORMAL_SIZE + 20);
+}
+
+/* See comments for findPackedSwitchIndex */
+static u8 findSparseSwitchIndex(const u2* switchData, int testVal)
+{
+ int size;
+ const int *keys;
+ const int *entries;
+ /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
+ int i;
+
+ /*
+ * Sparse switch data format:
+ * ushort ident = 0x0200 magic value
+ * ushort size number of entries in the table; > 0
+ * int keys[size] keys, sorted low-to-high; 32-bit aligned
+ * int targets[size] branch targets, relative to switch opcode
+ *
+ * Total size is (2+size*4) 16-bit code units.
+ */
+
+ size = switchData[1];
+ assert(size > 0);
+
+ /* The keys are guaranteed to be aligned on a 32-bit boundary;
+ * we can treat them as a native int array.
+ */
+ keys = (const int*) &switchData[2];
+ assert(((u4)keys & 0x3) == 0);
+
+ /* The entries are guaranteed to be aligned on a 32-bit boundary;
+ * we can treat them as a native int array.
+ */
+ entries = keys + size;
+ assert(((u4)entries & 0x3) == 0);
+
+ /*
+ * Run through the list of keys, which are guaranteed to
+ * be sorted low-to-high.
+ *
+ * Most tables have 3-4 entries. Few have more than 10. A binary
+ * search here is probably not useful.
+ */
+ for (i = 0; i < size; i++) {
+#ifdef HAVE_LITTLE_ENDIAN
+ int k = keys[i];
+ if (k == testVal) {
+ /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
+ int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
+ i : MAX_CHAINED_SWITCH_CASES + 1;
+ return (((u8) entries[i]) << 32) | (u8) (jumpIndex * CHAIN_CELL_NORMAL_SIZE + 20);
+#else
+ int k = (unsigned int)keys[i] >> 16 | keys[i] << 16;
+ if (k == testVal) {
+ /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
+ int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
+ i : MAX_CHAINED_SWITCH_CASES + 1;
+ int temp = (unsigned int)entries[i] >> 16 | entries[i] << 16;
+ return (((u8) temp) << 32) | (u8) (jumpIndex * CHAIN_CELL_NORMAL_SIZE + 20);
+#endif
+ } else if (k > testVal) {
+ break;
+ }
+ }
+ return MIN(size, MAX_CHAINED_SWITCH_CASES) * CHAIN_CELL_NORMAL_SIZE + 20;
+}
+
+static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ switch (dalvikOpcode) {
+ case OP_FILL_ARRAY_DATA: {
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ // Making a call - use explicit registers
+ dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
+ genExportPC(cUnit, mir);
+ loadValueDirectFixed(cUnit, rlSrc, r_A0);
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmInterpHandleFillArrayData);
+ loadConstant(cUnit, r_A1,
+ (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+ /* generate a branch over if successful */
+ MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
+ loadConstant(cUnit, r_A0,
+ (int) (cUnit->method->insns + mir->offset));
+ genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branchOver->generic.target = (LIR *) target;
+ break;
+ }
+ /*
+ * Compute the goto target of up to
+ * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
+ * See the comment before findPackedSwitchIndex for the code layout.
+ */
+ case OP_PACKED_SWITCH:
+ case OP_SPARSE_SWITCH: {
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
+ loadValueDirectFixed(cUnit, rlSrc, r_A1);
+ dvmCompilerLockAllTemps(cUnit);
+
+ if (dalvikOpcode == OP_PACKED_SWITCH) {
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)findPackedSwitchIndex);
+ } else {
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int)findSparseSwitchIndex);
+ }
+ /* r_A0 <- Addr of the switch data */
+ loadConstant(cUnit, r_A0,
+ (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ dvmCompilerClobberCallRegs(cUnit);
+ /* pc <- computed goto target using value in RA */
+ newLIR3(cUnit, kMipsAddu, r_A0, r_RA, r_RESULT0);
+ newLIR2(cUnit, kMipsMove, r_A1, r_RESULT1);
+ newLIR1(cUnit, kMipsJr, r_A0);
+ newLIR0(cUnit, kMipsNop); /* for maintaining 20 byte offset */
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+/*
+ * See the example of predicted inlining listed before the
+ * genValidationForPredictedInline function. The function here takes care the
+ * branch over at 0x4858de78 and the misprediction target at 0x4858de7a.
+ */
+static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir,
+ BasicBlock *bb,
+ MipsLIR *labelList)
+{
+ BasicBlock *fallThrough = bb->fallThrough;
+
+ /* Bypass the move-result block if there is one */
+ if (fallThrough->firstMIRInsn) {
+ assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED);
+ fallThrough = fallThrough->fallThrough;
+ }
+ /* Generate a branch over if the predicted inlining is correct */
+ genUnconditionalBranch(cUnit, &labelList[fallThrough->id]);
+
+ /* Reset the register state */
+ dvmCompilerResetRegPool(cUnit);
+ dvmCompilerClobberAllRegs(cUnit);
+ dvmCompilerResetNullCheck(cUnit);
+
+ /* Target for the slow invoke path */
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ /* Hook up the target to the verification branch */
+ mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target;
+}
+
+static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir,
+ BasicBlock *bb, MipsLIR *labelList)
+{
+ MipsLIR *retChainingCell = NULL;
+ MipsLIR *pcrLabel = NULL;
+
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ return false;
+
+ if (bb->fallThrough != NULL)
+ retChainingCell = &labelList[bb->fallThrough->id];
+
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ switch (mir->dalvikInsn.opcode) {
+ /*
+ * calleeMethod = this->clazz->vtable[
+ * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
+ * ]
+ */
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_VIRTUAL_RANGE: {
+ MipsLIR *predChainingCell = &labelList[bb->taken->id];
+ int methodIndex =
+ cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
+ methodIndex;
+
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (mir->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+ }
+
+ if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ genInvokeVirtualCommon(cUnit, mir, methodIndex,
+ retChainingCell,
+ predChainingCell,
+ pcrLabel);
+ break;
+ }
+ /*
+ * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
+ * ->pResMethods[BBBB]->methodIndex]
+ */
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_SUPER_RANGE: {
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod == cUnit->method->clazz->super->vtable[
+ cUnit->method->clazz->pDvmDex->
+ pResMethods[dInsn->vB]->methodIndex]);
+
+ if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
+ assert(calleeAddr);
+ genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr,
+ retChainingCell);
+ } else {
+ /* r_A0 = calleeMethod */
+ loadConstant(cUnit, r_A0, (int) calleeMethod);
+
+ genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
+ calleeMethod);
+ }
+ break;
+ }
+ /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_DIRECT_RANGE: {
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod ==
+ cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
+
+ if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ /* r_A0 = calleeMethod */
+ loadConstant(cUnit, r_A0, (int) calleeMethod);
+
+ genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
+ calleeMethod);
+ break;
+ }
+ /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_STATIC_RANGE: {
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod ==
+ cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
+
+ if (mir->dalvikInsn.opcode == OP_INVOKE_STATIC)
+ genProcessArgsNoRange(cUnit, mir, dInsn,
+ NULL /* no null check */);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn,
+ NULL /* no null check */);
+
+ if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
+ assert(calleeAddr);
+ genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr,
+ retChainingCell);
+ } else {
+ /* r_A0 = calleeMethod */
+ loadConstant(cUnit, r_A0, (int) calleeMethod);
+
+ genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
+ calleeMethod);
+ }
+ break;
+ }
+
+ /*
+ * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
+ * BBBB, method, method->clazz->pDvmDex)
+ *
+ * The following is an example of generated code for
+ * "invoke-interface v0"
+ *
+ * -------- dalvik offset: 0x000f @ invoke-interface (PI) v2
+ * 0x2f140c54 : lw a0,8(s1) # genProcessArgsNoRange
+ * 0x2f140c58 : addiu s4,s1,0xffffffe8(-24)
+ * 0x2f140c5c : beqz a0,0x2f140d5c (L0x11f864)
+ * 0x2f140c60 : pref 1,0(s4)
+ * -------- BARRIER
+ * 0x2f140c64 : sw a0,0(s4)
+ * 0x2f140c68 : addiu s4,s4,0x0004(4)
+ * -------- BARRIER
+ * 0x2f140c6c : lui s0,0x2d23(11555) # dalvikPC
+ * 0x2f140c70 : ori s0,s0,0x2d2365a6(757294502)
+ * 0x2f140c74 : lahi/lui a1,0x2f14(12052) # a1 <- &retChainingCell
+ * 0x2f140c78 : lalo/ori a1,a1,0x2f140d38(789843256)
+ * 0x2f140c7c : lahi/lui a2,0x2f14(12052) # a2 <- &predictedChainingCell
+ * 0x2f140c80 : lalo/ori a2,a2,0x2f140d80(789843328)
+ * 0x2f140c84 : jal 0x2f1311ec(789778924) # call TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
+ * 0x2f140c88 : nop
+ * 0x2f140c8c : b 0x2f140d80 (L0x11efc0) # off to the predicted chain
+ * 0x2f140c90 : nop
+ * 0x2f140c94 : b 0x2f140d60 (L0x12457c) # punt to the interpreter
+ * 0x2f140c98 : lui a0,0x2d23(11555)
+ * 0x2f140c9c : move s5,a1 # prepare for dvmFindInterfaceMethodInCache
+ * 0x2f140ca0 : move s6,a2
+ * 0x2f140ca4 : move s7,a3
+ * 0x2f140ca8 : move a0,a3
+ * 0x2f140cac : ori a1,zero,0x2b42(11074)
+ * 0x2f140cb0 : lui a2,0x2c92(11410)
+ * 0x2f140cb4 : ori a2,a2,0x2c92adf8(747810296)
+ * 0x2f140cb8 : lui a3,0x0009(9)
+ * 0x2f140cbc : ori a3,a3,0x924b8(599224)
+ * 0x2f140cc0 : lui t9,0x2ab2(10930)
+ * 0x2f140cc4 : ori t9,t9,0x2ab2a48c(716350604)
+ * 0x2f140cc8 : jalr ra,t9 # call dvmFindInterfaceMethodInCache
+ * 0x2f140ccc : nop
+ * 0x2f140cd0 : lw gp,84(sp)
+ * 0x2f140cd4 : move a0,v0
+ * 0x2f140cd8 : bne v0,zero,0x2f140cf0 (L0x120064)
+ * 0x2f140cdc : nop
+ * 0x2f140ce0 : lui a0,0x2d23(11555) # a0 <- dalvikPC
+ * 0x2f140ce4 : ori a0,a0,0x2d2365a6(757294502)
+ * 0x2f140ce8 : jal 0x2f131720(789780256) # call TEMPLATE_THROW_EXCEPTION_COMMON
+ * 0x2f140cec : nop
+ * 0x2f140cf0 : move a1,s5 # a1 <- &retChainingCell
+ * 0x2f140cf4 : bgtz s5,0x2f140d20 (L0x120324) # >0? don't rechain
+ * 0x2f140cf8 : nop
+ * 0x2f140cfc : lui t9,0x2aba(10938) # prepare for dvmJitToPatchPredictedChain
+ * 0x2f140d00 : ori t9,t9,0x2abae3c4(716891076)
+ * 0x2f140d04 : move a1,s2
+ * 0x2f140d08 : move a2,s6
+ * 0x2f140d0c : move a3,s7
+ * 0x2f140d10 : jalr ra,t9 # call dvmJitToPatchPredictedChain
+ * 0x2f140d14 : nop
+ * 0x2f140d18 : lw gp,84(sp)
+ * 0x2f140d1c : move a0,v0
+ * 0x2f140d20 : lahi/lui a1,0x2f14(12052)
+ * 0x2f140d24 : lalo/ori a1,a1,0x2f140d38(789843256) # a1 <- &retChainingCell
+ * 0x2f140d28 : jal 0x2f1310c4(789778628) # call TEMPLATE_INVOKE_METHOD_NO_OPT
+ * 0x2f140d2c : nop
+ * 0x2f140d30 : b 0x2f140d60 (L0x12457c)
+ * 0x2f140d34 : lui a0,0x2d23(11555)
+ * 0x2f140d38 : .align4
+ * -------- dalvik offset: 0x0012 @ move-result (PI) v1, (#0), (#0)
+ * 0x2f140d38 : lw a2,16(s2)
+ * 0x2f140d3c : sw a2,4(s1)
+ * 0x2f140d40 : b 0x2f140d74 (L0x1246fc)
+ * 0x2f140d44 : lw a0,116(s2)
+ * 0x2f140d48 : undefined
+ * -------- reconstruct dalvik PC : 0x2d2365a6 @ +0x000f
+ * 0x2f140d4c : lui a0,0x2d23(11555)
+ * 0x2f140d50 : ori a0,a0,0x2d2365a6(757294502)
+ * 0x2f140d54 : b 0x2f140d68 (L0x12463c)
+ * 0x2f140d58 : lw a1,108(s2)
+ * -------- reconstruct dalvik PC : 0x2d2365a6 @ +0x000f
+ * 0x2f140d5c : lui a0,0x2d23(11555)
+ * 0x2f140d60 : ori a0,a0,0x2d2365a6(757294502)
+ * Exception_Handling:
+ * 0x2f140d64 : lw a1,108(s2)
+ * 0x2f140d68 : jalr ra,a1
+ * 0x2f140d6c : nop
+ * 0x2f140d70 : .align4
+ * -------- chaining cell (hot): 0x0013
+ * 0x2f140d70 : lw a0,116(s2)
+ * 0x2f140d74 : jalr ra,a0
+ * 0x2f140d78 : nop
+ * 0x2f140d7c : data 0x2d2365ae(757294510)
+ * 0x2f140d80 : .align4
+ * -------- chaining cell (predicted): N/A
+ * 0x2f140d80 : data 0xe7fe(59390)
+ * 0x2f140d84 : data 0x0000(0)
+ * 0x2f140d88 : data 0x0000(0)
+ * 0x2f140d8c : data 0x0000(0)
+ * 0x2f140d90 : data 0x0000(0)
+ * -------- end of chaining cells (0x0190)
+ */
+ case OP_INVOKE_INTERFACE:
+ case OP_INVOKE_INTERFACE_RANGE: {
+ MipsLIR *predChainingCell = &labelList[bb->taken->id];
+
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (mir->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+ }
+
+ if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ /* "this" is already left in r_A0 by genProcessArgs* */
+
+ /* r4PC = dalvikCallsite */
+ loadConstant(cUnit, r4PC,
+ (int) (cUnit->method->insns + mir->offset));
+
+ /* r_A1 = &retChainingCell */
+ MipsLIR *addrRetChain = newLIR2(cUnit, kMipsLahi, r_A1, 0);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+ addrRetChain = newLIR3(cUnit, kMipsLalo, r_A1, r_A1, 0);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+
+
+ /* r_A2 = &predictedChainingCell */
+ MipsLIR *predictedChainingCell = newLIR2(cUnit, kMipsLahi, r_A2, 0);
+ predictedChainingCell->generic.target = (LIR *) predChainingCell;
+ predictedChainingCell = newLIR3(cUnit, kMipsLalo, r_A2, r_A2, 0);
+ predictedChainingCell->generic.target = (LIR *) predChainingCell;
+
+ genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF :
+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
+
+ /* return through ra - jump to the chaining cell */
+ genUnconditionalBranch(cUnit, predChainingCell);
+
+ /*
+ * null-check on "this" may have been eliminated, but we still need
+ * a PC-reconstruction label for stack overflow bailout.
+ */
+ if (pcrLabel == NULL) {
+ int dPC = (int) (cUnit->method->insns + mir->offset);
+ pcrLabel = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ pcrLabel->opcode = kMipsPseudoPCReconstructionCell;
+ pcrLabel->operands[0] = dPC;
+ pcrLabel->operands[1] = mir->offset;
+ /* Insert the place holder to the growable list */
+ dvmInsertGrowableList(&cUnit->pcReconstructionList,
+ (intptr_t) pcrLabel);
+ }
+
+ /* return through ra+8 - punt to the interpreter */
+ genUnconditionalBranch(cUnit, pcrLabel);
+
+ /*
+ * return through ra+16 - fully resolve the callee method.
+ * r_A1 <- count
+ * r_A2 <- &predictedChainCell
+ * r_A3 <- this->class
+ * r4 <- dPC
+ * r_S4 <- this->class->vtable
+ */
+
+ /* Save count, &predictedChainCell, and class to high regs first */
+ genRegCopy(cUnit, r_S5, r_A1);
+ genRegCopy(cUnit, r_S6, r_A2);
+ genRegCopy(cUnit, r_S7, r_A3);
+
+ /* r_A0 now contains this->clazz */
+ genRegCopy(cUnit, r_A0, r_A3);
+
+ /* r_A1 = BBBB */
+ loadConstant(cUnit, r_A1, dInsn->vB);
+
+ /* r_A2 = method (caller) */
+ loadConstant(cUnit, r_A2, (int) cUnit->method);
+
+ /* r_A3 = pDvmDex */
+ loadConstant(cUnit, r_A3, (int) cUnit->method->clazz->pDvmDex);
+
+ LOAD_FUNC_ADDR(cUnit, r_T9,
+ (intptr_t) dvmFindInterfaceMethodInCache);
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ /* r_V0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
+ genRegCopy(cUnit, r_A0, r_V0);
+
+ dvmCompilerClobberCallRegs(cUnit);
+ /* generate a branch over if the interface method is resolved */
+ MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
+ /*
+ * calleeMethod == NULL -> throw
+ */
+ loadConstant(cUnit, r_A0,
+ (int) (cUnit->method->insns + mir->offset));
+ genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+ /* noreturn */
+
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branchOver->generic.target = (LIR *) target;
+
+ genRegCopy(cUnit, r_A1, r_S5);
+
+ /* Check if rechain limit is reached */
+ MipsLIR *bypassRechaining = opCompareBranch(cUnit, kMipsBgtz, r_S5, -1);
+
+ LOAD_FUNC_ADDR(cUnit, r_T9, (int) dvmJitToPatchPredictedChain);
+
+ genRegCopy(cUnit, r_A1, rSELF);
+ genRegCopy(cUnit, r_A2, r_S6);
+ genRegCopy(cUnit, r_A3, r_S7);
+
+ /*
+ * r_A0 = calleeMethod
+ * r_A2 = &predictedChainingCell
+ * r_A3 = class
+ *
+ * &returnChainingCell has been loaded into r_A1 but is not needed
+ * when patching the chaining cell and will be clobbered upon
+ * returning so it will be reconstructed again.
+ */
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ genRegCopy(cUnit, r_A0, r_V0);
+
+ /* r_A1 = &retChainingCell */
+ addrRetChain = newLIR2(cUnit, kMipsLahi, r_A1, 0);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+ bypassRechaining->generic.target = (LIR *) addrRetChain;
+ addrRetChain = newLIR3(cUnit, kMipsLalo, r_A1, r_A1, 0);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+
+
+ /*
+ * r_A0 = this, r_A1 = calleeMethod,
+ * r_A1 = &ChainingCell,
+ * r4PC = callsiteDPC,
+ */
+ genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+ TEMPLATE_INVOKE_METHOD_NO_OPT_PROF :
+ TEMPLATE_INVOKE_METHOD_NO_OPT);
+
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.invokePolymorphic++;
+#endif
+ /* Handle exceptions using the interpreter */
+ genTrap(cUnit, mir->offset, pcrLabel);
+ break;
+ }
+ case OP_INVOKE_OBJECT_INIT_RANGE:
+ case OP_FILLED_NEW_ARRAY:
+ case OP_FILLED_NEW_ARRAY_RANGE: {
+ /* Just let the interpreter deal with these */
+ genInterpSingleStep(cUnit, mir);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
+ BasicBlock *bb, MipsLIR *labelList)
+{
+ MipsLIR *pcrLabel = NULL;
+
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (mir->OptimizationFlags & MIR_INLINED)
+ return false;
+
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ switch (mir->dalvikInsn.opcode) {
+ /* calleeMethod = this->clazz->vtable[BBBB] */
+ case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+ case OP_INVOKE_VIRTUAL_QUICK: {
+ int methodIndex = dInsn->vB;
+ MipsLIR *retChainingCell = &labelList[bb->fallThrough->id];
+ MipsLIR *predChainingCell = &labelList[bb->taken->id];
+
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (mir->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+ }
+
+ if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL_QUICK)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
+ assert(calleeAddr);
+ genInvokeVirtualWholeMethod(cUnit, mir, calleeAddr,
+ retChainingCell);
+ }
+
+ genInvokeVirtualCommon(cUnit, mir, methodIndex,
+ retChainingCell,
+ predChainingCell,
+ pcrLabel);
+ break;
+ }
+ /* calleeMethod = method->clazz->super->vtable[BBBB] */
+ case OP_INVOKE_SUPER_QUICK:
+ case OP_INVOKE_SUPER_QUICK_RANGE: {
+ /* Grab the method ptr directly from what the interpreter sees */
+ const Method *calleeMethod = mir->meta.callsiteInfo->method;
+ assert(calleeMethod ==
+ cUnit->method->clazz->super->vtable[dInsn->vB]);
+
+ if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER_QUICK)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ /* r_A0 = calleeMethod */
+ loadConstant(cUnit, r_A0, (int) calleeMethod);
+
+ genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
+ calleeMethod);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+/*
+ * This operation is complex enough that we'll do it partly inline
+ * and partly with a handler. NOTE: the handler uses hardcoded
+ * values for string object offsets and must be revisitied if the
+ * layout changes.
+ */
+static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
+{
+#if defined(USE_GLOBAL_STRING_DEFS)
+ return handleExecuteInlineC(cUnit, mir);
+#else
+ MipsLIR *rollback;
+ RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1);
+
+ loadValueDirectFixed(cUnit, rlThis, r_A0);
+ loadValueDirectFixed(cUnit, rlComp, r_A1);
+ /* Test objects for NULL */
+ rollback = genNullCheck(cUnit, rlThis.sRegLow, r_A0, mir->offset, NULL);
+ genNullCheck(cUnit, rlComp.sRegLow, r_A1, mir->offset, rollback);
+ /*
+ * TUNING: we could check for object pointer equality before invoking
+ * handler. Unclear whether the gain would be worth the added code size
+ * expansion.
+ */
+ genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
+ storeValue(cUnit, inlinedTarget(cUnit, mir, false),
+ dvmCompilerGetReturn(cUnit));
+ return false;
+#endif
+}
+
+static bool genInlinedFastIndexOf(CompilationUnit *cUnit, MIR *mir)
+{
+#if defined(USE_GLOBAL_STRING_DEFS)
+ return handleExecuteInlineC(cUnit, mir);
+#else
+ RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1);
+
+ loadValueDirectFixed(cUnit, rlThis, r_A0);
+ loadValueDirectFixed(cUnit, rlChar, r_A1);
+
+ RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
+ loadValueDirectFixed(cUnit, rlStart, r_A2);
+
+ /* Test objects for NULL */
+ genNullCheck(cUnit, rlThis.sRegLow, r_A0, mir->offset, NULL);
+ genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
+ storeValue(cUnit, inlinedTarget(cUnit, mir, false),
+ dvmCompilerGetReturn(cUnit));
+ return false;
+#endif
+}
+
+// Generates an inlined String.isEmpty or String.length.
+static bool genInlinedStringIsEmptyOrLength(CompilationUnit *cUnit, MIR *mir,
+ bool isEmpty)
+{
+ // dst = src.length();
+ RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
+ loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
+ rlResult.lowReg);
+ if (isEmpty) {
+ // dst = (dst == 0);
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ newLIR3(cUnit, kMipsSltu, tReg, r_ZERO, rlResult.lowReg);
+ opRegRegImm(cUnit, kOpXor, rlResult.lowReg, tReg, 1);
+ }
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
+{
+ return genInlinedStringIsEmptyOrLength(cUnit, mir, false);
+}
+
+static bool genInlinedStringIsEmpty(CompilationUnit *cUnit, MIR *mir)
+{
+ return genInlinedStringIsEmptyOrLength(cUnit, mir, true);
+}
+
+static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
+{
+ int contents = OFFSETOF_MEMBER(ArrayObject, contents);
+ RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlIdx = dvmCompilerGetSrc(cUnit, mir, 1);
+ RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+ RegLocation rlResult;
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
+ int regMax = dvmCompilerAllocTemp(cUnit);
+ int regOff = dvmCompilerAllocTemp(cUnit);
+ int regPtr = dvmCompilerAllocTemp(cUnit);
+ MipsLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
+ mir->offset, NULL);
+ loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
+ loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
+ loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
+ genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
+ dvmCompilerFreeTemp(cUnit, regMax);
+ opRegImm(cUnit, kOpAdd, regPtr, contents);
+ opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+ RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ int signReg = dvmCompilerAllocTemp(cUnit);
+ /*
+ * abs(x) = y<=x>>31, (x+y)^y.
+ * Thumb2's IT block also yields 3 instructions, but imposes
+ * scheduling constraints.
+ */
+ opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
+ opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
+ opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
+ rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+ RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ int signReg = dvmCompilerAllocTemp(cUnit);
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ /*
+ * abs(x) = y<=x>>31, (x+y)^y.
+ * Thumb2 IT block allows slightly shorter sequence,
+ * but introduces a scheduling barrier. Stick with this
+ * mechanism for now.
+ */
+ opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
+ opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
+ newLIR3(cUnit, kMipsSltu, tReg, rlResult.lowReg, signReg);
+ opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg, signReg);
+ opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlResult.highReg, tReg);
+ opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
+ opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
+ dvmCompilerFreeTemp(cUnit, signReg);
+ dvmCompilerFreeTemp(cUnit, tReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genInlinedIntFloatConversion(CompilationUnit *cUnit, MIR *mir)
+{
+ // Just move from source to destination...
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+ storeValue(cUnit, rlDest, rlSrc);
+ return false;
+}
+
+static bool genInlinedLongDoubleConversion(CompilationUnit *cUnit, MIR *mir)
+{
+ // Just move from source to destination...
+ RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
+ storeValueWide(cUnit, rlDest, rlSrc);
+ return false;
+}
+/*
+ * JITs a call to a C function.
+ * TODO: use this for faster native method invocation for simple native
+ * methods (http://b/3069458).
+ */
+static bool handleExecuteInlineC(CompilationUnit *cUnit, MIR *mir)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ int operation = dInsn->vB;
+ unsigned int i;
+ const InlineOperation* inLineTable = dvmGetInlineOpsTable();
+ uintptr_t fn = (int) inLineTable[operation].func;
+ if (fn == 0) {
+ dvmCompilerAbort(cUnit);
+ }
+ dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
+ dvmCompilerClobberCallRegs(cUnit);
+ dvmCompilerClobber(cUnit, r4PC);
+ dvmCompilerClobber(cUnit, rINST);
+ int offset = offsetof(Thread, interpSave.retval);
+ opRegRegImm(cUnit, kOpAdd, r4PC, rSELF, offset);
+ newLIR3(cUnit, kMipsSw, r4PC, 16, r_SP); /* sp has plenty of space */
+ genExportPC(cUnit, mir);
+ assert(dInsn->vA <= 4);
+ for (i=0; i < dInsn->vA; i++) {
+ loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i+r_A0);
+ }
+ LOAD_FUNC_ADDR(cUnit, r_T9, fn);
+ opReg(cUnit, kOpBlx, r_T9);
+ newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
+ /* NULL? */
+ MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
+ loadConstant(cUnit, r_A0, (int) (cUnit->method->insns + mir->offset));
+ genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+ MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branchOver->generic.target = (LIR *) target;
+ return false;
+}
+
+/*
+ * NOTE: Handles both range and non-range versions (arguments
+ * have already been normalized by this point).
+ */
+static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ assert(dInsn->opcode == OP_EXECUTE_INLINE_RANGE ||
+ dInsn->opcode == OP_EXECUTE_INLINE);
+ switch (dInsn->vB) {
+ case INLINE_EMPTYINLINEMETHOD:
+ return false; /* Nop */
+
+ /* These ones we potentially JIT inline. */
+
+ case INLINE_STRING_CHARAT:
+ return genInlinedStringCharAt(cUnit, mir);
+ case INLINE_STRING_LENGTH:
+ return genInlinedStringLength(cUnit, mir);
+ case INLINE_STRING_IS_EMPTY:
+ return genInlinedStringIsEmpty(cUnit, mir);
+ case INLINE_STRING_COMPARETO:
+ return genInlinedCompareTo(cUnit, mir);
+ case INLINE_STRING_FASTINDEXOF_II:
+ return genInlinedFastIndexOf(cUnit, mir);
+
+ case INLINE_MATH_ABS_INT:
+ case INLINE_STRICT_MATH_ABS_INT:
+ return genInlinedAbsInt(cUnit, mir);
+ case INLINE_MATH_ABS_LONG:
+ case INLINE_STRICT_MATH_ABS_LONG:
+ return genInlinedAbsLong(cUnit, mir);
+ case INLINE_MATH_MIN_INT:
+ case INLINE_STRICT_MATH_MIN_INT:
+ return genInlinedMinMaxInt(cUnit, mir, true);
+ case INLINE_MATH_MAX_INT:
+ case INLINE_STRICT_MATH_MAX_INT:
+ return genInlinedMinMaxInt(cUnit, mir, false);
+ case INLINE_MATH_SQRT:
+ case INLINE_STRICT_MATH_SQRT:
+ return genInlineSqrt(cUnit, mir);
+ case INLINE_MATH_ABS_FLOAT:
+ case INLINE_STRICT_MATH_ABS_FLOAT:
+ return genInlinedAbsFloat(cUnit, mir);
+ case INLINE_MATH_ABS_DOUBLE:
+ case INLINE_STRICT_MATH_ABS_DOUBLE:
+ return genInlinedAbsDouble(cUnit, mir);
+
+ case INLINE_FLOAT_TO_RAW_INT_BITS:
+ case INLINE_INT_BITS_TO_FLOAT:
+ return genInlinedIntFloatConversion(cUnit, mir);
+ case INLINE_DOUBLE_TO_RAW_LONG_BITS:
+ case INLINE_LONG_BITS_TO_DOUBLE:
+ return genInlinedLongDoubleConversion(cUnit, mir);
+
+ /*
+ * These ones we just JIT a call to a C function for.
+ * TODO: special-case these in the other "invoke" call paths.
+ */
+ case INLINE_STRING_EQUALS:
+ case INLINE_MATH_COS:
+ case INLINE_MATH_SIN:
+ case INLINE_FLOAT_TO_INT_BITS:
+ case INLINE_DOUBLE_TO_LONG_BITS:
+ return handleExecuteInlineC(cUnit, mir);
+ }
+ dvmCompilerAbort(cUnit);
+ return false; // Not reachable; keeps compiler happy.
+}
+
+static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
+{
+ //TUNING: We're using core regs here - not optimal when target is a double
+ RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ loadConstantNoClobber(cUnit, rlResult.lowReg,
+ mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
+ loadConstantNoClobber(cUnit, rlResult.highReg,
+ (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+}
+
+/*
+ * The following are special processing routines that handle transfer of
+ * controls between compiled code and the interpreter. Certain VM states like
+ * Dalvik PC and special-purpose registers are reconstructed here.
+ */
+
+/* Chaining cell for code that may need warmup. */
+static void handleNormalChainingCell(CompilationUnit *cUnit,
+ unsigned int offset)
+{
+ newLIR3(cUnit, kMipsLw, r_A0,
+ offsetof(Thread, jitToInterpEntries.dvmJitToInterpNormal),
+ rSELF);
+ newLIR2(cUnit, kMipsJalr, r_RA, r_A0);
+ addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
+}
+
+/*
+ * Chaining cell for instructions that immediately following already translated
+ * code.
+ */
+static void handleHotChainingCell(CompilationUnit *cUnit,
+ unsigned int offset)
+{
+ newLIR3(cUnit, kMipsLw, r_A0,
+ offsetof(Thread, jitToInterpEntries.dvmJitToInterpTraceSelect),
+ rSELF);
+ newLIR2(cUnit, kMipsJalr, r_RA, r_A0);
+ addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
+}
+
+/* Chaining cell for branches that branch back into the same basic block */
+static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
+ unsigned int offset)
+{
+ /*
+ * Use raw instruction constructors to guarantee that the generated
+ * instructions fit the predefined cell size.
+ */
+#if defined(WITH_SELF_VERIFICATION)
+ newLIR3(cUnit, kMipsLw, r_A0,
+ offsetof(Thread, jitToInterpEntries.dvmJitToInterpBackwardBranch),
+ rSELF);
+#else
+ newLIR3(cUnit, kMipsLw, r_A0,
+ offsetof(Thread, jitToInterpEntries.dvmJitToInterpNormal),
+ rSELF);
+#endif
+ newLIR2(cUnit, kMipsJalr, r_RA, r_A0);
+ addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
+}
+
+/* Chaining cell for monomorphic method invocations. */
+static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
+ const Method *callee)
+{
+ newLIR3(cUnit, kMipsLw, r_A0,
+ offsetof(Thread, jitToInterpEntries.dvmJitToInterpTraceSelect),
+ rSELF);
+ newLIR2(cUnit, kMipsJalr, r_RA, r_A0);
+ addWordData(cUnit, NULL, (int) (callee->insns));
+}
+
+/* Chaining cell for monomorphic method invocations. */
+static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
+{
+ /* Should not be executed in the initial state */
+ addWordData(cUnit, NULL, PREDICTED_CHAIN_BX_PAIR_INIT);
+ /* branch delay slot nop */
+ addWordData(cUnit, NULL, PREDICTED_CHAIN_DELAY_SLOT_INIT);
+ /* To be filled: class */
+ addWordData(cUnit, NULL, PREDICTED_CHAIN_CLAZZ_INIT);
+ /* To be filled: method */
+ addWordData(cUnit, NULL, PREDICTED_CHAIN_METHOD_INIT);
+ /*
+ * Rechain count. The initial value of 0 here will trigger chaining upon
+ * the first invocation of this callsite.
+ */
+ addWordData(cUnit, NULL, PREDICTED_CHAIN_COUNTER_INIT);
+}
+
+/* Load the Dalvik PC into a0 and jump to the specified target */
+static void handlePCReconstruction(CompilationUnit *cUnit,
+ MipsLIR *targetLabel)
+{
+ MipsLIR **pcrLabel =
+ (MipsLIR **) cUnit->pcReconstructionList.elemList;
+ int numElems = cUnit->pcReconstructionList.numUsed;
+ int i;
+
+ /*
+ * We should never reach here through fall-through code, so insert
+ * a bomb to signal troubles immediately.
+ */
+ if (numElems) {
+ newLIR0(cUnit, kMipsUndefined);
+ }
+
+ for (i = 0; i < numElems; i++) {
+ dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
+ /* a0 = dalvik PC */
+ loadConstant(cUnit, r_A0, pcrLabel[i]->operands[0]);
+ genUnconditionalBranch(cUnit, targetLabel);
+ }
+}
+
+static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
+ "kMirOpPhi",
+ "kMirOpNullNRangeUpCheck",
+ "kMirOpNullNRangeDownCheck",
+ "kMirOpLowerBound",
+ "kMirOpPunt",
+ "kMirOpCheckInlinePrediction",
+};
+
+/*
+ * vA = arrayReg;
+ * vB = idxReg;
+ * vC = endConditionReg;
+ * arg[0] = maxC
+ * arg[1] = minC
+ * arg[2] = loopBranchConditionCode
+ */
+static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
+{
+ /*
+ * NOTE: these synthesized blocks don't have ssa names assigned
+ * for Dalvik registers. However, because they dominate the following
+ * blocks we can simply use the Dalvik name w/ subscript 0 as the
+ * ssa name.
+ */
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ const int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+ const int maxC = dInsn->arg[0];
+ int regLength;
+ RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
+ RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
+
+ /* regArray <- arrayRef */
+ rlArray = loadValue(cUnit, rlArray, kCoreReg);
+ rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
+ genRegImmCheck(cUnit, kMipsCondEq, rlArray.lowReg, 0, 0,
+ (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
+
+ /* regLength <- len(arrayRef) */
+ regLength = dvmCompilerAllocTemp(cUnit);
+ loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
+
+ int delta = maxC;
+ /*
+ * If the loop end condition is ">=" instead of ">", then the largest value
+ * of the index is "endCondition - 1".
+ */
+ if (dInsn->arg[2] == OP_IF_GE) {
+ delta--;
+ }
+
+ if (delta) {
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
+ rlIdxEnd.lowReg = tReg;
+ dvmCompilerFreeTemp(cUnit, tReg);
+ }
+ /* Punt if "regIdxEnd < len(Array)" is false */
+ genRegRegCheck(cUnit, kMipsCondGe, rlIdxEnd.lowReg, regLength, 0,
+ (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
+}
+
+/*
+ * vA = arrayReg;
+ * vB = idxReg;
+ * vC = endConditionReg;
+ * arg[0] = maxC
+ * arg[1] = minC
+ * arg[2] = loopBranchConditionCode
+ */
+static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ const int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+ const int regLength = dvmCompilerAllocTemp(cUnit);
+ const int maxC = dInsn->arg[0];
+ RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
+ RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
+
+ /* regArray <- arrayRef */
+ rlArray = loadValue(cUnit, rlArray, kCoreReg);
+ rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
+ genRegImmCheck(cUnit, kMipsCondEq, rlArray.lowReg, 0, 0,
+ (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
+
+ /* regLength <- len(arrayRef) */
+ loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
+
+ if (maxC) {
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
+ rlIdxInit.lowReg = tReg;
+ dvmCompilerFreeTemp(cUnit, tReg);
+ }
+
+ /* Punt if "regIdxInit < len(Array)" is false */
+ genRegRegCheck(cUnit, kMipsCondGe, rlIdxInit.lowReg, regLength, 0,
+ (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
+}
+
+/*
+ * vA = idxReg;
+ * vB = minC;
+ */
+static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ const int minC = dInsn->vB;
+ RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
+
+ /* regIdx <- initial index value */
+ rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
+
+ /* Punt if "regIdxInit + minC >= 0" is false */
+ genRegImmCheck(cUnit, kMipsCondLt, rlIdx.lowReg, -minC, 0,
+ (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
+}
+
+/*
+ * vC = this
+ *
+ * A predicted inlining target looks like the following, where instructions
+ * between 0x2f130d24 and 0x2f130d40 are checking if the predicted class
+ * matches "this", and the verificaion code is generated by this routine.
+ *
+ * (C) means the instruction is inlined from the callee, and (PI) means the
+ * instruction is the predicted inlined invoke, whose corresponding
+ * instructions are still generated to handle the mispredicted case.
+ *
+ * D/dalvikvm( 2377): -------- kMirOpCheckInlinePrediction
+ * D/dalvikvm( 2377): 0x2f130d24 (0020): lw v0,16(s1)
+ * D/dalvikvm( 2377): 0x2f130d28 (0024): lui v1,0x0011(17)
+ * D/dalvikvm( 2377): 0x2f130d2c (0028): ori v1,v1,0x11e418(1172504)
+ * D/dalvikvm( 2377): 0x2f130d30 (002c): beqz v0,0x2f130df0 (L0x11f1f0)
+ * D/dalvikvm( 2377): 0x2f130d34 (0030): pref 0,0(v0)
+ * D/dalvikvm( 2377): 0x2f130d38 (0034): lw a0,0(v0)
+ * D/dalvikvm( 2377): 0x2f130d3c (0038): bne v1,a0,0x2f130d54 (L0x11f518)
+ * D/dalvikvm( 2377): 0x2f130d40 (003c): pref 0,8(v0)
+ * D/dalvikvm( 2377): -------- dalvik offset: 0x000a @ +iget-object-quick (C) v3, v4, (#8)
+ * D/dalvikvm( 2377): 0x2f130d44 (0040): lw a1,8(v0)
+ * D/dalvikvm( 2377): -------- dalvik offset: 0x000a @ +invoke-virtual-quick (PI) v4
+ * D/dalvikvm( 2377): 0x2f130d48 (0044): sw a1,12(s1)
+ * D/dalvikvm( 2377): 0x2f130d4c (0048): b 0x2f130e18 (L0x120150)
+ * D/dalvikvm( 2377): 0x2f130d50 (004c): lw a0,116(s2)
+ * D/dalvikvm( 2377): L0x11f518:
+ * D/dalvikvm( 2377): 0x2f130d54 (0050): lw a0,16(s1)
+ * D/dalvikvm( 2377): 0x2f130d58 (0054): addiu s4,s1,0xffffffe8(-24)
+ * D/dalvikvm( 2377): 0x2f130d5c (0058): beqz a0,0x2f130e00 (L0x11f618)
+ * D/dalvikvm( 2377): 0x2f130d60 (005c): pref 1,0(s4)
+ * D/dalvikvm( 2377): -------- BARRIER
+ * D/dalvikvm( 2377): 0x2f130d64 (0060): sw a0,0(s4)
+ * D/dalvikvm( 2377): 0x2f130d68 (0064): addiu s4,s4,0x0004(4)
+ * D/dalvikvm( 2377): -------- BARRIER
+ * D/dalvikvm( 2377): 0x2f130d6c (0068): lui s0,0x2d22(11554)
+ * D/dalvikvm( 2377): 0x2f130d70 (006c): ori s0,s0,0x2d228464(757236836)
+ * D/dalvikvm( 2377): 0x2f130d74 (0070): lahi/lui a1,0x2f13(12051)
+ * D/dalvikvm( 2377): 0x2f130d78 (0074): lalo/ori a1,a1,0x2f130ddc(789777884)
+ * D/dalvikvm( 2377): 0x2f130d7c (0078): lahi/lui a2,0x2f13(12051)
+ * D/dalvikvm( 2377): 0x2f130d80 (007c): lalo/ori a2,a2,0x2f130e24(789777956)
+ * D/dalvikvm( 2377): 0x2f130d84 (0080): jal 0x2f12d1ec(789762540)
+ * D/dalvikvm( 2377): 0x2f130d88 (0084): nop
+ * D/dalvikvm( 2377): 0x2f130d8c (0088): b 0x2f130e24 (L0x11ed6c)
+ * D/dalvikvm( 2377): 0x2f130d90 (008c): nop
+ * D/dalvikvm( 2377): 0x2f130d94 (0090): b 0x2f130e04 (L0x11ffd0)
+ * D/dalvikvm( 2377): 0x2f130d98 (0094): lui a0,0x2d22(11554)
+ * D/dalvikvm( 2377): 0x2f130d9c (0098): lw a0,44(s4)
+ * D/dalvikvm( 2377): 0x2f130da0 (009c): bgtz a1,0x2f130dc4 (L0x11fb98)
+ * D/dalvikvm( 2377): 0x2f130da4 (00a0): nop
+ * D/dalvikvm( 2377): 0x2f130da8 (00a4): lui t9,0x2aba(10938)
+ * D/dalvikvm( 2377): 0x2f130dac (00a8): ori t9,t9,0x2abae3f8(716891128)
+ * D/dalvikvm( 2377): 0x2f130db0 (00ac): move a1,s2
+ * D/dalvikvm( 2377): 0x2f130db4 (00b0): jalr ra,t9
+ * D/dalvikvm( 2377): 0x2f130db8 (00b4): nop
+ * D/dalvikvm( 2377): 0x2f130dbc (00b8): lw gp,84(sp)
+ * D/dalvikvm( 2377): 0x2f130dc0 (00bc): move a0,v0
+ * D/dalvikvm( 2377): 0x2f130dc4 (00c0): lahi/lui a1,0x2f13(12051)
+ * D/dalvikvm( 2377): 0x2f130dc8 (00c4): lalo/ori a1,a1,0x2f130ddc(789777884)
+ * D/dalvikvm( 2377): 0x2f130dcc (00c8): jal 0x2f12d0c4(789762244)
+ * D/dalvikvm( 2377): 0x2f130dd0 (00cc): nop
+ * D/dalvikvm( 2377): 0x2f130dd4 (00d0): b 0x2f130e04 (L0x11ffd0)
+ * D/dalvikvm( 2377): 0x2f130dd8 (00d4): lui a0,0x2d22(11554)
+ * D/dalvikvm( 2377): 0x2f130ddc (00d8): .align4
+ * D/dalvikvm( 2377): L0x11ed2c:
+ * D/dalvikvm( 2377): -------- dalvik offset: 0x000d @ move-result-object (PI) v3, (#0), (#0)
+ * D/dalvikvm( 2377): 0x2f130ddc (00d8): lw a2,16(s2)
+ * D/dalvikvm( 2377): 0x2f130de0 (00dc): sw a2,12(s1)
+ * D/dalvikvm( 2377): 0x2f130de4 (00e0): b 0x2f130e18 (L0x120150)
+ * D/dalvikvm( 2377): 0x2f130de8 (00e4): lw a0,116(s2)
+ * D/dalvikvm( 2377): 0x2f130dec (00e8): undefined
+ * D/dalvikvm( 2377): L0x11f1f0:
+ * D/dalvikvm( 2377): -------- reconstruct dalvik PC : 0x2d228464 @ +0x000a
+ * D/dalvikvm( 2377): 0x2f130df0 (00ec): lui a0,0x2d22(11554)
+ * D/dalvikvm( 2377): 0x2f130df4 (00f0): ori a0,a0,0x2d228464(757236836)
+ * D/dalvikvm( 2377): 0x2f130df8 (00f4): b 0x2f130e0c (L0x120090)
+ * D/dalvikvm( 2377): 0x2f130dfc (00f8): lw a1,108(s2)
+ * D/dalvikvm( 2377): L0x11f618:
+ * D/dalvikvm( 2377): -------- reconstruct dalvik PC : 0x2d228464 @ +0x000a
+ * D/dalvikvm( 2377): 0x2f130e00 (00fc): lui a0,0x2d22(11554)
+ * D/dalvikvm( 2377): 0x2f130e04 (0100): ori a0,a0,0x2d228464(757236836)
+ * D/dalvikvm( 2377): Exception_Handling:
+ * D/dalvikvm( 2377): 0x2f130e08 (0104): lw a1,108(s2)
+ * D/dalvikvm( 2377): 0x2f130e0c (0108): jalr ra,a1
+ * D/dalvikvm( 2377): 0x2f130e10 (010c): nop
+ * D/dalvikvm( 2377): 0x2f130e14 (0110): .align4
+ * D/dalvikvm( 2377): L0x11edac:
+ * D/dalvikvm( 2377): -------- chaining cell (hot): 0x000e
+ * D/dalvikvm( 2377): 0x2f130e14 (0110): lw a0,116(s2)
+ * D/dalvikvm( 2377): 0x2f130e18 (0114): jalr ra,a0
+ * D/dalvikvm( 2377): 0x2f130e1c (0118): nop
+ * D/dalvikvm( 2377): 0x2f130e20 (011c): data 0x2d22846c(757236844)
+ * D/dalvikvm( 2377): 0x2f130e24 (0120): .align4
+ * D/dalvikvm( 2377): L0x11ed6c:
+ * D/dalvikvm( 2377): -------- chaining cell (predicted)
+ * D/dalvikvm( 2377): 0x2f130e24 (0120): data 0xe7fe(59390)
+ * D/dalvikvm( 2377): 0x2f130e28 (0124): data 0x0000(0)
+ * D/dalvikvm( 2377): 0x2f130e2c (0128): data 0x0000(0)
+ * D/dalvikvm( 2377): 0x2f130e30 (012c): data 0x0000(0)
+ * D/dalvikvm( 2377): 0x2f130e34 (0130): data 0x0000(0)
+ */
+static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir)
+{
+ CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
+ RegLocation rlThis = cUnit->regLocation[mir->dalvikInsn.vC];
+
+ rlThis = loadValue(cUnit, rlThis, kCoreReg);
+ int regPredictedClass = dvmCompilerAllocTemp(cUnit);
+ loadClassPointer(cUnit, regPredictedClass, (int) callsiteInfo);
+ genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset,
+ NULL);/* null object? */
+ int regActualClass = dvmCompilerAllocTemp(cUnit);
+ loadWordDisp(cUnit, rlThis.lowReg, offsetof(Object, clazz), regActualClass);
+// opRegReg(cUnit, kOpCmp, regPredictedClass, regActualClass);
+ /*
+ * Set the misPredBranchOver target so that it will be generated when the
+ * code for the non-optimized invoke is generated.
+ */
+ callsiteInfo->misPredBranchOver = (LIR *) opCompareBranch(cUnit, kMipsBne, regPredictedClass, regActualClass);
+}
+
+/* Extended MIR instructions like PHI */
+static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
+{
+ int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
+ char *msg = (char *)dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
+ false);
+ strcpy(msg, extendedMIROpNames[opOffset]);
+ newLIR1(cUnit, kMipsPseudoExtended, (int) msg);
+
+ switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
+ case kMirOpPhi: {
+ char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
+ newLIR1(cUnit, kMipsPseudoSSARep, (int) ssaString);
+ break;
+ }
+ case kMirOpNullNRangeUpCheck: {
+ genHoistedChecksForCountUpLoop(cUnit, mir);
+ break;
+ }
+ case kMirOpNullNRangeDownCheck: {
+ genHoistedChecksForCountDownLoop(cUnit, mir);
+ break;
+ }
+ case kMirOpLowerBound: {
+ genHoistedLowerBoundCheck(cUnit, mir);
+ break;
+ }
+ case kMirOpPunt: {
+ genUnconditionalBranch(cUnit,
+ (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
+ break;
+ }
+ case kMirOpCheckInlinePrediction: {
+ genValidationForPredictedInline(cUnit, mir);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/*
+ * Create a PC-reconstruction cell for the starting offset of this trace.
+ * Since the PCR cell is placed near the end of the compiled code which is
+ * usually out of range for a conditional branch, we put two branches (one
+ * branch over to the loop body and one layover branch to the actual PCR) at the
+ * end of the entry block.
+ */
+static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
+ MipsLIR *bodyLabel)
+{
+ /* Set up the place holder to reconstruct this Dalvik PC */
+ MipsLIR *pcrLabel = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ pcrLabel->opcode = kMipsPseudoPCReconstructionCell;
+ pcrLabel->operands[0] =
+ (int) (cUnit->method->insns + entry->startOffset);
+ pcrLabel->operands[1] = entry->startOffset;
+ /* Insert the place holder to the growable list */
+ dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel);
+
+ /*
+ * Next, create two branches - one branch over to the loop body and the
+ * other branch to the PCR cell to punt.
+ */
+ MipsLIR *branchToBody = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ branchToBody->opcode = kMipsB;
+ branchToBody->generic.target = (LIR *) bodyLabel;
+ setupResourceMasks(branchToBody);
+ cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
+
+ MipsLIR *branchToPCR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ branchToPCR->opcode = kMipsB;
+ branchToPCR->generic.target = (LIR *) pcrLabel;
+ setupResourceMasks(branchToPCR);
+ cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
+}
+
+#if defined(WITH_SELF_VERIFICATION)
+static bool selfVerificationPuntOps(MIR *mir)
+{
+assert(0); /* MIPSTODO port selfVerificationPuntOps() */
+ DecodedInstruction *decInsn = &mir->dalvikInsn;
+
+ /*
+ * All opcodes that can throw exceptions and use the
+ * TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace
+ * under self-verification mode.
+ */
+ switch (decInsn->opcode) {
+ case OP_MONITOR_ENTER:
+ case OP_MONITOR_EXIT:
+ case OP_NEW_INSTANCE:
+ case OP_NEW_ARRAY:
+ case OP_CHECK_CAST:
+ case OP_MOVE_EXCEPTION:
+ case OP_FILL_ARRAY_DATA:
+ case OP_EXECUTE_INLINE:
+ case OP_EXECUTE_INLINE_RANGE:
+ return true;
+ default:
+ return false;
+ }
+}
+#endif
+
+void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
+{
+ /* Used to hold the labels of each block */
+ MipsLIR *labelList =
+ (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR) * cUnit->numBlocks, true);
+ MipsLIR *headLIR = NULL;
+ GrowableList chainingListByType[kChainingCellGap];
+ int i;
+
+ /*
+ * Initialize various types chaining lists.
+ */
+ for (i = 0; i < kChainingCellGap; i++) {
+ dvmInitGrowableList(&chainingListByType[i], 2);
+ }
+
+ /* Clear the visited flag for each block */
+ dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerClearVisitedFlag,
+ kAllNodes, false /* isIterative */);
+
+ GrowableListIterator iterator;
+ dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
+
+ /* Traces start with a profiling entry point. Generate it here */
+ cUnit->profileCodeSize = genTraceProfileEntry(cUnit);
+
+ /* Handle the content in each basic block */
+ for (i = 0; ; i++) {
+ MIR *mir;
+ BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+ if (bb == NULL) break;
+ if (bb->visited == true) continue;
+
+ labelList[i].operands[0] = bb->startOffset;
+
+ if (bb->blockType >= kChainingCellGap) {
+ if (bb->isFallThroughFromInvoke == true) {
+ /* Align this block first since it is a return chaining cell */
+ newLIR0(cUnit, kMipsPseudoPseudoAlign4);
+ }
+ /*
+ * Append the label pseudo LIR first. Chaining cells will be handled
+ * separately afterwards.
+ */
+ dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
+ }
+
+ if (bb->blockType == kEntryBlock) {
+ labelList[i].opcode = kMipsPseudoEntryBlock;
+ if (bb->firstMIRInsn == NULL) {
+ continue;
+ } else {
+ setupLoopEntryBlock(cUnit, bb,
+ &labelList[bb->fallThrough->id]);
+ }
+ } else if (bb->blockType == kExitBlock) {
+ labelList[i].opcode = kMipsPseudoExitBlock;
+ goto gen_fallthrough;
+ } else if (bb->blockType == kDalvikByteCode) {
+ if (bb->hidden == true) continue;
+ labelList[i].opcode = kMipsPseudoNormalBlockLabel;
+ /* Reset the register state */
+ dvmCompilerResetRegPool(cUnit);
+ dvmCompilerClobberAllRegs(cUnit);
+ dvmCompilerResetNullCheck(cUnit);
+ } else {
+ switch (bb->blockType) {
+ case kChainingCellNormal:
+ labelList[i].opcode = kMipsPseudoChainingCellNormal;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[kChainingCellNormal], i);
+ break;
+ case kChainingCellInvokeSingleton:
+ labelList[i].opcode =
+ kMipsPseudoChainingCellInvokeSingleton;
+ labelList[i].operands[0] =
+ (int) bb->containingMethod;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[kChainingCellInvokeSingleton], i);
+ break;
+ case kChainingCellInvokePredicted:
+ labelList[i].opcode =
+ kMipsPseudoChainingCellInvokePredicted;
+ /*
+ * Move the cached method pointer from operand 1 to 0.
+ * Operand 0 was clobbered earlier in this routine to store
+ * the block starting offset, which is not applicable to
+ * predicted chaining cell.
+ */
+ labelList[i].operands[0] = labelList[i].operands[1];
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[kChainingCellInvokePredicted], i);
+ break;
+ case kChainingCellHot:
+ labelList[i].opcode =
+ kMipsPseudoChainingCellHot;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[kChainingCellHot], i);
+ break;
+ case kPCReconstruction:
+ /* Make sure exception handling block is next */
+ labelList[i].opcode =
+ kMipsPseudoPCReconstructionBlockLabel;
+ handlePCReconstruction(cUnit,
+ &labelList[cUnit->puntBlock->id]);
+ break;
+ case kExceptionHandling:
+ labelList[i].opcode = kMipsPseudoEHBlockLabel;
+ if (cUnit->pcReconstructionList.numUsed) {
+ loadWordDisp(cUnit, rSELF, offsetof(Thread,
+ jitToInterpEntries.dvmJitToInterpPunt),
+ r_A1);
+ opReg(cUnit, kOpBlx, r_A1);
+ }
+ break;
+ case kChainingCellBackwardBranch:
+ labelList[i].opcode =
+ kMipsPseudoChainingCellBackwardBranch;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[kChainingCellBackwardBranch],
+ i);
+ break;
+ default:
+ break;
+ }
+ continue;
+ }
+
+ /*
+ * Try to build a longer optimization unit. Currently if the previous
+ * block ends with a goto, we continue adding instructions and don't
+ * reset the register allocation pool.
+ */
+ for (BasicBlock *nextBB = bb; nextBB != NULL; nextBB = cUnit->nextCodegenBlock) {
+ bb = nextBB;
+ bb->visited = true;
+ cUnit->nextCodegenBlock = NULL;
+
+ for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+
+ dvmCompilerResetRegPool(cUnit);
+ if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
+ dvmCompilerClobberAllRegs(cUnit);
+ }
+
+ if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
+ dvmCompilerResetDefTracking(cUnit);
+ }
+
+ if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
+ handleExtendedMIR(cUnit, mir);
+ continue;
+ }
+
+ Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+ InstructionFormat dalvikFormat =
+ dexGetFormatFromOpcode(dalvikOpcode);
+ const char *note;
+ if (mir->OptimizationFlags & MIR_INLINED) {
+ note = " (I)";
+ } else if (mir->OptimizationFlags & MIR_INLINED_PRED) {
+ note = " (PI)";
+ } else if (mir->OptimizationFlags & MIR_CALLEE) {
+ note = " (C)";
+ } else {
+ note = NULL;
+ }
+
+ MipsLIR *boundaryLIR =
+ newLIR2(cUnit, kMipsPseudoDalvikByteCodeBoundary,
+ mir->offset,
+ (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn,
+ note));
+ if (mir->ssaRep) {
+ char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
+ newLIR1(cUnit, kMipsPseudoSSARep, (int) ssaString);
+ }
+
+ /* Remember the first LIR for this block */
+ if (headLIR == NULL) {
+ headLIR = boundaryLIR;
+ /* Set the first boundaryLIR as a scheduling barrier */
+ headLIR->defMask = ENCODE_ALL;
+ }
+
+ bool notHandled;
+ /*
+ * Debugging: screen the opcode first to see if it is in the
+ * do[-not]-compile list
+ */
+ bool singleStepMe = SINGLE_STEP_OP(dalvikOpcode);
+#if defined(WITH_SELF_VERIFICATION)
+ if (singleStepMe == false) {
+ singleStepMe = selfVerificationPuntOps(mir);
+ }
+#endif
+ if (singleStepMe || cUnit->allSingleStep) {
+ notHandled = false;
+ genInterpSingleStep(cUnit, mir);
+ } else {
+ opcodeCoverage[dalvikOpcode]++;
+ switch (dalvikFormat) {
+ case kFmt10t:
+ case kFmt20t:
+ case kFmt30t:
+ notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
+ mir, bb, labelList);
+ break;
+ case kFmt10x:
+ notHandled = handleFmt10x(cUnit, mir);
+ break;
+ case kFmt11n:
+ case kFmt31i:
+ notHandled = handleFmt11n_Fmt31i(cUnit, mir);
+ break;
+ case kFmt11x:
+ notHandled = handleFmt11x(cUnit, mir);
+ break;
+ case kFmt12x:
+ notHandled = handleFmt12x(cUnit, mir);
+ break;
+ case kFmt20bc:
+ notHandled = handleFmt20bc(cUnit, mir);
+ break;
+ case kFmt21c:
+ case kFmt31c:
+ notHandled = handleFmt21c_Fmt31c(cUnit, mir);
+ break;
+ case kFmt21h:
+ notHandled = handleFmt21h(cUnit, mir);
+ break;
+ case kFmt21s:
+ notHandled = handleFmt21s(cUnit, mir);
+ break;
+ case kFmt21t:
+ notHandled = handleFmt21t(cUnit, mir, bb,
+ labelList);
+ break;
+ case kFmt22b:
+ case kFmt22s:
+ notHandled = handleFmt22b_Fmt22s(cUnit, mir);
+ break;
+ case kFmt22c:
+ notHandled = handleFmt22c(cUnit, mir);
+ break;
+ case kFmt22cs:
+ notHandled = handleFmt22cs(cUnit, mir);
+ break;
+ case kFmt22t:
+ notHandled = handleFmt22t(cUnit, mir, bb,
+ labelList);
+ break;
+ case kFmt22x:
+ case kFmt32x:
+ notHandled = handleFmt22x_Fmt32x(cUnit, mir);
+ break;
+ case kFmt23x:
+ notHandled = handleFmt23x(cUnit, mir);
+ break;
+ case kFmt31t:
+ notHandled = handleFmt31t(cUnit, mir);
+ break;
+ case kFmt3rc:
+ case kFmt35c:
+ notHandled = handleFmt35c_3rc(cUnit, mir, bb,
+ labelList);
+ break;
+ case kFmt3rms:
+ case kFmt35ms:
+ notHandled = handleFmt35ms_3rms(cUnit, mir,bb,
+ labelList);
+ break;
+ case kFmt35mi:
+ case kFmt3rmi:
+ notHandled = handleExecuteInline(cUnit, mir);
+ break;
+ case kFmt51l:
+ notHandled = handleFmt51l(cUnit, mir);
+ break;
+ default:
+ notHandled = true;
+ break;
+ }
+ }
+ if (notHandled) {
+ ALOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled",
+ mir->offset,
+ dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
+ dalvikFormat);
+ dvmCompilerAbort(cUnit);
+ break;
+ }
+ }
+ }
+
+ if (bb->blockType == kEntryBlock) {
+ dvmCompilerAppendLIR(cUnit,
+ (LIR *) cUnit->loopAnalysis->branchToBody);
+ dvmCompilerAppendLIR(cUnit,
+ (LIR *) cUnit->loopAnalysis->branchToPCR);
+ }
+
+ if (headLIR) {
+ /*
+ * Eliminate redundant loads/stores and delay stores into later
+ * slots
+ */
+ dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
+ cUnit->lastLIRInsn);
+ /* Reset headLIR which is also the optimization boundary */
+ headLIR = NULL;
+ }
+
+gen_fallthrough:
+ /*
+ * Check if the block is terminated due to trace length constraint -
+ * insert an unconditional branch to the chaining cell.
+ */
+ if (bb->needFallThroughBranch) {
+ genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+ }
+ }
+
+ /* Handle the chaining cells in predefined order */
+ for (i = 0; i < kChainingCellGap; i++) {
+ size_t j;
+ int *blockIdList = (int *) chainingListByType[i].elemList;
+
+ cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
+
+ /* No chaining cells of this type */
+ if (cUnit->numChainingCells[i] == 0)
+ continue;
+
+ /* Record the first LIR for a new type of chaining cell */
+ cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
+
+ for (j = 0; j < chainingListByType[i].numUsed; j++) {
+ int blockId = blockIdList[j];
+ BasicBlock *chainingBlock =
+ (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
+ blockId);
+
+ /* Align this chaining cell first */
+ newLIR0(cUnit, kMipsPseudoPseudoAlign4);
+
+ /* Insert the pseudo chaining instruction */
+ dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
+
+
+ switch (chainingBlock->blockType) {
+ case kChainingCellNormal:
+ handleNormalChainingCell(cUnit, chainingBlock->startOffset);
+ break;
+ case kChainingCellInvokeSingleton:
+ handleInvokeSingletonChainingCell(cUnit,
+ chainingBlock->containingMethod);
+ break;
+ case kChainingCellInvokePredicted:
+ handleInvokePredictedChainingCell(cUnit);
+ break;
+ case kChainingCellHot:
+ handleHotChainingCell(cUnit, chainingBlock->startOffset);
+ break;
+ case kChainingCellBackwardBranch:
+ handleBackwardBranchChainingCell(cUnit,
+ chainingBlock->startOffset);
+ break;
+ default:
+ ALOGE("Bad blocktype %d", chainingBlock->blockType);
+ dvmCompilerAbort(cUnit);
+ }
+ }
+ }
+
+ /* Mark the bottom of chaining cells */
+ cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kMipsChainingCellBottom);
+
+ /*
+ * Generate the branch to the dvmJitToInterpNoChain entry point at the end
+ * of all chaining cells for the overflow cases.
+ */
+ if (cUnit->switchOverflowPad) {
+ loadConstant(cUnit, r_A0, (int) cUnit->switchOverflowPad);
+ loadWordDisp(cUnit, rSELF, offsetof(Thread,
+ jitToInterpEntries.dvmJitToInterpNoChain), r_A2);
+ opRegReg(cUnit, kOpAdd, r_A1, r_A1);
+ opRegRegReg(cUnit, kOpAdd, r4PC, r_A0, r_A1);
+#if defined(WITH_JIT_TUNING)
+ loadConstant(cUnit, r_A0, kSwitchOverflow);
+#endif
+ opReg(cUnit, kOpBlx, r_A2);
+ }
+
+ dvmCompilerApplyGlobalOptimizations(cUnit);
+
+#if defined(WITH_SELF_VERIFICATION)
+ selfVerificationBranchInsertPass(cUnit);
+#endif
+}
+
+/*
+ * Accept the work and start compiling. Returns true if compilation
+ * is attempted.
+ */
+bool dvmCompilerDoWork(CompilerWorkOrder *work)
+{
+ JitTraceDescription *desc;
+ bool isCompile;
+ bool success = true;
+
+ if (gDvmJit.codeCacheFull) {
+ return false;
+ }
+
+ switch (work->kind) {
+ case kWorkOrderTrace:
+ isCompile = true;
+ /* Start compilation with maximally allowed trace length */
+ desc = (JitTraceDescription *)work->info;
+ success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
+ work->bailPtr, 0 /* no hints */);
+ break;
+ case kWorkOrderTraceDebug: {
+ bool oldPrintMe = gDvmJit.printMe;
+ gDvmJit.printMe = true;
+ isCompile = true;
+ /* Start compilation with maximally allowed trace length */
+ desc = (JitTraceDescription *)work->info;
+ success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
+ work->bailPtr, 0 /* no hints */);
+ gDvmJit.printMe = oldPrintMe;
+ break;
+ }
+ case kWorkOrderProfileMode:
+ dvmJitChangeProfileMode((TraceProfilingModes)(int)work->info);
+ isCompile = false;
+ break;
+ default:
+ isCompile = false;
+ ALOGE("Jit: unknown work order type");
+ assert(0); // Bail if debug build, discard otherwise
+ }
+ if (!success)
+ work->result.codeAddress = NULL;
+ return isCompile;
+}
+
+/* Architectural-specific debugging helpers go here */
+void dvmCompilerArchDump(void)
+{
+ /* Print compiled opcode in this VM instance */
+ int i, start, streak;
+ char buf[1024];
+
+ streak = i = 0;
+ buf[0] = 0;
+ while (opcodeCoverage[i] == 0 && i < 256) {
+ i++;
+ }
+ if (i == 256) {
+ return;
+ }
+ for (start = i++, streak = 1; i < 256; i++) {
+ if (opcodeCoverage[i]) {
+ streak++;
+ } else {
+ if (streak == 1) {
+ sprintf(buf+strlen(buf), "%x,", start);
+ } else {
+ sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
+ }
+ streak = 0;
+ while (opcodeCoverage[i] == 0 && i < 256) {
+ i++;
+ }
+ if (i < 256) {
+ streak = 1;
+ start = i;
+ }
+ }
+ }
+ if (streak) {
+ if (streak == 1) {
+ sprintf(buf+strlen(buf), "%x", start);
+ } else {
+ sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
+ }
+ }
+ if (strlen(buf)) {
+ ALOGD("dalvik.vm.jit.op = %s", buf);
+ }
+}
+
+/* Common initialization routine for an architecture family */
+bool dvmCompilerArchInit()
+{
+ int i;
+
+ for (i = 0; i < kMipsLast; i++) {
+ if (EncodingMap[i].opcode != i) {
+ ALOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
+ EncodingMap[i].name, i, EncodingMap[i].opcode);
+ dvmAbort(); // OK to dvmAbort - build error
+ }
+ }
+
+ return dvmCompilerArchVariantInit();
+}
+
+void *dvmCompilerGetInterpretTemplate()
+{
+ return (void*) ((int)gDvmJit.codeCache +
+ templateEntryOffsets[TEMPLATE_INTERPRET]);
+}
+
+JitInstructionSetType dvmCompilerGetInterpretTemplateSet()
+{
+ return DALVIK_JIT_MIPS;
+}
+
+/* Needed by the Assembler */
+void dvmCompilerSetupResourceMasks(MipsLIR *lir)
+{
+ setupResourceMasks(lir);
+}
+
+/* Needed by the ld/st optmizatons */
+MipsLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+ return genRegCopyNoInsert(cUnit, rDest, rSrc);
+}
+
+/* Needed by the register allocator */
+MipsLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+ return genRegCopy(cUnit, rDest, rSrc);
+}
+
+/* Needed by the register allocator */
+void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+ int srcLo, int srcHi)
+{
+ genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
+}
+
+void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc, OpSize size)
+{
+ storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
+}
+
+void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrcLo, int rSrcHi)
+{
+ storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
+}
diff --git a/vm/compiler/codegen/mips/CodegenFactory.cpp b/vm/compiler/codegen/mips/CodegenFactory.cpp
new file mode 100644
index 0000000..a1211cc
--- /dev/null
+++ b/vm/compiler/codegen/mips/CodegenFactory.cpp
@@ -0,0 +1,349 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen and support common to all supported
+ * Mips variants. It is included by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ * which combines this common code with specific support found in the
+ * applicable directory below this one.
+ */
+
+
+/* Load a word at base + displacement. Displacement must be word multiple */
+static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
+ int rDest)
+{
+ return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord,
+ INVALID_SREG);
+}
+
+static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc)
+{
+ return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
+}
+
+/*
+ * Load a Dalvik register into a physical register. Take care when
+ * using this routine, as it doesn't perform any bookkeeping regarding
+ * register liveness. That is the responsibility of the caller.
+ */
+static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
+ int reg1)
+{
+ rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
+ if (rlSrc.location == kLocPhysReg) {
+ genRegCopy(cUnit, reg1, rlSrc.lowReg);
+ } else if (rlSrc.location == kLocRetval) {
+ loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), reg1);
+ } else {
+ assert(rlSrc.location == kLocDalvikFrame);
+ loadWordDisp(cUnit, rFP, dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
+ reg1);
+ }
+}
+
+/*
+ * Similar to loadValueDirect, but clobbers and allocates the target
+ * register. Should be used when loading to a fixed register (for example,
+ * loading arguments to an out of line call.
+ */
+static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
+ int reg1)
+{
+ dvmCompilerClobber(cUnit, reg1);
+ dvmCompilerMarkInUse(cUnit, reg1);
+ loadValueDirect(cUnit, rlSrc, reg1);
+}
+
+/*
+ * Load a Dalvik register pair into a physical register[s]. Take care when
+ * using this routine, as it doesn't perform any bookkeeping regarding
+ * register liveness. That is the responsibility of the caller.
+ */
+static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
+ int regLo, int regHi)
+{
+ rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
+ if (rlSrc.location == kLocPhysReg) {
+ genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
+ } else if (rlSrc.location == kLocRetval) {
+ loadBaseDispWide(cUnit, NULL, rSELF, offsetof(Thread, interpSave.retval),
+ regLo, regHi, INVALID_SREG);
+ } else {
+ assert(rlSrc.location == kLocDalvikFrame);
+ loadBaseDispWide(cUnit, NULL, rFP,
+ dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
+ regLo, regHi, INVALID_SREG);
+ }
+}
+
+/*
+ * Similar to loadValueDirect, but clobbers and allocates the target
+ * registers. Should be used when loading to a fixed registers (for example,
+ * loading arguments to an out of line call.
+ */
+static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
+ int regLo, int regHi)
+{
+ dvmCompilerClobber(cUnit, regLo);
+ dvmCompilerClobber(cUnit, regHi);
+ dvmCompilerMarkInUse(cUnit, regLo);
+ dvmCompilerMarkInUse(cUnit, regHi);
+ loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
+}
+
+static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
+ RegisterClass opKind)
+{
+ rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
+ if (rlSrc.location == kLocDalvikFrame) {
+ loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
+ rlSrc.location = kLocPhysReg;
+ dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
+ } else if (rlSrc.location == kLocRetval) {
+ loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), rlSrc.lowReg);
+ rlSrc.location = kLocPhysReg;
+ dvmCompilerClobber(cUnit, rlSrc.lowReg);
+ }
+ return rlSrc;
+}
+
+static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ LIR *defStart;
+ LIR *defEnd;
+ assert(!rlDest.wide);
+ assert(!rlSrc.wide);
+ dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
+ rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
+ rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
+ if (rlSrc.location == kLocPhysReg) {
+ if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
+ (rlDest.location == kLocPhysReg)) {
+ // Src is live or Dest has assigned reg.
+ rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
+ genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
+ } else {
+ // Just re-assign the registers. Dest gets Src's regs
+ rlDest.lowReg = rlSrc.lowReg;
+ dvmCompilerClobber(cUnit, rlSrc.lowReg);
+ }
+ } else {
+ // Load Src either into promoted Dest or temps allocated for Dest
+ rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
+ loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
+ }
+
+ // Dest is now live and dirty (until/if we flush it to home location)
+ dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
+ dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
+
+
+ if (rlDest.location == kLocRetval) {
+ storeBaseDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval),
+ rlDest.lowReg, kWord);
+ dvmCompilerClobber(cUnit, rlDest.lowReg);
+ } else {
+ dvmCompilerResetDefLoc(cUnit, rlDest);
+ if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) {
+ defStart = (LIR *)cUnit->lastLIRInsn;
+ int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
+ storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
+ dvmCompilerMarkClean(cUnit, rlDest.lowReg);
+ defEnd = (LIR *)cUnit->lastLIRInsn;
+ dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd);
+ }
+ }
+}
+
+static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
+ RegisterClass opKind)
+{
+ assert(rlSrc.wide);
+ rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
+ if (rlSrc.location == kLocDalvikFrame) {
+ loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
+ rlSrc.location = kLocPhysReg;
+ dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
+ dvmCompilerMarkLive(cUnit, rlSrc.highReg,
+ dvmCompilerSRegHi(rlSrc.sRegLow));
+ } else if (rlSrc.location == kLocRetval) {
+ loadBaseDispWide(cUnit, NULL, rSELF, offsetof(Thread, interpSave.retval),
+ rlSrc.lowReg, rlSrc.highReg, INVALID_SREG);
+ rlSrc.location = kLocPhysReg;
+ dvmCompilerClobber(cUnit, rlSrc.lowReg);
+ dvmCompilerClobber(cUnit, rlSrc.highReg);
+ }
+ return rlSrc;
+}
+
+static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ LIR *defStart;
+ LIR *defEnd;
+ assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
+ assert(rlDest.wide);
+ assert(rlSrc.wide);
+ dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
+ if (rlSrc.location == kLocPhysReg) {
+ if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
+ dvmCompilerIsLive(cUnit, rlSrc.highReg) ||
+ (rlDest.location == kLocPhysReg)) {
+ // Src is live or Dest has assigned reg.
+ rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
+ genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
+ rlSrc.lowReg, rlSrc.highReg);
+ } else {
+ // Just re-assign the registers. Dest gets Src's regs
+ rlDest.lowReg = rlSrc.lowReg;
+ rlDest.highReg = rlSrc.highReg;
+ dvmCompilerClobber(cUnit, rlSrc.lowReg);
+ dvmCompilerClobber(cUnit, rlSrc.highReg);
+ }
+ } else {
+ // Load Src either into promoted Dest or temps allocated for Dest
+ rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
+ loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
+ rlDest.highReg);
+ }
+
+ // Dest is now live and dirty (until/if we flush it to home location)
+ dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
+ dvmCompilerMarkLive(cUnit, rlDest.highReg,
+ dvmCompilerSRegHi(rlDest.sRegLow));
+ dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
+ dvmCompilerMarkDirty(cUnit, rlDest.highReg);
+ dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
+
+
+ if (rlDest.location == kLocRetval) {
+ storeBaseDispWide(cUnit, rSELF, offsetof(Thread, interpSave.retval),
+ rlDest.lowReg, rlDest.highReg);
+ dvmCompilerClobber(cUnit, rlDest.lowReg);
+ dvmCompilerClobber(cUnit, rlDest.highReg);
+ } else {
+ dvmCompilerResetDefLocWide(cUnit, rlDest);
+ if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) ||
+ dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) {
+ defStart = (LIR *)cUnit->lastLIRInsn;
+ int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
+ assert((vReg+1) == dvmCompilerS2VReg(cUnit,
+ dvmCompilerSRegHi(rlDest.sRegLow)));
+ storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
+ rlDest.highReg);
+ dvmCompilerMarkClean(cUnit, rlDest.lowReg);
+ dvmCompilerMarkClean(cUnit, rlDest.highReg);
+ defEnd = (LIR *)cUnit->lastLIRInsn;
+ dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd);
+ }
+ }
+}
+/*
+ * Perform null-check on a register. sReg is the ssa register being checked,
+ * and mReg is the machine register holding the actual value. If internal state
+ * indicates that sReg has been checked before the check request is ignored.
+ */
+static MipsLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
+ int dOffset, MipsLIR *pcrLabel)
+{
+ /* This particular Dalvik register has been null-checked */
+ if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
+ return pcrLabel;
+ }
+ dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
+ return genRegImmCheck(cUnit, kMipsCondEq, mReg, 0, dOffset, pcrLabel);
+}
+
+
+
+/*
+ * Perform a "reg cmp reg" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
+ MipsConditionCode cond,
+ int reg1, int reg2, int dOffset,
+ MipsLIR *pcrLabel)
+{
+ MipsLIR *res = NULL;
+ if (cond == kMipsCondGe) { /* signed >= case */
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ res = newLIR3(cUnit, kMipsSlt, tReg, reg1, reg2);
+ MipsLIR *branch = opCompareBranch(cUnit, kMipsBeqz, tReg, -1);
+ genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+ } else if (cond == kMipsCondCs) { /* unsigned >= case */
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ res = newLIR3(cUnit, kMipsSltu, tReg, reg1, reg2);
+ MipsLIR *branch = opCompareBranch(cUnit, kMipsBeqz, tReg, -1);
+ genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+ } else {
+ ALOGE("Unexpected condition in genRegRegCheck: %d\n", (int) cond);
+ dvmAbort();
+ }
+ return res;
+}
+
+/*
+ * Perform zero-check on a register. Similar to genNullCheck but the value being
+ * checked does not have a corresponding Dalvik register.
+ */
+static MipsLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
+ int dOffset, MipsLIR *pcrLabel)
+{
+ return genRegImmCheck(cUnit, kMipsCondEq, mReg, 0, dOffset, pcrLabel);
+}
+
+/* Perform bound check on two registers */
+static MipsLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
+ int rBound, int dOffset, MipsLIR *pcrLabel)
+{
+ return genRegRegCheck(cUnit, kMipsCondCs, rIndex, rBound, dOffset,
+ pcrLabel);
+}
+
+/*
+ * Jump to the out-of-line handler to finish executing the
+ * remaining of more complex instructions.
+ */
+static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpcode opCode)
+{
+ /*
+ * We're jumping from a trace to a template. Using jal is preferable to jalr,
+ * but we need to ensure source and target addresses allow the use of jal.
+ * This should almost always be the case, but if source and target are in
+ * different 256mb regions then use jalr. The test below is very conservative
+ * since we don't have a source address yet, but this is ok for now given that
+ * we expect this case to be very rare. The test can be made less conservative
+ * as needed in the future in coordination with address assignment during
+ * the assembly process.
+ */
+ dvmCompilerClobberHandlerRegs(cUnit);
+ int targetAddr = (int) gDvmJit.codeCache + templateEntryOffsets[opCode];
+ int maxSourceAddr = (int) gDvmJit.codeCache + gDvmJit.codeCacheSize;
+
+ if ((targetAddr & 0xF0000000) == (maxSourceAddr & 0xF0000000)) {
+ newLIR1(cUnit, kMipsJal, targetAddr);
+ } else {
+ loadConstant(cUnit, r_T9, targetAddr);
+ newLIR2(cUnit, kMipsJalr, r_RA, r_T9);
+ }
+}
diff --git a/vm/compiler/codegen/mips/FP/MipsFP.cpp b/vm/compiler/codegen/mips/FP/MipsFP.cpp
new file mode 100644
index 0000000..cf44b0e
--- /dev/null
+++ b/vm/compiler/codegen/mips/FP/MipsFP.cpp
@@ -0,0 +1,409 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is included by Codegen-armv5te-vfp.c, and implements architecture
+ * variant-specific code.
+ */
+
+extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
+ int reg1, int reg2);
+extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg);
+
+/* First, flush any registers associated with this value */
+static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc,
+ int rDest)
+{
+ rlSrc = rlSrc.wide ? dvmCompilerUpdateLocWide(cUnit, rlSrc) :
+ dvmCompilerUpdateLoc(cUnit, rlSrc);
+ if (rlSrc.location == kLocPhysReg) {
+ if (rlSrc.wide) {
+ dvmCompilerFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg,
+ rlSrc.highReg);
+ } else {
+ dvmCompilerFlushRegForV5TEVFP(cUnit, rlSrc.lowReg);
+ }
+ }
+ opRegRegImm(cUnit, kOpAdd, rDest, rFP,
+ dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2);
+}
+
+static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+#ifdef __mips_hard_float
+ RegLocation rlResult = LOC_C_RETURN_WIDE_ALT;
+#else
+ RegLocation rlResult = LOC_C_RETURN_WIDE;
+#endif
+ RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
+ loadValueAddress(cUnit, rlSrc, r_A2);
+ genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP);
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+}
+
+/*
+ * TUNING: On some implementations, it is quicker to pass addresses
+ * to the handlers rather than load the operands into core registers
+ * and then move the values to FP regs in the handlers. Other implementations
+ * may prefer passing data in registers (and the latter approach would
+ * yeild cleaner register handling - avoiding the requirement that operands
+ * be flushed to memory prior to the call).
+ */
+static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+#ifdef __mips_hard_float
+ int op = kMipsNop;
+ RegLocation rlResult;
+
+ /*
+ * Don't attempt to optimize register usage since these opcodes call out to
+ * the handlers.
+ */
+ switch (mir->dalvikInsn.opcode) {
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_ADD_FLOAT:
+ op = kMipsFadds;
+ break;
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_SUB_FLOAT:
+ op = kMipsFsubs;
+ break;
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_DIV_FLOAT:
+ op = kMipsFdivs;
+ break;
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_MUL_FLOAT:
+ op = kMipsFmuls;
+ break;
+ case OP_REM_FLOAT_2ADDR:
+ case OP_REM_FLOAT:
+ case OP_NEG_FLOAT: {
+ return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+ }
+ default:
+ return true;
+ }
+ rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
+ rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR3(cUnit, (MipsOpCode)op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+
+ return false;
+#else
+ TemplateOpcode opcode;
+
+ /*
+ * Don't attempt to optimize register usage since these opcodes call out to
+ * the handlers.
+ */
+ switch (mir->dalvikInsn.opcode) {
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_ADD_FLOAT:
+ opcode = TEMPLATE_ADD_FLOAT_VFP;
+ break;
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_SUB_FLOAT:
+ opcode = TEMPLATE_SUB_FLOAT_VFP;
+ break;
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_DIV_FLOAT:
+ opcode = TEMPLATE_DIV_FLOAT_VFP;
+ break;
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_MUL_FLOAT:
+ opcode = TEMPLATE_MUL_FLOAT_VFP;
+ break;
+ case OP_REM_FLOAT_2ADDR:
+ case OP_REM_FLOAT:
+ case OP_NEG_FLOAT: {
+ return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+ }
+ default:
+ return true;
+ }
+ loadValueAddress(cUnit, rlDest, r_A0);
+ dvmCompilerClobber(cUnit, r_A0);
+ loadValueAddress(cUnit, rlSrc1, r_A1);
+ dvmCompilerClobber(cUnit, r_A1);
+ loadValueAddress(cUnit, rlSrc2, r_A2);
+ genDispatchToHandler(cUnit, opcode);
+ rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
+ if (rlDest.location == kLocPhysReg) {
+ dvmCompilerClobber(cUnit, rlDest.lowReg);
+ }
+ return false;
+#endif
+}
+
+static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+#ifdef __mips_hard_float
+ int op = kMipsNop;
+ RegLocation rlResult;
+
+ switch (mir->dalvikInsn.opcode) {
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_ADD_DOUBLE:
+ op = kMipsFaddd;
+ break;
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE:
+ op = kMipsFsubd;
+ break;
+ case OP_DIV_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE:
+ op = kMipsFdivd;
+ break;
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE:
+ op = kMipsFmuld;
+ break;
+ case OP_REM_DOUBLE_2ADDR:
+ case OP_REM_DOUBLE:
+ case OP_NEG_DOUBLE: {
+ return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+ }
+ default:
+ return true;
+ }
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
+ assert(rlSrc1.wide);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
+ assert(rlSrc2.wide);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+ assert(rlDest.wide);
+ assert(rlResult.wide);
+ newLIR3(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg),
+ S2D(rlSrc1.lowReg, rlSrc1.highReg),
+ S2D(rlSrc2.lowReg, rlSrc2.highReg));
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+#else
+ TemplateOpcode opcode;
+
+ switch (mir->dalvikInsn.opcode) {
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_ADD_DOUBLE:
+ opcode = TEMPLATE_ADD_DOUBLE_VFP;
+ break;
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE:
+ opcode = TEMPLATE_SUB_DOUBLE_VFP;
+ break;
+ case OP_DIV_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE:
+ opcode = TEMPLATE_DIV_DOUBLE_VFP;
+ break;
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE:
+ opcode = TEMPLATE_MUL_DOUBLE_VFP;
+ break;
+ case OP_REM_DOUBLE_2ADDR:
+ case OP_REM_DOUBLE:
+ case OP_NEG_DOUBLE: {
+ return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
+ rlSrc2);
+ }
+ default:
+ return true;
+ }
+ loadValueAddress(cUnit, rlDest, r_A0);
+ dvmCompilerClobber(cUnit, r_A0);
+ loadValueAddress(cUnit, rlSrc1, r_A1);
+ dvmCompilerClobber(cUnit, r_A1);
+ loadValueAddress(cUnit, rlSrc2, r_A2);
+ genDispatchToHandler(cUnit, opcode);
+ rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
+ if (rlDest.location == kLocPhysReg) {
+ dvmCompilerClobber(cUnit, rlDest.lowReg);
+ dvmCompilerClobber(cUnit, rlDest.highReg);
+ }
+ return false;
+#endif
+}
+
+static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+{
+ Opcode opcode = mir->dalvikInsn.opcode;
+ bool longSrc = false;
+ bool longDest = false;
+ RegLocation rlSrc;
+ RegLocation rlDest;
+#ifdef __mips_hard_float
+ int op = kMipsNop;
+ int srcReg;
+ RegLocation rlResult;
+
+ switch (opcode) {
+ case OP_INT_TO_FLOAT:
+ longSrc = false;
+ longDest = false;
+ op = kMipsFcvtsw;
+ break;
+ case OP_DOUBLE_TO_FLOAT:
+ longSrc = true;
+ longDest = false;
+ op = kMipsFcvtsd;
+ break;
+ case OP_FLOAT_TO_DOUBLE:
+ longSrc = false;
+ longDest = true;
+ op = kMipsFcvtds;
+ break;
+ case OP_INT_TO_DOUBLE:
+ longSrc = false;
+ longDest = true;
+ op = kMipsFcvtdw;
+ break;
+ case OP_FLOAT_TO_INT:
+ case OP_DOUBLE_TO_INT:
+ case OP_LONG_TO_DOUBLE:
+ case OP_FLOAT_TO_LONG:
+ case OP_LONG_TO_FLOAT:
+ case OP_DOUBLE_TO_LONG:
+ return genConversionPortable(cUnit, mir);
+ default:
+ return true;
+ }
+ if (longSrc) {
+ rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+ srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
+ } else {
+ rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+ srcReg = rlSrc.lowReg;
+ }
+ if (longDest) {
+ rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR2(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else {
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR2(cUnit, (MipsOpCode)op, rlResult.lowReg, srcReg);
+ storeValue(cUnit, rlDest, rlResult);
+ }
+ return false;
+#else
+ TemplateOpcode templateOpcode;
+ switch (opcode) {
+ case OP_INT_TO_FLOAT:
+ longSrc = false;
+ longDest = false;
+ templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP;
+ break;
+ case OP_FLOAT_TO_INT:
+ longSrc = false;
+ longDest = false;
+ templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP;
+ break;
+ case OP_DOUBLE_TO_FLOAT:
+ longSrc = true;
+ longDest = false;
+ templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
+ break;
+ case OP_FLOAT_TO_DOUBLE:
+ longSrc = false;
+ longDest = true;
+ templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
+ break;
+ case OP_INT_TO_DOUBLE:
+ longSrc = false;
+ longDest = true;
+ templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP;
+ break;
+ case OP_DOUBLE_TO_INT:
+ longSrc = true;
+ longDest = false;
+ templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP;
+ break;
+ case OP_LONG_TO_DOUBLE:
+ case OP_FLOAT_TO_LONG:
+ case OP_LONG_TO_FLOAT:
+ case OP_DOUBLE_TO_LONG:
+ return genConversionPortable(cUnit, mir);
+ default:
+ return true;
+ }
+
+ if (longSrc) {
+ rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ } else {
+ rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ }
+
+ if (longDest) {
+ rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+ } else {
+ rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+ }
+ loadValueAddress(cUnit, rlDest, r_A0);
+ dvmCompilerClobber(cUnit, r_A0);
+ loadValueAddress(cUnit, rlSrc, r_A1);
+ genDispatchToHandler(cUnit, templateOpcode);
+ if (rlDest.wide) {
+ rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
+ dvmCompilerClobber(cUnit, rlDest.highReg);
+ } else {
+ rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
+ }
+ dvmCompilerClobber(cUnit, rlDest.lowReg);
+ return false;
+#endif
+}
+
+static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ TemplateOpcode templateOpcode;
+ RegLocation rlResult = dvmCompilerGetReturn(cUnit);
+ bool wide = true;
+
+ switch(mir->dalvikInsn.opcode) {
+ case OP_CMPL_FLOAT:
+ templateOpcode = TEMPLATE_CMPL_FLOAT_VFP;
+ wide = false;
+ break;
+ case OP_CMPG_FLOAT:
+ templateOpcode = TEMPLATE_CMPG_FLOAT_VFP;
+ wide = false;
+ break;
+ case OP_CMPL_DOUBLE:
+ templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP;
+ break;
+ case OP_CMPG_DOUBLE:
+ templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP;
+ break;
+ default:
+ return true;
+ }
+ loadValueAddress(cUnit, rlSrc1, r_A0);
+ dvmCompilerClobber(cUnit, r_A0);
+ loadValueAddress(cUnit, rlSrc2, r_A1);
+ genDispatchToHandler(cUnit, templateOpcode);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
diff --git a/vm/compiler/codegen/mips/GlobalOptimizations.cpp b/vm/compiler/codegen/mips/GlobalOptimizations.cpp
new file mode 100644
index 0000000..189d818
--- /dev/null
+++ b/vm/compiler/codegen/mips/GlobalOptimizations.cpp
@@ -0,0 +1,422 @@
+/*
+ * 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.
+ */
+
+#include "Dalvik.h"
+#include "vm/compiler/CompilerInternals.h"
+#include "MipsLIR.h"
+
+/*
+ * Identify unconditional branches that jump to the immediate successor of the
+ * branch itself.
+ */
+static void applyRedundantBranchElimination(CompilationUnit *cUnit)
+{
+ MipsLIR *thisLIR;
+
+ for (thisLIR = (MipsLIR *) cUnit->firstLIRInsn;
+ thisLIR != (MipsLIR *) cUnit->lastLIRInsn;
+ thisLIR = NEXT_LIR(thisLIR)) {
+
+ /* Branch to the next instruction */
+ if (!thisLIR->flags.isNop && thisLIR->opcode == kMipsB) {
+ MipsLIR *nextLIR = thisLIR;
+
+ while (true) {
+ nextLIR = NEXT_LIR(nextLIR);
+
+ /*
+ * Is the branch target the next instruction?
+ */
+ if (nextLIR == (MipsLIR *) thisLIR->generic.target) {
+ thisLIR->flags.isNop = true;
+ break;
+ }
+
+ /*
+ * Found real useful stuff between the branch and the target.
+ * Need to explicitly check the lastLIRInsn here since with
+ * method-based JIT the branch might be the last real
+ * instruction.
+ */
+ if (!isPseudoOpCode(nextLIR->opcode) ||
+ (nextLIR = (MipsLIR *) cUnit->lastLIRInsn))
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Do simple a form of copy propagation and elimination.
+ */
+static void applyCopyPropagation(CompilationUnit *cUnit)
+{
+ MipsLIR *thisLIR;
+
+ /* look for copies to possibly eliminate */
+ for (thisLIR = (MipsLIR *) cUnit->firstLIRInsn;
+ thisLIR != (MipsLIR *) cUnit->lastLIRInsn;
+ thisLIR = NEXT_LIR(thisLIR)) {
+
+ if (thisLIR->flags.isNop || thisLIR->opcode != kMipsMove)
+ continue;
+
+ const int max_insns = 10;
+ MipsLIR *savedLIR[max_insns];
+ int srcRedefined = 0;
+ int insnCount = 0;
+ MipsLIR *nextLIR;
+
+ /* look for and record all uses of reg defined by the copy */
+ for (nextLIR = (MipsLIR *) NEXT_LIR(thisLIR);
+ nextLIR != (MipsLIR *) cUnit->lastLIRInsn;
+ nextLIR = NEXT_LIR(nextLIR)) {
+
+ if (nextLIR->flags.isNop || nextLIR->opcode == kMips32BitData)
+ continue;
+
+ if (isPseudoOpCode(nextLIR->opcode)) {
+ if (nextLIR->opcode == kMipsPseudoDalvikByteCodeBoundary ||
+ nextLIR->opcode == kMipsPseudoBarrier ||
+ nextLIR->opcode == kMipsPseudoExtended ||
+ nextLIR->opcode == kMipsPseudoSSARep)
+ continue; /* these pseudos don't pose problems */
+ else if (nextLIR->opcode == kMipsPseudoTargetLabel ||
+ nextLIR->opcode == kMipsPseudoEntryBlock ||
+ nextLIR->opcode == kMipsPseudoExitBlock)
+ insnCount = 0; /* give up for these pseudos */
+ break; /* reached end for copy propagation */
+ }
+
+ /* Since instructions with IS_BRANCH flag set will have its */
+ /* useMask and defMask set to ENCODE_ALL, any checking of */
+ /* these flags must come after the branching checks. */
+
+ /* don't propagate across branch/jump and link case
+ or jump via register */
+ if (EncodingMap[nextLIR->opcode].flags & REG_DEF_LR ||
+ nextLIR->opcode == kMipsJalr ||
+ nextLIR->opcode == kMipsJr) {
+ insnCount = 0;
+ break;
+ }
+
+ /* branches with certain targets ok while others aren't */
+ if (EncodingMap[nextLIR->opcode].flags & IS_BRANCH) {
+ MipsLIR *targetLIR = (MipsLIR *) nextLIR->generic.target;
+ if (targetLIR->opcode != kMipsPseudoEHBlockLabel &&
+ targetLIR->opcode != kMipsPseudoChainingCellHot &&
+ targetLIR->opcode != kMipsPseudoChainingCellNormal &&
+ targetLIR->opcode != kMipsPseudoChainingCellInvokePredicted &&
+ targetLIR->opcode != kMipsPseudoChainingCellInvokeSingleton &&
+ targetLIR->opcode != kMipsPseudoPCReconstructionBlockLabel &&
+ targetLIR->opcode != kMipsPseudoPCReconstructionCell) {
+ insnCount = 0;
+ break;
+ }
+ /* FIXME - for now don't propagate across any branch/jump. */
+ insnCount = 0;
+ break;
+ }
+
+ /* copy def reg used here, so record insn for copy propagation */
+ if (thisLIR->defMask & nextLIR->useMask) {
+ if (insnCount == max_insns || srcRedefined) {
+ insnCount = 0;
+ break; /* just give up if too many or not possible */
+ }
+ savedLIR[insnCount++] = nextLIR;
+ }
+
+ if (thisLIR->defMask & nextLIR->defMask) {
+ if (nextLIR->opcode == kMipsMovz)
+ insnCount = 0; /* movz relies on thisLIR setting dst reg so abandon propagation*/
+ break;
+ }
+
+ /* copy src reg redefined here, so can't propagate further */
+ if (thisLIR->useMask & nextLIR->defMask) {
+ if (insnCount == 0)
+ break; /* nothing to propagate */
+ srcRedefined = 1;
+ }
+ }
+
+ /* conditions allow propagation and copy elimination */
+ if (insnCount) {
+ int i;
+ for (i = 0; i < insnCount; i++) {
+ int flags = EncodingMap[savedLIR[i]->opcode].flags;
+ savedLIR[i]->useMask &= ~(1 << thisLIR->operands[0]);
+ savedLIR[i]->useMask |= 1 << thisLIR->operands[1];
+ if ((flags & REG_USE0) &&
+ savedLIR[i]->operands[0] == thisLIR->operands[0])
+ savedLIR[i]->operands[0] = thisLIR->operands[1];
+ if ((flags & REG_USE1) &&
+ savedLIR[i]->operands[1] == thisLIR->operands[0])
+ savedLIR[i]->operands[1] = thisLIR->operands[1];
+ if ((flags & REG_USE2) &&
+ savedLIR[i]->operands[2] == thisLIR->operands[0])
+ savedLIR[i]->operands[2] = thisLIR->operands[1];
+ if ((flags & REG_USE3) &&
+ savedLIR[i]->operands[3] == thisLIR->operands[0])
+ savedLIR[i]->operands[3] = thisLIR->operands[1];
+ }
+ thisLIR->flags.isNop = true;
+ }
+ }
+}
+
+#ifdef __mips_hard_float
+/*
+ * Look for pairs of mov.s instructions that can be combined into mov.d
+ */
+static void mergeMovs(CompilationUnit *cUnit)
+{
+ MipsLIR *movsLIR = NULL;
+ MipsLIR *thisLIR;
+
+ for (thisLIR = (MipsLIR *) cUnit->firstLIRInsn;
+ thisLIR != (MipsLIR *) cUnit->lastLIRInsn;
+ thisLIR = NEXT_LIR(thisLIR)) {
+ if (thisLIR->flags.isNop)
+ continue;
+
+ if (isPseudoOpCode(thisLIR->opcode)) {
+ if (thisLIR->opcode == kMipsPseudoDalvikByteCodeBoundary ||
+ thisLIR->opcode == kMipsPseudoExtended ||
+ thisLIR->opcode == kMipsPseudoSSARep)
+ continue; /* ok to move across these pseudos */
+ movsLIR = NULL; /* don't merge across other pseudos */
+ continue;
+ }
+
+ /* merge pairs of mov.s instructions */
+ if (thisLIR->opcode == kMipsFmovs) {
+ if (movsLIR == NULL)
+ movsLIR = thisLIR;
+ else if (((movsLIR->operands[0] & 1) == 0) &&
+ ((movsLIR->operands[1] & 1) == 0) &&
+ ((movsLIR->operands[0] + 1) == thisLIR->operands[0]) &&
+ ((movsLIR->operands[1] + 1) == thisLIR->operands[1])) {
+ /* movsLIR is handling even register - upgrade to mov.d */
+ movsLIR->opcode = kMipsFmovd;
+ movsLIR->operands[0] = S2D(movsLIR->operands[0], movsLIR->operands[0]+1);
+ movsLIR->operands[1] = S2D(movsLIR->operands[1], movsLIR->operands[1]+1);
+ thisLIR->flags.isNop = true;
+ movsLIR = NULL;
+ }
+ else if (((movsLIR->operands[0] & 1) == 1) &&
+ ((movsLIR->operands[1] & 1) == 1) &&
+ ((movsLIR->operands[0] - 1) == thisLIR->operands[0]) &&
+ ((movsLIR->operands[1] - 1) == thisLIR->operands[1])) {
+ /* thissLIR is handling even register - upgrade to mov.d */
+ thisLIR->opcode = kMipsFmovd;
+ thisLIR->operands[0] = S2D(thisLIR->operands[0], thisLIR->operands[0]+1);
+ thisLIR->operands[1] = S2D(thisLIR->operands[1], thisLIR->operands[1]+1);
+ movsLIR->flags.isNop = true;
+ movsLIR = NULL;
+ }
+ else
+ /* carry on searching from here */
+ movsLIR = thisLIR;
+ continue;
+ }
+
+ /* intervening instruction - start search from scratch */
+ movsLIR = NULL;
+ }
+}
+#endif
+
+
+/*
+ * Look back first and then ahead to try to find an instruction to move into
+ * the branch delay slot. If the analysis can be done cheaply enough, it may be
+ * be possible to tune this routine to be more beneficial (e.g., being more
+ * particular about what instruction is speculated).
+ */
+static MipsLIR *delaySlotLIR(MipsLIR *firstLIR, MipsLIR *branchLIR)
+{
+ int isLoad;
+ int loadVisited = 0;
+ int isStore;
+ int storeVisited = 0;
+ u8 useMask = branchLIR->useMask;
+ u8 defMask = branchLIR->defMask;
+ MipsLIR *thisLIR;
+ MipsLIR *newLIR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+
+ for (thisLIR = PREV_LIR(branchLIR);
+ thisLIR != firstLIR;
+ thisLIR = PREV_LIR(thisLIR)) {
+ if (thisLIR->flags.isNop)
+ continue;
+
+ if (isPseudoOpCode(thisLIR->opcode)) {
+ if (thisLIR->opcode == kMipsPseudoDalvikByteCodeBoundary ||
+ thisLIR->opcode == kMipsPseudoExtended ||
+ thisLIR->opcode == kMipsPseudoSSARep)
+ continue; /* ok to move across these pseudos */
+ break; /* don't move across all other pseudos */
+ }
+
+ /* give up on moving previous instruction down into slot */
+ if (thisLIR->opcode == kMipsNop ||
+ thisLIR->opcode == kMips32BitData ||
+ EncodingMap[thisLIR->opcode].flags & IS_BRANCH)
+ break;
+
+ /* don't reorder loads/stores (the alias info could
+ possibly be used to allow as a future enhancement) */
+ isLoad = EncodingMap[thisLIR->opcode].flags & IS_LOAD;
+ isStore = EncodingMap[thisLIR->opcode].flags & IS_STORE;
+
+ if (!(thisLIR->useMask & defMask) &&
+ !(thisLIR->defMask & useMask) &&
+ !(thisLIR->defMask & defMask) &&
+ !(isLoad && storeVisited) &&
+ !(isStore && loadVisited) &&
+ !(isStore && storeVisited)) {
+ *newLIR = *thisLIR;
+ thisLIR->flags.isNop = true;
+ return newLIR; /* move into delay slot succeeded */
+ }
+
+ loadVisited |= isLoad;
+ storeVisited |= isStore;
+
+ /* accumulate def/use constraints */
+ useMask |= thisLIR->useMask;
+ defMask |= thisLIR->defMask;
+ }
+
+ /* for unconditional branches try to copy the instruction at the
+ branch target up into the delay slot and adjust the branch */
+ if (branchLIR->opcode == kMipsB) {
+ MipsLIR *targetLIR;
+ for (targetLIR = (MipsLIR *) branchLIR->generic.target;
+ targetLIR;
+ targetLIR = NEXT_LIR(targetLIR)) {
+ if (!targetLIR->flags.isNop &&
+ (!isPseudoOpCode(targetLIR->opcode) || /* can't pull predicted up */
+ targetLIR->opcode == kMipsPseudoChainingCellInvokePredicted))
+ break; /* try to get to next real op at branch target */
+ }
+ if (targetLIR && !isPseudoOpCode(targetLIR->opcode) &&
+ !(EncodingMap[targetLIR->opcode].flags & IS_BRANCH)) {
+ *newLIR = *targetLIR;
+ branchLIR->generic.target = (LIR *) NEXT_LIR(targetLIR);
+ return newLIR;
+ }
+ } else if (branchLIR->opcode >= kMipsBeq && branchLIR->opcode <= kMipsBne) {
+ /* for conditional branches try to fill branch delay slot
+ via speculative execution when safe */
+ MipsLIR *targetLIR;
+ for (targetLIR = (MipsLIR *) branchLIR->generic.target;
+ targetLIR;
+ targetLIR = NEXT_LIR(targetLIR)) {
+ if (!targetLIR->flags.isNop && !isPseudoOpCode(targetLIR->opcode))
+ break; /* try to get to next real op at branch target */
+ }
+
+ MipsLIR *nextLIR;
+ for (nextLIR = NEXT_LIR(branchLIR);
+ nextLIR;
+ nextLIR = NEXT_LIR(nextLIR)) {
+ if (!nextLIR->flags.isNop && !isPseudoOpCode(nextLIR->opcode))
+ break; /* try to get to next real op for fall thru */
+ }
+
+ if (nextLIR && targetLIR) {
+ int flags = EncodingMap[nextLIR->opcode].flags;
+ int isLoad = flags & IS_LOAD;
+
+ /* common branch and fall thru to normal chaining cells case */
+ if (isLoad && nextLIR->opcode == targetLIR->opcode &&
+ nextLIR->operands[0] == targetLIR->operands[0] &&
+ nextLIR->operands[1] == targetLIR->operands[1] &&
+ nextLIR->operands[2] == targetLIR->operands[2]) {
+ *newLIR = *targetLIR;
+ branchLIR->generic.target = (LIR *) NEXT_LIR(targetLIR);
+ return newLIR;
+ }
+
+ /* try prefetching (maybe try speculating instructions along the
+ trace like dalvik frame load which is common and may be safe) */
+ int isStore = flags & IS_STORE;
+ if (isLoad || isStore) {
+ newLIR->opcode = kMipsPref;
+ newLIR->operands[0] = isLoad ? 0 : 1;
+ newLIR->operands[1] = nextLIR->operands[1];
+ newLIR->operands[2] = nextLIR->operands[2];
+ newLIR->defMask = nextLIR->defMask;
+ newLIR->useMask = nextLIR->useMask;
+ return newLIR;
+ }
+ }
+ }
+
+ /* couldn't find a useful instruction to move into the delay slot */
+ newLIR->opcode = kMipsNop;
+ return newLIR;
+}
+
+/*
+ * The branch delay slot has been ignored thus far. This is the point where
+ * a useful instruction is moved into it or a nop is inserted. Leave existing
+ * NOPs alone -- these came from sparse and packed switch ops and are needed
+ * to maintain the proper offset to the jump table.
+ */
+static void introduceBranchDelaySlot(CompilationUnit *cUnit)
+{
+ MipsLIR *thisLIR;
+ MipsLIR *firstLIR =(MipsLIR *) cUnit->firstLIRInsn;
+ MipsLIR *lastLIR =(MipsLIR *) cUnit->lastLIRInsn;
+
+ for (thisLIR = lastLIR; thisLIR != firstLIR; thisLIR = PREV_LIR(thisLIR)) {
+ if (thisLIR->flags.isNop ||
+ isPseudoOpCode(thisLIR->opcode) ||
+ !(EncodingMap[thisLIR->opcode].flags & IS_BRANCH)) {
+ continue;
+ } else if (thisLIR == lastLIR) {
+ dvmCompilerAppendLIR(cUnit,
+ (LIR *) delaySlotLIR(firstLIR, thisLIR));
+ } else if (NEXT_LIR(thisLIR)->opcode != kMipsNop) {
+ dvmCompilerInsertLIRAfter((LIR *) thisLIR,
+ (LIR *) delaySlotLIR(firstLIR, thisLIR));
+ }
+ }
+
+ if (!thisLIR->flags.isNop &&
+ !isPseudoOpCode(thisLIR->opcode) &&
+ EncodingMap[thisLIR->opcode].flags & IS_BRANCH) {
+ /* nothing available to move, so insert nop */
+ MipsLIR *nopLIR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ nopLIR->opcode = kMipsNop;
+ dvmCompilerInsertLIRAfter((LIR *) thisLIR, (LIR *) nopLIR);
+ }
+}
+
+void dvmCompilerApplyGlobalOptimizations(CompilationUnit *cUnit)
+{
+ applyRedundantBranchElimination(cUnit);
+ applyCopyPropagation(cUnit);
+#ifdef __mips_hard_float
+ mergeMovs(cUnit);
+#endif
+ introduceBranchDelaySlot(cUnit);
+}
diff --git a/vm/compiler/codegen/mips/LocalOptimizations.cpp b/vm/compiler/codegen/mips/LocalOptimizations.cpp
new file mode 100644
index 0000000..1ef0d17
--- /dev/null
+++ b/vm/compiler/codegen/mips/LocalOptimizations.cpp
@@ -0,0 +1,466 @@
+/*
+ * 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.
+ */
+
+#include "Dalvik.h"
+#include "vm/compiler/CompilerInternals.h"
+#include "MipsLIR.h"
+#include "Codegen.h"
+
+#define DEBUG_OPT(X)
+
+/* Check RAW, WAR, and WAR dependency on the register operands */
+#define CHECK_REG_DEP(use, def, check) ((def & check->useMask) || \
+ ((use | def) & check->defMask))
+
+/* Scheduler heuristics */
+#define MAX_HOIST_DISTANCE 20
+#define LDLD_DISTANCE 4
+#define LD_LATENCY 2
+
+static inline bool isDalvikRegisterClobbered(MipsLIR *lir1, MipsLIR *lir2)
+{
+ int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->aliasInfo);
+ int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->aliasInfo);
+ int reg2Lo = DECODE_ALIAS_INFO_REG(lir2->aliasInfo);
+ int reg2Hi = reg2Lo + DECODE_ALIAS_INFO_WIDE(lir2->aliasInfo);
+
+ return (reg1Lo == reg2Lo) || (reg1Lo == reg2Hi) || (reg1Hi == reg2Lo);
+}
+
+#if 0
+/* Debugging utility routine */
+static void dumpDependentInsnPair(MipsLIR *thisLIR, MipsLIR *checkLIR,
+ const char *optimization)
+{
+ LOGD("************ %s ************", optimization);
+ dvmDumpLIRInsn((LIR *) thisLIR, 0);
+ dvmDumpLIRInsn((LIR *) checkLIR, 0);
+}
+#endif
+
+/* Convert a more expensive instruction (ie load) into a move */
+static void convertMemOpIntoMove(CompilationUnit *cUnit, MipsLIR *origLIR,
+ int dest, int src)
+{
+ /* Insert a move to replace the load */
+ MipsLIR *moveLIR;
+ moveLIR = dvmCompilerRegCopyNoInsert( cUnit, dest, src);
+ /*
+ * Insert the converted instruction after the original since the
+ * optimization is scannng in the top-down order and the new instruction
+ * will need to be re-checked (eg the new dest clobbers the src used in
+ * thisLIR).
+ */
+ dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) moveLIR);
+}
+
+/*
+ * Perform a pass of top-down walk, from the second-last instruction in the
+ * superblock, to eliminate redundant loads and stores.
+ *
+ * An earlier load can eliminate a later load iff
+ * 1) They are must-aliases
+ * 2) The native register is not clobbered in between
+ * 3) The memory location is not written to in between
+ *
+ * An earlier store can eliminate a later load iff
+ * 1) They are must-aliases
+ * 2) The native register is not clobbered in between
+ * 3) The memory location is not written to in between
+ *
+ * A later store can be eliminated by an earlier store iff
+ * 1) They are must-aliases
+ * 2) The memory location is not written to in between
+ */
+static void applyLoadStoreElimination(CompilationUnit *cUnit,
+ MipsLIR *headLIR,
+ MipsLIR *tailLIR)
+{
+ MipsLIR *thisLIR;
+
+ if (headLIR == tailLIR) return;
+
+ for (thisLIR = PREV_LIR(tailLIR);
+ thisLIR != headLIR;
+ thisLIR = PREV_LIR(thisLIR)) {
+ int sinkDistance = 0;
+
+ /* Skip non-interesting instructions */
+ if ((thisLIR->flags.isNop == true) ||
+ isPseudoOpCode(thisLIR->opcode) ||
+ !(EncodingMap[thisLIR->opcode].flags & (IS_LOAD | IS_STORE))) {
+ continue;
+ }
+
+ int nativeRegId = thisLIR->operands[0];
+ bool isThisLIRLoad = EncodingMap[thisLIR->opcode].flags & IS_LOAD;
+ MipsLIR *checkLIR;
+ /* Use the mem mask to determine the rough memory location */
+ u8 thisMemMask = (thisLIR->useMask | thisLIR->defMask) & ENCODE_MEM;
+
+ /*
+ * Currently only eliminate redundant ld/st for constant and Dalvik
+ * register accesses.
+ */
+ if (!(thisMemMask & (ENCODE_LITERAL | ENCODE_DALVIK_REG))) continue;
+
+ /*
+ * Add r15 (pc) to the resource mask to prevent this instruction
+ * from sinking past branch instructions. Also take out the memory
+ * region bits since stopMask is used to check data/control
+ * dependencies.
+ */
+ u8 stopUseRegMask = (ENCODE_REG_PC | thisLIR->useMask) &
+ ~ENCODE_MEM;
+ u8 stopDefRegMask = thisLIR->defMask & ~ENCODE_MEM;
+
+ for (checkLIR = NEXT_LIR(thisLIR);
+ checkLIR != tailLIR;
+ checkLIR = NEXT_LIR(checkLIR)) {
+
+ /*
+ * Skip already dead instructions (whose dataflow information is
+ * outdated and misleading).
+ */
+ if (checkLIR->flags.isNop) continue;
+
+ u8 checkMemMask = (checkLIR->useMask | checkLIR->defMask) &
+ ENCODE_MEM;
+ u8 aliasCondition = thisMemMask & checkMemMask;
+ bool stopHere = false;
+
+ /*
+ * Potential aliases seen - check the alias relations
+ */
+ if (checkMemMask != ENCODE_MEM && aliasCondition != 0) {
+ bool isCheckLIRLoad = EncodingMap[checkLIR->opcode].flags &
+ IS_LOAD;
+ if (aliasCondition == ENCODE_LITERAL) {
+ /*
+ * Should only see literal loads in the instruction
+ * stream.
+ */
+ assert(!(EncodingMap[checkLIR->opcode].flags &
+ IS_STORE));
+ /* Same value && same register type */
+ if (checkLIR->aliasInfo == thisLIR->aliasInfo &&
+ REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId)){
+ /*
+ * Different destination register - insert
+ * a move
+ */
+ if (checkLIR->operands[0] != nativeRegId) {
+ convertMemOpIntoMove(cUnit, checkLIR,
+ checkLIR->operands[0],
+ nativeRegId);
+ }
+ checkLIR->flags.isNop = true;
+ }
+ } else if (aliasCondition == ENCODE_DALVIK_REG) {
+ /* Must alias */
+ if (checkLIR->aliasInfo == thisLIR->aliasInfo) {
+ /* Only optimize compatible registers */
+ bool regCompatible =
+ REGTYPE(checkLIR->operands[0]) ==
+ REGTYPE(nativeRegId);
+ if ((isThisLIRLoad && isCheckLIRLoad) ||
+ (!isThisLIRLoad && isCheckLIRLoad)) {
+ /* RAR or RAW */
+ if (regCompatible) {
+ /*
+ * Different destination register -
+ * insert a move
+ */
+ if (checkLIR->operands[0] !=
+ nativeRegId) {
+ convertMemOpIntoMove(cUnit,
+ checkLIR,
+ checkLIR->operands[0],
+ nativeRegId);
+ }
+ checkLIR->flags.isNop = true;
+ } else {
+ /*
+ * Destinaions are of different types -
+ * something complicated going on so
+ * stop looking now.
+ */
+ stopHere = true;
+ }
+ } else if (isThisLIRLoad && !isCheckLIRLoad) {
+ /* WAR - register value is killed */
+ stopHere = true;
+ } else if (!isThisLIRLoad && !isCheckLIRLoad) {
+ /* WAW - nuke the earlier store */
+ thisLIR->flags.isNop = true;
+ stopHere = true;
+ }
+ /* Partial overlap */
+ } else if (isDalvikRegisterClobbered(thisLIR, checkLIR)) {
+ /*
+ * It is actually ok to continue if checkLIR
+ * is a read. But it is hard to make a test
+ * case for this so we just stop here to be
+ * conservative.
+ */
+ stopHere = true;
+ }
+ }
+ /* Memory content may be updated. Stop looking now. */
+ if (stopHere) {
+ break;
+ /* The checkLIR has been transformed - check the next one */
+ } else if (checkLIR->flags.isNop) {
+ continue;
+ }
+ }
+
+
+ /*
+ * this and check LIRs have no memory dependency. Now check if
+ * their register operands have any RAW, WAR, and WAW
+ * dependencies. If so, stop looking.
+ */
+ if (stopHere == false) {
+ stopHere = CHECK_REG_DEP(stopUseRegMask, stopDefRegMask,
+ checkLIR);
+ }
+
+ if (stopHere == true) {
+ DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
+ "REG CLOBBERED"));
+ /* Only sink store instructions */
+ if (sinkDistance && !isThisLIRLoad) {
+ MipsLIR *newStoreLIR =
+ (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ *newStoreLIR = *thisLIR;
+ /*
+ * Stop point found - insert *before* the checkLIR
+ * since the instruction list is scanned in the
+ * top-down order.
+ */
+ dvmCompilerInsertLIRBefore((LIR *) checkLIR,
+ (LIR *) newStoreLIR);
+ thisLIR->flags.isNop = true;
+ }
+ break;
+ } else if (!checkLIR->flags.isNop) {
+ sinkDistance++;
+ }
+ }
+ }
+}
+
+/*
+ * Perform a pass of bottom-up walk, from the second instruction in the
+ * superblock, to try to hoist loads to earlier slots.
+ */
+static void applyLoadHoisting(CompilationUnit *cUnit,
+ MipsLIR *headLIR,
+ MipsLIR *tailLIR)
+{
+ MipsLIR *thisLIR, *checkLIR;
+ /*
+ * Store the list of independent instructions that can be hoisted past.
+ * Will decide the best place to insert later.
+ */
+ MipsLIR *prevInstList[MAX_HOIST_DISTANCE];
+
+ /* Empty block */
+ if (headLIR == tailLIR) return;
+
+ /* Start from the second instruction */
+ for (thisLIR = NEXT_LIR(headLIR);
+ thisLIR != tailLIR;
+ thisLIR = NEXT_LIR(thisLIR)) {
+
+ /* Skip non-interesting instructions */
+ if ((thisLIR->flags.isNop == true) ||
+ isPseudoOpCode(thisLIR->opcode) ||
+ !(EncodingMap[thisLIR->opcode].flags & IS_LOAD)) {
+ continue;
+ }
+
+ u8 stopUseAllMask = thisLIR->useMask;
+
+ /*
+ * Branches for null/range checks are marked with the true resource
+ * bits, and loads to Dalvik registers, constant pools, and non-alias
+ * locations are safe to be hoisted. So only mark the heap references
+ * conservatively here.
+ */
+ if (stopUseAllMask & ENCODE_HEAP_REF) {
+ stopUseAllMask |= ENCODE_REG_PC;
+ }
+
+ /* Similar as above, but just check for pure register dependency */
+ u8 stopUseRegMask = stopUseAllMask & ~ENCODE_MEM;
+ u8 stopDefRegMask = thisLIR->defMask & ~ENCODE_MEM;
+
+ int nextSlot = 0;
+ bool stopHere = false;
+
+ /* Try to hoist the load to a good spot */
+ for (checkLIR = PREV_LIR(thisLIR);
+ checkLIR != headLIR;
+ checkLIR = PREV_LIR(checkLIR)) {
+
+ /*
+ * Skip already dead instructions (whose dataflow information is
+ * outdated and misleading).
+ */
+ if (checkLIR->flags.isNop) continue;
+
+ u8 checkMemMask = checkLIR->defMask & ENCODE_MEM;
+ u8 aliasCondition = stopUseAllMask & checkMemMask;
+ stopHere = false;
+
+ /* Potential WAR alias seen - check the exact relation */
+ if (checkMemMask != ENCODE_MEM && aliasCondition != 0) {
+ /* We can fully disambiguate Dalvik references */
+ if (aliasCondition == ENCODE_DALVIK_REG) {
+ /* Must alias or partually overlap */
+ if ((checkLIR->aliasInfo == thisLIR->aliasInfo) ||
+ isDalvikRegisterClobbered(thisLIR, checkLIR)) {
+ stopHere = true;
+ }
+ /* Conservatively treat all heap refs as may-alias */
+ } else {
+ assert(aliasCondition == ENCODE_HEAP_REF);
+ stopHere = true;
+ }
+ /* Memory content may be updated. Stop looking now. */
+ if (stopHere) {
+ prevInstList[nextSlot++] = checkLIR;
+ break;
+ }
+ }
+
+ if (stopHere == false) {
+ stopHere = CHECK_REG_DEP(stopUseRegMask, stopDefRegMask,
+ checkLIR);
+ }
+
+ /*
+ * Store the dependent or non-pseudo/indepedent instruction to the
+ * list.
+ */
+ if (stopHere || !isPseudoOpCode(checkLIR->opcode)) {
+ prevInstList[nextSlot++] = checkLIR;
+ if (nextSlot == MAX_HOIST_DISTANCE) break;
+ }
+
+ /* Found a new place to put the load - move it here */
+ if (stopHere == true) {
+ DEBUG_OPT(dumpDependentInsnPair(checkLIR, thisLIR
+ "HOIST STOP"));
+ break;
+ }
+ }
+
+ /*
+ * Reached the top - use headLIR as the dependent marker as all labels
+ * are barriers.
+ */
+ if (stopHere == false && nextSlot < MAX_HOIST_DISTANCE) {
+ prevInstList[nextSlot++] = headLIR;
+ }
+
+ /*
+ * At least one independent instruction is found. Scan in the reversed
+ * direction to find a beneficial slot.
+ */
+ if (nextSlot >= 2) {
+ int firstSlot = nextSlot - 2;
+ int slot;
+ MipsLIR *depLIR = prevInstList[nextSlot-1];
+ /* If there is ld-ld dependency, wait LDLD_DISTANCE cycles */
+ if (!isPseudoOpCode(depLIR->opcode) &&
+ (EncodingMap[depLIR->opcode].flags & IS_LOAD)) {
+ firstSlot -= LDLD_DISTANCE;
+ }
+ /*
+ * Make sure we check slot >= 0 since firstSlot may be negative
+ * when the loop is first entered.
+ */
+ for (slot = firstSlot; slot >= 0; slot--) {
+ MipsLIR *curLIR = prevInstList[slot];
+ MipsLIR *prevLIR = prevInstList[slot+1];
+
+ /*
+ * Check the highest instruction.
+ * ENCODE_ALL represents a scheduling barrier.
+ */
+ if (prevLIR->defMask == ENCODE_ALL) {
+ /*
+ * If the first instruction is a load, don't hoist anything
+ * above it since it is unlikely to be beneficial.
+ */
+ if (EncodingMap[curLIR->opcode].flags & IS_LOAD) continue;
+ /*
+ * Need to unconditionally break here even if the hoisted
+ * distance is greater than LD_LATENCY (ie more than enough
+ * cycles are inserted to hide the load latency) since theu
+ * subsequent code doesn't expect to compare against a
+ * pseudo opcode (whose opcode value is negative).
+ */
+ break;
+ }
+
+ /*
+ * NOTE: now prevLIR is guaranteed to be a non-pseudo
+ * instruction (ie accessing EncodingMap[prevLIR->opcode] is
+ * safe).
+ *
+ * Try to find two instructions with load/use dependency until
+ * the remaining instructions are less than LD_LATENCY.
+ */
+ if (((curLIR->useMask & prevLIR->defMask) &&
+ (EncodingMap[prevLIR->opcode].flags & IS_LOAD)) ||
+ (slot < LD_LATENCY)) {
+ break;
+ }
+ }
+
+ /* Found a slot to hoist to */
+ if (slot >= 0) {
+ MipsLIR *curLIR = prevInstList[slot];
+ MipsLIR *newLoadLIR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR),
+ true);
+ *newLoadLIR = *thisLIR;
+ /*
+ * Insertion is guaranteed to succeed since checkLIR
+ * is never the first LIR on the list
+ */
+ dvmCompilerInsertLIRBefore((LIR *) curLIR,
+ (LIR *) newLoadLIR);
+ thisLIR->flags.isNop = true;
+ }
+ }
+ }
+}
+
+void dvmCompilerApplyLocalOptimizations(CompilationUnit *cUnit, LIR *headLIR,
+ LIR *tailLIR)
+{
+ if (!(gDvmJit.disableOpt & (1 << kLoadStoreElimination))) {
+ applyLoadStoreElimination(cUnit, (MipsLIR *) headLIR,
+ (MipsLIR *) tailLIR);
+ }
+ if (!(gDvmJit.disableOpt & (1 << kLoadHoisting))) {
+ applyLoadHoisting(cUnit, (MipsLIR *) headLIR, (MipsLIR *) tailLIR);
+ }
+}
diff --git a/vm/compiler/codegen/mips/Mips32/Factory.cpp b/vm/compiler/codegen/mips/Mips32/Factory.cpp
new file mode 100644
index 0000000..c6d7775
--- /dev/null
+++ b/vm/compiler/codegen/mips/Mips32/Factory.cpp
@@ -0,0 +1,1015 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen for the Thumb ISA and is intended to be
+ * includes by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
+ r_T3, r_T4, r_T5, r_T6, r_T7, r_T8, r_T9, r_S0, r_S4};
+#ifdef __mips_hard_float
+static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
+ r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
+#endif
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg,
+ int highReg);
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
+static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
+ int rDest);
+static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc);
+static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
+ MipsConditionCode cond,
+ int reg1, int reg2, int dOffset,
+ MipsLIR *pcrLabel);
+static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
+
+#ifdef __mips_hard_float
+static MipsLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+ MipsLIR* res = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ res->operands[0] = rDest;
+ res->operands[1] = rSrc;
+ if (rDest == rSrc) {
+ res->flags.isNop = true;
+ } else {
+ /* must be both DOUBLE or both not DOUBLE */
+ assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
+ if (DOUBLEREG(rDest)) {
+ res->opcode = kMipsFmovd;
+ } else {
+ if (SINGLEREG(rDest)) {
+ if (SINGLEREG(rSrc)) {
+ res->opcode = kMipsFmovs;
+ } else {
+ /* note the operands are swapped for the mtc1 instr */
+ res->opcode = kMipsMtc1;
+ res->operands[0] = rSrc;
+ res->operands[1] = rDest;
+ }
+ } else {
+ assert(SINGLEREG(rSrc));
+ res->opcode = kMipsMfc1;
+ }
+ }
+ }
+ setupResourceMasks(res);
+ return res;
+}
+#endif
+
+/*
+ * Load a immediate using a shortcut if possible; otherwise
+ * grab from the per-translation literal pool. If target is
+ * a high register, build constant into a low register and copy.
+ *
+ * No additional register clobbering operation performed. Use this version when
+ * 1) rDest is freshly returned from dvmCompilerAllocTemp or
+ * 2) The codegen is under fixed register usage
+ */
+static MipsLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
+ int value)
+{
+ MipsLIR *res;
+
+#ifdef __mips_hard_float
+ int rDestSave = rDest;
+ int isFpReg = FPREG(rDest);
+ if (isFpReg) {
+ assert(SINGLEREG(rDest));
+ rDest = dvmCompilerAllocTemp(cUnit);
+ }
+#endif
+
+ /* See if the value can be constructed cheaply */
+ if (value == 0) {
+ res = newLIR2(cUnit, kMipsMove, rDest, r_ZERO);
+ } else if ((value > 0) && (value <= 65535)) {
+ res = newLIR3(cUnit, kMipsOri, rDest, r_ZERO, value);
+ } else if ((value < 0) && (value >= -32768)) {
+ res = newLIR3(cUnit, kMipsAddiu, rDest, r_ZERO, value);
+ } else {
+ res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
+ if (value & 0xffff)
+ newLIR3(cUnit, kMipsOri, rDest, rDest, value);
+ }
+
+#ifdef __mips_hard_float
+ if (isFpReg) {
+ newLIR2(cUnit, kMipsMtc1, rDest, rDestSave);
+ dvmCompilerFreeTemp(cUnit, rDest);
+ }
+#endif
+
+ return res;
+}
+
+/*
+ * Load an immediate value into a fixed or temp register. Target
+ * register is clobbered, and marked inUse.
+ */
+static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
+{
+ if (dvmCompilerIsTemp(cUnit, rDest)) {
+ dvmCompilerClobber(cUnit, rDest);
+ dvmCompilerMarkInUse(cUnit, rDest);
+ }
+ return loadConstantNoClobber(cUnit, rDest, value);
+}
+
+/*
+ * Load a class pointer value into a fixed or temp register. Target
+ * register is clobbered, and marked inUse.
+ */
+static MipsLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
+{
+ MipsLIR *res;
+ if (dvmCompilerIsTemp(cUnit, rDest)) {
+ dvmCompilerClobber(cUnit, rDest);
+ dvmCompilerMarkInUse(cUnit, rDest);
+ }
+ res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
+ if (value & 0xffff)
+ newLIR3(cUnit, kMipsOri, rDest, rDest, value);
+ return res;
+}
+
+static MipsLIR *opNone(CompilationUnit *cUnit, OpKind op)
+{
+ MipsLIR *res;
+ MipsOpCode opcode = kMipsNop;
+ switch (op) {
+ case kOpUncondBr:
+ opcode = kMipsB;
+ break;
+ default:
+ ALOGE("Jit: bad case in opNone");
+ dvmCompilerAbort(cUnit);
+ }
+ res = newLIR0(cUnit, opcode);
+ return res;
+}
+
+static MipsLIR *opCompareBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt)
+{
+ MipsLIR *res;
+ if (rt < 0) {
+ assert(opc >= kMipsBeqz && opc <= kMipsBnez);
+ res = newLIR1(cUnit, opc, rs);
+ } else {
+ assert(opc == kMipsBeq || opc == kMipsBne);
+ res = newLIR2(cUnit, opc, rs, rt);
+ }
+ return res;
+}
+
+static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
+
+static MipsLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
+{
+ MipsOpCode opcode = kMipsNop;
+ switch (op) {
+ case kOpBlx:
+ opcode = kMipsJalr;
+ break;
+ default:
+ assert(0);
+ }
+ return newLIR2(cUnit, opcode, r_RA, rDestSrc);
+}
+
+static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+ int rSrc1, int value);
+static MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+ int value)
+{
+ MipsLIR *res;
+ bool neg = (value < 0);
+ int absValue = (neg) ? -value : value;
+ bool shortForm = (absValue & 0xff) == absValue;
+ MipsOpCode opcode = kMipsNop;
+ switch (op) {
+ case kOpAdd:
+ return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
+ break;
+ case kOpSub:
+ return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
+ break;
+ default:
+ ALOGE("Jit: bad case in opRegImm");
+ dvmCompilerAbort(cUnit);
+ break;
+ }
+ if (shortForm)
+ res = newLIR2(cUnit, opcode, rDestSrc1, absValue);
+ else {
+ int rScratch = dvmCompilerAllocTemp(cUnit);
+ res = loadConstant(cUnit, rScratch, value);
+ if (op == kOpCmp)
+ newLIR2(cUnit, opcode, rDestSrc1, rScratch);
+ else
+ newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rScratch);
+ }
+ return res;
+}
+
+static MipsLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
+ int rSrc1, int rSrc2)
+{
+ MipsOpCode opcode = kMipsNop;
+ switch (op) {
+ case kOpAdd:
+ opcode = kMipsAddu;
+ break;
+ case kOpSub:
+ opcode = kMipsSubu;
+ break;
+ case kOpAnd:
+ opcode = kMipsAnd;
+ break;
+ case kOpMul:
+ opcode = kMipsMul;
+ break;
+ case kOpOr:
+ opcode = kMipsOr;
+ break;
+ case kOpXor:
+ opcode = kMipsXor;
+ break;
+ case kOpLsl:
+ opcode = kMipsSllv;
+ break;
+ case kOpLsr:
+ opcode = kMipsSrlv;
+ break;
+ case kOpAsr:
+ opcode = kMipsSrav;
+ break;
+ default:
+ ALOGE("Jit: bad case in opRegRegReg");
+ dvmCompilerAbort(cUnit);
+ break;
+ }
+ return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
+}
+
+static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+ int rSrc1, int value)
+{
+ MipsLIR *res;
+ MipsOpCode opcode = kMipsNop;
+ bool shortForm = true;
+
+ switch(op) {
+ case kOpAdd:
+ if (IS_SIMM16(value)) {
+ opcode = kMipsAddiu;
+ }
+ else {
+ shortForm = false;
+ opcode = kMipsAddu;
+ }
+ break;
+ case kOpSub:
+ if (IS_SIMM16((-value))) {
+ value = -value;
+ opcode = kMipsAddiu;
+ }
+ else {
+ shortForm = false;
+ opcode = kMipsSubu;
+ }
+ break;
+ case kOpLsl:
+ assert(value >= 0 && value <= 31);
+ opcode = kMipsSll;
+ break;
+ case kOpLsr:
+ assert(value >= 0 && value <= 31);
+ opcode = kMipsSrl;
+ break;
+ case kOpAsr:
+ assert(value >= 0 && value <= 31);
+ opcode = kMipsSra;
+ break;
+ case kOpAnd:
+ if (IS_UIMM16((value))) {
+ opcode = kMipsAndi;
+ }
+ else {
+ shortForm = false;
+ opcode = kMipsAnd;
+ }
+ break;
+ case kOpOr:
+ if (IS_UIMM16((value))) {
+ opcode = kMipsOri;
+ }
+ else {
+ shortForm = false;
+ opcode = kMipsOr;
+ }
+ break;
+ case kOpXor:
+ if (IS_UIMM16((value))) {
+ opcode = kMipsXori;
+ }
+ else {
+ shortForm = false;
+ opcode = kMipsXor;
+ }
+ break;
+ case kOpMul:
+ shortForm = false;
+ opcode = kMipsMul;
+ break;
+ default:
+ ALOGE("Jit: bad case in opRegRegImm");
+ dvmCompilerAbort(cUnit);
+ break;
+ }
+
+ if (shortForm)
+ res = newLIR3(cUnit, opcode, rDest, rSrc1, value);
+ else {
+ if (rDest != rSrc1) {
+ res = loadConstant(cUnit, rDest, value);
+ newLIR3(cUnit, opcode, rDest, rSrc1, rDest);
+ } else {
+ int rScratch = dvmCompilerAllocTemp(cUnit);
+ res = loadConstant(cUnit, rScratch, value);
+ newLIR3(cUnit, opcode, rDest, rSrc1, rScratch);
+ }
+ }
+ return res;
+}
+
+static MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+ int rSrc2)
+{
+ MipsOpCode opcode = kMipsNop;
+ MipsLIR *res;
+ switch (op) {
+ case kOpMov:
+ opcode = kMipsMove;
+ break;
+ case kOpMvn:
+ return newLIR3(cUnit, kMipsNor, rDestSrc1, rSrc2, r_ZERO);
+ case kOpNeg:
+ return newLIR3(cUnit, kMipsSubu, rDestSrc1, r_ZERO, rSrc2);
+ case kOpAdd:
+ case kOpAnd:
+ case kOpMul:
+ case kOpOr:
+ case kOpSub:
+ case kOpXor:
+ return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
+ case kOp2Byte:
+#if __mips_isa_rev>=2
+ res = newLIR2(cUnit, kMipsSeb, rDestSrc1, rSrc2);
+#else
+ res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
+ opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
+#endif
+ return res;
+ case kOp2Short:
+#if __mips_isa_rev>=2
+ res = newLIR2(cUnit, kMipsSeh, rDestSrc1, rSrc2);
+#else
+ res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
+ opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
+#endif
+ return res;
+ case kOp2Char:
+ return newLIR3(cUnit, kMipsAndi, rDestSrc1, rSrc2, 0xFFFF);
+ default:
+ ALOGE("Jit: bad case in opRegReg");
+ dvmCompilerAbort(cUnit);
+ break;
+ }
+ return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
+}
+
+static MipsLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
+ int rDestHi, int valLo, int valHi)
+{
+ MipsLIR *res;
+ res = loadConstantNoClobber(cUnit, rDestLo, valLo);
+ loadConstantNoClobber(cUnit, rDestHi, valHi);
+ return res;
+}
+
+/* Load value from base + scaled index. */
+static MipsLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
+ int rIndex, int rDest, int scale, OpSize size)
+{
+ MipsLIR *first = NULL;
+ MipsLIR *res;
+ MipsOpCode opcode = kMipsNop;
+ int tReg = dvmCompilerAllocTemp(cUnit);
+
+#ifdef __mips_hard_float
+ if (FPREG(rDest)) {
+ assert(SINGLEREG(rDest));
+ assert((size == kWord) || (size == kSingle));
+ size = kSingle;
+ } else {
+ if (size == kSingle)
+ size = kWord;
+ }
+#endif
+
+ if (!scale) {
+ first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
+ } else {
+ first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
+ newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
+ }
+
+ switch (size) {
+#ifdef __mips_hard_float
+ case kSingle:
+ opcode = kMipsFlwc1;
+ break;
+#endif
+ case kWord:
+ opcode = kMipsLw;
+ break;
+ case kUnsignedHalf:
+ opcode = kMipsLhu;
+ break;
+ case kSignedHalf:
+ opcode = kMipsLh;
+ break;
+ case kUnsignedByte:
+ opcode = kMipsLbu;
+ break;
+ case kSignedByte:
+ opcode = kMipsLb;
+ break;
+ default:
+ ALOGE("Jit: bad case in loadBaseIndexed");
+ dvmCompilerAbort(cUnit);
+ }
+
+ res = newLIR3(cUnit, opcode, rDest, 0, tReg);
+#if defined(WITH_SELF_VERIFICATION)
+ if (cUnit->heapMemOp)
+ res->flags.insertWrapper = true;
+#endif
+ dvmCompilerFreeTemp(cUnit, tReg);
+ return (first) ? first : res;
+}
+
+/* store value base base + scaled index. */
+static MipsLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
+ int rIndex, int rSrc, int scale, OpSize size)
+{
+ MipsLIR *first = NULL;
+ MipsLIR *res;
+ MipsOpCode opcode = kMipsNop;
+ int rNewIndex = rIndex;
+ int tReg = dvmCompilerAllocTemp(cUnit);
+
+#ifdef __mips_hard_float
+ if (FPREG(rSrc)) {
+ assert(SINGLEREG(rSrc));
+ assert((size == kWord) || (size == kSingle));
+ size = kSingle;
+ } else {
+ if (size == kSingle)
+ size = kWord;
+ }
+#endif
+
+ if (!scale) {
+ first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
+ } else {
+ first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
+ newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
+ }
+
+ switch (size) {
+#ifdef __mips_hard_float
+ case kSingle:
+ opcode = kMipsFswc1;
+ break;
+#endif
+ case kWord:
+ opcode = kMipsSw;
+ break;
+ case kUnsignedHalf:
+ case kSignedHalf:
+ opcode = kMipsSh;
+ break;
+ case kUnsignedByte:
+ case kSignedByte:
+ opcode = kMipsSb;
+ break;
+ default:
+ ALOGE("Jit: bad case in storeBaseIndexed");
+ dvmCompilerAbort(cUnit);
+ }
+ res = newLIR3(cUnit, opcode, rSrc, 0, tReg);
+#if defined(WITH_SELF_VERIFICATION)
+ if (cUnit->heapMemOp)
+ res->flags.insertWrapper = true;
+#endif
+ dvmCompilerFreeTemp(cUnit, rNewIndex);
+ return first;
+}
+
+static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+ int i;
+ int loadCnt = 0;
+ MipsLIR *res = NULL ;
+ genBarrier(cUnit);
+
+ for (i = 0; i < 8; i++, rMask >>= 1) {
+ if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
+ newLIR3(cUnit, kMipsLw, i+r_A0, loadCnt*4, rBase);
+ loadCnt++;
+ }
+ }
+
+ if (loadCnt) {/* increment after */
+ newLIR3(cUnit, kMipsAddiu, rBase, rBase, loadCnt*4);
+ }
+
+#if defined(WITH_SELF_VERIFICATION)
+ if (cUnit->heapMemOp)
+ res->flags.insertWrapper = true;
+#endif
+ genBarrier(cUnit);
+ return res; /* NULL always returned which should be ok since no callers use it */
+}
+
+static MipsLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+ int i;
+ int storeCnt = 0;
+ MipsLIR *res = NULL ;
+ genBarrier(cUnit);
+
+ for (i = 0; i < 8; i++, rMask >>= 1) {
+ if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
+ newLIR3(cUnit, kMipsSw, i+r_A0, storeCnt*4, rBase);
+ storeCnt++;
+ }
+ }
+
+ if (storeCnt) { /* increment after */
+ newLIR3(cUnit, kMipsAddiu, rBase, rBase, storeCnt*4);
+ }
+
+#if defined(WITH_SELF_VERIFICATION)
+ if (cUnit->heapMemOp)
+ res->flags.insertWrapper = true;
+#endif
+ genBarrier(cUnit);
+ return res; /* NULL always returned which should be ok since no callers use it */
+}
+
+static MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
+ int displacement, int rDest, int rDestHi,
+ OpSize size, int sReg)
+/*
+ * Load value from base + displacement. Optionally perform null check
+ * on base (which must have an associated sReg and MIR). If not
+ * performing null check, incoming MIR can be null. IMPORTANT: this
+ * code must not allocate any new temps. If a new register is needed
+ * and base and dest are the same, spill some other register to
+ * rlp and then restore.
+ */
+{
+ MipsLIR *res;
+ MipsLIR *load = NULL;
+ MipsLIR *load2 = NULL;
+ MipsOpCode opcode = kMipsNop;
+ bool shortForm = IS_SIMM16(displacement);
+ bool pair = false;
+
+ switch (size) {
+ case kLong:
+ case kDouble:
+ pair = true;
+ opcode = kMipsLw;
+#ifdef __mips_hard_float
+ if (FPREG(rDest)) {
+ opcode = kMipsFlwc1;
+ if (DOUBLEREG(rDest)) {
+ rDest = rDest - FP_DOUBLE;
+ } else {
+ assert(FPREG(rDestHi));
+ assert(rDest == (rDestHi - 1));
+ }
+ rDestHi = rDest + 1;
+ }
+#endif
+ shortForm = IS_SIMM16_2WORD(displacement);
+ assert((displacement & 0x3) == 0);
+ break;
+ case kWord:
+ case kSingle:
+ opcode = kMipsLw;
+#ifdef __mips_hard_float
+ if (FPREG(rDest)) {
+ opcode = kMipsFlwc1;
+ assert(SINGLEREG(rDest));
+ }
+#endif
+ assert((displacement & 0x3) == 0);
+ break;
+ case kUnsignedHalf:
+ opcode = kMipsLhu;
+ assert((displacement & 0x1) == 0);
+ break;
+ case kSignedHalf:
+ opcode = kMipsLh;
+ assert((displacement & 0x1) == 0);
+ break;
+ case kUnsignedByte:
+ opcode = kMipsLbu;
+ break;
+ case kSignedByte:
+ opcode = kMipsLb;
+ break;
+ default:
+ ALOGE("Jit: bad case in loadBaseIndexedBody");
+ dvmCompilerAbort(cUnit);
+ }
+
+ if (shortForm) {
+ if (!pair) {
+ load = res = newLIR3(cUnit, opcode, rDest, displacement, rBase);
+ } else {
+ load = res = newLIR3(cUnit, opcode, rDest, displacement + LOWORD_OFFSET, rBase);
+ load2 = newLIR3(cUnit, opcode, rDestHi, displacement + HIWORD_OFFSET, rBase);
+ }
+ } else {
+ if (pair) {
+ int rTmp = dvmCompilerAllocFreeTemp(cUnit);
+ res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
+ load = newLIR3(cUnit, opcode, rDest, LOWORD_OFFSET, rTmp);
+ load2 = newLIR3(cUnit, opcode, rDestHi, HIWORD_OFFSET, rTmp);
+ dvmCompilerFreeTemp(cUnit, rTmp);
+ } else {
+ int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit)
+ : rDest;
+ res = loadConstant(cUnit, rTmp, displacement);
+ load = newLIR3(cUnit, opcode, rDest, rBase, rTmp);
+ if (rTmp != rDest)
+ dvmCompilerFreeTemp(cUnit, rTmp);
+ }
+ }
+
+ if (rBase == rFP) {
+ if (load != NULL)
+ annotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
+ true /* isLoad */);
+ if (load2 != NULL)
+ annotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
+ true /* isLoad */);
+ }
+#if defined(WITH_SELF_VERIFICATION)
+ if (load != NULL && cUnit->heapMemOp)
+ load->flags.insertWrapper = true;
+ if (load2 != NULL && cUnit->heapMemOp)
+ load2->flags.insertWrapper = true;
+#endif
+ return load;
+}
+
+static MipsLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
+ int displacement, int rDest, OpSize size,
+ int sReg)
+{
+ return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
+ size, sReg);
+}
+
+static MipsLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
+ int displacement, int rDestLo, int rDestHi,
+ int sReg)
+{
+ return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
+ kLong, sReg);
+}
+
+static MipsLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc, int rSrcHi,
+ OpSize size)
+{
+ MipsLIR *res;
+ MipsLIR *store = NULL;
+ MipsLIR *store2 = NULL;
+ MipsOpCode opcode = kMipsNop;
+ bool shortForm = IS_SIMM16(displacement);
+ bool pair = false;
+
+ switch (size) {
+ case kLong:
+ case kDouble:
+ pair = true;
+ opcode = kMipsSw;
+#ifdef __mips_hard_float
+ if (FPREG(rSrc)) {
+ opcode = kMipsFswc1;
+ if (DOUBLEREG(rSrc)) {
+ rSrc = rSrc - FP_DOUBLE;
+ } else {
+ assert(FPREG(rSrcHi));
+ assert(rSrc == (rSrcHi - 1));
+ }
+ rSrcHi = rSrc + 1;
+ }
+#endif
+ shortForm = IS_SIMM16_2WORD(displacement);
+ assert((displacement & 0x3) == 0);
+ break;
+ case kWord:
+ case kSingle:
+ opcode = kMipsSw;
+#ifdef __mips_hard_float
+ if (FPREG(rSrc)) {
+ opcode = kMipsFswc1;
+ assert(SINGLEREG(rSrc));
+ }
+#endif
+ assert((displacement & 0x3) == 0);
+ break;
+ case kUnsignedHalf:
+ case kSignedHalf:
+ opcode = kMipsSh;
+ assert((displacement & 0x1) == 0);
+ break;
+ case kUnsignedByte:
+ case kSignedByte:
+ opcode = kMipsSb;
+ break;
+ default:
+ ALOGE("Jit: bad case in storeBaseIndexedBody");
+ dvmCompilerAbort(cUnit);
+ }
+
+ if (shortForm) {
+ if (!pair) {
+ store = res = newLIR3(cUnit, opcode, rSrc, displacement, rBase);
+ } else {
+ store = res = newLIR3(cUnit, opcode, rSrc, displacement + LOWORD_OFFSET, rBase);
+ store2 = newLIR3(cUnit, opcode, rSrcHi, displacement + HIWORD_OFFSET, rBase);
+ }
+ } else {
+ int rScratch = dvmCompilerAllocTemp(cUnit);
+ res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
+ if (!pair) {
+ store = newLIR3(cUnit, opcode, rSrc, 0, rScratch);
+ } else {
+ store = newLIR3(cUnit, opcode, rSrc, LOWORD_OFFSET, rScratch);
+ store2 = newLIR3(cUnit, opcode, rSrcHi, HIWORD_OFFSET, rScratch);
+ }
+ dvmCompilerFreeTemp(cUnit, rScratch);
+ }
+
+ if (rBase == rFP) {
+ if (store != NULL)
+ annotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
+ false /* isLoad */);
+ if (store2 != NULL)
+ annotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
+ false /* isLoad */);
+ }
+
+#if defined(WITH_SELF_VERIFICATION)
+ if (store != NULL && cUnit->heapMemOp)
+ store->flags.insertWrapper = true;
+ if (store2 != NULL && cUnit->heapMemOp)
+ store2->flags.insertWrapper = true;
+#endif
+ return res;
+}
+
+static MipsLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc, OpSize size)
+{
+ return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
+}
+
+static MipsLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrcLo, int rSrcHi)
+{
+ return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
+}
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+ storeWordDisp(cUnit, base, LOWORD_OFFSET, lowReg);
+ storeWordDisp(cUnit, base, HIWORD_OFFSET, highReg);
+}
+
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+ loadWordDisp(cUnit, base, LOWORD_OFFSET , lowReg);
+ loadWordDisp(cUnit, base, HIWORD_OFFSET , highReg);
+}
+
+static MipsLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+ MipsLIR* res;
+ MipsOpCode opcode;
+#ifdef __mips_hard_float
+ if (FPREG(rDest) || FPREG(rSrc))
+ return fpRegCopy(cUnit, rDest, rSrc);
+#endif
+ res = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ opcode = kMipsMove;
+ assert(LOWREG(rDest) && LOWREG(rSrc));
+ res->operands[0] = rDest;
+ res->operands[1] = rSrc;
+ res->opcode = opcode;
+ setupResourceMasks(res);
+ if (rDest == rSrc) {
+ res->flags.isNop = true;
+ }
+ return res;
+}
+
+static MipsLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+ MipsLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
+ dvmCompilerAppendLIR(cUnit, (LIR*)res);
+ return res;
+}
+
+static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+ int srcLo, int srcHi)
+{
+#ifdef __mips_hard_float
+ bool destFP = FPREG(destLo) && FPREG(destHi);
+ bool srcFP = FPREG(srcLo) && FPREG(srcHi);
+ assert(FPREG(srcLo) == FPREG(srcHi));
+ assert(FPREG(destLo) == FPREG(destHi));
+ if (destFP) {
+ if (srcFP) {
+ genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
+ } else {
+ /* note the operands are swapped for the mtc1 instr */
+ newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
+ newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
+ }
+ } else {
+ if (srcFP) {
+ newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
+ newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
+ } else {
+ // Handle overlap
+ if (srcHi == destLo) {
+ genRegCopy(cUnit, destHi, srcHi);
+ genRegCopy(cUnit, destLo, srcLo);
+ } else {
+ genRegCopy(cUnit, destLo, srcLo);
+ genRegCopy(cUnit, destHi, srcHi);
+ }
+ }
+ }
+#else
+ // Handle overlap
+ if (srcHi == destLo) {
+ genRegCopy(cUnit, destHi, srcHi);
+ genRegCopy(cUnit, destLo, srcLo);
+ } else {
+ genRegCopy(cUnit, destLo, srcLo);
+ genRegCopy(cUnit, destHi, srcHi);
+ }
+#endif
+}
+
+static inline MipsLIR *genRegImmCheck(CompilationUnit *cUnit,
+ MipsConditionCode cond, int reg,
+ int checkValue, int dOffset,
+ MipsLIR *pcrLabel)
+{
+ MipsLIR *branch = NULL;
+
+ if (checkValue == 0) {
+ MipsOpCode opc = kMipsNop;
+ if (cond == kMipsCondEq) {
+ opc = kMipsBeqz;
+ } else if (cond == kMipsCondNe) {
+ opc = kMipsBnez;
+ } else if (cond == kMipsCondLt || cond == kMipsCondMi) {
+ opc = kMipsBltz;
+ } else if (cond == kMipsCondLe) {
+ opc = kMipsBlez;
+ } else if (cond == kMipsCondGt) {
+ opc = kMipsBgtz;
+ } else if (cond == kMipsCondGe) {
+ opc = kMipsBgez;
+ } else {
+ ALOGE("Jit: bad case in genRegImmCheck");
+ dvmCompilerAbort(cUnit);
+ }
+ branch = opCompareBranch(cUnit, opc, reg, -1);
+ } else if (IS_SIMM16(checkValue)) {
+ if (cond == kMipsCondLt) {
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ newLIR3(cUnit, kMipsSlti, tReg, reg, checkValue);
+ branch = opCompareBranch(cUnit, kMipsBne, tReg, r_ZERO);
+ dvmCompilerFreeTemp(cUnit, tReg);
+ } else {
+ ALOGE("Jit: bad case in genRegImmCheck");
+ dvmCompilerAbort(cUnit);
+ }
+ } else {
+ ALOGE("Jit: bad case in genRegImmCheck");
+ dvmCompilerAbort(cUnit);
+ }
+
+ if (cUnit->jitMode == kJitMethod) {
+ BasicBlock *bb = cUnit->curBlock;
+ if (bb->taken) {
+ MipsLIR *exceptionLabel = (MipsLIR *) cUnit->blockLabelList;
+ exceptionLabel += bb->taken->id;
+ branch->generic.target = (LIR *) exceptionLabel;
+ return exceptionLabel;
+ } else {
+ ALOGE("Catch blocks not handled yet");
+ dvmAbort();
+ return NULL;
+ }
+ } else {
+ return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+ }
+}
+
+#if defined(WITH_SELF_VERIFICATION)
+static void genSelfVerificationPreBranch(CompilationUnit *cUnit,
+ MipsLIR *origLIR) {
+// DOUGLAS - this still needs to be implemented for MIPS.
+#if 0
+ /*
+ * We need two separate pushes, since we want r5 to be pushed first.
+ * Store multiple will push LR first.
+ */
+ MipsLIR *pushFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ pushFP->opcode = kThumbPush;
+ pushFP->operands[0] = 1 << r5FP;
+ setupResourceMasks(pushFP);
+ dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushFP);
+
+ MipsLIR *pushLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ pushLR->opcode = kThumbPush;
+ /* Thumb push can handle LR, but is encoded differently at bit 8 */
+ pushLR->operands[0] = 1 << 8;
+ setupResourceMasks(pushLR);
+ dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushLR);
+#endif
+}
+
+static void genSelfVerificationPostBranch(CompilationUnit *cUnit,
+ MipsLIR *origLIR) {
+// DOUGLAS - this still needs to be implemented for MIPS.
+#if 0
+ /*
+ * Since Thumb cannot pop memory content into LR, we have to pop LR
+ * to a temp first (r5 in this case). Then we move r5 to LR, then pop the
+ * original r5 from stack.
+ */
+ /* Pop memory content(LR) into r5 first */
+ MipsLIR *popForLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ popForLR->opcode = kThumbPop;
+ popForLR->operands[0] = 1 << r5FP;
+ setupResourceMasks(popForLR);
+ dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) popForLR);
+
+ MipsLIR *copy = genRegCopyNoInsert(cUnit, r14lr, r5FP);
+ dvmCompilerInsertLIRAfter((LIR *) popForLR, (LIR *) copy);
+
+ /* Now restore the original r5 */
+ MipsLIR *popFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
+ popFP->opcode = kThumbPop;
+ popFP->operands[0] = 1 << r5FP;
+ setupResourceMasks(popFP);
+ dvmCompilerInsertLIRAfter((LIR *) copy, (LIR *) popFP);
+#endif
+}
+#endif
diff --git a/vm/compiler/codegen/mips/Mips32/Gen.cpp b/vm/compiler/codegen/mips/Mips32/Gen.cpp
new file mode 100644
index 0000000..29c7c5f
--- /dev/null
+++ b/vm/compiler/codegen/mips/Mips32/Gen.cpp
@@ -0,0 +1,313 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen for the Mips ISA and is intended to be
+ * includes by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Reserve 8 bytes at the beginning of the trace
+ * +----------------------------+
+ * | prof count addr (4 bytes) |
+ * +----------------------------+
+ * | chain cell offset (4 bytes)|
+ * +----------------------------+
+ *
+ * ...and then code to increment the execution
+ *
+ * For continuous profiling (24 bytes)
+ * lahi a0, addr # get ptr to prof count addr into a0
+ * lalo a0, addr
+ * lw a0, 0(a0) # read prof count addr into a0
+ * lw a1, 0(a0) # read prof count into a1
+ * addiu a1, a1, 1 # increment count
+ * sw a1, 0(a0) # store count
+ *
+ * For periodic profiling (8 bytes)
+ * call TEMPLATE_PERIODIC_PROFILING
+ * nop
+ *
+ * and return the size (in bytes) of the generated code.
+ */
+static int genTraceProfileEntry(CompilationUnit *cUnit)
+{
+ intptr_t addr = (intptr_t)dvmJitNextTraceCounter();
+ assert(__BYTE_ORDER == __LITTLE_ENDIAN);
+ MipsLIR *executionCount = newLIR1(cUnit, kMips32BitData, addr);
+ cUnit->chainCellOffsetLIR =
+ (LIR *) newLIR1(cUnit, kMips32BitData, CHAIN_CELL_OFFSET_TAG);
+ cUnit->headerSize = 8;
+ if ((gDvmJit.profileMode == kTraceProfilingContinuous) ||
+ (gDvmJit.profileMode == kTraceProfilingDisabled)) {
+ MipsLIR *loadAddr = newLIR2(cUnit, kMipsLahi, r_A0, 0);
+ loadAddr->generic.target = (LIR *) executionCount;
+ loadAddr = newLIR3(cUnit, kMipsLalo, r_A0, r_A0, 0);
+ loadAddr ->generic.target = (LIR *) executionCount;
+ newLIR3(cUnit, kMipsLw, r_A0, 0, r_A0);
+ newLIR3(cUnit, kMipsLw, r_A1, 0, r_A0);
+ newLIR3(cUnit, kMipsAddiu, r_A1, r_A1, 1);
+ newLIR3(cUnit, kMipsSw, r_A1, 0, r_A0);
+ return 24;
+ } else {
+ int opcode = TEMPLATE_PERIODIC_PROFILING;
+ newLIR1(cUnit, kMipsJal,
+ (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+ newLIR0(cUnit, kMipsNop); /* delay slot */
+ return 8;
+ }
+}
+
+/*
+ * Perform a "reg cmp imm" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ RegLocation rlResult;
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
+ rlSrc.lowReg, 0x80000000);
+ storeValue(cUnit, rlDest, rlResult);
+}
+
+static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ RegLocation rlResult;
+ rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
+ 0x80000000);
+ genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+}
+
+static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
+ genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
+ rlResult = dvmCompilerGetReturnWide(cUnit);
+ storeValueWide(cUnit, rlDest, rlResult);
+}
+
+static bool partialOverlap(int sreg1, int sreg2)
+{
+ return abs(sreg1 - sreg2) == 1;
+}
+
+static void withCarryHelper(CompilationUnit *cUnit, MipsOpCode opc,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2, int sltuSrc1, int sltuSrc2)
+{
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ newLIR3(cUnit, opc, rlDest.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+ newLIR3(cUnit, kMipsSltu, tReg, sltuSrc1, sltuSrc2);
+ newLIR3(cUnit, opc, rlDest.highReg, rlSrc1.highReg, rlSrc2.highReg);
+ newLIR3(cUnit, opc, rlDest.highReg, rlDest.highReg, tReg);
+ dvmCompilerFreeTemp(cUnit, tReg);
+}
+
+static void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
+ OpKind secondOp, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ int carryOp = (secondOp == kOpAdc || secondOp == kOpSbc);
+
+ if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
+ partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
+ partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
+ // Rare case - not enough registers to properly handle
+ genInterpSingleStep(cUnit, mir);
+ } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
+ rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+ if (!carryOp) {
+ opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlResult.lowReg, rlSrc2.lowReg);
+ opRegRegReg(cUnit, secondOp, rlResult.highReg, rlResult.highReg, rlSrc2.highReg);
+ } else if (secondOp == kOpAdc) {
+ withCarryHelper(cUnit, kMipsAddu, rlResult, rlResult, rlSrc2,
+ rlResult.lowReg, rlSrc2.lowReg);
+ } else {
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ newLIR2(cUnit, kMipsMove, tReg, rlResult.lowReg);
+ withCarryHelper(cUnit, kMipsSubu, rlResult, rlResult, rlSrc2,
+ tReg, rlResult.lowReg);
+ dvmCompilerFreeTemp(cUnit, tReg);
+ }
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
+ rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+ if (!carryOp) {
+ opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlResult.lowReg);
+ opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlResult.highReg);
+ } else if (secondOp == kOpAdc) {
+ withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlResult,
+ rlResult.lowReg, rlSrc1.lowReg);
+ } else {
+ withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlResult,
+ rlSrc1.lowReg, rlResult.lowReg);
+ }
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else {
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+ rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ if (!carryOp) {
+ opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+ opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
+ } else if (secondOp == kOpAdc) {
+ withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlSrc2,
+ rlResult.lowReg, rlSrc1.lowReg);
+ } else {
+ withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlSrc2,
+ rlSrc1.lowReg, rlResult.lowReg);
+ }
+ storeValueWide(cUnit, rlDest, rlResult);
+ }
+}
+
+void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
+{
+ int numTemps = sizeof(coreTemps)/sizeof(int);
+ RegisterPool *pool = (RegisterPool *) dvmCompilerNew(sizeof(*pool), true);
+ cUnit->regPool = pool;
+ pool->numCoreTemps = numTemps;
+ pool->coreTemps =
+ (RegisterInfo *) dvmCompilerNew(numTemps * sizeof(*pool->coreTemps), true);
+ dvmCompilerInitPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
+#ifdef __mips_hard_float
+ int numFPTemps = sizeof(fpTemps)/sizeof(int);
+ pool->numFPTemps = numFPTemps;
+ pool->FPTemps =
+ (RegisterInfo *) dvmCompilerNew(numFPTemps * sizeof(*pool->FPTemps), true);
+ dvmCompilerInitPool(pool->FPTemps, fpTemps, pool->numFPTemps);
+#else
+ pool->numFPTemps = 0;
+ pool->FPTemps = NULL;
+ dvmCompilerInitPool(pool->FPTemps, NULL, 0);
+#endif
+ pool->nullCheckedRegs =
+ dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
+}
+
+/* Export the Dalvik PC assicated with an instruction to the StackSave area */
+static MipsLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
+{
+ MipsLIR *res;
+ int rDPC = dvmCompilerAllocTemp(cUnit);
+ int rAddr = dvmCompilerAllocTemp(cUnit);
+ int offset = offsetof(StackSaveArea, xtra.currentPc);
+ res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
+ newLIR3(cUnit, kMipsAddiu, rAddr, rFP, -(sizeof(StackSaveArea) - offset));
+ storeWordDisp( cUnit, rAddr, 0, rDPC);
+ return res;
+}
+
+static void genMonitor(CompilationUnit *cUnit, MIR *mir)
+{
+ genMonitorPortable(cUnit, mir);
+}
+
+static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
+ genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
+ rlResult = dvmCompilerGetReturn(cUnit);
+ storeValue(cUnit, rlDest, rlResult);
+}
+
+static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
+{
+ int offset = offsetof(Thread, interpSave.retval);
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
+#if __mips_isa_rev>=2
+ newLIR4(cUnit, kMipsExt, reg0, reg0, 0, 31-1 /* size-1 */);
+#else
+ newLIR2(cUnit, kMipsSll, reg0, 1);
+ newLIR2(cUnit, kMipsSrl, reg0, 1);
+#endif
+ storeWordDisp(cUnit, rSELF, offset, reg0);
+ //TUNING: rewrite this to not clobber
+ dvmCompilerClobber(cUnit, reg0);
+ return false;
+}
+
+static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
+{
+ int offset = offsetof(Thread, interpSave.retval);
+ RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+ RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+ int reglo = regSrc.lowReg;
+ int reghi = regSrc.highReg;
+ storeWordDisp(cUnit, rSELF, offset + LOWORD_OFFSET, reglo);
+#if __mips_isa_rev>=2
+ newLIR4(cUnit, kMipsExt, reghi, reghi, 0, 31-1 /* size-1 */);
+#else
+ newLIR2(cUnit, kMipsSll, reghi, 1);
+ newLIR2(cUnit, kMipsSrl, reghi, 1);
+#endif
+ storeWordDisp(cUnit, rSELF, offset + HIWORD_OFFSET, reghi);
+ //TUNING: rewrite this to not clobber
+ dvmCompilerClobber(cUnit, reghi);
+ return false;
+}
+
+/* No select in thumb, so we need to branch. Thumb2 will do better */
+static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
+{
+ int offset = offsetof(Thread, interpSave.retval);
+ RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
+ RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
+ int reg0 = loadValue(cUnit, rlSrc1, kCoreReg).lowReg;
+ int reg1 = loadValue(cUnit, rlSrc2, kCoreReg).lowReg;
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ if (isMin) {
+ newLIR3(cUnit, kMipsSlt, tReg, reg0, reg1);
+ }
+ else {
+ newLIR3(cUnit, kMipsSlt, tReg, reg1, reg0);
+ }
+ newLIR3(cUnit, kMipsMovz, reg0, reg1, tReg);
+ dvmCompilerFreeTemp(cUnit, tReg);
+ newLIR3(cUnit, kMipsSw, reg0, offset, rSELF);
+ //TUNING: rewrite this to not clobber
+ dvmCompilerClobber(cUnit,reg0);
+ return false;
+}
+
+static void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit,
+ RegLocation rlSrc, RegLocation rlResult, int lit,
+ int firstBit, int secondBit)
+{
+ // We can't implement "add src, src, src, lsl#shift" on Thumb, so we have
+ // to do a regular multiply.
+ opRegRegImm(cUnit, kOpMul, rlResult.lowReg, rlSrc.lowReg, lit);
+}
diff --git a/vm/compiler/codegen/mips/Mips32/Ralloc.cpp b/vm/compiler/codegen/mips/Mips32/Ralloc.cpp
new file mode 100644
index 0000000..6810131
--- /dev/null
+++ b/vm/compiler/codegen/mips/Mips32/Ralloc.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen for the Mips ISA and is intended to be
+ * includes by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Alloc a pair of core registers, or a double. Low reg in low byte,
+ * high reg in next byte.
+ */
+int dvmCompilerAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
+ int regClass)
+{
+ int highReg;
+ int lowReg;
+ int res = 0;
+
+#ifdef __mips_hard_float
+ if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
+ lowReg = dvmCompilerAllocTempDouble(cUnit);
+ highReg = lowReg + 1;
+ res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+ return res;
+ }
+#endif
+
+ lowReg = dvmCompilerAllocTemp(cUnit);
+ highReg = dvmCompilerAllocTemp(cUnit);
+ res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+ return res;
+}
+
+int dvmCompilerAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
+{
+#ifdef __mips_hard_float
+ if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
+{
+ return dvmCompilerAllocTempFloat(cUnit);
+}
+#endif
+ return dvmCompilerAllocTemp(cUnit);
+}
diff --git a/vm/compiler/codegen/mips/MipsLIR.h b/vm/compiler/codegen/mips/MipsLIR.h
new file mode 100644
index 0000000..fc82da2
--- /dev/null
+++ b/vm/compiler/codegen/mips/MipsLIR.h
@@ -0,0 +1,644 @@
+/*
+ * 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.
+ */
+
+#ifndef DALVIK_VM_COMPILER_CODEGEN_MIPS_MIPSLIR_H_
+#define DALVIK_VM_COMPILER_CODEGEN_MIPS_MIPSLIR_H_
+
+#include "Dalvik.h"
+#include "compiler/CompilerInternals.h"
+
+/*
+ * zero is always the value 0
+ * at is scratch for Jit (normally used as temp reg by assembler)
+ * v0, v1 are scratch for Jit (normally hold subroutine return values)
+ * a0-a3 are scratch for Jit (normally hold subroutine arguments)
+ * t0-t7 are scratch for Jit
+ * t8 is scratch for Jit
+ * t9 is scratch for Jit (normally used for function calls)
+ * s0 (rFP) is reserved [holds Dalvik frame pointer]
+ * s1 (rSELF) is reserved [holds current &Thread]
+ * s2 (rINST) is scratch for Jit
+ * s3 (rIBASE) is scratch for Jit
+ * s4-s7 are scratch for Jit
+ * k0, k1 are reserved for use by interrupt handlers
+ * gp is reserved for global pointer
+ * sp is reserved
+ * s8 is scratch for Jit
+ * ra is scratch for Jit (normally holds the return addr)
+ *
+ * Preserved across C calls: s0-s8
+ * Trashed across C calls: at, v0-v1, a0-a3, t0-t9, gp, ra
+ *
+ * Floating pointer registers
+ * NOTE: there are 32 fp registers (16 df pairs), but current Jit code
+ * only support 16 fp registers (8 df pairs).
+ * f0-f15
+ * df0-df7, where df0={f0,f1}, df1={f2,f3}, ... , df7={f14,f15}
+ *
+ * f0-f15 (df0-df7) trashed across C calls
+ *
+ * For mips32 code use:
+ * a0-a3 to hold operands
+ * v0-v1 to hold results
+ * t0-t9 for temps
+ *
+ * All jump/branch instructions have a delay slot after it.
+ *
+ */
+
+/* Offset to distingish FP regs */
+#define FP_REG_OFFSET 32
+/* Offset to distinguish DP FP regs */
+#define FP_DOUBLE 64
+/* Offset to distingish the extra regs */
+#define EXTRA_REG_OFFSET 128
+/* Reg types */
+#define REGTYPE(x) (x & (FP_REG_OFFSET | FP_DOUBLE))
+#define FPREG(x) ((x & FP_REG_OFFSET) == FP_REG_OFFSET)
+#define EXTRAREG(x) ((x & EXTRA_REG_OFFSET) == EXTRA_REG_OFFSET)
+#define LOWREG(x) ((x & 0x1f) == x)
+#define DOUBLEREG(x) ((x & FP_DOUBLE) == FP_DOUBLE)
+#define SINGLEREG(x) (FPREG(x) && !DOUBLEREG(x))
+/*
+ * Note: the low register of a floating point pair is sufficient to
+ * create the name of a double, but require both names to be passed to
+ * allow for asserts to verify that the pair is consecutive if significant
+ * rework is done in this area. Also, it is a good reminder in the calling
+ * code that reg locations always describe doubles as a pair of singles.
+ */
+#define S2D(x,y) ((x) | FP_DOUBLE)
+/* Mask to strip off fp flags */
+#define FP_REG_MASK (FP_REG_OFFSET-1)
+/* non-existent Dalvik register */
+#define vNone (-1)
+/* non-existant physical register */
+#define rNone (-1)
+
+#ifdef HAVE_LITTLE_ENDIAN
+#define LOWORD_OFFSET 0
+#define HIWORD_OFFSET 4
+#define r_ARG0 r_A0
+#define r_ARG1 r_A1
+#define r_ARG2 r_A2
+#define r_ARG3 r_A3
+#define r_RESULT0 r_V0
+#define r_RESULT1 r_V1
+#else
+#define LOWORD_OFFSET 4
+#define HIWORD_OFFSET 0
+#define r_ARG0 r_A1
+#define r_ARG1 r_A0
+#define r_ARG2 r_A3
+#define r_ARG3 r_A2
+#define r_RESULT0 r_V1
+#define r_RESULT1 r_V0
+#endif
+
+/* These are the same for both big and little endian. */
+#define r_FARG0 r_F12
+#define r_FARG1 r_F13
+#define r_FRESULT0 r_F0
+#define r_FRESULT1 r_F1
+
+/* RegisterLocation templates return values (r_V0, or r_V0/r_V1) */
+#define LOC_C_RETURN {kLocPhysReg, 0, 0, r_V0, 0, -1}
+#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, r_RESULT0, r_RESULT1, -1}
+#define LOC_C_RETURN_ALT {kLocPhysReg, 0, 1, r_F0, 0, -1}
+#define LOC_C_RETURN_WIDE_ALT {kLocPhysReg, 1, 1, r_FRESULT0, r_FRESULT1, -1}
+/* RegisterLocation templates for interpState->retVal; */
+#define LOC_DALVIK_RETURN_VAL {kLocRetval, 0, 0, 0, 0, -1}
+#define LOC_DALVIK_RETURN_VAL_WIDE {kLocRetval, 1, 0, 0, 0, -1}
+
+ /*
+ * Data structure tracking the mapping between a Dalvik register (pair) and a
+ * native register (pair). The idea is to reuse the previously loaded value
+ * if possible, otherwise to keep the value in a native register as long as
+ * possible.
+ */
+typedef struct RegisterInfo {
+ int reg; // Reg number
+ bool inUse; // Has it been allocated?
+ bool pair; // Part of a register pair?
+ int partner; // If pair, other reg of pair
+ bool live; // Is there an associated SSA name?
+ bool dirty; // If live, is it dirty?
+ int sReg; // Name of live value
+ struct LIR *defStart; // Starting inst in last def sequence
+ struct LIR *defEnd; // Ending inst in last def sequence
+} RegisterInfo;
+
+typedef struct RegisterPool {
+ BitVector *nullCheckedRegs; // Track which registers have been null-checked
+ int numCoreTemps;
+ RegisterInfo *coreTemps;
+ int nextCoreTemp;
+ int numFPTemps;
+ RegisterInfo *FPTemps;
+ int nextFPTemp;
+} RegisterPool;
+
+typedef enum ResourceEncodingPos {
+ kGPReg0 = 0,
+ kRegSP = 29,
+ kRegLR = 31,
+ kFPReg0 = 32, /* only 16 fp regs supported currently */
+ kFPRegEnd = 48,
+ kRegHI = kFPRegEnd,
+ kRegLO,
+ kRegPC,
+ kRegEnd = 51,
+ kCCode = kRegEnd,
+ kFPStatus, // FP status word
+ // The following four bits are for memory disambiguation
+ kDalvikReg, // 1 Dalvik Frame (can be fully disambiguated)
+ kLiteral, // 2 Literal pool (can be fully disambiguated)
+ kHeapRef, // 3 Somewhere on the heap (alias with any other heap)
+ kMustNotAlias, // 4 Guaranteed to be non-alias (eg *(r6+x))
+} ResourceEncodingPos;
+
+#define ENCODE_REG_LIST(N) ((u8) N)
+#define ENCODE_REG_SP (1ULL << kRegSP)
+#define ENCODE_REG_LR (1ULL << kRegLR)
+#define ENCODE_REG_PC (1ULL << kRegPC)
+#define ENCODE_CCODE (1ULL << kCCode)
+#define ENCODE_FP_STATUS (1ULL << kFPStatus)
+
+/* Abstract memory locations */
+#define ENCODE_DALVIK_REG (1ULL << kDalvikReg)
+#define ENCODE_LITERAL (1ULL << kLiteral)
+#define ENCODE_HEAP_REF (1ULL << kHeapRef)
+#define ENCODE_MUST_NOT_ALIAS (1ULL << kMustNotAlias)
+
+#define ENCODE_ALL (~0ULL)
+#define ENCODE_MEM (ENCODE_DALVIK_REG | ENCODE_LITERAL | \
+ ENCODE_HEAP_REF | ENCODE_MUST_NOT_ALIAS)
+
+#define DECODE_ALIAS_INFO_REG(X) (X & 0xffff)
+#define DECODE_ALIAS_INFO_WIDE(X) ((X & 0x80000000) ? 1 : 0)
+
+typedef enum OpSize {
+ kWord,
+ kLong,
+ kSingle,
+ kDouble,
+ kUnsignedHalf,
+ kSignedHalf,
+ kUnsignedByte,
+ kSignedByte,
+} OpSize;
+
+typedef enum OpKind {
+ kOpMov,
+ kOpMvn,
+ kOpCmp,
+ kOpLsl,
+ kOpLsr,
+ kOpAsr,
+ kOpRor,
+ kOpNot,
+ kOpAnd,
+ kOpOr,
+ kOpXor,
+ kOpNeg,
+ kOpAdd,
+ kOpAdc,
+ kOpSub,
+ kOpSbc,
+ kOpRsub,
+ kOpMul,
+ kOpDiv,
+ kOpRem,
+ kOpBic,
+ kOpCmn,
+ kOpTst,
+ kOpBkpt,
+ kOpBlx,
+ kOpPush,
+ kOpPop,
+ kOp2Char,
+ kOp2Short,
+ kOp2Byte,
+ kOpCondBr,
+ kOpUncondBr,
+} OpKind;
+
+/*
+ * Annotate special-purpose core registers:
+ *
+ * rPC, rFP, and rSELF are for architecture-independent code to use.
+ */
+typedef enum NativeRegisterPool {
+ r_ZERO = 0,
+ r_AT = 1,
+ r_V0 = 2,
+ r_V1 = 3,
+ r_A0 = 4,
+ r_A1 = 5,
+ r_A2 = 6,
+ r_A3 = 7,
+ r_T0 = 8,
+ r_T1 = 9,
+ r_T2 = 10,
+ r_T3 = 11,
+ r_T4 = 12,
+ r_T5 = 13,
+ r_T6 = 14,
+ r_T7 = 15,
+ r_S0 = 16,
+ r_S1 = 17,
+ r_S2 = 18,
+ r_S3 = 19,
+ r_S4 = 20,
+ r_S5 = 21,
+ r_S6 = 22,
+ r_S7 = 23,
+ r_T8 = 24,
+ r_T9 = 25,
+ r_K0 = 26,
+ r_K1 = 27,
+ r_GP = 28,
+ r_SP = 29,
+ r_FP = 30,
+ r_RA = 31,
+
+ r_F0 = 0 + FP_REG_OFFSET,
+ r_F1,
+ r_F2,
+ r_F3,
+ r_F4,
+ r_F5,
+ r_F6,
+ r_F7,
+ r_F8,
+ r_F9,
+ r_F10,
+ r_F11,
+ r_F12,
+ r_F13,
+ r_F14,
+ r_F15,
+#if 0 /* only 16 fp regs supported currently */
+ r_F16,
+ r_F17,
+ r_F18,
+ r_F19,
+ r_F20,
+ r_F21,
+ r_F22,
+ r_F23,
+ r_F24,
+ r_F25,
+ r_F26,
+ r_F27,
+ r_F28,
+ r_F29,
+ r_F30,
+ r_F31,
+#endif
+ r_DF0 = r_F0 + FP_DOUBLE,
+ r_DF1 = r_F2 + FP_DOUBLE,
+ r_DF2 = r_F4 + FP_DOUBLE,
+ r_DF3 = r_F6 + FP_DOUBLE,
+ r_DF4 = r_F8 + FP_DOUBLE,
+ r_DF5 = r_F10 + FP_DOUBLE,
+ r_DF6 = r_F12 + FP_DOUBLE,
+ r_DF7 = r_F14 + FP_DOUBLE,
+#if 0 /* only 16 fp regs supported currently */
+ r_DF8 = r_F16 + FP_DOUBLE,
+ r_DF9 = r_F18 + FP_DOUBLE,
+ r_DF10 = r_F20 + FP_DOUBLE,
+ r_DF11 = r_F22 + FP_DOUBLE,
+ r_DF12 = r_F24 + FP_DOUBLE,
+ r_DF13 = r_F26 + FP_DOUBLE,
+ r_DF14 = r_F28 + FP_DOUBLE,
+ r_DF15 = r_F30 + FP_DOUBLE,
+#endif
+ r_HI = EXTRA_REG_OFFSET,
+ r_LO,
+ r_PC,
+} NativeRegisterPool;
+
+
+/* must match gp offset used mterp/mips files */
+#define STACK_OFFSET_GP 84
+
+/* MIPSTODO: properly remap arm regs (dPC, dFP, dGLUE) and remove these mappings */
+#define r4PC r_S0
+#define rFP r_S1
+#define rSELF r_S2
+#define rINST r_S4
+
+/* Shift encodings */
+typedef enum MipsShiftEncodings {
+ kMipsLsl = 0x0,
+ kMipsLsr = 0x1,
+ kMipsAsr = 0x2,
+ kMipsRor = 0x3
+} MipsShiftEncodings;
+
+/* condition encodings */
+typedef enum MipsConditionCode {
+ kMipsCondEq = 0x0, /* 0000 */
+ kMipsCondNe = 0x1, /* 0001 */
+ kMipsCondCs = 0x2, /* 0010 */
+ kMipsCondCc = 0x3, /* 0011 */
+ kMipsCondMi = 0x4, /* 0100 */
+ kMipsCondPl = 0x5, /* 0101 */
+ kMipsCondVs = 0x6, /* 0110 */
+ kMipsCondVc = 0x7, /* 0111 */
+ kMipsCondHi = 0x8, /* 1000 */
+ kMipsCondLs = 0x9, /* 1001 */
+ kMipsCondGe = 0xa, /* 1010 */
+ kMipsCondLt = 0xb, /* 1011 */
+ kMipsCondGt = 0xc, /* 1100 */
+ kMipsCondLe = 0xd, /* 1101 */
+ kMipsCondAl = 0xe, /* 1110 */
+ kMipsCondNv = 0xf, /* 1111 */
+} MipsConditionCode;
+
+#define isPseudoOpCode(opCode) ((int)(opCode) < 0)
+
+/*
+ * The following enum defines the list of supported Thumb instructions by the
+ * assembler. Their corresponding snippet positions will be defined in
+ * Assemble.c.
+ */
+typedef enum MipsOpCode {
+ kMipsChainingCellBottom = -18,
+ kMipsPseudoBarrier = -17,
+ kMipsPseudoExtended = -16,
+ kMipsPseudoSSARep = -15,
+ kMipsPseudoEntryBlock = -14,
+ kMipsPseudoExitBlock = -13,
+ kMipsPseudoTargetLabel = -12,
+ kMipsPseudoChainingCellBackwardBranch = -11,
+ kMipsPseudoChainingCellHot = -10,
+ kMipsPseudoChainingCellInvokePredicted = -9,
+ kMipsPseudoChainingCellInvokeSingleton = -8,
+ kMipsPseudoChainingCellNormal = -7,
+ kMipsPseudoDalvikByteCodeBoundary = -6,
+ kMipsPseudoPseudoAlign4 = -5,
+ kMipsPseudoPCReconstructionCell = -4,
+ kMipsPseudoPCReconstructionBlockLabel = -3,
+ kMipsPseudoEHBlockLabel = -2,
+ kMipsPseudoNormalBlockLabel = -1,
+
+ kMipsFirst,
+ kMips32BitData = kMipsFirst, /* data [31..0] */
+ kMipsAddiu, /* addiu t,s,imm16 [001001] s[25..21] t[20..16] imm16[15..0] */
+ kMipsAddu, /* add d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100001] */
+ kMipsAnd, /* and d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100100] */
+ kMipsAndi, /* andi t,s,imm16 [001100] s[25..21] t[20..16] imm16[15..0] */
+ kMipsB, /* b o [0001000000000000] o[15..0] */
+ kMipsBal, /* bal o [0000010000010001] o[15..0] */
+ /* NOTE: the code tests the range kMipsBeq thru kMipsBne, so
+ adding an instruction in this range may require updates */
+ kMipsBeq, /* beq s,t,o [000100] s[25..21] t[20..16] o[15..0] */
+ kMipsBeqz, /* beqz s,o [000100] s[25..21] [00000] o[15..0] */
+ kMipsBgez, /* bgez s,o [000001] s[25..21] [00001] o[15..0] */
+ kMipsBgtz, /* bgtz s,o [000111] s[25..21] [00000] o[15..0] */
+ kMipsBlez, /* blez s,o [000110] s[25..21] [00000] o[15..0] */
+ kMipsBltz, /* bltz s,o [000001] s[25..21] [00000] o[15..0] */
+ kMipsBnez, /* bnez s,o [000101] s[25..21] [00000] o[15..0] */
+ kMipsBne, /* bne s,t,o [000101] s[25..21] t[20..16] o[15..0] */
+ kMipsDiv, /* div s,t [000000] s[25..21] t[20..16] [0000000000011010] */
+#if __mips_isa_rev>=2
+ kMipsExt, /* ext t,s,p,z [011111] s[25..21] t[20..16] z[15..11] p[10..6] [000000] */
+#endif
+ kMipsJal, /* jal t [000011] t[25..0] */
+ kMipsJalr, /* jalr d,s [000000] s[25..21] [00000] d[15..11]
+ hint[10..6] [001001] */
+ kMipsJr, /* jr s [000000] s[25..21] [0000000000] hint[10..6] [001000] */
+ kMipsLahi, /* lui t,imm16 [00111100000] t[20..16] imm16[15..0] load addr hi */
+ kMipsLalo, /* ori t,s,imm16 [001001] s[25..21] t[20..16] imm16[15..0] load addr lo */
+ kMipsLui, /* lui t,imm16 [00111100000] t[20..16] imm16[15..0] */
+ kMipsLb, /* lb t,o(b) [100000] b[25..21] t[20..16] o[15..0] */
+ kMipsLbu, /* lbu t,o(b) [100100] b[25..21] t[20..16] o[15..0] */
+ kMipsLh, /* lh t,o(b) [100001] b[25..21] t[20..16] o[15..0] */
+ kMipsLhu, /* lhu t,o(b) [100101] b[25..21] t[20..16] o[15..0] */
+ kMipsLw, /* lw t,o(b) [100011] b[25..21] t[20..16] o[15..0] */
+ kMipsMfhi, /* mfhi d [0000000000000000] d[15..11] [00000010000] */
+ kMipsMflo, /* mflo d [0000000000000000] d[15..11] [00000010010] */
+ kMipsMove, /* move d,s [000000] s[25..21] [00000] d[15..11] [00000100101] */
+ kMipsMovz, /* movz d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000001010] */
+ kMipsMul, /* mul d,s,t [011100] s[25..21] t[20..16] d[15..11] [00000000010] */
+ kMipsNop, /* nop [00000000000000000000000000000000] */
+ kMipsNor, /* nor d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100111] */
+ kMipsOr, /* or d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100101] */
+ kMipsOri, /* ori t,s,imm16 [001001] s[25..21] t[20..16] imm16[15..0] */
+ kMipsPref, /* pref h,o(b) [101011] b[25..21] h[20..16] o[15..0] */
+ kMipsSb, /* sb t,o(b) [101000] b[25..21] t[20..16] o[15..0] */
+#if __mips_isa_rev>=2
+ kMipsSeb, /* seb d,t [01111100000] t[20..16] d[15..11] [10000100000] */
+ kMipsSeh, /* seh d,t [01111100000] t[20..16] d[15..11] [11000100000] */
+#endif
+ kMipsSh, /* sh t,o(b) [101001] b[25..21] t[20..16] o[15..0] */
+ kMipsSll, /* sll d,t,a [00000000000] t[20..16] d[15..11] a[10..6] [000000] */
+ kMipsSllv, /* sllv d,t,s [000000] s[25..21] t[20..16] d[15..11] [00000000100] */
+ kMipsSlt, /* slt d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000101010] */
+ kMipsSlti, /* slti t,s,imm16 [001010] s[25..21] t[20..16] imm16[15..0] */
+ kMipsSltu, /* sltu d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000101011] */
+ kMipsSra, /* sra d,s,imm5 [00000000000] t[20..16] d[15..11] imm5[10..6] [000011] */
+ kMipsSrav, /* srav d,t,s [000000] s[25..21] t[20..16] d[15..11] [00000000111] */
+ kMipsSrl, /* srl d,t,a [00000000000] t[20..16] d[20..16] a[10..6] [000010] */
+ kMipsSrlv, /* srlv d,t,s [000000] s[25..21] t[20..16] d[15..11] [00000000110] */
+ kMipsSubu, /* subu d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100011] */
+ kMipsSw, /* sw t,o(b) [101011] b[25..21] t[20..16] o[15..0] */
+ kMipsXor, /* xor d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100110] */
+ kMipsXori, /* xori t,s,imm16 [001110] s[25..21] t[20..16] imm16[15..0] */
+#ifdef __mips_hard_float
+ kMipsFadds, /* add.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000000] */
+ kMipsFsubs, /* sub.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000001] */
+ kMipsFmuls, /* mul.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000010] */
+ kMipsFdivs, /* div.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000011] */
+ kMipsFaddd, /* add.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000000] */
+ kMipsFsubd, /* sub.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000001] */
+ kMipsFmuld, /* mul.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000010] */
+ kMipsFdivd, /* div.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000011] */
+ kMipsFcvtsd, /* cvt.s.d d,s [01000110001] [00000] s[15..11] d[10..6] [100000] */
+ kMipsFcvtsw, /* cvt.s.w d,s [01000110100] [00000] s[15..11] d[10..6] [100000] */
+ kMipsFcvtds, /* cvt.d.s d,s [01000110000] [00000] s[15..11] d[10..6] [100001] */
+ kMipsFcvtdw, /* cvt.d.w d,s [01000110100] [00000] s[15..11] d[10..6] [100001] */
+ kMipsFcvtws, /* cvt.w.d d,s [01000110000] [00000] s[15..11] d[10..6] [100100] */
+ kMipsFcvtwd, /* cvt.w.d d,s [01000110001] [00000] s[15..11] d[10..6] [100100] */
+ kMipsFmovs, /* mov.s d,s [01000110000] [00000] s[15..11] d[10..6] [000110] */
+ kMipsFmovd, /* mov.d d,s [01000110001] [00000] s[15..11] d[10..6] [000110] */
+ kMipsFlwc1, /* lwc1 t,o(b) [110001] b[25..21] t[20..16] o[15..0] */
+ kMipsFldc1, /* ldc1 t,o(b) [110101] b[25..21] t[20..16] o[15..0] */
+ kMipsFswc1, /* swc1 t,o(b) [111001] b[25..21] t[20..16] o[15..0] */
+ kMipsFsdc1, /* sdc1 t,o(b) [111101] b[25..21] t[20..16] o[15..0] */
+ kMipsMfc1, /* mfc1 t,s [01000100000] t[20..16] s[15..11] [00000000000] */
+ kMipsMtc1, /* mtc1 t,s [01000100100] t[20..16] s[15..11] [00000000000] */
+#endif
+ kMipsUndefined, /* undefined [011001xxxxxxxxxxxxxxxx] */
+ kMipsLast
+} MipsOpCode;
+
+/* Bit flags describing the behavior of each native opcode */
+typedef enum MipsOpFeatureFlags {
+ kIsBranch = 0,
+ kRegDef0,
+ kRegDef1,
+ kRegDefSP,
+ kRegDefLR,
+ kRegDefList0,
+ kRegDefList1,
+ kRegUse0,
+ kRegUse1,
+ kRegUse2,
+ kRegUse3,
+ kRegUseSP,
+ kRegUsePC,
+ kRegUseList0,
+ kRegUseList1,
+ kNoOperand,
+ kIsUnaryOp,
+ kIsBinaryOp,
+ kIsTertiaryOp,
+ kIsQuadOp,
+ kIsIT,
+ kSetsCCodes,
+ kUsesCCodes,
+ kMemLoad,
+ kMemStore,
+} MipsOpFeatureFlags;
+
+#define IS_LOAD (1 << kMemLoad)
+#define IS_STORE (1 << kMemStore)
+#define IS_BRANCH (1 << kIsBranch)
+#define REG_DEF0 (1 << kRegDef0)
+#define REG_DEF1 (1 << kRegDef1)
+#define REG_DEF_SP (1 << kRegDefSP)
+#define REG_DEF_LR (1 << kRegDefLR)
+#define REG_DEF_LIST0 (1 << kRegDefList0)
+#define REG_DEF_LIST1 (1 << kRegDefList1)
+#define REG_USE0 (1 << kRegUse0)
+#define REG_USE1 (1 << kRegUse1)
+#define REG_USE2 (1 << kRegUse2)
+#define REG_USE3 (1 << kRegUse3)
+#define REG_USE_SP (1 << kRegUseSP)
+#define REG_USE_PC (1 << kRegUsePC)
+#define REG_USE_LIST0 (1 << kRegUseList0)
+#define REG_USE_LIST1 (1 << kRegUseList1)
+#define NO_OPERAND (1 << kNoOperand)
+#define IS_UNARY_OP (1 << kIsUnaryOp)
+#define IS_BINARY_OP (1 << kIsBinaryOp)
+#define IS_TERTIARY_OP (1 << kIsTertiaryOp)
+#define IS_QUAD_OP (1 << kIsQuadOp)
+#define IS_IT (1 << kIsIT)
+#define SETS_CCODES (1 << kSetsCCodes)
+#define USES_CCODES (1 << kUsesCCodes)
+
+/* Common combo register usage patterns */
+#define REG_USE01 (REG_USE0 | REG_USE1)
+#define REG_USE02 (REG_USE0 | REG_USE2)
+#define REG_USE012 (REG_USE01 | REG_USE2)
+#define REG_USE12 (REG_USE1 | REG_USE2)
+#define REG_USE23 (REG_USE2 | REG_USE3)
+#define REG_DEF01 (REG_DEF0 | REG_DEF1)
+#define REG_DEF0_USE0 (REG_DEF0 | REG_USE0)
+#define REG_DEF0_USE1 (REG_DEF0 | REG_USE1)
+#define REG_DEF0_USE2 (REG_DEF0 | REG_USE2)
+#define REG_DEF0_USE01 (REG_DEF0 | REG_USE01)
+#define REG_DEF0_USE12 (REG_DEF0 | REG_USE12)
+#define REG_DEF01_USE2 (REG_DEF0 | REG_DEF1 | REG_USE2)
+
+/* Instruction assembly fieldLoc kind */
+typedef enum MipsEncodingKind {
+ kFmtUnused,
+ kFmtBitBlt, /* Bit string using end/start */
+ kFmtDfp, /* Double FP reg */
+ kFmtSfp, /* Single FP reg */
+} MipsEncodingKind;
+
+/* Struct used to define the snippet positions for each Thumb opcode */
+typedef struct MipsEncodingMap {
+ u4 skeleton;
+ struct {
+ MipsEncodingKind kind;
+ int end; /* end for kFmtBitBlt, 1-bit slice end for FP regs */
+ int start; /* start for kFmtBitBlt, 4-bit slice end for FP regs */
+ } fieldLoc[4];
+ MipsOpCode opcode;
+ int flags;
+ const char *name;
+ const char* fmt;
+ int size;
+} MipsEncodingMap;
+
+/* Keys for target-specific scheduling and other optimization hints */
+typedef enum MipsTargetOptHints {
+ kMaxHoistDistance,
+} MipsTargetOptHints;
+
+extern MipsEncodingMap EncodingMap[kMipsLast];
+
+/*
+ * Each instance of this struct holds a pseudo or real LIR instruction:
+ * - pseudo ones (eg labels and marks) and will be discarded by the assembler.
+ * - real ones will be assembled into Thumb instructions.
+ *
+ * Machine resources are encoded into a 64-bit vector, where the encodings are
+ * as following:
+ * - [ 0..15]: general purpose registers including PC, SP, and LR
+ * - [16..47]: floating-point registers where d0 is expanded to s[01] and s0
+ * starts at bit 16
+ * - [48]: IT block
+ * - [49]: integer condition code
+ * - [50]: floatint-point status word
+ */
+typedef struct MipsLIR {
+ LIR generic;
+ MipsOpCode opcode;
+ int operands[4]; // [0..3] = [dest, src1, src2, extra]
+ struct {
+ bool isNop:1; // LIR is optimized away
+ bool insertWrapper:1; // insert branch to emulate memory accesses
+ unsigned int age:4; // default is 0, set lazily by the optimizer
+ unsigned int size:3; // bytes (2 for thumb, 2/4 for thumb2)
+ unsigned int unused:23;
+ } flags;
+ int aliasInfo; // For Dalvik register access & litpool disambiguation
+ u8 useMask; // Resource mask for use
+ u8 defMask; // Resource mask for def
+} MipsLIR;
+
+/* Init values when a predicted chain is initially assembled */
+/* E7FE is branch to self */
+#define PREDICTED_CHAIN_BX_PAIR_INIT 0xe7fe
+#define PREDICTED_CHAIN_DELAY_SLOT_INIT 0
+#define PREDICTED_CHAIN_CLAZZ_INIT 0
+#define PREDICTED_CHAIN_METHOD_INIT 0
+#define PREDICTED_CHAIN_COUNTER_INIT 0
+
+/* Utility macros to traverse the LIR/MipsLIR list */
+#define NEXT_LIR(lir) ((MipsLIR *) lir->generic.next)
+#define PREV_LIR(lir) ((MipsLIR *) lir->generic.prev)
+
+#define NEXT_LIR_LVALUE(lir) (lir)->generic.next
+#define PREV_LIR_LVALUE(lir) (lir)->generic.prev
+
+#define CHAIN_CELL_OFFSET_TAG 0xcdabcdabL
+
+#define IS_UIMM16(v) ((0 <= (v)) && ((v) <= 65535))
+#define IS_SIMM16(v) ((-32768 <= (v)) && ((v) <= 32766))
+#define IS_SIMM16_2WORD(v) ((-32764 <= (v)) && ((v) <= 32763)) /* 2 offsets must fit */
+
+#define CHAIN_CELL_NORMAL_SIZE 16
+#define CHAIN_CELL_PREDICTED_SIZE 20
+
+
+#endif // DALVIK_VM_COMPILER_CODEGEN_MIPS_MIPSLIR_H_
diff --git a/vm/compiler/codegen/mips/Ralloc.h b/vm/compiler/codegen/mips/Ralloc.h
new file mode 100644
index 0000000..33ad2fb
--- /dev/null
+++ b/vm/compiler/codegen/mips/Ralloc.h
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains register alloction support and is intended to be
+ * included by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "compiler/CompilerUtility.h"
+#include "compiler/CompilerIR.h"
+#include "compiler/Dataflow.h"
+#include "compiler/codegen/mips/MipsLIR.h"
+
+/*
+ * Return most flexible allowed register class based on size.
+ * Bug: 2813841
+ * Must use a core register for data types narrower than word (due
+ * to possible unaligned load/store.
+ */
+static inline RegisterClass dvmCompilerRegClassBySize(OpSize size)
+{
+ return (size == kUnsignedHalf ||
+ size == kSignedHalf ||
+ size == kUnsignedByte ||
+ size == kSignedByte ) ? kCoreReg : kAnyReg;
+}
+
+static inline int dvmCompilerS2VReg(CompilationUnit *cUnit, int sReg)
+{
+ assert(sReg != INVALID_SREG);
+ return DECODE_REG(dvmConvertSSARegToDalvik(cUnit, sReg));
+}
+
+/* Reset the tracker to unknown state */
+static inline void dvmCompilerResetNullCheck(CompilationUnit *cUnit)
+{
+ dvmClearAllBits(cUnit->regPool->nullCheckedRegs);
+}
+
+/*
+ * Get the "real" sreg number associated with an sReg slot. In general,
+ * sReg values passed through codegen are the SSA names created by
+ * dataflow analysis and refer to slot numbers in the cUnit->regLocation
+ * array. However, renaming is accomplished by simply replacing RegLocation
+ * entries in the cUnit->reglocation[] array. Therefore, when location
+ * records for operands are first created, we need to ask the locRecord
+ * identified by the dataflow pass what it's new name is.
+ */
+
+static inline int dvmCompilerSRegHi(int lowSreg) {
+ return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
+}
+
+
+static inline bool dvmCompilerLiveOut(CompilationUnit *cUnit, int sReg)
+{
+ //TODO: fully implement
+ return true;
+}
+
+static inline int dvmCompilerSSASrc(MIR *mir, int num)
+{
+ assert(mir->ssaRep->numUses > num);
+ return mir->ssaRep->uses[num];
+}
+
+extern RegLocation dvmCompilerEvalLoc(CompilationUnit *cUnit, RegLocation loc,
+ int regClass, bool update);
+/* Mark a temp register as dead. Does not affect allocation state. */
+extern void dvmCompilerClobber(CompilationUnit *cUnit, int reg);
+
+extern RegLocation dvmCompilerUpdateLoc(CompilationUnit *cUnit,
+ RegLocation loc);
+
+/* see comments for updateLoc */
+extern RegLocation dvmCompilerUpdateLocWide(CompilationUnit *cUnit,
+ RegLocation loc);
+
+/* Clobber all of the temps that might be used by a handler. */
+extern void dvmCompilerClobberHandlerRegs(CompilationUnit *cUnit);
+
+extern void dvmCompilerMarkLive(CompilationUnit *cUnit, int reg, int sReg);
+
+extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg);
+
+extern void dvmCompilerMarkPair(CompilationUnit *cUnit, int lowReg,
+ int highReg);
+
+extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg);
+
+extern void dvmCompilerResetDef(CompilationUnit *cUnit, int reg);
+
+extern void dvmCompilerResetDefLoc(CompilationUnit *cUnit, RegLocation rl);
+
+/* Set up temp & preserved register pools specialized by target */
+extern void dvmCompilerInitPool(RegisterInfo *regs, int *regNums, int num);
+
+/*
+ * Mark the beginning and end LIR of a def sequence. Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+extern void dvmCompilerMarkDef(CompilationUnit *cUnit, RegLocation rl,
+ LIR *start, LIR *finish);
+/*
+ * Mark the beginning and end LIR of a def sequence. Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+extern void dvmCompilerMarkDefWide(CompilationUnit *cUnit, RegLocation rl,
+ LIR *start, LIR *finish);
+
+extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir,
+ int low, int high);
+
+extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir,
+ int low, int high);
+// Get the LocRecord associated with an SSA name use.
+extern RegLocation dvmCompilerGetSrc(CompilationUnit *cUnit, MIR *mir, int num);
+
+// Get the LocRecord associated with an SSA name def.
+extern RegLocation dvmCompilerGetDest(CompilationUnit *cUnit, MIR *mir,
+ int num);
+
+extern RegLocation dvmCompilerGetReturnWide(CompilationUnit *cUnit);
+
+/* Clobber all regs that might be used by an external C call */
+extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit);
+
+extern RegisterInfo *dvmCompilerIsTemp(CompilationUnit *cUnit, int reg);
+
+extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg);
+
+extern int dvmCompilerAllocTemp(CompilationUnit *cUnit);
+
+extern int dvmCompilerAllocTempFloat(CompilationUnit *cUnit);
+
+//REDO: too many assumptions.
+extern int dvmCompilerAllocTempDouble(CompilationUnit *cUnit);
+
+extern void dvmCompilerFreeTemp(CompilationUnit *cUnit, int reg);
+
+extern void dvmCompilerResetDefLocWide(CompilationUnit *cUnit, RegLocation rl);
+
+extern void dvmCompilerResetDefTracking(CompilationUnit *cUnit);
+
+/* Kill the corresponding bit in the null-checked register list */
+extern void dvmCompilerKillNullCheckedLoc(CompilationUnit *cUnit,
+ RegLocation loc);
+
+//FIXME - this needs to also check the preserved pool.
+extern RegisterInfo *dvmCompilerIsLive(CompilationUnit *cUnit, int reg);
+
+/* To be used when explicitly managing register use */
+extern void dvmCompilerLockAllTemps(CompilationUnit *cUnit);
+
+extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit);
+
+extern RegLocation dvmCompilerGetReturnWideAlt(CompilationUnit *cUnit);
+
+extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit);
+
+extern RegLocation dvmCompilerGetReturnAlt(CompilationUnit *cUnit);
+
+/* Clobber any temp associated with an sReg. Could be in either class */
+extern void dvmCompilerClobberSReg(CompilationUnit *cUnit, int sReg);
+
+/* Return a temp if one is available, -1 otherwise */
+extern int dvmCompilerAllocFreeTemp(CompilationUnit *cUnit);
+
+/*
+ * Similar to dvmCompilerAllocTemp(), but forces the allocation of a specific
+ * register. No check is made to see if the register was previously
+ * allocated. Use with caution.
+ */
+extern void dvmCompilerLockTemp(CompilationUnit *cUnit, int reg);
+
+extern RegLocation dvmCompilerWideToNarrow(CompilationUnit *cUnit,
+ RegLocation rl);
+
+/*
+ * Free all allocated temps in the temp pools. Note that this does
+ * not affect the "liveness" of a temp register, which will stay
+ * live until it is either explicitly killed or reallocated.
+ */
+extern void dvmCompilerResetRegPool(CompilationUnit *cUnit);
+
+extern void dvmCompilerClobberAllRegs(CompilationUnit *cUnit);
+
+extern void dvmCompilerResetDefTracking(CompilationUnit *cUnit);
diff --git a/vm/compiler/codegen/mips/RallocUtil.cpp b/vm/compiler/codegen/mips/RallocUtil.cpp
new file mode 100644
index 0000000..b13dddf
--- /dev/null
+++ b/vm/compiler/codegen/mips/RallocUtil.cpp
@@ -0,0 +1,1025 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains register alloction support and is intended to be
+ * included by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "compiler/CompilerUtility.h"
+#include "compiler/CompilerIR.h"
+#include "compiler/Dataflow.h"
+#include "MipsLIR.h"
+#include "Codegen.h"
+#include "Ralloc.h"
+
+#define SREG(c, s) ((c)->regLocation[(s)].sRegLow)
+/*
+ * Get the "real" sreg number associated with an sReg slot. In general,
+ * sReg values passed through codegen are the SSA names created by
+ * dataflow analysis and refer to slot numbers in the cUnit->regLocation
+ * array. However, renaming is accomplished by simply replacing RegLocation
+ * entries in the cUnit->reglocation[] array. Therefore, when location
+ * records for operands are first created, we need to ask the locRecord
+ * identified by the dataflow pass what it's new name is.
+ */
+
+/*
+ * Free all allocated temps in the temp pools. Note that this does
+ * not affect the "liveness" of a temp register, which will stay
+ * live until it is either explicitly killed or reallocated.
+ */
+extern void dvmCompilerResetRegPool(CompilationUnit *cUnit)
+{
+ int i;
+ for (i=0; i < cUnit->regPool->numCoreTemps; i++) {
+ cUnit->regPool->coreTemps[i].inUse = false;
+ }
+ for (i=0; i < cUnit->regPool->numFPTemps; i++) {
+ cUnit->regPool->FPTemps[i].inUse = false;
+ }
+}
+
+ /* Set up temp & preserved register pools specialized by target */
+extern void dvmCompilerInitPool(RegisterInfo *regs, int *regNums, int num)
+{
+ int i;
+ for (i=0; i < num; i++) {
+ regs[i].reg = regNums[i];
+ regs[i].inUse = false;
+ regs[i].pair = false;
+ regs[i].live = false;
+ regs[i].dirty = false;
+ regs[i].sReg = INVALID_SREG;
+ }
+}
+
+static void dumpRegPool(RegisterInfo *p, int numRegs)
+{
+ int i;
+ ALOGE("================================================");
+ for (i=0; i < numRegs; i++ ){
+ ALOGE("R[%d]: U:%d, P:%d, part:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x",
+ p[i].reg, p[i].inUse, p[i].pair, p[i].partner, p[i].live,
+ p[i].dirty, p[i].sReg,(int)p[i].defStart, (int)p[i].defEnd);
+ }
+ ALOGE("================================================");
+}
+
+static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg)
+{
+ int numTemps = cUnit->regPool->numCoreTemps;
+ RegisterInfo *p = cUnit->regPool->coreTemps;
+ int i;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ return &p[i];
+ }
+ }
+ p = cUnit->regPool->FPTemps;
+ numTemps = cUnit->regPool->numFPTemps;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ return &p[i];
+ }
+ }
+ ALOGE("Tried to get info on a non-existant temp: r%d",reg);
+ dvmCompilerAbort(cUnit);
+ return NULL;
+}
+
+static void flushRegWide(CompilationUnit *cUnit, int reg1, int reg2)
+{
+ RegisterInfo *info1 = getRegInfo(cUnit, reg1);
+ RegisterInfo *info2 = getRegInfo(cUnit, reg2);
+ assert(info1 && info2 && info1->pair && info2->pair &&
+ (info1->partner == info2->reg) &&
+ (info2->partner == info1->reg));
+ if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
+ info1->dirty = false;
+ info2->dirty = false;
+ if (dvmCompilerS2VReg(cUnit, info2->sReg) <
+ dvmCompilerS2VReg(cUnit, info1->sReg))
+ info1 = info2;
+ dvmCompilerFlushRegWideImpl(cUnit, rFP,
+ dvmCompilerS2VReg(cUnit, info1->sReg) << 2,
+ info1->reg, info1->partner);
+ }
+}
+
+static void flushReg(CompilationUnit *cUnit, int reg)
+{
+ RegisterInfo *info = getRegInfo(cUnit, reg);
+ if (info->live && info->dirty) {
+ info->dirty = false;
+ dvmCompilerFlushRegImpl(cUnit, rFP,
+ dvmCompilerS2VReg(cUnit, info->sReg) << 2,
+ reg, kWord);
+ }
+}
+
+/* return true if found reg to clobber */
+static bool clobberRegBody(CompilationUnit *cUnit, RegisterInfo *p,
+ int numTemps, int reg)
+{
+ int i;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ if (p[i].live && p[i].dirty) {
+ if (p[i].pair) {
+ flushRegWide(cUnit, p[i].reg, p[i].partner);
+ } else {
+ flushReg(cUnit, p[i].reg);
+ }
+ }
+ p[i].live = false;
+ p[i].sReg = INVALID_SREG;
+ p[i].defStart = NULL;
+ p[i].defEnd = NULL;
+ if (p[i].pair) {
+ p[i].pair = false;
+ /* partners should be in same pool */
+ clobberRegBody(cUnit, p, numTemps, p[i].partner);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Mark a temp register as dead. Does not affect allocation state. */
+void dvmCompilerClobber(CompilationUnit *cUnit, int reg)
+{
+ if (!clobberRegBody(cUnit, cUnit->regPool->coreTemps,
+ cUnit->regPool->numCoreTemps, reg)) {
+ clobberRegBody(cUnit, cUnit->regPool->FPTemps,
+ cUnit->regPool->numFPTemps, reg);
+ }
+}
+
+static void clobberSRegBody(RegisterInfo *p, int numTemps, int sReg)
+{
+ int i;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].sReg == sReg) {
+ p[i].live = false;
+ p[i].defStart = NULL;
+ p[i].defEnd = NULL;
+ }
+ }
+}
+
+/* Clobber any temp associated with an sReg. Could be in either class */
+extern void dvmCompilerClobberSReg(CompilationUnit *cUnit, int sReg)
+{
+ clobberSRegBody(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps,
+ sReg);
+ clobberSRegBody(cUnit->regPool->FPTemps, cUnit->regPool->numFPTemps,
+ sReg);
+}
+
+static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps,
+ int *nextTemp, bool required)
+{
+ int i;
+ int next = *nextTemp;
+ for (i=0; i< numTemps; i++) {
+ if (next >= numTemps)
+ next = 0;
+ if (!p[next].inUse && !p[next].live) {
+ dvmCompilerClobber(cUnit, p[next].reg);
+ p[next].inUse = true;
+ p[next].pair = false;
+ *nextTemp = next + 1;
+ return p[next].reg;
+ }
+ next++;
+ }
+ next = *nextTemp;
+ for (i=0; i< numTemps; i++) {
+ if (next >= numTemps)
+ next = 0;
+ if (!p[next].inUse) {
+ dvmCompilerClobber(cUnit, p[next].reg);
+ p[next].inUse = true;
+ p[next].pair = false;
+ *nextTemp = next + 1;
+ return p[next].reg;
+ }
+ next++;
+ }
+ if (required) {
+ ALOGE("No free temp registers");
+ dvmCompilerAbort(cUnit);
+ }
+ return -1; // No register available
+}
+
+//REDO: too many assumptions.
+extern int dvmCompilerAllocTempDouble(CompilationUnit *cUnit)
+{
+ RegisterInfo *p = cUnit->regPool->FPTemps;
+ int numTemps = cUnit->regPool->numFPTemps;
+ /* Cleanup - not all targets need aligned regs */
+ int start = cUnit->regPool->nextFPTemp + (cUnit->regPool->nextFPTemp & 1);
+ int next = start;
+ int i;
+
+ for (i=0; i < numTemps; i+=2) {
+ if (next >= numTemps)
+ next = 0;
+ if ((!p[next].inUse && !p[next].live) &&
+ (!p[next+1].inUse && !p[next+1].live)) {
+ dvmCompilerClobber(cUnit, p[next].reg);
+ dvmCompilerClobber(cUnit, p[next+1].reg);
+ p[next].inUse = true;
+ p[next+1].inUse = true;
+ assert((p[next].reg+1) == p[next+1].reg);
+ assert((p[next].reg & 0x1) == 0);
+ cUnit->regPool->nextFPTemp += 2;
+ return p[next].reg;
+ }
+ next += 2;
+ }
+ next = start;
+ for (i=0; i < numTemps; i+=2) {
+ if (next >= numTemps)
+ next = 0;
+ if (!p[next].inUse && !p[next+1].inUse) {
+ dvmCompilerClobber(cUnit, p[next].reg);
+ dvmCompilerClobber(cUnit, p[next+1].reg);
+ p[next].inUse = true;
+ p[next+1].inUse = true;
+ assert((p[next].reg+1) == p[next+1].reg);
+ assert((p[next].reg & 0x1) == 0);
+ cUnit->regPool->nextFPTemp += 2;
+ return p[next].reg;
+ }
+ next += 2;
+ }
+ ALOGE("No free temp registers");
+ dvmCompilerAbort(cUnit);
+ return -1;
+}
+
+/* Return a temp if one is available, -1 otherwise */
+extern int dvmCompilerAllocFreeTemp(CompilationUnit *cUnit)
+{
+ return allocTempBody(cUnit, cUnit->regPool->coreTemps,
+ cUnit->regPool->numCoreTemps,
+ &cUnit->regPool->nextCoreTemp, true);
+}
+
+extern int dvmCompilerAllocTemp(CompilationUnit *cUnit)
+{
+ return allocTempBody(cUnit, cUnit->regPool->coreTemps,
+ cUnit->regPool->numCoreTemps,
+ &cUnit->regPool->nextCoreTemp, true);
+}
+
+extern int dvmCompilerAllocTempFloat(CompilationUnit *cUnit)
+{
+ return allocTempBody(cUnit, cUnit->regPool->FPTemps,
+ cUnit->regPool->numFPTemps,
+ &cUnit->regPool->nextFPTemp, true);
+}
+
+static RegisterInfo *allocLiveBody(RegisterInfo *p, int numTemps, int sReg)
+{
+ int i;
+ if (sReg == -1)
+ return NULL;
+ for (i=0; i < numTemps; i++) {
+ if (p[i].live && (p[i].sReg == sReg)) {
+ p[i].inUse = true;
+ return &p[i];
+ }
+ }
+ return NULL;
+}
+
+static RegisterInfo *allocLive(CompilationUnit *cUnit, int sReg,
+ int regClass)
+{
+ RegisterInfo *res = NULL;
+ switch(regClass) {
+ case kAnyReg:
+ res = allocLiveBody(cUnit->regPool->FPTemps,
+ cUnit->regPool->numFPTemps, sReg);
+ if (res)
+ break;
+ /* Intentional fallthrough */
+ case kCoreReg:
+ res = allocLiveBody(cUnit->regPool->coreTemps,
+ cUnit->regPool->numCoreTemps, sReg);
+ break;
+ case kFPReg:
+ res = allocLiveBody(cUnit->regPool->FPTemps,
+ cUnit->regPool->numFPTemps, sReg);
+ break;
+ default:
+ ALOGE("Invalid register type");
+ dvmCompilerAbort(cUnit);
+ }
+ return res;
+}
+
+extern void dvmCompilerFreeTemp(CompilationUnit *cUnit, int reg)
+{
+ RegisterInfo *p = cUnit->regPool->coreTemps;
+ int numTemps = cUnit->regPool->numCoreTemps;
+ int i;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ p[i].inUse = false;
+ p[i].pair = false;
+ return;
+ }
+ }
+ p = cUnit->regPool->FPTemps;
+ numTemps = cUnit->regPool->numFPTemps;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ p[i].inUse = false;
+ p[i].pair = false;
+ return;
+ }
+ }
+ ALOGE("Tried to free a non-existant temp: r%d",reg);
+ dvmCompilerAbort(cUnit);
+}
+
+/*
+ * FIXME - this needs to also check the preserved pool once we start
+ * start using preserved registers.
+ */
+extern RegisterInfo *dvmCompilerIsLive(CompilationUnit *cUnit, int reg)
+{
+ RegisterInfo *p = cUnit->regPool->coreTemps;
+ int numTemps = cUnit->regPool->numCoreTemps;
+ int i;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ return p[i].live ? &p[i] : NULL;
+ }
+ }
+ p = cUnit->regPool->FPTemps;
+ numTemps = cUnit->regPool->numFPTemps;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ return p[i].live ? &p[i] : NULL;
+ }
+ }
+ return NULL;
+}
+
+extern RegisterInfo *dvmCompilerIsTemp(CompilationUnit *cUnit, int reg)
+{
+ RegisterInfo *p = cUnit->regPool->coreTemps;
+ int numTemps = cUnit->regPool->numCoreTemps;
+ int i;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ return &p[i];
+ }
+ }
+ p = cUnit->regPool->FPTemps;
+ numTemps = cUnit->regPool->numFPTemps;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ return &p[i];
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Similar to dvmCompilerAllocTemp(), but forces the allocation of a specific
+ * register. No check is made to see if the register was previously
+ * allocated. Use with caution.
+ */
+extern void dvmCompilerLockTemp(CompilationUnit *cUnit, int reg)
+{
+ RegisterInfo *p = cUnit->regPool->coreTemps;
+ int numTemps = cUnit->regPool->numCoreTemps;
+ int i;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ p[i].inUse = true;
+ p[i].live = false;
+ return;
+ }
+ }
+ p = cUnit->regPool->FPTemps;
+ numTemps = cUnit->regPool->numFPTemps;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ p[i].inUse = true;
+ p[i].live = false;
+ return;
+ }
+ }
+ ALOGE("Tried to lock a non-existant temp: r%d",reg);
+ dvmCompilerAbort(cUnit);
+}
+
+/* Clobber all regs that might be used by an external C call */
+extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit)
+{
+ dvmCompilerClobber(cUnit, r_ZERO);
+ dvmCompilerClobber(cUnit, r_AT);
+ dvmCompilerClobber(cUnit, r_V0);
+ dvmCompilerClobber(cUnit, r_V1);
+ dvmCompilerClobber(cUnit, r_A0);
+ dvmCompilerClobber(cUnit, r_A1);
+ dvmCompilerClobber(cUnit, r_A2);
+ dvmCompilerClobber(cUnit, r_A3);
+ dvmCompilerClobber(cUnit, r_T0);
+ dvmCompilerClobber(cUnit, r_T1);
+ dvmCompilerClobber(cUnit, r_T2);
+ dvmCompilerClobber(cUnit, r_T3);
+ dvmCompilerClobber(cUnit, r_T4);
+ dvmCompilerClobber(cUnit, r_T5);
+ dvmCompilerClobber(cUnit, r_T6);
+ dvmCompilerClobber(cUnit, r_T7);
+ dvmCompilerClobber(cUnit, r_T8);
+ dvmCompilerClobber(cUnit, r_T9);
+ dvmCompilerClobber(cUnit, r_K0);
+ dvmCompilerClobber(cUnit, r_K1);
+ dvmCompilerClobber(cUnit, r_GP);
+ dvmCompilerClobber(cUnit, r_FP);
+ dvmCompilerClobber(cUnit, r_RA);
+ dvmCompilerClobber(cUnit, r_HI);
+ dvmCompilerClobber(cUnit, r_LO);
+ dvmCompilerClobber(cUnit, r_F0);
+ dvmCompilerClobber(cUnit, r_F1);
+ dvmCompilerClobber(cUnit, r_F2);
+ dvmCompilerClobber(cUnit, r_F3);
+ dvmCompilerClobber(cUnit, r_F4);
+ dvmCompilerClobber(cUnit, r_F5);
+ dvmCompilerClobber(cUnit, r_F6);
+ dvmCompilerClobber(cUnit, r_F7);
+ dvmCompilerClobber(cUnit, r_F8);
+ dvmCompilerClobber(cUnit, r_F9);
+ dvmCompilerClobber(cUnit, r_F10);
+ dvmCompilerClobber(cUnit, r_F11);
+ dvmCompilerClobber(cUnit, r_F12);
+ dvmCompilerClobber(cUnit, r_F13);
+ dvmCompilerClobber(cUnit, r_F14);
+ dvmCompilerClobber(cUnit, r_F15);
+}
+
+/* Clobber all of the temps that might be used by a handler. */
+extern void dvmCompilerClobberHandlerRegs(CompilationUnit *cUnit)
+{
+ //TUNING: reduce the set of regs used by handlers. Only a few need lots.
+ dvmCompilerClobberCallRegs(cUnit);
+ dvmCompilerClobber(cUnit, r_S0);
+ dvmCompilerClobber(cUnit, r_S1);
+ dvmCompilerClobber(cUnit, r_S2);
+ dvmCompilerClobber(cUnit, r_S3);
+ dvmCompilerClobber(cUnit, r_S4);
+ dvmCompilerClobber(cUnit, r_S5);
+ dvmCompilerClobber(cUnit, r_S6);
+ dvmCompilerClobber(cUnit, r_S7);
+}
+
+extern void dvmCompilerResetDef(CompilationUnit *cUnit, int reg)
+{
+ RegisterInfo *p = getRegInfo(cUnit, reg);
+ p->defStart = NULL;
+ p->defEnd = NULL;
+}
+
+static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish,
+ int sReg1, int sReg2)
+{
+ if (start && finish) {
+ LIR *p;
+ assert(sReg1 == sReg2);
+ for (p = start; ;p = p->next) {
+ ((MipsLIR *)p)->flags.isNop = true;
+ if (p == finish)
+ break;
+ }
+ }
+}
+
+/*
+ * Mark the beginning and end LIR of a def sequence. Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+extern void dvmCompilerMarkDef(CompilationUnit *cUnit, RegLocation rl,
+ LIR *start, LIR *finish)
+{
+ assert(!rl.wide);
+ assert(start && start->next);
+ assert(finish);
+ RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+ p->defStart = start->next;
+ p->defEnd = finish;
+}
+
+/*
+ * Mark the beginning and end LIR of a def sequence. Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+extern void dvmCompilerMarkDefWide(CompilationUnit *cUnit, RegLocation rl,
+ LIR *start, LIR *finish)
+{
+ assert(rl.wide);
+ assert(start && start->next);
+ assert(finish);
+ RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+ dvmCompilerResetDef(cUnit, rl.highReg); // Only track low of pair
+ p->defStart = start->next;
+ p->defEnd = finish;
+}
+
+extern RegLocation dvmCompilerWideToNarrow(CompilationUnit *cUnit,
+ RegLocation rl)
+{
+ assert(rl.wide);
+ if (rl.location == kLocPhysReg) {
+ RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg);
+ RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg);
+ if (!infoLo->pair) {
+ dumpRegPool(cUnit->regPool->coreTemps,
+ cUnit->regPool->numCoreTemps);
+ assert(infoLo->pair);
+ }
+ if (!infoHi->pair) {
+ dumpRegPool(cUnit->regPool->coreTemps,
+ cUnit->regPool->numCoreTemps);
+ assert(infoHi->pair);
+ }
+ assert(infoLo->pair);
+ assert(infoHi->pair);
+ assert(infoLo->partner == infoHi->reg);
+ assert(infoHi->partner == infoLo->reg);
+ infoLo->pair = false;
+ infoHi->pair = false;
+ infoLo->defStart = NULL;
+ infoLo->defEnd = NULL;
+ infoHi->defStart = NULL;
+ infoHi->defEnd = NULL;
+ }
+#ifndef HAVE_LITTLE_ENDIAN
+ else if (rl.location == kLocDalvikFrame) {
+ rl.sRegLow = dvmCompilerSRegHi(rl.sRegLow);
+ }
+#endif
+
+ rl.wide = false;
+ return rl;
+}
+
+extern void dvmCompilerResetDefLoc(CompilationUnit *cUnit, RegLocation rl)
+{
+ assert(!rl.wide);
+ if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
+ RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+ assert(!p->pair);
+ nullifyRange(cUnit, p->defStart, p->defEnd,
+ p->sReg, rl.sRegLow);
+ }
+ dvmCompilerResetDef(cUnit, rl.lowReg);
+}
+
+extern void dvmCompilerResetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
+{
+ assert(rl.wide);
+ if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
+ RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+ assert(p->pair);
+ nullifyRange(cUnit, p->defStart, p->defEnd,
+ p->sReg, rl.sRegLow);
+ }
+ dvmCompilerResetDef(cUnit, rl.lowReg);
+ dvmCompilerResetDef(cUnit, rl.highReg);
+}
+
+extern void dvmCompilerResetDefTracking(CompilationUnit *cUnit)
+{
+ int i;
+ for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
+ dvmCompilerResetDef(cUnit, cUnit->regPool->coreTemps[i].reg);
+ }
+ for (i=0; i< cUnit->regPool->numFPTemps; i++) {
+ dvmCompilerResetDef(cUnit, cUnit->regPool->FPTemps[i].reg);
+ }
+}
+
+extern void dvmCompilerClobberAllRegs(CompilationUnit *cUnit)
+{
+ int i;
+ for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
+ dvmCompilerClobber(cUnit, cUnit->regPool->coreTemps[i].reg);
+ }
+ for (i=0; i< cUnit->regPool->numFPTemps; i++) {
+ dvmCompilerClobber(cUnit, cUnit->regPool->FPTemps[i].reg);
+ }
+}
+
+/* To be used when explicitly managing register use */
+extern void dvmCompilerLockAllTemps(CompilationUnit *cUnit)
+{
+ int i;
+ for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
+ dvmCompilerLockTemp(cUnit, cUnit->regPool->coreTemps[i].reg);
+ }
+}
+
+// Make sure nothing is live and dirty
+static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info,
+ int numRegs)
+{
+ int i;
+ for (i=0; i < numRegs; i++) {
+ if (info[i].live && info[i].dirty) {
+ if (info[i].pair) {
+ flushRegWide(cUnit, info[i].reg, info[i].partner);
+ } else {
+ flushReg(cUnit, info[i].reg);
+ }
+ }
+ }
+}
+
+extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit)
+{
+ flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
+ cUnit->regPool->numCoreTemps);
+ flushAllRegsBody(cUnit, cUnit->regPool->FPTemps,
+ cUnit->regPool->numFPTemps);
+ dvmCompilerClobberAllRegs(cUnit);
+}
+
+
+//TUNING: rewrite all of this reg stuff. Probably use an attribute table
+static bool regClassMatches(int regClass, int reg)
+{
+ if (regClass == kAnyReg) {
+ return true;
+ } else if (regClass == kCoreReg) {
+ return !FPREG(reg);
+ } else {
+ return FPREG(reg);
+ }
+}
+
+extern void dvmCompilerMarkLive(CompilationUnit *cUnit, int reg, int sReg)
+{
+ RegisterInfo *info = getRegInfo(cUnit, reg);
+ if ((info->reg == reg) && (info->sReg == sReg) && info->live) {
+ return; /* already live */
+ } else if (sReg != INVALID_SREG) {
+ dvmCompilerClobberSReg(cUnit, sReg);
+ info->live = true;
+ } else {
+ /* Can't be live if no associated sReg */
+ info->live = false;
+ }
+ info->sReg = sReg;
+}
+
+extern void dvmCompilerMarkPair(CompilationUnit *cUnit, int lowReg, int highReg)
+{
+ RegisterInfo *infoLo = getRegInfo(cUnit, lowReg);
+ RegisterInfo *infoHi = getRegInfo(cUnit, highReg);
+ infoLo->pair = infoHi->pair = true;
+ infoLo->partner = highReg;
+ infoHi->partner = lowReg;
+}
+
+extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg)
+{
+ RegisterInfo *info = getRegInfo(cUnit, reg);
+ info->dirty = false;
+}
+
+extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg)
+{
+ RegisterInfo *info = getRegInfo(cUnit, reg);
+ info->dirty = true;
+}
+
+extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg)
+{
+ RegisterInfo *info = getRegInfo(cUnit, reg);
+ info->inUse = true;
+}
+
+void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg)
+{
+ RegisterInfo *newInfo = getRegInfo(cUnit, newReg);
+ RegisterInfo *oldInfo = getRegInfo(cUnit, oldReg);
+ *newInfo = *oldInfo;
+ newInfo->reg = newReg;
+}
+
+/*
+ * Return an updated location record with current in-register status.
+ * If the value lives in live temps, reflect that fact. No code
+ * is generated. The the live value is part of an older pair,
+ * clobber both low and high.
+ * TUNING: clobbering both is a bit heavy-handed, but the alternative
+ * is a bit complex when dealing with FP regs. Examine code to see
+ * if it's worthwhile trying to be more clever here.
+ */
+extern RegLocation dvmCompilerUpdateLoc(CompilationUnit *cUnit, RegLocation loc)
+{
+ assert(!loc.wide);
+ if (loc.location == kLocDalvikFrame) {
+ RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
+ if (infoLo) {
+ if (infoLo->pair) {
+ dvmCompilerClobber(cUnit, infoLo->reg);
+ dvmCompilerClobber(cUnit, infoLo->partner);
+ } else {
+ loc.lowReg = infoLo->reg;
+ loc.location = kLocPhysReg;
+ }
+ }
+ }
+
+ return loc;
+}
+
+/* see comments for updateLoc */
+extern RegLocation dvmCompilerUpdateLocWide(CompilationUnit *cUnit,
+ RegLocation loc)
+{
+ assert(loc.wide);
+ if (loc.location == kLocDalvikFrame) {
+ // Are the dalvik regs already live in physical registers?
+ RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
+ RegisterInfo *infoHi = allocLive(cUnit,
+ dvmCompilerSRegHi(loc.sRegLow), kAnyReg);
+ bool match = true;
+ match = match && (infoLo != NULL);
+ match = match && (infoHi != NULL);
+ // Are they both core or both FP?
+ match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
+ // If a pair of floating point singles, are they properly aligned?
+ if (match && FPREG(infoLo->reg)) {
+ match &= ((infoLo->reg & 0x1) == 0);
+ match &= ((infoHi->reg - infoLo->reg) == 1);
+ }
+ // If previously used as a pair, it is the same pair?
+ if (match && (infoLo->pair || infoHi->pair)) {
+ match = (infoLo->pair == infoHi->pair);
+ match &= ((infoLo->reg == infoHi->partner) &&
+ (infoHi->reg == infoLo->partner));
+ }
+ if (match) {
+ // Can reuse - update the register usage info
+ loc.lowReg = infoLo->reg;
+ loc.highReg = infoHi->reg;
+ loc.location = kLocPhysReg;
+ dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
+ assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+ return loc;
+ }
+ // Can't easily reuse - clobber any overlaps
+ if (infoLo) {
+ dvmCompilerClobber(cUnit, infoLo->reg);
+ if (infoLo->pair)
+ dvmCompilerClobber(cUnit, infoLo->partner);
+ }
+ if (infoHi) {
+ dvmCompilerClobber(cUnit, infoHi->reg);
+ if (infoHi->pair)
+ dvmCompilerClobber(cUnit, infoHi->partner);
+ }
+ }
+
+ return loc;
+}
+
+static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
+ int regClass, bool update)
+{
+ assert(loc.wide);
+ int newRegs;
+ int lowReg;
+ int highReg;
+
+ loc = dvmCompilerUpdateLocWide(cUnit, loc);
+
+ /* If already in registers, we can assume proper form. Right reg class? */
+ if (loc.location == kLocPhysReg) {
+ assert(FPREG(loc.lowReg) == FPREG(loc.highReg));
+ assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+ if (!regClassMatches(regClass, loc.lowReg)) {
+ /* Wrong register class. Reallocate and copy */
+ newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
+ lowReg = newRegs & 0xff;
+ highReg = (newRegs >> 8) & 0xff;
+ dvmCompilerRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
+ loc.highReg);
+ copyRegInfo(cUnit, lowReg, loc.lowReg);
+ copyRegInfo(cUnit, highReg, loc.highReg);
+ dvmCompilerClobber(cUnit, loc.lowReg);
+ dvmCompilerClobber(cUnit, loc.highReg);
+ loc.lowReg = lowReg;
+ loc.highReg = highReg;
+ dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
+ assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+ }
+ return loc;
+ }
+
+ assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
+ assert((loc.location != kLocRetval) ||
+ (dvmCompilerSRegHi(loc.sRegLow) == INVALID_SREG));
+
+ newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
+ loc.lowReg = newRegs & 0xff;
+ loc.highReg = (newRegs >> 8) & 0xff;
+
+ dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
+ if (update) {
+ loc.location = kLocPhysReg;
+ dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow);
+ dvmCompilerMarkLive(cUnit, loc.highReg, dvmCompilerSRegHi(loc.sRegLow));
+ }
+ assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+ return loc;
+}
+
+extern RegLocation dvmCompilerEvalLoc(CompilationUnit *cUnit, RegLocation loc,
+ int regClass, bool update)
+{
+ int newReg;
+ if (loc.wide)
+ return evalLocWide(cUnit, loc, regClass, update);
+ loc = dvmCompilerUpdateLoc(cUnit, loc);
+
+ if (loc.location == kLocPhysReg) {
+ if (!regClassMatches(regClass, loc.lowReg)) {
+ /* Wrong register class. Realloc, copy and transfer ownership */
+ newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
+ dvmCompilerRegCopy(cUnit, newReg, loc.lowReg);
+ copyRegInfo(cUnit, newReg, loc.lowReg);
+ dvmCompilerClobber(cUnit, loc.lowReg);
+ loc.lowReg = newReg;
+ }
+ return loc;
+ }
+
+ assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
+
+ newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
+ loc.lowReg = newReg;
+
+ if (update) {
+ loc.location = kLocPhysReg;
+ dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow);
+ }
+ return loc;
+}
+
+static inline int getDestSSAName(MIR *mir, int num)
+{
+ assert(mir->ssaRep->numDefs > num);
+ return mir->ssaRep->defs[num];
+}
+
+// Get the LocRecord associated with an SSA name use.
+extern RegLocation dvmCompilerGetSrc(CompilationUnit *cUnit, MIR *mir, int num)
+{
+ RegLocation loc = cUnit->regLocation[
+ SREG(cUnit, dvmCompilerSSASrc(mir, num))];
+ loc.fp = cUnit->regLocation[dvmCompilerSSASrc(mir, num)].fp;
+ loc.wide = false;
+ return loc;
+}
+
+// Get the LocRecord associated with an SSA name def.
+extern RegLocation dvmCompilerGetDest(CompilationUnit *cUnit, MIR *mir,
+ int num)
+{
+ RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))];
+ loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp;
+ loc.wide = false;
+ return loc;
+}
+
+static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir,
+ int low, int high, bool isSrc)
+{
+ RegLocation lowLoc;
+ RegLocation highLoc;
+ /* Copy loc record for low word and patch in data from high word */
+ if (isSrc) {
+ lowLoc = dvmCompilerGetSrc(cUnit, mir, low);
+ highLoc = dvmCompilerGetSrc(cUnit, mir, high);
+ } else {
+ lowLoc = dvmCompilerGetDest(cUnit, mir, low);
+ highLoc = dvmCompilerGetDest(cUnit, mir, high);
+ }
+ /* Avoid this case by either promoting both or neither. */
+ assert(lowLoc.location == highLoc.location);
+ if (lowLoc.location == kLocPhysReg) {
+ /* This case shouldn't happen if we've named correctly */
+ assert(lowLoc.fp == highLoc.fp);
+ }
+ lowLoc.wide = true;
+ lowLoc.highReg = highLoc.lowReg;
+ return lowLoc;
+}
+
+extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir,
+ int low, int high)
+{
+ return getLocWide(cUnit, mir, low, high, false);
+}
+
+extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir,
+ int low, int high)
+{
+ return getLocWide(cUnit, mir, low, high, true);
+}
+
+extern RegLocation dvmCompilerGetReturnWide(CompilationUnit *cUnit)
+{
+ RegLocation res = LOC_C_RETURN_WIDE;
+ dvmCompilerClobber(cUnit, r_V0);
+ dvmCompilerClobber(cUnit, r_V1);
+ dvmCompilerMarkInUse(cUnit, r_V0);
+ dvmCompilerMarkInUse(cUnit, r_V1);
+ dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
+ return res;
+}
+
+extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit)
+{
+ RegLocation res = LOC_C_RETURN;
+ dvmCompilerClobber(cUnit, r_V0);
+ dvmCompilerMarkInUse(cUnit, r_V0);
+ return res;
+}
+
+extern RegLocation dvmCompilerGetReturnWideAlt(CompilationUnit *cUnit)
+{
+ RegLocation res = LOC_C_RETURN_WIDE_ALT;
+ dvmCompilerClobber(cUnit, r_F0);
+ dvmCompilerClobber(cUnit, r_F1);
+ dvmCompilerMarkInUse(cUnit, r_F0);
+ dvmCompilerMarkInUse(cUnit, r_F1);
+ dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
+ return res;
+}
+
+extern RegLocation dvmCompilerGetReturnAlt(CompilationUnit *cUnit)
+{
+ RegLocation res = LOC_C_RETURN_ALT;
+ dvmCompilerClobber(cUnit, r_F0);
+ dvmCompilerMarkInUse(cUnit, r_F0);
+ return res;
+}
+
+/* Kill the corresponding bit in the null-checked register list */
+extern void dvmCompilerKillNullCheckedLoc(CompilationUnit *cUnit,
+ RegLocation loc)
+{
+ if (loc.location != kLocRetval) {
+ assert(loc.sRegLow != INVALID_SREG);
+ dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
+ if (loc.wide) {
+ assert(dvmCompilerSRegHi(loc.sRegLow) != INVALID_SREG);
+ dvmClearBit(cUnit->regPool->nullCheckedRegs,
+ dvmCompilerSRegHi(loc.sRegLow));
+ }
+ }
+}
+
+extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
+ int reg1, int reg2)
+{
+ flushRegWide(cUnit, reg1, reg2);
+}
+
+extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg)
+{
+ flushReg(cUnit, reg);
+}
diff --git a/vm/compiler/codegen/mips/mips/ArchVariant.cpp b/vm/compiler/codegen/mips/mips/ArchVariant.cpp
new file mode 100644
index 0000000..9204a58
--- /dev/null
+++ b/vm/compiler/codegen/mips/mips/ArchVariant.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+extern "C" void dvmCompilerTemplateStart(void);
+
+/*
+ * This file is included by Codegen-mips.c, and implements architecture
+ * variant-specific code.
+ */
+
+/*
+ * Determine the initial instruction set to be used for this trace.
+ * Later components may decide to change this.
+ */
+JitInstructionSetType dvmCompilerInstructionSet(void)
+{
+ return DALVIK_JIT_MIPS;
+}
+
+/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
+#define JIT_TEMPLATE(X) extern "C" void dvmCompiler_TEMPLATE_##X();
+#include "../../../template/mips/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+/* Architecture-specific initializations and checks go here */
+bool dvmCompilerArchVariantInit(void)
+{
+ int i = 0;
+
+ /*
+ * Then, populate the templateEntryOffsets array with the offsets from the
+ * the dvmCompilerTemplateStart symbol for each template.
+ */
+#define JIT_TEMPLATE(X) templateEntryOffsets[i++] = \
+ (intptr_t) dvmCompiler_TEMPLATE_##X - (intptr_t) dvmCompilerTemplateStart;
+#include "../../../template/mips/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+ /* Target-specific configuration */
+ gDvmJit.jitTableSize = 1 << 9; // 512
+ gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+ gDvmJit.threshold = 200;
+ gDvmJit.codeCacheSize = 512*1024;
+
+#if defined(WITH_SELF_VERIFICATION)
+ /* Force into blocking mode */
+ gDvmJit.blockingMode = true;
+ gDvm.nativeDebuggerActive = true;
+#endif
+
+ /* Codegen-specific assumptions */
+ assert(OFFSETOF_MEMBER(ClassObject, vtable) < 128 &&
+ (OFFSETOF_MEMBER(ClassObject, vtable) & 0x3) == 0);
+ assert(OFFSETOF_MEMBER(ArrayObject, length) < 128 &&
+ (OFFSETOF_MEMBER(ArrayObject, length) & 0x3) == 0);
+ assert(OFFSETOF_MEMBER(ArrayObject, contents) < 256);
+
+ /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
+ assert(sizeof(StackSaveArea) < 236);
+
+ /*
+ * EA is calculated by doing "Rn + imm5 << 2", make sure that the last
+ * offset from the struct is less than 128.
+ */
+ assert((offsetof(Thread, jitToInterpEntries) +
+ sizeof(struct JitToInterpEntries)) < 128);
+
+ /* FIXME - comment out the following to enable method-based JIT */
+ gDvmJit.disableOpt |= (1 << kMethodJit);
+
+ // Make sure all threads have current values
+ dvmJitUpdateThreadStateAll();
+
+ return true;
+}
+
+int dvmCompilerTargetOptHint(int key)
+{
+ int res;
+ switch (key) {
+ case kMaxHoistDistance:
+ res = 2;
+ break;
+ default:
+ ALOGE("Unknown target optimization hint key: %d",key);
+ res = 0;
+ }
+ return res;
+}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
+{
+ __asm__ __volatile__ ("" : : : "memory");
+}
diff --git a/vm/compiler/codegen/mips/mips/ArchVariant.h b/vm/compiler/codegen/mips/mips/ArchVariant.h
new file mode 100644
index 0000000..ec04dd8
--- /dev/null
+++ b/vm/compiler/codegen/mips/mips/ArchVariant.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef DALVIK_VM_COMPILER_CODEGEN_MIPS_ARCHVARIANT_H_
+#define DALVIK_VM_COMPILER_CODEGEN_MIPS_ARCHVARIANT_H_
+
+/* Create the TemplateOpcode enum */
+#define JIT_TEMPLATE(X) TEMPLATE_##X,
+enum TemplateOpcode{
+#include "../../../template/mips/TemplateOpList.h"
+/*
+ * For example,
+ * TEMPLATE_CMP_LONG,
+ * TEMPLATE_RETURN,
+ * ...
+ */
+ TEMPLATE_LAST_MARK,
+};
+#undef JIT_TEMPLATE
+
+#endif // DALVIK_VM_COMPILER_CODEGEN_MIPS_ARCHVARIANT_H_
diff --git a/vm/compiler/codegen/mips/mips/CallingConvention.S b/vm/compiler/codegen/mips/mips/CallingConvention.S
new file mode 100644
index 0000000..ab97655
--- /dev/null
+++ b/vm/compiler/codegen/mips/mips/CallingConvention.S
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ * a0 : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+ .text
+ .align 2
+ .global dvmJitCalleeSave
+ .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+ jr $31
+
+ .global dvmJitCalleeRestore
+ .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+ jr $31
diff --git a/vm/compiler/codegen/mips/mips/Codegen.cpp b/vm/compiler/codegen/mips/mips/Codegen.cpp
new file mode 100644
index 0000000..2c7456e
--- /dev/null
+++ b/vm/compiler/codegen/mips/mips/Codegen.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+ #define _CODEGEN_C
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/DexOpcodes.h"
+#include "compiler/CompilerInternals.h"
+#include "compiler/codegen/mips/MipsLIR.h"
+#include "mterp/common/FindInterface.h"
+#include "compiler/codegen/mips/Ralloc.h"
+#include "compiler/codegen/mips/Codegen.h"
+#include "compiler/Loop.h"
+#include "ArchVariant.h"
+
+/* Architectural independent building blocks */
+#include "../CodegenCommon.cpp"
+
+/* Architectural independent building blocks */
+#include "../Mips32/Factory.cpp"
+/* Factory utilities dependent on arch-specific features */
+#include "../CodegenFactory.cpp"
+
+/* Thumb-specific codegen routines */
+#include "../Mips32/Gen.cpp"
+/* Thumb+Portable FP codegen routines */
+#include "../FP/MipsFP.cpp"
+
+/* Thumb-specific register allocation */
+#include "../Mips32/Ralloc.cpp"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.cpp"
+
+/* Dummy driver for method-based JIT */
+#include "MethodCodegenDriver.cpp"
+
+/* Architecture manifest */
+#include "ArchVariant.cpp"
diff --git a/vm/compiler/codegen/mips/mips/MethodCodegenDriver.cpp b/vm/compiler/codegen/mips/mips/MethodCodegenDriver.cpp
new file mode 100644
index 0000000..55c2d89
--- /dev/null
+++ b/vm/compiler/codegen/mips/mips/MethodCodegenDriver.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit)
+{
+ ALOGE("Method-based JIT not supported for the Mips target");
+ dvmAbort();
+}
diff --git a/vm/compiler/codegen/x86/AnalysisO1.cpp b/vm/compiler/codegen/x86/AnalysisO1.cpp
new file mode 100644
index 0000000..d7e9726
--- /dev/null
+++ b/vm/compiler/codegen/x86/AnalysisO1.cpp
@@ -0,0 +1,5315 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file AnalysisO1.cpp
+ \brief This file implements register allocator, constant folding
+*/
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "Lower.h"
+#include "interp/InterpState.h"
+#include "interp/InterpDefs.h"
+#include "libdex/Leb128.h"
+
+/* compilation flags to turn on debug printout */
+//#define DEBUG_COMPILE_TABLE
+//#define DEBUG_ALLOC_CONSTRAINT
+//#define DEBUG_REGALLOC
+//#define DEBUG_REG_USED
+//#define DEBUG_REFCOUNT
+//#define DEBUG_REACHING_DEF2
+//#define DEBUG_REACHING_DEF
+//#define DEBUG_LIVE_RANGE
+//#define DEBUG_MOVE_OPT
+//#define DEBUG_SPILL
+//#define DEBUG_ENDOFBB
+//#define DEBUG_CONST
+/*
+ #define DEBUG_XFER_POINTS
+ #define DEBUG_DSE
+ #define DEBUG_CFG
+ #define DEBUG_GLOBALTYPE
+ #define DEBUG_STATE
+ #define DEBUG_COMPILE_TABLE
+ #define DEBUG_VIRTUAL_INFO
+ #define DEBUG_MOVE_OPT
+ #define DEBUG_MERGE_ENTRY
+ #define DEBUG_INVALIDATE
+*/
+#include "AnalysisO1.h"
+
+void dumpCompileTable();
+
+/* There are 3 kinds of variables that are handled in this file:
+ 1> virtual register (isVirtualReg())
+ 2> temporary (!isVirtualReg() && regNum < PhysicalReg_GLUE_DVMDEX)
+ 3> glue variables: regNum >= PhysicalReg_GLUE_DVMDEX
+*/
+/** check whether a variable is a virtual register
+ */
+bool isVirtualReg(int type) {
+ if((type & LowOpndRegType_virtual) != 0) return true;
+ return false;
+}
+bool isTemporary(int type, int regNum) {
+ if(!isVirtualReg(type) && regNum < PhysicalReg_GLUE_DVMDEX) return true;
+ return false;
+}
+
+/** convert type defined in lowering module to type defined in register allocator
+ in lowering module <type, isPhysical>
+ in register allocator: LowOpndRegType_hard LowOpndRegType_virtual LowOpndRegType_scratch
+*/
+int convertType(int type, int reg, bool isPhysical) {
+ int newType = type;
+ if(isPhysical) newType |= LowOpndRegType_hard;
+ if(isVirtualReg(type)) newType |= LowOpndRegType_virtual;
+ else {
+ /* reg number for a VR can exceed PhysicalReg_SCRATCH_1 */
+ if(reg >= PhysicalReg_SCRATCH_1 && reg < PhysicalReg_GLUE_DVMDEX)
+ newType |= LowOpndRegType_scratch;
+ }
+ return newType;
+}
+
+/** return the size of a variable
+ */
+OpndSize getRegSize(int type) {
+ if((type & MASK_FOR_TYPE) == LowOpndRegType_xmm) return OpndSize_64;
+ if((type & MASK_FOR_TYPE) == LowOpndRegType_fs) return OpndSize_64;
+ /* for type _gp, _fs_s, _ss */
+ return OpndSize_32;
+}
+
+/*
+ Overlapping cases between two variables A and B
+ layout for A,B isAPartiallyOverlapB isBPartiallyOverlapA
+ 1> |__| |____| OVERLAP_ALIGN OVERLAP_B_COVER_A
+ |__| |____|
+ 2> |____| OVERLAP_B_IS_LOW_OF_A OVERLAP_B_COVER_LOW_OF_A
+ |__|
+ 3> |____| OVERLAP_B_IS_HIGH_OF_A OVERLAP_B_COVER_HIGH_OF_A
+ |__|
+ 4> |____| OVERLAP_LOW_OF_A_IS_HIGH_OF_B OVERLAP_B_COVER_LOW_OF_A
+ |____|
+ 5> |____| OVERLAP_HIGH_OF_A_IS_LOW_OF_B OVERLAP_B_COVER_HIGH_OF_A
+ |____|
+ 6> |__| OVERLAP_A_IS_LOW_OF_B OVERLAP_B_COVER_A
+ |____|
+ 7> |__| OVERLAP_A_IS_HIGH_OF_B OVERLAP_B_COVER_A
+ |____|
+*/
+/** determine the overlapping between variable B and A
+*/
+OverlapCase getBPartiallyOverlapA(int regB, LowOpndRegType tB, int regA, LowOpndRegType tA) {
+ if(getRegSize(tA) == getRegSize(tB) && regA == regB) return OVERLAP_B_COVER_A;
+ if(getRegSize(tA) == OpndSize_64 && getRegSize(tB) == OpndSize_32 && regA == regB) return OVERLAP_B_COVER_LOW_OF_A;
+ if(getRegSize(tA) == OpndSize_64 && getRegSize(tB) == OpndSize_32 && regB == regA + 1) return OVERLAP_B_COVER_HIGH_OF_A;
+ if(getRegSize(tA) == OpndSize_32 && getRegSize(tB) == OpndSize_64 && (regA == regB || regA == regB+1)) return OVERLAP_B_COVER_A;
+ if(getRegSize(tB) == OpndSize_64 && getRegSize(tA) == OpndSize_64 && regA == regB+1) return OVERLAP_B_COVER_LOW_OF_A;
+ if(getRegSize(tB) == OpndSize_64 && getRegSize(tA) == OpndSize_64 && regB == regA+1) return OVERLAP_B_COVER_HIGH_OF_A;
+ return OVERLAP_NO;
+}
+
+/** determine overlapping between variable A and B
+*/
+OverlapCase getAPartiallyOverlapB(int regA, LowOpndRegType tA, int regB, LowOpndRegType tB) {
+ if(getRegSize(tA) == getRegSize(tB) && regA == regB) return OVERLAP_ALIGN;
+ if(getRegSize(tA) == OpndSize_64 && getRegSize(tB) == OpndSize_32 && regA == regB)
+ return OVERLAP_B_IS_LOW_OF_A;
+ if(getRegSize(tA) == OpndSize_64 && getRegSize(tB) == OpndSize_32 && regB == regA+1)
+ return OVERLAP_B_IS_HIGH_OF_A;
+ if(getRegSize(tB) == OpndSize_64 && getRegSize(tA) == OpndSize_64 && regA == regB+1)
+ return OVERLAP_LOW_OF_A_IS_HIGH_OF_B;
+ if(getRegSize(tB) == OpndSize_64 && getRegSize(tA) == OpndSize_64 && regB == regA+1)
+ return OVERLAP_HIGH_OF_A_IS_LOW_OF_B;
+ if(getRegSize(tA) == OpndSize_32 && getRegSize(tB) == OpndSize_64 && regA == regB)
+ return OVERLAP_A_IS_LOW_OF_B;
+ if(getRegSize(tA) == OpndSize_32 && getRegSize(tB) == OpndSize_64 && regA == regB+1)
+ return OVERLAP_A_IS_HIGH_OF_B;
+ return OVERLAP_NO;
+}
+
+/** determine whether variable A fully covers B
+ */
+bool isAFullyCoverB(int regA, LowOpndRegType tA, int regB, LowOpndRegType tB) {
+ if(getRegSize(tB) == OpndSize_32) return true;
+ if(getRegSize(tA) == getRegSize(tB) && regA == regB) return true;
+ return false;
+}
+
+/*
+ RegAccessType accessType
+ 1> DefOrUse.accessType
+ can only be D(VR), L(low part of VR), H(high part of VR), N(none)
+ for def, it means which part of the VR is live
+ for use, it means which part of the VR comes from the def
+ 2> VirtualRegInfo.accessType
+ for currentInfo, it can only be a combination of U & D
+ for entries in infoBasicBlock, it can be a combination of U & D|L|H
+*/
+
+/*
+ Key data structures used:
+ 1> BasicBlock_O1
+ VirtualRegInfo infoBasicBlock[]
+ DefUsePair* defUseTable
+ XferPoint xferPoints[]
+ 2> MemoryVRInfo memVRTable[]
+ LiveRange* ranges
+ 3> compileTableEntry compileTable[]
+ 4> VirtualRegInfo
+ DefOrUse reachingDefs[3]
+ 5> DefUsePair, LiveRange
+*/
+
+//! one entry for each variable used
+
+//! a variable can be virtual register, or a temporary (can be hard-coded)
+compileTableEntry compileTable[COMPILE_TABLE_SIZE];
+int num_compile_entries;
+//! tables to save the states of register allocation
+regAllocStateEntry1 stateTable1_1[COMPILE_TABLE_SIZE];
+regAllocStateEntry1 stateTable1_2[COMPILE_TABLE_SIZE];
+regAllocStateEntry1 stateTable1_3[COMPILE_TABLE_SIZE];
+regAllocStateEntry1 stateTable1_4[COMPILE_TABLE_SIZE];
+regAllocStateEntry2 stateTable2_1[COMPILE_TABLE_SIZE];
+regAllocStateEntry2 stateTable2_2[COMPILE_TABLE_SIZE];
+regAllocStateEntry2 stateTable2_3[COMPILE_TABLE_SIZE];
+regAllocStateEntry2 stateTable2_4[COMPILE_TABLE_SIZE];
+
+//! array of VirtualRegInfo to store VRs accessed by a single bytecode
+VirtualRegInfo infoByteCode[MAX_REG_PER_BYTECODE];
+int num_regs_per_bytecode;
+//! array of TempRegInfo to store temporaries accessed by a single bytecode
+TempRegInfo infoByteCodeTemp[MAX_TEMP_REG_PER_BYTECODE];
+int num_temp_regs_per_bytecode;
+//! array of MemoryVRInfo to store whether a VR is in memory
+#define NUM_MEM_VR_ENTRY 140
+MemoryVRInfo memVRTable[NUM_MEM_VR_ENTRY];
+int num_memory_vr;
+
+CompilationUnit* currentUnit = NULL;
+
+//! the current basic block
+BasicBlock_O1* currentBB = NULL;
+//! array of RegisterInfo for all the physical registers
+RegisterInfo allRegs[PhysicalReg_GLUE+1]; //initialized in codeGen
+
+VirtualRegInfo currentInfo;
+VirtualRegInfo tmpInfo;
+
+//! this array says whether a spill location is used (0 means not used, 1 means used)
+int spillIndexUsed[MAX_SPILL_JIT_IA];
+int indexForGlue = -1;
+
+int num_bbs_for_method;
+//! array of basic blocks in a method in program order
+BasicBlock_O1* method_bbs_sorted[MAX_NUM_BBS_PER_METHOD];
+//! the entry basic block
+BasicBlock_O1* bb_entry;
+int pc_start = -1;
+int pc_end = -1;
+
+//!array of PCs for exception handlers
+int exceptionHandlers[10];
+int num_exception_handlers;
+
+bool canSpillReg[PhysicalReg_Null]; //physical registers that should not be spilled
+int inGetVR_num = -1;
+int inGetVR_type;
+
+///////////////////////////////////////////////////////////////////////////////
+// FORWARD FUNCTION DECLARATION
+void addExceptionHandler(s4 tmp);
+
+int createCFG(Method* method);
+int collectInfoOfBasicBlock(Method* method, BasicBlock_O1* bb);
+void dumpVirtualInfoOfBasicBlock(BasicBlock_O1* bb);
+void setTypeOfVR();
+void insertGlueReg();
+void dumpVirtualInfoOfMethod();
+int codeGenBasicBlock(const Method* method, BasicBlock_O1* bb);
+
+//used in collectInfoOfBasicBlock: getVirtualRegInfo
+int mergeEntry2(BasicBlock_O1* bb);
+int sortAllocConstraint(RegAllocConstraint* allocConstraints,
+ RegAllocConstraint* allocConstraintsSorted, bool fromHighToLow);
+
+//used in codeGenBasicBlock
+void insertFromVirtualInfo(BasicBlock_O1* bb, int k); //update compileTable
+void insertFromTempInfo(int k); //update compileTable
+int updateXferPoints();
+void updateLiveTable();
+void printDefUseTable();
+bool isFirstOfHandler(BasicBlock_O1* bb);
+
+//used in mergeEntry2
+//following functions will not update global data structure
+RegAccessType mergeAccess2(RegAccessType A, RegAccessType B, OverlapCase isBPartiallyOverlapA);
+RegAccessType updateAccess1(RegAccessType A, OverlapCase isAPartiallyOverlapB); //will not update global data structure
+RegAccessType updateAccess2(RegAccessType C1, RegAccessType C2);
+RegAccessType updateAccess3(RegAccessType C, RegAccessType B);
+
+void updateDefUseTable();
+void updateReachingDefA(int indexToA, OverlapCase isBPartiallyOverlapA);
+void updateReachingDefB1(int indexToA);
+void updateReachingDefB2();
+void updateReachingDefB3();
+
+RegAccessType insertAUse(DefUsePair* ptr, int offsetPC, int regNum, LowOpndRegType physicalType);
+DefUsePair* insertADef(int offsetPC, int regNum, LowOpndRegType pType, RegAccessType rType);
+RegAccessType insertDefUsePair(int reachingDefIndex);
+
+//used in updateXferPoints
+int fakeUsageAtEndOfBB(BasicBlock_O1* bb);
+void insertLoadXfer(int offset, int regNum, LowOpndRegType pType);
+int searchMemTable(int regNum);
+void mergeLiveRange(int tableIndex, int rangeStart, int rangeEnd);
+//used in updateLiveTable
+RegAccessType setAccessTypeOfUse(OverlapCase isDefPartiallyOverlapUse, RegAccessType reachingDefLive);
+DefUsePair* searchDefUseTable(int offsetPC, int regNum, LowOpndRegType pType);
+void insertAccess(int tableIndex, LiveRange* startP, int rangeStart);
+
+//register allocation
+int spillLogicalReg(int spill_index, bool updateTable);
+
+/** check whether the current bytecode is IF or GOTO or SWITCH
+ */
+bool isCurrentByteCodeJump() {
+ u2 inst_op = INST_INST(inst);
+ if(inst_op == OP_IF_EQ || inst_op == OP_IF_NE || inst_op == OP_IF_LT ||
+ inst_op == OP_IF_GE || inst_op == OP_IF_GT || inst_op == OP_IF_LE) return true;
+ if(inst_op == OP_IF_EQZ || inst_op == OP_IF_NEZ || inst_op == OP_IF_LTZ ||
+ inst_op == OP_IF_GEZ || inst_op == OP_IF_GTZ || inst_op == OP_IF_LEZ) return true;
+ if(inst_op == OP_GOTO || inst_op == OP_GOTO_16 || inst_op == OP_GOTO_32) return true;
+ if(inst_op == OP_PACKED_SWITCH || inst_op == OP_SPARSE_SWITCH) return true;
+ return false;
+}
+
+/* this function is called before code generation of basic blocks
+ initialize data structure allRegs, which stores information for each physical register,
+ whether it is used, when it was last freed, whether it is callee-saved */
+void initializeAllRegs() {
+ int k;
+ for(k = PhysicalReg_EAX; k <= PhysicalReg_EBP; k++) {
+ allRegs[k].physicalReg = (PhysicalReg) k;
+ if(k == PhysicalReg_EDI || k == PhysicalReg_ESP || k == PhysicalReg_EBP)
+ allRegs[k].isUsed = true;
+ else {
+ allRegs[k].isUsed = false;
+ allRegs[k].freeTimeStamp = -1;
+ }
+ if(k == PhysicalReg_EBX || k == PhysicalReg_EBP || k == PhysicalReg_ESI || k == PhysicalReg_EDI)
+ allRegs[k].isCalleeSaved = true;
+ else
+ allRegs[k].isCalleeSaved = false;
+ }
+ for(k = PhysicalReg_XMM0; k <= PhysicalReg_XMM7; k++) {
+ allRegs[k].physicalReg = (PhysicalReg) k;
+ allRegs[k].isUsed = false;
+ allRegs[k].freeTimeStamp = -1;
+ allRegs[k].isCalleeSaved = false;
+ }
+}
+
+/** sync up allRegs (isUsed & freeTimeStamp) with compileTable
+ global data: RegisterInfo allRegs[PhysicalReg_Null]
+ update allRegs[EAX to XMM7] except EDI,ESP,EBP
+ update RegisterInfo.isUsed & RegisterInfo.freeTimeStamp
+ if the physical register was used and is not used now
+*/
+void syncAllRegs() {
+ int k, k2;
+ for(k = PhysicalReg_EAX; k <= PhysicalReg_XMM7; k++) {
+ if(k == PhysicalReg_EDI || k == PhysicalReg_ESP || k == PhysicalReg_EBP)
+ continue;
+ //check whether the physical register is used by any logical register
+ bool stillUsed = false;
+ for(k2 = 0; k2 < num_compile_entries; k2++) {
+ if(compileTable[k2].physicalReg == k) {
+ stillUsed = true;
+ break;
+ }
+ }
+ if(stillUsed && !allRegs[k].isUsed) {
+ allRegs[k].isUsed = true;
+ }
+ if(!stillUsed && allRegs[k].isUsed) {
+ allRegs[k].isUsed = false;
+ allRegs[k].freeTimeStamp = lowOpTimeStamp;
+ }
+ }
+ return;
+}
+
+//!sync up spillIndexUsed with compileTable
+
+//!
+void updateSpillIndexUsed() {
+ int k;
+ for(k = 0; k <= MAX_SPILL_JIT_IA-1; k++) spillIndexUsed[k] = 0;
+ for(k = 0; k < num_compile_entries; k++) {
+ if(isVirtualReg(compileTable[k].physicalType)) continue;
+ if(compileTable[k].spill_loc_index >= 0) {
+ if(compileTable[k].spill_loc_index > 4*(MAX_SPILL_JIT_IA-1))
+ ALOGE("spill_loc_index is wrong for entry %d: %d",
+ k, compileTable[k].spill_loc_index);
+ spillIndexUsed[compileTable[k].spill_loc_index >> 2] = 1;
+ }
+ }
+}
+
+/* free memory used in all basic blocks */
+void freeCFG() {
+ int k;
+ for(k = 0; k < num_bbs_for_method; k++) {
+ /* free defUseTable for method_bbs_sorted[k] */
+ DefUsePair* ptr = method_bbs_sorted[k]->defUseTable;
+ while(ptr != NULL) {
+ DefUsePair* tmp = ptr->next;
+ /* free ptr->uses */
+ DefOrUseLink* ptrUse = ptr->uses;
+ while(ptrUse != NULL) {
+ DefOrUseLink* tmp2 = ptrUse->next;
+ free(ptrUse);
+ ptrUse = tmp2;
+ }
+ free(ptr);
+ ptr = tmp;
+ }
+ free(method_bbs_sorted[k]);
+ }
+}
+
+/* update compileTable.physicalReg, compileTable.spill_loc_index & allRegs.isUsed
+ for glue-related variables, they do not exist
+ not in a physical register (physicalReg is Null)
+ not in a spilled memory location (spill_loc_index is -1)
+*/
+void initializeRegStateOfBB(BasicBlock_O1* bb) {
+ //for GLUE variables, do not exist
+ int k;
+ for(k = 0; k < num_compile_entries; k++) {
+ /* trace-based JIT: there is no VR with GG type */
+ if(isVirtualReg(compileTable[k].physicalType) && compileTable[k].gType == GLOBALTYPE_GG) {
+ if(bb->bb_index > 0) { //non-entry block
+ if(isFirstOfHandler(bb)) {
+ /* at the beginning of an exception handler, GG VR is in the interpreted stack */
+ compileTable[k].physicalReg = PhysicalReg_Null;
+#ifdef DEBUG_COMPILE_TABLE
+ ALOGI("at the first basic block of an exception handler, GG VR %d type %d is in memory",
+ compileTable[k].regNum, compileTable[k].physicalType);
+#endif
+ } else {
+ if(compileTable[k].physicalReg == PhysicalReg_Null) {
+ /* GG VR is in a specific physical register */
+ compileTable[k].physicalReg = compileTable[k].physicalReg_prev;
+ }
+ int tReg = compileTable[k].physicalReg;
+ allRegs[tReg].isUsed = true;
+#ifdef DEBUG_REG_USED
+ ALOGI("REGALLOC: physical reg %d is used by a GG VR %d %d at beginning of BB", tReg, compileTable[k].regNum, compileTable[k].physicalType);
+#endif
+ }
+ } //non-entry block
+ } //if GG VR
+ if(compileTable[k].regNum != PhysicalReg_GLUE &&
+ compileTable[k].regNum >= PhysicalReg_GLUE_DVMDEX) {
+ /* glue related registers */
+ compileTable[k].physicalReg = PhysicalReg_Null;
+ compileTable[k].spill_loc_index = -1;
+ }
+ }
+}
+
+/* update memVRTable[].nullCheckDone */
+void initializeNullCheck(int indexToMemVR) {
+ bool found = false;
+#ifdef GLOBAL_NULLCHECK_OPT
+ /* search nullCheck_inB of the current Basic Block */
+ for(k = 0; k < nullCheck_inSize[currentBB->bb_index2]; k++) {
+ if(nullCheck_inB[currentBB->bb_index2][k] == memVRTable[indexToMemVR].regNum) {
+ found = true;
+ break;
+ }
+ }
+#endif
+ memVRTable[indexToMemVR].nullCheckDone = found;
+}
+
+/* initialize memVRTable */
+void initializeMemVRTable() {
+ num_memory_vr = 0;
+ int k;
+ for(k = 0; k < num_compile_entries; k++) {
+ if(!isVirtualReg(compileTable[k].physicalType)) continue;
+ /* VRs in compileTable */
+ bool setToInMemory = (compileTable[k].physicalReg == PhysicalReg_Null);
+ int regNum = compileTable[k].regNum;
+ OpndSize sizeVR = getRegSize(compileTable[k].physicalType);
+ /* search memVRTable for the VR in compileTable */
+ int kk;
+ int indexL = -1;
+ int indexH = -1;
+ for(kk = 0; kk < num_memory_vr; kk++) {
+ if(memVRTable[kk].regNum == regNum) {
+ indexL = kk;
+ continue;
+ }
+ if(memVRTable[kk].regNum == regNum+1 && sizeVR == OpndSize_64) {
+ indexH = kk;
+ continue;
+ }
+ }
+ if(indexL < 0) {
+ /* the low half of VR is not in memVRTable
+ add an entry for the low half in memVRTable */
+ if(num_memory_vr >= NUM_MEM_VR_ENTRY) {
+ ALOGE("exceeds size of memVRTable");
+ dvmAbort();
+ }
+ memVRTable[num_memory_vr].regNum = regNum;
+ memVRTable[num_memory_vr].inMemory = setToInMemory;
+ initializeNullCheck(num_memory_vr); //set nullCheckDone
+ memVRTable[num_memory_vr].boundCheck.checkDone = false;
+ memVRTable[num_memory_vr].num_ranges = 0;
+ memVRTable[num_memory_vr].ranges = NULL;
+ memVRTable[num_memory_vr].delayFreeFlags = VRDELAY_NONE;
+ num_memory_vr++;
+ }
+ if(sizeVR == OpndSize_64 && indexH < 0) {
+ /* the high half of VR is not in memVRTable
+ add an entry for the high half in memVRTable */
+ if(num_memory_vr >= NUM_MEM_VR_ENTRY) {
+ ALOGE("exceeds size of memVRTable");
+ dvmAbort();
+ }
+ memVRTable[num_memory_vr].regNum = regNum+1;
+ memVRTable[num_memory_vr].inMemory = setToInMemory;
+ initializeNullCheck(num_memory_vr);
+ memVRTable[num_memory_vr].boundCheck.checkDone = false;
+ memVRTable[num_memory_vr].num_ranges = 0;
+ memVRTable[num_memory_vr].ranges = NULL;
+ memVRTable[num_memory_vr].delayFreeFlags = VRDELAY_NONE;
+ num_memory_vr++;
+ }
+ }
+}
+
+/* create a O1 basic block from basic block constructed in JIT MIR */
+BasicBlock_O1* createBasicBlockO1(BasicBlock* bb) {
+ BasicBlock_O1* bb1 = createBasicBlock(0, -1);
+ bb1->jitBasicBlock = bb;
+ return bb1;
+}
+
+/* a basic block in JIT MIR can contain bytecodes that are not in program order
+ for example, a "goto" bytecode will be followed by the goto target */
+void preprocessingBB(BasicBlock* bb) {
+ currentBB = createBasicBlockO1(bb);
+ /* initialize currentBB->allocConstraints */
+ int ii;
+ for(ii = 0; ii < 8; ii++) {
+ currentBB->allocConstraints[ii].physicalReg = (PhysicalReg)ii;
+ currentBB->allocConstraints[ii].count = 0;
+ }
+ collectInfoOfBasicBlock(currentMethod, currentBB);
+#ifdef DEBUG_COMPILE_TABLE
+ dumpVirtualInfoOfBasicBlock(currentBB);
+#endif
+ currentBB = NULL;
+}
+
+void preprocessingTrace() {
+ int k, k2, k3, jj;
+ /* this is a simplified verson of setTypeOfVR()
+ all VRs are assumed to be GL, no VR will be GG
+ */
+ for(k = 0; k < num_bbs_for_method; k++)
+ for(jj = 0; jj < method_bbs_sorted[k]->num_regs; jj++)
+ method_bbs_sorted[k]->infoBasicBlock[jj].gType = GLOBALTYPE_GL;
+
+ /* insert a glue-related register GLUE_DVMDEX to compileTable */
+ insertGlueReg();
+
+ int compile_entries_old = num_compile_entries;
+ for(k2 = 0; k2 < num_bbs_for_method; k2++) {
+ currentBB = method_bbs_sorted[k2];
+ /* update compileTable with virtual register from currentBB */
+ for(k3 = 0; k3 < currentBB->num_regs; k3++) {
+ insertFromVirtualInfo(currentBB, k3);
+ }
+
+ /* for each GL|GG type VR, insert fake usage at end of basic block to keep it live */
+ int offsetPC_back = offsetPC;
+ offsetPC = PC_FOR_END_OF_BB;
+ for(k = 0; k < num_compile_entries; k++) {
+ currentInfo.regNum = compileTable[k].regNum;
+ currentInfo.physicalType = (LowOpndRegType)compileTable[k].physicalType;
+ if(isVirtualReg(compileTable[k].physicalType) &&
+ compileTable[k].gType == GLOBALTYPE_GL) {
+ /* update defUseTable by assuming a fake usage at END of a basic block for variable @ currentInfo */
+ fakeUsageAtEndOfBB(currentBB);
+ }
+ if(isVirtualReg(compileTable[k].physicalType) &&
+ compileTable[k].gType == GLOBALTYPE_GG) {
+ fakeUsageAtEndOfBB(currentBB);
+ }
+ }
+ offsetPC = offsetPC_back;
+ num_compile_entries = compile_entries_old;
+ }
+ /* initialize data structure allRegs */
+ initializeAllRegs();
+#ifdef DEBUG_COMPILE_TABLE
+ dumpCompileTable();
+#endif
+ currentBB = NULL;
+}
+
+void printJitTraceInfoAtRunTime(const Method* method, int offset) {
+ ALOGI("execute trace for %s%s at offset %x", method->clazz->descriptor, method->name, offset);
+}
+
+void startOfTraceO1(const Method* method, LowOpBlockLabel* labelList, int exceptionBlockId, CompilationUnit *cUnit) {
+ num_exception_handlers = 0;
+ num_compile_entries = 0;
+ currentBB = NULL;
+ pc_start = -1;
+ bb_entry = NULL;
+ num_bbs_for_method = 0;
+ currentUnit = cUnit;
+ lowOpTimeStamp = 0;
+
+// dumpDebuggingInfo is gone in CompilationUnit struct
+#if 0
+ /* add code to dump debugging information */
+ if(cUnit->dumpDebuggingInfo) {
+ move_imm_to_mem(OpndSize_32, cUnit->startOffset, -4, PhysicalReg_ESP, true); //2nd argument: offset
+ move_imm_to_mem(OpndSize_32, (int)currentMethod, -8, PhysicalReg_ESP, true); //1st argument: method
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+
+ typedef void (*vmHelper)(const Method*, int);
+ vmHelper funcPtr = printJitTraceInfoAtRunTime;
+ move_imm_to_reg(OpndSize_32, (int)funcPtr, PhysicalReg_ECX, true);
+ call_reg(PhysicalReg_ECX, true);
+
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ }
+#endif
+}
+
+
+/* Code generation for a basic block defined for JIT
+ We have two data structures for a basic block:
+ BasicBlock defined in vm/compiler by JIT
+ BasicBlock_O1 defined in o1 */
+int codeGenBasicBlockJit(const Method* method, BasicBlock* bb) {
+ /* search method_bbs_sorted to find the O1 basic block corresponding to bb */
+ int k;
+ for(k = 0; k < num_bbs_for_method; k++) {
+ if(method_bbs_sorted[k]->jitBasicBlock == bb) {
+ lowOpTimeStamp = 0; //reset time stamp at start of a basic block
+ currentBB = method_bbs_sorted[k];
+ int cg_ret = codeGenBasicBlock(method, currentBB);
+ currentBB = NULL;
+ return cg_ret;
+ }
+ }
+ ALOGE("can't find the corresponding O1 basic block for id %d type %d",
+ bb->id, bb->blockType);
+ return -1;
+}
+void endOfBasicBlock(BasicBlock* bb) {
+ isScratchPhysical = true;
+ currentBB = NULL;
+}
+void endOfTraceO1() {
+ freeCFG();
+}
+
+/** entry point to collect information about virtual registers used in a basic block
+ Initialize data structure BasicBlock_O1
+ The usage information of virtual registers is stoerd in bb->infoBasicBlock
+
+ Global variables accessed: offsetPC, rPC
+*/
+int collectInfoOfBasicBlock(Method* method, BasicBlock_O1* bb) {
+ bb->num_regs = 0;
+ bb->num_defs = 0;
+ bb->defUseTable = NULL;
+ bb->defUseTail = NULL;
+ u2* rPC_start = (u2*)method->insns;
+ int kk;
+ bb->endsWithReturn = false;
+ bb->hasAccessToGlue = false;
+
+ MIR* mir;
+ int seqNum = 0;
+ /* traverse the MIR in basic block
+ sequence number is used to make sure next bytecode will have a larger sequence number */
+ for(mir = bb->jitBasicBlock->firstMIRInsn; mir; mir = mir->next) {
+ offsetPC = seqNum;
+ mir->seqNum = seqNum++;
+ rPC = rPC_start + mir->offset;
+#ifdef WITH_JIT_INLINING
+ if(mir->dalvikInsn.opcode >= kMirOpFirst &&
+ mir->dalvikInsn.opcode != kMirOpCheckInlinePrediction) continue;
+ if(ir->dalvikInsn.opcode == kMirOpCheckInlinePrediction) { //TODO
+ }
+#else
+ if(mir->dalvikInsn.opcode >= kNumPackedOpcodes) continue;
+#endif
+ inst = FETCH(0);
+ u2 inst_op = INST_INST(inst);
+ /* update bb->hasAccessToGlue */
+ if((inst_op >= OP_MOVE_RESULT && inst_op <= OP_RETURN_OBJECT) ||
+ (inst_op >= OP_MONITOR_ENTER && inst_op <= OP_INSTANCE_OF) ||
+ (inst_op == OP_FILLED_NEW_ARRAY) ||
+ (inst_op == OP_FILLED_NEW_ARRAY_RANGE) ||
+ (inst_op == OP_THROW) ||
+ (inst_op >= OP_INVOKE_VIRTUAL && inst_op <= OP_INVOKE_INTERFACE_RANGE) ||
+ (inst_op >= OP_THROW_VERIFICATION_ERROR &&
+ inst_op <= OP_EXECUTE_INLINE_RANGE) ||
+ (inst_op >= OP_INVOKE_VIRTUAL_QUICK && inst_op <= OP_INVOKE_SUPER_QUICK_RANGE))
+ bb->hasAccessToGlue = true;
+ /* update bb->endsWithReturn */
+ if(inst_op == OP_RETURN_VOID || inst_op == OP_RETURN || inst_op == OP_RETURN_VOID_BARRIER ||
+ inst_op == OP_RETURN_OBJECT || inst_op == OP_RETURN_WIDE)
+ bb->endsWithReturn = true;
+
+ /* get virtual register usage in current bytecode */
+ getVirtualRegInfo(infoByteCode);
+ int num_regs = num_regs_per_bytecode;
+ for(kk = 0; kk < num_regs; kk++) {
+ currentInfo = infoByteCode[kk];
+#ifdef DEBUG_MERGE_ENTRY
+ ALOGI("call mergeEntry2 at offsetPC %x kk %d VR %d %d", offsetPC, kk,
+ currentInfo.regNum, currentInfo.physicalType);
+#endif
+ mergeEntry2(bb); //update defUseTable of the basic block
+ }
+
+ //dumpVirtualInfoOfBasicBlock(bb);
+ }//for each bytecode
+
+ bb->pc_end = seqNum;
+
+ //sort allocConstraints of each basic block
+ for(kk = 0; kk < bb->num_regs; kk++) {
+#ifdef DEBUG_ALLOC_CONSTRAINT
+ ALOGI("sort virtual reg %d type %d -------", bb->infoBasicBlock[kk].regNum,
+ bb->infoBasicBlock[kk].physicalType);
+#endif
+ sortAllocConstraint(bb->infoBasicBlock[kk].allocConstraints,
+ bb->infoBasicBlock[kk].allocConstraintsSorted, true);
+ }
+#ifdef DEBUG_ALLOC_CONSTRAINT
+ ALOGI("sort constraints for BB %d --------", bb->bb_index);
+#endif
+ sortAllocConstraint(bb->allocConstraints, bb->allocConstraintsSorted, false);
+ return 0;
+}
+
+/** entry point to generate native code for a O1 basic block
+ There are 3 kinds of virtual registers in a O1 basic block:
+ 1> L VR: local within the basic block
+ 2> GG VR: is live in other basic blocks,
+ its content is in a pre-defined GPR at the beginning of a basic block
+ 3> GL VR: is live in other basic blocks,
+ its content is in the interpreted stack at the beginning of a basic block
+ compileTable is updated with infoBasicBlock at the start of the basic block;
+ Before lowering each bytecode, compileTable is updated with infoByteCodeTemp;
+ At end of the basic block, right before the jump instruction, handles constant VRs and GG VRs
+*/
+int codeGenBasicBlock(const Method* method, BasicBlock_O1* bb) {
+ /* we assume at the beginning of each basic block,
+ all GL VRs reside in memory and all GG VRs reside in predefined physical registers,
+ so at the end of a basic block, recover a spilled GG VR, store a GL VR to memory */
+ /* update compileTable with entries in bb->infoBasicBlock */
+ int k;
+ for(k = 0; k < bb->num_regs; k++) {
+ insertFromVirtualInfo(bb, k);
+ }
+ updateXferPoints(); //call fakeUsageAtEndOfBB
+#ifdef DEBUG_REACHING_DEF
+ printDefUseTable();
+#endif
+#ifdef DSE_OPT
+ removeDeadDefs();
+ printDefUseTable();
+#endif
+ //clear const section of compileTable
+ for(k = 0; k < num_compile_entries; k++) compileTable[k].isConst = false;
+ num_const_vr = 0;
+#ifdef DEBUG_COMPILE_TABLE
+ ALOGI("At start of basic block %d (num of VRs %d) -------", bb->bb_index, bb->num_regs);
+ dumpCompileTable();
+#endif
+ initializeRegStateOfBB(bb);
+ initializeMemVRTable();
+ updateLiveTable();
+ freeReg(true); //before code gen of a basic block, also called at end of a basic block?
+#ifdef DEBUG_COMPILE_TABLE
+ ALOGI("At start of basic block %d (num of VRs %d) -------", bb->bb_index, bb->num_regs);
+#endif
+
+ u2* rPC_start = (u2*)method->insns;
+ bool lastByteCodeIsJump = false;
+ MIR* mir;
+ for(mir = bb->jitBasicBlock->firstMIRInsn; mir; mir = mir->next) {
+ offsetPC = mir->seqNum;
+ rPC = rPC_start + mir->offset;
+#ifdef WITH_JIT_INLINING
+ if(mir->dalvikInsn.opcode >= kMirOpFirst &&
+ mir->dalvikInsn.opcode != kMirOpCheckInlinePrediction) {
+#else
+ if(mir->dalvikInsn.opcode >= kNumPackedOpcodes) {
+#endif
+ handleExtendedMIR(currentUnit, mir);
+ continue;
+ }
+
+ inst = FETCH(0);
+ //before handling a bytecode, import info of temporary registers to compileTable including refCount
+ num_temp_regs_per_bytecode = getTempRegInfo(infoByteCodeTemp);
+ for(k = 0; k < num_temp_regs_per_bytecode; k++) {
+ if(infoByteCodeTemp[k].versionNum > 0) continue;
+ insertFromTempInfo(k);
+ }
+ startNativeCode(-1, -1);
+ for(k = 0; k <= MAX_SPILL_JIT_IA-1; k++) spillIndexUsed[k] = 0;
+ //update spillIndexUsed if a glue variable was spilled
+ for(k = 0; k < num_compile_entries; k++) {
+ if(compileTable[k].regNum >= PhysicalReg_GLUE_DVMDEX) {
+ if(compileTable[k].spill_loc_index >= 0)
+ spillIndexUsed[compileTable[k].spill_loc_index >> 2] = 1;
+ }
+ }
+#ifdef DEBUG_COMPILE_TABLE
+ ALOGI("compile table size after importing temporary info %d", num_compile_entries);
+ ALOGI("before one bytecode %d (num of VRs %d) -------", bb->bb_index, bb->num_regs);
+#endif
+ //set isConst to true for CONST & MOVE MOVE_OBJ?
+ //clear isConst to true for MOVE, MOVE_OBJ, MOVE_RESULT, MOVE_EXCEPTION ...
+ bool isConst = getConstInfo(bb); //will reset isConst if a VR is updated by the bytecode
+ bool isDeadStmt = false;
+#ifdef DSE_OPT
+ for(k = 0; k < num_dead_pc; k++) {
+ if(deadPCs[k] == offsetPC) {
+ isDeadStmt = true;
+ break;
+ }
+ }
+#endif
+ getVirtualRegInfo(infoByteCode);
+ //call something similar to mergeEntry2, but only update refCount
+ //clear refCount
+ for(k = 0; k < num_regs_per_bytecode; k++) {
+ int indexT = searchCompileTable(LowOpndRegType_virtual | infoByteCode[k].physicalType,
+ infoByteCode[k].regNum);
+ if(indexT >= 0)
+ compileTable[indexT].refCount = 0;
+ }
+ for(k = 0; k < num_regs_per_bytecode; k++) {
+ int indexT = searchCompileTable(LowOpndRegType_virtual | infoByteCode[k].physicalType,
+ infoByteCode[k].regNum);
+ if(indexT >= 0)
+ compileTable[indexT].refCount += infoByteCode[k].refCount;
+ } //for k
+#ifdef DSE_OPT
+ if(isDeadStmt) { //search compileTable
+ getVirtualRegInfo(infoByteCode);
+#ifdef DEBUG_DSE
+ ALOGI("DSE: stmt at offsetPC %d is dead", offsetPC);
+#endif
+ for(k = 0; k < num_regs_per_bytecode; k++) {
+ int indexT = searchCompileTable(LowOpndRegType_virtual | infoByteCode[k].physicalType,
+ infoByteCode[k].regNum);
+ if(indexT >= 0)
+ compileTable[indexT].refCount -= infoByteCode[k].refCount;
+ }
+ }
+#endif
+ lastByteCodeIsJump = false;
+ if(!isConst && !isDeadStmt) //isDeadStmt is false when DSE_OPT is not enabled
+ {
+#ifdef DEBUG_COMPILE_TABLE
+ dumpCompileTable();
+#endif
+ globalShortMap = NULL;
+ if(isCurrentByteCodeJump()) lastByteCodeIsJump = true;
+ //lowerByteCode will call globalVREndOfBB if it is jump
+ int retCode = lowerByteCodeJit(method, rPC, mir);
+ if(gDvmJit.codeCacheByteUsed + (stream - streamStart) +
+ CODE_CACHE_PADDING > gDvmJit.codeCacheSize) {
+ ALOGE("JIT code cache full");
+ gDvmJit.codeCacheFull = true;
+ return -1;
+ }
+
+ if (retCode == 1) {
+ ALOGE("JIT couldn't compile %s%s dex_pc=%d", method->clazz->descriptor, method->name, offsetPC);
+ return -1;
+ }
+ updateConstInfo(bb);
+ freeShortMap();
+ if(retCode < 0) {
+ ALOGE("error in lowering the bytecode");
+ return retCode;
+ }
+ freeReg(true); //may dump GL VR to memory (this is necessary)
+ //after each bytecode, make sure non-VRs have refCount of zero
+ for(k = 0; k < num_compile_entries; k++) {
+ if(isTemporary(compileTable[k].physicalType, compileTable[k].regNum)) {
+#ifdef PRINT_WARNING
+ if(compileTable[k].refCount > 0) {
+ ALOGW("refCount for a temporary reg %d %d is %d after a bytecode", compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].refCount);
+ }
+#endif
+ compileTable[k].refCount = 0;
+ }
+ }
+ } else { //isConst || isDeadStmt
+ //if this bytecode is the target of a jump, the mapFromBCtoNCG should be updated
+ offsetNCG = stream - streamMethodStart;
+ mapFromBCtoNCG[offsetPC] = offsetNCG;
+#ifdef DEBUG_COMPILE_TABLE
+ ALOGI("this bytecode generates a constant and has no side effect");
+#endif
+ freeReg(true); //may dump GL VR to memory (this is necessary)
+ }
+#ifdef DEBUG_COMPILE_TABLE
+ ALOGI("after one bytecode BB %d (num of VRs %d)", bb->bb_index, bb->num_regs);
+#endif
+ }//for each bytecode
+#ifdef DEBUG_COMPILE_TABLE
+ dumpCompileTable();
+#endif
+ if(!lastByteCodeIsJump) constVREndOfBB();
+ //at end of a basic block, get spilled GG VR & dump GL VR
+ if(!lastByteCodeIsJump) globalVREndOfBB(method);
+ //remove entries for temporary registers, L VR and GL VR
+ int jj;
+ for(k = 0; k < num_compile_entries; ) {
+ bool removeEntry = false;
+ if(isVirtualReg(compileTable[k].physicalType) && compileTable[k].gType != GLOBALTYPE_GG) {
+ removeEntry = true;
+ }
+ if(isTemporary(compileTable[k].physicalType, compileTable[k].regNum))
+ removeEntry = true;
+ if(removeEntry) {
+#ifdef PRINT_WARNING
+ if(compileTable[k].refCount > 0)
+ ALOGW("refCount for REG %d %d is %d at end of a basic block", compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].refCount);
+#endif
+ compileTable[k].refCount = 0;
+ for(jj = k+1; jj < num_compile_entries; jj++) {
+ compileTable[jj-1] = compileTable[jj];
+ }
+ num_compile_entries--;
+ } else {
+ k++;
+ }
+ }
+ freeReg(true);
+ //free LIVE TABLE
+ for(k = 0; k < num_memory_vr; k++) {
+ LiveRange* ptr2 = memVRTable[k].ranges;
+ while(ptr2 != NULL) {
+ LiveRange* tmpP = ptr2->next;
+ free(ptr2->accessPC);
+ free(ptr2);
+ ptr2 = tmpP;
+ }
+ }
+#ifdef DEBUG_COMPILE_TABLE
+ ALOGI("At end of basic block -------");
+ dumpCompileTable();
+#endif
+ return 0;
+}
+
+/** update infoBasicBlock & defUseTable
+ input: currentInfo
+ side effect: update currentInfo.reachingDefs
+
+ update entries in infoBasicBlock by calling updateReachingDefA
+ if there is no entry in infoBasicBlock for B, an entry will be created and inserted to infoBasicBlock
+
+ defUseTable is updated to account for the access at currentInfo
+ if accessType of B is U or UD, we call updateReachingDefB to update currentInfo.reachingDefs
+ in order to correctly insert the usage to defUseTable
+*/
+int mergeEntry2(BasicBlock_O1* bb) {
+ LowOpndRegType typeB = currentInfo.physicalType;
+ int regB = currentInfo.regNum;
+ int jj, k;
+ int jjend = bb->num_regs;
+ bool isMerged = false;
+ bool hasAlias = false;
+ OverlapCase isBPartiallyOverlapA, isAPartiallyOverlapB;
+ RegAccessType tmpType = REGACCESS_N;
+ currentInfo.num_reaching_defs = 0;
+
+ /* traverse variable A in infoBasicBlock */
+ for(jj = 0; jj < jjend; jj++) {
+ int regA = bb->infoBasicBlock[jj].regNum;
+ LowOpndRegType typeA = bb->infoBasicBlock[jj].physicalType;
+ isBPartiallyOverlapA = getBPartiallyOverlapA(regB, typeB, regA, typeA);
+ isAPartiallyOverlapB = getAPartiallyOverlapB(regA, typeA, regB, typeB);
+ if(regA == regB && typeA == typeB) {
+ /* variable A and B are aligned */
+ bb->infoBasicBlock[jj].accessType = mergeAccess2(bb->infoBasicBlock[jj].accessType, currentInfo.accessType,
+ OVERLAP_B_COVER_A);
+ bb->infoBasicBlock[jj].refCount += currentInfo.refCount;
+ /* copy reaching defs of variable B from variable A */
+ currentInfo.num_reaching_defs = bb->infoBasicBlock[jj].num_reaching_defs;
+ for(k = 0; k < currentInfo.num_reaching_defs; k++)
+ currentInfo.reachingDefs[k] = bb->infoBasicBlock[jj].reachingDefs[k];
+ updateDefUseTable(); //use currentInfo to update defUseTable
+ updateReachingDefA(jj, OVERLAP_B_COVER_A); //update reachingDefs of A
+ isMerged = true;
+ hasAlias = true;
+ if(typeB == LowOpndRegType_gp) {
+ //merge allocConstraints
+ for(k = 0; k < 8; k++) {
+ bb->infoBasicBlock[jj].allocConstraints[k].count += currentInfo.allocConstraints[k].count;
+ }
+ }
+ }
+ else if(isBPartiallyOverlapA != OVERLAP_NO) {
+ tmpType = updateAccess2(tmpType, updateAccess1(bb->infoBasicBlock[jj].accessType, isAPartiallyOverlapB));
+ bb->infoBasicBlock[jj].accessType = mergeAccess2(bb->infoBasicBlock[jj].accessType, currentInfo.accessType,
+ isBPartiallyOverlapA);
+#ifdef DEBUG_MERGE_ENTRY
+ ALOGI("update accessType in case 2: VR %d %d accessType %d", regA, typeA, bb->infoBasicBlock[jj].accessType);
+#endif
+ hasAlias = true;
+ if(currentInfo.accessType == REGACCESS_U || currentInfo.accessType == REGACCESS_UD) {
+ /* update currentInfo.reachingDefs */
+ updateReachingDefB1(jj);
+ updateReachingDefB2();
+ }
+ updateReachingDefA(jj, isBPartiallyOverlapA);
+ }
+ else {
+ //even if B does not overlap with A, B can affect the reaching defs of A
+ //for example, B is a def of "v0", A is "v1"
+ // B can kill some reaching defs of A or affect the accessType of a reaching def
+ updateReachingDefA(jj, OVERLAP_NO); //update reachingDefs of A
+ }
+ }//for each variable A in infoBasicBlock
+ if(!isMerged) {
+ /* create a new entry in infoBasicBlock */
+ bb->infoBasicBlock[bb->num_regs].refCount = currentInfo.refCount;
+ bb->infoBasicBlock[bb->num_regs].physicalType = typeB;
+ if(hasAlias)
+ bb->infoBasicBlock[bb->num_regs].accessType = updateAccess3(tmpType, currentInfo.accessType);
+ else
+ bb->infoBasicBlock[bb->num_regs].accessType = currentInfo.accessType;
+#ifdef DEBUG_MERGE_ENTRY
+ ALOGI("update accessType in case 3: VR %d %d accessType %d", regB, typeB, bb->infoBasicBlock[bb->num_regs].accessType);
+#endif
+ bb->infoBasicBlock[bb->num_regs].regNum = regB;
+ for(k = 0; k < 8; k++)
+ bb->infoBasicBlock[bb->num_regs].allocConstraints[k] = currentInfo.allocConstraints[k];
+#ifdef DEBUG_MERGE_ENTRY
+ ALOGI("isMerged is false, call updateDefUseTable");
+#endif
+ updateDefUseTable(); //use currentInfo to update defUseTable
+ updateReachingDefB3(); //update currentInfo.reachingDefs if currentInfo defines variable B
+
+ //copy from currentInfo.reachingDefs to bb->infoBasicBlock[bb->num_regs]
+ bb->infoBasicBlock[bb->num_regs].num_reaching_defs = currentInfo.num_reaching_defs;
+ for(k = 0; k < currentInfo.num_reaching_defs; k++)
+ bb->infoBasicBlock[bb->num_regs].reachingDefs[k] = currentInfo.reachingDefs[k];
+#ifdef DEBUG_MERGE_ENTRY
+ ALOGI("try to update reaching defs for VR %d %d", regB, typeB);
+ for(k = 0; k < bb->infoBasicBlock[bb->num_regs].num_reaching_defs; k++)
+ ALOGI("reaching def %d @ %d for VR %d %d access %d", k, currentInfo.reachingDefs[k].offsetPC,
+ currentInfo.reachingDefs[k].regNum, currentInfo.reachingDefs[k].physicalType,
+ currentInfo.reachingDefs[k].accessType);
+#endif
+ bb->num_regs++;
+ if(bb->num_regs >= MAX_REG_PER_BASICBLOCK) {
+ ALOGE("too many VRs in a basic block");
+ dvmAbort();
+ }
+ return -1;
+ }
+ return 0;
+}
+
+//!update reaching defs for infoBasicBlock[indexToA]
+
+//!use currentInfo.reachingDefs to update reaching defs for variable A
+void updateReachingDefA(int indexToA, OverlapCase isBPartiallyOverlapA) {
+ if(indexToA < 0) return;
+ int k, k2;
+ OverlapCase isBPartiallyOverlapDef;
+ if(currentInfo.accessType == REGACCESS_U) {
+ return; //no update to reachingDefs of the VR
+ }
+ /* access in currentInfo is DU, D, or UD */
+ if(isBPartiallyOverlapA == OVERLAP_B_COVER_A) {
+ /* from this point on, the reachingDefs for variable A is a single def to currentInfo at offsetPC */
+ currentBB->infoBasicBlock[indexToA].num_reaching_defs = 1;
+ currentBB->infoBasicBlock[indexToA].reachingDefs[0].offsetPC = offsetPC;
+ currentBB->infoBasicBlock[indexToA].reachingDefs[0].regNum = currentInfo.regNum;
+ currentBB->infoBasicBlock[indexToA].reachingDefs[0].physicalType = currentInfo.physicalType;
+ currentBB->infoBasicBlock[indexToA].reachingDefs[0].accessType = REGACCESS_D;
+#ifdef DEBUG_REACHING_DEF
+ ALOGI("single reaching def @ %d for VR %d %d", offsetPC, currentInfo.regNum, currentInfo.physicalType);
+#endif
+ return;
+ }
+ /* update reachingDefs for variable A to get rid of dead defs */
+ /* Bug fix: it is possible that more than one reaching defs need to be removed
+ after one reaching def is removed, num_reaching_defs--, but k should not change
+ */
+ for(k = 0; k < currentBB->infoBasicBlock[indexToA].num_reaching_defs; ) {
+ /* remove one reaching def in one interation of the loop */
+ //check overlapping between def & B
+ isBPartiallyOverlapDef = getBPartiallyOverlapA(currentInfo.regNum, currentInfo.physicalType,
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].regNum,
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType);
+#ifdef DEBUG_REACHING_DEF
+ ALOGI("DEBUG B %d %d def %d %d %d", currentInfo.regNum, currentInfo.physicalType,
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].regNum,
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType,
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType);
+#endif
+ /* cases where one def nees to be removed:
+ if B fully covers def, def is removed
+ if B overlaps high half of def & def's accessType is H, def is removed
+ if B overlaps low half of def & def's accessType is L, def is removed
+ */
+ if((isBPartiallyOverlapDef == OVERLAP_B_COVER_HIGH_OF_A &&
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType == REGACCESS_H) ||
+ (isBPartiallyOverlapDef == OVERLAP_B_COVER_LOW_OF_A &&
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType == REGACCESS_L) ||
+ isBPartiallyOverlapDef == OVERLAP_B_COVER_A
+ ) { //remove def
+ //shift from k+1 to end
+ for(k2 = k+1; k2 < currentBB->infoBasicBlock[indexToA].num_reaching_defs; k2++)
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k2-1] = currentBB->infoBasicBlock[indexToA].reachingDefs[k2];
+ currentBB->infoBasicBlock[indexToA].num_reaching_defs--;
+ }
+ /*
+ if B overlaps high half of def & def's accessType is not H --> update accessType of def
+ */
+ else if(isBPartiallyOverlapDef == OVERLAP_B_COVER_HIGH_OF_A &&
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType != REGACCESS_H) {
+ //low half is still valid
+ if(getRegSize(currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType) == OpndSize_32)
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType = REGACCESS_D;
+ else
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType = REGACCESS_L;
+#ifdef DEBUG_REACHING_DEF
+ ALOGI("DEBUG: set accessType of def to L");
+#endif
+ k++;
+ }
+ /*
+ if B overlaps low half of def & def's accessType is not L --> update accessType of def
+ */
+ else if(isBPartiallyOverlapDef == OVERLAP_B_COVER_LOW_OF_A &&
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType != REGACCESS_L) {
+ //high half of def is still valid
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType = REGACCESS_H;
+#ifdef DEBUG_REACHING_DEF
+ ALOGI("DEBUG: set accessType of def to H");
+#endif
+ k++;
+ }
+ else {
+ k++;
+ }
+ }//for k
+ if(isBPartiallyOverlapA != OVERLAP_NO) {
+ //insert the def to variable @ currentInfo
+ k = currentBB->infoBasicBlock[indexToA].num_reaching_defs;
+ if(k >= 3) {
+ ALOGE("more than 3 reaching defs");
+ }
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].offsetPC = offsetPC;
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].regNum = currentInfo.regNum;
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType = currentInfo.physicalType;
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType = REGACCESS_D;
+ currentBB->infoBasicBlock[indexToA].num_reaching_defs++;
+ }
+#ifdef DEBUG_REACHING_DEF2
+ ALOGI("IN updateReachingDefA for VR %d %d", currentBB->infoBasicBlock[indexToA].regNum,
+ currentBB->infoBasicBlock[indexToA].physicalType);
+ for(k = 0; k < currentBB->infoBasicBlock[indexToA].num_reaching_defs; k++)
+ ALOGI("reaching def %d @ %d for VR %d %d access %d", k,
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].offsetPC,
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].regNum,
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType,
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType);
+#endif
+}
+
+/** Given a variable B @currentInfo,
+ updates its reaching defs by checking reaching defs of variable A @currentBB->infoBasicBlock[indexToA]
+ The result is stored in tmpInfo.reachingDefs
+*/
+void updateReachingDefB1(int indexToA) {
+ if(indexToA < 0) return;
+ int k;
+ tmpInfo.num_reaching_defs = 0;
+ for(k = 0; k < currentBB->infoBasicBlock[indexToA].num_reaching_defs; k++) {
+ /* go through reachingDefs of variable A @currentBB->infoBasicBlock[indexToA]
+ for each def, check whether it overlaps with variable B @currentInfo
+ if the def overlaps with variable B, insert it to tmpInfo.reachingDefs
+ */
+ OverlapCase isDefPartiallyOverlapB = getAPartiallyOverlapB(
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].regNum,
+ currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType,
+ currentInfo.regNum, currentInfo.physicalType
+ );
+ bool insert1 = false; //whether to insert the def to tmpInfo.reachingDefs
+ if(isDefPartiallyOverlapB == OVERLAP_ALIGN ||
+ isDefPartiallyOverlapB == OVERLAP_A_IS_LOW_OF_B ||
+ isDefPartiallyOverlapB == OVERLAP_A_IS_HIGH_OF_B) {
+ /* B aligns with def */
+ /* def is low half of B, def is high half of B
+ in these two cases, def is 32 bits */
+ insert1 = true;
+ }
+ RegAccessType deftype = currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType;
+ if(isDefPartiallyOverlapB == OVERLAP_B_IS_LOW_OF_A ||
+ isDefPartiallyOverlapB == OVERLAP_LOW_OF_A_IS_HIGH_OF_B) {
+ /* B is the low half of def */
+ /* the low half of def is the high half of B */
+ if(deftype != REGACCESS_H) insert1 = true;
+ }
+ if(isDefPartiallyOverlapB == OVERLAP_B_IS_HIGH_OF_A ||
+ isDefPartiallyOverlapB == OVERLAP_HIGH_OF_A_IS_LOW_OF_B) {
+ /* B is the high half of def */
+ /* the high half of def is the low half of B */
+ if(deftype != REGACCESS_L) insert1 = true;
+ }
+ if(insert1) {
+ if(tmpInfo.num_reaching_defs >= 3) {
+ ALOGE("more than 3 reaching defs for tmpInfo");
+ }
+ tmpInfo.reachingDefs[tmpInfo.num_reaching_defs] = currentBB->infoBasicBlock[indexToA].reachingDefs[k];
+ tmpInfo.num_reaching_defs++;
+#ifdef DEBUG_REACHING_DEF2
+ ALOGI("insert from entry %d %d: index %d", currentBB->infoBasicBlock[indexToA].regNum,
+ currentBB->infoBasicBlock[indexToA].physicalType, k);
+#endif
+ }
+ }
+}
+
+/** update currentInfo.reachingDefs by merging currentInfo.reachingDefs with tmpInfo.reachingDefs
+*/
+void updateReachingDefB2() {
+ int k, k2;
+ for(k2 = 0; k2 < tmpInfo.num_reaching_defs; k2++ ) {
+ bool merged = false;
+ for(k = 0; k < currentInfo.num_reaching_defs; k++) {
+ /* check whether it is the same def, if yes, do nothing */
+ if(currentInfo.reachingDefs[k].regNum == tmpInfo.reachingDefs[k2].regNum &&
+ currentInfo.reachingDefs[k].physicalType == tmpInfo.reachingDefs[k2].physicalType) {
+ merged = true;
+ if(currentInfo.reachingDefs[k].offsetPC != tmpInfo.reachingDefs[k2].offsetPC) {
+ ALOGE("defs on the same VR %d %d with different offsetPC %d vs %d",
+ currentInfo.reachingDefs[k].regNum, currentInfo.reachingDefs[k].physicalType,
+ currentInfo.reachingDefs[k].offsetPC, tmpInfo.reachingDefs[k2].offsetPC);
+ }
+ if(currentInfo.reachingDefs[k].accessType != tmpInfo.reachingDefs[k2].accessType)
+ ALOGE("defs on the same VR %d %d with different accessType",
+ currentInfo.reachingDefs[k].regNum, currentInfo.reachingDefs[k].physicalType);
+ break;
+ }
+ }
+ if(!merged) {
+ if(currentInfo.num_reaching_defs >= 3) {
+ ALOGE("more than 3 reaching defs for currentInfo");
+ }
+ currentInfo.reachingDefs[currentInfo.num_reaching_defs] = tmpInfo.reachingDefs[k2];
+ currentInfo.num_reaching_defs++;
+ }
+ }
+}
+
+//!update currentInfo.reachingDefs with currentInfo if variable is defined in currentInfo
+
+//!
+void updateReachingDefB3() {
+ if(currentInfo.accessType == REGACCESS_U) {
+ return; //no need to update currentInfo.reachingDefs
+ }
+ currentInfo.num_reaching_defs = 1;
+ currentInfo.reachingDefs[0].regNum = currentInfo.regNum;
+ currentInfo.reachingDefs[0].physicalType = currentInfo.physicalType;
+ currentInfo.reachingDefs[0].offsetPC = offsetPC;
+ currentInfo.reachingDefs[0].accessType = REGACCESS_D;
+}
+
+/** update defUseTable by checking currentInfo
+*/
+void updateDefUseTable() {
+ /* no access */
+ if(currentInfo.accessType == REGACCESS_N) return;
+ /* define then use, or define only */
+ if(currentInfo.accessType == REGACCESS_DU || currentInfo.accessType == REGACCESS_D) {
+ /* insert a definition at offsetPC to variable @ currentInfo */
+ DefUsePair* ptr = insertADef(offsetPC, currentInfo.regNum, currentInfo.physicalType, REGACCESS_D);
+ if(currentInfo.accessType != REGACCESS_D) {
+ /* if access is define then use, insert a use at offsetPC */
+ insertAUse(ptr, offsetPC, currentInfo.regNum, currentInfo.physicalType);
+ }
+ return;
+ }
+ /* use only or use then define
+ check the reaching defs for the usage */
+ int k;
+ bool isLCovered = false, isHCovered = false, isDCovered = false;
+ for(k = 0; k < currentInfo.num_reaching_defs; k++) {
+ /* insert a def currentInfo.reachingDefs[k] and a use of variable at offsetPC */
+ RegAccessType useType = insertDefUsePair(k);
+ if(useType == REGACCESS_D) isDCovered = true;
+ if(useType == REGACCESS_L) isLCovered = true;
+ if(useType == REGACCESS_H) isHCovered = true;
+ }
+ OpndSize useSize = getRegSize(currentInfo.physicalType);
+ if((!isDCovered) && (!isLCovered)) {
+ /* the low half of variable is not defined in the basic block
+ so insert a def to the low half at START of the basic block */
+ insertDefUsePair(-1);
+ }
+ if(useSize == OpndSize_64 && (!isDCovered) && (!isHCovered)) {
+ /* the high half of variable is not defined in the basic block
+ so insert a def to the high half at START of the basic block */
+ insertDefUsePair(-2);
+ }
+ if(currentInfo.accessType == REGACCESS_UD) {
+ /* insert a def at offsetPC to variable @ currentInfo */
+ insertADef(offsetPC, currentInfo.regNum, currentInfo.physicalType, REGACCESS_D);
+ return;
+ }
+}
+
+//! insert a use at offsetPC of given variable at end of DefUsePair
+
+//!
+RegAccessType insertAUse(DefUsePair* ptr, int offsetPC, int regNum, LowOpndRegType physicalType) {
+ DefOrUseLink* tLink = (DefOrUseLink*)malloc(sizeof(DefOrUseLink));
+ if(tLink == NULL) {
+ ALOGE("Memory allocation failed");
+ return REGACCESS_UNKNOWN;
+ }
+ tLink->offsetPC = offsetPC;
+ tLink->regNum = regNum;
+ tLink->physicalType = physicalType;
+ tLink->next = NULL;
+ if(ptr->useTail != NULL)
+ ptr->useTail->next = tLink;
+ ptr->useTail = tLink;
+ if(ptr->uses == NULL)
+ ptr->uses = tLink;
+ ptr->num_uses++;
+
+ //check whether the def is partially overlapping with the variable
+ OverlapCase isDefPartiallyOverlapB = getBPartiallyOverlapA(ptr->def.regNum,
+ ptr->def.physicalType,
+ regNum, physicalType);
+ RegAccessType useType = setAccessTypeOfUse(isDefPartiallyOverlapB, ptr->def.accessType);
+ tLink->accessType = useType;
+ return useType;
+}
+
+//! insert a def to currentBB->defUseTable
+
+//! update currentBB->defUseTail if necessary
+DefUsePair* insertADef(int offsetPC, int regNum, LowOpndRegType pType, RegAccessType rType) {
+ DefUsePair* ptr = (DefUsePair*)malloc(sizeof(DefUsePair));
+ if(ptr == NULL) {
+ ALOGE("Memory allocation failed");
+ return NULL;
+ }
+ ptr->next = NULL;
+ ptr->def.offsetPC = offsetPC;
+ ptr->def.regNum = regNum;
+ ptr->def.physicalType = pType;
+ ptr->def.accessType = rType;
+ ptr->num_uses = 0;
+ ptr->useTail = NULL;
+ ptr->uses = NULL;
+ if(currentBB->defUseTail != NULL) {
+ currentBB->defUseTail->next = ptr;
+ }
+ currentBB->defUseTail = ptr;
+ if(currentBB->defUseTable == NULL)
+ currentBB->defUseTable = ptr;
+ currentBB->num_defs++;
+#ifdef DEBUG_REACHING_DEF
+ ALOGI("insert a def at %d to defUseTable for VR %d %d", offsetPC,
+ regNum, pType);
+#endif
+ return ptr;
+}
+
+/** insert a def to defUseTable, then insert a use of variable @ currentInfo
+ if reachingDefIndex >= 0, the def is currentInfo.reachingDefs[index]
+ if reachingDefIndex is -1, the low half is defined at START of the basic block
+ if reachingDefIndex is -2, the high half is defined at START of the basic block
+*/
+RegAccessType insertDefUsePair(int reachingDefIndex) {
+ int k = reachingDefIndex;
+ DefUsePair* tableIndex = NULL;
+ DefOrUse theDef;
+ theDef.regNum = 0;
+ if(k < 0) {
+ /* def at start of the basic blcok */
+ theDef.offsetPC = PC_FOR_START_OF_BB;
+ theDef.accessType = REGACCESS_D;
+ if(k == -1) //low half of variable
+ theDef.regNum = currentInfo.regNum;
+ if(k == -2) //high half of variable
+ theDef.regNum = currentInfo.regNum+1;
+ theDef.physicalType = LowOpndRegType_gp;
+ }
+ else {
+ theDef = currentInfo.reachingDefs[k];
+ }
+ tableIndex = searchDefUseTable(theDef.offsetPC, theDef.regNum, theDef.physicalType);
+ if(tableIndex == NULL) //insert an entry
+ tableIndex = insertADef(theDef.offsetPC, theDef.regNum, theDef.physicalType, theDef.accessType);
+ else
+ tableIndex->def.accessType = theDef.accessType;
+ RegAccessType useType = insertAUse(tableIndex, offsetPC, currentInfo.regNum, currentInfo.physicalType);
+ return useType;
+}
+
+//! insert a XFER_MEM_TO_XMM to currentBB->xferPoints
+
+//!
+void insertLoadXfer(int offset, int regNum, LowOpndRegType pType) {
+ //check whether it is already in currentBB->xferPoints
+ int k;
+ for(k = 0; k < currentBB->num_xfer_points; k++) {
+ if(currentBB->xferPoints[k].xtype == XFER_MEM_TO_XMM &&
+ currentBB->xferPoints[k].offsetPC == offset &&
+ currentBB->xferPoints[k].regNum == regNum &&
+ currentBB->xferPoints[k].physicalType == pType)
+ return;
+ }
+ currentBB->xferPoints[currentBB->num_xfer_points].xtype = XFER_MEM_TO_XMM;
+ currentBB->xferPoints[currentBB->num_xfer_points].regNum = regNum;
+ currentBB->xferPoints[currentBB->num_xfer_points].offsetPC = offset;
+ currentBB->xferPoints[currentBB->num_xfer_points].physicalType = pType;
+#ifdef DEBUG_XFER_POINTS
+ ALOGI("insert to xferPoints %d: XFER_MEM_TO_XMM of VR %d %d at %d", currentBB->num_xfer_points, regNum, pType, offset);
+#endif
+ currentBB->num_xfer_points++;
+ if(currentBB->num_xfer_points >= MAX_XFER_PER_BB) {
+ ALOGE("too many xfer points");
+ dvmAbort();
+ }
+}
+
+/** update defUseTable by assuming a fake usage at END of a basic block for variable @ currentInfo
+ create a fake usage at end of a basic block for variable B (currentInfo.physicalType, currentInfo.regNum)
+ get reaching def info for variable B and store the info in currentInfo.reachingDefs
+ for each virtual register (variable A) accessed in the basic block
+ update reaching defs of B by checking reaching defs of variable A
+ update defUseTable
+*/
+int fakeUsageAtEndOfBB(BasicBlock_O1* bb) {
+ currentInfo.accessType = REGACCESS_U;
+ LowOpndRegType typeB = currentInfo.physicalType;
+ int regB = currentInfo.regNum;
+ int jj, k;
+ currentInfo.num_reaching_defs = 0;
+ for(jj = 0; jj < bb->num_regs; jj++) {
+ int regA = bb->infoBasicBlock[jj].regNum;
+ LowOpndRegType typeA = bb->infoBasicBlock[jj].physicalType;
+ OverlapCase isBPartiallyOverlapA = getBPartiallyOverlapA(regB, typeB, regA, typeA);
+ if(regA == regB && typeA == typeB) {
+ /* copy reachingDefs from variable A */
+ currentInfo.num_reaching_defs = bb->infoBasicBlock[jj].num_reaching_defs;
+ for(k = 0; k < currentInfo.num_reaching_defs; k++)
+ currentInfo.reachingDefs[k] = bb->infoBasicBlock[jj].reachingDefs[k];
+ break;
+ }
+ else if(isBPartiallyOverlapA != OVERLAP_NO) {
+ /* B overlaps with A */
+ /* update reaching defs of variable B by checking reaching defs of bb->infoBasicBlock[jj] */
+ updateReachingDefB1(jj);
+ updateReachingDefB2(); //merge currentInfo with tmpInfo
+ }
+ }
+ /* update defUseTable by checking currentInfo */
+ updateDefUseTable();
+ return 0;
+}
+
+/** update xferPoints of currentBB
+ Traverse currentBB->defUseTable
+*/
+int updateXferPoints() {
+ int k = 0;
+ currentBB->num_xfer_points = 0;
+ DefUsePair* ptr = currentBB->defUseTable;
+ DefOrUseLink* ptrUse = NULL;
+ /* traverse the def use chain of the basic block */
+ while(ptr != NULL) {
+ LowOpndRegType defType = ptr->def.physicalType;
+ //if definition is for a variable of 32 bits
+ if(getRegSize(defType) == OpndSize_32) {
+ /* check usages of the definition, whether it reaches a GPR, a XMM, a FS, or a SS */
+ bool hasGpUsage = false;
+ bool hasGpUsage2 = false; //not a fake usage
+ bool hasXmmUsage = false;
+ bool hasFSUsage = false;
+ bool hasSSUsage = false;
+ ptrUse = ptr->uses;
+ while(ptrUse != NULL) {
+ if(ptrUse->physicalType == LowOpndRegType_gp) {
+ hasGpUsage = true;
+ if(ptrUse->offsetPC != PC_FOR_END_OF_BB)
+ hasGpUsage2 = true;
+ }
+ if(ptrUse->physicalType == LowOpndRegType_ss) hasSSUsage = true;
+ if(ptrUse->physicalType == LowOpndRegType_fs ||
+ ptrUse->physicalType == LowOpndRegType_fs_s)
+ hasFSUsage = true;
+ if(ptrUse->physicalType == LowOpndRegType_xmm) {
+ hasXmmUsage = true;
+ }
+ if(ptrUse->physicalType == LowOpndRegType_xmm ||
+ ptrUse->physicalType == LowOpndRegType_ss) {
+ /* if a 32-bit definition reaches a xmm usage or a SS usage,
+ insert a XFER_MEM_TO_XMM */
+ insertLoadXfer(ptrUse->offsetPC,
+ ptrUse->regNum, LowOpndRegType_xmm);
+ }
+ ptrUse = ptrUse->next;
+ }
+ if(((hasXmmUsage || hasFSUsage || hasSSUsage) && defType == LowOpndRegType_gp) ||
+ (hasGpUsage && defType == LowOpndRegType_fs) ||
+ (defType == LowOpndRegType_ss && (hasGpUsage || hasXmmUsage || hasFSUsage))) {
+ /* insert a transfer if def is on a GPR, usage is on a XMM, FS or SS
+ if def is on a FS, usage is on a GPR
+ if def is on a SS, usage is on a GPR, XMM or FS
+ transfer type is XFER_DEF_TO_GP_MEM if a real GPR usage exisits
+ transfer type is XFER_DEF_TO_GP otherwise*/
+ currentBB->xferPoints[currentBB->num_xfer_points].offsetPC = ptr->def.offsetPC;
+ currentBB->xferPoints[currentBB->num_xfer_points].regNum = ptr->def.regNum;
+ currentBB->xferPoints[currentBB->num_xfer_points].physicalType = ptr->def.physicalType;
+ if(hasGpUsage2) { //create an entry XFER_DEF_TO_GP_MEM
+ currentBB->xferPoints[currentBB->num_xfer_points].xtype = XFER_DEF_TO_GP_MEM;
+ }
+ else { //create an entry XFER_DEF_TO_MEM
+ currentBB->xferPoints[currentBB->num_xfer_points].xtype = XFER_DEF_TO_MEM;
+ }
+ currentBB->xferPoints[currentBB->num_xfer_points].tableIndex = k;
+#ifdef DEBUG_XFER_POINTS
+ ALOGI("insert XFER %d at def %d: V%d %d", currentBB->num_xfer_points, ptr->def.offsetPC, ptr->def.regNum, defType);
+#endif
+ currentBB->num_xfer_points++;
+ if(currentBB->num_xfer_points >= MAX_XFER_PER_BB) {
+ ALOGE("too many xfer points");
+ dvmAbort();
+ }
+ }
+ }
+ else { /* def is on 64 bits */
+ bool hasGpUsageOfL = false; //exist a GPR usage of the low half
+ bool hasGpUsageOfH = false; //exist a GPR usage of the high half
+ bool hasGpUsageOfL2 = false;
+ bool hasGpUsageOfH2 = false;
+ bool hasMisaligned = false;
+ bool hasAligned = false;
+ bool hasFSUsage = false;
+ bool hasSSUsage = false;
+ ptrUse = ptr->uses;
+ while(ptrUse != NULL) {
+ if(ptrUse->physicalType == LowOpndRegType_gp &&
+ ptrUse->regNum == ptr->def.regNum) {
+ hasGpUsageOfL = true;
+ if(ptrUse->offsetPC != PC_FOR_END_OF_BB)
+ hasGpUsageOfL2 = true;
+ }
+ if(ptrUse->physicalType == LowOpndRegType_gp &&
+ ptrUse->regNum == ptr->def.regNum + 1) {
+ hasGpUsageOfH = true;
+ if(ptrUse->offsetPC != PC_FOR_END_OF_BB)
+ hasGpUsageOfH2 = true;
+ }
+ if(ptrUse->physicalType == LowOpndRegType_xmm &&
+ ptrUse->regNum == ptr->def.regNum) {
+ hasAligned = true;
+ /* if def is on FS and use is on XMM, insert a XFER_MEM_TO_XMM */
+ if(defType == LowOpndRegType_fs)
+ insertLoadXfer(ptrUse->offsetPC,
+ ptrUse->regNum, LowOpndRegType_xmm);
+ }
+ if(ptrUse->physicalType == LowOpndRegType_fs ||
+ ptrUse->physicalType == LowOpndRegType_fs_s)
+ hasFSUsage = true;
+ if(ptrUse->physicalType == LowOpndRegType_xmm &&
+ ptrUse->regNum != ptr->def.regNum) {
+ hasMisaligned = true;
+ /* if use is on XMM and use and def are misaligned, insert a XFER_MEM_TO_XMM */
+ insertLoadXfer(ptrUse->offsetPC,
+ ptrUse->regNum, LowOpndRegType_xmm);
+ }
+ if(ptrUse->physicalType == LowOpndRegType_ss) {
+ hasSSUsage = true;
+ /* if use is on SS, insert a XFER_MEM_TO_XMM */
+ insertLoadXfer(ptrUse->offsetPC,
+ ptrUse->regNum, LowOpndRegType_ss);
+ }
+ ptrUse = ptrUse->next;
+ }
+ if(defType == LowOpndRegType_fs && !hasGpUsageOfL && !hasGpUsageOfH) {
+ ptr = ptr->next;
+ continue;
+ }
+ if(defType == LowOpndRegType_xmm && !hasFSUsage &&
+ !hasGpUsageOfL && !hasGpUsageOfH && !hasMisaligned && !hasSSUsage) {
+ ptr = ptr->next;
+ continue;
+ }
+ /* insert a XFER_DEF_IS_XMM */
+ currentBB->xferPoints[currentBB->num_xfer_points].regNum = ptr->def.regNum;
+ currentBB->xferPoints[currentBB->num_xfer_points].offsetPC = ptr->def.offsetPC;
+ currentBB->xferPoints[currentBB->num_xfer_points].physicalType = ptr->def.physicalType;
+ currentBB->xferPoints[currentBB->num_xfer_points].xtype = XFER_DEF_IS_XMM;
+ currentBB->xferPoints[currentBB->num_xfer_points].vr_gpl = -1;
+ currentBB->xferPoints[currentBB->num_xfer_points].vr_gph = -1;
+ if(hasGpUsageOfL2) currentBB->xferPoints[currentBB->num_xfer_points].vr_gpl = ptr->def.regNum;
+ if(hasGpUsageOfH2) currentBB->xferPoints[currentBB->num_xfer_points].vr_gph = ptr->def.regNum+1;
+ currentBB->xferPoints[currentBB->num_xfer_points].dumpToMem = true;
+ currentBB->xferPoints[currentBB->num_xfer_points].dumpToXmm = false; //not used in updateVirtualReg
+ if(hasAligned) currentBB->xferPoints[currentBB->num_xfer_points].dumpToXmm = true;
+ currentBB->xferPoints[currentBB->num_xfer_points].tableIndex = k;
+#ifdef DEBUG_XFER_POINTS
+ ALOGI("insert XFER %d at def %d: V%d %d", currentBB->num_xfer_points, ptr->def.offsetPC, ptr->def.regNum, defType);
+#endif
+ currentBB->num_xfer_points++;
+ if(currentBB->num_xfer_points >= MAX_XFER_PER_BB) {
+ ALOGE("too many xfer points");
+ dvmAbort();
+ }
+ }
+ ptr = ptr->next;
+ } //while ptr
+#ifdef DEBUG_XFER_POINTS
+ ALOGI("XFER points for current basic block ------");
+ for(k = 0; k < currentBB->num_xfer_points; k++) {
+ ALOGI(" at offset %x, VR %d %d: type %d, vr_gpl %d, vr_gph %d, dumpToMem %d, dumpToXmm %d",
+ currentBB->xferPoints[k].offsetPC, currentBB->xferPoints[k].regNum,
+ currentBB->xferPoints[k].physicalType, currentBB->xferPoints[k].xtype,
+ currentBB->xferPoints[k].vr_gpl, currentBB->xferPoints[k].vr_gph,
+ currentBB->xferPoints[k].dumpToMem, currentBB->xferPoints[k].dumpToXmm);
+ }
+#endif
+ return -1;
+}
+
+//! update memVRTable[].ranges by browsing the defUseTable
+
+//! each virtual register has a list of live ranges, and each live range has a list of PCs that access the VR
+void updateLiveTable() {
+ DefUsePair* ptr = currentBB->defUseTable;
+ while(ptr != NULL) {
+ bool updateUse = false;
+ if(ptr->num_uses == 0) {
+ ptr->num_uses = 1;
+ ptr->uses = (DefOrUseLink*)malloc(sizeof(DefOrUseLink));
+ if(ptr->uses == NULL) {
+ ALOGE("Memory allocation failed");
+ return;
+ }
+ ptr->uses->accessType = REGACCESS_D;
+ ptr->uses->regNum = ptr->def.regNum;
+ ptr->uses->offsetPC = ptr->def.offsetPC;
+ ptr->uses->physicalType = ptr->def.physicalType;
+ ptr->uses->next = NULL;
+ ptr->useTail = ptr->uses;
+ updateUse = true;
+ }
+ DefOrUseLink* ptrUse = ptr->uses;
+ while(ptrUse != NULL) {
+ RegAccessType useType = ptrUse->accessType;
+ if(useType == REGACCESS_L || useType == REGACCESS_D) {
+ int indexL = searchMemTable(ptrUse->regNum);
+ if(indexL >= 0)
+ mergeLiveRange(indexL, ptr->def.offsetPC,
+ ptrUse->offsetPC); //tableIndex, start PC, end PC
+ }
+ if(getRegSize(ptrUse->physicalType) == OpndSize_64 &&
+ (useType == REGACCESS_H || useType == REGACCESS_D)) {
+ int indexH = searchMemTable(ptrUse->regNum+1);
+ if(indexH >= 0)
+ mergeLiveRange(indexH, ptr->def.offsetPC,
+ ptrUse->offsetPC);
+ }
+ ptrUse = ptrUse->next;
+ }//while ptrUse
+ if(updateUse) {
+ ptr->num_uses = 0;
+ free(ptr->uses);
+ ptr->uses = NULL;
+ ptr->useTail = NULL;
+ }
+ ptr = ptr->next;
+ }//while ptr
+#ifdef DEBUG_LIVE_RANGE
+ ALOGI("LIVE TABLE");
+ for(int k = 0; k < num_memory_vr; k++) {
+ ALOGI("VR %d live ", memVRTable[k].regNum);
+ LiveRange* ptr = memVRTable[k].ranges;
+ while(ptr != NULL) {
+ ALOGI("[%x %x] (", ptr->start, ptr->end);
+ for(int k3 = 0; k3 < ptr->num_access; k3++)
+ ALOGI("%x ", ptr->accessPC[k3]);
+ ALOGI(") ");
+ ptr = ptr->next;
+ }
+ ALOGI("");
+ }
+#endif
+}
+
+//!add a live range [rangeStart, rangeEnd] to ranges of memVRTable, merge to existing live ranges if necessary
+
+//!ranges are in increasing order of startPC
+void mergeLiveRange(int tableIndex, int rangeStart, int rangeEnd) {
+ if(rangeStart == PC_FOR_START_OF_BB) rangeStart = currentBB->pc_start;
+ if(rangeEnd == PC_FOR_END_OF_BB) rangeEnd = currentBB->pc_end;
+#ifdef DEBUG_LIVE_RANGE
+ ALOGI("LIVERANGE call mergeLiveRange on tableIndex %d with [%x %x]", tableIndex, rangeStart, rangeEnd);
+#endif
+ int startIndex = -1, endIndex = -1;
+ bool startBeforeRange = false, endBeforeRange = false; //before the index or in the range
+ bool startDone = false, endDone = false;
+ LiveRange* ptr = memVRTable[tableIndex].ranges;
+ LiveRange* ptrStart = NULL;
+ LiveRange* ptrStart_prev = NULL;
+ LiveRange* ptrEnd = NULL;
+ LiveRange* ptrEnd_prev = NULL;
+ int k = 0;
+ while(ptr != NULL) {
+ if(!startDone) {
+ if(ptr->start <= rangeStart &&
+ ptr->end >= rangeStart) {
+ startIndex = k;
+ ptrStart = ptr;
+ startBeforeRange = false;
+ startDone = true;
+ }
+ else if(ptr->start > rangeStart) {
+ startIndex = k;
+ ptrStart = ptr;
+ startBeforeRange = true;
+ startDone = true;
+ }
+ }
+ if(!startDone) ptrStart_prev = ptr;
+ if(!endDone) {
+ if(ptr->start <= rangeEnd &&
+ ptr->end >= rangeEnd) {
+ endIndex = k;
+ ptrEnd = ptr;
+ endBeforeRange = false;
+ endDone = true;
+ }
+ else if(ptr->start > rangeEnd) {
+ endIndex = k;
+ ptrEnd = ptr;
+ endBeforeRange = true;
+ endDone = true;
+ }
+ }
+ if(!endDone) ptrEnd_prev = ptr;
+ ptr = ptr->next;
+ k++;
+ } //while
+ if(!startDone) { //both can be NULL
+ startIndex = memVRTable[tableIndex].num_ranges;
+ ptrStart = NULL; //ptrStart_prev should be the last live range
+ startBeforeRange = true;
+ }
+ //if endDone, ptrEnd is not NULL, ptrEnd_prev can be NULL
+ if(!endDone) { //both can be NULL
+ endIndex = memVRTable[tableIndex].num_ranges;
+ ptrEnd = NULL;
+ endBeforeRange = true;
+ }
+ if(startIndex == endIndex && startBeforeRange && endBeforeRange) { //insert at startIndex
+ //3 cases depending on BeforeRange when startIndex == endIndex
+ //insert only if both true
+ //merge otherwise
+ /////////// insert before ptrStart
+ LiveRange* currRange = (LiveRange *)malloc(sizeof(LiveRange));
+ if(ptrStart_prev == NULL) {
+ currRange->next = memVRTable[tableIndex].ranges;
+ memVRTable[tableIndex].ranges = currRange;
+ } else {
+ currRange->next = ptrStart_prev->next;
+ ptrStart_prev->next = currRange;
+ }
+ currRange->start = rangeStart;
+ currRange->end = rangeEnd;
+ currRange->accessPC = (int *)malloc(sizeof(int) * NUM_ACCESS_IN_LIVERANGE);
+ currRange->num_alloc = NUM_ACCESS_IN_LIVERANGE;
+ if(rangeStart != rangeEnd) {
+ currRange->num_access = 2;
+ currRange->accessPC[0] = rangeStart;
+ currRange->accessPC[1] = rangeEnd;
+ } else {
+ currRange->num_access = 1;
+ currRange->accessPC[0] = rangeStart;
+ }
+ memVRTable[tableIndex].num_ranges++;
+#ifdef DEBUG_LIVE_RANGE
+ ALOGI("LIVERANGE insert one live range [%x %x] to tableIndex %d", rangeStart, rangeEnd, tableIndex);
+#endif
+ return;
+ }
+ if(!endBeforeRange) { //here ptrEnd is not NULL
+ endIndex++; //next
+ ptrEnd_prev = ptrEnd; //ptrEnd_prev is not NULL
+ ptrEnd = ptrEnd->next; //ptrEnd can be NULL
+ }
+ if(endIndex < startIndex+1) ALOGE("mergeLiveRange endIndex %d startIndex %d", endIndex, startIndex);
+ ///////// use ptrStart & ptrEnd_prev
+ if(ptrStart == NULL || ptrEnd_prev == NULL) {
+ ALOGE("mergeLiveRange ptr is NULL");
+ return;
+ }
+ //endIndex > startIndex (merge the ranges between startIndex and endIndex-1)
+ //update ptrStart
+ if(ptrStart->start > rangeStart)
+ ptrStart->start = rangeStart; //min of old start & rangeStart
+ ptrStart->end = ptrEnd_prev->end; //max of old end & rangeEnd
+ if(rangeEnd > ptrStart->end)
+ ptrStart->end = rangeEnd;
+#ifdef DEBUG_LIVE_RANGE
+ ALOGI("LIVERANGE merge entries for tableIndex %d from %d to %d", tableIndex, startIndex+1, endIndex-1);
+#endif
+ if(ptrStart->num_access <= 0) ALOGE("mergeLiveRange number of access");
+#ifdef DEBUG_LIVE_RANGE
+ ALOGI("LIVERANGE tableIndex %d startIndex %d num_access %d (", tableIndex, startIndex, ptrStart->num_access);
+ for(k = 0; k < ptrStart->num_access; k++)
+ ALOGI("%x ", ptrStart->accessPC[k]);
+ ALOGI(")");
+#endif
+ ///// go through pointers from ptrStart->next to ptrEnd
+ //from startIndex+1 to endIndex-1
+ ptr = ptrStart->next;
+ while(ptr != NULL && ptr != ptrEnd) {
+ int k2;
+ for(k2 = 0; k2 < ptr->num_access; k2++) { //merge to startIndex
+ insertAccess(tableIndex, ptrStart, ptr->accessPC[k2]);
+ }//k2
+ ptr = ptr->next;
+ }
+ insertAccess(tableIndex, ptrStart, rangeStart);
+ insertAccess(tableIndex, ptrStart, rangeEnd);
+ //remove startIndex+1 to endIndex-1
+ if(startIndex+1 < endIndex) {
+ ptr = ptrStart->next;
+ while(ptr != NULL && ptr != ptrEnd) {
+ LiveRange* tmpP = ptr->next;
+ free(ptr->accessPC);
+ free(ptr);
+ ptr = tmpP;
+ }
+ ptrStart->next = ptrEnd;
+ }
+ memVRTable[tableIndex].num_ranges -= (endIndex - startIndex - 1);
+#ifdef DEBUG_LIVE_RANGE
+ ALOGI("num_ranges for VR %d: %d", memVRTable[tableIndex].regNum, memVRTable[tableIndex].num_ranges);
+#endif
+}
+//! insert an access to a given live range, in order
+
+//!
+void insertAccess(int tableIndex, LiveRange* startP, int rangeStart) {
+ int k3, k4;
+#ifdef DEBUG_LIVE_RANGE
+ ALOGI("LIVERANGE insertAccess %d %x", tableIndex, rangeStart);
+#endif
+ int insertIndex = -1;
+ for(k3 = 0; k3 < startP->num_access; k3++) {
+ if(startP->accessPC[k3] == rangeStart) {
+ return;
+ }
+ if(startP->accessPC[k3] > rangeStart) {
+ insertIndex = k3;
+ break;
+ }
+ }
+
+ //insert here
+ k3 = insertIndex;
+ if(insertIndex == -1) {
+ k3 = startP->num_access;
+ }
+ if(startP->num_access == startP->num_alloc) {
+ int currentAlloc = startP->num_alloc;
+ startP->num_alloc += NUM_ACCESS_IN_LIVERANGE;
+ int* tmpPtr = (int *)malloc(sizeof(int) * startP->num_alloc);
+ for(k4 = 0; k4 < currentAlloc; k4++)
+ tmpPtr[k4] = startP->accessPC[k4];
+ free(startP->accessPC);
+ startP->accessPC = tmpPtr;
+ }
+ //insert accessPC
+ for(k4 = startP->num_access-1; k4 >= k3; k4--)
+ startP->accessPC[k4+1] = startP->accessPC[k4];
+ startP->accessPC[k3] = rangeStart;
+#ifdef DEBUG_LIVE_RANGE
+ ALOGI("LIVERANGE insert %x to tableIndex %d", rangeStart, tableIndex);
+#endif
+ startP->num_access++;
+ return;
+}
+
+/////////////////////////////////////////////////////////////////////
+bool isInMemory(int regNum, OpndSize size);
+void setVRToMemory(int regNum, OpndSize size);
+bool isVRLive(int vA);
+int getSpillIndex(bool isGLUE, OpndSize size);
+void clearVRToMemory(int regNum, OpndSize size);
+void clearVRNullCheck(int regNum, OpndSize size);
+
+inline int getSpillLocDisp(int offset) {
+#ifdef SPILL_IN_THREAD
+ return offset+offsetof(Thread, spillRegion);;
+#else
+ return offset+offEBP_spill;
+#endif
+}
+#if 0
+/* used if we keep self pointer in a physical register */
+inline int getSpillLocReg(int offset) {
+ return PhysicalReg_Glue;
+}
+#endif
+#ifdef SPILL_IN_THREAD
+inline void loadFromSpillRegion_with_self(OpndSize size, int reg_self, bool selfPhysical, int reg, int offset) {
+ /* only 1 instruction is generated by move_mem_to_reg_noalloc */
+ move_mem_to_reg_noalloc(size,
+ getSpillLocDisp(offset), reg_self, selfPhysical,
+ MemoryAccess_SPILL, offset,
+ reg, true);
+}
+inline void loadFromSpillRegion(OpndSize size, int reg, int offset) {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ int reg_self = registerAlloc(LowOpndRegType_scratch, C_SCRATCH_1, isScratchPhysical, false);
+ /* only 1 instruction is generated by move_mem_to_reg_noalloc */
+ move_mem_to_reg_noalloc(size,
+ getSpillLocDisp(offset), reg_self, true,
+ MemoryAccess_SPILL, offset,
+ reg, true);
+}
+inline void saveToSpillRegion_with_self(OpndSize size, int selfReg, bool selfPhysical, int reg, int offset) {
+ move_reg_to_mem_noalloc(size,
+ reg, true,
+ getSpillLocDisp(offset), selfReg, selfPhysical,
+ MemoryAccess_SPILL, offset);
+}
+inline void saveToSpillRegion(OpndSize size, int reg, int offset) {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ int reg_self = registerAlloc(LowOpndRegType_scratch, C_SCRATCH_1, isScratchPhysical, false);
+ move_reg_to_mem_noalloc(size,
+ reg, true,
+ getSpillLocDisp(offset), reg_self, true,
+ MemoryAccess_SPILL, offset);
+}
+#else
+inline void loadFromSpillRegion(OpndSize size, int reg, int offset) {
+ /* only 1 instruction is generated by move_mem_to_reg_noalloc */
+ move_mem_to_reg_noalloc(size,
+ getSpillLocDisp(offset), PhysicalReg_EBP, true,
+ MemoryAccess_SPILL, offset,
+ reg, true);
+}
+inline void saveToSpillRegion(OpndSize size, int reg, int offset) {
+ move_reg_to_mem_noalloc(size,
+ reg, true,
+ getSpillLocDisp(offset), PhysicalReg_EBP, true,
+ MemoryAccess_SPILL, offset);
+}
+#endif
+
+//! dump an immediate to memory, set inMemory to true
+
+//!
+void dumpImmToMem(int vrNum, OpndSize size, int value) {
+ if(isInMemory(vrNum, size)) {
+#ifdef DEBUG_SPILL
+ ALOGI("Skip dumpImmToMem vA %d size %d", vrNum, size);
+#endif
+ return;
+ }
+ set_VR_to_imm_noalloc(vrNum, size, value);
+ setVRToMemory(vrNum, size);
+}
+//! dump content of a VR to memory, set inMemory to true
+
+//!
+void dumpToMem(int vrNum, LowOpndRegType type, int regAll) { //ss,gp,xmm
+ if(isInMemory(vrNum, getRegSize(type))) {
+#ifdef DEBUG_SPILL
+ ALOGI("Skip dumpToMem vA %d type %d", vrNum, type);
+#endif
+ return;
+ }
+ if(type == LowOpndRegType_gp || type == LowOpndRegType_xmm)
+ set_virtual_reg_noalloc(vrNum, getRegSize(type), regAll, true);
+ if(type == LowOpndRegType_ss)
+ move_ss_reg_to_mem_noalloc(regAll, true,
+ 4*vrNum, PhysicalReg_FP, true,
+ MemoryAccess_VR, vrNum);
+ setVRToMemory(vrNum, getRegSize(type));
+}
+//! dump part of a 64-bit VR to memory and update inMemory
+
+//! isLow tells whether low half or high half is dumped
+void dumpPartToMem(int reg /*xmm physical reg*/, int vA, bool isLow) {
+ if(isLow) {
+ if(isInMemory(vA, OpndSize_32)) {
+#ifdef DEBUG_SPILL
+ ALOGI("Skip dumpPartToMem isLow %d vA %d", isLow, vA);
+#endif
+ return;
+ }
+ }
+ else {
+ if(isInMemory(vA+1, OpndSize_32)) {
+#ifdef DEBUG_SPILL
+ ALOGI("Skip dumpPartToMem isLow %d vA %d", isLow, vA);
+#endif
+ return;
+ }
+ }
+ if(isLow) {
+ if(!isVRLive(vA)) return;
+ }
+ else {
+ if(!isVRLive(vA+1)) return;
+ }
+ //move part to vA or vA+1
+ if(isLow) {
+ move_ss_reg_to_mem_noalloc(reg, true,
+ 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA);
+ } else {
+ int k = getSpillIndex(false, OpndSize_64);
+ //H, L in 4*k+4 & 4*k
+#ifdef SPILL_IN_THREAD
+ get_self_pointer(PhysicalReg_SCRATCH_1, isScratchPhysical);
+ saveToSpillRegion_with_self(OpndSize_64, PhysicalReg_SCRATCH_1, isScratchPhysical, reg, 4*k);
+ //update low 32 bits of xmm reg from 4*k+4
+ move_ss_mem_to_reg(NULL,
+ getSpillLocDisp(4*k+4), PhysicalReg_SCRATCH_1, isScratchPhysical,
+ reg, true);
+#else
+ saveToSpillRegion(OpndSize_64, reg, 4*k);
+ //update low 32 bits of xmm reg from 4*k+4
+ move_ss_mem_to_reg_noalloc(
+ getSpillLocDisp(4*k+4), PhysicalReg_EBP, true,
+ MemoryAccess_SPILL, 4*k+4,
+ reg, true);
+#endif
+ //move low 32 bits of xmm reg to vA+1
+ move_ss_reg_to_mem_noalloc(reg, true, 4*(vA+1), PhysicalReg_FP, true, MemoryAccess_VR, vA+1);
+ }
+ if(isLow)
+ setVRToMemory(vA, OpndSize_32);
+ else
+ setVRToMemory(vA+1, OpndSize_32);
+}
+void clearVRBoundCheck(int regNum, OpndSize size);
+//! the content of a VR is no longer in memory or in physical register if the latest content of a VR is constant
+
+//! clear nullCheckDone; if another VR is overlapped with the given VR, the content of that VR is no longer in physical register
+void invalidateVRDueToConst(int reg, OpndSize size) {
+ clearVRToMemory(reg, size); //memory content is out-dated
+ clearVRNullCheck(reg, size);
+ clearVRBoundCheck(reg, size);
+ //check reg,gp reg,ss reg,xmm reg-1,xmm
+ //if size is 64: check reg+1,gp|ss reg+1,xmm
+ int index;
+ //if VR is xmm, check whether we need to dump part of VR to memory
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_xmm);
+#endif
+ if(size == OpndSize_32)
+ dumpPartToMem(compileTable[index].physicalReg, reg, false); //dump high of xmm to memory
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg-1);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg-1, LowOpndRegType_xmm);
+#endif
+ dumpPartToMem(compileTable[index].physicalReg, reg-1, true); //dump low of xmm to memory
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_gp, reg);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_gp);
+#endif
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_ss, reg);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_ss);
+#endif
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ if(size == OpndSize_64) {
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg+1);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_xmm);
+#endif
+ dumpPartToMem(compileTable[index].physicalReg, reg+1, false); //dump high of xmm to memory
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_gp, reg+1);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_gp);
+#endif
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_ss, reg+1);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_ss);
+#endif
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ }
+}
+//! check which physical registers hold out-dated content if there is a def
+
+//! if another VR is overlapped with the given VR, the content of that VR is no longer in physical register
+//! should we update inMemory?
+void invalidateVR(int reg, LowOpndRegType pType) {
+ //def at fs: content of xmm & gp & ss are out-dated (reg-1,xmm reg,xmm reg+1,xmm) (reg,gp|ss reg+1,gp|ss)
+ //def at xmm: content of misaligned xmm & gp are out-dated (reg-1,xmm reg+1,xmm) (reg,gp|ss reg+1,gp|ss)
+ //def at fs_s: content of xmm & gp are out-dated (reg-1,xmm reg,xmm) (reg,gp|ss)
+ //def at gp: content of xmm is out-dated (reg-1,xmm reg,xmm) (reg,ss)
+ //def at ss: content of xmm & gp are out-dated (reg-1,xmm reg,xmm) (reg,gp)
+ int index;
+ if(pType != LowOpndRegType_xmm) { //check xmm @reg
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_xmm);
+#endif
+ if(getRegSize(pType) == OpndSize_32)
+ dumpPartToMem(compileTable[index].physicalReg, reg, false); //dump high of xmm to memory
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ }
+ //check misaligned xmm @ reg-1
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg-1);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg-1, LowOpndRegType_xmm);
+#endif
+ dumpPartToMem(compileTable[index].physicalReg, reg-1, true); //dump low of xmm to memory
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ //check misaligned xmm @ reg+1
+ if(pType == LowOpndRegType_xmm || pType == LowOpndRegType_fs) {
+ //check reg+1,xmm
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg+1);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_xmm);
+#endif
+ dumpPartToMem(compileTable[index].physicalReg, reg+1, false); //dump high of xmm to memory
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ }
+ if(pType != LowOpndRegType_gp) {
+ //check reg,gp
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_gp, reg);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_gp);
+#endif
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ }
+ if(pType == LowOpndRegType_xmm || pType == LowOpndRegType_fs) {
+ //check reg+1,gp
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_gp, reg+1);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_gp);
+#endif
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ }
+ if(pType != LowOpndRegType_ss) {
+ //check reg,ss
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_ss, reg);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_ss);
+#endif
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ }
+ if(pType == LowOpndRegType_xmm || pType == LowOpndRegType_fs) {
+ //check reg+1,ss
+ index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_ss, reg+1);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_INVALIDATE
+ ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_ss);
+#endif
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ }
+ }
+}
+//! bookkeeping when a VR is updated
+
+//! invalidate contents of some physical registers, clear nullCheckDone, and update inMemory;
+//! check whether there exist tranfer points for this bytecode, if yes, perform the transfer
+int updateVirtualReg(int reg, LowOpndRegType pType) {
+ int k;
+ OpndSize size = getRegSize(pType);
+ //WAS only invalidate xmm VRs for the following cases:
+ //if def reaches a use of vA,xmm and (the def is not xmm or is misaligned xmm)
+ // invalidate "vA,xmm"
+ invalidateVR(reg, pType);
+ clearVRNullCheck(reg, size);
+ clearVRBoundCheck(reg, size);
+ if(pType == LowOpndRegType_fs || pType == LowOpndRegType_fs_s)
+ setVRToMemory(reg, size);
+ else {
+ clearVRToMemory(reg, size);
+ }
+ for(k = 0; k < currentBB->num_xfer_points; k++) {
+ if(currentBB->xferPoints[k].offsetPC == offsetPC &&
+ currentBB->xferPoints[k].regNum == reg &&
+ currentBB->xferPoints[k].physicalType == pType &&
+ currentBB->xferPoints[k].xtype != XFER_MEM_TO_XMM) {
+ //perform the corresponding action for the def
+ PhysicalReg regAll;
+ if(currentBB->xferPoints[k].xtype == XFER_DEF_IS_XMM) {
+ //def at fs: content of xmm is out-dated
+ //def at xmm: content of misaligned xmm is out-dated
+ //invalidateXmmVR(currentBB->xferPoints[k].tableIndex);
+#ifdef DEBUG_XFER_POINTS
+ if(currentBB->xferPoints[k].dumpToXmm) ALOGI("XFER set_virtual_reg to xmm: xmm VR %d", reg);
+#endif
+ if(pType == LowOpndRegType_xmm) {
+#ifdef DEBUG_XFER_POINTS
+ ALOGI("XFER set_virtual_reg to memory: xmm VR %d", reg);
+#endif
+ PhysicalReg regAll = (PhysicalReg)checkVirtualReg(reg, LowOpndRegType_xmm, 0 /* do not update*/);
+ dumpToMem(reg, LowOpndRegType_xmm, regAll);
+ }
+ if(currentBB->xferPoints[k].vr_gpl >= 0) { //
+ }
+ if(currentBB->xferPoints[k].vr_gph >= 0) {
+ }
+ }
+ if((pType == LowOpndRegType_gp || pType == LowOpndRegType_ss) &&
+ (currentBB->xferPoints[k].xtype == XFER_DEF_TO_MEM ||
+ currentBB->xferPoints[k].xtype == XFER_DEF_TO_GP_MEM)) {
+ //the defined gp VR already in register
+ //invalidateXmmVR(currentBB->xferPoints[k].tableIndex);
+ regAll = (PhysicalReg)checkVirtualReg(reg, pType, 0 /* do not update*/);
+ dumpToMem(reg, pType, regAll);
+#ifdef DEBUG_XFER_POINTS
+ ALOGI("XFER set_virtual_reg to memory: gp VR %d", reg);
+#endif
+ }
+ if((pType == LowOpndRegType_fs_s || pType == LowOpndRegType_ss) &&
+ currentBB->xferPoints[k].xtype == XFER_DEF_TO_GP_MEM) {
+ }
+ }
+ }
+ return -1;
+}
+////////////////////////////////////////////////////////////////
+//REGISTER ALLOCATION
+int spillForHardReg(int regNum, int type);
+void decreaseRefCount(int index);
+int getFreeReg(int type, int reg, int indexToCompileTable);
+PhysicalReg spillForLogicalReg(int type, int reg, int indexToCompileTable);
+int unspillLogicalReg(int spill_index, int physicalReg);
+int searchVirtualInfoOfBB(LowOpndRegType type, int regNum, BasicBlock_O1* bb);
+bool isTemp8Bit(int type, int reg);
+bool matchType(int typeA, int typeB);
+int getNextAccess(int compileIndex);
+void dumpCompileTable();
+
+//! allocate a register for a variable
+
+//!if no physical register is free, call spillForLogicalReg to free up a physical register;
+//!if the variable is a temporary and it was spilled, call unspillLogicalReg to load from spill location to the allocated physical register;
+//!if updateRefCount is true, reduce reference count of the variable by 1
+int registerAlloc(int type, int reg, bool isPhysical, bool updateRefCount) {
+#ifdef DEBUG_REGALLOC
+ ALOGI("%p: try to allocate register %d type %d isPhysical %d", currentBB, reg, type, isPhysical);
+#endif
+ if(currentBB == NULL) {
+ if(type & LowOpndRegType_virtual) return PhysicalReg_Null;
+ if(isPhysical) return reg; //for helper functions
+ return PhysicalReg_Null;
+ }
+ //ignore EDI, ESP, EBP (glue)
+ if(isPhysical && (reg == PhysicalReg_EDI || reg == PhysicalReg_ESP ||
+ reg == PhysicalReg_EBP || reg == PhysicalReg_Null))
+ return reg;
+
+ int newType = convertType(type, reg, isPhysical);
+ if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
+ int tIndex = searchCompileTable(newType, reg);
+ if(tIndex < 0) {
+ ALOGE("reg %d type %d not found in registerAlloc", reg, newType);
+ return PhysicalReg_Null;
+ }
+
+ //physical register
+ if(isPhysical) {
+ if(allRegs[reg].isUsed) { //if used by a non hard-coded register
+ spillForHardReg(reg, newType);
+ }
+ allRegs[reg].isUsed = true;
+#ifdef DEBUG_REG_USED
+ ALOGI("REGALLOC: allocate a reg %d", reg);
+#endif
+ compileTable[tIndex].physicalReg = reg;
+ if(updateRefCount)
+ decreaseRefCount(tIndex);
+#ifdef DEBUG_REGALLOC
+ ALOGI("REGALLOC: allocate register %d for logical register %d %d",
+ compileTable[tIndex].physicalReg, reg, newType);
+#endif
+ return reg;
+ }
+ //already allocated
+ if(compileTable[tIndex].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_REGALLOC
+ ALOGI("already allocated to physical register %d", compileTable[tIndex].physicalReg);
+#endif
+ if(updateRefCount)
+ decreaseRefCount(tIndex);
+ return compileTable[tIndex].physicalReg;
+ }
+
+ //at this point, the logical register is not hard-coded and is mapped to Reg_Null
+ //first check whether there is a free reg
+ //if not, call spillForLogicalReg
+ int index = getFreeReg(newType, reg, tIndex);
+ if(index >= 0 && index < PhysicalReg_Null) {
+ //update compileTable & allRegs
+ compileTable[tIndex].physicalReg = allRegs[index].physicalReg;
+ allRegs[index].isUsed = true;
+#ifdef DEBUG_REG_USED
+ ALOGI("REGALLOC: register %d is free", allRegs[index].physicalReg);
+#endif
+ } else {
+ PhysicalReg allocR = spillForLogicalReg(newType, reg, tIndex);
+ compileTable[tIndex].physicalReg = allocR;
+ }
+ if(compileTable[tIndex].spill_loc_index >= 0) {
+ unspillLogicalReg(tIndex, compileTable[tIndex].physicalReg);
+ }
+ if(updateRefCount)
+ decreaseRefCount(tIndex);
+#ifdef DEBUG_REGALLOC
+ ALOGI("REGALLOC: allocate register %d for logical register %d %d",
+ compileTable[tIndex].physicalReg, reg, newType);
+#endif
+ return compileTable[tIndex].physicalReg;
+}
+//!a variable will use a physical register allocated for another variable
+
+//!This is used when MOVE_OPT is on, it tries to alias a virtual register with a temporary to remove a move
+int registerAllocMove(int reg, int type, bool isPhysical, int srcReg) {
+ if(srcReg == PhysicalReg_EDI || srcReg == PhysicalReg_ESP || srcReg == PhysicalReg_EBP)
+ ALOGE("can't move from srcReg EDI or ESP or EBP");
+#ifdef DEBUG_REGALLOC
+ ALOGI("in registerAllocMove: reg %d type %d srcReg %d", reg, type, srcReg);
+#endif
+ int newType = convertType(type, reg, isPhysical);
+ if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
+ int index = searchCompileTable(newType, reg);
+ if(index < 0) {
+ ALOGE("reg %d type %d not found in registerAllocMove", reg, newType);
+ return -1;
+ }
+
+ decreaseRefCount(index);
+ compileTable[index].physicalReg = srcReg;
+#ifdef DEBUG_REGALLOC
+ ALOGI("REGALLOC: registerAllocMove %d for logical register %d %d",
+ compileTable[index].physicalReg, reg, newType);
+#endif
+ return srcReg;
+}
+
+//! check whether a physical register is available to be used by a variable
+
+//! data structures accessed:
+//! 1> currentBB->infoBasicBlock[index].allocConstraintsSorted
+//! sorted from high count to low count
+//! 2> currentBB->allocConstraintsSorted
+//! sorted from low count to high count
+//! 3> allRegs: whether a physical register is available, indexed by PhysicalReg
+//! NOTE: if a temporary variable is 8-bit, only %eax, %ebx, %ecx, %edx can be used
+int getFreeReg(int type, int reg, int indexToCompileTable) {
+ syncAllRegs();
+ /* handles requests for xmm or ss registers */
+ int k;
+ if(((type & MASK_FOR_TYPE) == LowOpndRegType_xmm) ||
+ ((type & MASK_FOR_TYPE) == LowOpndRegType_ss)) {
+ for(k = PhysicalReg_XMM0; k <= PhysicalReg_XMM7; k++) {
+ if(!allRegs[k].isUsed) return k;
+ }
+ return -1;
+ }
+#ifdef DEBUG_REGALLOC
+ ALOGI("USED registers: ");
+ for(k = 0; k < 8; k++)
+ ALOGI("%d used: %d time freed: %d callee-saveld: %d", k, allRegs[k].isUsed,
+ allRegs[k].freeTimeStamp, allRegs[k].isCalleeSaved);
+ ALOGI("");
+#endif
+
+ /* a VR is requesting a physical register */
+ if(isVirtualReg(type)) { //find a callee-saved register
+ /* if VR is type GG, check the pre-allocated physical register first */
+ bool isGGVR = compileTable[indexToCompileTable].gType == GLOBALTYPE_GG;
+ if(isGGVR) {
+ int regCandidateT = compileTable[indexToCompileTable].physicalReg_prev;
+ if(!allRegs[regCandidateT].isUsed) return regCandidateT;
+ }
+
+ int index = searchVirtualInfoOfBB((LowOpndRegType)(type&MASK_FOR_TYPE), reg, currentBB);
+ if(index < 0) {
+ ALOGE("VR %d %d not found in infoBasicBlock of currentBB %d (num of VRs %d)",
+ reg, type, currentBB->bb_index, currentBB->num_regs);
+ dvmAbort();
+ }
+
+ /* check allocConstraints for this VR,
+ return an available physical register with the highest constraint > 0 */
+ for(k = 0; k < 8; k++) {
+ if(currentBB->infoBasicBlock[index].allocConstraintsSorted[k].count == 0) break;
+ int regCandidateT = currentBB->infoBasicBlock[index].allocConstraintsSorted[k].physicalReg;
+ assert(regCandidateT < PhysicalReg_Null);
+ if(!allRegs[regCandidateT].isUsed) return regCandidateT;
+ }
+
+ /* WAS: return an available physical register with the lowest constraint
+ NOW: consider a new factor (freeTime) when there is a tie
+ if 2 available physical registers have the same number of constraints
+ choose the one with smaller free time stamp */
+ int currentCount = -1;
+ int index1 = -1;
+ int smallestTime = -1;
+ for(k = 0; k < 8; k++) {
+ int regCandidateT = currentBB->allocConstraintsSorted[k].physicalReg;
+ assert(regCandidateT < PhysicalReg_Null);
+ if(index1 >= 0 && currentBB->allocConstraintsSorted[k].count > currentCount)
+ break; //candidate has higher count than index1
+ if(!allRegs[regCandidateT].isUsed) {
+ if(index1 < 0) {
+ index1 = k;
+ currentCount = currentBB->allocConstraintsSorted[k].count;
+ smallestTime = allRegs[regCandidateT].freeTimeStamp;
+ } else if(allRegs[regCandidateT].freeTimeStamp < smallestTime) {
+ index1 = k;
+ smallestTime = allRegs[regCandidateT].freeTimeStamp;
+ }
+ }
+ }
+ if(index1 >= 0) return currentBB->allocConstraintsSorted[index1].physicalReg;
+ return -1;
+ }
+ /* handle request from a temporary variable or a glue variable */
+ else {
+ bool is8Bit = isTemp8Bit(type, reg);
+
+ /* if the temporary variable is linked to a VR and
+ the VR is not yet allocated to any physical register */
+ int vr_num = compileTable[indexToCompileTable].linkageToVR;
+ if(vr_num >= 0) {
+ int index3 = searchCompileTable(LowOpndRegType_gp | LowOpndRegType_virtual, vr_num);
+ if(index3 < 0) {
+ ALOGE("2 in tracing linkage to VR %d", vr_num);
+ dvmAbort();
+ }
+
+ if(compileTable[index3].physicalReg == PhysicalReg_Null) {
+ int index2 = searchVirtualInfoOfBB(LowOpndRegType_gp, vr_num, currentBB);
+ if(index2 < 0) {
+ ALOGE("1 in tracing linkage to VR %d", vr_num);
+ dvmAbort();
+ }
+#ifdef DEBUG_REGALLOC
+ ALOGI("in getFreeReg for temporary reg %d, trace the linkage to VR %d",
+ reg, vr_num);
+#endif
+
+ /* check allocConstraints on the VR
+ return an available physical register with the highest constraint > 0
+ */
+ for(k = 0; k < 8; k++) {
+ if(currentBB->infoBasicBlock[index2].allocConstraintsSorted[k].count == 0) break;
+ int regCandidateT = currentBB->infoBasicBlock[index2].allocConstraintsSorted[k].physicalReg;
+#ifdef DEBUG_REGALLOC
+ ALOGI("check register %d with count %d", regCandidateT,
+ currentBB->infoBasicBlock[index2].allocConstraintsSorted[k].count);
+#endif
+ /* if the requesting variable is 8 bit */
+ if(is8Bit && regCandidateT > PhysicalReg_EDX) continue;
+ assert(regCandidateT < PhysicalReg_Null);
+ if(!allRegs[regCandidateT].isUsed) return regCandidateT;
+ }
+ }
+ }
+ /* check allocConstraints of the basic block
+ if 2 available physical registers have the same constraint count,
+ return the non callee-saved physical reg */
+ /* enhancement: record the time when a register is freed (freeTimeStamp)
+ the purpose is to reduce false dependency
+ priority: constraint count, non callee-saved, time freed
+ let x be the lowest constraint count
+ set A be available callee-saved physical registers with count == x
+ set B be available non callee-saved physical registers with count == x
+ if set B is not null, return the one with smallest free time
+ otherwise, return the one in A with smallest free time
+ To ignore whether it is callee-saved, add all candidates to set A
+ */
+ int setAIndex[8];
+ int num_A = 0;
+ int setBIndex[8];
+ int num_B = 0;
+ int index1 = -1; //points to an available physical reg with lowest count
+ int currentCount = -1;
+ for(k = 0; k < 8; k++) {
+ int regCandidateT = currentBB->allocConstraintsSorted[k].physicalReg;
+ if(is8Bit && regCandidateT > PhysicalReg_EDX) continue;
+
+ if(index1 >= 0 && currentBB->allocConstraintsSorted[k].count > currentCount)
+ break; //candidate has higher count than index1
+ assert(regCandidateT < PhysicalReg_Null);
+ if(!allRegs[regCandidateT].isUsed) {
+ /*To ignore whether it is callee-saved, add all candidates to set A */
+ if(false) {//!allRegs[regCandidateT].isCalleeSaved) { //add to set B
+ setBIndex[num_B++] = k;
+ } else { //add to set A
+ setAIndex[num_A++] = k;
+ }
+ if(index1 < 0) {
+ /* index1 points to a physical reg with lowest count */
+ index1 = k;
+ currentCount = currentBB->allocConstraintsSorted[k].count;
+ }
+ }
+ }
+
+ int kk;
+ int smallestTime = -1;
+ index1 = -1;
+ for(kk = 0; kk < num_B; kk++) {
+ k = setBIndex[kk];
+ int regCandidateT = currentBB->allocConstraintsSorted[k].physicalReg;
+ assert(regCandidateT < PhysicalReg_Null);
+ if(kk == 0 || allRegs[regCandidateT].freeTimeStamp < smallestTime) {
+ index1 = k;
+ smallestTime = allRegs[regCandidateT].freeTimeStamp;
+ }
+ }
+ if(index1 >= 0)
+ return currentBB->allocConstraintsSorted[index1].physicalReg;
+ index1 = -1;
+ for(kk = 0; kk < num_A; kk++) {
+ k = setAIndex[kk];
+ int regCandidateT = currentBB->allocConstraintsSorted[k].physicalReg;
+ if(kk == 0 || allRegs[regCandidateT].freeTimeStamp < smallestTime) {
+ index1 = k;
+ smallestTime = allRegs[regCandidateT].freeTimeStamp;
+ }
+ }
+ if(index1 >= 0) return currentBB->allocConstraintsSorted[index1].physicalReg;
+ return -1;
+ }
+ return -1;
+}
+
+//! find a candidate physical register for a variable and spill all variables that are mapped to the candidate
+
+//!
+PhysicalReg spillForLogicalReg(int type, int reg, int indexToCompileTable) {
+ //choose a used register to spill
+ //when a GG virtual register is spilled, write it to interpretd stack, set physicalReg to Null
+ // at end of the basic block, load spilled GG VR to physical reg
+ //when other types of VR is spilled, write it to interpreted stack, set physicalReg to Null
+ //when a temporary (non-virtual) register is spilled, write it to stack, set physicalReg to Null
+ //can we spill a hard-coded temporary register? YES
+ int k, k2;
+ PhysicalReg allocR;
+
+ //do not try to free a physical reg that is used by more than one logical registers
+ //fix on sep 28, 2009
+ //do not try to spill a hard-coded logical register
+ //do not try to free a physical reg that is outside of the range for 8-bit logical reg
+ /* for each physical register,
+ collect number of non-hardcode entries that are mapped to the physical register */
+ int numOfUses[PhysicalReg_Null];
+ for(k = PhysicalReg_EAX; k < PhysicalReg_Null; k++)
+ numOfUses[k] = 0;
+ for(k = 0; k < num_compile_entries; k++) {
+ if((compileTable[k].physicalReg != PhysicalReg_Null) &&
+ matchType(type, compileTable[k].physicalType) &&
+ (compileTable[k].physicalType & LowOpndRegType_hard) == 0) {
+ numOfUses[compileTable[k].physicalReg]++;
+ }
+ }
+
+ /* candidates: all non-hardcode entries that are mapped to
+ a physical register that is used by only one entry*/
+ bool is8Bit = isTemp8Bit(type, reg);
+ int candidates[COMPILE_TABLE_SIZE];
+ int num_cand = 0;
+ for(k = 0; k < num_compile_entries; k++) {
+ if(matchType(type, compileTable[k].physicalType) &&
+ compileTable[k].physicalReg != PhysicalReg_Null) {
+ if(is8Bit && compileTable[k].physicalReg > PhysicalReg_EDX) continue; //not a candidate
+ if(!canSpillReg[compileTable[k].physicalReg]) continue; //not a candidate
+ if((compileTable[k].physicalType & LowOpndRegType_hard) == 0 &&
+ numOfUses[compileTable[k].physicalReg] <= 1) {
+ candidates[num_cand++] = k;
+ }
+ }
+ }
+
+ /* go through all candidates:
+ first check GLUE-related entries */
+ int spill_index = -1;
+ for(k2 = 0; k2 < num_cand; k2++) {
+ k = candidates[k2];
+ if((compileTable[k].physicalReg != PhysicalReg_Null) &&
+ matchType(type, compileTable[k].physicalType) &&
+ (compileTable[k].regNum >= PhysicalReg_GLUE_DVMDEX &&
+ compileTable[k].regNum != PhysicalReg_GLUE)) {
+ allocR = (PhysicalReg)spillLogicalReg(k, true);
+#ifdef DEBUG_REGALLOC
+ ALOGI("SPILL register used by num %d type %d it is a GLUE register with refCount %d",
+ compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].refCount);
+#endif
+ return allocR;
+ }
+ }
+
+ /* out of the candates, find a VR that has the furthest next use */
+ int furthestUse = offsetPC;
+ for(k2 = 0; k2 < num_cand; k2++) {
+ k = candidates[k2];
+ if((compileTable[k].physicalReg != PhysicalReg_Null) &&
+ matchType(type, compileTable[k].physicalType) &&
+ isVirtualReg(compileTable[k].physicalType)) {
+ int nextUse = getNextAccess(k);
+ if(spill_index < 0 || nextUse > furthestUse) {
+ spill_index = k;
+ furthestUse = nextUse;
+ }
+ }
+ }
+
+ /* spill the VR with the furthest next use */
+ if(spill_index >= 0) {
+ allocR = (PhysicalReg)spillLogicalReg(spill_index, true);
+ return allocR; //the register is still being used
+ }
+
+ /* spill an entry with the smallest refCount */
+ int baseLeftOver = 0;
+ int index = -1;
+ for(k2 = 0; k2 < num_cand; k2++) {
+ k = candidates[k2];
+ if(k != indexForGlue &&
+ (compileTable[k].physicalReg != PhysicalReg_Null) &&
+ (compileTable[k].physicalType & LowOpndRegType_hard) == 0 && //not hard-coded
+ matchType(type, compileTable[k].physicalType)) {
+ if((index < 0) || (compileTable[k].refCount < baseLeftOver)) {
+ baseLeftOver = compileTable[k].refCount;
+ index = k;
+ }
+ }
+ }
+ if(index < 0) {
+ dumpCompileTable();
+ ALOGE("no register to spill for logical %d %d", reg, type);
+ dvmAbort();
+ }
+ allocR = (PhysicalReg)spillLogicalReg(index, true);
+#ifdef DEBUG_REGALLOC
+ ALOGI("SPILL register used by num %d type %d it is a temporary register with refCount %d",
+ compileTable[index].regNum, compileTable[index].physicalType, compileTable[index].refCount);
+#endif
+ return allocR;
+}
+//!spill a variable to memory, the variable is specified by an index to compileTable
+
+//!If the variable is a temporary, get a spill location that is not in use and spill the content to the spill location;
+//!If updateTable is true, set physicalReg to Null;
+//!Return the physical register that was allocated to the variable
+int spillLogicalReg(int spill_index, bool updateTable) {
+ if((compileTable[spill_index].physicalType & LowOpndRegType_hard) != 0) {
+ ALOGE("can't spill a hard-coded register");
+ dvmAbort();
+ }
+ int physicalReg = compileTable[spill_index].physicalReg;
+ if(!canSpillReg[physicalReg]) {
+#ifdef PRINT_WARNING
+ ALOGW("can't spill register %d", physicalReg);
+#endif
+ //dvmAbort(); //this happens in get_virtual_reg where VR is allocated to the same reg as the hardcoded temporary
+ }
+ if(isVirtualReg(compileTable[spill_index].physicalType)) {
+ //spill back to memory
+ dumpToMem(compileTable[spill_index].regNum,
+ (LowOpndRegType)(compileTable[spill_index].physicalType&MASK_FOR_TYPE),
+ compileTable[spill_index].physicalReg);
+ }
+ else {
+ //update spill_loc_index
+ int k = getSpillIndex(spill_index == indexForGlue,
+ getRegSize(compileTable[spill_index].physicalType));
+ compileTable[spill_index].spill_loc_index = 4*k;
+ if(k >= 0)
+ spillIndexUsed[k] = 1;
+ saveToSpillRegion(getRegSize(compileTable[spill_index].physicalType),
+ compileTable[spill_index].physicalReg, 4*k);
+ }
+ //compileTable[spill_index].physicalReg_prev = compileTable[spill_index].physicalReg;
+#ifdef DEBUG_REGALLOC
+ ALOGI("REGALLOC: SPILL logical reg %d %d with refCount %d allocated to %d",
+ compileTable[spill_index].regNum,
+ compileTable[spill_index].physicalType, compileTable[spill_index].refCount,
+ compileTable[spill_index].physicalReg);
+#endif
+ if(!updateTable) return PhysicalReg_Null;
+
+ int allocR = compileTable[spill_index].physicalReg;
+ compileTable[spill_index].physicalReg = PhysicalReg_Null;
+ return allocR;
+}
+//! load a varible from memory to physical register, the variable is specified with an index to compileTable
+
+//!If the variable is a temporary, load from spill location and set the flag for the spill location to not used
+int unspillLogicalReg(int spill_index, int physicalReg) {
+ //can't un-spill to %eax in afterCall!!!
+ //what if GG VR is allocated to %eax!!!
+ if(isVirtualReg(compileTable[spill_index].physicalType)) {
+ get_virtual_reg_noalloc(compileTable[spill_index].regNum,
+ getRegSize(compileTable[spill_index].physicalType),
+ physicalReg, true);
+ }
+ else {
+ loadFromSpillRegion(getRegSize(compileTable[spill_index].physicalType),
+ physicalReg, compileTable[spill_index].spill_loc_index);
+ spillIndexUsed[compileTable[spill_index].spill_loc_index >> 2] = 0;
+ compileTable[spill_index].spill_loc_index = -1;
+ }
+#ifdef DEBUG_REGALLOC
+ ALOGI("REGALLOC: UNSPILL logical reg %d %d with refCount %d", compileTable[spill_index].regNum,
+ compileTable[spill_index].physicalType, compileTable[spill_index].refCount);
+#endif
+ return PhysicalReg_Null;
+}
+
+//!spill a virtual register to memory
+
+//!if the current value of a VR is constant, write immediate to memory;
+//!if the current value of a VR is in a physical register, call spillLogicalReg to dump content of the physical register to memory;
+//!ifupdateTable is true, set the physical register for VR to Null and decrease reference count of the virtual register
+int spillVirtualReg(int vrNum, LowOpndRegType type, bool updateTable) {
+ int index = searchCompileTable(type | LowOpndRegType_virtual, vrNum);
+ if(index < 0) {
+ ALOGE("can't find VR %d %d in spillVirtualReg", vrNum, type);
+ return -1;
+ }
+ //check whether it is const
+ int value[2];
+ int isConst = isVirtualRegConstant(vrNum, type, value, false); //do not update refCount
+ if(isConst == 1 || isConst == 3) {
+ dumpImmToMem(vrNum, OpndSize_32, value[0]);
+ }
+ if(getRegSize(type) == OpndSize_64 && (isConst == 2 || isConst == 3)) {
+ dumpImmToMem(vrNum+1, OpndSize_32, value[1]);
+ }
+ if(isConst != 3 && compileTable[index].physicalReg != PhysicalReg_Null)
+ spillLogicalReg(index, updateTable);
+ if(updateTable) decreaseRefCount(index);
+ return -1;
+}
+
+//! spill variables that are mapped to physical register (regNum)
+
+//!
+int spillForHardReg(int regNum, int type) {
+ //find an entry that uses the physical register
+ int spill_index = -1;
+ int k;
+ for(k = 0; k < num_compile_entries; k++) {
+ if(k != indexForGlue &&
+ compileTable[k].physicalReg == regNum &&
+ matchType(type, compileTable[k].physicalType)) {
+ spill_index = k;
+ if(compileTable[k].regNum == regNum && compileTable[k].physicalType == type)
+ continue;
+ if(inGetVR_num >= 0 && compileTable[k].regNum == inGetVR_num && compileTable[k].physicalType == (type | LowOpndRegType_virtual))
+ continue;
+#ifdef DEBUG_REGALLOC
+ ALOGI("SPILL logical reg %d %d to free hard-coded reg %d %d",
+ compileTable[spill_index].regNum, compileTable[spill_index].physicalType,
+ regNum, type);
+ if(compileTable[spill_index].physicalType & LowOpndRegType_hard) dumpCompileTable();
+#endif
+ assert(spill_index < COMPILE_TABLE_SIZE);
+ spillLogicalReg(spill_index, true);
+ }
+ }
+ return regNum;
+}
+////////////////////////////////////////////////////////////////
+//! update allocConstraints of the current basic block
+
+//! allocConstraints specify how many times a hardcoded register is used in this basic block
+void updateCurrentBBWithConstraints(PhysicalReg reg) {
+ if(reg > PhysicalReg_EBP) {
+ ALOGE("register %d out of range in updateCurrentBBWithConstraints", reg);
+ }
+ currentBB->allocConstraints[reg].count++;
+}
+//! sort allocConstraints and save the result in allocConstraintsSorted
+
+//! allocConstraints specify how many times a virtual register is linked to a hardcode register
+//! it is updated in getVirtualRegInfo and merged by mergeEntry2
+int sortAllocConstraint(RegAllocConstraint* allocConstraints,
+ RegAllocConstraint* allocConstraintsSorted, bool fromHighToLow) {
+ int ii, jj;
+ int num_sorted = 0;
+ for(jj = 0; jj < 8; jj++) {
+ //figure out where to insert allocConstraints[jj]
+ int count = allocConstraints[jj].count;
+ int regT = allocConstraints[jj].physicalReg;
+ assert(regT < PhysicalReg_Null);
+ int insertIndex = -1;
+ for(ii = 0; ii < num_sorted; ii++) {
+ int regT2 = allocConstraintsSorted[ii].physicalReg;
+ assert(regT2 < PhysicalReg_Null);
+ if(allRegs[regT].isCalleeSaved &&
+ count == allocConstraintsSorted[ii].count) {
+ insertIndex = ii;
+ break;
+ }
+ if((!allRegs[regT].isCalleeSaved) &&
+ count == allocConstraintsSorted[ii].count &&
+ (!allRegs[regT2].isCalleeSaved)) { //skip until found one that is not callee-saved
+ insertIndex = ii;
+ break;
+ }
+ if((fromHighToLow && count > allocConstraintsSorted[ii].count) ||
+ ((!fromHighToLow) && count < allocConstraintsSorted[ii].count)) {
+ insertIndex = ii;
+ break;
+ }
+ }
+ if(insertIndex < 0) {
+ allocConstraintsSorted[num_sorted].physicalReg = (PhysicalReg)regT;
+ allocConstraintsSorted[num_sorted].count = count;
+ num_sorted++;
+ } else {
+ for(ii = num_sorted-1; ii >= insertIndex; ii--) {
+ allocConstraintsSorted[ii+1] = allocConstraintsSorted[ii];
+ }
+ allocConstraintsSorted[insertIndex] = allocConstraints[jj];
+ num_sorted++;
+ }
+ } //for jj
+#ifdef DEBUG_ALLOC_CONSTRAINT
+ for(jj = 0; jj < 8; jj++) {
+ if(allocConstraintsSorted[jj].count > 0)
+ ALOGI("%d: register %d has count %d", jj, allocConstraintsSorted[jj].physicalReg, allocConstraintsSorted[jj].count);
+ }
+#endif
+ return 0;
+}
+//! find the entry for a given virtual register in compileTable
+
+//!
+int findVirtualRegInTable(u2 vA, LowOpndRegType type, bool printError) {
+ int k = searchCompileTable(type | LowOpndRegType_virtual, vA);
+ if(k < 0 && printError) {
+ ALOGE("findVirtualRegInTable virtual register %d type %d", vA, type);
+ dvmAbort();
+ }
+ return k;
+}
+
+//! check whether a virtual register is constant
+
+//! the value of the constant is stored in valuePtr; if updateRefCount is true & the VR is constant, reference count for the VR will be reduced by 1
+int isVirtualRegConstant(int regNum, LowOpndRegType type, int* valuePtr, bool updateRefCount) {
+
+ OpndSize size = getRegSize(type);
+ int k;
+ int indexL = -1;
+ int indexH = -1;
+ for(k = 0; k < num_const_vr; k++) {
+#ifdef DEBUG_CONST
+ ALOGI("constVRTable VR %d isConst %d value %x", constVRTable[k].regNum, constVRTable[k].isConst, constVRTable[k].value);
+#endif
+ if(constVRTable[k].regNum == regNum) {
+ indexL = k;
+ continue;
+ }
+ if(constVRTable[k].regNum == regNum + 1 && size == OpndSize_64) {
+ indexH = k;
+ continue;
+ }
+ }
+ bool isConstL = false;
+ bool isConstH = false;
+ if(indexL >= 0) {
+ isConstL = constVRTable[indexL].isConst;
+ }
+ if(size == OpndSize_64 && indexH >= 0) {
+ isConstH = constVRTable[indexH].isConst;
+ }
+
+ if((isConstL || isConstH)) {
+ if(size == OpndSize_64 && isConstH)
+ valuePtr[1] = constVRTable[indexH].value;
+ if(isConstL)
+ *valuePtr = constVRTable[indexL].value;
+ }
+ if((isConstL && size == OpndSize_32) || (isConstL && isConstH)) {
+ if(updateRefCount) {
+ int indexOrig = searchCompileTable(type | LowOpndRegType_virtual, regNum);
+ if(indexOrig < 0) ALOGE("can't find VR in isVirtualRegConstant num %d type %d", regNum, type);
+ decreaseRefCount(indexOrig);
+ }
+#ifdef DEBUG_CONST
+ ALOGI("VR %d %d is const case", regNum, type);
+#endif
+ return 3;
+ }
+ if(size == OpndSize_32) return 0;
+ if(isConstL) return 1;
+ if(isConstH) return 2;
+ return 0;
+}
+
+//!update RegAccessType of virtual register vB given RegAccessType of vA
+
+//!RegAccessType can be D, L, H
+//!D means full definition, L means only lower-half is defined, H means only higher half is defined
+//!we say a VR has no exposed usage in a basic block if the accessType is D or DU
+//!we say a VR has exposed usage in a basic block if the accessType is not D nor DU
+//!we say a VR has exposed usage in other basic blocks (hasOtherExposedUsage) if
+//! there exists another basic block where VR has exposed usage in that basic block
+//!A can be U, D, L, H, UD, UL, UH, DU, LU, HU (merged result)
+//!B can be U, D, UD, DU (an entry for the current bytecode)
+//!input isAPartiallyOverlapB can be any value between -1 to 6
+//!if A is xmm: gp B lower half of A, (isAPartiallyOverlapB is 1)
+//! gp B higher half of A, (isAPartiallyOverlapB is 2)
+//! lower half of A covers the higher half of xmm B (isAPartiallyOverlapB is 4)
+//! higher half of A covers the lower half of xmm B (isAPartiallyOverlapB is 3)
+//!if A is gp: A covers the lower half of xmm B, (isAPartiallyOverlapB is 5)
+//! A covers the higher half of xmm B (isAPartiallyOverlapB is 6)
+RegAccessType updateAccess1(RegAccessType A, OverlapCase isAPartiallyOverlapB) {
+ if(A == REGACCESS_D || A == REGACCESS_DU || A == REGACCESS_UD) {
+ if(isAPartiallyOverlapB == OVERLAP_ALIGN) return REGACCESS_D;
+ if(isAPartiallyOverlapB == OVERLAP_B_IS_LOW_OF_A || isAPartiallyOverlapB == OVERLAP_B_IS_HIGH_OF_A)
+ return REGACCESS_D;
+ if(isAPartiallyOverlapB == OVERLAP_LOW_OF_A_IS_HIGH_OF_B || isAPartiallyOverlapB == OVERLAP_A_IS_LOW_OF_B)
+ return REGACCESS_L;
+ return REGACCESS_H;
+ }
+ if(A == REGACCESS_L || A == REGACCESS_LU || A == REGACCESS_UL) {
+ if(isAPartiallyOverlapB == OVERLAP_ALIGN || isAPartiallyOverlapB == OVERLAP_A_IS_LOW_OF_B)
+ return REGACCESS_L;
+ if(isAPartiallyOverlapB == OVERLAP_B_IS_LOW_OF_A) return REGACCESS_D;
+ if(isAPartiallyOverlapB == OVERLAP_B_IS_HIGH_OF_A || isAPartiallyOverlapB == OVERLAP_LOW_OF_A_IS_HIGH_OF_B)
+ return REGACCESS_N;
+ if(isAPartiallyOverlapB == OVERLAP_HIGH_OF_A_IS_LOW_OF_B || isAPartiallyOverlapB == OVERLAP_A_IS_HIGH_OF_B)
+ return REGACCESS_H;
+ }
+ if(A == REGACCESS_H || A == REGACCESS_HU || A == REGACCESS_UH) {
+ if(isAPartiallyOverlapB == OVERLAP_ALIGN || isAPartiallyOverlapB == OVERLAP_A_IS_HIGH_OF_B)
+ return REGACCESS_H;
+ if(isAPartiallyOverlapB == OVERLAP_B_IS_LOW_OF_A || isAPartiallyOverlapB == OVERLAP_HIGH_OF_A_IS_LOW_OF_B)
+ return REGACCESS_N;
+ if(isAPartiallyOverlapB == OVERLAP_B_IS_HIGH_OF_A) return REGACCESS_D;
+ if(isAPartiallyOverlapB == OVERLAP_LOW_OF_A_IS_HIGH_OF_B || isAPartiallyOverlapB == OVERLAP_A_IS_LOW_OF_B)
+ return REGACCESS_L;
+ }
+ return REGACCESS_N;
+}
+//! merge RegAccessType C1 with RegAccessType C2
+
+//!C can be N,L,H,D
+RegAccessType updateAccess2(RegAccessType C1, RegAccessType C2) {
+ if(C1 == REGACCESS_D || C2 == REGACCESS_D) return REGACCESS_D;
+ if(C1 == REGACCESS_N) return C2;
+ if(C2 == REGACCESS_N) return C1;
+ if(C1 == REGACCESS_L && C2 == REGACCESS_H) return REGACCESS_D;
+ if(C1 == REGACCESS_H && C2 == REGACCESS_L) return REGACCESS_D;
+ return C1;
+}
+//! merge RegAccessType C with RegAccessType B
+
+//!C can be N,L,H,D
+//!B can be U, D, UD, DU
+RegAccessType updateAccess3(RegAccessType C, RegAccessType B) {
+ if(B == REGACCESS_D || B == REGACCESS_DU) return B; //no exposed usage
+ if(B == REGACCESS_U || B == REGACCESS_UD) {
+ if(C == REGACCESS_N) return B;
+ if(C == REGACCESS_L) return REGACCESS_LU;
+ if(C == REGACCESS_H) return REGACCESS_HU;
+ if(C == REGACCESS_D) return REGACCESS_DU;
+ }
+ return B;
+}
+//! merge RegAccessType A with RegAccessType B
+
+//!argument isBPartiallyOverlapA can be any value between -1 and 2
+//!0 means fully overlapping, 1 means B is the lower half, 2 means B is the higher half
+RegAccessType mergeAccess2(RegAccessType A, RegAccessType B, OverlapCase isBPartiallyOverlapA) {
+ if(A == REGACCESS_UD || A == REGACCESS_UL || A == REGACCESS_UH ||
+ A == REGACCESS_DU || A == REGACCESS_LU || A == REGACCESS_HU) return A;
+ if(A == REGACCESS_D) {
+ if(B == REGACCESS_D) return REGACCESS_D;
+ if(B == REGACCESS_U) return REGACCESS_DU;
+ if(B == REGACCESS_UD) return REGACCESS_DU;
+ if(B == REGACCESS_DU) return B;
+ }
+ if(A == REGACCESS_U) {
+ if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_UL;
+ if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_UH;
+ if(B == REGACCESS_D && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_UD;
+ if(B == REGACCESS_U) return A;
+ if(B == REGACCESS_UD && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_UL;
+ if(B == REGACCESS_UD && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_UH;
+ if(B == REGACCESS_UD && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_UD;
+ if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_UL;
+ if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_UH;
+ if(B == REGACCESS_DU && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_UD;
+ }
+ if(A == REGACCESS_L) {
+ if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_L;
+ if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_D;
+ if(B == REGACCESS_D && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_D;
+ if(B == REGACCESS_U) return REGACCESS_LU;
+ if(B == REGACCESS_UD) return REGACCESS_LU;
+ if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_LU;
+ if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_DU;
+ if(B == REGACCESS_DU && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_DU;
+ }
+ if(A == REGACCESS_H) {
+ if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_D;
+ if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_H;
+ if(B == REGACCESS_D && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_D;
+ if(B == REGACCESS_U) return REGACCESS_HU;
+ if(B == REGACCESS_UD) return REGACCESS_HU;
+ if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_DU;
+ if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_HU;
+ if(B == REGACCESS_DU && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_DU;
+ }
+ return REGACCESS_N;
+}
+
+//!determines which part of a use is from a given definition
+
+//!reachingDefLive tells us which part of the def is live at this point
+//!isDefPartiallyOverlapUse can be any value between -1 and 2
+RegAccessType setAccessTypeOfUse(OverlapCase isDefPartiallyOverlapUse, RegAccessType reachingDefLive) {
+ if(isDefPartiallyOverlapUse == OVERLAP_B_COVER_A)
+ return reachingDefLive;
+ if(isDefPartiallyOverlapUse == OVERLAP_B_COVER_LOW_OF_A) { //def covers the low half of use
+ return REGACCESS_L;
+ }
+ if(isDefPartiallyOverlapUse == OVERLAP_B_COVER_HIGH_OF_A) {
+ return REGACCESS_H;
+ }
+ return REGACCESS_N;
+}
+
+//! search currentBB->defUseTable to find a def for regNum at offsetPC
+
+//!
+DefUsePair* searchDefUseTable(int offsetPC, int regNum, LowOpndRegType pType) {
+ DefUsePair* ptr = currentBB->defUseTable;
+ while(ptr != NULL) {
+ if(ptr->def.offsetPC == offsetPC &&
+ ptr->def.regNum == regNum &&
+ ptr->def.physicalType == pType) {
+ return ptr;
+ }
+ ptr = ptr->next;
+ }
+ return NULL;
+}
+void printDefUseTable() {
+ ALOGI("PRINT defUseTable --------");
+ DefUsePair* ptr = currentBB->defUseTable;
+ while(ptr != NULL) {
+ ALOGI(" def @ %x of VR %d %d has %d uses", ptr->def.offsetPC,
+ ptr->def.regNum, ptr->def.physicalType,
+ ptr->num_uses);
+ DefOrUseLink* ptr2 = ptr->uses;
+ while(ptr2 != NULL) {
+ ALOGI(" use @ %x of VR %d %d accessType %d", ptr2->offsetPC,
+ ptr2->regNum,
+ ptr2->physicalType,
+ ptr2->accessType);
+ ptr2 = ptr2->next;
+ }
+ ptr = ptr->next;
+ }
+}
+//! when a VR is used, check whether a transfer from memory to XMM is necessary
+
+//!
+int updateVRAtUse(int reg, LowOpndRegType pType, int regAll) {
+ int k;
+ for(k = 0; k < currentBB->num_xfer_points; k++) {
+ if(currentBB->xferPoints[k].offsetPC == offsetPC &&
+ currentBB->xferPoints[k].xtype == XFER_MEM_TO_XMM &&
+ currentBB->xferPoints[k].regNum == reg &&
+ currentBB->xferPoints[k].physicalType == pType) {
+#ifdef DEBUG_XFER_POINTS
+ ALOGI("XFER from memory to xmm %d", reg);
+#endif
+ move_mem_to_reg_noalloc(OpndSize_64,
+ 4*currentBB->xferPoints[k].regNum, PhysicalReg_FP, true,
+ MemoryAccess_VR, currentBB->xferPoints[k].regNum,
+ regAll, true);
+ }
+ }
+ return 0;
+}
+///////////////////////////////////////////////////////////////////////////////
+// DEAD/USELESS STATEMENT ELMINATION
+// bytecodes can be removed if a bytecode has no side effect and the defs are not used
+// this optimization is guarded with DSE_OPT
+// currently, this optimization is not on, since it does not provide observable performance improvement
+// and it increases compilation time
+
+/* we remove a maximal of 40 bytecodes within a single basic block */
+#define MAX_NUM_DEAD_PC_IN_BB 40
+int deadPCs[MAX_NUM_DEAD_PC_IN_BB];
+int num_dead_pc = 0;
+//! collect all PCs that can be removed
+
+//! traverse each byte code in the current basic block and check whether it can be removed, if yes, update deadPCs
+void getDeadStmts() {
+ BasicBlock_O1* bb = currentBB;
+ int k;
+ num_dead_pc = 0;
+ //traverse each bytecode in the basic block
+ //update offsetPC, rPC & inst
+ u2* rPC_start = (u2*)currentMethod->insns;
+ MIR* mir;
+ for(mir = bb->jitBasicBlock->firstMIRInsn; mir; mir = mir->next) {
+ offsetPC = mir->seqNum;
+ rPC = rPC_start + mir->offset;
+ if(mir->dalvikInsn.opcode >= kNumPackedOpcodes) continue;
+#ifdef DEBUG_DSE
+ ALOGI("DSE: offsetPC %x", offsetPC);
+#endif
+ inst = FETCH(0);
+ bool isDeadStmt = true;
+ getVirtualRegInfo(infoByteCode);
+ u2 inst_op = INST_INST(inst);
+ //skip bytecodes with side effect
+ if(inst_op != OP_CONST_STRING && inst_op != OP_CONST_STRING_JUMBO &&
+ inst_op != OP_MOVE && inst_op != OP_MOVE_OBJECT &&
+ inst_op != OP_MOVE_FROM16 && inst_op != OP_MOVE_OBJECT_FROM16 &&
+ inst_op != OP_MOVE_16 && inst_op != OP_CONST_CLASS &&
+ inst_op != OP_MOVE_OBJECT_16 && inst_op != OP_MOVE_WIDE &&
+ inst_op != OP_MOVE_WIDE_FROM16 && inst_op != OP_MOVE_WIDE_16 &&
+ inst_op != OP_MOVE_RESULT && inst_op != OP_MOVE_RESULT_OBJECT) {
+ continue;
+ }
+ //some statements do not define any VR!!!
+ int num_defs = 0;
+ for(k = 0; k < num_regs_per_bytecode; k++) {
+ if(infoByteCode[k].accessType == REGACCESS_D ||
+ infoByteCode[k].accessType == REGACCESS_UD ||
+ infoByteCode[k].accessType == REGACCESS_DU) { //search defUseTable
+ num_defs++;
+ DefUsePair* indexT = searchDefUseTable(offsetPC, infoByteCode[k].regNum, infoByteCode[k].physicalType);
+ if(indexT == NULL) {
+ ALOGE("def at %x of VR %d %d not in table",
+ offsetPC, infoByteCode[k].regNum, infoByteCode[k].physicalType);
+ return;
+ }
+ if(indexT->num_uses > 0) {
+ isDeadStmt = false;
+ break;
+ } else {
+#ifdef DEBUG_DSE
+ ALOGI("DSE: num_uses is %d for def at %d for VR %d %d", indexT->num_uses,
+ offsetPC, infoByteCode[k].regNum, infoByteCode[k].physicalType);
+#endif
+ }
+ }
+ } //for k
+ if(num_defs == 0) isDeadStmt = false;
+ if(isDeadStmt && num_dead_pc < MAX_NUM_DEAD_PC_IN_BB) {
+#ifdef DEBUG_DSE
+ ALOGI("DSE: stmt at %x is dead", offsetPC);
+#endif
+ deadPCs[num_dead_pc++] = offsetPC;
+ }
+ } //for offsetPC
+#ifdef DEBUG_DSE
+ ALOGI("Dead Stmts: ");
+ for(k = 0; k < num_dead_pc; k++) ALOGI("%x ", deadPCs[k]);
+ ALOGI("");
+#endif
+}
+//! entry point to remove dead statements
+
+//! recursively call getDeadStmts and remove uses in defUseTable that are from a dead PC
+//! until there is no change to number of dead PCs
+void removeDeadDefs() {
+ int k;
+ int deadPCs_2[MAX_NUM_DEAD_PC_IN_BB];
+ int num_dead_pc_2 = 0;
+ getDeadStmts();
+ if(num_dead_pc == 0) return;
+ DefUsePair* ptr = NULL;
+ DefOrUseLink* ptrUse = NULL;
+ DefOrUseLink* ptrUse_prev = NULL;
+ while(true) {
+ //check all the uses in defUseTable and remove any use that is from a dead PC
+ ptr = currentBB->defUseTable;
+ while(ptr != NULL) {
+ int k3;
+ ptrUse = ptr->uses;
+ ptrUse_prev = NULL;
+ while(ptrUse != NULL) {
+ bool isIn = false;
+ for(k3 = 0; k3 < num_dead_pc; k3++) {
+ if(ptrUse->offsetPC == deadPCs[k3]) {
+ isIn = true;
+ break;
+ }
+ }//k3
+ if(!isIn) {
+ ptrUse_prev = ptrUse;
+ ptrUse = ptrUse->next; //next use
+ }
+ else {
+ //go to next use and remove ptrUse
+#ifdef DEBUG_DSE
+ ALOGI("DSE: remove usage at offsetPC %d reached by def at %d", ptrUse->offsetPC,
+ ptr->def.offsetPC);
+#endif
+ DefOrUseLink* nextP = ptrUse->next;
+ if(ptrUse == ptr->useTail) ptr->useTail = ptrUse_prev;
+ free(ptrUse);
+ if(ptrUse_prev == NULL) {
+ ptr->uses = nextP;
+ } else {
+ ptrUse_prev->next = nextP;
+ }
+ ptrUse = nextP; //do not update ptrUse_prev
+ ptr->num_uses--;
+ }
+ }//while ptrUse
+ ptr = ptr->next;
+ }//while ptr
+ //save deadPCs in deadPCs_2
+ num_dead_pc_2 = num_dead_pc;
+ for(k = 0; k < num_dead_pc_2; k++)
+ deadPCs_2[k] = deadPCs[k];
+ //update deadPCs
+ getDeadStmts();
+ //if no change to number of dead PCs, break out of the while loop
+ if(num_dead_pc_2 == num_dead_pc) break;
+ }//while
+#ifdef DEBUG_DSE
+ ALOGI("DSE: DEAD STMTS: ");
+ for(k = 0; k < num_dead_pc; k++) {
+ ALOGI("%d ", deadPCs[k]);
+ }
+ ALOGI("");
+#endif
+}
+/////////////////////////////////////////////////////////////
+//!search memVRTable for a given virtual register
+
+//!
+int searchMemTable(int regNum) {
+ int k;
+ for(k = 0; k < num_memory_vr; k++) {
+ if(memVRTable[k].regNum == regNum) {
+ return k;
+ }
+ }
+ ALOGW("in searchMemTable can't find VR %d num_memory_vr %d", regNum, num_memory_vr);
+ return -1;
+}
+/////////////////////////////////////////////////////////////////////////
+// A VR is already in memory && NULL CHECK
+//!check whether the latest content of a VR is in memory
+
+//!
+bool isInMemory(int regNum, OpndSize size) {
+ int indexL = searchMemTable(regNum);
+ int indexH = -1;
+ if(size == OpndSize_64) indexH = searchMemTable(regNum+1);
+ if(indexL < 0) return false;
+ if(size == OpndSize_64 && indexH < 0) return false;
+ if(!memVRTable[indexL].inMemory) return false;
+ if(size == OpndSize_64 && (!memVRTable[indexH].inMemory)) return false;
+ return true;
+}
+//!set field inMemory of memVRTable to true
+
+//!
+void setVRToMemory(int regNum, OpndSize size) {
+ int indexL = searchMemTable(regNum);
+ int indexH = -1;
+ if(size == OpndSize_64) indexH = searchMemTable(regNum+1);
+ if(indexL < 0) {
+ ALOGE("VR %d not in memVRTable", regNum);
+ return;
+ }
+ memVRTable[indexL].inMemory = true;
+ if(size == OpndSize_64) {
+ if(indexH < 0) {
+ ALOGE("VR %d not in memVRTable", regNum+1);
+ return;
+ }
+ memVRTable[indexH].inMemory = true;
+ }
+}
+//! check whether null check for a VR is performed previously
+
+//!
+bool isVRNullCheck(int regNum, OpndSize size) {
+ if(size != OpndSize_32) {
+ ALOGE("isVRNullCheck size should be 32");
+ dvmAbort();
+ }
+ int indexL = searchMemTable(regNum);
+ if(indexL < 0) {
+ ALOGE("VR %d not in memVRTable", regNum);
+ return false;
+ }
+ return memVRTable[indexL].nullCheckDone;
+}
+bool isVRBoundCheck(int vr_array, int vr_index) {
+ int indexL = searchMemTable(vr_array);
+ if(indexL < 0) {
+ ALOGE("isVRBoundCheck: VR %d not in memVRTable", vr_array);
+ return false;
+ }
+ if(memVRTable[indexL].boundCheck.indexVR == vr_index)
+ return memVRTable[indexL].boundCheck.checkDone;
+ return false;
+}
+//! set nullCheckDone in memVRTable to true
+
+//!
+void setVRNullCheck(int regNum, OpndSize size) {
+ if(size != OpndSize_32) {
+ ALOGE("setVRNullCheck size should be 32");
+ dvmAbort();
+ }
+ int indexL = searchMemTable(regNum);
+ if(indexL < 0) {
+ ALOGE("VR %d not in memVRTable", regNum);
+ return;
+ }
+ memVRTable[indexL].nullCheckDone = true;
+}
+void setVRBoundCheck(int vr_array, int vr_index) {
+ int indexL = searchMemTable(vr_array);
+ if(indexL < 0) {
+ ALOGE("setVRBoundCheck: VR %d not in memVRTable", vr_array);
+ return;
+ }
+ memVRTable[indexL].boundCheck.indexVR = vr_index;
+ memVRTable[indexL].boundCheck.checkDone = true;
+}
+void clearVRBoundCheck(int regNum, OpndSize size) {
+ int k;
+ for(k = 0; k < num_memory_vr; k++) {
+ if(memVRTable[k].regNum == regNum ||
+ (size == OpndSize_64 && memVRTable[k].regNum == regNum+1)) {
+ memVRTable[k].boundCheck.checkDone = false;
+ }
+ if(memVRTable[k].boundCheck.indexVR == regNum ||
+ (size == OpndSize_64 && memVRTable[k].boundCheck.indexVR == regNum+1)) {
+ memVRTable[k].boundCheck.checkDone = false;
+ }
+ }
+}
+//! set inMemory of memVRTable to false
+
+//!
+void clearVRToMemory(int regNum, OpndSize size) {
+ int indexL = searchMemTable(regNum);
+ int indexH = -1;
+ if(size == OpndSize_64) indexH = searchMemTable(regNum+1);
+ if(indexL >= 0) {
+ memVRTable[indexL].inMemory = false;
+ }
+ if(size == OpndSize_64 && indexH >= 0) {
+ memVRTable[indexH].inMemory = false;
+ }
+}
+//! set nullCheckDone of memVRTable to false
+
+//!
+void clearVRNullCheck(int regNum, OpndSize size) {
+ int indexL = searchMemTable(regNum);
+ int indexH = -1;
+ if(size == OpndSize_64) indexH = searchMemTable(regNum+1);
+ if(indexL >= 0) {
+ memVRTable[indexL].nullCheckDone = false;
+ }
+ if(size == OpndSize_64 && indexH >= 0) {
+ memVRTable[indexH].nullCheckDone = false;
+ }
+}
+
+//! Extend Virtual Register life
+
+//! Requests that the life of a specific virtual register be extended. This ensures
+//! that its mapping to a physical register won't be canceled while the extension
+//! request is valid. NOTE: This does not support 64-bit values (when two adjacent
+//! VRs are used)
+//! @see cancelVRFreeDelayRequest
+//! @see getVRFreeDelayRequested
+//! @see VRFreeDelayFlags
+//! @param regNum is the VR number
+//! @param reason explains why freeing must be delayed. A single or combination
+//! of VRFreeDelayFlags should be used.
+//! @return negative value if request failed
+int requestVRFreeDelay(int regNum, u4 reason) {
+ //TODO Add 64-bit operand support when needed
+ int indexL = searchMemTable(regNum);
+ if(indexL >= 0) {
+ memVRTable[indexL].delayFreeFlags |= reason;
+ } else {
+ ALOGE("requestVRFreeDelay: VR %d not in memVRTable", regNum);
+ }
+ return indexL;
+}
+
+//! Cancel request for virtual register life extension
+
+//! Cancels any outstanding requests to extended liveness of VR. Additionally,
+//! this ensures that if the VR is no longer life after this point, it will
+//! no longer be associated with a physical register which can then be reused.
+//! NOTE: This does not support 64-bit values (when two adjacent VRs are used)
+//! @see requestVRFreeDelay
+//! @see getVRFreeDelayRequested
+//! @see VRFreeDelayFlags
+//! @param regNum is the VR number
+//! @param reason explains what freeing delay request should be canceled. A single
+//! or combination of VRFreeDelayFlags should be used.
+void cancelVRFreeDelayRequest(int regNum, u4 reason) {
+ //TODO Add 64-bit operand support when needed
+ bool needCallToFreeReg = false;
+ int indexL = searchMemTable(regNum);
+ if(indexL >= 0) {
+ if((memVRTable[indexL].delayFreeFlags & reason) != VRDELAY_NONE) { // don't cancel delay if it wasn't requested
+ memVRTable[indexL].delayFreeFlags ^= reason; // only cancel this particular reason, not all others
+ if(memVRTable[indexL].delayFreeFlags == VRDELAY_NONE)
+ needCallToFreeReg = true; // freeReg might want to free this VR now if there is no longer a valid delay
+ }
+ }
+ if(needCallToFreeReg)
+ freeReg(true);
+}
+
+//! Gets status of virtual register free delay request
+
+//! Finds out if there was a delay request for freeing this VR.
+//! NOTE: This does not support 64-bit values (when two adjacent VRs are used)
+//! @see requestVRFreeDelay
+//! @see cancelVRFreeDelayRequest
+//! @param regNum is the VR number
+//! @return true if VR has an active delay request
+bool getVRFreeDelayRequested(int regNum) {
+ //TODO Add 64-bit operand support when needed
+ int indexL = searchMemTable(regNum);
+ if(indexL >= 0) {
+ if(memVRTable[indexL].delayFreeFlags != VRDELAY_NONE)
+ return true;
+ return false;
+ }
+ return false;
+}
+
+//! find the basic block that a bytecode is in
+
+//!
+BasicBlock_O1* findForOffset(int offset) {
+ int k;
+ for(k = 0; k < num_bbs_for_method; k++) {
+ if(method_bbs_sorted[k]->pc_start <= offset && method_bbs_sorted[k]->pc_end > offset)
+ return method_bbs_sorted[k];
+ }
+ return NULL;
+}
+void dump_CFG(Method* method);
+
+int current_bc_size = -1;
+
+//! check whether a virtual register is used in a basic block
+
+//!
+bool isUsedInBB(int regNum, int type, BasicBlock_O1* bb) {
+ int k;
+ for(k = 0; k < bb->num_regs; k++) {
+ if(bb->infoBasicBlock[k].physicalType == (type&MASK_FOR_TYPE) && bb->infoBasicBlock[k].regNum == regNum)
+ return true;
+ }
+ return false;
+}
+//! return the index to infoBasicBlock for a given virtual register
+
+//! return -1 if not found
+int searchVirtualInfoOfBB(LowOpndRegType type, int regNum, BasicBlock_O1* bb) {
+ int k;
+ for(k = 0; k < bb->num_regs; k++) {
+ if(bb->infoBasicBlock[k].physicalType == type && bb->infoBasicBlock[k].regNum == regNum)
+ return k;
+ }
+ return -1;
+}
+//! return the index to compileTable for a given virtual register
+
+//! return -1 if not found
+int searchCompileTable(int type, int regNum) { //returns the index
+ int k;
+ for(k = 0; k < num_compile_entries; k++) {
+ if(compileTable[k].physicalType == type && compileTable[k].regNum == regNum)
+ return k;
+ }
+ return -1;
+}
+//!check whether a physical register for a variable with typeA will work for another variable with typeB
+
+//!Type LowOpndRegType_ss is compatible with type LowOpndRegType_xmm
+bool matchType(int typeA, int typeB) {
+ if((typeA & MASK_FOR_TYPE) == (typeB & MASK_FOR_TYPE)) return true;
+ if((typeA & MASK_FOR_TYPE) == LowOpndRegType_ss &&
+ (typeB & MASK_FOR_TYPE) == LowOpndRegType_xmm) return true;
+ if((typeA & MASK_FOR_TYPE) == LowOpndRegType_xmm &&
+ (typeB & MASK_FOR_TYPE) == LowOpndRegType_ss) return true;
+ return false;
+}
+//!check whether a virtual register is used in the current bytecode
+
+//!
+bool isUsedInByteCode(int regNum, int type) {
+ getVirtualRegInfo(infoByteCode);
+ int k;
+ for(k = 0; k < num_regs_per_bytecode; k++) {
+ if(infoByteCode[k].physicalType == (type&MASK_FOR_TYPE) && infoByteCode[k].regNum == regNum)
+ return true;
+ }
+ return false;
+}
+//! obsolete
+bool defineFirst(int atype) {
+ if(atype == REGACCESS_D || atype == REGACCESS_L || atype == REGACCESS_H || atype == REGACCESS_DU)
+ return true;
+ return false;
+}
+//!check whether a virtual register is updated in a basic block
+
+//!
+bool notUpdated(RegAccessType atype) {
+ if(atype == REGACCESS_U) return true;
+ return false;
+}
+//!check whether a virtual register has exposed usage within a given basic block
+
+//!
+bool hasExposedUsage2(BasicBlock_O1* bb, int index) {
+ RegAccessType atype = bb->infoBasicBlock[index].accessType;
+ if(atype == REGACCESS_D || atype == REGACCESS_L || atype == REGACCESS_H || atype == REGACCESS_DU)
+ return false;
+ return true;
+}
+//! return the spill location that is not used
+
+//!
+int getSpillIndex(bool isGLUE, OpndSize size) {
+ if(isGLUE) return 0;
+ int k;
+ for(k = 1; k <= MAX_SPILL_JIT_IA-1; k++) {
+ if(size == OpndSize_64) {
+ if(k < MAX_SPILL_JIT_IA-1 && spillIndexUsed[k] == 0 && spillIndexUsed[k+1] == 0)
+ return k;
+ }
+ else if(spillIndexUsed[k] == 0) {
+ return k;
+ }
+ }
+ ALOGE("can't find spill position in spillLogicalReg");
+ return -1;
+}
+//!this is called before generating a native code, it sets entries in array canSpillReg to true
+
+//!startNativeCode must be paired with endNativeCode
+void startNativeCode(int vr_num, int vr_type) {
+ int k;
+ for(k = 0; k < PhysicalReg_Null; k++) {
+ canSpillReg[k] = true;
+ }
+ inGetVR_num = vr_num;
+ inGetVR_type = vr_type;
+}
+//! called right after generating a native code
+
+//!It sets entries in array canSpillReg to true and reset inGetVR_num to -1
+void endNativeCode() {
+ int k;
+ for(k = 0; k < PhysicalReg_Null; k++) {
+ canSpillReg[k] = true;
+ }
+ inGetVR_num = -1;
+}
+//! set canSpillReg[physicalReg] to false
+
+//!
+void donotSpillReg(int physicalReg) {
+ canSpillReg[physicalReg] = false;
+}
+//! set canSpillReg[physicalReg] to true
+
+//!
+void doSpillReg(int physicalReg) {
+ canSpillReg[physicalReg] = true;
+}
+//! touch hardcoded register %ecx and reduce its reference count
+
+//!
+int touchEcx() {
+ //registerAlloc will spill logical reg that is mapped to ecx
+ //registerAlloc will reduce refCount
+ registerAlloc(LowOpndRegType_gp, PhysicalReg_ECX, true, true);
+ return 0;
+}
+//! touch hardcoded register %eax and reduce its reference count
+
+//!
+int touchEax() {
+ registerAlloc(LowOpndRegType_gp, PhysicalReg_EAX, true, true);
+ return 0;
+}
+int touchEsi() {
+ registerAlloc(LowOpndRegType_gp, PhysicalReg_ESI, true, true);
+ return 0;
+}
+int touchXmm1() {
+ registerAlloc(LowOpndRegType_xmm, XMM_1, true, true);
+ return 0;
+}
+int touchEbx() {
+ registerAlloc(LowOpndRegType_gp, PhysicalReg_EBX, true, true);
+ return 0;
+}
+
+//! touch hardcoded register %edx and reduce its reference count
+
+//!
+int touchEdx() {
+ registerAlloc(LowOpndRegType_gp, PhysicalReg_EDX, true, true);
+ return 0;
+}
+
+#ifdef HACK_FOR_DEBUG
+//for debugging purpose, instructions are added at a certain place
+bool hacked = false;
+void hackBug() {
+ if(!hacked && iget_obj_inst == 13) {
+#if 0
+ move_reg_to_reg_noalloc(OpndSize_32, PhysicalReg_EBX, true, PhysicalReg_ECX, true);
+ //move from ebx to ecx & update compileTable for v3
+ int tIndex = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_gp, 3);
+ if(tIndex < 0) ALOGE("hack can't find VR3");
+ compileTable[tIndex].physicalReg = PhysicalReg_ECX;
+#else
+ move_reg_to_mem_noalloc(OpndSize_32, PhysicalReg_EBX, true, 12, PhysicalReg_FP, true);
+#endif
+ }
+}
+void hackBug2() {
+ if(!hacked && iget_obj_inst == 13) {
+ dump_imm_mem_noalloc(Mnemonic_MOV, OpndSize_32, 0, 12, PhysicalReg_FP, true);
+ hacked = true;
+ }
+}
+#endif
+
+//! this function is called before calling a helper function or a vm function
+int beforeCall(const char* target) { //spill all live registers
+ if(currentBB == NULL) return -1;
+
+ /* special case for ncgGetEIP: this function only updates %edx */
+ if(!strcmp(target, "ncgGetEIP")) {
+ touchEdx();
+ return -1;
+ }
+
+ /* these functions use %eax for the return value */
+ if((!strcmp(target, "dvmInstanceofNonTrivial")) ||
+ (!strcmp(target, "dvmUnlockObject")) ||
+ (!strcmp(target, "dvmAllocObject")) ||
+ (!strcmp(target, "dvmAllocArrayByClass")) ||
+ (!strcmp(target, "dvmAllocPrimitiveArray")) ||
+ (!strcmp(target, "dvmInterpHandleFillArrayData")) ||
+ (!strcmp(target, "dvmFindInterfaceMethodInCache2")) ||
+ (!strcmp(target, "dvmNcgHandlePackedSwitch")) ||
+ (!strcmp(target, "dvmNcgHandleSparseSwitch")) ||
+ (!strcmp(target, "dvmCanPutArrayElement")) ||
+ (!strcmp(target, "moddi3")) || (!strcmp(target, "divdi3")) ||
+ (!strcmp(target, "execute_inline"))
+ || (!strcmp(target, "dvmJitToPatchPredictedChain"))
+ || (!strcmp(target, "dvmJitHandlePackedSwitch"))
+ || (!strcmp(target, "dvmJitHandleSparseSwitch"))
+ ) {
+ touchEax();
+ }
+
+ //these two functions also use %edx for the return value
+ if((!strcmp(target, "moddi3")) || (!strcmp(target, "divdi3"))) {
+ touchEdx();
+ }
+ if((!strcmp(target, ".new_instance_helper"))) {
+ touchEsi(); touchEax();
+ }
+#if defined(ENABLE_TRACING)
+ if((!strcmp(target, "common_periodicChecks4"))) {
+ touchEdx();
+ }
+#endif
+ if((!strcmp(target, ".const_string_helper"))) {
+ touchEcx(); touchEax();
+ }
+ if((!strcmp(target, ".check_cast_helper"))) {
+ touchEbx(); touchEsi();
+ }
+ if((!strcmp(target, ".instance_of_helper"))) {
+ touchEbx(); touchEsi(); touchEcx();
+ }
+ if((!strcmp(target, ".monitor_enter_helper"))) {
+ touchEbx();
+ }
+ if((!strcmp(target, ".monitor_exit_helper"))) {
+ touchEbx();
+ }
+ if((!strcmp(target, ".aget_wide_helper"))) {
+ touchEbx(); touchEcx(); touchXmm1();
+ }
+ if((!strcmp(target, ".aget_helper")) || (!strcmp(target, ".aget_char_helper")) ||
+ (!strcmp(target, ".aget_short_helper")) || (!strcmp(target, ".aget_bool_helper")) ||
+ (!strcmp(target, ".aget_byte_helper"))) {
+ touchEbx(); touchEcx(); touchEdx();
+ }
+ if((!strcmp(target, ".aput_helper")) || (!strcmp(target, ".aput_char_helper")) ||
+ (!strcmp(target, ".aput_short_helper")) || (!strcmp(target, ".aput_bool_helper")) ||
+ (!strcmp(target, ".aput_byte_helper")) || (!strcmp(target, ".aput_wide_helper"))) {
+ touchEbx(); touchEcx(); touchEdx();
+ }
+ if((!strcmp(target, ".sput_helper")) || (!strcmp(target, ".sput_wide_helper"))) {
+ touchEdx(); touchEax();
+ }
+ if((!strcmp(target, ".sget_helper"))) {
+ touchEdx(); touchEcx();
+ }
+ if((!strcmp(target, ".sget_wide_helper"))) {
+ touchEdx(); touchXmm1();
+ }
+ if((!strcmp(target, ".aput_obj_helper"))) {
+ touchEdx(); touchEcx(); touchEax();
+ }
+ if((!strcmp(target, ".iput_helper")) || (!strcmp(target, ".iput_wide_helper"))) {
+ touchEbx(); touchEcx(); touchEsi();
+ }
+ if((!strcmp(target, ".iget_helper"))) {
+ touchEbx(); touchEcx(); touchEdx();
+ }
+ if((!strcmp(target, ".iget_wide_helper"))) {
+ touchEbx(); touchEcx(); touchXmm1();
+ }
+ if((!strcmp(target, ".new_array_helper"))) {
+ touchEbx(); touchEdx(); touchEax();
+ }
+ if((!strcmp(target, ".invoke_virtual_helper"))) {
+ touchEbx(); touchEcx();
+ }
+ if((!strcmp(target, ".invoke_direct_helper"))) {
+ touchEsi(); touchEcx();
+ }
+ if((!strcmp(target, ".invoke_super_helper"))) {
+ touchEbx(); touchEcx();
+ }
+ if((!strcmp(target, ".invoke_interface_helper"))) {
+ touchEbx(); touchEcx();
+ }
+ if((!strcmp(target, ".invokeMethodNoRange_5_helper")) ||
+ (!strcmp(target, ".invokeMethodNoRange_4_helper"))) {
+ touchEbx(); touchEsi(); touchEax(); touchEdx();
+ }
+ if((!strcmp(target, ".invokeMethodNoRange_3_helper"))) {
+ touchEbx(); touchEsi(); touchEax();
+ }
+ if((!strcmp(target, ".invokeMethodNoRange_2_helper"))) {
+ touchEbx(); touchEsi();
+ }
+ if((!strcmp(target, ".invokeMethodNoRange_1_helper"))) {
+ touchEbx();
+ }
+ if((!strcmp(target, ".invokeMethodRange_helper"))) {
+ touchEdx(); touchEsi();
+ }
+#ifdef DEBUG_REGALLOC
+ ALOGI("enter beforeCall");
+#endif
+ if(!strncmp(target, ".invokeArgsDone", 15)) resetGlue(PhysicalReg_GLUE_DVMDEX);
+
+ freeReg(true); //to avoid spilling dead logical registers
+ int k;
+ for(k = 0; k < num_compile_entries; k++) {
+ /* before throwing an exception, if GLUE is spilled, load to %ebp
+ this should happen at last */
+ if(k == indexForGlue) continue;
+ if(compileTable[k].physicalReg != PhysicalReg_Null &&
+ (compileTable[k].physicalType & LowOpndRegType_hard) == 0) {
+ /* handles non hardcoded variables that are in physical registers */
+ if(!strcmp(target, "exception")) {
+ /* before throwing an exception
+ update contents of all VRs in Java stack */
+ if(!isVirtualReg(compileTable[k].physicalType)) continue;
+ /* to have correct GC, we should update contents for L VRs as well */
+ //if(compileTable[k].gType == GLOBALTYPE_L) continue;
+ }
+ if((!strcmp(target, ".const_string_resolve")) ||
+ (!strcmp(target, ".static_field_resolve")) ||
+ (!strcmp(target, ".inst_field_resolve")) ||
+ (!strcmp(target, ".class_resolve")) ||
+ (!strcmp(target, ".direct_method_resolve")) ||
+ (!strcmp(target, ".virtual_method_resolve")) ||
+ (!strcmp(target, ".static_method_resolve"))) {
+ /* physical register %ebx will keep its content
+ but to have correct GC, we should dump content of a VR
+ that is mapped to %ebx */
+ if(compileTable[k].physicalReg == PhysicalReg_EBX &&
+ (!isVirtualReg(compileTable[k].physicalType)))
+ continue;
+ }
+ if((!strncmp(target, "dvm", 3)) || (!strcmp(target, "moddi3")) ||
+ (!strcmp(target, "divdi3")) ||
+ (!strcmp(target, "fmod")) || (!strcmp(target, "fmodf"))) {
+ /* callee-saved registers (%ebx, %esi, %ebp, %edi) will keep the content
+ but to have correct GC, we should dump content of a VR
+ that is mapped to a callee-saved register */
+ if((compileTable[k].physicalReg == PhysicalReg_EBX ||
+ compileTable[k].physicalReg == PhysicalReg_ESI) &&
+ (!isVirtualReg(compileTable[k].physicalType)))
+ continue;
+ }
+#ifdef DEBUG_REGALLOC
+ ALOGI("SPILL logical register %d %d in beforeCall",
+ compileTable[k].regNum, compileTable[k].physicalType);
+#endif
+ spillLogicalReg(k, true);
+ }
+ }
+ if(indexForGlue >= 0 && !strcmp(target, "exception") &&
+ compileTable[indexForGlue].physicalReg == PhysicalReg_Null) {
+ unspillLogicalReg(indexForGlue, PhysicalReg_EBP); //load %ebp
+ }
+#ifdef DEBUG_REGALLOC
+ ALOGI("exit beforeCall");
+#endif
+ return 0;
+}
+int getFreeReg(int type, int reg, int indexToCompileTable);
+//! after calling a helper function or a VM function
+
+//!
+int afterCall(const char* target) { //un-spill
+ if(currentBB == NULL) return -1;
+ if(!strcmp(target, "ncgGetEIP")) return -1;
+
+ return 0;
+}
+//! check whether a temporary is 8-bit
+
+//!
+bool isTemp8Bit(int type, int reg) {
+ if(currentBB == NULL) return false;
+ if(!isTemporary(type, reg)) return false;
+ int k;
+ for(k = 0; k < num_temp_regs_per_bytecode; k++) {
+ if(infoByteCodeTemp[k].physicalType == type &&
+ infoByteCodeTemp[k].regNum == reg) {
+ return infoByteCodeTemp[k].is8Bit;
+ }
+ }
+ ALOGE("isTemp8Bit %d %d", type, reg);
+ return false;
+}
+
+/* functions to access live ranges of a VR
+ Live range info is stored in memVRTable[].ranges, which is a linked list
+*/
+//! check whether a VR is live at the current bytecode
+
+//!
+bool isVRLive(int vA) {
+ int index = searchMemTable(vA);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", vA);
+ return false;
+ }
+ LiveRange* ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ if(offsetPC >= ptr->start && offsetPC <= ptr->end) return true;
+ ptr = ptr->next;
+ }
+ return false;
+}
+
+//! check whether the current bytecode is the last access to a VR within a live range
+
+//!for 64-bit VR, return true only when true for both low half and high half
+bool isLastByteCodeOfLiveRange(int compileIndex) {
+ int k = compileIndex;
+ OpndSize tSize = getRegSize(compileTable[k].physicalType);
+ int index;
+ LiveRange* ptr = NULL;
+ if(tSize == OpndSize_32) {
+ /* check live ranges for the VR */
+ index = searchMemTable(compileTable[k].regNum);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
+ return false;
+ }
+ ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ if(offsetPC == ptr->end) return true;
+ ptr = ptr->next;
+ }
+ return false;
+ }
+ /* size of the VR is 64 */
+ /* check live ranges of the low half */
+ index = searchMemTable(compileTable[k].regNum);
+ bool tmpB = false;
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
+ return false;
+ }
+ ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ if(offsetPC == ptr->end) {
+ tmpB = true;
+ break;
+ }
+ ptr = ptr->next;
+ }
+ if(!tmpB) return false;
+ /* check live ranges of the high half */
+ index = searchMemTable(compileTable[k].regNum+1);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum+1);
+ return false;
+ }
+ ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ if(offsetPC == ptr->end) {
+ return true;
+ }
+ ptr = ptr->next;
+ }
+ return false;
+}
+
+//! check whether the current bytecode is in a live range that extends to end of a basic block
+
+//!for 64 bit, return true if true for both low half and high half
+bool reachEndOfBB(int compileIndex) {
+ int k = compileIndex;
+ OpndSize tSize = getRegSize(compileTable[k].physicalType);
+ int index;
+ bool retCode = false;
+ /* check live ranges of the low half */
+ index = searchMemTable(compileTable[k].regNum);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
+ return false;
+ }
+ LiveRange* ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ if(offsetPC >= ptr->start &&
+ offsetPC <= ptr->end) {
+ if(ptr->end == currentBB->pc_end) {
+ retCode = true;
+ }
+ break;
+ }
+ ptr = ptr->next;
+ }
+ if(!retCode) return false;
+ if(tSize == OpndSize_32) return true;
+ /* check live ranges of the high half */
+ index = searchMemTable(compileTable[k].regNum+1);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum+1);
+ return false;
+ }
+ ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ if(offsetPC >= ptr->start &&
+ offsetPC <= ptr->end) {
+ if(ptr->end == currentBB->pc_end) return true;
+ return false;
+ }
+ ptr = ptr->next;
+ }
+#ifdef PRINT_WARNING
+ ALOGW("offsetPC %d not in live range of VR %d", offsetPC, compileTable[k].regNum+1);
+#endif
+ return false;
+}
+
+//!check whether the current bytecode is the next to last access to a VR within a live range
+
+//!for 64 bit, return true if true for both low half and high half
+bool isNextToLastAccess(int compileIndex) {
+ int k = compileIndex;
+ OpndSize tSize = getRegSize(compileTable[k].physicalType);
+ int index;
+ /* check live ranges for the low half */
+ bool retCode = false;
+ index = searchMemTable(compileTable[k].regNum);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
+ return false;
+ }
+ LiveRange* ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ int num_access = ptr->num_access;
+
+ if(num_access < 2) {
+ ptr = ptr->next;
+ continue;
+ }
+
+ if(offsetPC == ptr->accessPC[num_access-2]) {
+ retCode = true;
+ break;
+ }
+ ptr = ptr->next;
+ }
+ if(!retCode) return false;
+ if(tSize == OpndSize_32) return true;
+ /* check live ranges for the high half */
+ index = searchMemTable(compileTable[k].regNum+1);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum+1);
+ return false;
+ }
+ ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ int num_access = ptr->num_access;
+
+ if(num_access < 2) {
+ ptr = ptr->next;
+ continue;
+ }
+
+ if(offsetPC == ptr->accessPC[num_access-2]) return true;
+ ptr = ptr->next;
+ }
+ return false;
+}
+
+/** return the start of the next live range
+ if there does not exist a next live range, return pc_end of the basic block
+ for 64 bits, return the larger one for low half and high half
+ Assume live ranges are sorted in order
+*/
+int getNextLiveRange(int compileIndex) {
+ int k = compileIndex;
+ OpndSize tSize = getRegSize(compileTable[k].physicalType);
+ /* check live ranges of the low half */
+ int index;
+ index = searchMemTable(compileTable[k].regNum);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
+ return offsetPC;
+ }
+ bool found = false;
+ int nextUse = offsetPC;
+ LiveRange* ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ if(ptr->start > offsetPC) {
+ nextUse = ptr->start;
+ found = true;
+ break;
+ }
+ ptr = ptr->next;
+ }
+ if(!found) return currentBB->pc_end;
+ if(tSize == OpndSize_32) return nextUse;
+
+ /* check live ranges of the high half */
+ found = false;
+ index = searchMemTable(compileTable[k].regNum+1);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum+1);
+ return offsetPC;
+ }
+ int nextUse2 = offsetPC;
+ ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ if(ptr->start > offsetPC) {
+ nextUse2 = ptr->start;
+ found = true;
+ break;
+ }
+ ptr = ptr->next;
+ }
+ if(!found) return currentBB->pc_end;
+ /* return the larger one */
+ return (nextUse2 > nextUse ? nextUse2 : nextUse);
+}
+
+/** return the next access to a variable
+ If variable is 64-bit, get the next access to the lower half and the high half
+ return the eariler one
+*/
+int getNextAccess(int compileIndex) {
+ int k = compileIndex;
+ OpndSize tSize = getRegSize(compileTable[k].physicalType);
+ int index, k3;
+ /* check live ranges of the low half */
+ index = searchMemTable(compileTable[k].regNum);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
+ return offsetPC;
+ }
+ bool found = false;
+ int nextUse = offsetPC;
+ LiveRange* ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ if(offsetPC >= ptr->start &&
+ offsetPC <= ptr->end) {
+ /* offsetPC belongs to this live range */
+ for(k3 = 0; k3 < ptr->num_access; k3++) {
+ if(ptr->accessPC[k3] > offsetPC) {
+ nextUse = ptr->accessPC[k3];
+ break;
+ }
+ }
+ found = true;
+ break;
+ }
+ ptr = ptr->next;
+ }
+#ifdef PRINT_WARNING
+ if(!found)
+ ALOGW("offsetPC %d not in live range of VR %d", offsetPC, compileTable[k].regNum);
+#endif
+ if(tSize == OpndSize_32) return nextUse;
+
+ /* check live ranges of the high half */
+ found = false;
+ index = searchMemTable(compileTable[k].regNum+1);
+ if(index < 0) {
+ ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum+1);
+ return offsetPC;
+ }
+ int nextUse2 = offsetPC;
+ ptr = memVRTable[index].ranges;
+ while(ptr != NULL) {
+ if(offsetPC >= ptr->start &&
+ offsetPC <= ptr->end) {
+ for(k3 = 0; k3 < ptr->num_access; k3++) {
+ if(ptr->accessPC[k3] > offsetPC) {
+ nextUse2 = ptr->accessPC[k3];
+ break;
+ }
+ }
+ found = true;
+ break;
+ }
+ ptr = ptr->next;
+ }
+#ifdef PRINT_WARNING
+ if(!found) ALOGW("offsetPC %d not in live range of VR %d", offsetPC, compileTable[k].regNum+1);
+#endif
+ /* return the earlier one */
+ if(nextUse2 < nextUse) return nextUse2;
+ return nextUse;
+}
+
+/** free variables that are no longer in use
+ free a temporary with reference count of zero
+ will dump content of a GL VR to memory if necessary
+*/
+int freeReg(bool spillGL) {
+ if(currentBB == NULL) return 0;
+ int k;
+ for(k = 0; k < num_compile_entries; k++) {
+ if(compileTable[k].refCount == 0 && compileTable[k].physicalReg != PhysicalReg_Null) {
+ /* check entries with reference count of zero and is mapped to a physical register */
+ bool typeA = !isVirtualReg(compileTable[k].physicalType);
+ bool freeCrit = true, delayFreeing = false;
+ bool typeC = false, typeB = false, reachEnd = false;
+ if(isVirtualReg(compileTable[k].physicalType)) {
+ /* VRs in the compile table */
+
+ /* Check if delay for freeing was requested for this VR */
+ delayFreeing = getVRFreeDelayRequested(compileTable[k].regNum);
+
+ freeCrit = isLastByteCodeOfLiveRange(k); /* last bytecode of a live range */
+ reachEnd = reachEndOfBB(k); /* in a live range that extends to end of a basic block */
+#ifdef DEBUG_LIVE_RANGE
+ ALOGI("IN freeReg: VR %d offsetPC %x freecrit %d reachEnd %d nextToLast %d", compileTable[k].regNum, offsetPC, freeCrit, reachEnd, isNextToLastAccess(k));
+#endif
+ /* Bug: spilling of VRs after edi(rFP) is updated in RETURN bytecode
+ will cause variables for callee to be spilled to the caller stack frame and
+ to overwrite varaibles for caller
+ */
+ /* last bytecode of a live range reaching end of BB if not counting the fake usage at end */
+ bool boolB = reachEnd && isNextToLastAccess(k);
+ /* Bug: when a GG VR is checked at end of a basic block,
+ freeCrit will be true and physicalReg will be set to Null
+ Fix: change free condition from freeCrit to (freeCrit && offsetPC != currentBB->pc_end)
+ */
+ /* conditions to free a GG VR:
+ last bytecode of a live range reaching end of BB if not counting the fake usage at end && endsWithReturn
+ or
+ last bytecode of a live range && offsetPC != currentBB->pc_end
+ -> last bytecode of a live range not reaching end
+ */
+ typeC = ((freeCrit && offsetPC != currentBB->pc_end) ||
+ (currentBB->endsWithReturn && boolB)) &&
+ compileTable[k].gType == GLOBALTYPE_GG &&
+ !delayFreeing;
+ /* conditions to free a L|GL VR:
+ last bytecode of a live range
+ or
+ last bytecode of a live range reaching end of BB if not counting the fake usage at end
+ */
+ typeB = (freeCrit || boolB) &&
+ (compileTable[k].gType != GLOBALTYPE_GG) &&
+ !delayFreeing;
+ }
+ if(typeA || typeB || typeC) {
+#ifdef DEBUG_REGALLOC
+ if(typeA)
+ ALOGI("FREE TEMP %d with type %d allocated to %d",
+ compileTable[k].regNum, compileTable[k].physicalType,
+ compileTable[k].physicalReg);
+ else if(typeB)
+ ALOGI("FREE VR L|GL %d with type %d allocated to %d",
+ compileTable[k].regNum, compileTable[k].physicalType,
+ compileTable[k].physicalReg);
+ else if(typeC)
+ ALOGI("FREE VR GG %d with type %d allocated to %d",
+ compileTable[k].regNum, compileTable[k].physicalType,
+ compileTable[k].physicalReg);
+#endif
+ bool dumpGL = false;
+ if(compileTable[k].gType == GLOBALTYPE_GL && !reachEnd) {
+ /* if the live range does not reach end of basic block
+ and there exists a try block from offsetPC to the next live range
+ dump VR to interpreted stack */
+ int tmpPC = getNextLiveRange(k);
+ if(existATryBlock(currentMethod, offsetPC, tmpPC)) dumpGL = true;
+ }
+ /* if the live range reach end of basic block, dump VR to interpreted stack */
+ if(compileTable[k].gType == GLOBALTYPE_GL && reachEnd) dumpGL = true;
+ if(dumpGL) {
+ if(spillGL) {
+#ifdef DEBUG_REGALLOC
+ ALOGI("SPILL VR GL %d %d", compileTable[k].regNum, compileTable[k].physicalType);
+#endif
+ spillLogicalReg(k, true); //will dump VR to memory & update physicalReg
+ }
+ }
+ else
+ compileTable[k].physicalReg = PhysicalReg_Null;
+ }
+ if(typeA) {
+ if(compileTable[k].spill_loc_index >= 0) {
+ /* update spill info for temporaries */
+ spillIndexUsed[compileTable[k].spill_loc_index >> 2] = 0;
+ compileTable[k].spill_loc_index = -1;
+ ALOGE("free a temporary register with TRSTATE_SPILLED");
+ }
+ }
+ }
+ }
+ syncAllRegs(); //sync up allRegs (isUsed & freeTimeStamp) with compileTable
+ return 0;
+}
+
+//! reduce the reference count by 1
+
+//! input: index to compileTable
+void decreaseRefCount(int index) {
+#ifdef DEBUG_REFCOUNT
+ ALOGI("REFCOUNT: %d in decreaseRefCount %d %d", compileTable[index].refCount,
+ compileTable[index].regNum, compileTable[index].physicalType);
+#endif
+ compileTable[index].refCount--;
+ if(compileTable[index].refCount < 0) {
+ ALOGE("refCount is negative for REG %d %d", compileTable[index].regNum, compileTable[index].physicalType);
+ dvmAbort();
+ }
+}
+//! reduce the reference count of a VR by 1
+
+//! input: reg & type
+int updateRefCount(int reg, LowOpndRegType type) {
+ if(currentBB == NULL) return 0;
+ int index = searchCompileTable(LowOpndRegType_virtual | type, reg);
+ if(index < 0) {
+ ALOGE("virtual reg %d type %d not found in updateRefCount", reg, type);
+ return -1;
+ }
+ decreaseRefCount(index);
+ return 0;
+}
+//! reduce the reference count of a variable by 1
+
+//! The variable is named with lowering module's naming mechanism
+int updateRefCount2(int reg, int type, bool isPhysical) {
+ if(currentBB == NULL) return 0;
+ int newType = convertType(type, reg, isPhysical);
+ if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
+ int index = searchCompileTable(newType, reg);
+ if(index < 0) {
+ ALOGE("reg %d type %d not found in updateRefCount", reg, newType);
+ return -1;
+ }
+ decreaseRefCount(index);
+ return 0;
+}
+//! check whether a glue variable is in physical register or spilled
+
+//!
+bool isGlueHandled(int glue_reg) {
+ if(currentBB == NULL) return false;
+ int index = searchCompileTable(LowOpndRegType_gp, glue_reg);
+ if(index < 0) {
+ ALOGE("glue reg %d not found in isGlueHandled", glue_reg);
+ return -1;
+ }
+ if(compileTable[index].spill_loc_index >= 0 ||
+ compileTable[index].physicalReg != PhysicalReg_Null) {
+#ifdef DEBUG_GLUE
+ ALOGI("GLUE isGlueHandled for %d returns true", glue_reg);
+#endif
+ return true;
+ }
+#ifdef DEBUG_GLUE
+ ALOGI("GLUE isGlueHandled for %d returns false", glue_reg);
+#endif
+ return false;
+}
+//! reset the state of a glue variable to not existant (not in physical register nor spilled)
+
+//!
+void resetGlue(int glue_reg) {
+ if(currentBB == NULL) return;
+ int index = searchCompileTable(LowOpndRegType_gp, glue_reg);
+ if(index < 0) {
+ ALOGE("glue reg %d not found in resetGlue", glue_reg);
+ return;
+ }
+#ifdef DEBUG_GLUE
+ ALOGI("GLUE reset for %d", glue_reg);
+#endif
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ if(compileTable[index].spill_loc_index >= 0)
+ spillIndexUsed[compileTable[index].spill_loc_index >> 2] = 0;
+ compileTable[index].spill_loc_index = -1;
+}
+//! set a glue variable in a physical register allocated for a variable
+
+//! Variable is using lowering module's naming convention
+void updateGlue(int reg, bool isPhysical, int glue_reg) {
+ if(currentBB == NULL) return;
+ int index = searchCompileTable(LowOpndRegType_gp, glue_reg);
+ if(index < 0) {
+ ALOGE("glue reg %d not found in updateGlue", glue_reg);
+ return;
+ }
+ /* find the compileTable entry for variable <reg, isPhysical> */
+ int newType = convertType(LowOpndRegType_gp, reg, isPhysical);
+ if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
+ int index2 = searchCompileTable(newType, reg);
+ if(index2 < 0 || compileTable[index2].physicalReg == PhysicalReg_Null) {
+ ALOGE("updateGlue reg %d type %d", reg, newType);
+ return;
+ }
+#ifdef DEBUG_GLUE
+ ALOGI("physical register for GLUE %d set to %d", glue_reg, compileTable[index2].physicalReg);
+#endif
+ compileTable[index].physicalReg = compileTable[index2].physicalReg;
+ compileTable[index].spill_loc_index = -1;
+}
+
+//! check whether a virtual register is in a physical register
+
+//! If updateRefCount is 0, do not update reference count;
+//!If updateRefCount is 1, update reference count only when VR is in a physical register
+//!If updateRefCount is 2, update reference count
+int checkVirtualReg(int reg, LowOpndRegType type, int updateRefCount) {
+ if(currentBB == NULL) return PhysicalReg_Null;
+ int index = searchCompileTable(LowOpndRegType_virtual | type, reg);
+ if(index < 0) {
+ ALOGE("virtual reg %d type %d not found in checkVirtualReg", reg, type);
+ return PhysicalReg_Null;
+ }
+ //reduce reference count
+ if(compileTable[index].physicalReg != PhysicalReg_Null) {
+ if(updateRefCount != 0) decreaseRefCount(index);
+ return compileTable[index].physicalReg;
+ }
+ if(updateRefCount == 2) decreaseRefCount(index);
+ return PhysicalReg_Null;
+}
+//!check whether a temporary can share the same physical register with a VR
+
+//!This is called in get_virtual_reg
+//!If this function returns false, new register will be allocated for this temporary
+bool checkTempReg2(int reg, int type, bool isPhysical, int physicalRegForVR) {
+ if(currentBB == NULL) return false;
+ if(isPhysical) return false;
+
+ int newType = convertType(type, reg, isPhysical);
+ if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
+ int k;
+ for(k = 0; k < num_temp_regs_per_bytecode; k++) {
+ if(infoByteCodeTemp[k].physicalType == newType &&
+ infoByteCodeTemp[k].regNum == reg) {
+#ifdef DEBUG_MOVE_OPT
+ ALOGI("MOVE_OPT checkTempRegs for %d %d returns %d %d",
+ reg, newType, infoByteCodeTemp[k].shareWithVR, infoByteCodeTemp[k].is8Bit);
+#endif
+ if(!infoByteCodeTemp[k].is8Bit) return infoByteCodeTemp[k].shareWithVR;
+ //is8Bit true for gp type only
+ if(!infoByteCodeTemp[k].shareWithVR) return false;
+ //both true
+ if(physicalRegForVR >= PhysicalReg_EAX && physicalRegForVR <= PhysicalReg_EDX) return true;
+#ifdef DEBUG_MOVE_OPT
+ ALOGI("MOVE_OPT registerAllocMove not used for 8-bit register");
+#endif
+ return false;
+ }
+ }
+ ALOGE("checkTempReg2 %d %d", reg, newType);
+ return false;
+}
+//!check whether a temporary can share the same physical register with a VR
+
+//!This is called in set_virtual_reg
+int checkTempReg(int reg, int type, bool isPhysical, int vrNum) {
+ if(currentBB == NULL) return PhysicalReg_Null;
+
+ int newType = convertType(type, reg, isPhysical);
+ if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
+ int index = searchCompileTable(newType, reg);
+ if(index < 0) {
+ ALOGE("temp reg %d type %d not found in checkTempReg", reg, newType);
+ return PhysicalReg_Null;
+ }
+
+ //a temporary register can share the same physical reg with a VR if registerAllocMove is called
+ //this will cause problem with move bytecode
+ //get_VR(v1, t1) t1 and v1 point to the same physical reg
+ //set_VR(t1, v2) t1 and v2 point to the same physical reg
+ //this will cause v1 and v2 point to the same physical reg
+ //FIX: if this temp reg shares a physical reg with another reg
+ if(compileTable[index].physicalReg != PhysicalReg_Null) {
+ int k;
+ for(k = 0; k < num_compile_entries; k++) {
+ if(k == index) continue;
+ if(compileTable[k].physicalReg == compileTable[index].physicalReg) {
+ return PhysicalReg_Null; //will allocate a register for VR
+ }
+ }
+ decreaseRefCount(index);
+ return compileTable[index].physicalReg;
+ }
+ if(compileTable[index].spill_loc_index >= 0) {
+ //registerAlloc will call unspillLogicalReg (load from memory)
+#ifdef DEBUG_REGALLOC
+ ALOGW("in checkTempReg, the temporary register %d %d was spilled", reg, type);
+#endif
+ int regAll = registerAlloc(type, reg, isPhysical, true/* updateRefCount */);
+ return regAll;
+ }
+ return PhysicalReg_Null;
+}
+//!check whether a variable has exposed usage in a basic block
+
+//!It calls hasExposedUsage2
+bool hasExposedUsage(LowOpndRegType type, int regNum, BasicBlock_O1* bb) {
+ int index = searchVirtualInfoOfBB(type, regNum, bb);
+ if(index >= 0 && hasExposedUsage2(bb, index)) {
+ return true;
+ }
+ return false;
+}
+//!check whether a variable has exposed usage in other basic blocks
+
+//!
+bool hasOtherExposedUsage(OpndSize size, int regNum, BasicBlock_O1* bb) {
+ return true; //assume the worst case
+}
+
+//! handles constant VRs at end of a basic block
+
+//!If a VR is constant at end of a basic block and (it has exposed usage in other basic blocks or reaches a GG VR), dump immediate to memory
+void constVREndOfBB() {
+ BasicBlock_O1* bb = currentBB;
+ int k, k2;
+ //go through GG VRs, update a bool array
+ int constUsedByGG[MAX_CONST_REG];
+ for(k = 0; k < num_const_vr; k++)
+ constUsedByGG[k] = 0;
+ for(k = 0; k < num_compile_entries; k++) {
+ if(isVirtualReg(compileTable[k].physicalType) && compileTable[k].gType == GLOBALTYPE_GG) {
+ OpndSize size = getRegSize(compileTable[k].physicalType);
+ int regNum = compileTable[k].regNum;
+ int indexL = -1;
+ int indexH = -1;
+ for(k2 = 0; k2 < num_const_vr; k2++) {
+ if(constVRTable[k2].regNum == regNum) {
+ indexL = k2;
+ continue;
+ }
+ if(constVRTable[k2].regNum == regNum + 1 && size == OpndSize_64) {
+ indexH = k2;
+ continue;
+ }
+ }
+ if(indexL >= 0) constUsedByGG[indexL] = 1;
+ if(indexH >= 0) constUsedByGG[indexH] = 1;
+ } //GG VR
+ }
+ for(k = 0; k < num_const_vr; k++) {
+ if(!constVRTable[k].isConst) continue;
+ bool hasExp = false;
+ if(constUsedByGG[k] == 0)
+ hasExp = hasOtherExposedUsage(OpndSize_32, constVRTable[k].regNum, bb);
+ if(constUsedByGG[k] != 0 || hasExp) {
+ dumpImmToMem(constVRTable[k].regNum, OpndSize_32, constVRTable[k].value);
+ setVRToMemory(constVRTable[k].regNum, OpndSize_32);
+#ifdef DEBUG_ENDOFBB
+ ALOGI("ENDOFBB: exposed VR %d is const %d (%x)",
+ constVRTable[k].regNum, constVRTable[k].value, constVRTable[k].value);
+#endif
+ } else {
+#ifdef DEBUG_ENDOFBB
+ ALOGI("ENDOFBB: unexposed VR %d is const %d (%x)",
+ constVRTable[k].regNum, constVRTable[k].value, constVRTable[k].value);
+#endif
+ }
+ }
+}
+
+//!handles GG VRs at end of a basic block
+
+//!make sure all GG VRs are in pre-defined physical registers
+void globalVREndOfBB(const Method* method) {
+ //fix: freeReg first to write LL VR back to memory to avoid it gets overwritten by GG VRs
+ freeReg(true);
+ int k;
+ //spill GG VR first if it is not mapped to the specific reg
+ //release GLUE regs
+ for(k = 0; k < num_compile_entries; k++) {
+ if(compileTable[k].regNum >= PhysicalReg_GLUE_DVMDEX &&
+ compileTable[k].regNum != PhysicalReg_GLUE) {
+ compileTable[k].physicalReg = PhysicalReg_Null;
+ compileTable[k].spill_loc_index = -1;
+ }
+ //if part of a GG VR is const, the physical reg is set to null
+ if(isVirtualReg(compileTable[k].physicalType) &&
+ compileTable[k].gType == GLOBALTYPE_GG && compileTable[k].physicalReg != PhysicalReg_Null &&
+ compileTable[k].physicalReg != compileTable[k].physicalReg_prev) {
+#ifdef DEBUG_ENDOFBB
+ ALOGW("end of BB GG VR is not mapped to the specific reg: %d %d %d",
+ compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].physicalReg);
+ ALOGW("ENDOFBB SPILL VR %d %d", compileTable[k].regNum, compileTable[k].physicalType);
+#endif
+ spillLogicalReg(k, true); //the next section will load VR from memory to the specific reg
+ }
+ }
+ syncAllRegs();
+ for(k = 0; k < num_compile_entries; k++) {
+ if(isVirtualReg(compileTable[k].physicalType)) {
+ if(compileTable[k].gType == GLOBALTYPE_GG &&
+ compileTable[k].physicalReg == PhysicalReg_Null && (!currentBB->endsWithReturn)) {
+#ifdef DEBUG_ENDOFBB
+ ALOGI("ENDOFBB GET GG VR %d %d to physical register %d", compileTable[k].regNum,
+ compileTable[k].physicalType, compileTable[k].physicalReg_prev);
+#endif
+ compileTable[k].physicalReg = compileTable[k].physicalReg_prev;
+ if(allRegs[compileTable[k].physicalReg_prev].isUsed) {
+ ALOGE("physical register for GG VR is still used");
+ }
+ get_virtual_reg_noalloc(compileTable[k].regNum,
+ getRegSize(compileTable[k].physicalType),
+ compileTable[k].physicalReg_prev,
+ true);
+ }
+ }//not const
+ }
+ if(indexForGlue >= 0 &&
+ compileTable[indexForGlue].physicalReg == PhysicalReg_Null) {
+ unspillLogicalReg(indexForGlue, PhysicalReg_EBP); //load %ebp
+ }
+}
+
+//! get ready for the next version of a hard-coded register
+
+//!set its physicalReg to Null and update its reference count
+int nextVersionOfHardReg(PhysicalReg pReg, int refCount) {
+ int indexT = searchCompileTable(LowOpndRegType_gp | LowOpndRegType_hard, pReg);
+ if(indexT < 0)
+ return -1;
+ compileTable[indexT].physicalReg = PhysicalReg_Null;
+#ifdef DEBUG_REFCOUNT
+ ALOGI("REFCOUNT: to %d in nextVersionOfHardReg %d", refCount, pReg);
+#endif
+ compileTable[indexT].refCount = refCount;
+ return 0;
+}
+
+/** update compileTable with bb->infoBasicBlock[k]
+*/
+void insertFromVirtualInfo(BasicBlock_O1* bb, int k) {
+ int index = searchCompileTable(LowOpndRegType_virtual | bb->infoBasicBlock[k].physicalType, bb->infoBasicBlock[k].regNum);
+ if(index < 0) {
+ /* the virtual register is not in compileTable, insert it */
+ index = num_compile_entries;
+ compileTable[num_compile_entries].physicalType = (LowOpndRegType_virtual | bb->infoBasicBlock[k].physicalType);
+ compileTable[num_compile_entries].regNum = bb->infoBasicBlock[k].regNum;
+ compileTable[num_compile_entries].physicalReg = PhysicalReg_Null;
+ compileTable[num_compile_entries].bb = bb;
+ compileTable[num_compile_entries].indexToInfoBB = k;
+ compileTable[num_compile_entries].spill_loc_index = -1;
+ compileTable[num_compile_entries].gType = bb->infoBasicBlock[k].gType;
+ num_compile_entries++;
+ if(num_compile_entries >= COMPILE_TABLE_SIZE) {
+ ALOGE("compileTable overflow");
+ dvmAbort();
+ }
+ }
+ /* re-set reference count of all VRs */
+ compileTable[index].refCount = bb->infoBasicBlock[k].refCount;
+ compileTable[index].accessType = bb->infoBasicBlock[k].accessType;
+ if(compileTable[index].gType == GLOBALTYPE_GG)
+ compileTable[index].physicalReg_prev = bb->infoBasicBlock[k].physicalReg_GG;
+}
+
+/** update compileTable with infoByteCodeTemp[k]
+*/
+void insertFromTempInfo(int k) {
+ int index = searchCompileTable(infoByteCodeTemp[k].physicalType, infoByteCodeTemp[k].regNum);
+ if(index < 0) {
+ /* the temporary is not in compileTable, insert it */
+ index = num_compile_entries;
+ compileTable[num_compile_entries].physicalType = infoByteCodeTemp[k].physicalType;
+ compileTable[num_compile_entries].regNum = infoByteCodeTemp[k].regNum;
+ num_compile_entries++;
+ if(num_compile_entries >= COMPILE_TABLE_SIZE) {
+ ALOGE("compileTable overflow");
+ dvmAbort();
+ }
+ }
+ compileTable[index].physicalReg = PhysicalReg_Null;
+ compileTable[index].refCount = infoByteCodeTemp[k].refCount;
+ compileTable[index].linkageToVR = infoByteCodeTemp[k].linkageToVR;
+ compileTable[index].gType = GLOBALTYPE_L;
+ compileTable[index].spill_loc_index = -1;
+}
+
+/* insert a glue-related register GLUE_DVMDEX to compileTable */
+void insertGlueReg() {
+ compileTable[num_compile_entries].physicalType = LowOpndRegType_gp;
+ compileTable[num_compile_entries].regNum = PhysicalReg_GLUE_DVMDEX;
+ compileTable[num_compile_entries].refCount = 2;
+ compileTable[num_compile_entries].physicalReg = PhysicalReg_Null;
+ compileTable[num_compile_entries].bb = NULL;
+ compileTable[num_compile_entries].spill_loc_index = -1;
+ compileTable[num_compile_entries].accessType = REGACCESS_N;
+ compileTable[num_compile_entries].linkageToVR = -1;
+ compileTable[num_compile_entries].gType = GLOBALTYPE_L;
+
+ num_compile_entries++;
+ if(num_compile_entries >= COMPILE_TABLE_SIZE) {
+ ALOGE("compileTable overflow");
+ dvmAbort();
+ }
+}
+
+/** print infoBasicBlock of the given basic block
+*/
+void dumpVirtualInfoOfBasicBlock(BasicBlock_O1* bb) {
+ int jj;
+ ALOGI("Virtual Info for BB%d --------", bb->bb_index);
+ for(jj = 0; jj < bb->num_regs; jj++) {
+ ALOGI("regNum %d physicalType %d accessType %d refCount %d def ",
+ bb->infoBasicBlock[jj].regNum, bb->infoBasicBlock[jj].physicalType,
+ bb->infoBasicBlock[jj].accessType, bb->infoBasicBlock[jj].refCount);
+ int k;
+ for(k = 0; k < bb->infoBasicBlock[jj].num_reaching_defs; k++)
+ ALOGI("[%x %d %d %d] ", bb->infoBasicBlock[jj].reachingDefs[k].offsetPC,
+ bb->infoBasicBlock[jj].reachingDefs[k].regNum,
+ bb->infoBasicBlock[jj].reachingDefs[k].physicalType,
+ bb->infoBasicBlock[jj].reachingDefs[k].accessType);
+ ALOGI("");
+ }
+}
+
+/** print compileTable
+*/
+void dumpCompileTable() {
+ int jj;
+ ALOGI("Compile Table for method ----------");
+ for(jj = 0; jj < num_compile_entries; jj++) {
+ ALOGI("regNum %d physicalType %d refCount %d isConst %d physicalReg %d type %d",
+ compileTable[jj].regNum, compileTable[jj].physicalType,
+ compileTable[jj].refCount, compileTable[jj].isConst, compileTable[jj].physicalReg, compileTable[jj].gType);
+ }
+}
+
+//!check whether a basic block is the start of an exception handler
+
+//!
+bool isFirstOfHandler(BasicBlock_O1* bb) {
+ int i;
+ for(i = 0; i < num_exception_handlers; i++) {
+ if(bb->pc_start == exceptionHandlers[i]) return true;
+ }
+ return false;
+}
+
+//! create a basic block that starts at src_pc and ends at end_pc
+
+//!
+BasicBlock_O1* createBasicBlock(int src_pc, int end_pc) {
+ BasicBlock_O1* bb = (BasicBlock_O1*)malloc(sizeof(BasicBlock_O1));
+ if(bb == NULL) {
+ ALOGE("out of memory");
+ return NULL;
+ }
+ bb->pc_start = src_pc;
+ bb->bb_index = num_bbs_for_method;
+ if(bb_entry == NULL) bb_entry = bb;
+
+ /* insert the basic block to method_bbs_sorted in ascending order of pc_start */
+ int k;
+ int index = -1;
+ for(k = 0; k < num_bbs_for_method; k++)
+ if(method_bbs_sorted[k]->pc_start > src_pc) {
+ index = k;
+ break;
+ }
+ if(index == -1)
+ method_bbs_sorted[num_bbs_for_method] = bb;
+ else {
+ /* push the elements from index by 1 */
+ for(k = num_bbs_for_method-1; k >= index; k--)
+ method_bbs_sorted[k+1] = method_bbs_sorted[k];
+ method_bbs_sorted[index] = bb;
+ }
+ num_bbs_for_method++;
+ if(num_bbs_for_method >= MAX_NUM_BBS_PER_METHOD) {
+ ALOGE("too many basic blocks");
+ dvmAbort();
+ }
+ return bb;
+}
+
+/* BEGIN code to handle state transfers */
+//! save the current state of register allocator to a state table
+
+//!
+void rememberState(int stateNum) {
+#ifdef DEBUG_STATE
+ ALOGI("STATE: remember state %d", stateNum);
+#endif
+ int k;
+ for(k = 0; k < num_compile_entries; k++) {
+ if(stateNum == 1) {
+ stateTable1_1[k].physicalReg = compileTable[k].physicalReg;
+ stateTable1_1[k].spill_loc_index = compileTable[k].spill_loc_index;
+ }
+ else if(stateNum == 2) {
+ stateTable1_2[k].physicalReg = compileTable[k].physicalReg;
+ stateTable1_2[k].spill_loc_index = compileTable[k].spill_loc_index;
+ }
+ else if(stateNum == 3) {
+ stateTable1_3[k].physicalReg = compileTable[k].physicalReg;
+ stateTable1_3[k].spill_loc_index = compileTable[k].spill_loc_index;
+ }
+ else if(stateNum == 4) {
+ stateTable1_4[k].physicalReg = compileTable[k].physicalReg;
+ stateTable1_4[k].spill_loc_index = compileTable[k].spill_loc_index;
+ }
+ else ALOGE("state table overflow");
+#ifdef DEBUG_STATE
+ ALOGI("logical reg %d %d mapped to physical reg %d with spill index %d refCount %d",
+ compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].physicalReg,
+ compileTable[k].spill_loc_index, compileTable[k].refCount);
+#endif
+ }
+ for(k = 0; k < num_memory_vr; k++) {
+ if(stateNum == 1) {
+ stateTable2_1[k].regNum = memVRTable[k].regNum;
+ stateTable2_1[k].inMemory = memVRTable[k].inMemory;
+ }
+ else if(stateNum == 2) {
+ stateTable2_2[k].regNum = memVRTable[k].regNum;
+ stateTable2_2[k].inMemory = memVRTable[k].inMemory;
+ }
+ else if(stateNum == 3) {
+ stateTable2_3[k].regNum = memVRTable[k].regNum;
+ stateTable2_3[k].inMemory = memVRTable[k].inMemory;
+ }
+ else if(stateNum == 4) {
+ stateTable2_4[k].regNum = memVRTable[k].regNum;
+ stateTable2_4[k].inMemory = memVRTable[k].inMemory;
+ }
+ else ALOGE("state table overflow");
+#ifdef DEBUG_STATE
+ ALOGI("virtual reg %d in memory %d", memVRTable[k].regNum, memVRTable[k].inMemory);
+#endif
+ }
+}
+
+//!update current state of register allocator with a state table
+
+//!
+void goToState(int stateNum) {
+ int k;
+#ifdef DEBUG_STATE
+ ALOGI("STATE: go to state %d", stateNum);
+#endif
+ for(k = 0; k < num_compile_entries; k++) {
+ if(stateNum == 1) {
+ compileTable[k].physicalReg = stateTable1_1[k].physicalReg;
+ compileTable[k].spill_loc_index = stateTable1_1[k].spill_loc_index;
+ }
+ else if(stateNum == 2) {
+ compileTable[k].physicalReg = stateTable1_2[k].physicalReg;
+ compileTable[k].spill_loc_index = stateTable1_2[k].spill_loc_index;
+ }
+ else if(stateNum == 3) {
+ compileTable[k].physicalReg = stateTable1_3[k].physicalReg;
+ compileTable[k].spill_loc_index = stateTable1_3[k].spill_loc_index;
+ }
+ else if(stateNum == 4) {
+ compileTable[k].physicalReg = stateTable1_4[k].physicalReg;
+ compileTable[k].spill_loc_index = stateTable1_4[k].spill_loc_index;
+ }
+ else ALOGE("state table overflow");
+ }
+ updateSpillIndexUsed();
+ syncAllRegs(); //to sync up allRegs CAN'T call freeReg here
+ //since it will change the state!!!
+ for(k = 0; k < num_memory_vr; k++) {
+ if(stateNum == 1) {
+ memVRTable[k].regNum = stateTable2_1[k].regNum;
+ memVRTable[k].inMemory = stateTable2_1[k].inMemory;
+ }
+ else if(stateNum == 2) {
+ memVRTable[k].regNum = stateTable2_2[k].regNum;
+ memVRTable[k].inMemory = stateTable2_2[k].inMemory;
+ }
+ else if(stateNum == 3) {
+ memVRTable[k].regNum = stateTable2_3[k].regNum;
+ memVRTable[k].inMemory = stateTable2_3[k].inMemory;
+ }
+ else if(stateNum == 4) {
+ memVRTable[k].regNum = stateTable2_4[k].regNum;
+ memVRTable[k].inMemory = stateTable2_4[k].inMemory;
+ }
+ else ALOGE("state table overflow");
+ }
+}
+typedef struct TransferOrder {
+ int targetReg;
+ int targetSpill;
+ int compileIndex;
+} TransferOrder;
+#define MAX_NUM_DEST 20
+//! a source register is used as a source in transfer
+//! it can have a maximum of MAX_NUM_DEST destinations
+typedef struct SourceReg {
+ int physicalReg;
+ int num_dests; //check bound
+ TransferOrder dsts[MAX_NUM_DEST];
+} SourceReg;
+int num_src_regs = 0; //check bound
+//! physical registers that are used as a source in transfer
+//! we allow a maximum of MAX_NUM_DEST sources in a transfer
+SourceReg srcRegs[MAX_NUM_DEST];
+//! tell us whether a source register is handled already
+bool handledSrc[MAX_NUM_DEST];
+//! in what order should the source registers be handled
+int handledOrder[MAX_NUM_DEST];
+//! insert a source register with a single destination
+
+//!
+void insertSrcReg(int srcPhysical, int targetReg, int targetSpill, int index) {
+ int k = 0;
+ for(k = 0; k < num_src_regs; k++) {
+ if(srcRegs[k].physicalReg == srcPhysical) { //increase num_dests
+ if(srcRegs[k].num_dests >= MAX_NUM_DEST) {
+ ALOGE("exceed number dst regs for a source reg");
+ dvmAbort();
+ }
+ srcRegs[k].dsts[srcRegs[k].num_dests].targetReg = targetReg;
+ srcRegs[k].dsts[srcRegs[k].num_dests].targetSpill = targetSpill;
+ srcRegs[k].dsts[srcRegs[k].num_dests].compileIndex = index;
+ srcRegs[k].num_dests++;
+ return;
+ }
+ }
+ if(num_src_regs >= MAX_NUM_DEST) {
+ ALOGE("exceed number of source regs");
+ dvmAbort();
+ }
+ srcRegs[num_src_regs].physicalReg = srcPhysical;
+ srcRegs[num_src_regs].num_dests = 1;
+ srcRegs[num_src_regs].dsts[0].targetReg = targetReg;
+ srcRegs[num_src_regs].dsts[0].targetSpill = targetSpill;
+ srcRegs[num_src_regs].dsts[0].compileIndex = index;
+ num_src_regs++;
+}
+//! check whether a register is a source and the source is not yet handled
+
+//!
+bool dstStillInUse(int dstReg) {
+ if(dstReg == PhysicalReg_Null) return false;
+ int k;
+ int index = -1;
+ for(k = 0; k < num_src_regs; k++) {
+ if(dstReg == srcRegs[k].physicalReg) {
+ index = k;
+ break;
+ }
+ }
+ if(index < 0) return false; //not in use
+ if(handledSrc[index]) return false; //not in use
+ return true;
+}
+//! reset the state of glue variables in a state table
+
+//!
+void resetStateOfGlue(int stateNum, int k) {
+#ifdef DEBUG_STATE
+ ALOGI("resetStateOfGlue state %d regNum %d", stateNum, compileTable[k].regNum);
+#endif
+ if(stateNum == 1) {
+ stateTable1_1[k].physicalReg = PhysicalReg_Null;
+ stateTable1_1[k].spill_loc_index = -1;
+ }
+ else if(stateNum == 2) {
+ stateTable1_2[k].physicalReg = PhysicalReg_Null;
+ stateTable1_2[k].spill_loc_index = -1;
+ }
+ else if(stateNum == 3) {
+ stateTable1_3[k].physicalReg = PhysicalReg_Null;
+ stateTable1_3[k].spill_loc_index = -1;
+ }
+ else if(stateNum == 4) {
+ stateTable1_4[k].physicalReg = PhysicalReg_Null;
+ stateTable1_4[k].spill_loc_index = -1;
+ }
+}
+//! construct a legal order of the source registers in this transfer
+
+//!
+void constructSrcRegs(int stateNum) {
+ int k;
+ num_src_regs = 0;
+#ifdef DEBUG_STATE
+ ALOGI("IN constructSrcRegs");
+#endif
+
+ for(k = 0; k < num_compile_entries; k++) {
+#ifdef DEBUG_STATE
+ ALOGI("logical reg %d %d mapped to physical reg %d with spill index %d refCount %d",
+ compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].physicalReg,
+ compileTable[k].spill_loc_index, compileTable[k].refCount);
+#endif
+
+ int pType = compileTable[k].physicalType;
+ //ignore hardcoded logical registers
+ if((pType & LowOpndRegType_hard) != 0) continue;
+ //ignore type _fs
+ if((pType & MASK_FOR_TYPE) == LowOpndRegType_fs) continue;
+ if((pType & MASK_FOR_TYPE) == LowOpndRegType_fs_s) continue;
+
+ //GL VR refCount is zero, can't ignore
+ //L VR refCount is zero, ignore
+ //GG VR refCount is zero, can't ignore
+ //temporary refCount is zero, ignore
+
+ //for GLUE variables, if they do not exist, reset the entries in state table
+ if(compileTable[k].physicalReg == PhysicalReg_Null &&
+ compileTable[k].regNum >= PhysicalReg_GLUE_DVMDEX &&
+ compileTable[k].regNum != PhysicalReg_GLUE &&
+ compileTable[k].spill_loc_index < 0) {
+ resetStateOfGlue(stateNum, k);
+ }
+
+ /* get the target state */
+ int targetReg = PhysicalReg_Null;
+ int targetSpill = -1;
+ if(stateNum == 1) {
+ targetReg = stateTable1_1[k].physicalReg;
+ targetSpill = stateTable1_1[k].spill_loc_index;
+ }
+ else if(stateNum == 2) {
+ targetReg = stateTable1_2[k].physicalReg;
+ targetSpill = stateTable1_2[k].spill_loc_index;
+ }
+ else if(stateNum == 3) {
+ targetReg = stateTable1_3[k].physicalReg;
+ targetSpill = stateTable1_3[k].spill_loc_index;
+ }
+ else if(stateNum == 4) {
+ targetReg = stateTable1_4[k].physicalReg;
+ targetSpill = stateTable1_4[k].spill_loc_index;
+ }
+
+ /* there exists an ordering problem
+ for example:
+ for a VR, move from memory to a physical reg esi
+ for a temporary regsiter, from esi to ecx
+ if we handle VR first, content of the temporary reg. will be overwritten
+ there are 4 cases:
+ I: a variable is currently in memory and its target is in physical reg
+ II: a variable is currently in a register and its target is in memory
+ III: a variable is currently in a different register
+ IV: a variable is currently in a different memory location (for non-VRs)
+ for GLUE, since it can only be allocated to %ebp, we don't have case III
+ For now, case IV is not handled since it didn't show
+ */
+ if(compileTable[k].physicalReg != targetReg &&
+ isVirtualReg(compileTable[k].physicalType)) {
+ /* handles VR for case I to III */
+
+ if(compileTable[k].physicalReg == PhysicalReg_Null && targetReg != PhysicalReg_Null) {
+ /* handles VR for case I:
+ insert a xfer order from PhysicalReg_Null to targetReg */
+ insertSrcReg(PhysicalReg_Null, targetReg, targetSpill, k);
+#ifdef DEBUG_STATE
+ ALOGI("insert for VR Null %d %d %d", targetReg, targetSpill, k);
+#endif
+ }
+
+ if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg != PhysicalReg_Null) {
+ /* handles VR for case III
+ insert a xfer order from srcReg to targetReg */
+ insertSrcReg(compileTable[k].physicalReg, targetReg, targetSpill, k);
+ }
+
+ if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg == PhysicalReg_Null) {
+ /* handles VR for case II
+ insert a xfer order from srcReg to memory */
+ insertSrcReg(compileTable[k].physicalReg, targetReg, targetSpill, k);
+ }
+ }
+
+ if(compileTable[k].physicalReg != targetReg &&
+ !isVirtualReg(compileTable[k].physicalType)) {
+ /* handles non-VR for case I to III */
+
+ if(compileTable[k].physicalReg == PhysicalReg_Null && targetReg != PhysicalReg_Null) {
+ /* handles non-VR for case I */
+ if(compileTable[k].spill_loc_index < 0) {
+ /* this variable is freed, no need to transfer */
+#ifdef DEBUG_STATE
+ ALOGW("in transferToState spill_loc_index is negative for temporary %d", compileTable[k].regNum);
+#endif
+ } else {
+ /* insert a xfer order from memory to targetReg */
+#ifdef DEBUG_STATE
+ ALOGI("insert Null %d %d %d", targetReg, targetSpill, k);
+#endif
+ insertSrcReg(PhysicalReg_Null, targetReg, targetSpill, k);
+ }
+ }
+
+ if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg != PhysicalReg_Null) {
+ /* handles non-VR for case III
+ insert a xfer order from srcReg to targetReg */
+ insertSrcReg(compileTable[k].physicalReg, targetReg, targetSpill, k);
+ }
+
+ if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg == PhysicalReg_Null) {
+ /* handles non-VR for case II */
+ if(targetSpill < 0) {
+ /* this variable is freed, no need to transfer */
+#ifdef DEBUG_STATE
+ ALOGW("in transferToState spill_loc_index is negative for temporary %d", compileTable[k].regNum);
+#endif
+ } else {
+ /* insert a xfer order from srcReg to memory */
+ insertSrcReg(compileTable[k].physicalReg, targetReg, targetSpill, k);
+ }
+ }
+
+ }
+ }//for compile entries
+
+ int k2;
+#ifdef DEBUG_STATE
+ for(k = 0; k < num_src_regs; k++) {
+ ALOGI("SRCREG %d: ", srcRegs[k].physicalReg);
+ for(k2 = 0; k2 < srcRegs[k].num_dests; k2++) {
+ int index = srcRegs[k].dsts[k2].compileIndex;
+ ALOGI("[%d %d %d: %d %d %d] ", srcRegs[k].dsts[k2].targetReg,
+ srcRegs[k].dsts[k2].targetSpill, srcRegs[k].dsts[k2].compileIndex,
+ compileTable[index].regNum, compileTable[index].physicalType,
+ compileTable[index].spill_loc_index);
+ }
+ ALOGI("");
+ }
+#endif
+
+ /* construct an order: xfers from srcReg first, then xfers from memory */
+ int num_handled = 0;
+ int num_in_order = 0;
+ for(k = 0; k < num_src_regs; k++) {
+ if(srcRegs[k].physicalReg == PhysicalReg_Null) {
+ handledSrc[k] = true;
+ num_handled++;
+ } else {
+ handledSrc[k] = false;
+ }
+ }
+ while(num_handled < num_src_regs) {
+ int prev_handled = num_handled;
+ for(k = 0; k < num_src_regs; k++) {
+ if(handledSrc[k]) continue;
+ bool canHandleNow = true;
+ for(k2 = 0; k2 < srcRegs[k].num_dests; k2++) {
+ if(dstStillInUse(srcRegs[k].dsts[k2].targetReg)) {
+ canHandleNow = false;
+ break;
+ }
+ }
+ if(canHandleNow) {
+ handledSrc[k] = true;
+ num_handled++;
+ handledOrder[num_in_order] = k;
+ num_in_order++;
+ }
+ } //for k
+ if(num_handled == prev_handled) {
+ ALOGE("no progress in selecting order");
+ dvmAbort();
+ }
+ } //while
+ for(k = 0; k < num_src_regs; k++) {
+ if(srcRegs[k].physicalReg == PhysicalReg_Null) {
+ handledOrder[num_in_order] = k;
+ num_in_order++;
+ }
+ }
+ if(num_in_order != num_src_regs) {
+ ALOGE("num_in_order != num_src_regs");
+ dvmAbort();
+ }
+#ifdef DEBUG_STATE
+ ALOGI("ORDER: ");
+ for(k = 0; k < num_src_regs; k++) {
+ ALOGI("%d ", handledOrder[k]);
+ }
+ ALOGI("");
+#endif
+}
+//! transfer the state of register allocator to a state specified in a state table
+
+//!
+void transferToState(int stateNum) {
+ freeReg(false); //do not spill GL
+ int k;
+#ifdef DEBUG_STATE
+ ALOGI("STATE: transfer to state %d", stateNum);
+#endif
+ if(stateNum > 4 || stateNum < 1) ALOGE("state table overflow");
+ constructSrcRegs(stateNum);
+ int k4, k3;
+ for(k4 = 0; k4 < num_src_regs; k4++) {
+ int k2 = handledOrder[k4]; //index to srcRegs
+ for(k3 = 0; k3 < srcRegs[k2].num_dests; k3++) {
+ k = srcRegs[k2].dsts[k3].compileIndex;
+ int targetReg = srcRegs[k2].dsts[k3].targetReg;
+ int targetSpill = srcRegs[k2].dsts[k3].targetSpill;
+ if(compileTable[k].physicalReg != targetReg && isVirtualReg(compileTable[k].physicalType)) {
+ OpndSize oSize = getRegSize(compileTable[k].physicalType);
+ bool isSS = ((compileTable[k].physicalType & MASK_FOR_TYPE) == LowOpndRegType_ss);
+ if(compileTable[k].physicalReg == PhysicalReg_Null && targetReg != PhysicalReg_Null) {
+ if(isSS)
+ move_ss_mem_to_reg_noalloc(4*compileTable[k].regNum,
+ PhysicalReg_FP, true,
+ MemoryAccess_VR, compileTable[k].regNum,
+ targetReg, true);
+ else
+ move_mem_to_reg_noalloc(oSize, 4*compileTable[k].regNum,
+ PhysicalReg_FP, true,
+ MemoryAccess_VR, compileTable[k].regNum,
+ targetReg, true);
+ }
+ if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg != PhysicalReg_Null) {
+ move_reg_to_reg_noalloc((isSS ? OpndSize_64 : oSize),
+ compileTable[k].physicalReg, true,
+ targetReg, true);
+ }
+ if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg == PhysicalReg_Null) {
+ dumpToMem(compileTable[k].regNum, (LowOpndRegType)(compileTable[k].physicalType & MASK_FOR_TYPE),
+ compileTable[k].physicalReg);
+ }
+ } //VR
+ if(compileTable[k].physicalReg != targetReg && !isVirtualReg(compileTable[k].physicalType)) {
+ OpndSize oSize = getRegSize(compileTable[k].physicalType);
+ if(compileTable[k].physicalReg == PhysicalReg_Null && targetReg != PhysicalReg_Null) {
+ loadFromSpillRegion(oSize, targetReg,
+ compileTable[k].spill_loc_index);
+ }
+ //both are not null, move from one to the other
+ if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg != PhysicalReg_Null) {
+ move_reg_to_reg_noalloc(oSize, compileTable[k].physicalReg, true,
+ targetReg, true);
+ }
+ //current is not null, target is null (move from reg to memory)
+ if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg == PhysicalReg_Null) {
+ saveToSpillRegion(oSize, compileTable[k].physicalReg, targetSpill);
+ }
+ } //temporary
+ }//for
+ }//for
+ for(k = 0; k < num_memory_vr; k++) {
+ bool targetBool = false;
+ int targetReg = -1;
+ if(stateNum == 1) {
+ targetReg = stateTable2_1[k].regNum;
+ targetBool = stateTable2_1[k].inMemory;
+ }
+ else if(stateNum == 2) {
+ targetReg = stateTable2_2[k].regNum;
+ targetBool = stateTable2_2[k].inMemory;
+ }
+ else if(stateNum == 3) {
+ targetReg = stateTable2_3[k].regNum;
+ targetBool = stateTable2_3[k].inMemory;
+ }
+ else if(stateNum == 4) {
+ targetReg = stateTable2_4[k].regNum;
+ targetBool = stateTable2_4[k].inMemory;
+ }
+ if(targetReg != memVRTable[k].regNum)
+ ALOGE("regNum mismatch in transferToState");
+ if(targetBool && (!memVRTable[k].inMemory)) {
+ //dump to memory, check entries in compileTable: vA gp vA xmm vA ss
+#ifdef DEBUG_STATE
+ ALOGW("inMemory mismatch for VR %d in transferToState", targetReg);
+#endif
+ bool doneXfer = false;
+ int index = searchCompileTable(LowOpndRegType_xmm | LowOpndRegType_virtual, targetReg);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+ dumpToMem(targetReg, LowOpndRegType_xmm, compileTable[index].physicalReg);
+ doneXfer = true;
+ }
+ if(!doneXfer) { //vA-1, xmm
+ index = searchCompileTable(LowOpndRegType_xmm | LowOpndRegType_virtual, targetReg-1);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+ dumpToMem(targetReg-1, LowOpndRegType_xmm, compileTable[index].physicalReg);
+ doneXfer = true;
+ }
+ }
+ if(!doneXfer) { //vA gp
+ index = searchCompileTable(LowOpndRegType_gp | LowOpndRegType_virtual, targetReg);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+ dumpToMem(targetReg, LowOpndRegType_gp, compileTable[index].physicalReg);
+ doneXfer = true;
+ }
+ }
+ if(!doneXfer) { //vA, ss
+ index = searchCompileTable(LowOpndRegType_ss | LowOpndRegType_virtual, targetReg);
+ if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
+ dumpToMem(targetReg, LowOpndRegType_ss, compileTable[index].physicalReg);
+ doneXfer = true;
+ }
+ }
+ if(!doneXfer) ALOGW("can't match inMemory of VR %d in transferToState", targetReg);
+ }
+ if((!targetBool) && memVRTable[k].inMemory) {
+ //do nothing
+ }
+ }
+#ifdef DEBUG_STATE
+ ALOGI("END transferToState %d", stateNum);
+#endif
+ goToState(stateNum);
+}
+/* END code to handle state transfers */
diff --git a/vm/compiler/codegen/x86/AnalysisO1.h b/vm/compiler/codegen/x86/AnalysisO1.h
new file mode 100644
index 0000000..7f436d9
--- /dev/null
+++ b/vm/compiler/codegen/x86/AnalysisO1.h
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file ncg_o1_data.h
+ \brief A header file to define data structures used by register allocator & const folding
+*/
+#ifndef _DALVIK_NCG_ANALYSISO1_H
+#define _DALVIK_NCG_ANALYSISO1_H
+
+#include "Dalvik.h"
+#include "enc_wrapper.h"
+#include "Lower.h"
+#ifdef WITH_JIT
+#include "compiler/CompilerIR.h"
+#endif
+
+//! maximal number of edges per basic block
+#define MAX_NUM_EDGE_PER_BB 300
+//! maximal number of basic blocks per method
+#define MAX_NUM_BBS_PER_METHOD 1000
+//! maximal number of virtual registers per basic block
+#define MAX_REG_PER_BASICBLOCK 140
+//! maximal number of virtual registers per bytecode
+#define MAX_REG_PER_BYTECODE 40
+//! maximal number of virtual registers per method
+#define MAX_REG_PER_METHOD 200
+//! maximal number of temporaries per bytecode
+#define MAX_TEMP_REG_PER_BYTECODE 30
+//! maximal number of GG GPR VRs in a method
+#define MAX_GLOBAL_VR 2
+//! maximal number of GG XMM VRs in a method
+#define MAX_GLOBAL_VR_XMM 4
+#define MAX_CONST_REG 150
+
+#define MASK_FOR_TYPE 7 //last 3 bits 111
+
+#define LOOP_COUNT 10
+//! maximal number of entries in compileTable
+#define COMPILE_TABLE_SIZE 200
+//! maximal number of transfer points per basic block
+#define MAX_XFER_PER_BB 1000 //on Jan 4
+#define PC_FOR_END_OF_BB -999
+#define PC_FOR_START_OF_BB -998
+
+//! various cases of overlapping between 2 variables
+typedef enum OverlapCase {
+ OVERLAP_ALIGN = 0,
+ OVERLAP_B_IS_LOW_OF_A,
+ OVERLAP_B_IS_HIGH_OF_A,
+ OVERLAP_LOW_OF_A_IS_HIGH_OF_B,
+ OVERLAP_HIGH_OF_A_IS_LOW_OF_B,
+ OVERLAP_A_IS_LOW_OF_B,
+ OVERLAP_A_IS_HIGH_OF_B,
+ OVERLAP_B_COVER_A,
+ OVERLAP_B_COVER_LOW_OF_A,
+ OVERLAP_B_COVER_HIGH_OF_A,
+ OVERLAP_NO
+} OverlapCase;
+
+//!access type of a variable
+typedef enum RegAccessType {
+ REGACCESS_D = 0,
+ REGACCESS_U,
+ REGACCESS_DU,
+ REGACCESS_UD,
+ REGACCESS_L,
+ REGACCESS_H,
+ REGACCESS_UL,
+ REGACCESS_UH,
+ REGACCESS_LU,
+ REGACCESS_HU,
+ REGACCESS_N, //no access
+ REGACCESS_UNKNOWN
+} RegAccessType;
+//! a variable can be local (L), globally local (GL) or global (GG)
+typedef enum GlobalType {
+ GLOBALTYPE_GG,
+ GLOBALTYPE_GL,
+ GLOBALTYPE_L
+} GlobalType;
+typedef enum VRState {
+ VRSTATE_SPILLED,
+ VRSTATE_UPDATED,
+ VRSTATE_CLEAN
+} VRState;
+//! helper state to determine if freeing VRs needs to be delayed
+enum VRDelayFreeFlags {
+ VRDELAY_NONE = 0, // used when VR can be freed from using physical register if needed
+ VRDELAY_NULLCHECK = 1 << 0, // used when VR is used for null check and freeing must be delayed
+ VRDELAY_BOUNDCHECK = 1 << 1 // used when VR is used for bound check and freeing must be delayed
+};
+typedef enum TRState { //state of temporary registers
+ TRSTATE_SPILLED,
+ TRSTATE_UNSPILLED,
+ TRSTATE_CLEAN
+} TRState;
+//!information about a physical register
+typedef struct RegisterInfo {
+ PhysicalReg physicalReg;
+ bool isUsed;
+ bool isCalleeSaved;
+ int freeTimeStamp;
+} RegisterInfo;
+typedef struct UniqueRegister {
+ LowOpndRegType physicalType;
+ int regNum;
+ int numExposedUsage;
+ PhysicalReg physicalReg;
+} UniqueRegister;
+//!specifies the weight of a VR allocated to a specific physical register
+//!it is used for GPR VR only
+typedef struct RegAllocConstraint {
+ PhysicalReg physicalReg;
+ int count;
+} RegAllocConstraint;
+
+typedef enum XferType {
+ XFER_MEM_TO_XMM, //for usage
+ XFER_DEF_TO_MEM, //def is gp
+ XFER_DEF_TO_GP_MEM,
+ XFER_DEF_TO_GP,
+ XFER_DEF_IS_XMM //def is xmm
+} XferType;
+typedef struct XferPoint {
+ int tableIndex; //generated from a def-use pair
+ XferType xtype;
+ int offsetPC;
+ int regNum; //get or set VR at offsetPC
+ LowOpndRegType physicalType;
+
+ //if XFER_DEF_IS_XMM
+ int vr_gpl; //a gp VR that uses the lower half of the def
+ int vr_gph;
+ bool dumpToXmm;
+ bool dumpToMem;
+} XferPoint;
+
+//!for def: accessType means which part of the VR defined at offestPC is live now
+//!for use: accessType means which part of the usage comes from the reachingDef
+typedef struct DefOrUse {
+ int offsetPC; //!the program point
+ int regNum; //!access the virtual reg
+ LowOpndRegType physicalType; //!xmm or gp or ss
+ RegAccessType accessType; //!D, L, H, N
+} DefOrUse;
+//!a link list of DefOrUse
+typedef struct DefOrUseLink {
+ int offsetPC;
+ int regNum; //access the virtual reg
+ LowOpndRegType physicalType; //xmm or gp
+ RegAccessType accessType; //D, L, H, N
+ struct DefOrUseLink* next;
+} DefOrUseLink;
+//!pair of def and uses
+typedef struct DefUsePair {
+ DefOrUseLink* uses;
+ DefOrUseLink* useTail;
+ int num_uses;
+ DefOrUse def;
+ struct DefUsePair* next;
+} DefUsePair;
+
+//!information associated with a virtual register
+//!the pair <regNum, physicalType> uniquely determines a variable
+typedef struct VirtualRegInfo {
+ int regNum;
+ LowOpndRegType physicalType;
+ int refCount;
+ RegAccessType accessType;
+ GlobalType gType;
+ int physicalReg_GG;
+ RegAllocConstraint allocConstraints[8];
+ RegAllocConstraint allocConstraintsSorted[8];
+
+ DefOrUse reachingDefs[3]; //!reaching defs to the virtual register
+ int num_reaching_defs;
+} VirtualRegInfo;
+//!information of whether a VR is constant and its value
+typedef struct ConstVRInfo {
+ int regNum;
+ int value;
+ bool isConst;
+} ConstVRInfo;
+#define NUM_ACCESS_IN_LIVERANGE 10
+//!specifies one live range
+typedef struct LiveRange {
+ int start;
+ int end; //inclusive
+ //all accesses in the live range
+ int num_access;
+ int num_alloc;
+ int* accessPC;
+ struct LiveRange* next;
+} LiveRange;
+typedef struct BoundCheckIndex {
+ int indexVR;
+ bool checkDone;
+} BoundCheckIndex;
+//!information for a virtual register such as live ranges, in memory
+typedef struct MemoryVRInfo {
+ int regNum;
+ bool inMemory;
+ bool nullCheckDone;
+ BoundCheckIndex boundCheck;
+ int num_ranges;
+ LiveRange* ranges;
+ u4 delayFreeFlags; //! for use with flags defined by VRDelayFreeFlags enum
+} MemoryVRInfo;
+//!information of a temporary
+//!the pair <regNum, physicalType> uniquely determines a variable
+typedef struct TempRegInfo {
+ int regNum;
+ int physicalType;
+ int refCount;
+ int linkageToVR;
+ int versionNum;
+ bool shareWithVR; //for temp. regs updated by get_virtual_reg
+ bool is8Bit;
+} TempRegInfo;
+struct BasicBlock_O1;
+//!all variables accessed
+//!the pair <regNum, physicalType> uniquely determines a variable
+typedef struct compileTableEntry {
+ int regNum;
+ int physicalType; //gp, xmm or scratch, virtual
+ int physicalReg;
+ int physicalReg_prev; //for spilled GG VR
+ RegAccessType accessType;
+
+ bool isConst;
+ int value[2]; //[0]: lower [1]: higher
+ int refCount;
+
+ int linkageToVR; //for temporary registers only
+ GlobalType gType;
+ struct BasicBlock_O1* bb; //bb VR belongs to
+ int indexToInfoBB;
+
+ VRState regState;
+ TRState trState; //for temporary registers only
+ int spill_loc_index; //for temporary registers only
+} compileTableEntry;
+//!to save the state of register allocator
+typedef struct regAllocStateEntry1 {
+ int spill_loc_index;
+ int physicalReg;
+} regAllocStateEntry1;
+typedef struct regAllocStateEntry2 {
+ int regNum; //
+ bool inMemory; //whether 4-byte virtual reg is in memory
+} regAllocStateEntry2;
+//!edge in control flow graph
+typedef struct Edge_O1 {
+ struct BasicBlock_O1* src;
+ struct BasicBlock_O1* dst;
+} Edge_O1;
+//!information associated with a basic block
+typedef struct BasicBlock_O1 {
+ int bb_index;
+ int bb_index2;
+ int pc_start; //!inclusive
+#ifndef WITH_JIT
+ int pc_end; //!exclusive
+ Edge_O1* in_edges[MAX_NUM_EDGE_PER_BB]; //array of Edge*
+ int num_in_edges;
+ Edge_O1* out_edges[MAX_NUM_EDGE_PER_BB];
+ int num_out_edges;
+#else
+ int pc_end;
+ BasicBlock* jitBasicBlock;
+#endif
+ VirtualRegInfo infoBasicBlock[MAX_REG_PER_BASICBLOCK];
+ int num_regs;
+
+ RegAllocConstraint allocConstraints[8]; //# of times a hardcoded register is used in this basic block
+ //a physical register that is used many times has a lower priority to get picked in getFreeReg
+ RegAllocConstraint allocConstraintsSorted[8]; //count from low to high
+
+ DefUsePair* defUseTable;
+ DefUsePair* defUseTail;
+ int num_defs;
+ XferPoint xferPoints[MAX_XFER_PER_BB]; //program points where the transfer is required
+ int num_xfer_points;
+
+ bool endsWithReturn;
+ bool hasAccessToGlue;
+} BasicBlock_O1;
+typedef struct CFG_O1 {
+ BasicBlock_O1* head;
+} CFG_O1;
+//!worklist to create a control flow graph
+typedef struct CFGWork {
+ BasicBlock_O1* bb_prev;
+ int targetOff;
+ struct CFGWork* nextItem;
+} CFGWork;
+
+/////////////////////////////////////////
+extern compileTableEntry compileTable[COMPILE_TABLE_SIZE];
+extern int num_compile_entries;
+extern VirtualRegInfo infoByteCode[MAX_REG_PER_BYTECODE];
+extern int num_regs_per_bytecode;
+extern TempRegInfo infoByteCodeTemp[MAX_TEMP_REG_PER_BYTECODE];
+extern int num_temp_regs_per_bytecode;
+extern VirtualRegInfo infoMethod[MAX_REG_PER_METHOD];
+extern int num_regs_per_method;
+extern BasicBlock_O1* currentBB;
+
+extern BasicBlock_O1* method_bbs[MAX_NUM_BBS_PER_METHOD];
+extern int num_bbs_for_method;
+extern BasicBlock_O1* method_bbs_sorted[MAX_NUM_BBS_PER_METHOD];
+extern BasicBlock_O1* bb_entry;
+extern int pc_start;
+extern int pc_end;
+extern int current_bc_size;
+extern int num_exception_handlers;
+extern int exceptionHandlers[10];
+
+extern int num_const_vr;
+extern ConstVRInfo constVRTable[MAX_CONST_REG];
+
+extern int genSet[MAX_REG_PER_BYTECODE];
+extern int killSet[MAX_REG_PER_BYTECODE];
+extern int num_regs_gen; //per bytecode
+extern int num_regs_kill; //per bytecode
+
+extern int genSetBB[MAX_NUM_BBS_PER_METHOD][40];
+extern int killSetBB[MAX_NUM_BBS_PER_METHOD][40]; //same as size of memVRTable
+extern int num_gen_bb[MAX_NUM_BBS_PER_METHOD];
+extern int num_kill_bb[MAX_NUM_BBS_PER_METHOD];
+
+extern int nullCheck_inB[MAX_NUM_BBS_PER_METHOD][40];
+extern int nullCheck_inSize[MAX_NUM_BBS_PER_METHOD];
+extern int nullCheck_outB[MAX_NUM_BBS_PER_METHOD][40];
+extern int nullCheck_outSize[MAX_NUM_BBS_PER_METHOD];
+
+typedef enum GlueVarType {
+ RES_CLASS = 0,
+ RES_METHOD,
+ RES_FIELD,
+ RES_STRING,
+ GLUE_DVMDEX,
+ GLUE_METHOD_CLASS,
+ GLUE_METHOD
+} GlueVarType;
+
+void forwardAnalysis(int type);
+
+//functions in bc_visitor.c
+int getByteCodeSize();
+bool getConstInfo(BasicBlock_O1* bb);
+int getVirtualRegInfo(VirtualRegInfo* infoArray);
+int getTempRegInfo(TempRegInfo* infoArray);
+int createCFGHandler(Method* method);
+
+int findVirtualRegInTable(u2 vA, LowOpndRegType type, bool printError);
+int searchCompileTable(int type, int regNum);
+BasicBlock_O1* createBasicBlock(int src_pc, int end_pc);
+void handleJump(BasicBlock_O1* bb_prev, int relOff);
+void connectBasicBlock(BasicBlock_O1* src, BasicBlock_O1* dst);
+int insertWorklist(BasicBlock_O1* bb_prev, int targetOff);
+
+int collectInfoOfBasicBlock(Method* method, BasicBlock_O1* bb); //update bb->infoBasicBlock
+
+void updateCurrentBBWithConstraints(PhysicalReg reg);
+void updateConstInfo(BasicBlock_O1*);
+OpndSize getRegSize(int type);
+void invalidateVRDueToConst(int reg, OpndSize size);
+#endif
+
diff --git a/vm/compiler/codegen/x86/ArchUtility.cpp b/vm/compiler/codegen/x86/ArchUtility.cpp
deleted file mode 100644
index f7c48d6..0000000
--- a/vm/compiler/codegen/x86/ArchUtility.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "../../CompilerInternals.h"
-#include "libdex/DexOpcodes.h"
-#include "X86LIR.h"
-
-/* Dump instructions and constant pool contents */
-void dvmCompilerCodegenDump(CompilationUnit *cUnit)
-{
-}
-
-/* Target-specific cache flushing (not needed for x86 */
-int dvmCompilerCacheFlush(long start, long end, long flags)
-{
- return 0;
-}
diff --git a/vm/compiler/codegen/x86/Assemble.cpp b/vm/compiler/codegen/x86/Assemble.cpp
deleted file mode 100644
index 03edbf1..0000000
--- a/vm/compiler/codegen/x86/Assemble.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Dalvik.h"
-#include "libdex/DexOpcodes.h"
-
-#include "../../CompilerInternals.h"
-#include "X86LIR.h"
-#include "Codegen.h"
-#include <sys/mman.h> /* for protection change */
-
-#define MAX_ASSEMBLER_RETRIES 10
-
-
-/* Track the number of times that the code cache is patched */
-#if defined(WITH_JIT_TUNING)
-#define UPDATE_CODE_CACHE_PATCHES() (gDvmJit.codeCachePatches++)
-#else
-#define UPDATE_CODE_CACHE_PATCHES()
-#endif
-
-/*
- * Translation layout in the code cache. Note that the codeAddress pointer
- * in JitTable will point directly to the code body (field codeAddress). The
- * chain cell offset codeAddress - 2, and (if present) executionCount is at
- * codeAddress - 6.
- *
- * +----------------------------+
- * | Execution count | -> [Optional] 4 bytes
- * +----------------------------+
- * +--| Offset to chain cell counts| -> 2 bytes
- * | +----------------------------+
- * | | Code body | -> Start address for translation
- * | | | variable in 2-byte chunks
- * | . . (JitTable's codeAddress points here)
- * | . .
- * | | |
- * | +----------------------------+
- * | | Chaining Cells | -> 16 bytes each, 8 byte aligned
- * | . .
- * | . .
- * | | |
- * | +----------------------------+
- * | | Gap for large switch stmt | -> # cases >= MAX_CHAINED_SWITCH_CASES
- * | +----------------------------+
- * +->| Chaining cell counts | -> 8 bytes, chain cell counts by type
- * +----------------------------+
- * | Trace description | -> variable sized
- * . .
- * | |
- * +----------------------------+
- * | Literal pool | -> 4-byte aligned, variable size
- * . . Note: for x86 literals will
- * . . generally appear inline.
- * | |
- * +----------------------------+
- *
- * Go over each instruction in the list and calculate the offset from the top
- * before sending them off to the assembler. If out-of-range branch distance is
- * seen rearrange the instructions a bit to correct it.
- */
-void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
-{
-}
-
-/*
- * Perform translation chain operation.
- */
-void* dvmJitChain(void* tgtAddr, u4* branchAddr)
-{
- return 0;
-}
-
-/*
- * This method is called from the invoke templates for virtual and interface
- * methods to speculatively setup a chain to the callee. The templates are
- * written in assembly and have setup method, cell, and clazz at r0, r2, and
- * r3 respectively, so there is a unused argument in the list. Upon return one
- * of the following three results may happen:
- * 1) Chain is not setup because the callee is native. Reset the rechain
- * count to a big number so that it will take a long time before the next
- * rechain attempt to happen.
- * 2) Chain is not setup because the callee has not been created yet. Reset
- * the rechain count to a small number and retry in the near future.
- * 3) Enqueue the new content for the chaining cell which will be appled in
- * next safe point.
- */
-const Method *dvmJitToPatchPredictedChain(const Method *method,
- Thread *self,
- PredictedChainingCell *cell,
- const ClassObject *clazz)
-{
- return 0;
-}
-
-/*
- * Patch the inline cache content based on the content passed from the work
- * order.
- */
-void dvmCompilerPatchInlineCache(void)
-{
-}
-
-/*
- * Unchain a trace given the starting address of the translation
- * in the code cache. Refer to the diagram in dvmCompilerAssembleLIR.
- * Returns the address following the last cell unchained. Note that
- * the incoming codeAddr is a thumb code address, and therefore has
- * the low bit set.
- */
-u4* dvmJitUnchain(void* codeAddr)
-{
- return 0;
-}
-
-/* Unchain all translation in the cache. */
-void dvmJitUnchainAll()
-{
-}
-
-/* Create a copy of the trace descriptor of an existing compilation */
-JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
- const JitEntry *knownEntry)
-{
- return 0;
-}
-
-/* Sort the trace profile counts and dump them */
-void dvmCompilerSortAndPrintTraceProfiles()
-{
-}
-
-void dvmJitScanAllClassPointers(void (*callback)(void *))
-{
-}
diff --git a/vm/compiler/codegen/x86/BytecodeVisitor.cpp b/vm/compiler/codegen/x86/BytecodeVisitor.cpp
new file mode 100644
index 0000000..1d3c70e
--- /dev/null
+++ b/vm/compiler/codegen/x86/BytecodeVisitor.cpp
@@ -0,0 +1,5468 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file BytecodeVisitor.cpp
+ \brief This file implements visitors of the bytecode
+*/
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "Lower.h"
+#include "AnalysisO1.h"
+
+//! Returns size of the current bytecode in u2 unit
+
+//!
+int getByteCodeSize() { //uses inst, unit in u2
+ switch (INST_INST(inst)) {
+ case OP_NOP:
+ return 1;
+ case OP_MOVE:
+ case OP_MOVE_OBJECT:
+ return 1;
+ case OP_MOVE_FROM16:
+ case OP_MOVE_OBJECT_FROM16:
+ return 2;
+ case OP_MOVE_16:
+ case OP_MOVE_OBJECT_16:
+ return 3;
+ case OP_MOVE_WIDE:
+ return 1;
+ case OP_MOVE_WIDE_FROM16:
+ return 2;
+ case OP_MOVE_WIDE_16:
+ return 3;
+ case OP_MOVE_RESULT:
+ case OP_MOVE_RESULT_OBJECT:
+ return 1;
+ case OP_MOVE_RESULT_WIDE:
+ return 1;
+ case OP_MOVE_EXCEPTION:
+ return 1;
+ case OP_RETURN_VOID:
+ case OP_RETURN_VOID_BARRIER:
+ return 1;
+ case OP_RETURN:
+ case OP_RETURN_OBJECT:
+ return 1;
+ case OP_RETURN_WIDE:
+ return 1;
+ case OP_CONST_4:
+ return 1;
+ case OP_CONST_16:
+ return 2;
+ case OP_CONST:
+ return 3;
+ case OP_CONST_HIGH16:
+ return 2;
+ case OP_CONST_WIDE_16:
+ return 2;
+ case OP_CONST_WIDE_32:
+ return 3;
+ case OP_CONST_WIDE:
+ return 5;
+ case OP_CONST_WIDE_HIGH16:
+ return 2;
+ case OP_CONST_STRING:
+ return 2;
+ case OP_CONST_STRING_JUMBO:
+ return 3;
+ case OP_CONST_CLASS:
+ return 2;
+ case OP_MONITOR_ENTER:
+ return 1;
+ case OP_MONITOR_EXIT:
+ return 1;
+ case OP_CHECK_CAST:
+ return 2;
+ case OP_INSTANCE_OF:
+ return 2;
+ case OP_ARRAY_LENGTH:
+ return 1;
+ case OP_NEW_INSTANCE:
+ return 2;
+ case OP_NEW_ARRAY:
+ return 2;
+ case OP_FILLED_NEW_ARRAY:
+ return 3;
+ case OP_FILLED_NEW_ARRAY_RANGE:
+ return 3;
+ case OP_FILL_ARRAY_DATA:
+ return 3;
+ case OP_THROW:
+ return 1;
+ case OP_THROW_VERIFICATION_ERROR:
+ return 2;
+ case OP_GOTO:
+ return 1;
+ case OP_GOTO_16:
+ return 2;
+ case OP_GOTO_32:
+ return 3;
+ case OP_PACKED_SWITCH:
+ return 3;
+ case OP_SPARSE_SWITCH:
+ return 3;
+ case OP_CMPL_FLOAT:
+ return 2;
+ case OP_CMPG_FLOAT:
+ return 2;
+ case OP_CMPL_DOUBLE:
+ return 2;
+ case OP_CMPG_DOUBLE:
+ return 2;
+ case OP_CMP_LONG:
+ return 2;
+ case OP_IF_EQ:
+ return 2;
+ case OP_IF_NE:
+ return 2;
+ case OP_IF_LT:
+ return 2;
+ case OP_IF_GE:
+ return 2;
+ case OP_IF_GT:
+ return 2;
+ case OP_IF_LE:
+ return 2;
+ case OP_IF_EQZ:
+ return 2;
+ case OP_IF_NEZ:
+ return 2;
+ case OP_IF_LTZ:
+ return 2;
+ case OP_IF_GEZ:
+ return 2;
+ case OP_IF_GTZ:
+ return 2;
+ case OP_IF_LEZ:
+ return 2;
+ case OP_AGET:
+ return 2;
+ case OP_AGET_WIDE:
+ return 2;
+ case OP_AGET_OBJECT:
+ return 2;
+ case OP_AGET_BOOLEAN:
+ return 2;
+ case OP_AGET_BYTE:
+ return 2;
+ case OP_AGET_CHAR:
+ return 2;
+ case OP_AGET_SHORT:
+ return 2;
+ case OP_APUT:
+ return 2;
+ case OP_APUT_WIDE:
+ return 2;
+ case OP_APUT_OBJECT:
+ return 2;
+ case OP_APUT_BOOLEAN:
+ return 2;
+ case OP_APUT_BYTE:
+ return 2;
+ case OP_APUT_CHAR:
+ return 2;
+ case OP_APUT_SHORT:
+ return 2;
+ case OP_IGET:
+ case OP_IGET_WIDE:
+ case OP_IGET_OBJECT:
+ case OP_IGET_VOLATILE:
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IGET_OBJECT_VOLATILE:
+ case OP_IGET_BOOLEAN:
+ case OP_IGET_BYTE:
+ case OP_IGET_CHAR:
+ case OP_IGET_SHORT:
+ case OP_IPUT:
+ case OP_IPUT_WIDE:
+ case OP_IPUT_OBJECT:
+ case OP_IPUT_VOLATILE:
+ case OP_IPUT_WIDE_VOLATILE:
+ case OP_IPUT_OBJECT_VOLATILE:
+ case OP_IPUT_BOOLEAN:
+ case OP_IPUT_BYTE:
+ case OP_IPUT_CHAR:
+ case OP_IPUT_SHORT:
+ return 2;
+ case OP_SGET:
+ case OP_SGET_WIDE:
+ case OP_SGET_OBJECT:
+ case OP_SGET_VOLATILE:
+ case OP_SGET_WIDE_VOLATILE:
+ case OP_SGET_OBJECT_VOLATILE:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_BYTE:
+ case OP_SGET_CHAR:
+ case OP_SGET_SHORT:
+ case OP_SPUT:
+ case OP_SPUT_WIDE:
+ case OP_SPUT_OBJECT:
+ case OP_SPUT_VOLATILE:
+ case OP_SPUT_WIDE_VOLATILE:
+ case OP_SPUT_OBJECT_VOLATILE:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_SHORT:
+ return 2;
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_INTERFACE:
+ case OP_INVOKE_VIRTUAL_RANGE:
+ case OP_INVOKE_SUPER_RANGE:
+ case OP_INVOKE_DIRECT_RANGE:
+ case OP_INVOKE_STATIC_RANGE:
+ case OP_INVOKE_INTERFACE_RANGE:
+ return 3;
+
+ case OP_NEG_INT:
+ case OP_NOT_INT:
+ case OP_NEG_LONG:
+ case OP_NOT_LONG:
+ case OP_NEG_FLOAT:
+ case OP_NEG_DOUBLE:
+ case OP_INT_TO_LONG:
+ case OP_INT_TO_FLOAT:
+ case OP_INT_TO_DOUBLE:
+ case OP_LONG_TO_INT:
+ case OP_LONG_TO_FLOAT:
+ case OP_LONG_TO_DOUBLE:
+ case OP_FLOAT_TO_INT:
+ case OP_FLOAT_TO_LONG:
+ case OP_FLOAT_TO_DOUBLE:
+ case OP_DOUBLE_TO_INT:
+ case OP_DOUBLE_TO_LONG:
+ case OP_DOUBLE_TO_FLOAT:
+ case OP_INT_TO_BYTE:
+ case OP_INT_TO_CHAR:
+ case OP_INT_TO_SHORT:
+ return 1;
+
+ case OP_ADD_INT:
+ case OP_SUB_INT:
+ case OP_MUL_INT:
+ case OP_DIV_INT:
+ case OP_REM_INT:
+ case OP_AND_INT:
+ case OP_OR_INT:
+ case OP_XOR_INT:
+ case OP_SHL_INT:
+ case OP_SHR_INT:
+ case OP_USHR_INT:
+ case OP_ADD_LONG:
+ case OP_SUB_LONG:
+ case OP_MUL_LONG:
+ case OP_DIV_LONG:
+ case OP_REM_LONG:
+ case OP_AND_LONG:
+ case OP_OR_LONG:
+ case OP_XOR_LONG:
+ case OP_SHL_LONG:
+ case OP_SHR_LONG:
+ case OP_USHR_LONG:
+ case OP_ADD_FLOAT:
+ case OP_SUB_FLOAT:
+ case OP_MUL_FLOAT:
+ case OP_DIV_FLOAT:
+ case OP_REM_FLOAT:
+ case OP_ADD_DOUBLE:
+ case OP_SUB_DOUBLE:
+ case OP_MUL_DOUBLE:
+ case OP_DIV_DOUBLE:
+ case OP_REM_DOUBLE:
+ return 2;
+
+ case OP_ADD_INT_2ADDR:
+ case OP_SUB_INT_2ADDR:
+ case OP_MUL_INT_2ADDR:
+ case OP_DIV_INT_2ADDR:
+ case OP_REM_INT_2ADDR:
+ case OP_AND_INT_2ADDR:
+ case OP_OR_INT_2ADDR:
+ case OP_XOR_INT_2ADDR:
+ case OP_SHL_INT_2ADDR:
+ case OP_SHR_INT_2ADDR:
+ case OP_USHR_INT_2ADDR:
+ case OP_ADD_LONG_2ADDR:
+ case OP_SUB_LONG_2ADDR:
+ case OP_MUL_LONG_2ADDR:
+ case OP_DIV_LONG_2ADDR:
+ case OP_REM_LONG_2ADDR:
+ case OP_AND_LONG_2ADDR:
+ case OP_OR_LONG_2ADDR:
+ case OP_XOR_LONG_2ADDR:
+ case OP_SHL_LONG_2ADDR:
+ case OP_SHR_LONG_2ADDR:
+ case OP_USHR_LONG_2ADDR:
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_REM_FLOAT_2ADDR:
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE_2ADDR:
+ case OP_REM_DOUBLE_2ADDR:
+ return 1;
+
+ case OP_ADD_INT_LIT16:
+ case OP_RSUB_INT:
+ case OP_MUL_INT_LIT16:
+ case OP_DIV_INT_LIT16:
+ case OP_REM_INT_LIT16:
+ case OP_AND_INT_LIT16:
+ case OP_OR_INT_LIT16:
+ case OP_XOR_INT_LIT16:
+ return 2;
+
+ case OP_ADD_INT_LIT8:
+ case OP_RSUB_INT_LIT8:
+ case OP_MUL_INT_LIT8:
+ case OP_DIV_INT_LIT8:
+ case OP_REM_INT_LIT8:
+ case OP_AND_INT_LIT8:
+ case OP_OR_INT_LIT8:
+ case OP_XOR_INT_LIT8:
+ case OP_SHL_INT_LIT8:
+ case OP_SHR_INT_LIT8:
+ case OP_USHR_INT_LIT8:
+ return 2;
+
+ case OP_EXECUTE_INLINE:
+ case OP_EXECUTE_INLINE_RANGE:
+ return 3;
+#if FIXME
+ case OP_INVOKE_OBJECT_INIT_RANGE:
+ return 3;
+#endif
+
+ case OP_IGET_QUICK:
+ case OP_IGET_WIDE_QUICK:
+ case OP_IGET_OBJECT_QUICK:
+ case OP_IPUT_QUICK:
+ case OP_IPUT_WIDE_QUICK:
+ case OP_IPUT_OBJECT_QUICK:
+ return 2;
+
+ case OP_INVOKE_VIRTUAL_QUICK:
+ case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+ case OP_INVOKE_SUPER_QUICK:
+ case OP_INVOKE_SUPER_QUICK_RANGE:
+ return 3;
+#ifdef SUPPORT_HLO
+ case kExtInstruction:
+ switch(inst) {
+ case OP_X_AGET_QUICK:
+ case OP_X_AGET_WIDE_QUICK:
+ case OP_X_AGET_OBJECT_QUICK:
+ case OP_X_AGET_BOOLEAN_QUICK:
+ case OP_X_AGET_BYTE_QUICK:
+ case OP_X_AGET_CHAR_QUICK:
+ case OP_X_AGET_SHORT_QUICK:
+ case OP_X_APUT_QUICK:
+ case OP_X_APUT_WIDE_QUICK:
+ case OP_X_APUT_OBJECT_QUICK:
+ case OP_X_APUT_BOOLEAN_QUICK:
+ case OP_X_APUT_BYTE_QUICK:
+ case OP_X_APUT_CHAR_QUICK:
+ case OP_X_APUT_SHORT_QUICK:
+ return 3;
+ case OP_X_DEREF_GET:
+ case OP_X_DEREF_GET_OBJECT:
+ case OP_X_DEREF_GET_WIDE:
+ case OP_X_DEREF_GET_BOOLEAN:
+ case OP_X_DEREF_GET_BYTE:
+ case OP_X_DEREF_GET_CHAR:
+ case OP_X_DEREF_GET_SHORT:
+ case OP_X_DEREF_PUT:
+ case OP_X_DEREF_PUT_WIDE:
+ case OP_X_DEREF_PUT_OBJECT:
+ case OP_X_DEREF_PUT_BOOLEAN:
+ case OP_X_DEREF_PUT_BYTE:
+ case OP_X_DEREF_PUT_CHAR:
+ case OP_X_DEREF_PUT_SHORT:
+ return 2;
+ case OP_X_ARRAY_CHECKS:
+ case OP_X_ARRAY_OBJECT_CHECKS:
+ return 3;
+ case OP_X_CHECK_BOUNDS:
+ case OP_X_CHECK_NULL:
+ case OP_X_CHECK_TYPE:
+ return 2;
+ }
+#endif
+ }
+ return -1;
+}
+//! reduces refCount of a virtual register
+
+//!
+void touchOneVR(u2 vA, LowOpndRegType type) {
+ int index = searchCompileTable(LowOpndRegType_virtual | type, vA);
+ if(index < 0) {
+ ALOGE("virtual reg %d type %d not found in touchOneVR", vA, type);
+ return;
+ }
+ compileTable[index].refCount--;
+}
+//! reduces refCount of two virtual registers
+
+//!
+void touchTwoVRs(u2 vA, u2 vB, LowOpndRegType type) {
+ int index = searchCompileTable(LowOpndRegType_virtual | type, vA);
+ if(index < 0) {
+ ALOGE("virtual reg vA %d type %d not found in touchTwoVRs", vA, type);
+ return;
+ }
+ compileTable[index].refCount--;
+ index = searchCompileTable(LowOpndRegType_virtual | type, vB);
+ if(index < 0) {
+ ALOGE("virtual reg vB %d type %d not found in touchTwoVRs", vB, type);
+ return;
+ }
+ compileTable[index].refCount--;
+}
+int num_const_worklist;
+//! worklist to update constVRTable later
+int constWorklist[10];
+
+int num_const_vr; //in a basic block
+//! table to store the constant information for virtual registers
+ConstVRInfo constVRTable[MAX_CONST_REG];
+//! update constVRTable for a given virtual register
+
+//! set "isConst" to false
+void setVRToNonConst(int regNum, OpndSize size) {
+ int k;
+ int indexL = -1;
+ int indexH = -1;
+ for(k = 0; k < num_const_vr; k++) {
+ if(constVRTable[k].regNum == regNum) {
+ indexL = k;
+ continue;
+ }
+ if(constVRTable[k].regNum == regNum + 1 && size == OpndSize_64) {
+ indexH = k;
+ continue;
+ }
+ }
+ if(indexL >= 0) {
+ //remove this entry??
+ constVRTable[indexL].isConst = false;
+ }
+ if(size == OpndSize_64 && indexH >= 0) {
+ constVRTable[indexH].isConst = false;
+ }
+}
+//! update constVRTable for a given virtual register
+
+//! set "isConst" to true
+void setVRToConst(int regNum, OpndSize size, int* tmpValue) {
+ int k;
+ int indexL = -1;
+ int indexH = -1;
+ for(k = 0; k < num_const_vr; k++) {
+ if(constVRTable[k].regNum == regNum) {
+ indexL = k;
+ continue;
+ }
+ if(constVRTable[k].regNum == regNum + 1 && size == OpndSize_64) {
+ indexH = k;
+ continue;
+ }
+ }
+ if(indexL < 0) {
+ indexL = num_const_vr;
+ constVRTable[indexL].regNum = regNum;
+ num_const_vr++;
+ }
+ constVRTable[indexL].isConst = true;
+ constVRTable[indexL].value = tmpValue[0];
+ if(size == OpndSize_64) {
+ if(indexH < 0) {
+ indexH = num_const_vr;
+ constVRTable[indexH].regNum = regNum+1;
+ num_const_vr++;
+ }
+ constVRTable[indexH].isConst = true;
+ constVRTable[indexH].value = tmpValue[1];
+ }
+ if(num_const_vr > MAX_CONST_REG) ALOGE("constVRTable overflows");
+ invalidateVRDueToConst(regNum, size);
+}
+
+//! perform work on constWorklist
+
+//!
+void updateConstInfo(BasicBlock_O1* bb) {
+ if(bb == NULL) return;
+ int k;
+ for(k = 0; k < num_const_worklist; k++) {
+ //int indexOrig = constWorklist[k];
+ //compileTable[indexOrig].isConst = false;
+ //int A = compileTable[indexOrig].regNum;
+ //LowOpndRegType type = compileTable[indexOrig].physicalType & MASK_FOR_TYPE;
+ setVRToNonConst(constWorklist[k], OpndSize_32);
+ }
+}
+//! check whether the current bytecode generates a const
+
+//! if yes, update constVRTable; otherwise, update constWorklist
+//! if a bytecode uses vA (const), and updates vA to non const, getConstInfo will return false and update constWorklist to make sure when lowering the bytecode, vA is treated as constant
+bool getConstInfo(BasicBlock_O1* bb) {
+ compileTableEntry* infoArray = compileTable;
+ u2 inst_op = INST_INST(inst);
+ u2 vA = 0, vB = 0, v1, v2;
+ u2 BBBB;
+ u2 tmp_u2;
+ s4 tmp_s4;
+ u4 tmp_u4;
+ int entry, tmpValue[2], tmpValue2[2];
+ num_const_worklist = 0;
+
+ switch(inst_op) {
+ //for other opcode, if update the register, set isConst to false
+ case OP_MOVE:
+ case OP_MOVE_OBJECT:
+ case OP_MOVE_FROM16:
+ case OP_MOVE_OBJECT_FROM16:
+ case OP_MOVE_16:
+ case OP_MOVE_OBJECT_16:
+ if(inst_op == OP_MOVE || inst_op == OP_MOVE_OBJECT) {
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ }
+ else if(inst_op == OP_MOVE_FROM16 || inst_op == OP_MOVE_OBJECT_FROM16) {
+ vA = INST_AA(inst);
+ vB = FETCH(1);
+ }
+ else if(inst_op == OP_MOVE_16 || inst_op == OP_MOVE_OBJECT_16) {
+ vA = FETCH(1);
+ vB = FETCH(2);
+ }
+ if(isVirtualRegConstant(vB, LowOpndRegType_gp, tmpValue, false) == 3) {
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ setVRToConst(vA, OpndSize_32, tmpValue);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = tmpValue[0];
+ compileTable[entry].refCount--;
+ touchOneVR(vB, LowOpndRegType_gp);
+ return true;
+ } else {
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ }
+ return false;
+ case OP_MOVE_WIDE:
+ case OP_MOVE_WIDE_FROM16:
+ case OP_MOVE_WIDE_16:
+ if(inst_op == OP_MOVE_WIDE) {
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ }
+ else if(inst_op == OP_MOVE_WIDE_FROM16) {
+ vA = INST_AA(inst);
+ vB = FETCH(1);
+ }
+ else if(inst_op == OP_MOVE_WIDE_16) {
+ vA = FETCH(1);
+ vB = FETCH(2);
+ }
+ if(isVirtualRegConstant(vB, LowOpndRegType_xmm, tmpValue, false) == 3) {
+ entry = findVirtualRegInTable(vA, LowOpndRegType_xmm, true);
+ setVRToConst(vA, OpndSize_64, tmpValue);
+ compileTable[entry].refCount--;
+ touchOneVR(vB, LowOpndRegType_xmm);
+ return true;
+ } else {
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1;
+ num_const_worklist++;
+ }
+ return false;
+ case OP_MOVE_RESULT:
+ case OP_MOVE_RESULT_OBJECT:
+ case OP_MOVE_EXCEPTION:
+ case OP_CONST_STRING:
+ case OP_CONST_STRING_JUMBO:
+ case OP_CONST_CLASS:
+ case OP_NEW_INSTANCE:
+ case OP_CMPL_FLOAT:
+ case OP_CMPG_FLOAT:
+ case OP_CMPL_DOUBLE:
+ case OP_CMPG_DOUBLE:
+ case OP_AGET:
+ case OP_AGET_OBJECT:
+ case OP_AGET_BOOLEAN:
+ case OP_AGET_BYTE:
+ case OP_AGET_CHAR:
+ case OP_AGET_SHORT:
+ case OP_SGET:
+ case OP_SGET_OBJECT:
+ case OP_SGET_VOLATILE:
+ case OP_SGET_OBJECT_VOLATILE:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_BYTE:
+ case OP_SGET_CHAR:
+ case OP_SGET_SHORT:
+ vA = INST_AA(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ case OP_MOVE_RESULT_WIDE:
+ case OP_AGET_WIDE:
+ case OP_SGET_WIDE:
+ case OP_SGET_WIDE_VOLATILE:
+ vA = INST_AA(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1;
+ num_const_worklist++;
+ return false;
+ case OP_INSTANCE_OF:
+ case OP_ARRAY_LENGTH:
+ case OP_NEW_ARRAY:
+ case OP_IGET:
+ case OP_IGET_OBJECT:
+ case OP_IGET_VOLATILE:
+ case OP_IGET_OBJECT_VOLATILE:
+ case OP_IGET_BOOLEAN:
+ case OP_IGET_BYTE:
+ case OP_IGET_CHAR:
+ case OP_IGET_SHORT:
+ case OP_IGET_QUICK:
+ case OP_IGET_OBJECT_QUICK:
+ vA = INST_A(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ case OP_IGET_WIDE:
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IGET_WIDE_QUICK:
+ vA = INST_A(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1;
+ num_const_worklist++;
+ return false;
+ //TODO: constant folding for float/double/long ALU
+ case OP_ADD_FLOAT:
+ case OP_SUB_FLOAT:
+ case OP_MUL_FLOAT:
+ case OP_DIV_FLOAT:
+ case OP_REM_FLOAT:
+ vA = INST_AA(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ case OP_ADD_DOUBLE:
+ case OP_SUB_DOUBLE:
+ case OP_MUL_DOUBLE:
+ case OP_DIV_DOUBLE:
+ case OP_REM_DOUBLE:
+ vA = INST_AA(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1;
+ num_const_worklist++;
+ return false;
+ case OP_NEG_FLOAT:
+ case OP_INT_TO_FLOAT:
+ case OP_LONG_TO_FLOAT:
+ case OP_FLOAT_TO_INT:
+ case OP_DOUBLE_TO_INT:
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_REM_FLOAT_2ADDR:
+ case OP_DOUBLE_TO_FLOAT:
+ vA = INST_A(inst);
+ constWorklist[num_const_worklist] = vA; //change constWorklist to point to vA TODO
+ num_const_worklist++;
+ return false;
+ case OP_FLOAT_TO_LONG:
+ case OP_DOUBLE_TO_LONG:
+ case OP_FLOAT_TO_DOUBLE:
+ vA = INST_A(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1;
+ num_const_worklist++;
+ return false;
+ case OP_NEG_DOUBLE:
+ case OP_INT_TO_DOUBLE: //fp stack
+ case OP_LONG_TO_DOUBLE:
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE_2ADDR:
+ case OP_REM_DOUBLE_2ADDR:
+ //ops on float, double
+ vA = INST_A(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1;
+ num_const_worklist++;
+ return false;
+ case OP_NEG_INT:
+ case OP_NOT_INT:
+ case OP_LONG_TO_INT:
+ case OP_INT_TO_BYTE:
+ case OP_INT_TO_CHAR:
+ case OP_INT_TO_SHORT:
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ if(isVirtualRegConstant(vB, LowOpndRegType_gp, tmpValue, false) == 3) {
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ if(inst_op == OP_NEG_INT)
+ infoArray[entry].value[0] = -tmpValue[0];
+ if(inst_op == OP_NOT_INT)
+ infoArray[entry].value[0] = ~tmpValue[0]; //CHECK
+ if(inst_op == OP_LONG_TO_INT)
+ infoArray[entry].value[0] = tmpValue[0];
+ if(inst_op == OP_INT_TO_BYTE)// sar
+ infoArray[entry].value[0] = (tmpValue[0] << 24) >> 24;
+ if(inst_op == OP_INT_TO_CHAR) //shr
+ infoArray[entry].value[0] = ((unsigned int)(tmpValue[0] << 16)) >> 16;
+ if(inst_op == OP_INT_TO_SHORT) //sar
+ infoArray[entry].value[0] = (tmpValue[0] << 16) >> 16;
+ tmpValue[0] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_32, tmpValue);
+ compileTable[entry].refCount--;
+ touchOneVR(vB, LowOpndRegType_gp);
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %d", vA, infoArray[entry].value[0]);
+#endif
+ return true;
+ }
+ else {
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ }
+ case OP_NEG_LONG:
+ case OP_NOT_LONG:
+ case OP_INT_TO_LONG:
+ vA = INST_A(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1; //fixed on 10/15/2009
+ num_const_worklist++;
+ return false;
+ case OP_DIV_INT_2ADDR:
+ case OP_REM_INT_2ADDR:
+ case OP_REM_INT_LIT16:
+ case OP_DIV_INT_LIT16:
+ case OP_REM_INT_LIT8:
+ case OP_DIV_INT_LIT8:
+ case OP_DIV_INT:
+ case OP_REM_INT:
+ if(inst_op == OP_DIV_INT || inst_op == OP_DIV_INT_LIT8 ||
+ inst_op == OP_REM_INT || inst_op == OP_REM_INT_LIT8)
+ vA = INST_AA(inst);
+ else
+ vA = INST_A(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ case OP_ADD_INT_2ADDR:
+ case OP_SUB_INT_2ADDR:
+ case OP_MUL_INT_2ADDR:
+ case OP_AND_INT_2ADDR:
+ case OP_OR_INT_2ADDR:
+ case OP_XOR_INT_2ADDR:
+ case OP_SHL_INT_2ADDR:
+ case OP_SHR_INT_2ADDR:
+ case OP_USHR_INT_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ if(isVirtualRegConstant(vA, LowOpndRegType_gp, tmpValue, false) == 3 &&
+ isVirtualRegConstant(v2, LowOpndRegType_gp, tmpValue2, false) == 3) {
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ if(inst_op == OP_ADD_INT_2ADDR)
+ infoArray[entry].value[0] = tmpValue[0] + tmpValue2[0];
+ if(inst_op == OP_SUB_INT_2ADDR)
+ infoArray[entry].value[0] = tmpValue[0] - tmpValue2[0];
+ if(inst_op == OP_MUL_INT_2ADDR)
+ infoArray[entry].value[0] = tmpValue[0] * tmpValue2[0];
+ if(inst_op == OP_DIV_INT_2ADDR)
+ infoArray[entry].value[0] = tmpValue[0] / tmpValue2[0];
+ if(inst_op == OP_REM_INT_2ADDR)
+ infoArray[entry].value[0] = tmpValue[0] % tmpValue2[0];
+ if(inst_op == OP_AND_INT_2ADDR)
+ infoArray[entry].value[0] = tmpValue[0] & tmpValue2[0];
+ if(inst_op == OP_OR_INT_2ADDR)
+ infoArray[entry].value[0] = tmpValue[0] | tmpValue2[0];
+ if(inst_op == OP_XOR_INT_2ADDR)
+ infoArray[entry].value[0] = tmpValue[0] ^ tmpValue2[0];
+ if(inst_op == OP_SHL_INT_2ADDR)
+ infoArray[entry].value[0] = tmpValue[0] << tmpValue2[0];
+ if(inst_op == OP_SHR_INT_2ADDR)
+ infoArray[entry].value[0] = tmpValue[0] >> tmpValue2[0];
+ if(inst_op == OP_USHR_INT_2ADDR)
+ infoArray[entry].value[0] = (unsigned int)tmpValue[0] >> tmpValue2[0];
+ tmpValue[0] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_32, tmpValue);
+ compileTable[entry].refCount--;
+ touchOneVR(v2, LowOpndRegType_gp);
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %d", vA, infoArray[entry].value[0]);
+#endif
+ return true;
+ }
+ else {
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ }
+ case OP_ADD_INT_LIT16:
+ case OP_RSUB_INT:
+ case OP_MUL_INT_LIT16:
+ case OP_AND_INT_LIT16:
+ case OP_OR_INT_LIT16:
+ case OP_XOR_INT_LIT16:
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ tmp_s4 = (s2)FETCH(1);
+ if(isVirtualRegConstant(vB, LowOpndRegType_gp, tmpValue, false) == 3) {
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ if(inst_op == OP_ADD_INT_LIT16)
+ infoArray[entry].value[0] = tmpValue[0] + tmp_s4;
+ if(inst_op == OP_RSUB_INT)
+ infoArray[entry].value[0] = tmp_s4 - tmpValue[0];
+ if(inst_op == OP_MUL_INT_LIT16)
+ infoArray[entry].value[0] = tmpValue[0] * tmp_s4;
+ if(inst_op == OP_DIV_INT_LIT16)
+ infoArray[entry].value[0] = tmpValue[0] / tmp_s4;
+ if(inst_op == OP_REM_INT_LIT16)
+ infoArray[entry].value[0] = tmpValue[0] % tmp_s4;
+ if(inst_op == OP_AND_INT_LIT16)
+ infoArray[entry].value[0] = tmpValue[0] & tmp_s4;
+ if(inst_op == OP_OR_INT_LIT16)
+ infoArray[entry].value[0] = tmpValue[0] | tmp_s4;
+ if(inst_op == OP_XOR_INT_LIT16)
+ infoArray[entry].value[0] = tmpValue[0] ^ tmp_s4;
+ tmpValue[0] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_32, tmpValue);
+ compileTable[entry].refCount--;
+ touchOneVR(vB, LowOpndRegType_gp);
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %d", vA, infoArray[entry].value[0]);
+#endif
+ return true;
+ }
+ else {
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ }
+ case OP_ADD_INT:
+ case OP_SUB_INT:
+ case OP_MUL_INT:
+ case OP_AND_INT:
+ case OP_OR_INT:
+ case OP_XOR_INT:
+ case OP_SHL_INT:
+ case OP_SHR_INT:
+ case OP_USHR_INT:
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ if(isVirtualRegConstant(v1, LowOpndRegType_gp, tmpValue, false) == 3 &&
+ isVirtualRegConstant(v2, LowOpndRegType_gp, tmpValue2, false) == 3) {
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ if(inst_op == OP_ADD_INT)
+ infoArray[entry].value[0] = tmpValue[0] + tmpValue2[0];
+ if(inst_op == OP_SUB_INT)
+ infoArray[entry].value[0] = tmpValue[0] - tmpValue2[0];
+ if(inst_op == OP_MUL_INT)
+ infoArray[entry].value[0] = tmpValue[0] * tmpValue2[0];
+ if(inst_op == OP_DIV_INT)
+ infoArray[entry].value[0] = tmpValue[0] / tmpValue2[0];
+ if(inst_op == OP_REM_INT)
+ infoArray[entry].value[0] = tmpValue[0] % tmpValue2[0];
+ if(inst_op == OP_AND_INT)
+ infoArray[entry].value[0] = tmpValue[0] & tmpValue2[0];
+ if(inst_op == OP_OR_INT)
+ infoArray[entry].value[0] = tmpValue[0] | tmpValue2[0];
+ if(inst_op == OP_XOR_INT)
+ infoArray[entry].value[0] = tmpValue[0] ^ tmpValue2[0];
+ if(inst_op == OP_SHL_INT)
+ infoArray[entry].value[0] = tmpValue[0] << tmpValue2[0];
+ if(inst_op == OP_SHR_INT)
+ infoArray[entry].value[0] = tmpValue[0] >> tmpValue2[0];
+ if(inst_op == OP_USHR_INT)
+ infoArray[entry].value[0] = (unsigned int)tmpValue[0] >> tmpValue2[0];
+ tmpValue[0] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_32, tmpValue);
+ compileTable[entry].refCount--;
+ touchOneVR(v1, LowOpndRegType_gp);
+ touchOneVR(v2, LowOpndRegType_gp);
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %d", vA, infoArray[entry].value[0]);
+#endif
+ return true;
+ }
+ else {
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ }
+ case OP_ADD_INT_LIT8: //INST_AA
+ case OP_RSUB_INT_LIT8:
+ case OP_MUL_INT_LIT8:
+ case OP_AND_INT_LIT8:
+ case OP_OR_INT_LIT8:
+ case OP_XOR_INT_LIT8:
+ case OP_SHL_INT_LIT8:
+ case OP_SHR_INT_LIT8:
+ case OP_USHR_INT_LIT8:
+ vA = INST_AA(inst);
+ vB = (u2)FETCH(1) & 0xff;
+ tmp_s4 = (s2)FETCH(1) >> 8;
+ if(isVirtualRegConstant(vB, LowOpndRegType_gp, tmpValue, false) == 3) {
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ if(inst_op == OP_ADD_INT_LIT8)
+ infoArray[entry].value[0] = tmpValue[0] + tmp_s4;
+ if(inst_op == OP_RSUB_INT_LIT8)
+ infoArray[entry].value[0] = tmp_s4 - tmpValue[0];
+ if(inst_op == OP_MUL_INT_LIT8)
+ infoArray[entry].value[0] = tmpValue[0] * tmp_s4;
+ if(inst_op == OP_DIV_INT_LIT8)
+ infoArray[entry].value[0] = tmpValue[0] / tmp_s4;
+ if(inst_op == OP_REM_INT_LIT8)
+ infoArray[entry].value[0] = tmpValue[0] % tmp_s4;
+ if(inst_op == OP_AND_INT_LIT8)
+ infoArray[entry].value[0] = tmpValue[0] & tmp_s4;
+ if(inst_op == OP_OR_INT_LIT8)
+ infoArray[entry].value[0] = tmpValue[0] | tmp_s4;
+ if(inst_op == OP_XOR_INT_LIT8)
+ infoArray[entry].value[0] = tmpValue[0] ^ tmp_s4;
+ if(inst_op == OP_SHL_INT_LIT8)
+ infoArray[entry].value[0] = tmpValue[0] << tmp_s4;
+ if(inst_op == OP_SHR_INT_LIT8)
+ infoArray[entry].value[0] = tmpValue[0] >> tmp_s4;
+ if(inst_op == OP_USHR_INT_LIT8)
+ infoArray[entry].value[0] = (unsigned int)tmpValue[0] >> tmp_s4;
+ tmpValue[0] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_32, tmpValue);
+ compileTable[entry].refCount--;
+ touchOneVR(vB, LowOpndRegType_gp);
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %d", vA, infoArray[entry].value[0]);
+#endif
+ return true;
+ }
+ else {
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ }
+ case OP_ADD_LONG:
+ case OP_SUB_LONG:
+ case OP_AND_LONG:
+ case OP_OR_LONG:
+ case OP_XOR_LONG:
+ case OP_MUL_LONG:
+ case OP_DIV_LONG:
+ case OP_REM_LONG:
+ case OP_SHL_LONG:
+ case OP_SHR_LONG:
+ case OP_USHR_LONG:
+ //TODO bytecode is not going to update state registers
+ //constant folding
+ vA = INST_AA(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1;
+ num_const_worklist++;
+ return false;
+ case OP_CMP_LONG:
+ vA = INST_AA(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ case OP_ADD_LONG_2ADDR:
+ case OP_SUB_LONG_2ADDR:
+ case OP_AND_LONG_2ADDR:
+ case OP_OR_LONG_2ADDR:
+ case OP_XOR_LONG_2ADDR:
+ case OP_MUL_LONG_2ADDR:
+ case OP_DIV_LONG_2ADDR:
+ case OP_REM_LONG_2ADDR:
+ case OP_SHL_LONG_2ADDR:
+ case OP_SHR_LONG_2ADDR:
+ case OP_USHR_LONG_2ADDR:
+ vA = INST_A(inst);
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1;
+ num_const_worklist++;
+ return false;
+ case OP_CONST_4:
+ vA = INST_A(inst);
+ tmp_s4 = (s4) (INST_B(inst) << 28) >> 28;
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = tmp_s4;
+ tmpValue[0] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_32, tmpValue);
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %d", vA, tmp_s4);
+#endif
+ return true;
+ case OP_CONST_16:
+ BBBB = FETCH(1);
+ vA = INST_AA(inst);
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = (s2)BBBB;
+ tmpValue[0] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_32, tmpValue);
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %d", vA, infoArray[entry].value[0]);
+#endif
+ return true;
+ case OP_CONST:
+ vA = INST_AA(inst);
+ tmp_u4 = FETCH(1);
+ tmp_u4 |= (u4)FETCH(2) << 16;
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = (s4)tmp_u4;
+ tmpValue[0] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_32, tmpValue);
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %d", vA, infoArray[entry].value[0]);
+#endif
+ return true;
+ case OP_CONST_HIGH16:
+ vA = INST_AA(inst);
+ tmp_u2 = FETCH(1);
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = (s4)tmp_u2<<16;
+ tmpValue[0] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_32, tmpValue);
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %d", vA, infoArray[entry].value[0]);
+#endif
+ return true;
+ case OP_CONST_WIDE_16:
+ vA = INST_AA(inst);
+ tmp_u2 = FETCH(1);
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = (s2)tmp_u2;
+ tmpValue[0] = infoArray[entry].value[0];
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %x", vA, infoArray[entry].value[0]);
+#endif
+
+ entry = findVirtualRegInTable(vA+1, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = (s2)tmp_u2>>31;
+ tmpValue[1] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_64, tmpValue);
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %x", vA+1, infoArray[entry].value[0]);
+#endif
+ return true;
+ case OP_CONST_WIDE_32:
+ vA = INST_AA(inst);
+ tmp_u4 = FETCH(1);
+ tmp_u4 |= (u4)FETCH(2) << 16;
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = (s4)tmp_u4;
+ tmpValue[0] = infoArray[entry].value[0];
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %x", vA, infoArray[entry].value[0]);
+#endif
+
+ entry = findVirtualRegInTable(vA+1, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = (s4)tmp_u4>>31;
+ tmpValue[1] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_64, tmpValue);
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %x", vA+1, infoArray[entry].value[0]);
+#endif
+ return true;
+ case OP_CONST_WIDE:
+ vA = INST_AA(inst);
+ tmp_u4 = FETCH(1);
+ tmp_u4 |= (u8)FETCH(2) << 16;
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = (s4)tmp_u4;
+ tmpValue[0] = infoArray[entry].value[0];
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %x", vA, infoArray[entry].value[0]);
+#endif
+
+ tmp_u4 = (u8)FETCH(3);
+ tmp_u4 |= (u8)FETCH(4) << 16;
+ entry = findVirtualRegInTable(vA+1, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = (s4)tmp_u4;
+ tmpValue[1] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_64, tmpValue);
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %x", vA+1, infoArray[entry].value[0]);
+#endif
+ return true;
+ case OP_CONST_WIDE_HIGH16:
+ vA = INST_AA(inst);
+ tmp_u2 = FETCH(1);
+ entry = findVirtualRegInTable(vA, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = 0;
+ tmpValue[0] = infoArray[entry].value[0];
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %x", vA, infoArray[entry].value[0]);
+#endif
+
+ entry = findVirtualRegInTable(vA+1, LowOpndRegType_gp, true);
+ infoArray[entry].isConst = true;
+ infoArray[entry].value[0] = (s4)tmp_u2<<16;
+ tmpValue[1] = infoArray[entry].value[0];
+ setVRToConst(vA, OpndSize_64, tmpValue);
+ compileTable[entry].refCount--;
+#ifdef DEBUG_CONST
+ LOGD("getConstInfo: set VR %d to %x", vA+1, infoArray[entry].value[0]);
+#endif
+ return true;
+#ifdef SUPPORT_HLO
+ case OP_X_AGET_QUICK:
+ case OP_X_AGET_OBJECT_QUICK:
+ case OP_X_AGET_BOOLEAN_QUICK:
+ case OP_X_AGET_BYTE_QUICK:
+ case OP_X_AGET_CHAR_QUICK:
+ case OP_X_AGET_SHORT_QUICK:
+ vA = FETCH(1) & 0xff;
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ case OP_X_AGET_WIDE_QUICK:
+ vA = FETCH(1) & 0xff;
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1;
+ num_const_worklist++;
+ return false;
+ case OP_X_DEREF_GET:
+ case OP_X_DEREF_GET_OBJECT:
+ case OP_X_DEREF_GET_BOOLEAN:
+ case OP_X_DEREF_GET_BYTE:
+ case OP_X_DEREF_GET_CHAR:
+ case OP_X_DEREF_GET_SHORT:
+ vA = FETCH(1) & 0xff;
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ return false;
+ case OP_X_DEREF_GET_WIDE:
+ vA = FETCH(1) & 0xff;
+ constWorklist[num_const_worklist] = vA;
+ num_const_worklist++;
+ constWorklist[num_const_worklist] = vA+1;
+ num_const_worklist++;
+ return false;
+#endif
+ }
+ return false;
+}
+
+//! This function updates infoArray with virtual registers accessed when lowering the bytecode, and returns size of the bytecode in unit of u2
+
+//! uses of virtual registers are added to infoArray first
+int getVirtualRegInfo(VirtualRegInfo* infoArray) {
+ u2 inst_op = INST_INST(inst);
+ u2 vA = 0, vB = 0, vref, vindex;
+ u2 v1, v2, length, vD, vG, vE, vF, count;
+ u4 v1_u4, v2_u4;
+ int kk, num, num_entry;
+ s4 tmp_s4;
+ s2 tmp_s2;
+ u4 tmp_u4;
+ int codeSize = 0;
+ num_regs_per_bytecode = 0;
+ //update infoArray[xx].allocConstraints
+ for(num = 0; num < MAX_REG_PER_BYTECODE; num++) {
+ for(kk = 0; kk < 8; kk++) {
+ infoArray[num].allocConstraints[kk].physicalReg = (PhysicalReg)kk;
+ infoArray[num].allocConstraints[kk].count = 0;
+ }
+ }
+
+ switch (inst_op) {
+ case OP_NOP:
+ codeSize = 1;
+ break;
+ case OP_MOVE:
+ case OP_MOVE_OBJECT:
+ case OP_MOVE_FROM16:
+ case OP_MOVE_OBJECT_FROM16:
+ case OP_MOVE_16:
+ case OP_MOVE_OBJECT_16:
+ if(inst_op == OP_MOVE || inst_op == OP_MOVE_OBJECT) {
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ codeSize = 1;
+ }
+ else if(inst_op == OP_MOVE_FROM16 || inst_op == OP_MOVE_OBJECT_FROM16) {
+ vA = INST_AA(inst);
+ vB = FETCH(1);
+ codeSize = 2;
+ }
+ else if(inst_op == OP_MOVE_16 || inst_op == OP_MOVE_OBJECT_16) {
+ vA = FETCH(1);
+ vB = FETCH(2);
+ codeSize = 3;
+ }
+ infoArray[1].regNum = vA; //dst
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = vB; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_MOVE_WIDE:
+ case OP_MOVE_WIDE_FROM16:
+ case OP_MOVE_WIDE_16:
+ if(inst_op == OP_MOVE_WIDE) {
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ codeSize = 1;
+ }
+ else if(inst_op == OP_MOVE_WIDE_FROM16) {
+ vA = INST_AA(inst);
+ vB = FETCH(1);
+ codeSize = 2;
+ }
+ else if(inst_op == OP_MOVE_WIDE_16) {
+ vA = FETCH(1);
+ vB = FETCH(2);
+ codeSize = 3;
+ }
+ infoArray[1].regNum = vA; //dst
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[0].regNum = vB; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_MOVE_RESULT: //access memory
+ case OP_MOVE_RESULT_OBJECT:
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ codeSize = 1;
+ num_regs_per_bytecode = 1;
+ break;
+ case OP_MOVE_RESULT_WIDE: //note: 2 destinations
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ codeSize = 1;
+ num_regs_per_bytecode = 1;
+ break;
+ case OP_MOVE_EXCEPTION: //access memory
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ codeSize = 1;
+ num_regs_per_bytecode = 1;
+ break;
+ case OP_RETURN_VOID:
+ case OP_RETURN_VOID_BARRIER:
+ codeSize = 1;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ num_regs_per_bytecode = 0;
+ break;
+ case OP_RETURN:
+ case OP_RETURN_OBJECT:
+ vA = INST_AA(inst);
+ codeSize = 1;
+ infoArray[0].regNum = vA; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ num_regs_per_bytecode = 1;
+ break;
+ case OP_RETURN_WIDE:
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 1;
+ codeSize = 1;
+ break;
+ case OP_CONST_4:
+ vA = INST_A(inst);
+ tmp_s4 = (s4) (INST_B(inst) << 28) >> 28;
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 1;
+ codeSize = 1;
+ break;
+ case OP_CONST_16:
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 1;
+ codeSize = 2;
+ break;
+ case OP_CONST:
+ vA = INST_AA(inst);
+ tmp_u4 = FETCH(1);
+ tmp_u4 |= (u4)FETCH(2) << 16;
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 1;
+ codeSize = 3;
+ break;
+ case OP_CONST_HIGH16:
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 1;
+ codeSize = 2;
+ break;
+ case OP_CONST_WIDE_16:
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = vA+1;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ codeSize = 2;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_CONST_WIDE_32:
+ vA = INST_AA(inst);
+ tmp_u4 = FETCH(1);
+ tmp_u4 |= (u4)FETCH(2) << 16;
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = vA+1;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ codeSize = 3;
+ break;
+ case OP_CONST_WIDE:
+ vA = INST_AA(inst);
+ tmp_u4 = FETCH(1);
+ tmp_u4 |= (u8)FETCH(2) << 16;
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ tmp_u4 = (u8)FETCH(3);
+ tmp_u4 |= (u8)FETCH(4) << 16;
+ infoArray[1].regNum = vA+1;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ codeSize = 5;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_CONST_WIDE_HIGH16:
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = vA+1;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ codeSize = 2;
+ break;
+ case OP_CONST_STRING:
+ case OP_CONST_STRING_JUMBO:
+ case OP_CONST_CLASS:
+ vA = INST_AA(inst);
+ if(inst_op == OP_CONST_STRING || inst_op == OP_CONST_CLASS)
+ codeSize = 2;
+ else if(inst_op == OP_CONST_STRING_JUMBO)
+ codeSize = 3;
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[0].allocConstraints[PhysicalReg_EAX].count = 1;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ num_regs_per_bytecode = 1;
+ break;
+ case OP_MONITOR_ENTER:
+ vA = INST_AA(inst);
+ codeSize = 1;
+ infoArray[0].regNum = vA; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 1;
+ break;
+ case OP_MONITOR_EXIT:
+ vA = INST_AA(inst);
+ codeSize = 1;
+ infoArray[0].regNum = vA; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX); //eax is used as return value from c function
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 1;
+ break;
+ case OP_CHECK_CAST:
+ codeSize = 2;
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_ECX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 1;
+ break;
+ case OP_INSTANCE_OF:
+ codeSize = 2;
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ infoArray[0].regNum = vB; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = vA; //dst
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_ARRAY_LENGTH:
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ codeSize = 1;
+ infoArray[0].regNum = vB; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = vA; //dst
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ //%edx is used in this bytecode, update currentBB->allocConstraints
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_NEW_INSTANCE:
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //dst
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[0].allocConstraints[PhysicalReg_EAX].count = 1;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_ECX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 1;
+ codeSize = 2;
+ break;
+ case OP_NEW_ARRAY:
+ vA = INST_A(inst); //destination
+ vB = INST_B(inst); //length
+ infoArray[0].regNum = vB; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = vA; //dst
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[1].allocConstraints[PhysicalReg_EAX].count = 1;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 2;
+ codeSize = 2;
+ break;
+ case OP_FILLED_NEW_ARRAY: {//update return value
+ //can use up to 5 registers to fill the content of array
+ length = INST_B(inst);
+ u2 vv = FETCH(2);
+ v1 = vv & 0xf;
+ v2 = (vv >> 4) & 0xf;
+ u2 v3 = (vv >> 8) & 0xf;
+ u2 v4 = (vv >> 12) & 0xf;
+ u2 v5 = INST_A(inst);
+ if(length >= 1) {
+ infoArray[0].regNum = v1; //src
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ }
+ if(length >= 2) {
+ infoArray[1].regNum = v2; //src
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ }
+ if(length >= 3) {
+ infoArray[2].regNum = v3; //src
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_U;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ }
+ if(length >= 4) {
+ infoArray[3].regNum = v4; //src
+ infoArray[3].refCount = 1;
+ infoArray[3].accessType = REGACCESS_U;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ }
+ if(length >= 5) {
+ infoArray[4].regNum = v5; //src
+ infoArray[4].refCount = 1;
+ infoArray[4].accessType = REGACCESS_U;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ }
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = length;
+ codeSize = 3;
+ break;
+ }
+ case OP_FILLED_NEW_ARRAY_RANGE: {//use "length" virtual registers
+ length = INST_AA(inst);
+ u4 vC = (u4)FETCH(2);
+ for(kk = 0; kk < length; kk++) {
+ infoArray[kk].regNum = vC+kk; //src
+ infoArray[kk].refCount = 1;
+ infoArray[kk].accessType = REGACCESS_U;
+ infoArray[kk].physicalType = LowOpndRegType_gp;
+ }
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = length;
+ codeSize = 3;
+ break;
+ }
+ case OP_FILL_ARRAY_DATA: //update content of array, read memory
+ vA = INST_AA(inst); //use virtual register, but has side-effect, update memory
+ infoArray[0].regNum = vA; //use
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 1;
+ codeSize = 3;
+ break;
+ case OP_THROW: //update glue->exception
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //use
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 1;
+ codeSize = 1;
+ break;
+ case OP_THROW_VERIFICATION_ERROR:
+ num_regs_per_bytecode = 0;
+ codeSize = 2;
+ break;
+ case OP_GOTO:
+ codeSize = 1;
+ num_regs_per_bytecode = 0;
+ break;
+ case OP_GOTO_16:
+ codeSize = 2;
+ num_regs_per_bytecode = 0;
+ break;
+ case OP_GOTO_32:
+ codeSize = 3;
+ num_regs_per_bytecode = 0;
+ break;
+ case OP_PACKED_SWITCH:
+ case OP_SPARSE_SWITCH:
+ vA = INST_AA(inst);
+ codeSize = 3;
+ infoArray[0].regNum = vA; //use
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 1;
+ break;
+
+ case OP_CMPL_FLOAT: //move 32 bits from memory to lower part of XMM register
+ case OP_CMPG_FLOAT:
+ codeSize = 2;
+ vA = INST_AA(inst);
+ v1_u4 = FETCH(1) & 0xff;
+ v2_u4 = FETCH(1) >> 8;
+ num_regs_per_bytecode = 1;
+ infoArray[0].regNum = v1_u4; //use ss or sd CHECK
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_ss;
+ infoArray[1].regNum = v2_u4; //use
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_ss;
+ num_regs_per_bytecode = 3;
+ num_entry = 2;
+ infoArray[num_entry].regNum = vA; //define
+ infoArray[num_entry].refCount = 1;
+ infoArray[num_entry].accessType = REGACCESS_D;
+ infoArray[num_entry].physicalType = LowOpndRegType_gp;
+ break;
+ case OP_CMPL_DOUBLE: //move 64 bits from memory to lower part of XMM register
+ case OP_CMPG_DOUBLE:
+ case OP_CMP_LONG: //load v1, v1+1, v2, v2+1 to gpr
+ codeSize = 2;
+ vA = INST_AA(inst);
+ v1_u4 = FETCH(1) & 0xff;
+ v2_u4 = FETCH(1) >> 8;
+ num_regs_per_bytecode = 1;
+ if(inst_op == OP_CMP_LONG) {
+ infoArray[0].regNum = v1_u4; //use
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = v1_u4 + 1; //use
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = v2_u4; //use
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_U;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = v2_u4 + 1; //use
+ infoArray[3].refCount = 1;
+ infoArray[3].accessType = REGACCESS_U;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 5;
+ num_entry = 4;
+ infoArray[num_entry].regNum = vA; //define
+ infoArray[num_entry].refCount = 2;
+ infoArray[num_entry].accessType = REGACCESS_D;
+ infoArray[num_entry].physicalType = LowOpndRegType_gp;
+ }
+ else {
+ infoArray[0].regNum = v1_u4; //use ss or sd CHECK
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = v2_u4; //use
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 3;
+ num_entry = 2;
+ infoArray[num_entry].regNum = vA; //define
+ infoArray[num_entry].refCount = 1;
+ infoArray[num_entry].accessType = REGACCESS_D;
+ infoArray[num_entry].physicalType = LowOpndRegType_gp;
+ }
+ break;
+ case OP_IF_EQ:
+ case OP_IF_NE:
+ case OP_IF_LT:
+ case OP_IF_GE:
+ case OP_IF_GT:
+ case OP_IF_LE:
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ infoArray[0].regNum = vA; //use
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = vB;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ codeSize =12;
+ break;
+ case OP_IF_EQZ:
+ case OP_IF_NEZ:
+ case OP_IF_LTZ:
+ case OP_IF_GEZ:
+ case OP_IF_GTZ:
+ case OP_IF_LEZ:
+ vA = INST_AA(inst);
+ infoArray[0].regNum = vA; //use
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 1;
+ codeSize = 2;
+ break;
+ case OP_AGET:
+ codeSize = 2;
+ case OP_AGET_WIDE:
+ codeSize = 2;
+ case OP_AGET_OBJECT:
+ codeSize = 2;
+ case OP_AGET_BOOLEAN: //movez 8
+ codeSize = 2;
+ case OP_AGET_BYTE: //moves 8
+ codeSize = 2;
+ case OP_AGET_CHAR: //movez 16
+ codeSize = 2;
+ case OP_AGET_SHORT: //moves 16
+ codeSize = 2;
+ vA = INST_AA(inst);
+ vref = FETCH(1) & 0xff;
+ vindex = FETCH(1) >> 8;
+ if(inst_op == OP_AGET_WIDE) {
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_xmm; //64, 128 not used in lowering
+ } else {
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ }
+ infoArray[0].regNum = vref; //use
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = vindex; //use
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_APUT:
+ case OP_APUT_WIDE:
+ case OP_APUT_OBJECT:
+ case OP_APUT_BOOLEAN:
+ case OP_APUT_BYTE:
+ case OP_APUT_CHAR:
+ case OP_APUT_SHORT:
+ vA = INST_AA(inst);
+ vref = FETCH(1) & 0xff;
+ vindex = FETCH(1) >> 8;
+ codeSize = 2;
+ if(inst_op == OP_APUT_WIDE) {
+ infoArray[0].regNum = vA;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm; //64, 128 not used in lowering
+ } else {
+ infoArray[0].regNum = vA;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ }
+ infoArray[1].regNum = vref; //use
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = vindex; //use
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_U;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ if(inst_op == OP_APUT_OBJECT) {
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ }
+ num_regs_per_bytecode = 3;
+ break;
+
+ case OP_IGET:
+ case OP_IGET_WIDE:
+ case OP_IGET_OBJECT:
+ case OP_IGET_VOLATILE:
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IGET_OBJECT_VOLATILE:
+ case OP_IGET_BOOLEAN:
+ case OP_IGET_BYTE:
+ case OP_IGET_CHAR:
+ case OP_IGET_SHORT:
+ case OP_IGET_QUICK:
+ case OP_IGET_WIDE_QUICK:
+ case OP_IGET_OBJECT_QUICK:
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ codeSize = 2;
+ if(inst_op == OP_IGET_WIDE || inst_op == OP_IGET_WIDE_QUICK) {
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_xmm; //64
+ } else if(inst_op == OP_IGET_WIDE_VOLATILE) {
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = vA+1;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ } else {
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ }
+ infoArray[0].regNum = vB; //object instance
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ if(inst_op == OP_IGET_WIDE_VOLATILE)
+ num_regs_per_bytecode = 3;
+ else
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_IPUT:
+ case OP_IPUT_WIDE:
+ case OP_IPUT_OBJECT:
+ case OP_IPUT_VOLATILE:
+ case OP_IPUT_WIDE_VOLATILE:
+ case OP_IPUT_OBJECT_VOLATILE:
+ case OP_IPUT_BOOLEAN:
+ case OP_IPUT_BYTE:
+ case OP_IPUT_CHAR:
+ case OP_IPUT_SHORT:
+ case OP_IPUT_QUICK:
+ case OP_IPUT_WIDE_QUICK:
+ case OP_IPUT_OBJECT_QUICK:
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ codeSize = 2;
+ if(inst_op == OP_IPUT_WIDE || inst_op == OP_IPUT_WIDE_QUICK || inst_op == OP_IPUT_WIDE_VOLATILE) {
+ infoArray[0].regNum = vA;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm; //64
+ } else {
+ infoArray[0].regNum = vA;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ }
+ infoArray[1].regNum = vB; //object instance
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_SGET:
+ case OP_SGET_WIDE:
+ case OP_SGET_OBJECT:
+ case OP_SGET_VOLATILE:
+ case OP_SGET_WIDE_VOLATILE:
+ case OP_SGET_OBJECT_VOLATILE:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_BYTE:
+ case OP_SGET_CHAR:
+ case OP_SGET_SHORT:
+ vA = INST_AA(inst);
+ codeSize = 2;
+ if(inst_op == OP_SGET_WIDE) {
+ infoArray[0].regNum = vA;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_xmm; //64
+ } else if(inst_op == OP_SGET_WIDE_VOLATILE) {
+ infoArray[0].regNum = vA;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = vA+1;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ } else {
+ infoArray[0].regNum = vA;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_D;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ }
+ if(inst_op == OP_SGET_WIDE_VOLATILE)
+ num_regs_per_bytecode = 2;
+ else
+ num_regs_per_bytecode = 1;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ break;
+ case OP_SPUT:
+ case OP_SPUT_WIDE:
+ case OP_SPUT_OBJECT:
+ case OP_SPUT_VOLATILE:
+ case OP_SPUT_WIDE_VOLATILE:
+ case OP_SPUT_OBJECT_VOLATILE:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_SHORT:
+ vA = INST_AA(inst);
+ codeSize = 2;
+ if(inst_op == OP_SPUT_WIDE || inst_op == OP_SPUT_WIDE_VOLATILE) {
+ infoArray[0].regNum = vA;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm; //64
+ } else {
+ infoArray[0].regNum = vA;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ }
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ num_regs_per_bytecode = 1;
+ break;
+
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_INTERFACE:
+ case OP_INVOKE_VIRTUAL_QUICK:
+ case OP_INVOKE_SUPER_QUICK:
+ codeSize = 3;
+ vD = FETCH(2) & 0xf; //object for virtual,direct & interface
+ count = INST_B(inst);
+ vE = (FETCH(2) >> 4) & 0xf;
+ vF = (FETCH(2) >> 8) & 0xf;
+ vG = (FETCH(2) >> 12) & 0xf;
+ vA = INST_A(inst); //5th argument
+ if(count == 0) {
+ if(inst_op == OP_INVOKE_VIRTUAL || inst_op == OP_INVOKE_DIRECT ||
+ inst_op == OP_INVOKE_INTERFACE || inst_op == OP_INVOKE_VIRTUAL_QUICK ||
+ inst_op == OP_INVOKE_SUPER_QUICK) {
+ infoArray[0].regNum = vD;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 1;
+ }
+ num_regs_per_bytecode = 0;
+ }
+ else num_regs_per_bytecode = count;
+ if(count >= 1) {
+ infoArray[0].regNum = vD;
+ if(inst_op == OP_INVOKE_VIRTUAL_QUICK ||
+ inst_op == OP_INVOKE_SUPER_QUICK) {
+ infoArray[0].refCount = 2;
+ } else if(inst_op == OP_INVOKE_VIRTUAL || inst_op == OP_INVOKE_DIRECT || inst_op == OP_INVOKE_INTERFACE) {
+ infoArray[0].refCount = 2;
+ } else {
+ infoArray[0].refCount = 1;
+ }
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ }
+ if(count >= 2) {
+ infoArray[1].regNum = vE;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ }
+ if(count >= 3) {
+ infoArray[2].regNum = vF;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_U;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ }
+ if(count >= 4) {
+ infoArray[3].regNum = vG;
+ infoArray[3].refCount = 1;
+ infoArray[3].accessType = REGACCESS_U;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ }
+ if(count >= 5) {
+ infoArray[4].regNum = vA;
+ infoArray[4].refCount = 1;
+ infoArray[4].accessType = REGACCESS_U;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ }
+ if(inst_op != OP_INVOKE_VIRTUAL_QUICK && inst_op != OP_INVOKE_SUPER_QUICK)
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_ECX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ break;
+ case OP_INVOKE_VIRTUAL_RANGE:
+ case OP_INVOKE_SUPER_RANGE:
+ case OP_INVOKE_DIRECT_RANGE:
+ case OP_INVOKE_STATIC_RANGE:
+ case OP_INVOKE_INTERFACE_RANGE:
+ case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+ case OP_INVOKE_SUPER_QUICK_RANGE:
+ codeSize = 3;
+ vD = FETCH(2);
+ count = INST_AA(inst);
+ if(count == 0) {
+ if(inst_op == OP_INVOKE_VIRTUAL_RANGE || inst_op == OP_INVOKE_DIRECT_RANGE ||
+ inst_op == OP_INVOKE_INTERFACE_RANGE || inst_op == OP_INVOKE_VIRTUAL_QUICK_RANGE ||
+ inst_op == OP_INVOKE_SUPER_QUICK_RANGE) {
+ infoArray[0].regNum = vD;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ }
+ }
+ if(count > 0) { //same for count > 10
+ for(kk = 0; kk < count; kk++) {
+ infoArray[kk].regNum = vD+kk; //src
+ if(kk == 0 && (inst_op == OP_INVOKE_VIRTUAL_QUICK_RANGE ||
+ inst_op == OP_INVOKE_SUPER_QUICK_RANGE))
+ infoArray[kk].refCount = 2;
+ else if(kk == 0 && (inst_op == OP_INVOKE_VIRTUAL_RANGE ||
+ inst_op == OP_INVOKE_DIRECT_RANGE ||
+ inst_op == OP_INVOKE_INTERFACE_RANGE))
+ infoArray[kk].refCount = 2;
+ else
+ infoArray[kk].refCount = 1;
+ infoArray[kk].accessType = REGACCESS_U;
+ infoArray[kk].physicalType = LowOpndRegType_gp;
+ }
+ }
+ if(inst_op != OP_INVOKE_VIRTUAL_QUICK_RANGE && inst_op != OP_INVOKE_SUPER_QUICK_RANGE)
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_ECX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = count;
+ break;
+ case OP_NEG_INT:
+ case OP_NOT_INT:
+ case OP_NEG_FLOAT:
+ vA = INST_A(inst); //destination
+ vB = INST_B(inst);
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ codeSize = 1;
+ break;
+ case OP_NEG_LONG:
+ case OP_NOT_LONG:
+ case OP_NEG_DOUBLE:
+ vA = INST_A(inst); //destination
+ vB = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_INT_TO_LONG: //hard-coded registers
+ vA = INST_A(inst); //destination
+ vB = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp; //save from %eax
+ infoArray[1].allocConstraints[PhysicalReg_EAX].count = 1;
+ infoArray[2].regNum = vA+1;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[2].allocConstraints[PhysicalReg_EDX].count = 1;
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[0].allocConstraints[PhysicalReg_EAX].count = 1;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_INT_TO_FLOAT: //32 to 32
+ case OP_INT_TO_DOUBLE: //32 to 64
+ case OP_LONG_TO_FLOAT: //64 to 32
+ case OP_LONG_TO_DOUBLE: //64 to 64
+ case OP_FLOAT_TO_DOUBLE: //32 to 64
+ case OP_DOUBLE_TO_FLOAT: //64 to 32
+ vA = INST_A(inst); //destination
+ vB = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ if(inst_op == OP_INT_TO_DOUBLE || inst_op == OP_LONG_TO_DOUBLE || inst_op == OP_FLOAT_TO_DOUBLE)
+ infoArray[1].physicalType = LowOpndRegType_fs;
+ else
+ infoArray[1].physicalType = LowOpndRegType_fs_s;
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ if(inst_op == OP_INT_TO_FLOAT || inst_op == OP_INT_TO_DOUBLE || inst_op == OP_FLOAT_TO_DOUBLE)
+ infoArray[0].physicalType = LowOpndRegType_fs_s; //float
+ else
+ infoArray[0].physicalType = LowOpndRegType_fs;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_LONG_TO_INT:
+ vA = INST_A(inst); //destination
+ vB = INST_B(inst);
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ codeSize = 1;
+ break;
+ case OP_FLOAT_TO_INT:
+ case OP_DOUBLE_TO_INT: //for reaching-def analysis
+ vA = INST_A(inst); //destination
+ vB = INST_B(inst);
+ codeSize = 1;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 3;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_fs_s; //store_int_fp_stack_VR
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ if(inst_op == OP_DOUBLE_TO_INT)
+ infoArray[0].physicalType = LowOpndRegType_fs;
+ else
+ infoArray[0].physicalType = LowOpndRegType_fs_s;
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_FLOAT_TO_LONG:
+ case OP_DOUBLE_TO_LONG:
+ vA = INST_A(inst); //destination
+ vB = INST_B(inst);
+ codeSize = 1;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 3;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_fs;
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ if(inst_op == OP_DOUBLE_TO_LONG)
+ infoArray[0].physicalType = LowOpndRegType_fs;
+ else
+ infoArray[0].physicalType = LowOpndRegType_fs_s;
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_INT_TO_BYTE:
+ case OP_INT_TO_CHAR:
+ case OP_INT_TO_SHORT:
+ vA = INST_A(inst); //destination
+ vB = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ break;
+
+ case OP_ADD_INT:
+ case OP_SUB_INT:
+ case OP_MUL_INT:
+ case OP_AND_INT:
+ case OP_OR_INT:
+ case OP_XOR_INT:
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ codeSize = 2;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_DIV_INT:
+ case OP_REM_INT:
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ codeSize = 2;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 2;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].allocConstraints[PhysicalReg_EAX].count = 1; //for v1
+ if(inst_op == OP_REM_INT)
+ infoArray[2].allocConstraints[PhysicalReg_EDX].count = 1;//vA
+ else
+ infoArray[2].allocConstraints[PhysicalReg_EAX].count = 1;//vA
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_SHL_INT:
+ case OP_SHR_INT:
+ case OP_USHR_INT:
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ codeSize = 2;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = v2; // in ecx
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[1].allocConstraints[PhysicalReg_ECX].count = 1;
+ updateCurrentBBWithConstraints(PhysicalReg_ECX);
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_ADD_LONG:
+ case OP_SUB_LONG:
+ case OP_AND_LONG:
+ case OP_OR_LONG:
+ case OP_XOR_LONG:
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ codeSize = 2;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_xmm;
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_MUL_LONG: //used int
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = v1+1;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = v2;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_U;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = v2+1;
+ infoArray[3].refCount = 1;
+ infoArray[3].accessType = REGACCESS_U;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = vA;
+ infoArray[4].refCount = 1;
+ infoArray[4].accessType = REGACCESS_D;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = vA+1;
+ infoArray[5].refCount = 1;
+ infoArray[5].accessType = REGACCESS_D;
+ infoArray[5].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 6;
+ codeSize = 2;
+ break;
+ case OP_DIV_LONG: //v1: xmm v2,vA:
+ case OP_REM_LONG:
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = v2+1;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_U;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = vA;
+ infoArray[3].refCount = 1;
+ infoArray[3].accessType = REGACCESS_D;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = vA+1;
+ infoArray[4].refCount = 1;
+ infoArray[4].accessType = REGACCESS_D;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 5;
+ codeSize = 2;
+ break;
+ case OP_SHL_LONG: //v2: 32, move_ss; v1,vA: xmm CHECK
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_ss;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 3;
+ codeSize = 2;
+ break;
+ case OP_SHR_LONG: //v2: 32, move_ss; v1,vA: xmm CHECK
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_ss;
+ infoArray[2].regNum = v1+1;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_U;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = vA;
+ infoArray[3].refCount = 1;
+ infoArray[3].accessType = REGACCESS_D;
+ infoArray[3].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 4;
+ codeSize = 2;
+ break;
+ case OP_USHR_LONG: //v2: move_ss; v1,vA: move_sd
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm; //sd
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_ss; //ss
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_xmm; //sd
+ num_regs_per_bytecode = 3;
+ codeSize = 2;
+ break;
+ case OP_ADD_FLOAT: //move_ss
+ case OP_SUB_FLOAT:
+ case OP_MUL_FLOAT:
+ case OP_DIV_FLOAT:
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ codeSize = 2;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_ss;
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_ss;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_ss;
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_REM_FLOAT: //32 bit GPR, fp_stack for output
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ codeSize = 2;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_fs_s;
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_ADD_DOUBLE: //move_sd
+ case OP_SUB_DOUBLE:
+ case OP_MUL_DOUBLE:
+ case OP_DIV_DOUBLE:
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ codeSize = 2;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_xmm;
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 3;
+ break;
+ case OP_REM_DOUBLE: //64 bit XMM, fp_stack for output
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ codeSize = 2;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_D;
+ infoArray[2].physicalType = LowOpndRegType_fs;
+ infoArray[0].regNum = v1;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 3;
+ break;
+
+ case OP_ADD_INT_2ADDR:
+ case OP_SUB_INT_2ADDR:
+ case OP_MUL_INT_2ADDR:
+ case OP_AND_INT_2ADDR:
+ case OP_OR_INT_2ADDR:
+ case OP_XOR_INT_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 2;
+ infoArray[1].accessType = REGACCESS_UD; //use then define
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = v2;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_DIV_INT_2ADDR:
+ case OP_REM_INT_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 3;
+ infoArray[1].accessType = REGACCESS_UD; //use then define
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = v2;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].allocConstraints[PhysicalReg_EAX].count = 1; //for v1 is vA
+ if(inst_op == OP_REM_INT_2ADDR)
+ infoArray[1].allocConstraints[PhysicalReg_EDX].count = 1;//vA
+ else
+ infoArray[1].allocConstraints[PhysicalReg_EAX].count = 1;//vA
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_SHL_INT_2ADDR:
+ case OP_SHR_INT_2ADDR:
+ case OP_USHR_INT_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 2;
+ infoArray[1].accessType = REGACCESS_UD; //use then define
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = v2;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[0].allocConstraints[PhysicalReg_ECX].count = 1; //v2
+ updateCurrentBBWithConstraints(PhysicalReg_ECX);
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_ADD_LONG_2ADDR:
+ case OP_SUB_LONG_2ADDR:
+ case OP_AND_LONG_2ADDR:
+ case OP_OR_LONG_2ADDR:
+ case OP_XOR_LONG_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 2;
+ infoArray[1].accessType = REGACCESS_UD;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[0].regNum = v2;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_MUL_LONG_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ codeSize = 1;
+ num_regs_per_bytecode = 4;
+ infoArray[0].regNum = v2;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = v2+1;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 2;
+ infoArray[2].accessType = REGACCESS_UD;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = vA+1;
+ infoArray[3].refCount = 2;
+ infoArray[3].accessType = REGACCESS_UD;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ break;
+ case OP_DIV_LONG_2ADDR: //vA used as xmm, then updated as gps
+ case OP_REM_LONG_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ num_regs_per_bytecode = 5;
+ codeSize = 1;
+ infoArray[0].regNum = vA;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = v2;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = v2+1;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_U;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = vA;
+ infoArray[3].refCount = 1;
+ infoArray[3].accessType = REGACCESS_D;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = vA+1;
+ infoArray[4].refCount = 1;
+ infoArray[4].accessType = REGACCESS_D;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ break;
+ case OP_SHL_LONG_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ num_regs_per_bytecode = 2;
+ codeSize = 1;
+ infoArray[0].regNum = v2; //ss
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_ss;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 2;
+ infoArray[1].accessType = REGACCESS_UD;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ break;
+ case OP_SHR_LONG_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ num_regs_per_bytecode = 3;
+ codeSize = 1;
+ infoArray[0].regNum = v2; //ss
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_ss;
+ infoArray[1].regNum = vA+1;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = vA;
+ infoArray[2].refCount = 2;
+ infoArray[2].accessType = REGACCESS_UD;
+ infoArray[2].physicalType = LowOpndRegType_xmm;
+ break;
+ case OP_USHR_LONG_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ num_regs_per_bytecode = 2;
+ codeSize = 1;
+ infoArray[0].regNum = v2;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_ss; //ss CHECK
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 2;
+ infoArray[1].accessType = REGACCESS_UD;
+ infoArray[1].physicalType = LowOpndRegType_xmm; //sd
+ break;
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_DIV_FLOAT_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 2;
+ infoArray[1].accessType = REGACCESS_UD;
+ infoArray[1].physicalType = LowOpndRegType_ss;
+ infoArray[0].regNum = v2;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_ss;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_REM_FLOAT_2ADDR: //load vA as GPR, store from fs
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 2;
+ infoArray[1].accessType = REGACCESS_UD;
+ infoArray[1].physicalType = LowOpndRegType_gp; //CHECK
+ infoArray[0].regNum = v2;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE_2ADDR:
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 2;
+ infoArray[1].accessType = REGACCESS_UD;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[0].regNum = v2;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_REM_DOUBLE_2ADDR: //load to xmm, store from fs
+ vA = INST_A(inst);
+ v2 = INST_B(inst);
+ codeSize = 1;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 2;
+ infoArray[1].accessType = REGACCESS_UD;
+ infoArray[1].physicalType = LowOpndRegType_xmm; //CHECK
+ infoArray[0].regNum = v2;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ num_regs_per_bytecode = 2;
+ break;
+
+ case OP_ADD_INT_LIT16:
+ case OP_RSUB_INT:
+ case OP_MUL_INT_LIT16:
+ case OP_AND_INT_LIT16:
+ case OP_OR_INT_LIT16:
+ case OP_XOR_INT_LIT16:
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ codeSize = 2;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_DIV_INT_LIT16:
+ case OP_REM_INT_LIT16:
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ codeSize = 2;
+ tmp_s4 = (s2)FETCH(1);
+ tmp_s2 = tmp_s4;
+ if(tmp_s2 == 0) {
+ num_regs_per_bytecode = 0;
+ break;
+ }
+ infoArray[1].regNum = vA; //in edx for rem, in eax
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = vB; //in eax
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ if(inst_op == OP_DIV_INT_LIT16) {
+ int power = isPowerOfTwo(tmp_s2);
+ if(power >= 1) { /* divide by a power of 2 constant */
+ infoArray[1].refCount = 1;
+ break;
+ }
+ }
+ if(tmp_s2 == -1)
+ infoArray[1].refCount = 2;
+ else
+ infoArray[1].refCount = 1;
+ if(inst_op == OP_REM_INT_LIT16)
+ infoArray[1].allocConstraints[PhysicalReg_EDX].count = 1;
+ else
+ infoArray[1].allocConstraints[PhysicalReg_EAX].count = 1;
+ infoArray[0].allocConstraints[PhysicalReg_EAX].count = 1;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ break;
+ case OP_ADD_INT_LIT8:
+ case OP_RSUB_INT_LIT8:
+ case OP_MUL_INT_LIT8:
+ case OP_AND_INT_LIT8:
+ case OP_OR_INT_LIT8:
+ case OP_XOR_INT_LIT8:
+ case OP_SHL_INT_LIT8:
+ case OP_SHR_INT_LIT8:
+ case OP_USHR_INT_LIT8:
+ codeSize = 2;
+ vA = INST_AA(inst);
+ vB = (u2)FETCH(1) & 0xff;
+ infoArray[1].regNum = vA;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ break;
+ case OP_DIV_INT_LIT8:
+ case OP_REM_INT_LIT8:
+ codeSize = 2;
+ vA = INST_AA(inst);
+ vB = (u2)FETCH(1) & 0xff;
+ tmp_s2 = (s2)FETCH(1) >> 8;
+ if(tmp_s2 == 0) {
+ num_regs_per_bytecode = 0;
+ break;
+ }
+
+ infoArray[1].regNum = vA;
+ infoArray[1].accessType = REGACCESS_D;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[0].regNum = vB;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ num_regs_per_bytecode = 2;
+ if(inst_op == OP_DIV_INT_LIT8) {
+ int power = isPowerOfTwo(tmp_s2);
+ if(power >= 1) { /* divide by a power of 2 constant */
+ infoArray[1].refCount = 1;
+ break;
+ }
+ }
+
+ if(tmp_s2 == -1)
+ infoArray[1].refCount = 2;
+ else
+ infoArray[1].refCount = 1;
+ if(inst_op == OP_REM_INT_LIT8)
+ infoArray[1].allocConstraints[PhysicalReg_EDX].count = 1;
+ else
+ infoArray[1].allocConstraints[PhysicalReg_EAX].count = 1;
+ infoArray[0].allocConstraints[PhysicalReg_EAX].count = 1;
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ break;
+ case OP_EXECUTE_INLINE: //update glue->retval
+ case OP_EXECUTE_INLINE_RANGE:
+ u4 vC;
+ if(inst_op == OP_EXECUTE_INLINE)
+ num = INST_B(inst);
+ else
+ num = INST_AA(inst);
+ if(inst_op == OP_EXECUTE_INLINE) {
+ vC = FETCH(2) & 0xf;
+ vD = (FETCH(2) >> 4) & 0xf;
+ vE = (FETCH(2) >> 8) & 0xf;
+ vF = FETCH(2) >> 12;
+ } else {
+ vC = FETCH(2);
+ vD = vC + 1;
+ vE = vC + 2;
+ vF = vC + 3;
+ }
+ codeSize = 3;
+ if(num >= 1) {
+ infoArray[0].regNum = vC;
+ infoArray[0].refCount = 1;
+ infoArray[0].accessType = REGACCESS_U;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ }
+ if(num >= 2) {
+ infoArray[1].regNum = vD;
+ infoArray[1].refCount = 1;
+ infoArray[1].accessType = REGACCESS_U;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ }
+ if(num >= 3) {
+ infoArray[2].regNum = vE;
+ infoArray[2].refCount = 1;
+ infoArray[2].accessType = REGACCESS_U;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ }
+ if(num >= 4) {
+ infoArray[3].regNum = vF;
+ infoArray[3].refCount = 1;
+ infoArray[3].accessType = REGACCESS_U;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ }
+ updateCurrentBBWithConstraints(PhysicalReg_EAX);
+ updateCurrentBBWithConstraints(PhysicalReg_EDX);
+ num_regs_per_bytecode = num;
+ break;
+#if FIXME
+ case OP_INVOKE_OBJECT_INIT_RANGE:
+ codeSize = 3;
+ num_regs_per_bytecode = 0;
+ break;
+#endif
+ }
+ return codeSize;
+}
+//! Updates infoArray(TempRegInfo) with temporaries accessed by INVOKE_NO_RANGE
+
+//!
+int updateInvokeNoRange(TempRegInfo* infoArray, int startInd) {
+ int j = startInd;
+ //invokeMethodNoRange
+ int count = INST_B(inst);
+ if(count == 5) {
+ infoArray[j].regNum = 22;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 4) {
+ infoArray[j].regNum = 23;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 3) {
+ infoArray[j].regNum = 24;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 2) {
+ infoArray[j].regNum = 25;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 1) {
+ infoArray[j].regNum = 26;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ return j;
+}
+//! Updates infoArray(TempRegInfo) with temporaries accessed by INVOKE_RANGE
+
+//! LOOP_COUNT is used to indicate a variable is live through a loop
+int updateInvokeRange(TempRegInfo* infoArray, int startIndex) {
+ int j = startIndex;
+ int count = INST_AA(inst);
+ infoArray[j].regNum = 21;
+ if(count <= 10) {
+ infoArray[j].refCount = 1+count; //DU
+ } else {
+ infoArray[j].refCount = 2+3*LOOP_COUNT;
+ }
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ if(count >= 1 && count <= 10) {
+ infoArray[j].regNum = 22;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 2 && count <= 10) {
+ infoArray[j].regNum = 23;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 3 && count <= 10) {
+ infoArray[j].regNum = 24;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 4 && count <= 10) {
+ infoArray[j].regNum = 25;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 5 && count <= 10) {
+ infoArray[j].regNum = 26;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 6 && count <= 10) {
+ infoArray[j].regNum = 27;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 7 && count <= 10) {
+ infoArray[j].regNum = 28;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 8 && count <= 10) {
+ infoArray[j].regNum = 29;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count >= 9 && count <= 10) {
+ infoArray[j].regNum = 30;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count == 10) {
+ infoArray[j].regNum = 31;
+ infoArray[j].refCount = 2; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ if(count > 10) {
+ //NOTE: inside a loop, LOOP_COUNT can't be 1
+ // if LOOP_COUNT is 1, it is likely that a logical register is freed inside the loop
+ // and the next iteration will have incorrect result
+ infoArray[j].regNum = 12;
+ infoArray[j].refCount = 1+3*LOOP_COUNT; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ infoArray[j].regNum = 13;
+ infoArray[j].refCount = 1+LOOP_COUNT; //DU
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ infoArray[j].regNum = 14;
+ //MUST be 2, otherwise, transferToState will think its state was in memory
+ infoArray[j].refCount = 2; //DU local
+ infoArray[j].physicalType = LowOpndRegType_gp;
+ j++;
+ }
+ return j;
+}
+
+/* update temporaries used by RETURN bytecodes
+ a temporary is represented by <number, type of the temporary>
+ */
+int updateReturnCommon(TempRegInfo* infoArray) {
+ int numTmps;
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4; //DU
+ infoArray[0].physicalType = LowOpndRegType_scratch;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+ infoArray[2].regNum = PhysicalReg_EAX;
+ infoArray[2].refCount = 5; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[3].regNum = 1;
+#if defined(ENABLE_TRACING)//WITH_DEBUGGER is true WITH_PROFILER can be false
+ infoArray[3].refCount = 6+4;
+#else
+ infoArray[3].refCount = 6; //DU
+#endif
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 2;
+ infoArray[4].refCount = 4; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = 5;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_gp;
+ infoArray[6].regNum = 10;
+ infoArray[6].refCount = 3;
+ infoArray[6].physicalType = LowOpndRegType_gp;
+ infoArray[7].regNum = 6;
+ infoArray[7].refCount = 4; //DU
+ infoArray[7].physicalType = LowOpndRegType_gp;
+ infoArray[8].regNum = 3;
+ infoArray[8].refCount = 3;
+ infoArray[8].physicalType = LowOpndRegType_gp;
+ infoArray[9].regNum = 7;
+ infoArray[9].refCount = 2; //DU
+ infoArray[9].physicalType = LowOpndRegType_gp;
+ numTmps = 12;
+#if defined(ENABLE_TRACING)
+ infoArray[12].regNum = 4;
+ infoArray[12].refCount = 3; //DU
+ infoArray[12].physicalType = LowOpndRegType_gp;
+ infoArray[13].regNum = 3;
+ infoArray[13].refCount = 2; //DU
+ infoArray[13].physicalType = LowOpndRegType_scratch;
+ infoArray[14].regNum = 15;
+ infoArray[14].refCount = 2; //DU
+ infoArray[14].physicalType = LowOpndRegType_gp;
+ infoArray[15].regNum = 16;
+ infoArray[15].refCount = 2; //DU
+ infoArray[15].physicalType = LowOpndRegType_gp;
+ infoArray[16].regNum = PhysicalReg_EDX;
+ infoArray[16].refCount = 2; //DU
+ infoArray[16].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[17].regNum = 6;
+ infoArray[17].refCount = 2; //DU
+ infoArray[17].physicalType = LowOpndRegType_scratch;
+ numTmps = 18;
+#endif
+ infoArray[10].regNum = 14;
+ infoArray[10].refCount = 2; //DU
+ infoArray[10].physicalType = LowOpndRegType_gp;
+ infoArray[11].regNum = 4;
+ infoArray[11].refCount = 2; //DU
+ infoArray[11].physicalType = LowOpndRegType_scratch;
+#ifdef DEBUG_CALL_STACK
+ infoArray[numTmps].regNum = 5;
+ infoArray[numTmps].refCount = 2;
+ infoArray[numTmps].physicalType = LowOpndRegType_scratch;
+ numTmps++;
+#endif
+ infoArray[numTmps].regNum = PhysicalReg_EBX;
+ /* used to hold chaining cell
+ updated to be returnAddr
+ then conditionally updated to zero
+ used to update inJitCodeCache
+ compare against zero to determine whether to jump to native code
+ jump to native code (%ebx)
+ */
+ infoArray[numTmps].refCount = 3+1+1;
+ infoArray[numTmps].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ numTmps++;
+ infoArray[numTmps].regNum = 17;
+ infoArray[numTmps].refCount = 2; //DU
+ infoArray[numTmps].physicalType = LowOpndRegType_gp;
+ numTmps++;
+ infoArray[numTmps].regNum = 7;
+ infoArray[numTmps].refCount = 4; //DU
+ infoArray[numTmps].physicalType = LowOpndRegType_scratch;
+ numTmps++;
+ return numTmps;
+}
+
+/* update temporaries used by predicted INVOKE_VIRTUAL & INVOKE_INTERFACE */
+int updateGenPrediction(TempRegInfo* infoArray, bool isInterface) {
+ infoArray[0].regNum = 40;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 41;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 32;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+
+ if(isInterface) {
+ infoArray[0].refCount = 2+2;
+ infoArray[1].refCount = 3+2-1; //for temp41, -1 for gingerbread
+ infoArray[3].regNum = 33;
+ infoArray[3].refCount = 4+1;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = PhysicalReg_EAX;
+ infoArray[4].refCount = 5;
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[5].regNum = PhysicalReg_ECX;
+ infoArray[5].refCount = 1+1+2; //used in ArgsDone (twice)
+ infoArray[5].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[6].regNum = 10;
+ infoArray[6].refCount = 2;
+ infoArray[6].physicalType = LowOpndRegType_scratch;
+ infoArray[7].regNum = 9;
+ infoArray[7].refCount = 2;
+ infoArray[7].physicalType = LowOpndRegType_scratch;
+ infoArray[8].regNum = 8;
+ infoArray[8].refCount = 2;
+ infoArray[8].physicalType = LowOpndRegType_scratch;
+ infoArray[9].regNum = PhysicalReg_EDX; //space holder
+ infoArray[9].refCount = 1;
+ infoArray[9].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[10].regNum = 43;
+ infoArray[10].refCount = 3;
+ infoArray[10].physicalType = LowOpndRegType_gp;
+ infoArray[11].regNum = 44;
+ infoArray[11].refCount = 3;
+ infoArray[11].physicalType = LowOpndRegType_gp;
+ infoArray[12].regNum = 45;
+ infoArray[12].refCount = 2;
+ infoArray[12].physicalType = LowOpndRegType_gp;
+ infoArray[13].regNum = 7;
+ infoArray[13].refCount = 4;
+ infoArray[13].physicalType = LowOpndRegType_scratch;
+ return 14;
+ } else { //virtual or virtual_quick
+ infoArray[0].refCount = 2+2;
+ infoArray[1].refCount = 3+2-2; //for temp41, -2 for gingerbread
+ infoArray[2].refCount++; //for temp32 gingerbread
+ infoArray[3].regNum = 33;
+ infoArray[3].refCount = 4+1;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 34;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = PhysicalReg_EAX;
+ infoArray[5].refCount = 2;
+ infoArray[5].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[6].regNum = PhysicalReg_ECX;
+ infoArray[6].refCount = 1+3+2;
+ infoArray[6].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[7].regNum = 10;
+ infoArray[7].refCount = 2;
+ infoArray[7].physicalType = LowOpndRegType_scratch;
+ infoArray[8].regNum = PhysicalReg_EDX; //space holder
+ infoArray[8].refCount = 1;
+ infoArray[8].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[9].regNum = 43;
+ infoArray[9].refCount = 3;
+ infoArray[9].physicalType = LowOpndRegType_gp;
+ infoArray[10].regNum = 44;
+ infoArray[10].refCount = 3;
+ infoArray[10].physicalType = LowOpndRegType_gp;
+ infoArray[11].regNum = 7;
+ infoArray[11].refCount = 4;
+ infoArray[11].physicalType = LowOpndRegType_scratch;
+ return 12;
+ }
+}
+
+int updateMarkCard(TempRegInfo* infoArray, int j1/*valReg*/,
+ int j2/*tgtAddrReg*/, int j3/*scratchReg*/) {
+ infoArray[j3].regNum = 11;
+ infoArray[j3].physicalType = LowOpndRegType_gp;
+ infoArray[j3].refCount = 3;
+ infoArray[j3].is8Bit = true;
+ infoArray[j1].refCount++;
+ infoArray[j2].refCount += 2;
+ infoArray[j3+1].regNum = 6;
+ infoArray[j3+1].physicalType = LowOpndRegType_scratch;
+ infoArray[j3+1].refCount = 2;
+ return j3+2;
+}
+
+int updateMarkCard_notNull(TempRegInfo* infoArray,
+ int j2/*tgtAddrReg*/, int j3/*scratchReg*/) {
+ infoArray[j3].regNum = 11;
+ infoArray[j3].physicalType = LowOpndRegType_gp;
+ infoArray[j3].refCount = 3;
+ infoArray[j3].is8Bit = true;
+ infoArray[j2].refCount += 2;
+ infoArray[j3+1].regNum = 2;
+ infoArray[j3+1].refCount = 2; //DU
+ infoArray[j3+1].physicalType = LowOpndRegType_scratch;
+ return j3+2;
+}
+
+int iget_obj_inst = -1;
+//! This function updates infoArray with temporaries accessed when lowering the bytecode
+
+//! returns the number of temporaries
+int getTempRegInfo(TempRegInfo* infoArray) { //returns an array of TempRegInfo
+ int k;
+ int numTmps;
+ for(k = 0; k < MAX_TEMP_REG_PER_BYTECODE; k++) {
+ infoArray[k].linkageToVR = -1;
+ infoArray[k].versionNum = 0;
+ infoArray[k].shareWithVR = true;
+ infoArray[k].is8Bit = false;
+ }
+ u2 vA, v1, length, num, tmp;
+ u2 inst_op = INST_INST(inst);
+ s2 tmp_s2;
+ s4 tmp_s4;
+ switch(inst_op) {
+ case OP_APUT_BYTE:
+ for(k = 0; k < MAX_TEMP_REG_PER_BYTECODE; k++)
+ infoArray[k].shareWithVR = true; //false;
+ break;
+ }
+ switch (INST_INST(inst)) {
+ case OP_NOP:
+ return 0;
+ case OP_MOVE:
+ case OP_MOVE_OBJECT:
+ case OP_MOVE_FROM16:
+ case OP_MOVE_OBJECT_FROM16:
+ case OP_MOVE_16:
+ case OP_MOVE_OBJECT_16:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ return 1;
+ case OP_MOVE_WIDE:
+ case OP_MOVE_WIDE_FROM16:
+ case OP_MOVE_WIDE_16:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ return 1;
+ case OP_MOVE_RESULT:
+ case OP_MOVE_RESULT_OBJECT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+ return 2;
+ case OP_MOVE_RESULT_WIDE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+ return 2;
+ case OP_MOVE_EXCEPTION:
+ infoArray[0].regNum = 2;
+ infoArray[0].refCount = 3; //DUU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 3;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 1;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_scratch;
+ return 3;
+
+ case OP_CONST_4:
+ case OP_CONST_16:
+ case OP_CONST:
+ case OP_CONST_HIGH16:
+ case OP_CONST_WIDE_16:
+ case OP_CONST_WIDE_32:
+ case OP_CONST_WIDE:
+ case OP_CONST_WIDE_HIGH16:
+ return 0;
+ case OP_CONST_STRING: //hardcode %eax
+ case OP_CONST_STRING_JUMBO:
+ infoArray[0].regNum = 3;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+ infoArray[2].regNum = 2;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_scratch;
+ infoArray[3].regNum = PhysicalReg_EAX;
+ infoArray[3].refCount = 4;
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 4;
+ case OP_CONST_CLASS:
+ infoArray[0].regNum = 3;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+ infoArray[2].regNum = 2;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_scratch;
+ infoArray[3].regNum = PhysicalReg_EAX;
+ infoArray[3].refCount = 4;
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 4;
+
+ case OP_MONITOR_ENTER:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 3;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 1;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_scratch;
+ infoArray[3].regNum = 2;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_scratch;
+ infoArray[4].regNum = PhysicalReg_EDX;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 5;
+ case OP_MONITOR_EXIT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = PhysicalReg_EAX;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[2].regNum = 1;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_scratch;
+ infoArray[3].regNum = PhysicalReg_EDX;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[4].regNum = 2;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_scratch;
+ infoArray[5].regNum = 3;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_scratch;
+ return 6;
+ case OP_CHECK_CAST:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 4;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 6;
+ infoArray[2].refCount = 3; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+
+ infoArray[3].regNum = 1;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_scratch;
+ infoArray[4].regNum = 2;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_scratch;
+
+ infoArray[5].regNum = PhysicalReg_EAX;
+ /* %eax has 3 live ranges
+ 1> 5 accesses: to resolve the class object
+ 2> call dvmInstanceofNonTrivial to define %eax, then use it once
+ 3> move exception object to %eax, then jump to throw_exception
+ if WITH_JIT is true, the first live range has 6 accesses
+ */
+ infoArray[5].refCount = 6;
+ infoArray[5].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[6].regNum = PhysicalReg_EDX;
+ infoArray[6].refCount = 2; //export_pc
+ infoArray[6].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[7].regNum = PhysicalReg_ECX;
+ infoArray[7].refCount = 1;
+ infoArray[7].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[8].regNum = 3;
+ infoArray[8].refCount = 2; //DU
+ infoArray[8].physicalType = LowOpndRegType_scratch;
+ return 9;
+ case OP_INSTANCE_OF:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 3;
+ infoArray[1].refCount = 4; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 4;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 6;
+ infoArray[3].refCount = 3; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+
+ infoArray[4].regNum = 1;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_scratch;
+ infoArray[5].regNum = 2;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_scratch;
+
+ infoArray[6].regNum = PhysicalReg_EAX;
+ infoArray[6].refCount = 6;
+ infoArray[6].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[7].regNum = 3;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_scratch;
+ infoArray[8].regNum = PhysicalReg_EDX;
+ infoArray[8].refCount = 2; //export_pc for class_resolve
+ infoArray[8].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 9;
+
+ case OP_ARRAY_LENGTH:
+ vA = INST_A(inst);
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[1].linkageToVR = vA;
+ infoArray[2].regNum = PhysicalReg_EDX;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 3;
+ case OP_NEW_INSTANCE:
+ infoArray[0].regNum = PhysicalReg_EAX;
+ //6: class object
+ //3: defined by C function, used twice
+ infoArray[0].refCount = 6; //next version has 3 references
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[1].regNum = PhysicalReg_ECX; //before common_throw_message
+ infoArray[1].refCount = 1;
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 5;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[3].is8Bit = true;
+ infoArray[4].regNum = 6;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+
+ infoArray[5].regNum = 1;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_scratch;
+ infoArray[6].regNum = 2;
+ infoArray[6].refCount = 2; //DU
+ infoArray[6].physicalType = LowOpndRegType_scratch;
+ infoArray[7].regNum = 3;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_scratch;
+
+ infoArray[8].regNum = PhysicalReg_EDX; //before common_throw_message
+ infoArray[8].refCount = 2;
+ infoArray[8].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[9].regNum = 4;
+ infoArray[9].refCount = 2; //DU
+ infoArray[9].physicalType = LowOpndRegType_scratch;
+ return 10;
+
+ case OP_NEW_ARRAY:
+ infoArray[0].regNum = PhysicalReg_EAX;
+ //4: class object
+ //3: defined by C function, used twice
+ infoArray[0].refCount = 4; //next version has 3 references
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[1].regNum = PhysicalReg_EDX; //before common_throw_message
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 5;
+ infoArray[3].refCount = 3; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+
+ infoArray[4].regNum = 1;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_scratch;
+ infoArray[5].regNum = 2;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_scratch;
+ infoArray[6].regNum = 3;
+ infoArray[6].refCount = 2; //DU
+ infoArray[6].physicalType = LowOpndRegType_scratch;
+ infoArray[7].regNum = 4;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_scratch;
+ return 8;
+
+ case OP_FILLED_NEW_ARRAY:
+ length = INST_B(inst);
+ infoArray[0].regNum = PhysicalReg_EAX;
+ //4: class object
+ //3: defined by C function, used twice (array object)
+ //length: access array object to update the content
+ infoArray[0].refCount = 4; //next version has 5+length references
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[1].regNum = PhysicalReg_EDX; //before common_throw_message
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 5;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 6;
+ infoArray[4].refCount = 8; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[4].is8Bit = true;
+
+ if(length >= 1) {
+ infoArray[5].regNum = 7;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_gp;
+ }
+ if(length >= 2) {
+ infoArray[6].regNum = 8;
+ infoArray[6].refCount = 2; //DU
+ infoArray[6].physicalType = LowOpndRegType_gp;
+ }
+ if(length >= 3) {
+ infoArray[7].regNum = 9;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_gp;
+ }
+ if(length >= 4) {
+ infoArray[8].regNum = 10;
+ infoArray[8].refCount = 2; //DU
+ infoArray[8].physicalType = LowOpndRegType_gp;
+ }
+ if(length >= 5) {
+ infoArray[9].regNum = 11;
+ infoArray[9].refCount = 2; //DU
+ infoArray[9].physicalType = LowOpndRegType_gp;
+ }
+ infoArray[5+length].regNum = 1;
+ infoArray[5+length].refCount = 2; //DU
+ infoArray[5+length].physicalType = LowOpndRegType_scratch;
+ infoArray[6+length].regNum = 2;
+ infoArray[6+length].refCount = 4; //DU
+ infoArray[6+length].physicalType = LowOpndRegType_scratch;
+ infoArray[7+length].regNum = 3;
+ infoArray[7+length].refCount = 2; //DU
+ infoArray[7+length].physicalType = LowOpndRegType_scratch;
+ infoArray[8+length].regNum = 4;
+ infoArray[8+length].refCount = 5; //DU
+ infoArray[8+length].physicalType = LowOpndRegType_scratch;
+ return 9+length;
+
+ case OP_FILLED_NEW_ARRAY_RANGE:
+ length = INST_AA(inst);
+ infoArray[0].regNum = PhysicalReg_EAX;
+ //4: class object
+ //3: defined by C function, used twice (array object)
+ //if length is 0, no access to array object
+ //else, used inside a loop
+ infoArray[0].refCount = 4; //next version: 5+(length >= 1 ? LOOP_COUNT : 0)
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[1].regNum = PhysicalReg_EDX; //before common_throw_message
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 5;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 6;
+ infoArray[4].refCount = 8; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[4].is8Bit = true;
+
+ infoArray[5].regNum = 1;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_scratch;
+ infoArray[6].regNum = 2;
+ infoArray[6].refCount = 4; //DU
+ infoArray[6].physicalType = LowOpndRegType_scratch;
+ infoArray[7].regNum = 3;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_scratch;
+
+ infoArray[8].regNum = 7;
+ infoArray[8].refCount = 3*(length >= 1 ? LOOP_COUNT : 0);
+ infoArray[8].physicalType = LowOpndRegType_gp;
+ infoArray[9].regNum = 8;
+ infoArray[9].refCount = 3*(length >= 1 ? LOOP_COUNT : 0);
+ infoArray[9].physicalType = LowOpndRegType_gp;
+ infoArray[10].regNum = 9;
+ infoArray[10].refCount = 2*(length >= 1 ? LOOP_COUNT : 0);
+ infoArray[10].physicalType = LowOpndRegType_gp;
+ infoArray[11].regNum = 10;
+ infoArray[11].refCount = 2*(length >= 1 ? LOOP_COUNT : 0);
+ infoArray[11].physicalType = LowOpndRegType_gp;
+ infoArray[12].regNum = 4;
+ infoArray[12].refCount = 5; //DU
+ infoArray[12].physicalType = LowOpndRegType_scratch;
+ return 13;
+
+ case OP_FILL_ARRAY_DATA:
+ infoArray[0].regNum = PhysicalReg_EAX;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[1].regNum = PhysicalReg_EDX; //before common_throw_message
+#if 0//def HARDREG_OPT
+ infoArray[1].refCount = 3; //next version has refCount of 2
+#else
+ infoArray[1].refCount = 5;
+#endif
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[2].regNum =1;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+
+ infoArray[3].regNum = 1;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_scratch;
+ infoArray[4].regNum = 2;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_scratch;
+ return 5;
+
+ case OP_THROW:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = PhysicalReg_EDX; //before common_throw_message
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[2].regNum = 1;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_scratch;
+ infoArray[3].regNum = 2;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_scratch;
+ return 4;
+ case OP_THROW_VERIFICATION_ERROR:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = PhysicalReg_EDX; //export_pc
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[2].regNum = 1;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_scratch;
+ infoArray[3].regNum = 2;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_scratch;
+ return 4;
+
+ case OP_GOTO: //called function common_periodicChecks4
+#if defined(ENABLE_TRACING)
+ tt = INST_AA(inst);
+ tmp_s2 = (s2)((s2)tt << 8) >> 8;
+ if(tmp_s2 < 0) {
+ infoArray[0].regNum = PhysicalReg_EDX;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 1;
+ }
+#endif
+ return 0;
+ case OP_GOTO_16:
+#if defined(ENABLE_TRACING)
+ tmp_s2 = (s2)FETCH(1);
+ if(tmp_s2 < 0) {
+ infoArray[0].regNum = PhysicalReg_EDX;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 1;
+ }
+#endif
+ return 0;
+ case OP_GOTO_32:
+#if defined(ENABLE_TRACING)
+ tmp_u4 = (u4)FETCH(1);
+ tmp_u4 |= (u4)FETCH(2) << 16;
+ if(((s4)tmp_u4) < 0) {
+ infoArray[0].regNum = PhysicalReg_EDX;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 1;
+ }
+#endif
+ return 0;
+ case OP_IF_EQ:
+ case OP_IF_NE:
+ case OP_IF_LT:
+ case OP_IF_GE:
+ case OP_IF_GT:
+ case OP_IF_LE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+#if defined(ENABLE_TRACING)
+ tmp_s2 = (s2)FETCH(1);
+ if(tmp_s2 < 0) {
+ infoArray[1].regNum = PhysicalReg_EDX;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 2;
+ }
+#endif
+ return 1;
+ case OP_IF_EQZ: //called function common_periodicChecks4
+ case OP_IF_NEZ:
+ case OP_IF_LTZ:
+ case OP_IF_GEZ:
+ case OP_IF_GTZ:
+ case OP_IF_LEZ:
+#if defined(ENABLE_TRACING)
+ tmp_s2 = (s2)FETCH(1);
+ if(tmp_s2 < 0) {
+ infoArray[0].regNum = PhysicalReg_EDX;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 1;
+ }
+#endif
+ return 0;
+ case OP_PACKED_SWITCH: //jump common_backwardBranch, which calls common_periodicChecks_entry, then jump_reg %eax
+ case OP_SPARSE_SWITCH: //%edx, %eax
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = PhysicalReg_EDX;
+ infoArray[1].refCount = 6;
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[2].regNum = PhysicalReg_EAX; //return by dvm helper
+ infoArray[2].refCount = 2+1; //2 uses
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[3].regNum = 1;
+ infoArray[3].refCount = 2;
+ infoArray[3].physicalType = LowOpndRegType_scratch;
+ infoArray[4].regNum = 2;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_scratch;
+ return 5;
+
+ case OP_AGET:
+ case OP_AGET_OBJECT:
+ case OP_AGET_BOOLEAN:
+ case OP_AGET_BYTE:
+ case OP_AGET_CHAR:
+ case OP_AGET_SHORT:
+ vA = INST_AA(inst);
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 4;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[3].linkageToVR = vA;
+ if(inst_op == OP_AGET_BYTE || inst_op == OP_AGET_BOOLEAN)
+ infoArray[3].is8Bit = true;
+ infoArray[4].regNum = PhysicalReg_EDX;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 5;
+ case OP_AGET_WIDE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 1;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_xmm;
+ infoArray[4].regNum = PhysicalReg_EDX;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 5;
+
+ case OP_APUT:
+ case OP_APUT_BOOLEAN:
+ case OP_APUT_BYTE:
+ case OP_APUT_CHAR:
+ case OP_APUT_SHORT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 4;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ if(inst_op == OP_APUT_BYTE || inst_op == OP_APUT_BOOLEAN)
+ infoArray[3].is8Bit = true;
+ infoArray[4].regNum = PhysicalReg_EDX;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 5;
+ case OP_APUT_WIDE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 1;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_xmm;
+ infoArray[4].regNum = PhysicalReg_EDX;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 5;
+ case OP_APUT_OBJECT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 5+1; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2; //live through function call dvmCanPut
+ infoArray[1].refCount = 3+1; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 4;
+ infoArray[3].refCount = 4+1; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 5;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = 6;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_gp;
+
+ infoArray[6].regNum = PhysicalReg_EDX;
+ infoArray[6].refCount = 2; //DU
+ infoArray[6].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[7].regNum = PhysicalReg_EAX;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[8].regNum = 1;
+ infoArray[8].refCount = 2; //DU
+ infoArray[8].physicalType = LowOpndRegType_scratch;
+ infoArray[0].shareWithVR = false;
+ return updateMarkCard_notNull(infoArray,
+ 0/*index for tgtAddrReg*/, 9);
+
+ case OP_IGET:
+ case OP_IGET_OBJECT:
+ case OP_IGET_VOLATILE:
+ case OP_IGET_OBJECT_VOLATILE:
+ case OP_IGET_BOOLEAN:
+ case OP_IGET_BYTE:
+ case OP_IGET_CHAR:
+ case OP_IGET_SHORT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_scratch;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+
+ infoArray[2].regNum = PhysicalReg_EDX;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[3].regNum = PhysicalReg_EAX;
+ infoArray[3].refCount = 3; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[4].regNum = 3;
+ infoArray[4].refCount = 3; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = 7;
+#ifdef DEBUG_IGET_OBJ
+ //add hack for a specific instance (iget_obj_inst) of IGET_OBJECT within a method
+ if(inst_op == OP_IGET_OBJECT && !strncmp(currentMethod->clazz->descriptor, "Lspec/benchmarks/_228_jack/Parse", 32) &&
+ !strncmp(currentMethod->name, "buildPhase3", 11))
+ {
+#if 0
+ if(iget_obj_inst == 12) {
+ LOGD("increase count for instance %d of %s %s", iget_obj_inst, currentMethod->clazz->descriptor, currentMethod->name);
+ infoArray[5].refCount = 4; //DU
+ }
+ else
+#endif
+ infoArray[5].refCount = 3;
+ iget_obj_inst++;
+ }
+ else
+ infoArray[5].refCount = 3;
+#else
+ infoArray[5].refCount = 3; //DU
+#endif
+ infoArray[5].physicalType = LowOpndRegType_gp;
+ infoArray[6].regNum = 8;
+ infoArray[6].refCount = 2; //DU
+ infoArray[6].physicalType = LowOpndRegType_gp;
+ infoArray[7].regNum = 9;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_gp;
+ return 8;
+ case OP_IPUT:
+ case OP_IPUT_OBJECT:
+ case OP_IPUT_VOLATILE:
+ case OP_IPUT_OBJECT_VOLATILE:
+ case OP_IPUT_BOOLEAN:
+ case OP_IPUT_BYTE:
+ case OP_IPUT_CHAR:
+ case OP_IPUT_SHORT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_scratch;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+
+ infoArray[2].regNum = PhysicalReg_EDX;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[3].regNum = PhysicalReg_EAX;
+ infoArray[3].refCount = 3; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[4].regNum = 3;
+ infoArray[4].refCount = 3; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = 7;
+ infoArray[5].refCount = 3; //DU
+ infoArray[5].physicalType = LowOpndRegType_gp;
+ infoArray[6].regNum = 8;
+ infoArray[6].refCount = 2; //DU
+ infoArray[6].physicalType = LowOpndRegType_gp;
+ infoArray[7].regNum = 9;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_gp;
+ if(inst_op == OP_IPUT_OBJECT || inst_op == OP_IPUT_OBJECT_VOLATILE) {
+ infoArray[5].shareWithVR = false;
+ return updateMarkCard(infoArray, 7/*index for valReg*/,
+ 5/*index for tgtAddrReg*/, 8);
+ }
+ return 8;
+ case OP_IGET_WIDE:
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IPUT_WIDE:
+ case OP_IPUT_WIDE_VOLATILE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_scratch;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+
+ infoArray[2].regNum = PhysicalReg_EDX;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[3].regNum = PhysicalReg_EAX;
+ infoArray[3].refCount = 3; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[4].regNum = 3;
+ infoArray[4].refCount = 3; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = 7;
+ infoArray[5].refCount = 3; //DU
+ infoArray[5].physicalType = LowOpndRegType_gp;
+ infoArray[6].regNum = 8;
+ infoArray[6].refCount = 2; //DU
+ infoArray[6].physicalType = LowOpndRegType_gp;
+ infoArray[7].regNum = 1;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_xmm;
+
+ if(inst_op == OP_IPUT_WIDE_VOLATILE || inst_op == OP_IGET_WIDE_VOLATILE) {
+ infoArray[8].regNum = 3;
+ infoArray[8].refCount = 2; //DU
+ infoArray[8].physicalType = LowOpndRegType_scratch;
+ infoArray[9].regNum = 9;
+ infoArray[9].refCount = 2; //DU
+ infoArray[9].physicalType = LowOpndRegType_gp;
+ return 10;
+ }
+ return 8;
+
+ case OP_SGET:
+ case OP_SGET_OBJECT:
+ case OP_SGET_VOLATILE:
+ case OP_SGET_OBJECT_VOLATILE:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_BYTE:
+ case OP_SGET_CHAR:
+ case OP_SGET_SHORT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_scratch;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+
+ infoArray[2].regNum = PhysicalReg_EAX;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[3].regNum = 3;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 7;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = PhysicalReg_EDX;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 6;
+ case OP_SPUT:
+ case OP_SPUT_OBJECT:
+ case OP_SPUT_VOLATILE:
+ case OP_SPUT_OBJECT_VOLATILE:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_SHORT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_scratch;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+
+ infoArray[2].regNum = PhysicalReg_EAX;
+ infoArray[2].refCount = 2+1; //access clazz of the field
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[3].regNum = 3;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 7;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = PhysicalReg_EDX;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ if(inst_op == OP_SPUT_OBJECT || inst_op == OP_SPUT_OBJECT_VOLATILE) {
+ infoArray[2].shareWithVR = false;
+ infoArray[6].regNum = 12;
+ infoArray[6].refCount = 1; //1 def, 2 uses in updateMarkCard
+ infoArray[6].physicalType = LowOpndRegType_gp;
+ return updateMarkCard(infoArray, 4/*index for valReg*/,
+ 6/*index for tgtAddrReg */, 7);
+ }
+ return 6;
+ case OP_SGET_WIDE:
+ case OP_SGET_WIDE_VOLATILE:
+ case OP_SPUT_WIDE:
+ case OP_SPUT_WIDE_VOLATILE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_scratch;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_scratch;
+
+ infoArray[2].regNum = PhysicalReg_EAX;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[3].regNum = 3;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 1;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_xmm;
+ infoArray[5].regNum = PhysicalReg_EDX;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ if(inst_op == OP_SPUT_WIDE_VOLATILE || inst_op == OP_SGET_WIDE_VOLATILE) {
+ infoArray[6].regNum = 3;
+ infoArray[6].refCount = 2; //DU
+ infoArray[6].physicalType = LowOpndRegType_scratch;
+ infoArray[7].regNum = 9;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_gp;
+ return 8;
+ }
+ return 6;
+
+ case OP_IGET_QUICK:
+ case OP_IGET_OBJECT_QUICK:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = PhysicalReg_EDX;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 3;
+ case OP_IPUT_QUICK:
+ case OP_IPUT_OBJECT_QUICK:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = PhysicalReg_EDX;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ if(inst_op == OP_IPUT_OBJECT_QUICK) {
+ infoArray[0].shareWithVR = false;
+ return updateMarkCard(infoArray, 1/*index for valReg*/,
+ 0/*index for tgtAddrReg*/, 3);
+ }
+ return 3;
+ case OP_IGET_WIDE_QUICK:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[2].regNum = PhysicalReg_EDX;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 3;
+ case OP_IPUT_WIDE_QUICK:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[2].regNum = PhysicalReg_EDX;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 3;
+
+ case OP_RETURN_VOID:
+ case OP_RETURN_VOID_BARRIER:
+ return updateReturnCommon(infoArray);
+ case OP_RETURN:
+ case OP_RETURN_OBJECT:
+ numTmps = updateReturnCommon(infoArray);
+
+ infoArray[numTmps].regNum = 21;
+ infoArray[numTmps].refCount = 2; //DU
+ infoArray[numTmps].physicalType = LowOpndRegType_gp;
+ numTmps++;
+ infoArray[numTmps].regNum = 22;
+ infoArray[numTmps].refCount = 2; //DU
+ infoArray[numTmps].physicalType = LowOpndRegType_gp;
+ numTmps++;
+ return numTmps;
+ case OP_RETURN_WIDE:
+ numTmps = updateReturnCommon(infoArray);
+
+ infoArray[numTmps].regNum = 10;
+ infoArray[numTmps].refCount = 2; //DU
+ infoArray[numTmps].physicalType = LowOpndRegType_scratch;
+ numTmps++;
+ infoArray[numTmps].regNum = 1;
+ infoArray[numTmps].refCount = 2; //DU
+ infoArray[numTmps].physicalType = LowOpndRegType_xmm;
+ numTmps++;
+ return numTmps;
+
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_VIRTUAL_RANGE:
+#ifdef PREDICTED_CHAINING
+ numTmps = updateGenPrediction(infoArray, false /*not interface*/);
+ infoArray[numTmps].regNum = 5;
+ infoArray[numTmps].refCount = 3; //DU
+ infoArray[numTmps].physicalType = LowOpndRegType_gp;
+ numTmps++;
+ if(inst_op == OP_INVOKE_VIRTUAL)
+ k = updateInvokeNoRange(infoArray, numTmps);
+ else
+ k = updateInvokeRange(infoArray, numTmps);
+ return k;
+#else
+ infoArray[0].regNum = 3;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 7;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 8;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 6;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 5;
+ infoArray[4].refCount = 3; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = PhysicalReg_EDX;
+ infoArray[5].refCount = 2; //2 versions, first version DU is for exception, 2nd version: eip right before jumping to invokeArgsDone
+ infoArray[5].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[6].regNum = PhysicalReg_ECX; //ecx is ued in invokeArgsDone
+ infoArray[6].refCount = 1+1; //used in .invokeArgsDone
+ infoArray[6].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ //when WITH_JIT is true and PREDICTED_CHAINING is false
+ // temp 8 and EAX are not used; but it is okay to keep it here
+ infoArray[7].regNum = PhysicalReg_EAX;
+ infoArray[7].refCount = 4; //DU
+ infoArray[7].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[8].regNum = 1;
+ infoArray[8].refCount = 2; //DU
+ infoArray[8].physicalType = LowOpndRegType_scratch;
+ infoArray[9].regNum = 2;
+ infoArray[9].refCount = 2; //DU
+ infoArray[9].physicalType = LowOpndRegType_scratch;
+ if(inst_op == OP_INVOKE_VIRTUAL)
+ k = updateInvokeNoRange(infoArray, 10);
+ else
+ k = updateInvokeRange(infoArray, 10);
+ return k;
+#endif
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_SUPER_RANGE:
+ infoArray[0].regNum = 3;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 7;
+ infoArray[1].refCount = 3; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 8;
+ infoArray[2].refCount = 3; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 6;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 9;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+
+ infoArray[5].regNum = PhysicalReg_EDX;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[6].regNum = PhysicalReg_ECX;
+ infoArray[6].refCount = 1+1; //DU
+ infoArray[6].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[7].regNum = PhysicalReg_EAX;
+ infoArray[7].refCount = 4; //DU
+ infoArray[7].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[8].regNum = 1;
+ infoArray[8].refCount = 2; //DU
+ infoArray[8].physicalType = LowOpndRegType_scratch;
+ infoArray[9].regNum = 2;
+ infoArray[9].refCount = 2; //DU
+ infoArray[9].physicalType = LowOpndRegType_scratch;
+ infoArray[10].regNum = 3;
+ infoArray[10].refCount = 2; //DU
+ infoArray[10].physicalType = LowOpndRegType_scratch;
+ infoArray[11].regNum = 4;
+ infoArray[11].refCount = 2; //DU
+ infoArray[11].physicalType = LowOpndRegType_scratch;
+ if(inst_op == OP_INVOKE_SUPER)
+ k = updateInvokeNoRange(infoArray, 12);
+ else
+ k = updateInvokeRange(infoArray, 12);
+ return k;
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_DIRECT_RANGE:
+ infoArray[0].regNum = 3;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 5;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+
+ infoArray[2].regNum = PhysicalReg_EDX;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[3].regNum = PhysicalReg_ECX;
+ infoArray[3].refCount = 2;
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[4].regNum = PhysicalReg_EAX;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[5].regNum = 1;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_scratch;
+ infoArray[6].regNum = 2;
+ infoArray[6].refCount = 2; //DU
+ infoArray[6].physicalType = LowOpndRegType_scratch;
+ if(inst_op == OP_INVOKE_DIRECT)
+ k = updateInvokeNoRange(infoArray, 7);
+ else
+ k = updateInvokeRange(infoArray, 7);
+ return k;
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_STATIC_RANGE:
+ infoArray[0].regNum = 3;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+
+ infoArray[1].regNum = PhysicalReg_EDX;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[2].regNum = PhysicalReg_ECX;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[3].regNum = PhysicalReg_EAX;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[4].regNum = 1;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_scratch;
+ infoArray[5].regNum = 2;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_scratch;
+ if(inst_op == OP_INVOKE_STATIC)
+ k = updateInvokeNoRange(infoArray, 6);
+ else
+ k = updateInvokeRange(infoArray, 6);
+ return k;
+ case OP_INVOKE_INTERFACE:
+ case OP_INVOKE_INTERFACE_RANGE:
+#ifdef PREDICTED_CHAINING
+ numTmps = updateGenPrediction(infoArray, true /*interface*/);
+ infoArray[numTmps].regNum = 1;
+ infoArray[numTmps].refCount = 3; //DU
+ infoArray[numTmps].physicalType = LowOpndRegType_gp;
+ numTmps++;
+ if(inst_op == OP_INVOKE_INTERFACE)
+ k = updateInvokeNoRange(infoArray, numTmps);
+ else
+ k = updateInvokeRange(infoArray, numTmps);
+ return k;
+#else
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 3;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 4;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 5;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+
+ infoArray[4].regNum = PhysicalReg_EDX;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[5].regNum = PhysicalReg_ECX;
+ infoArray[5].refCount = 1+1; //DU
+ infoArray[5].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[6].regNum = PhysicalReg_EAX;
+ infoArray[6].refCount = 2+1; //2 uses
+ infoArray[6].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[7].regNum = 1;
+ infoArray[7].refCount = 2; //DU
+ infoArray[7].physicalType = LowOpndRegType_scratch;
+ infoArray[8].regNum = 2;
+ infoArray[8].refCount = 2; //DU
+ infoArray[8].physicalType = LowOpndRegType_scratch;
+ infoArray[9].regNum = 3;
+ infoArray[9].refCount = 2; //DU
+ infoArray[9].physicalType = LowOpndRegType_scratch;
+ if(inst_op == OP_INVOKE_INTERFACE)
+ k = updateInvokeNoRange(infoArray, 10);
+ else
+ k = updateInvokeRange(infoArray, 10);
+ return k;
+#endif
+ ////////////////////////////////////////////// ALU
+ case OP_NEG_INT:
+ case OP_NOT_INT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[0].shareWithVR = false;
+ return 1;
+ case OP_NEG_LONG:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //define, use
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 4; //define, update, use
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ return 2;
+ case OP_NOT_LONG:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ return 2;
+ case OP_NEG_FLOAT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[0].shareWithVR = false;
+ return 1;
+ case OP_NEG_DOUBLE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //define, use
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3; //define, update, use
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ return 2;
+ case OP_INT_TO_LONG: //hard-code eax & edx
+ infoArray[0].regNum = PhysicalReg_EAX;
+ infoArray[0].refCount = 2+1;
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = PhysicalReg_EDX;
+ infoArray[1].refCount = 1+1; //cdq accesses edx & eax
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 2;
+ case OP_INT_TO_FLOAT:
+ case OP_INT_TO_DOUBLE:
+ case OP_LONG_TO_FLOAT:
+ case OP_LONG_TO_DOUBLE:
+ case OP_FLOAT_TO_DOUBLE:
+ case OP_DOUBLE_TO_FLOAT:
+ return 0; //fp stack
+ case OP_LONG_TO_INT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ return 1;
+ case OP_FLOAT_TO_INT:
+ case OP_DOUBLE_TO_INT: //fp stack
+ return 0;
+ case OP_FLOAT_TO_LONG:
+ case OP_DOUBLE_TO_LONG:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //define, use
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //define, use
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //define, use
+ infoArray[2].physicalType = LowOpndRegType_xmm;
+ return 3;
+ case OP_INT_TO_BYTE:
+ case OP_INT_TO_CHAR:
+ case OP_INT_TO_SHORT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4; //define, update, update, use
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[0].shareWithVR = false;
+ return 1;
+
+ case OP_ADD_INT:
+ case OP_SUB_INT:
+ case OP_MUL_INT:
+ case OP_AND_INT:
+ case OP_OR_INT:
+ case OP_XOR_INT:
+ case OP_ADD_INT_2ADDR:
+ case OP_SUB_INT_2ADDR:
+ case OP_MUL_INT_2ADDR:
+ case OP_AND_INT_2ADDR:
+ case OP_OR_INT_2ADDR:
+ case OP_XOR_INT_2ADDR:
+ if(inst_op == OP_ADD_INT || inst_op == OP_SUB_INT || inst_op == OP_MUL_INT ||
+ inst_op == OP_AND_INT || inst_op == OP_OR_INT || inst_op == OP_XOR_INT) {
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ } else {
+ vA = INST_A(inst);
+ v1 = vA;
+ }
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ if(vA != v1)
+ infoArray[0].shareWithVR = false;
+ return 1; //common_alu_int
+
+ case OP_SHL_INT:
+ case OP_SHR_INT:
+ case OP_USHR_INT:
+ case OP_SHL_INT_2ADDR:
+ case OP_SHR_INT_2ADDR:
+ case OP_USHR_INT_2ADDR: //use %cl or %ecx?
+ if(inst_op == OP_SHL_INT || inst_op == OP_SHR_INT || inst_op == OP_USHR_INT) {
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ } else {
+ vA = INST_A(inst);
+ v1 = vA;
+ }
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ if(vA != v1)
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = PhysicalReg_ECX;
+ infoArray[1].refCount = 2; //define, use
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 2;//common_shift_int
+
+ case OP_DIV_INT:
+ case OP_REM_INT:
+ case OP_DIV_INT_2ADDR:
+ case OP_REM_INT_2ADDR: //hard-code %eax, %edx (dividend in edx:eax; quotient in eax; remainder in edx)
+ infoArray[0].regNum = 2;
+ infoArray[0].refCount = 4; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = PhysicalReg_EAX; //dividend, quotient
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[1].shareWithVR = false;
+ infoArray[2].regNum = PhysicalReg_EDX; //export_pc, output for REM
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[3].regNum = 1;
+ infoArray[3].refCount = 2; //define, use
+ infoArray[3].physicalType = LowOpndRegType_scratch;
+ if(inst_op == OP_DIV_INT || inst_op == OP_DIV_INT_2ADDR) {
+ infoArray[1].refCount = 5;
+ infoArray[2].refCount = 4;
+ } else {
+ infoArray[1].refCount = 4;
+ infoArray[2].refCount = 5;
+ }
+ return 4;
+
+ case OP_ADD_INT_LIT16:
+ case OP_MUL_INT_LIT16:
+ case OP_AND_INT_LIT16:
+ case OP_OR_INT_LIT16:
+ case OP_XOR_INT_LIT16:
+ case OP_ADD_INT_LIT8:
+ case OP_MUL_INT_LIT8:
+ case OP_AND_INT_LIT8:
+ case OP_OR_INT_LIT8:
+ case OP_XOR_INT_LIT8:
+ case OP_SHL_INT_LIT8:
+ case OP_SHR_INT_LIT8:
+ case OP_USHR_INT_LIT8:
+ if(inst_op == OP_ADD_INT_LIT16 || inst_op == OP_MUL_INT_LIT16 ||
+ inst_op == OP_AND_INT_LIT16 || inst_op == OP_OR_INT_LIT16 || inst_op == OP_XOR_INT_LIT16) {
+ vA = INST_A(inst);
+ v1 = INST_B(inst);
+ } else {
+ vA = INST_AA(inst);
+ v1 = (u2)FETCH(1) & 0xff;
+ }
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ if(vA != v1)
+ infoArray[0].shareWithVR = false;
+ return 1;
+
+ case OP_RSUB_INT_LIT8:
+ case OP_RSUB_INT:
+ vA = INST_AA(inst);
+ v1 = (inst_op == OP_RSUB_INT) ? INST_B(inst) : ((u2)FETCH(1) & 0xff);
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ if(vA != v1)
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ if(vA != v1)
+ infoArray[1].shareWithVR = false;
+ return 2;
+
+ case OP_DIV_INT_LIT16:
+ case OP_REM_INT_LIT16:
+ case OP_DIV_INT_LIT8:
+ case OP_REM_INT_LIT8:
+ if(inst_op == OP_DIV_INT_LIT8 || inst_op == OP_REM_INT_LIT8) {
+ tmp_s2 = (s2)FETCH(1) >> 8;
+ }
+ else {
+ tmp_s4 = (s2)FETCH(1);
+ tmp_s2 = tmp_s4;
+ }
+ if((inst_op == OP_DIV_INT_LIT8 || inst_op == OP_DIV_INT_LIT16)) {
+ int power = isPowerOfTwo(tmp_s2);
+ if(power >= 1) { /* divide by a power of 2 constant */
+ infoArray[0].regNum = 2;
+ infoArray[0].refCount = 3; //define, use, use
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 1;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ if(power == 1) infoArray[1].refCount = 5;
+ else infoArray[1].refCount = 6;
+ return 2;
+ }
+ }
+ if(tmp_s2 == 0) {
+ //export_pc
+ infoArray[0].regNum = PhysicalReg_EDX; //export_pc, output for REM
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 1;
+ }
+ if(inst_op == OP_DIV_INT_LIT16 || inst_op == OP_DIV_INT_LIT8) {
+ if(tmp_s2 == -1)
+ infoArray[1].refCount = 4+1;
+ else
+ infoArray[1].refCount = 4;
+ infoArray[2].refCount = 2; //edx
+ } else {
+ if(tmp_s2 == -1)
+ infoArray[1].refCount = 3+1;
+ else
+ infoArray[1].refCount = 3;
+ infoArray[2].refCount = 3; //edx
+ }
+ infoArray[0].regNum = 2;
+ infoArray[0].refCount = 2; //define, use
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = PhysicalReg_EAX; //dividend, quotient
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[1].shareWithVR = false;
+ infoArray[2].regNum = PhysicalReg_EDX; //export_pc, output for REM
+ infoArray[2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 3;
+
+ case OP_ADD_LONG:
+ case OP_SUB_LONG:
+ case OP_AND_LONG:
+ case OP_OR_LONG:
+ case OP_XOR_LONG:
+ case OP_ADD_LONG_2ADDR:
+ case OP_SUB_LONG_2ADDR:
+ case OP_AND_LONG_2ADDR:
+ case OP_OR_LONG_2ADDR:
+ case OP_XOR_LONG_2ADDR:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //define, use
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ return 2;
+
+ case OP_SHL_LONG:
+ case OP_SHL_LONG_2ADDR:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3; //define, update, use
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[1].shareWithVR = false;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //define, use
+ infoArray[2].physicalType = LowOpndRegType_xmm;
+ return 3;
+
+ case OP_SHR_LONG:
+ case OP_SHR_LONG_2ADDR:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 4; //define, update, use
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[1].shareWithVR = false;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //define, use
+ infoArray[2].physicalType = LowOpndRegType_xmm;
+ infoArray[3].regNum = 4;
+ infoArray[3].refCount = 3;
+ infoArray[3].physicalType = LowOpndRegType_xmm;
+ infoArray[4].regNum = 5;
+ infoArray[4].refCount = 3;
+ infoArray[4].physicalType = LowOpndRegType_xmm;
+ return 5;
+
+ case OP_USHR_LONG:
+ case OP_USHR_LONG_2ADDR:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //define, update, use
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3; //define, update, use
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[1].shareWithVR = false;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //define, use
+ infoArray[2].physicalType = LowOpndRegType_xmm;
+ return 3;
+
+ case OP_MUL_LONG: //general purpose register
+ case OP_MUL_LONG_2ADDR:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 6;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 3;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = PhysicalReg_EAX;
+ infoArray[3].refCount = 2+1; //for mul_opc
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[4].regNum = PhysicalReg_EDX;
+ infoArray[4].refCount = 2; //for mul_opc
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 5;
+
+ case OP_DIV_LONG:
+ case OP_REM_LONG:
+ case OP_DIV_LONG_2ADDR:
+ case OP_REM_LONG_2ADDR:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 1;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_xmm;
+ infoArray[3].regNum = PhysicalReg_EAX;
+ infoArray[3].refCount = 2; //defined by function call
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[4].regNum = PhysicalReg_EDX;
+ infoArray[4].refCount = 2; //next version has 2 references
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[5].regNum = 1;
+ infoArray[5].refCount = 2;
+ infoArray[5].physicalType = LowOpndRegType_scratch;
+ return 6;
+
+ case OP_ADD_FLOAT:
+ case OP_SUB_FLOAT:
+ case OP_MUL_FLOAT:
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_ADD_DOUBLE: //PhysicalReg_FP TODO
+ case OP_SUB_DOUBLE:
+ case OP_MUL_DOUBLE:
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_DIV_FLOAT:
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_DIV_DOUBLE:
+ case OP_DIV_DOUBLE_2ADDR:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ //for ALU ops with 2ADDR, the temp variable can share the same physical
+ //reg as the virtual register, since the content of VR is updated by
+ //the content of the temp variable
+ if(inst_op == OP_ADD_FLOAT || inst_op == OP_SUB_FLOAT ||
+ inst_op == OP_MUL_FLOAT || inst_op == OP_ADD_DOUBLE ||
+ inst_op == OP_SUB_DOUBLE || inst_op == OP_MUL_DOUBLE ||
+ inst_op == OP_DIV_FLOAT || inst_op == OP_DIV_DOUBLE)
+ infoArray[0].shareWithVR = false;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ return 2;
+ case OP_REM_FLOAT:
+ case OP_REM_FLOAT_2ADDR:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 1;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_scratch;
+ return 3;
+
+ case OP_REM_DOUBLE:
+ case OP_REM_DOUBLE_2ADDR:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ infoArray[2].regNum = 1;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_scratch;
+ return 3;
+
+ case OP_CMPL_FLOAT:
+ case OP_CMPL_DOUBLE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 2;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 3;
+ infoArray[3].refCount = 2;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 4; //return
+ infoArray[4].refCount = 5;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ return 5;
+
+ case OP_CMPG_FLOAT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 2;
+ infoArray[2].refCount = 3;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 3;
+ infoArray[3].refCount = 5;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ return 4;
+ break;
+ case OP_CMPG_DOUBLE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_xmm;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 2;
+ infoArray[2].refCount = 3;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 3;
+ infoArray[3].refCount = 5;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ return 4;
+
+ case OP_CMP_LONG:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 3;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 4;
+ infoArray[3].refCount = 3;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 5;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = 6;
+ infoArray[5].refCount = 7;
+ infoArray[5].physicalType = LowOpndRegType_gp;
+ return 6;
+
+ case OP_EXECUTE_INLINE:
+ case OP_EXECUTE_INLINE_RANGE:
+ if(inst_op == OP_EXECUTE_INLINE)
+ num = INST_B(inst);
+ else
+ num = INST_AA(inst);
+ tmp = FETCH(1);
+ switch (tmp) {
+ case INLINE_STRING_LENGTH:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 1;
+ infoArray[3].refCount = 2;
+ infoArray[3].physicalType = LowOpndRegType_scratch;
+ return 4;
+ case INLINE_STRING_IS_EMPTY:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 4;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 1;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_scratch;
+ return 3;
+ case INLINE_STRING_FASTINDEXOF_II:
+#if defined(USE_GLOBAL_STRING_DEFS)
+ break;
+#else
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 14 * LOOP_COUNT;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3 * LOOP_COUNT;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 11 * LOOP_COUNT;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 4;
+ infoArray[3].refCount = 3 * LOOP_COUNT;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 5;
+ infoArray[4].refCount = 9 * LOOP_COUNT;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = 6;
+ infoArray[5].refCount = 4 * LOOP_COUNT;
+ infoArray[5].physicalType = LowOpndRegType_gp;
+ infoArray[6].regNum = 7;
+ infoArray[6].refCount = 2;
+ infoArray[6].physicalType = LowOpndRegType_gp;
+ infoArray[7].regNum = 1;
+ infoArray[7].refCount = 2;
+ infoArray[7].physicalType = LowOpndRegType_scratch;
+ return 8;
+#endif
+ case INLINE_MATH_ABS_LONG:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 7;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 3;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 4;
+ infoArray[3].refCount = 3;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 5;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = 6;
+ infoArray[5].refCount = 5;
+ infoArray[5].physicalType = LowOpndRegType_gp;
+ return 6;
+ case INLINE_MATH_ABS_INT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 5;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 4;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ return 3;
+ case INLINE_MATH_MAX_INT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ return 3;
+ case INLINE_MATH_ABS_FLOAT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ return 2;
+ case INLINE_MATH_ABS_DOUBLE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 3;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ return 3;
+ case INLINE_FLOAT_TO_RAW_INT_BITS:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ return 2;
+ case INLINE_INT_BITS_TO_FLOAT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ return 2;
+ case INLINE_DOUBLE_TO_RAW_LONG_BITS:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 3;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ return 3;
+ case INLINE_LONG_BITS_TO_DOUBLE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 3;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ return 3;
+ default:
+ break;
+ }
+
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 4;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ if(num >= 1) {
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ }
+ if(num >= 2) {
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ }
+ if(num >= 3) {
+ infoArray[3].regNum = 4;
+ infoArray[3].refCount = 2;
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ }
+ if(num >= 4) {
+ infoArray[4].regNum = 5;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ }
+ infoArray[num+1].regNum = 6;
+ infoArray[num+1].refCount = 2;
+ infoArray[num+1].physicalType = LowOpndRegType_gp;
+ infoArray[num+2].regNum = PhysicalReg_EAX;
+ infoArray[num+2].refCount = 2;
+ infoArray[num+2].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[num+3].regNum = PhysicalReg_EDX;
+ infoArray[num+3].refCount = 2;
+ infoArray[num+3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[num+4].regNum = 1;
+ infoArray[num+4].refCount = 4;
+ infoArray[num+4].physicalType = LowOpndRegType_scratch;
+ return num+5;
+#if FIXME
+ case OP_INVOKE_OBJECT_INIT_RANGE:
+ return 0;
+#endif
+ case OP_INVOKE_VIRTUAL_QUICK:
+ case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+#ifdef PREDICTED_CHAINING
+ numTmps = updateGenPrediction(infoArray, false /*not interface*/);
+ infoArray[numTmps].regNum = 1;
+ infoArray[numTmps].refCount = 3; //DU
+ infoArray[numTmps].physicalType = LowOpndRegType_gp;
+ numTmps++;
+ if(inst_op == OP_INVOKE_VIRTUAL_QUICK)
+ k = updateInvokeNoRange(infoArray, numTmps);
+ else
+ k = updateInvokeRange(infoArray, numTmps);
+ return k;
+#else
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+
+ infoArray[3].regNum = PhysicalReg_ECX;
+ infoArray[3].refCount = 1+1;
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[4].regNum = PhysicalReg_EDX;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ if(inst_op == OP_INVOKE_VIRTUAL_QUICK_RANGE)
+ k = updateInvokeRange(infoArray, 5);
+ else
+ k = updateInvokeNoRange(infoArray, 5);
+ return k;
+#endif
+ case OP_INVOKE_SUPER_QUICK:
+ case OP_INVOKE_SUPER_QUICK_RANGE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2;
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 4;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 5;
+ infoArray[2].refCount = 2;
+ infoArray[2].physicalType = LowOpndRegType_gp;
+
+ infoArray[3].regNum = PhysicalReg_ECX;
+ infoArray[3].refCount = 1+1;
+ infoArray[3].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ infoArray[4].regNum = PhysicalReg_EDX;
+ infoArray[4].refCount = 2;
+ infoArray[4].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+
+ infoArray[5].regNum = 1;
+ infoArray[5].refCount = 2;
+ infoArray[5].physicalType = LowOpndRegType_scratch;
+ infoArray[6].regNum = 2;
+ infoArray[6].refCount = 2;
+ infoArray[6].physicalType = LowOpndRegType_scratch;
+ if(inst_op == OP_INVOKE_SUPER_QUICK_RANGE)
+ k = updateInvokeRange(infoArray, 7);
+ else
+ k = updateInvokeNoRange(infoArray, 7);
+ return k;
+#ifdef SUPPORT_HLO
+ case kExtInstruction:
+ switch(inst) {
+ case OP_X_AGET_QUICK:
+ case OP_X_AGET_OBJECT_QUICK:
+ case OP_X_AGET_BOOLEAN_QUICK:
+ case OP_X_AGET_BYTE_QUICK:
+ case OP_X_AGET_CHAR_QUICK:
+ case OP_X_AGET_SHORT_QUICK:
+ vA = FETCH(1) & 0xff;
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 4;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[3].linkageToVR = vA;
+ if(inst == OP_X_AGET_BYTE_QUICK || inst == OP_X_AGET_BOOLEAN_QUICK)
+ infoArray[3].is8Bit = true;
+ return 4;
+ case OP_X_AGET_WIDE_QUICK:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 1;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_xmm;
+ return 4;
+ case OP_X_APUT_QUICK:
+ case OP_X_APUT_OBJECT_QUICK:
+ case OP_X_APUT_BOOLEAN_QUICK:
+ case OP_X_APUT_BYTE_QUICK:
+ case OP_X_APUT_CHAR_QUICK:
+ case OP_X_APUT_SHORT_QUICK:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 4;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ if(inst == OP_X_APUT_BYTE_QUICK || inst == OP_X_APUT_BOOLEAN_QUICK)
+ infoArray[3].is8Bit = true;
+ return 4;
+ case OP_X_APUT_WIDE_QUICK:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 1;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_xmm;
+ return 4;
+ case OP_X_DEREF_GET:
+ case OP_X_DEREF_GET_OBJECT:
+ case OP_X_DEREF_GET_BOOLEAN:
+ case OP_X_DEREF_GET_BYTE:
+ case OP_X_DEREF_GET_CHAR:
+ case OP_X_DEREF_GET_SHORT:
+ vA = FETCH(1) & 0xff;
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[1].linkageToVR = vA;
+ if(inst == OP_X_DEREF_GET_BYTE || inst == OP_X_DEREF_GET_BOOLEAN)
+ infoArray[1].is8Bit = true;
+ return 2;
+ case OP_X_DEREF_GET_WIDE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ return 2;
+ case OP_X_DEREF_PUT:
+ case OP_X_DEREF_PUT_OBJECT:
+ case OP_X_DEREF_PUT_BOOLEAN:
+ case OP_X_DEREF_PUT_BYTE:
+ case OP_X_DEREF_PUT_CHAR:
+ case OP_X_DEREF_PUT_SHORT:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ if(inst == OP_X_DEREF_PUT_BYTE || inst == OP_X_DEREF_PUT_BOOLEAN)
+ infoArray[1].is8Bit = true;
+ return 2;
+ case OP_X_DEREF_PUT_WIDE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 1;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_xmm;
+ return 2;
+ case OP_X_ARRAY_CHECKS:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ return 2;
+ case OP_X_CHECK_BOUNDS:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 2; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ return 2;
+ case OP_X_CHECK_NULL:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 2; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = PhysicalReg_EDX;
+ infoArray[1].refCount = 2;
+ infoArray[1].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 2;
+ case OP_X_CHECK_TYPE:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 3; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 5;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 6;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 1;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_scratch;
+ infoArray[5].regNum = PhysicalReg_EAX;
+ infoArray[5].refCount = 2;
+ infoArray[5].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 6;
+ case OP_X_ARRAY_OBJECT_CHECKS:
+ infoArray[0].regNum = 1;
+ infoArray[0].refCount = 3; //DU
+ infoArray[0].physicalType = LowOpndRegType_gp;
+ infoArray[1].regNum = 2;
+ infoArray[1].refCount = 4; //DU
+ infoArray[1].physicalType = LowOpndRegType_gp;
+ infoArray[2].regNum = 3;
+ infoArray[2].refCount = 2; //DU
+ infoArray[2].physicalType = LowOpndRegType_gp;
+ infoArray[3].regNum = 5;
+ infoArray[3].refCount = 2; //DU
+ infoArray[3].physicalType = LowOpndRegType_gp;
+ infoArray[4].regNum = 6;
+ infoArray[4].refCount = 2; //DU
+ infoArray[4].physicalType = LowOpndRegType_gp;
+ infoArray[5].regNum = 1;
+ infoArray[5].refCount = 2; //DU
+ infoArray[5].physicalType = LowOpndRegType_scratch;
+ infoArray[6].regNum = PhysicalReg_EAX;
+ infoArray[6].refCount = 2;
+ infoArray[6].physicalType = LowOpndRegType_gp | LowOpndRegType_hard;
+ return 7;
+ }
+#endif
+ }
+ return -1;
+}
diff --git a/vm/compiler/codegen/x86/CalloutHelper.h b/vm/compiler/codegen/x86/CalloutHelper.h
deleted file mode 100644
index 3490f04..0000000
--- a/vm/compiler/codegen/x86/CalloutHelper.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DALVIK_VM_COMPILER_CODEGEN_X86_CALLOUT_HELPER_H_
-#define DALVIK_VM_COMPILER_CODEGEN_X86_CALLOUT_HELPER_H_
-
-#include "Dalvik.h"
-
-/*
- * Declare/comment prototypes of all native callout functions invoked by the
- * JIT'ed code here and use the LOAD_FUNC_ADDR macro to load the address into
- * a register. In this way we have a centralized place to find out all native
- * helper functions and we can grep for LOAD_FUNC_ADDR to find out all the
- * callsites.
- */
-
-/* Load a statically compiled function address as a constant */
-#define LOAD_FUNC_ADDR(cUnit, reg, addr) loadConstant(cUnit, reg, addr)
-
-/* Originally declared in Sync.h */
-bool dvmUnlockObject(struct Thread* self, struct Object* obj); //OP_MONITOR_EXIT
-
-/* Originally declared in oo/TypeCheck.h */
-bool dvmCanPutArrayElement(const ClassObject* elemClass, // OP_APUT_OBJECT
- const ClassObject* arrayClass);
-int dvmInstanceofNonTrivial(const ClassObject* instance, // OP_CHECK_CAST &&
- const ClassObject* clazz); // OP_INSTANCE_OF
-
-/* Originally declared in oo/Array.h */
-ArrayObject* dvmAllocArrayByClass(ClassObject* arrayClass, // OP_NEW_ARRAY
- size_t length, int allocFlags);
-
-/* Originally declared in interp/InterpDefs.h */
-bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,// OP_FILL_ARRAY_DATA
- const u2* arrayData);
-
-/* Originally declared in alloc/Alloc.h */
-Object* dvmAllocObject(ClassObject* clazz, int flags); // OP_NEW_INSTANCE
-
-/*
- * Functions declared in gDvmInlineOpsTable[] are used for
- * OP_EXECUTE_INLINE & OP_EXECUTE_INLINE_RANGE.
- */
-extern "C" double sqrt(double x); // INLINE_MATH_SQRT
-
-#endif // DALVIK_VM_COMPILER_CODEGEN_X86_CALLOUT_HELPER_H_
diff --git a/vm/compiler/codegen/x86/Codegen.h b/vm/compiler/codegen/x86/Codegen.h
deleted file mode 100644
index 1ccdad3..0000000
--- a/vm/compiler/codegen/x86/Codegen.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * This file contains register alloction support and is intended to be
- * included by:
- *
- * Codegen-$(TARGET_ARCH_VARIANT).c
- *
- */
-
-#include "compiler/CompilerIR.h"
-#include "CalloutHelper.h"
diff --git a/vm/compiler/codegen/x86/CodegenDriver.cpp b/vm/compiler/codegen/x86/CodegenDriver.cpp
deleted file mode 100644
index 9c7bf1e..0000000
--- a/vm/compiler/codegen/x86/CodegenDriver.cpp
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * This file contains codegen and support common to all supported
- * X86 variants. It is included by:
- *
- * Codegen-$(TARGET_ARCH_VARIANT).c
- *
- * which combines this common code with specific support found in the
- * applicable directory below this one.
- */
-
-extern X86LIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
-extern X86LIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
- int displacement, int rDest);
-extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit);
-extern void storeWordDisp(CompilationUnit *cUnit, int rBase,
- int displacement, int rSrc);
-extern X86LIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc);
-
-static int opcodeCoverage[kNumPackedOpcodes];
-static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
-
-#if 0 // Avoid compiler warnings when x86 disabled during development
-/*
- * Bail to the interpreter. Will not return to this trace.
- * On entry, rPC must be set correctly.
- */
-static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
-{
- dvmCompilerFlushAllRegs(cUnit);
- loadConstant(cUnit, rPC, (int)(cUnit->method->insns + offset));
- loadWordDisp(cUnit, rEBP, 0, rECX); // Get glue
- loadWordDisp(cUnit, rECX,
- offsetof(Thread, jitToInterpEntries.dvmJitToInterpPunt),
- rEAX);
- opReg(cUnit, kOpUncondBr, rEAX);
-}
-
-static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
-{
- int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode);
- int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
- kInstrCanThrow;
-
- //If already optimized out, just ignore
- if (mir->dalvikInsn.opcode == OP_NOP)
- return;
-
- //Ugly, but necessary. Flush all Dalvik regs so Interp can find them
- dvmCompilerFlushAllRegs(cUnit);
-
- if ((mir->next == NULL) || (flags & flagsToCheck)) {
- genPuntToInterp(cUnit, mir->offset);
- return;
- }
- int entryAddr = offsetof(Thread,
- jitToInterpEntries.dvmJitToInterpSingleStep);
- loadWordDisp(cUnit, rEBP, 0, rECX); // Get glue
- loadWordDisp(cUnit, rECX, entryAddr, rEAX); // rEAX<- entry address
- /* rPC = dalvik pc */
- loadConstant(cUnit, rPC, (int) (cUnit->method->insns + mir->offset));
- /* rECX = dalvik pc of following instruction */
- loadConstant(cUnit, rECX, (int) (cUnit->method->insns + mir->next->offset));
- /* Pass on the stack */
- storeWordDisp(cUnit, rESP, OUT_ARG0, rECX);
- opReg(cUnit, kOpCall, rEAX);
-}
-#endif
-
-/*
- * The following are the first-level codegen routines that analyze the format
- * of each bytecode then either dispatch special purpose codegen routines
- * or produce corresponding Thumb instructions directly.
- */
-
-#if 0
-static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
- BasicBlock *bb, X86LIR *labelList)
-{
- /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
- return true;
-}
-
-static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
- X86LIR *labelList)
-{
- return true;
-}
-
-static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
- X86LIR *labelList)
-{
- return true;
-}
-
-static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
- X86LIR *labelList)
-{
- return true;
-}
-
-static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
- BasicBlock *bb, X86LIR *labelList)
-{
- return true;
-}
-
-/*
- * NOTE: Handles both range and non-range versions (arguments
- * have already been normalized by this point).
- */
-static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-
-static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
-{
- return true;
-}
-#endif
-
-
-void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
-{
-}
-
-/* Accept the work and start compiling */
-bool dvmCompilerDoWork(CompilerWorkOrder *work)
-{
- JitTraceDescription *desc;
- bool res;
-
- if (gDvmJit.codeCacheFull) {
- return false;
- }
-
- switch (work->kind) {
- case kWorkOrderTrace:
- /* Start compilation with maximally allowed trace length */
- desc = (JitTraceDescription *)work->info;
- res = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
- work->bailPtr, 0 /* no hints */);
- break;
- case kWorkOrderTraceDebug: {
- bool oldPrintMe = gDvmJit.printMe;
- gDvmJit.printMe = true;
- /* Start compilation with maximally allowed trace length */
- desc = (JitTraceDescription *)work->info;
- res = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
- work->bailPtr, 0 /* no hints */);
- gDvmJit.printMe = oldPrintMe;
- break;
- }
- default:
- res = false;
- ALOGE("Jit: unknown work order type");
- assert(0); // Bail if debug build, discard otherwise
- }
- return res;
-}
-
-/* Architectural-specific debugging helpers go here */
-void dvmCompilerArchDump(void)
-{
- /* Print compiled opcode in this VM instance */
- int i, start, streak;
- char buf[1024];
-
- streak = i = 0;
- buf[0] = 0;
- while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
- i++;
- }
- if (i == kNumPackedOpcodes) {
- return;
- }
- for (start = i++, streak = 1; i < kNumPackedOpcodes; i++) {
- if (opcodeCoverage[i]) {
- streak++;
- } else {
- if (streak == 1) {
- sprintf(buf+strlen(buf), "%x,", start);
- } else {
- sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
- }
- streak = 0;
- while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
- i++;
- }
- if (i < kNumPackedOpcodes) {
- streak = 1;
- start = i;
- }
- }
- }
- if (streak) {
- if (streak == 1) {
- sprintf(buf+strlen(buf), "%x", start);
- } else {
- sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
- }
- }
- if (strlen(buf)) {
- ALOGD("dalvik.vm.jit.op = %s", buf);
- }
-}
-
-/* Common initialization routine for an architecture family */
-bool dvmCompilerArchInit()
-{
- return dvmCompilerArchVariantInit();
-}
-
-void *dvmCompilerGetInterpretTemplate()
-{
- return (void*) ((int)gDvmJit.codeCache +
- templateEntryOffsets[TEMPLATE_INTERPRET]);
-}
-
-JitInstructionSetType dvmCompilerGetInterpretTemplateSet()
-{
- return DALVIK_JIT_X86;
-}
-
-void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
-{
-}
diff --git a/vm/compiler/codegen/x86/CodegenInterface.cpp b/vm/compiler/codegen/x86/CodegenInterface.cpp
new file mode 100644
index 0000000..aade180
--- /dev/null
+++ b/vm/compiler/codegen/x86/CodegenInterface.cpp
@@ -0,0 +1,1532 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <sys/mman.h>
+#include "Dalvik.h"
+#include "libdex/DexOpcodes.h"
+#include "compiler/Compiler.h"
+#include "compiler/CompilerIR.h"
+#include "interp/Jit.h"
+#include "libdex/DexFile.h"
+#include "Lower.h"
+#include "NcgAot.h"
+#include "compiler/codegen/CompilerCodegen.h"
+
+/* Init values when a predicted chain is initially assembled */
+/* E7FE is branch to self */
+#define PREDICTED_CHAIN_BX_PAIR_INIT 0xe7fe
+
+/* Target-specific save/restore */
+extern "C" void dvmJitCalleeSave(double *saveArea);
+extern "C" void dvmJitCalleeRestore(double *saveArea);
+
+/*
+ * Determine the initial instruction set to be used for this trace.
+ * Later components may decide to change this.
+ */
+//JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit)
+JitInstructionSetType dvmCompilerInstructionSet(void)
+{
+ return DALVIK_JIT_IA32;
+}
+
+JitInstructionSetType dvmCompilerGetInterpretTemplateSet()
+{
+ return DALVIK_JIT_IA32;
+}
+
+/* we don't use template for IA32 */
+void *dvmCompilerGetInterpretTemplate()
+{
+ return NULL;
+}
+
+/* Track the number of times that the code cache is patched */
+#if defined(WITH_JIT_TUNING)
+#define UPDATE_CODE_CACHE_PATCHES() (gDvmJit.codeCachePatches++)
+#else
+#define UPDATE_CODE_CACHE_PATCHES()
+#endif
+
+bool dvmCompilerArchInit() {
+ /* Target-specific configuration */
+ gDvmJit.jitTableSize = 1 << 12;
+ gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+ gDvmJit.threshold = 255;
+ gDvmJit.codeCacheSize = 512*1024;
+ gDvmJit.optLevel = kJitOptLevelO1;
+
+#if defined(WITH_SELF_VERIFICATION)
+ /* Force into blocking mode */
+ gDvmJit.blockingMode = true;
+ gDvm.nativeDebuggerActive = true;
+#endif
+
+ // Make sure all threads have current values
+ dvmJitUpdateThreadStateAll();
+
+ return true;
+}
+
+void dvmCompilerPatchInlineCache(void)
+{
+ int i;
+ PredictedChainingCell *minAddr, *maxAddr;
+
+ /* Nothing to be done */
+ if (gDvmJit.compilerICPatchIndex == 0) return;
+
+ /*
+ * Since all threads are already stopped we don't really need to acquire
+ * the lock. But race condition can be easily introduced in the future w/o
+ * paying attention so we still acquire the lock here.
+ */
+ dvmLockMutex(&gDvmJit.compilerICPatchLock);
+
+ UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+ //ALOGD("Number of IC patch work orders: %d", gDvmJit.compilerICPatchIndex);
+
+ /* Initialize the min/max address range */
+ minAddr = (PredictedChainingCell *)
+ ((char *) gDvmJit.codeCache + gDvmJit.codeCacheSize);
+ maxAddr = (PredictedChainingCell *) gDvmJit.codeCache;
+
+ for (i = 0; i < gDvmJit.compilerICPatchIndex; i++) {
+ ICPatchWorkOrder *workOrder = &gDvmJit.compilerICPatchQueue[i];
+ PredictedChainingCell *cellAddr = workOrder->cellAddr;
+ PredictedChainingCell *cellContent = &workOrder->cellContent;
+ ClassObject *clazz = dvmFindClassNoInit(workOrder->classDescriptor,
+ workOrder->classLoader);
+
+ assert(clazz->serialNumber == workOrder->serialNumber);
+
+ /* Use the newly resolved clazz pointer */
+ cellContent->clazz = clazz;
+
+ if (cellAddr->clazz == NULL) {
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: predicted chain %p to %s (%s) initialized",
+ cellAddr,
+ cellContent->clazz->descriptor,
+ cellContent->method->name));
+ } else {
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: predicted chain %p from %s to %s (%s) "
+ "patched",
+ cellAddr,
+ cellAddr->clazz->descriptor,
+ cellContent->clazz->descriptor,
+ cellContent->method->name));
+ }
+
+ /* Patch the chaining cell */
+ *cellAddr = *cellContent;
+ minAddr = (cellAddr < minAddr) ? cellAddr : minAddr;
+ maxAddr = (cellAddr > maxAddr) ? cellAddr : maxAddr;
+ }
+
+ PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+ gDvmJit.compilerICPatchIndex = 0;
+ dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
+}
+
+/* Target-specific cache clearing */
+void dvmCompilerCacheClear(char *start, size_t size)
+{
+ /* "0xFF 0xFF" is an invalid opcode for x86. */
+ memset(start, 0xFF, size);
+}
+
+/* for JIT debugging, to be implemented */
+void dvmJitCalleeSave(double *saveArea) {
+}
+
+void dvmJitCalleeRestore(double *saveArea) {
+}
+
+void dvmJitToInterpSingleStep() {
+}
+
+JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
+ const JitEntry *knownEntry) {
+ return NULL;
+}
+
+void dvmCompilerCodegenDump(CompilationUnit *cUnit) //in ArchUtility.c
+{
+}
+
+void dvmCompilerArchDump(void)
+{
+}
+
+char *getTraceBase(const JitEntry *p)
+{
+ return NULL;
+}
+
+void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo* info)
+{
+}
+
+void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit, char *codeAddress)
+{
+}
+
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit)
+{
+ ALOGE("Method-based JIT not supported for the x86 target");
+ dvmAbort();
+}
+
+void dvmJitScanAllClassPointers(void (*callback)(void *))
+{
+}
+
+/* Handy function to retrieve the profile count */
+static inline int getProfileCount(const JitEntry *entry)
+{
+ if (entry->dPC == 0 || entry->codeAddress == 0)
+ return 0;
+ u4 *pExecutionCount = (u4 *) getTraceBase(entry);
+
+ return pExecutionCount ? *pExecutionCount : 0;
+}
+
+/* qsort callback function */
+static int sortTraceProfileCount(const void *entry1, const void *entry2)
+{
+ const JitEntry *jitEntry1 = (const JitEntry *)entry1;
+ const JitEntry *jitEntry2 = (const JitEntry *)entry2;
+
+ JitTraceCounter_t count1 = getProfileCount(jitEntry1);
+ JitTraceCounter_t count2 = getProfileCount(jitEntry2);
+ return (count1 == count2) ? 0 : ((count1 > count2) ? -1 : 1);
+}
+
+/* Sort the trace profile counts and dump them */
+void dvmCompilerSortAndPrintTraceProfiles() //in Assemble.c
+{
+ JitEntry *sortedEntries;
+ int numTraces = 0;
+ unsigned long counts = 0;
+ unsigned int i;
+
+ /* Make sure that the table is not changing */
+ dvmLockMutex(&gDvmJit.tableLock);
+
+ /* Sort the entries by descending order */
+ sortedEntries = (JitEntry *)malloc(sizeof(JitEntry) * gDvmJit.jitTableSize);
+ if (sortedEntries == NULL)
+ goto done;
+ memcpy(sortedEntries, gDvmJit.pJitEntryTable,
+ sizeof(JitEntry) * gDvmJit.jitTableSize);
+ qsort(sortedEntries, gDvmJit.jitTableSize, sizeof(JitEntry),
+ sortTraceProfileCount);
+
+ /* Dump the sorted entries */
+ for (i=0; i < gDvmJit.jitTableSize; i++) {
+ if (sortedEntries[i].dPC != 0) {
+ numTraces++;
+ }
+ }
+ if (numTraces == 0)
+ numTraces = 1;
+ ALOGI("JIT: Average execution count -> %d",(int)(counts / numTraces));
+
+ free(sortedEntries);
+done:
+ dvmUnlockMutex(&gDvmJit.tableLock);
+ return;
+}
+
+void jumpWithRelOffset(char* instAddr, int relOffset) {
+ stream = instAddr;
+ OpndSize immSize = estOpndSizeFromImm(relOffset);
+ relOffset -= getJmpCallInstSize(immSize, JmpCall_uncond);
+ dump_imm(Mnemonic_JMP, immSize, relOffset);
+}
+
+// works whether instructions for target basic block are generated or not
+LowOp* jumpToBasicBlock(char* instAddr, int targetId) {
+ stream = instAddr;
+ bool unknown;
+ OpndSize size;
+ int relativeNCG = targetId;
+ relativeNCG = getRelativeNCG(targetId, JmpCall_uncond, &unknown, &size);
+ unconditional_jump_int(relativeNCG, size);
+ return NULL;
+}
+
+LowOp* condJumpToBasicBlock(char* instAddr, ConditionCode cc, int targetId) {
+ stream = instAddr;
+ bool unknown;
+ OpndSize size;
+ int relativeNCG = targetId;
+ relativeNCG = getRelativeNCG(targetId, JmpCall_cond, &unknown, &size);
+ conditional_jump_int(cc, relativeNCG, size);
+ return NULL;
+}
+
+/*
+ * Attempt to enqueue a work order to patch an inline cache for a predicted
+ * chaining cell for virtual/interface calls.
+ */
+static bool inlineCachePatchEnqueue(PredictedChainingCell *cellAddr,
+ PredictedChainingCell *newContent)
+{
+ bool result = true;
+
+ /*
+ * Make sure only one thread gets here since updating the cell (ie fast
+ * path and queueing the request (ie the queued path) have to be done
+ * in an atomic fashion.
+ */
+ dvmLockMutex(&gDvmJit.compilerICPatchLock);
+
+ /* Fast path for uninitialized chaining cell */
+ if (cellAddr->clazz == NULL &&
+ cellAddr->branch == PREDICTED_CHAIN_BX_PAIR_INIT) {
+ UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+ cellAddr->method = newContent->method;
+ cellAddr->branch = newContent->branch;
+ cellAddr->branch2 = newContent->branch2;
+
+ /*
+ * The update order matters - make sure clazz is updated last since it
+ * will bring the uninitialized chaining cell to life.
+ */
+ android_atomic_release_store((int32_t)newContent->clazz,
+ (volatile int32_t *)(void*) &cellAddr->clazz);
+ //cacheflush((intptr_t) cellAddr, (intptr_t) (cellAddr+1), 0);
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if 0
+ MEM_BARRIER();
+ cellAddr->clazz = newContent->clazz;
+ //cacheflush((intptr_t) cellAddr, (intptr_t) (cellAddr+1), 0);
+#endif
+#if defined(IA_JIT_TUNING)
+ gDvmJit.icPatchInit++;
+#endif
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: FAST predicted chain %p to method %s%s %p",
+ cellAddr, newContent->clazz->descriptor, newContent->method->name, newContent->method));
+ /* Check if this is a frequently missed clazz */
+ } else if (cellAddr->stagedClazz != newContent->clazz) {
+ /* Not proven to be frequent yet - build up the filter cache */
+ UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+ cellAddr->stagedClazz = newContent->clazz;
+
+ UPDATE_CODE_CACHE_PATCHES();
+ PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchRejected++;
+#endif
+ /*
+ * Different classes but same method implementation - it is safe to just
+ * patch the class value without the need to stop the world.
+ */
+ } else if (cellAddr->method == newContent->method) {
+ UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+ cellAddr->clazz = newContent->clazz;
+ /* No need to flush the cache here since the branch is not patched */
+ UPDATE_CODE_CACHE_PATCHES();
+
+ PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchLockFree++;
+#endif
+ /*
+ * Cannot patch the chaining cell inline - queue it until the next safe
+ * point.
+ */
+ } else if (gDvmJit.compilerICPatchIndex < COMPILER_IC_PATCH_QUEUE_SIZE) {
+ int index = gDvmJit.compilerICPatchIndex++;
+ const ClassObject *clazz = newContent->clazz;
+
+ gDvmJit.compilerICPatchQueue[index].cellAddr = cellAddr;
+ gDvmJit.compilerICPatchQueue[index].cellContent = *newContent;
+ gDvmJit.compilerICPatchQueue[index].classDescriptor = clazz->descriptor;
+ gDvmJit.compilerICPatchQueue[index].classLoader = clazz->classLoader;
+ /* For verification purpose only */
+ gDvmJit.compilerICPatchQueue[index].serialNumber = clazz->serialNumber;
+
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchQueued++;
+#endif
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: QUEUE predicted chain %p to method %s%s",
+ cellAddr, newContent->clazz->descriptor, newContent->method->name));
+ } else {
+ /* Queue is full - just drop this patch request */
+#if defined(WITH_JIT_TUNING)
+ gDvmJit.icPatchDropped++;
+#endif
+
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: DROP predicted chain %p to method %s%s",
+ cellAddr, newContent->clazz->descriptor, newContent->method->name));
+ }
+
+ dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
+ return result;
+}
+
+/*
+ * This method is called from the invoke templates for virtual and interface
+ * methods to speculatively setup a chain to the callee. The templates are
+ * written in assembly and have setup method, cell, and clazz at r0, r2, and
+ * r3 respectively, so there is a unused argument in the list. Upon return one
+ * of the following three results may happen:
+ * 1) Chain is not setup because the callee is native. Reset the rechain
+ * count to a big number so that it will take a long time before the next
+ * rechain attempt to happen.
+ * 2) Chain is not setup because the callee has not been created yet. Reset
+ * the rechain count to a small number and retry in the near future.
+ * 3) Ask all other threads to stop before patching this chaining cell.
+ * This is required because another thread may have passed the class check
+ * but hasn't reached the chaining cell yet to follow the chain. If we
+ * patch the content before halting the other thread, there could be a
+ * small window for race conditions to happen that it may follow the new
+ * but wrong chain to invoke a different method.
+ */
+const Method *dvmJitToPatchPredictedChain(const Method *method,
+ Thread *self,
+ PredictedChainingCell *cell,
+ const ClassObject *clazz)
+{
+ int newRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
+ /* Don't come back here for a long time if the method is native */
+ if (dvmIsNativeMethod(method)) {
+ UNPROTECT_CODE_CACHE(cell, sizeof(*cell));
+
+ /*
+ * Put a non-zero/bogus value in the clazz field so that it won't
+ * trigger immediate patching and will continue to fail to match with
+ * a real clazz pointer.
+ */
+ cell->clazz = (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ;
+
+ UPDATE_CODE_CACHE_PATCHES();
+ PROTECT_CODE_CACHE(cell, sizeof(*cell));
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: predicted chain %p to native method %s ignored",
+ cell, method->name));
+ goto done;
+ }
+ {
+ int tgtAddr = (int) dvmJitGetTraceAddr(method->insns);
+
+ /*
+ * Compilation not made yet for the callee. Reset the counter to a small
+ * value and come back to check soon.
+ */
+ if ((tgtAddr == 0) ||
+ ((void*)tgtAddr == dvmCompilerGetInterpretTemplate())) {
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: predicted chain %p to method %s%s delayed",
+ cell, method->clazz->descriptor, method->name));
+ goto done;
+ }
+
+ PredictedChainingCell newCell;
+
+ if (cell->clazz == NULL) {
+ newRechainCount = self->icRechainCount;
+ }
+
+ int relOffset = (int) tgtAddr - (int)cell;
+ OpndSize immSize = estOpndSizeFromImm(relOffset);
+ int jumpSize = getJmpCallInstSize(immSize, JmpCall_uncond);
+ relOffset -= jumpSize;
+ COMPILER_TRACE_CHAINING(
+ ALOGI("inlineCachePatchEnqueue chain %p to method %s%s inst size %d",
+ cell, method->clazz->descriptor, method->name, jumpSize));
+ //can't use stream here since it is used by the compilation thread
+ dump_imm_with_codeaddr(Mnemonic_JMP, immSize, relOffset, (char*) (&newCell)); //update newCell.branch
+
+ newCell.clazz = clazz;
+ newCell.method = method;
+
+ /*
+ * Enter the work order to the queue and the chaining cell will be patched
+ * the next time a safe point is entered.
+ *
+ * If the enqueuing fails reset the rechain count to a normal value so that
+ * it won't get indefinitely delayed.
+ */
+ inlineCachePatchEnqueue(cell, &newCell);
+ }
+done:
+ self->icRechainCount = newRechainCount;
+ return method;
+}
+
+/*
+ * Unchain a trace given the starting address of the translation
+ * in the code cache. Refer to the diagram in dvmCompilerAssembleLIR.
+ * For ARM, it returns the address following the last cell unchained.
+ * For IA, it returns NULL since cacheflush is not required for IA.
+ */
+u4* dvmJitUnchain(void* codeAddr)
+{
+ /* codeAddr is 4-byte aligned, so is chain cell count offset */
+ u2* pChainCellCountOffset = (u2*)((char*)codeAddr - 4);
+ u2 chainCellCountOffset = *pChainCellCountOffset;
+ /* chain cell counts information is 4-byte aligned */
+ ChainCellCounts *pChainCellCounts =
+ (ChainCellCounts*)((char*)codeAddr + chainCellCountOffset);
+ u2* pChainCellOffset = (u2*)((char*)codeAddr - 2);
+ u2 chainCellOffset = *pChainCellOffset;
+ u1* pChainCells;
+ int i,j;
+ PredictedChainingCell *predChainCell;
+ int padding;
+
+ /* Locate the beginning of the chain cell region */
+ pChainCells = (u1 *)((char*)codeAddr + chainCellOffset);
+
+ /* The cells are sorted in order - walk through them and reset */
+ for (i = 0; i < kChainingCellGap; i++) {
+ /* for hot, normal, singleton chaining:
+ nop //padding.
+ jmp 0
+ mov imm32, reg1
+ mov imm32, reg2
+ call reg2
+ after chaining:
+ nop
+ jmp imm
+ mov imm32, reg1
+ mov imm32, reg2
+ call reg2
+ after unchaining:
+ nop
+ jmp 0
+ mov imm32, reg1
+ mov imm32, reg2
+ call reg2
+ Space occupied by the chaining cell in bytes: nop is for padding,
+ jump 0, the target 0 is 4 bytes aligned.
+ Space for predicted chaining: 5 words = 20 bytes
+ */
+ int elemSize = 0;
+ if (i == kChainingCellInvokePredicted) {
+ elemSize = 20;
+ }
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: unchaining type %d count %d", i, pChainCellCounts->u.count[i]));
+
+ for (j = 0; j < pChainCellCounts->u.count[i]; j++) {
+ switch(i) {
+ case kChainingCellNormal:
+ case kChainingCellHot:
+ case kChainingCellInvokeSingleton:
+ case kChainingCellBackwardBranch:
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: unchaining of normal, hot, or singleton"));
+ pChainCells = (u1*) (((uint)pChainCells + 4)&(~0x03));
+ elemSize = 4+5+5+2;
+ memset(pChainCells, 0, 4);
+ break;
+ case kChainingCellInvokePredicted:
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: unchaining of predicted"));
+ /* 4-byte aligned */
+ padding = (4 - ((u4)pChainCells & 3)) & 3;
+ pChainCells += padding;
+ predChainCell = (PredictedChainingCell *) pChainCells;
+ /*
+ * There could be a race on another mutator thread to use
+ * this particular predicted cell and the check has passed
+ * the clazz comparison. So we cannot safely wipe the
+ * method and branch but it is safe to clear the clazz,
+ * which serves as the key.
+ */
+ predChainCell->clazz = PREDICTED_CHAIN_CLAZZ_INIT;
+ break;
+ default:
+ ALOGE("Unexpected chaining type: %d", i);
+ dvmAbort(); // dvmAbort OK here - can't safely recover
+ }
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: unchaining 0x%x", (int)pChainCells));
+ pChainCells += elemSize; /* Advance by a fixed number of bytes */
+ }
+ }
+ return NULL;
+}
+
+/* Unchain all translation in the cache. */
+void dvmJitUnchainAll()
+{
+ ALOGV("Jit Runtime: unchaining all");
+ if (gDvmJit.pJitEntryTable != NULL) {
+ COMPILER_TRACE_CHAINING(ALOGI("Jit Runtime: unchaining all"));
+ dvmLockMutex(&gDvmJit.tableLock);
+
+ UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+ for (size_t i = 0; i < gDvmJit.jitTableSize; i++) {
+ if (gDvmJit.pJitEntryTable[i].dPC &&
+ !gDvmJit.pJitEntryTable[i].u.info.isMethodEntry &&
+ gDvmJit.pJitEntryTable[i].codeAddress) {
+ dvmJitUnchain(gDvmJit.pJitEntryTable[i].codeAddress);
+ }
+ }
+
+ PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+ dvmUnlockMutex(&gDvmJit.tableLock);
+ gDvmJit.translationChains = 0;
+ }
+ gDvmJit.hasNewChain = false;
+}
+
+#define P_GPR_1 PhysicalReg_EBX
+/* Add an additional jump instruction, keep jump target 4 bytes aligned.*/
+static void insertJumpHelp()
+{
+ int rem = (uint)stream % 4;
+ int nop_size = 3 - rem;
+ dump_nop(nop_size);
+ unconditional_jump_int(0, OpndSize_32);
+ return;
+}
+
+/* Chaining cell for code that may need warmup. */
+/* ARM assembly: ldr r0, [r6, #76] (why a single instruction to access member of glue structure?)
+ blx r0
+ data 0xb23a //bytecode address: 0x5115b23a
+ data 0x5115
+ IA32 assembly:
+ jmp 0 //5 bytes
+ movl address, %ebx
+ movl dvmJitToInterpNormal, %eax
+ call %eax
+ <-- return address
+*/
+static void handleNormalChainingCell(CompilationUnit *cUnit,
+ unsigned int offset, int blockId, LowOpBlockLabel* labelList)
+{
+ ALOGV("in handleNormalChainingCell for method %s block %d BC offset %x NCG offset %x",
+ cUnit->method->name, blockId, offset, stream - streamMethodStart);
+ if(dump_x86_inst)
+ ALOGI("LOWER NormalChainingCell at offsetPC %x offsetNCG %x @%p",
+ offset, stream - streamMethodStart, stream);
+ /* Add one additional "jump 0" instruction, it may be modified during jit chaining. This helps
+ * reslove the multithreading issue.
+ */
+ insertJumpHelp();
+ move_imm_to_reg(OpndSize_32, (int) (cUnit->method->insns + offset), P_GPR_1, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_dvmJitToInterpNormal();
+ //move_imm_to_reg(OpndSize_32, (int) (cUnit->method->insns + offset), P_GPR_1, true); /* used when unchaining */
+}
+
+/*
+ * Chaining cell for instructions that immediately following already translated
+ * code.
+ */
+static void handleHotChainingCell(CompilationUnit *cUnit,
+ unsigned int offset, int blockId, LowOpBlockLabel* labelList)
+{
+ ALOGV("in handleHotChainingCell for method %s block %d BC offset %x NCG offset %x",
+ cUnit->method->name, blockId, offset, stream - streamMethodStart);
+ if(dump_x86_inst)
+ ALOGI("LOWER HotChainingCell at offsetPC %x offsetNCG %x @%p",
+ offset, stream - streamMethodStart, stream);
+ /* Add one additional "jump 0" instruction, it may be modified during jit chaining. This helps
+ * reslove the multithreading issue.
+ */
+ insertJumpHelp();
+ move_imm_to_reg(OpndSize_32, (int) (cUnit->method->insns + offset), P_GPR_1, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_dvmJitToInterpTraceSelect();
+ //move_imm_to_reg(OpndSize_32, (int) (cUnit->method->insns + offset), P_GPR_1, true); /* used when unchaining */
+}
+
+/* Chaining cell for branches that branch back into the same basic block */
+static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
+ unsigned int offset, int blockId, LowOpBlockLabel* labelList)
+{
+ ALOGV("in handleBackwardBranchChainingCell for method %s block %d BC offset %x NCG offset %x",
+ cUnit->method->name, blockId, offset, stream - streamMethodStart);
+ if(dump_x86_inst)
+ ALOGI("LOWER BackwardBranchChainingCell at offsetPC %x offsetNCG %x @%p",
+ offset, stream - streamMethodStart, stream);
+ /* Add one additional "jump 0" instruction, it may be modified during jit chaining. This helps
+ * reslove the multithreading issue.
+ */
+ insertJumpHelp();
+ move_imm_to_reg(OpndSize_32, (int) (cUnit->method->insns + offset), P_GPR_1, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_dvmJitToInterpNormal();
+ //move_imm_to_reg(OpndSize_32, (int) (cUnit->method->insns + offset), P_GPR_1, true); /* used when unchaining */
+}
+
+/* Chaining cell for monomorphic method invocations. */
+static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
+ const Method *callee, int blockId, LowOpBlockLabel* labelList)
+{
+ ALOGV("in handleInvokeSingletonChainingCell for method %s block %d callee %s NCG offset %x",
+ cUnit->method->name, blockId, callee->name, stream - streamMethodStart);
+ if(dump_x86_inst)
+ ALOGI("LOWER InvokeSingletonChainingCell at block %d offsetNCG %x @%p",
+ blockId, stream - streamMethodStart, stream);
+ /* Add one additional "jump 0" instruction, it may be modified during jit chaining. This helps
+ * reslove the multithreading issue.
+ */
+ insertJumpHelp();
+ move_imm_to_reg(OpndSize_32, (int) (callee->insns), P_GPR_1, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_dvmJitToInterpTraceSelect();
+ //move_imm_to_reg(OpndSize_32, (int) (callee->insns), P_GPR_1, true); /* used when unchaining */
+}
+#undef P_GPR_1
+
+/* Chaining cell for monomorphic method invocations. */
+static void handleInvokePredictedChainingCell(CompilationUnit *cUnit, int blockId)
+{
+ if(dump_x86_inst)
+ ALOGI("LOWER InvokePredictedChainingCell at block %d offsetNCG %x @%p",
+ blockId, stream - streamMethodStart, stream);
+#ifndef PREDICTED_CHAINING
+ //assume rPC for callee->insns in %ebx
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_dvmJitToInterpTraceSelectNoChain();
+#else
+ /* make sure section for predicited chaining cell is 4-byte aligned */
+ //int padding = (4 - ((u4)stream & 3)) & 3;
+ //stream += padding;
+ int* streamData = (int*)stream;
+ /* Should not be executed in the initial state */
+ streamData[0] = PREDICTED_CHAIN_BX_PAIR_INIT;
+ streamData[1] = 0;
+ /* To be filled: class */
+ streamData[2] = PREDICTED_CHAIN_CLAZZ_INIT;
+ /* To be filled: method */
+ streamData[3] = PREDICTED_CHAIN_METHOD_INIT;
+ /*
+ * Rechain count. The initial value of 0 here will trigger chaining upon
+ * the first invocation of this callsite.
+ */
+ streamData[4] = PREDICTED_CHAIN_COUNTER_INIT;
+#if 0
+ ALOGI("--- DATA @ %p: %x %x %x %x", stream, *((int*)stream), *((int*)(stream+4)),
+ *((int*)(stream+8)), *((int*)(stream+12)));
+#endif
+ stream += 20; //5 *4
+#endif
+}
+
+/* Load the Dalvik PC into r0 and jump to the specified target */
+static void handlePCReconstruction(CompilationUnit *cUnit,
+ LowOpBlockLabel *targetLabel)
+{
+#if 0
+ LowOp **pcrLabel =
+ (LowOp **) cUnit->pcReconstructionList.elemList;
+ int numElems = cUnit->pcReconstructionList.numUsed;
+ int i;
+ for (i = 0; i < numElems; i++) {
+ dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
+ /* r0 = dalvik PC */
+ loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
+ genUnconditionalBranch(cUnit, targetLabel);
+ }
+#endif
+}
+
+//use O0 code generator for hoisted checks outside of the loop
+/*
+ * vA = arrayReg;
+ * vB = idxReg;
+ * vC = endConditionReg;
+ * arg[0] = maxC
+ * arg[1] = minC
+ * arg[2] = loopBranchConditionCode
+ */
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
+{
+ /*
+ * NOTE: these synthesized blocks don't have ssa names assigned
+ * for Dalvik registers. However, because they dominate the following
+ * blocks we can simply use the Dalvik name w/ subscript 0 as the
+ * ssa name.
+ */
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ const int maxC = dInsn->arg[0];
+
+ /* assign array in virtual register to P_GPR_1 */
+ get_virtual_reg(mir->dalvikInsn.vA, OpndSize_32, P_GPR_1, true);
+ /* assign index in virtual register to P_GPR_2 */
+ get_virtual_reg(mir->dalvikInsn.vC, OpndSize_32, P_GPR_2, true);
+ export_pc();
+ compare_imm_reg(OpndSize_32, 0, P_GPR_1, true);
+ condJumpToBasicBlock(stream, Condition_E, cUnit->exceptionBlockId);
+ int delta = maxC;
+ /*
+ * If the loop end condition is ">=" instead of ">", then the largest value
+ * of the index is "endCondition - 1".
+ */
+ if (dInsn->arg[2] == OP_IF_GE) {
+ delta--;
+ }
+
+ if (delta < 0) { //+delta
+ //if P_GPR_2 is mapped to a VR, we can't do this
+ alu_binary_imm_reg(OpndSize_32, sub_opc, -delta, P_GPR_2, true);
+ } else if(delta > 0) {
+ alu_binary_imm_reg(OpndSize_32, add_opc, delta, P_GPR_2, true);
+ }
+ compare_mem_reg(OpndSize_32, offArrayObject_length, P_GPR_1, true, P_GPR_2, true);
+ condJumpToBasicBlock(stream, Condition_NC, cUnit->exceptionBlockId);
+}
+
+/*
+ * vA = arrayReg;
+ * vB = idxReg;
+ * vC = endConditionReg;
+ * arg[0] = maxC
+ * arg[1] = minC
+ * arg[2] = loopBranchConditionCode
+ */
+static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ const int maxC = dInsn->arg[0];
+
+ /* assign array in virtual register to P_GPR_1 */
+ get_virtual_reg(mir->dalvikInsn.vA, OpndSize_32, P_GPR_1, true);
+ /* assign index in virtual register to P_GPR_2 */
+ get_virtual_reg(mir->dalvikInsn.vB, OpndSize_32, P_GPR_2, true);
+ export_pc();
+ compare_imm_reg(OpndSize_32, 0, P_GPR_1, true);
+ condJumpToBasicBlock(stream, Condition_E, cUnit->exceptionBlockId);
+
+ if (maxC < 0) {
+ //if P_GPR_2 is mapped to a VR, we can't do this
+ alu_binary_imm_reg(OpndSize_32, sub_opc, -maxC, P_GPR_2, true);
+ } else if(maxC > 0) {
+ alu_binary_imm_reg(OpndSize_32, add_opc, maxC, P_GPR_2, true);
+ }
+ compare_mem_reg(OpndSize_32, offArrayObject_length, P_GPR_1, true, P_GPR_2, true);
+ condJumpToBasicBlock(stream, Condition_NC, cUnit->exceptionBlockId);
+
+}
+#undef P_GPR_1
+#undef P_GPR_2
+
+/*
+ * vA = idxReg;
+ * vB = minC;
+ */
+#define P_GPR_1 PhysicalReg_ECX
+static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ const int minC = dInsn->vB;
+ get_virtual_reg(mir->dalvikInsn.vA, OpndSize_32, P_GPR_1, true); //array
+ export_pc();
+ compare_imm_reg(OpndSize_32, -minC, P_GPR_1, true);
+ condJumpToBasicBlock(stream, Condition_C, cUnit->exceptionBlockId);
+}
+#undef P_GPR_1
+
+#ifdef WITH_JIT_INLINING
+static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir)
+{
+ CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
+ if(gDvm.executionMode == kExecutionModeNcgO0) {
+ get_virtual_reg(mir->dalvikInsn.vC, OpndSize_32, PhysicalReg_EBX, true);
+ move_imm_to_reg(OpndSize_32, (int) callsiteInfo->clazz, PhysicalReg_ECX, true);
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EBX, true);
+ export_pc(); //use %edx
+ conditional_jump_global_API(, Condition_E, "common_errNullObject", false);
+ move_mem_to_reg(OpndSize_32, offObject_clazz, PhysicalReg_EBX, true, PhysicalReg_EAX, true);
+ compare_reg_reg(PhysicalReg_ECX, true, PhysicalReg_EAX, true);
+ } else {
+ get_virtual_reg(mir->dalvikInsn.vC, OpndSize_32, 5, false);
+ move_imm_to_reg(OpndSize_32, (int) callsiteInfo->clazz, 4, false);
+ nullCheck(5, false, 1, mir->dalvikInsn.vC);
+ move_mem_to_reg(OpndSize_32, offObject_clazz, 5, false, 6, false);
+ compare_reg_reg(4, false, 6, false);
+ }
+
+ //immdiate will be updated later in genLandingPadForMispredictedCallee
+ streamMisPred = stream;
+ callsiteInfo->misPredBranchOver = (LIR*)conditional_jump_int(Condition_NE, 0, OpndSize_8);
+}
+#endif
+
+/* Extended MIR instructions like PHI */
+void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
+{
+ ExecutionMode origMode = gDvm.executionMode;
+ gDvm.executionMode = kExecutionModeNcgO0;
+ switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
+ case kMirOpPhi: {
+ break;
+ }
+ case kMirOpNullNRangeUpCheck: {
+ genHoistedChecksForCountUpLoop(cUnit, mir);
+ break;
+ }
+ case kMirOpNullNRangeDownCheck: {
+ genHoistedChecksForCountDownLoop(cUnit, mir);
+ break;
+ }
+ case kMirOpLowerBound: {
+ genHoistedLowerBoundCheck(cUnit, mir);
+ break;
+ }
+ case kMirOpPunt: {
+ break;
+ }
+#ifdef WITH_JIT_INLINING
+ case kMirOpCheckInlinePrediction: { //handled in ncg_o1_data.c
+ genValidationForPredictedInline(cUnit, mir);
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+ gDvm.executionMode = origMode;
+}
+
+static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
+ int bodyId)
+{
+ /*
+ * Next, create two branches - one branch over to the loop body and the
+ * other branch to the PCR cell to punt.
+ */
+ //LowOp* branchToBody = jumpToBasicBlock(stream, bodyId);
+ //setupResourceMasks(branchToBody);
+ //cUnit->loopAnalysis->branchToBody = ((LIR*)branchToBody);
+
+#if 0
+ LowOp *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
+ branchToPCR->opCode = kThumbBUncond;
+ branchToPCR->generic.target = (LIR *) pcrLabel;
+ setupResourceMasks(branchToPCR);
+ cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
+#endif
+}
+
+/* check whether we can merge the block at index i with its target block */
+bool mergeBlock(BasicBlock *bb) {
+ if(bb->blockType == kDalvikByteCode &&
+ bb->firstMIRInsn != NULL &&
+ (bb->lastMIRInsn->dalvikInsn.opcode == OP_GOTO_16 ||
+ bb->lastMIRInsn->dalvikInsn.opcode == OP_GOTO ||
+ bb->lastMIRInsn->dalvikInsn.opcode == OP_GOTO_32) &&
+ bb->fallThrough == NULL) {// &&
+ //cUnit->hasLoop) {
+ //ALOGI("merge blocks ending with goto at index %d", i);
+ MIR* prevInsn = bb->lastMIRInsn->prev;
+ if(bb->taken == NULL) return false;
+ MIR* mergeInsn = bb->taken->firstMIRInsn;
+ if(mergeInsn == NULL) return false;
+ if(prevInsn == NULL) {//the block has a single instruction
+ bb->firstMIRInsn = mergeInsn;
+ } else {
+ prevInsn->next = mergeInsn; //remove goto from the chain
+ }
+ mergeInsn->prev = prevInsn;
+ bb->lastMIRInsn = bb->taken->lastMIRInsn;
+ bb->taken->firstMIRInsn = NULL; //block being merged in
+ bb->fallThrough = bb->taken->fallThrough;
+ bb->taken = bb->taken->taken;
+ return true;
+ }
+ return false;
+}
+
+static int genTraceProfileEntry(CompilationUnit *cUnit)
+{
+ cUnit->headerSize = 6;
+ if ((gDvmJit.profileMode == kTraceProfilingContinuous) ||
+ (gDvmJit.profileMode == kTraceProfilingDisabled)) {
+ return 12;
+ } else {
+ return 4;
+ }
+
+}
+
+#define PRINT_BUFFER_LEN 1024
+/* Print the code block in code cache in the range of [startAddr, endAddr)
+ * in readable format.
+ */
+void printEmittedCodeBlock(unsigned char *startAddr, unsigned char *endAddr)
+{
+ char strbuf[PRINT_BUFFER_LEN];
+ unsigned char *addr;
+ unsigned char *next_addr;
+ int n;
+
+ if (gDvmJit.printBinary) {
+ // print binary in bytes
+ n = 0;
+ for (addr = startAddr; addr < endAddr; addr++) {
+ n += snprintf(&strbuf[n], PRINT_BUFFER_LEN-n, "0x%x, ", *addr);
+ if (n > PRINT_BUFFER_LEN - 10) {
+ ALOGD("## %s", strbuf);
+ n = 0;
+ }
+ }
+ if (n > 0)
+ ALOGD("## %s", strbuf);
+ }
+
+ // print disassembled instructions
+ addr = startAddr;
+ while (addr < endAddr) {
+ next_addr = reinterpret_cast<unsigned char*>
+ (decoder_disassemble_instr(reinterpret_cast<char*>(addr),
+ strbuf, PRINT_BUFFER_LEN));
+ if (addr != next_addr) {
+ ALOGD("** %p: %s", addr, strbuf);
+ } else { // check whether this is nop padding
+ if (addr[0] == 0x90) {
+ ALOGD("** %p: NOP (1 byte)", addr);
+ next_addr += 1;
+ } else if (addr[0] == 0x66 && addr[1] == 0x90) {
+ ALOGD("** %p: NOP (2 bytes)", addr);
+ next_addr += 2;
+ } else if (addr[0] == 0x0f && addr[1] == 0x1f && addr[2] == 0x00) {
+ ALOGD("** %p: NOP (3 bytes)", addr);
+ next_addr += 3;
+ } else {
+ ALOGD("** unable to decode binary at %p", addr);
+ break;
+ }
+ }
+ addr = next_addr;
+ }
+}
+
+/* 4 is the number of additional bytes needed for chaining information for trace:
+ * 2 bytes for chaining cell count offset and 2 bytes for chaining cell offset */
+#define EXTRA_BYTES_FOR_CHAINING 4
+
+/* Entry function to invoke the backend of the JIT compiler */
+void dvmCompilerMIR2LIR(CompilationUnit *cUnit, JitTranslationInfo *info)
+{
+ dump_x86_inst = cUnit->printMe;
+ /* Used to hold the labels of each block */
+ LowOpBlockLabel *labelList =
+ (LowOpBlockLabel *)dvmCompilerNew(sizeof(LowOpBlockLabel) * cUnit->numBlocks, true); //Utility.c
+ LowOp *headLIR = NULL;
+ GrowableList chainingListByType[kChainingCellLast];
+ unsigned int i, padding;
+
+ /*
+ * Initialize various types chaining lists.
+ */
+ for (i = 0; i < kChainingCellLast; i++) {
+ dvmInitGrowableList(&chainingListByType[i], 2);
+ }
+
+ /* Clear the visited flag for each block */
+ dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerClearVisitedFlag,
+ kAllNodes, false /* isIterative */);
+
+ GrowableListIterator iterator;
+ dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
+
+ /* Traces start with a profiling entry point. Generate it here */
+ cUnit->profileCodeSize = genTraceProfileEntry(cUnit);
+
+ //BasicBlock **blockList = cUnit->blockList;
+ GrowableList *blockList = &cUnit->blockList;
+ BasicBlock *bb;
+
+ info->codeAddress = NULL;
+ stream = (char*)gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
+
+ // TODO: compile into a temporary buffer and then copy into the code cache.
+ // That would let us leave the code cache unprotected for a shorter time.
+ size_t unprotected_code_cache_bytes =
+ gDvmJit.codeCacheSize - gDvmJit.codeCacheByteUsed - CODE_CACHE_PADDING;
+ UNPROTECT_CODE_CACHE(stream, unprotected_code_cache_bytes);
+
+ streamStart = stream; /* trace start before alignment */
+ stream += EXTRA_BYTES_FOR_CHAINING; /* This is needed for chaining. Add the bytes before the alignment */
+ stream = (char*)(((unsigned int)stream + 0xF) & ~0xF); /* Align trace to 16-bytes */
+ streamMethodStart = stream; /* code start */
+ for (i = 0; i < ((unsigned int) cUnit->numBlocks); i++) {
+ labelList[i].lop.generic.offset = -1;
+ }
+ cUnit->exceptionBlockId = -1;
+ for (i = 0; i < blockList->numUsed; i++) {
+ bb = (BasicBlock *) blockList->elemList[i];
+ if(bb->blockType == kExceptionHandling)
+ cUnit->exceptionBlockId = i;
+ }
+ startOfTrace(cUnit->method, labelList, cUnit->exceptionBlockId, cUnit);
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ //merge blocks ending with "goto" with the fall through block
+ if (cUnit->jitMode != kJitLoop)
+ for (i = 0; i < blockList->numUsed; i++) {
+ bb = (BasicBlock *) blockList->elemList[i];
+ bool merged = mergeBlock(bb);
+ while(merged) merged = mergeBlock(bb);
+ }
+ for (i = 0; i < blockList->numUsed; i++) {
+ bb = (BasicBlock *) blockList->elemList[i];
+ if(bb->blockType == kDalvikByteCode &&
+ bb->firstMIRInsn != NULL) {
+ preprocessingBB(bb);
+ }
+ }
+ preprocessingTrace();
+ }
+
+ /* Handle the content in each basic block */
+ for (i = 0; ; i++) {
+ MIR *mir;
+ bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+ if (bb == NULL) break;
+ if (bb->visited == true) continue;
+
+ labelList[i].immOpnd.value = bb->startOffset;
+
+ if (bb->blockType >= kChainingCellLast) {
+ /*
+ * Append the label pseudo LIR first. Chaining cells will be handled
+ * separately afterwards.
+ */
+ dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
+ }
+
+ if (bb->blockType == kEntryBlock) {
+ labelList[i].lop.opCode2 = ATOM_PSEUDO_ENTRY_BLOCK;
+ if (bb->firstMIRInsn == NULL) {
+ continue;
+ } else {
+ setupLoopEntryBlock(cUnit, bb, bb->fallThrough->id);
+ //&labelList[blockList[i]->fallThrough->id]);
+ }
+ } else if (bb->blockType == kExitBlock) {
+ labelList[i].lop.opCode2 = ATOM_PSEUDO_EXIT_BLOCK;
+ labelList[i].lop.generic.offset = (stream - streamMethodStart);
+ goto gen_fallthrough;
+ } else if (bb->blockType == kDalvikByteCode) {
+ if (bb->hidden == true) continue;
+ labelList[i].lop.opCode2 = ATOM_PSEUDO_NORMAL_BLOCK_LABEL;
+ /* Reset the register state */
+#if 0
+ resetRegisterScoreboard(cUnit);
+#endif
+ } else {
+ switch (bb->blockType) {
+ case kChainingCellNormal:
+ labelList[i].lop.opCode2 = ATOM_PSEUDO_CHAINING_CELL_NORMAL;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[kChainingCellNormal], i);
+ break;
+ case kChainingCellInvokeSingleton:
+ labelList[i].lop.opCode2 =
+ ATOM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
+ labelList[i].immOpnd.value =
+ (int) bb->containingMethod;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[kChainingCellInvokeSingleton], i);
+ break;
+ case kChainingCellInvokePredicted:
+ labelList[i].lop.opCode2 =
+ ATOM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
+ /*
+ * Move the cached method pointer from operand 1 to 0.
+ * Operand 0 was clobbered earlier in this routine to store
+ * the block starting offset, which is not applicable to
+ * predicted chaining cell.
+ */
+ //TODO
+ //labelList[i].operands[0] = labelList[i].operands[1];
+
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[kChainingCellInvokePredicted], i);
+ break;
+ case kChainingCellHot:
+ labelList[i].lop.opCode2 =
+ ATOM_PSEUDO_CHAINING_CELL_HOT;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[kChainingCellHot], i);
+ break;
+ case kPCReconstruction:
+ /* Make sure exception handling block is next */
+ labelList[i].lop.opCode2 =
+ ATOM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
+ //assert (i == cUnit->numBlocks - 2);
+ labelList[i].lop.generic.offset = (stream - streamMethodStart);
+ handlePCReconstruction(cUnit,
+ &labelList[cUnit->puntBlock->id]);
+ break;
+ case kExceptionHandling:
+ labelList[i].lop.opCode2 = ATOM_PSEUDO_EH_BLOCK_LABEL;
+ labelList[i].lop.generic.offset = (stream - streamMethodStart);
+ //if (cUnit->pcReconstructionList.numUsed) {
+ scratchRegs[0] = PhysicalReg_EAX;
+ jumpToInterpPunt();
+ //call_dvmJitToInterpPunt();
+ //}
+ break;
+ case kChainingCellBackwardBranch:
+ labelList[i].lop.opCode2 = ATOM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[kChainingCellBackwardBranch],
+ i);
+ break;
+ default:
+ break;
+ }
+ continue;
+ }
+ {
+ //LowOp *headLIR = NULL;
+ const DexCode *dexCode = dvmGetMethodCode(cUnit->method);
+ const u2 *startCodePtr = dexCode->insns;
+ const u2 *codePtr;
+ labelList[i].lop.generic.offset = (stream - streamMethodStart);
+ ALOGV("get ready to handle JIT bb %d type %d hidden %d",
+ bb->id, bb->blockType, bb->hidden);
+ for (BasicBlock *nextBB = bb; nextBB != NULL; nextBB = cUnit->nextCodegenBlock) {
+ bb = nextBB;
+ bb->visited = true;
+ cUnit->nextCodegenBlock = NULL;
+
+ if(gDvm.executionMode == kExecutionModeNcgO1 &&
+ bb->blockType != kEntryBlock &&
+ bb->firstMIRInsn != NULL) {
+ startOfBasicBlock(bb);
+ int cg_ret = codeGenBasicBlockJit(cUnit->method, bb);
+ endOfBasicBlock(bb);
+ if(cg_ret < 0) {
+ endOfTrace(true/*freeOnly*/);
+ cUnit->baseAddr = NULL;
+ ALOGI("codeGenBasicBlockJit returns negative number");
+ PROTECT_CODE_CACHE(stream, unprotected_code_cache_bytes);
+ return;
+ }
+ } else {
+ for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+ startOfBasicBlock(bb); //why here for O0
+ Opcode dalvikOpCode = mir->dalvikInsn.opcode;
+ if((int)dalvikOpCode >= (int)kMirOpFirst) {
+ handleExtendedMIR(cUnit, mir);
+ continue;
+ }
+ InstructionFormat dalvikFormat =
+ dexGetFormatFromOpcode(dalvikOpCode);
+ ALOGV("ready to handle bytecode at offset %x: opcode %d format %d",
+ mir->offset, dalvikOpCode, dalvikFormat);
+ LowOpImm *boundaryLIR = dump_special(ATOM_PSEUDO_DALVIK_BYTECODE_BOUNDARY, mir->offset);
+ /* Remember the first LIR for this block */
+ if (headLIR == NULL) {
+ headLIR = (LowOp*)boundaryLIR;
+ }
+ bool notHandled = true;
+ /*
+ * Debugging: screen the opcode first to see if it is in the
+ * do[-not]-compile list
+ */
+ bool singleStepMe =
+ gDvmJit.includeSelectedOp !=
+ ((gDvmJit.opList[dalvikOpCode >> 3] &
+ (1 << (dalvikOpCode & 0x7))) !=
+ 0);
+ if (singleStepMe || cUnit->allSingleStep) {
+ } else {
+ codePtr = startCodePtr + mir->offset;
+ //lower each byte code, update LIR
+ notHandled = lowerByteCodeJit(cUnit->method, cUnit->method->insns+mir->offset, mir);
+ if(gDvmJit.codeCacheByteUsed + (stream - streamStart) +
+ CODE_CACHE_PADDING > gDvmJit.codeCacheSize) {
+ ALOGI("JIT code cache full after lowerByteCodeJit (trace uses %uB)", (stream - streamStart));
+ gDvmJit.codeCacheFull = true;
+ cUnit->baseAddr = NULL;
+ endOfTrace(true/*freeOnly*/);
+ PROTECT_CODE_CACHE(stream, unprotected_code_cache_bytes);
+ return;
+ }
+ }
+ if (notHandled) {
+ ALOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled",
+ mir->offset,
+ dalvikOpCode, dexGetOpcodeName(dalvikOpCode),
+ dalvikFormat);
+ dvmAbort();
+ break;
+ }
+ } // end for
+ } // end else //JIT + O0 code generator
+ }
+ } // end for
+ /* Eliminate redundant loads/stores and delay stores into later slots */
+#if 0
+ dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
+ cUnit->lastLIRInsn);
+#endif
+ if (headLIR) headLIR = NULL;
+gen_fallthrough:
+ /*
+ * Check if the block is terminated due to trace length constraint -
+ * insert an unconditional branch to the chaining cell.
+ */
+ if (bb->needFallThroughBranch) {
+ jumpToBasicBlock(stream, bb->fallThrough->id);
+ }
+
+ }
+
+ char* streamChainingStart = (char*)stream;
+ /* Handle the chaining cells in predefined order */
+ for (i = 0; i < kChainingCellGap; i++) {
+ size_t j;
+ int *blockIdList = (int *) chainingListByType[i].elemList;
+
+ cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
+
+ /* No chaining cells of this type */
+ if (cUnit->numChainingCells[i] == 0)
+ continue;
+
+ /* Record the first LIR for a new type of chaining cell */
+ cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
+ for (j = 0; j < chainingListByType[i].numUsed; j++) {
+ int blockId = blockIdList[j];
+ BasicBlock *chainingBlock =
+ (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
+ blockId);
+
+ labelList[blockId].lop.generic.offset = (stream - streamMethodStart);
+
+ /* Align this chaining cell first */
+#if 0
+ newLIR0(cUnit, ATOM_PSEUDO_ALIGN4);
+#endif
+ /* Insert the pseudo chaining instruction */
+ dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
+
+
+ switch (chainingBlock->blockType) {
+ case kChainingCellNormal:
+ handleNormalChainingCell(cUnit,
+ chainingBlock->startOffset, blockId, labelList);
+ break;
+ case kChainingCellInvokeSingleton:
+ handleInvokeSingletonChainingCell(cUnit,
+ chainingBlock->containingMethod, blockId, labelList);
+ break;
+ case kChainingCellInvokePredicted:
+ handleInvokePredictedChainingCell(cUnit, blockId);
+ break;
+ case kChainingCellHot:
+ handleHotChainingCell(cUnit,
+ chainingBlock->startOffset, blockId, labelList);
+ break;
+ case kChainingCellBackwardBranch:
+ handleBackwardBranchChainingCell(cUnit,
+ chainingBlock->startOffset, blockId, labelList);
+ break;
+ default:
+ ALOGE("Bad blocktype %d", chainingBlock->blockType);
+ dvmAbort();
+ break;
+ }
+
+ if (gDvmJit.codeCacheByteUsed + (stream - streamStart) + CODE_CACHE_PADDING > gDvmJit.codeCacheSize) {
+ ALOGI("JIT code cache full after ChainingCell (trace uses %uB)", (stream - streamStart));
+ gDvmJit.codeCacheFull = true;
+ cUnit->baseAddr = NULL;
+ endOfTrace(true); /* need to free structures */
+ PROTECT_CODE_CACHE(stream, unprotected_code_cache_bytes);
+ return;
+ }
+ }
+ }
+#if 0
+ dvmCompilerApplyGlobalOptimizations(cUnit);
+#endif
+ endOfTrace(false);
+
+ if (gDvmJit.codeCacheFull) {
+ /* We hit code cache size limit inside endofTrace(false).
+ * Bail out for this trace!
+ */
+ ALOGI("JIT code cache full after endOfTrace (trace uses %uB)", (stream - streamStart));
+ cUnit->baseAddr = NULL;
+ PROTECT_CODE_CACHE(stream, unprotected_code_cache_bytes);
+ return;
+ }
+
+ /* dump section for chaining cell counts, make sure it is 4-byte aligned */
+ padding = (4 - ((u4)stream & 3)) & 3;
+ stream += padding;
+ ChainCellCounts chainCellCounts;
+ /* Install the chaining cell counts */
+ for (i=0; i< kChainingCellGap; i++) {
+ chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
+ }
+ char* streamCountStart = (char*)stream;
+ memcpy((char*)stream, &chainCellCounts, sizeof(chainCellCounts));
+ stream += sizeof(chainCellCounts);
+
+ cUnit->baseAddr = streamMethodStart;
+ cUnit->totalSize = (stream - streamStart);
+ if(gDvmJit.codeCacheByteUsed + cUnit->totalSize + CODE_CACHE_PADDING > gDvmJit.codeCacheSize) {
+ ALOGI("JIT code cache full after ChainingCellCounts (trace uses %uB)", (stream - streamStart));
+ gDvmJit.codeCacheFull = true;
+ cUnit->baseAddr = NULL;
+ PROTECT_CODE_CACHE(stream, unprotected_code_cache_bytes);
+ return;
+ }
+
+ /* write chaining cell count offset & chaining cell offset */
+ u2* pOffset = (u2*)(streamMethodStart - EXTRA_BYTES_FOR_CHAINING); /* space was already allocated for this purpose */
+ *pOffset = streamCountStart - streamMethodStart; /* from codeAddr */
+ pOffset[1] = streamChainingStart - streamMethodStart;
+
+ PROTECT_CODE_CACHE(stream, unprotected_code_cache_bytes);
+
+ gDvmJit.codeCacheByteUsed += (stream - streamStart);
+ if (cUnit->printMe) {
+ unsigned char* codeBaseAddr = (unsigned char *) cUnit->baseAddr;
+ unsigned char* codeBaseAddrNext = ((unsigned char *) gDvmJit.codeCache) + gDvmJit.codeCacheByteUsed;
+ ALOGD("-------- Built trace for %s%s, JIT code [%p, %p) cache start %p",
+ cUnit->method->clazz->descriptor, cUnit->method->name,
+ codeBaseAddr, codeBaseAddrNext, gDvmJit.codeCache);
+ ALOGD("** %s%s@0x%x:", cUnit->method->clazz->descriptor,
+ cUnit->method->name, cUnit->traceDesc->trace[0].info.frag.startOffset);
+ printEmittedCodeBlock(codeBaseAddr, codeBaseAddrNext);
+ }
+ ALOGV("JIT CODE after trace %p to %p size %x START %p", cUnit->baseAddr,
+ (char *) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed,
+ cUnit->totalSize, gDvmJit.codeCache);
+
+ gDvmJit.numCompilations++;
+
+ info->codeAddress = (char*)cUnit->baseAddr;// + cUnit->headerSize;
+}
+
+/*
+ * Perform translation chain operation.
+ */
+void* dvmJitChain(void* tgtAddr, u4* branchAddr)
+{
+#ifdef JIT_CHAIN
+ int relOffset = (int) tgtAddr - (int)branchAddr;
+
+ if ((gDvmJit.pProfTable != NULL) && (gDvm.sumThreadSuspendCount == 0) &&
+ (gDvmJit.codeCacheFull == false)) {
+
+ gDvmJit.translationChains++;
+
+ //OpndSize immSize = estOpndSizeFromImm(relOffset);
+ //relOffset -= getJmpCallInstSize(immSize, JmpCall_uncond);
+ /* Hard coded the jump opnd size to 32 bits, This instruction will replace the "jump 0" in
+ * the original code sequence.
+ */
+ OpndSize immSize = OpndSize_32;
+ relOffset -= 5;
+ //can't use stream here since it is used by the compilation thread
+ UNPROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
+ dump_imm_with_codeaddr(Mnemonic_JMP, immSize, relOffset, (char*)branchAddr); //dump to branchAddr
+ PROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
+
+ gDvmJit.hasNewChain = true;
+
+ COMPILER_TRACE_CHAINING(
+ ALOGI("Jit Runtime: chaining 0x%x to %p with relOffset %x",
+ (int) branchAddr, tgtAddr, relOffset));
+ }
+#endif
+ return tgtAddr;
+}
+
+/*
+ * Accept the work and start compiling. Returns true if compilation
+ * is attempted.
+ */
+bool dvmCompilerDoWork(CompilerWorkOrder *work)
+{
+ JitTraceDescription *desc;
+ bool isCompile;
+ bool success = true;
+
+ if (gDvmJit.codeCacheFull) {
+ return false;
+ }
+
+ switch (work->kind) {
+ case kWorkOrderTrace:
+ isCompile = true;
+ /* Start compilation with maximally allowed trace length */
+ desc = (JitTraceDescription *)work->info;
+ success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
+ work->bailPtr, 0 /* no hints */);
+ break;
+ case kWorkOrderTraceDebug: {
+ bool oldPrintMe = gDvmJit.printMe;
+ gDvmJit.printMe = true;
+ isCompile = true;
+ /* Start compilation with maximally allowed trace length */
+ desc = (JitTraceDescription *)work->info;
+ success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
+ work->bailPtr, 0 /* no hints */);
+ gDvmJit.printMe = oldPrintMe;
+ break;
+ }
+ case kWorkOrderProfileMode:
+ dvmJitChangeProfileMode((TraceProfilingModes)(int)work->info);
+ isCompile = false;
+ break;
+ default:
+ isCompile = false;
+ ALOGE("Jit: unknown work order type");
+ assert(0); // Bail if debug build, discard otherwise
+ }
+ if (!success)
+ work->result.codeAddress = NULL;
+ return isCompile;
+}
+
+void dvmCompilerCacheFlush(long start, long end, long flags) {
+ /* cacheflush is needed for ARM, but not for IA32 (coherent icache) */
+}
+
+//#endif
diff --git a/vm/compiler/codegen/x86/Lower.cpp b/vm/compiler/codegen/x86/Lower.cpp
new file mode 100644
index 0000000..d0e7f92
--- /dev/null
+++ b/vm/compiler/codegen/x86/Lower.cpp
@@ -0,0 +1,982 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file Lower.cpp
+ \brief This file implements the high-level wrapper for lowering
+
+*/
+
+//#include "uthash.h"
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include <math.h>
+#include <sys/mman.h>
+#include "Translator.h"
+#include "Lower.h"
+#include "enc_wrapper.h"
+#include "vm/mterp/Mterp.h"
+#include "NcgHelper.h"
+#include "libdex/DexCatch.h"
+#include "compiler/CompilerIR.h"
+
+//statistics for optimization
+int num_removed_nullCheck;
+
+PhysicalReg scratchRegs[4];
+
+LowOp* ops[BUFFER_SIZE];
+LowOp* op;
+u2* rPC; //PC pointer to bytecode
+u2 inst; //current bytecode
+int offsetPC/*offset in bytecode*/, offsetNCG/*byte offset in native code*/;
+int ncg_rPC;
+//! map from PC in bytecode to PC in native code
+int mapFromBCtoNCG[BYTECODE_SIZE_PER_METHOD]; //initially mapped to -1
+char* streamStart = NULL; //start of the Pure CodeItem?, not include the global symbols
+char* streamCode = NULL; //start of the Pure CodeItem?, not include the global symbols
+char* streamMethodStart; //start of the method
+char* stream; //current stream pointer
+int lowOpTimeStamp = 0;
+Method* currentMethod = NULL;
+int currentExceptionBlockIdx = -1;
+LowOpBlockLabel* traceLabelList = NULL;
+BasicBlock* traceCurrentBB = NULL;
+MIR* traceCurrentMIR = NULL;
+bool scheduling_is_on = false;
+
+int common_invokeMethodNoRange();
+int common_invokeMethodRange();
+int common_invokeArgsDone(ArgsDoneType, bool);
+
+//data section of .ia32:
+char globalData[128];
+
+char strClassCastException[] = "Ljava/lang/ClassCastException;";
+char strInstantiationError[] = "Ljava/lang/InstantiationError;";
+char strInternalError[] = "Ljava/lang/InternalError;";
+char strFilledNewArrayNotImpl[] = "filled-new-array only implemented for 'int'";
+char strArithmeticException[] = "Ljava/lang/ArithmeticException;";
+char strArrayIndexException[] = "Ljava/lang/ArrayIndexOutOfBoundsException;";
+char strArrayStoreException[] = "Ljava/lang/ArrayStoreException;";
+char strDivideByZero[] = "divide by zero";
+char strNegativeArraySizeException[] = "Ljava/lang/NegativeArraySizeException;";
+char strNoSuchMethodError[] = "Ljava/lang/NoSuchMethodError;";
+char strNullPointerException[] = "Ljava/lang/NullPointerException;";
+char strStringIndexOutOfBoundsException[] = "Ljava/lang/StringIndexOutOfBoundsException;";
+
+int LstrClassCastExceptionPtr, LstrInstantiationErrorPtr, LstrInternalError, LstrFilledNewArrayNotImpl;
+int LstrArithmeticException, LstrArrayIndexException, LstrArrayStoreException, LstrStringIndexOutOfBoundsException;
+int LstrDivideByZero, LstrNegativeArraySizeException, LstrNoSuchMethodError, LstrNullPointerException;
+int LdoubNeg, LvaluePosInfLong, LvalueNegInfLong, LvalueNanLong, LshiftMask, Lvalue64, L64bits, LintMax, LintMin;
+
+void initConstDataSec() {
+ char* tmpPtr = globalData;
+
+ LdoubNeg = (int)tmpPtr;
+ *((u4*)tmpPtr) = 0x00000000;
+ tmpPtr += sizeof(u4);
+ *((u4*)tmpPtr) = 0x80000000;
+ tmpPtr += sizeof(u4);
+
+ LvaluePosInfLong = (int)tmpPtr;
+ *((u4*)tmpPtr) = 0xFFFFFFFF;
+ tmpPtr += sizeof(u4);
+ *((u4*)tmpPtr) = 0x7FFFFFFF;
+ tmpPtr += sizeof(u4);
+
+ LvalueNegInfLong = (int)tmpPtr;
+ *((u4*)tmpPtr) = 0x00000000;
+ tmpPtr += sizeof(u4);
+ *((u4*)tmpPtr) = 0x80000000;
+ tmpPtr += sizeof(u4);
+
+ LvalueNanLong = (int)tmpPtr;
+ *((u4*)tmpPtr) = 0;
+ tmpPtr += sizeof(u4);
+ *((u4*)tmpPtr) = 0;
+ tmpPtr += sizeof(u4);
+
+ LshiftMask = (int)tmpPtr;
+ *((u4*)tmpPtr) = 0x3f;
+ tmpPtr += sizeof(u4);
+ *((u4*)tmpPtr) = 0;
+ tmpPtr += sizeof(u4);
+
+ Lvalue64 = (int)tmpPtr;
+ *((u4*)tmpPtr) = 0x40;
+ tmpPtr += sizeof(u4);
+ *((u4*)tmpPtr) = 0;
+ tmpPtr += sizeof(u4);
+
+ L64bits = (int)tmpPtr;
+ *((u4*)tmpPtr) = 0xFFFFFFFF;
+ tmpPtr += sizeof(u4);
+ *((u4*)tmpPtr) = 0xFFFFFFFF;
+ tmpPtr += sizeof(u4);
+
+ LintMin = (int)tmpPtr;
+ *((u4*)tmpPtr) = 0x80000000;
+ tmpPtr += sizeof(u4);
+
+ LintMax = (int)tmpPtr;
+ *((u4*)tmpPtr) = 0x7FFFFFFF;
+ tmpPtr += sizeof(u4);
+
+ LstrClassCastExceptionPtr = (int)strClassCastException;
+ LstrInstantiationErrorPtr = (int)strInstantiationError;
+ LstrInternalError = (int)strInternalError;
+ LstrFilledNewArrayNotImpl = (int)strFilledNewArrayNotImpl;
+ LstrArithmeticException = (int)strArithmeticException;
+ LstrArrayIndexException = (int)strArrayIndexException;
+ LstrArrayStoreException = (int)strArrayStoreException;
+ LstrDivideByZero = (int)strDivideByZero;
+ LstrNegativeArraySizeException = (int)strNegativeArraySizeException;
+ LstrNoSuchMethodError = (int)strNoSuchMethodError;
+ LstrNullPointerException = (int)strNullPointerException;
+ LstrStringIndexOutOfBoundsException = (int)strStringIndexOutOfBoundsException;
+}
+
+//declarations of functions used in this file
+int spill_reg(int reg, bool isPhysical);
+int unspill_reg(int reg, bool isPhysical);
+
+int const_string_resolve();
+int sget_sput_resolve();
+int new_instance_needinit();
+int new_instance_abstract();
+int invoke_virtual_resolve();
+int invoke_direct_resolve();
+int invoke_static_resolve();
+int filled_new_array_notimpl();
+int resolve_class2(
+ int startLR/*logical register index*/, bool isPhysical, int indexReg/*const pool index*/,
+ bool indexPhysical,
+ int thirdArg);
+int resolve_method2(
+ int startLR/*logical register index*/, bool isPhysical, int indexReg/*const pool index*/,
+ bool indexPhysical,
+ int thirdArg/*VIRTUAL*/);
+int resolve_inst_field2(
+ int startLR/*logical register index*/, bool isPhysical,
+ int indexReg/*const pool index*/,
+ bool indexPhysical);
+int resolve_static_field2(
+ int startLR/*logical register index*/, bool isPhysical,
+ int indexReg/*const pool index*/,
+ bool indexPhysical);
+
+int invokeMethodNoRange_1_helper();
+int invokeMethodNoRange_2_helper();
+int invokeMethodNoRange_3_helper();
+int invokeMethodNoRange_4_helper();
+int invokeMethodNoRange_5_helper();
+int invokeMethodRange_helper();
+
+int invoke_virtual_helper();
+int invoke_virtual_quick_helper();
+int invoke_static_helper();
+int invoke_direct_helper();
+int new_instance_helper();
+int sget_sput_helper(int flag);
+int aput_obj_helper();
+int aget_helper(int flag);
+int aput_helper(int flag);
+int monitor_enter_helper();
+int monitor_exit_helper();
+int throw_helper();
+int const_string_helper();
+int array_length_helper();
+int invoke_super_helper();
+int invoke_interface_helper();
+int iget_iput_helper(int flag);
+int check_cast_helper(bool instance);
+int new_array_helper();
+
+int common_returnFromMethod();
+
+/*!
+\brief dump helper functions
+
+*/
+int performCGWorklist() {
+ filled_new_array_notimpl();
+ freeShortMap();
+ const_string_resolve();
+ freeShortMap();
+
+ resolve_class2(PhysicalReg_EAX, true, PhysicalReg_EAX, true, 0);
+ freeShortMap();
+ resolve_method2(PhysicalReg_EAX, true, PhysicalReg_EAX, true, METHOD_VIRTUAL);
+ freeShortMap();
+ resolve_method2(PhysicalReg_EAX, true, PhysicalReg_EAX, true, METHOD_DIRECT);
+ freeShortMap();
+ resolve_method2(PhysicalReg_EAX, true, PhysicalReg_EAX, true, METHOD_STATIC);
+ freeShortMap();
+ resolve_inst_field2(PhysicalReg_EAX, true, PhysicalReg_EAX, true);
+ freeShortMap();
+ resolve_static_field2(PhysicalReg_EAX, true, PhysicalReg_EAX, true);
+ freeShortMap();
+ throw_exception_message(PhysicalReg_ECX, PhysicalReg_EAX, true, PhysicalReg_Null, true);
+ freeShortMap();
+ throw_exception(PhysicalReg_ECX, PhysicalReg_EAX, PhysicalReg_Null, true);
+ freeShortMap();
+ new_instance_needinit();
+ freeShortMap();
+ return 0;
+}
+
+int aput_object_count;
+int common_periodicChecks_entry();
+int common_periodicChecks4();
+/*!
+\brief for debugging purpose, dump the sequence of native code for each bytecode
+
+*/
+int ncgMethodFake(Method* method) {
+ //to measure code size expansion, no need to patch up labels
+ methodDataWorklist = NULL;
+ globalShortWorklist = NULL;
+ globalNCGWorklist = NULL;
+ streamMethodStart = stream;
+
+ //initialize mapFromBCtoNCG
+ memset(&mapFromBCtoNCG[0], -1, BYTECODE_SIZE_PER_METHOD * sizeof(mapFromBCtoNCG[0]));
+ unsigned int i;
+ u2* rStart = (u2*)malloc(5*sizeof(u2));
+ if(rStart == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ rPC = rStart;
+ method->insns = rStart;
+ for(i = 0; i < 5; i++) *rPC++ = 0;
+ for(i = 0; i < 256; i++) {
+ rPC = rStart;
+ //modify the opcode
+ char* tmp = (char*)rStart;
+ *tmp++ = i;
+ *tmp = i;
+ inst = FETCH(0);
+ char* tmpStart = stream;
+ lowerByteCode(method); //use inst, rPC, method, modify rPC
+ int size_in_u2 = rPC - rStart;
+ if(stream - tmpStart > 0)
+ ALOGI("LOWER bytecode %x size in u2: %d ncg size in byte: %d", i, size_in_u2, stream - tmpStart);
+ }
+ exit(0);
+}
+
+bool existATryBlock(Method* method, int startPC, int endPC) {
+ const DexCode* pCode = dvmGetMethodCode(method);
+ u4 triesSize = pCode->triesSize;
+ const DexTry* pTries = dexGetTries(pCode);
+ unsigned int i;
+ for (i = 0; i < triesSize; i++) {
+ const DexTry* pTry = &pTries[i];
+ u4 start = pTry->startAddr; //offsetPC
+ u4 end = start + pTry->insnCount;
+ //if [start, end] overlaps with [startPC, endPC] returns true
+ if((int)end < startPC || (int)start > endPC) { //no overlap
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
+
+int mm_bytecode_size = 0;
+int mm_ncg_size = 0;
+int mm_relocation_size = 0;
+int mm_map_size = 0;
+void resetCodeSize() {
+ mm_bytecode_size = 0;
+ mm_ncg_size = 0;
+ mm_relocation_size = 0;
+ mm_map_size = 0;
+}
+
+bool bytecodeIsRemoved(const Method* method, u4 bytecodeOffset) {
+ if(gDvm.executionMode == kExecutionModeNcgO0) return false;
+ u4 ncgOff = mapFromBCtoNCG[bytecodeOffset];
+ int k = bytecodeOffset+1;
+ u2 insnsSize = dvmGetMethodInsnsSize(method);
+ while(k < insnsSize) {
+ if(mapFromBCtoNCG[k] < 0) {
+ k++;
+ continue;
+ }
+ if(mapFromBCtoNCG[k] == (int)ncgOff) return true;
+ return false;
+ }
+ return false;
+}
+
+int invoke_super_nsm();
+void init_common(const char* curFileName, DvmDex *pDvmDex, bool forNCG); //forward declaration
+void initGlobalMethods(); //forward declaration
+
+//called once when compiler thread starts up
+void initJIT(const char* curFileName, DvmDex *pDvmDex) {
+ init_common(curFileName, pDvmDex, false);
+}
+
+void init_common(const char* curFileName, DvmDex *pDvmDex, bool forNCG) {
+ if(!gDvm.constInit) {
+ globalMapNum = 0;
+ globalMap = NULL;
+ initConstDataSec();
+ gDvm.constInit = true;
+ }
+
+ //for initJIT: stream is already set
+ if(!gDvm.commonInit) {
+ initGlobalMethods();
+ gDvm.commonInit = true;
+ }
+}
+
+void initGlobalMethods() {
+ dump_x86_inst = false; /* DEBUG */
+ // generate native code for function ncgGetEIP
+ insertLabel("ncgGetEIP", false);
+ move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, PhysicalReg_EDX, true);
+ x86_return();
+
+ //generate code for common labels
+ //jumps within a helper function is treated as short labels
+ globalShortMap = NULL;
+ common_periodicChecks_entry();
+ freeShortMap();
+ common_periodicChecks4();
+ freeShortMap();
+ //common_invokeMethodNoRange();
+ //common_invokeMethodRange();
+
+ if(dump_x86_inst) ALOGI("ArgsDone_Normal start");
+ common_invokeArgsDone(ArgsDone_Normal, false);
+ freeShortMap();
+ if(dump_x86_inst) ALOGI("ArgsDone_Native start");
+ common_invokeArgsDone(ArgsDone_Native, false);
+ freeShortMap();
+ if(dump_x86_inst) ALOGI("ArgsDone_Full start");
+ common_invokeArgsDone(ArgsDone_Full, true/*isJitFull*/);
+ if(dump_x86_inst) ALOGI("ArgsDone_Full end");
+ freeShortMap();
+
+ common_backwardBranch();
+ freeShortMap();
+ common_exceptionThrown();
+ freeShortMap();
+ common_errNullObject();
+ freeShortMap();
+ common_errArrayIndex();
+ freeShortMap();
+ common_errArrayStore();
+ freeShortMap();
+ common_errNegArraySize();
+ freeShortMap();
+ common_errNoSuchMethod();
+ freeShortMap();
+ common_errDivideByZero();
+ freeShortMap();
+ common_gotoBail();
+ freeShortMap();
+ common_gotoBail_0();
+ freeShortMap();
+ invoke_super_nsm();
+ freeShortMap();
+
+ performCGWorklist(); //generate code for helper functions
+ performLabelWorklist(); //it is likely that the common labels will jump to other common labels
+
+ dump_x86_inst = false;
+}
+
+ExecutionMode origMode;
+//when to update streamMethodStart
+bool lowerByteCodeJit(const Method* method, const u2* codePtr, MIR* mir) {
+ rPC = (u2*)codePtr;
+ inst = FETCH(0);
+ traceCurrentMIR = mir;
+ int retCode = lowerByteCode(method);
+ traceCurrentMIR = NULL;
+ freeShortMap();
+ if(retCode >= 0) return false; //handled
+ return true; //not handled
+}
+
+void startOfBasicBlock(BasicBlock* bb) {
+ traceCurrentBB = bb;
+ if(gDvm.executionMode == kExecutionModeNcgO0) {
+ isScratchPhysical = true;
+ } else {
+ isScratchPhysical = false;
+ }
+}
+
+void startOfTrace(const Method* method, LowOpBlockLabel* labelList, int exceptionBlockId,
+ CompilationUnit *cUnit) {
+ origMode = gDvm.executionMode;
+ gDvm.executionMode = kExecutionModeNcgO1;
+ if(gDvm.executionMode == kExecutionModeNcgO0) {
+ isScratchPhysical = true;
+ } else {
+ isScratchPhysical = false;
+ }
+ currentMethod = (Method*)method;
+ currentExceptionBlockIdx = exceptionBlockId;
+ methodDataWorklist = NULL;
+ globalShortWorklist = NULL;
+ globalNCGWorklist = NULL;
+
+ streamMethodStart = stream;
+ //initialize mapFromBCtoNCG
+ memset(&mapFromBCtoNCG[0], -1, BYTECODE_SIZE_PER_METHOD * sizeof(mapFromBCtoNCG[0]));
+ traceLabelList = labelList;
+ if(gDvm.executionMode == kExecutionModeNcgO1)
+ startOfTraceO1(method, labelList, exceptionBlockId, cUnit);
+}
+
+void endOfTrace(bool freeOnly) {
+ if(freeOnly) {
+ freeLabelWorklist();
+ freeNCGWorklist();
+ freeDataWorklist();
+ freeChainingWorklist();
+ }
+ else {
+ performLabelWorklist();
+ performNCGWorklist(); //handle forward jump (GOTO, IF)
+ performDataWorklist(); //handle SWITCH & FILL_ARRAY_DATA
+ performChainingWorklist();
+ }
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ endOfTraceO1();
+ }
+ gDvm.executionMode = origMode;
+}
+
+///////////////////////////////////////////////////////////////////
+//!
+//! each bytecode is translated to a sequence of machine codes
+int lowerByteCode(const Method* method) { //inputs: rPC & inst & stream & streamMethodStart
+ /* offsetPC is used in O1 code generator, where it is defined as the sequence number
+ use a local version to avoid overwriting */
+ int offsetPC = rPC - (u2*)method->insns;
+
+ if(dump_x86_inst)
+ ALOGI("LOWER bytecode %x at offsetPC %x offsetNCG %x @%p",
+ INST_INST(inst), offsetPC, stream - streamMethodStart, stream);
+
+ //update mapFromBCtoNCG
+ offsetNCG = stream - streamMethodStart;
+ if(offsetPC >= BYTECODE_SIZE_PER_METHOD) ALOGE("offsetPC %d exceeds BYTECODE_SIZE_PER_METHOD", offsetPC);
+ mapFromBCtoNCG[offsetPC] = offsetNCG;
+#if defined(ENABLE_TRACING) && defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC, mapFromBCtoNCG[offsetPC], 1);
+#endif
+ //return number of LowOps generated
+ switch (INST_INST(inst)) {
+ case OP_NOP:
+ return op_nop();
+ case OP_MOVE:
+ case OP_MOVE_OBJECT:
+ return op_move();
+ case OP_MOVE_FROM16:
+ case OP_MOVE_OBJECT_FROM16:
+ return op_move_from16();
+ case OP_MOVE_16:
+ case OP_MOVE_OBJECT_16:
+ return op_move_16();
+ case OP_MOVE_WIDE:
+ return op_move_wide();
+ case OP_MOVE_WIDE_FROM16:
+ return op_move_wide_from16();
+ case OP_MOVE_WIDE_16:
+ return op_move_wide_16();
+ case OP_MOVE_RESULT:
+ case OP_MOVE_RESULT_OBJECT:
+ return op_move_result();
+ case OP_MOVE_RESULT_WIDE:
+ return op_move_result_wide();
+ case OP_MOVE_EXCEPTION:
+ return op_move_exception();
+ case OP_RETURN_VOID:
+ case OP_RETURN_VOID_BARRIER:
+ return op_return_void();
+ case OP_RETURN:
+ case OP_RETURN_OBJECT:
+ return op_return();
+ case OP_RETURN_WIDE:
+ return op_return_wide();
+ case OP_CONST_4:
+ return op_const_4();
+ case OP_CONST_16:
+ return op_const_16();
+ case OP_CONST:
+ return op_const();
+ case OP_CONST_HIGH16:
+ return op_const_high16();
+ case OP_CONST_WIDE_16:
+ return op_const_wide_16();
+ case OP_CONST_WIDE_32:
+ return op_const_wide_32();
+ case OP_CONST_WIDE:
+ return op_const_wide();
+ case OP_CONST_WIDE_HIGH16:
+ return op_const_wide_high16();
+ case OP_CONST_STRING:
+ return op_const_string();
+ case OP_CONST_STRING_JUMBO:
+ return op_const_string_jumbo();
+ case OP_CONST_CLASS:
+ return op_const_class();
+ case OP_MONITOR_ENTER:
+ return op_monitor_enter();
+ case OP_MONITOR_EXIT:
+ return op_monitor_exit();
+ case OP_CHECK_CAST:
+ return op_check_cast();
+ case OP_INSTANCE_OF:
+ return op_instance_of();
+ case OP_ARRAY_LENGTH:
+ return op_array_length();
+ case OP_NEW_INSTANCE:
+ return op_new_instance();
+ case OP_NEW_ARRAY:
+ return op_new_array();
+ case OP_FILLED_NEW_ARRAY:
+ return op_filled_new_array();
+ case OP_FILLED_NEW_ARRAY_RANGE:
+ return op_filled_new_array_range();
+ case OP_FILL_ARRAY_DATA:
+ return op_fill_array_data();
+ case OP_THROW:
+ return op_throw();
+ case OP_THROW_VERIFICATION_ERROR:
+ return op_throw_verification_error();
+ case OP_GOTO:
+ return op_goto();
+ case OP_GOTO_16:
+ return op_goto_16();
+ case OP_GOTO_32:
+ return op_goto_32();
+ case OP_PACKED_SWITCH:
+ return op_packed_switch();
+ case OP_SPARSE_SWITCH:
+ return op_sparse_switch();
+ case OP_CMPL_FLOAT:
+ return op_cmpl_float();
+ case OP_CMPG_FLOAT:
+ return op_cmpg_float();
+ case OP_CMPL_DOUBLE:
+ return op_cmpl_double();
+ case OP_CMPG_DOUBLE:
+ return op_cmpg_double();
+ case OP_CMP_LONG:
+ return op_cmp_long();
+ case OP_IF_EQ:
+ return op_if_eq();
+ case OP_IF_NE:
+ return op_if_ne();
+ case OP_IF_LT:
+ return op_if_lt();
+ case OP_IF_GE:
+ return op_if_ge();
+ case OP_IF_GT:
+ return op_if_gt();
+ case OP_IF_LE:
+ return op_if_le();
+ case OP_IF_EQZ:
+ return op_if_eqz();
+ case OP_IF_NEZ:
+ return op_if_nez();
+ case OP_IF_LTZ:
+ return op_if_ltz();
+ case OP_IF_GEZ:
+ return op_if_gez();
+ case OP_IF_GTZ:
+ return op_if_gtz();
+ case OP_IF_LEZ:
+ return op_if_lez();
+ case OP_AGET:
+ return op_aget();
+ case OP_AGET_WIDE:
+ return op_aget_wide();
+ case OP_AGET_OBJECT:
+ return op_aget_object();
+ case OP_AGET_BOOLEAN:
+ return op_aget_boolean();
+ case OP_AGET_BYTE:
+ return op_aget_byte();
+ case OP_AGET_CHAR:
+ return op_aget_char();
+ case OP_AGET_SHORT:
+ return op_aget_short();
+ case OP_APUT:
+ return op_aput();
+ case OP_APUT_WIDE:
+ return op_aput_wide();
+ case OP_APUT_OBJECT:
+ return op_aput_object();
+ case OP_APUT_BOOLEAN:
+ return op_aput_boolean();
+ case OP_APUT_BYTE:
+ return op_aput_byte();
+ case OP_APUT_CHAR:
+ return op_aput_char();
+ case OP_APUT_SHORT:
+ return op_aput_short();
+ case OP_IGET:
+ case OP_IGET_VOLATILE:
+ return op_iget();
+ case OP_IGET_WIDE:
+ return op_iget_wide(false); // isVolatile==false
+ case OP_IGET_WIDE_VOLATILE:
+ return op_iget_wide(true); // isVolatile==true
+ case OP_IGET_OBJECT:
+ case OP_IGET_OBJECT_VOLATILE:
+ return op_iget_object();
+ case OP_IGET_BOOLEAN:
+ return op_iget_boolean();
+ case OP_IGET_BYTE:
+ return op_iget_byte();
+ case OP_IGET_CHAR:
+ return op_iget_char();
+ case OP_IGET_SHORT:
+ return op_iget_short();
+ case OP_IPUT:
+ case OP_IPUT_VOLATILE:
+ return op_iput();
+ case OP_IPUT_WIDE:
+ return op_iput_wide(false); // isVolatile==false
+ case OP_IPUT_WIDE_VOLATILE:
+ return op_iput_wide(true); // isVolatile==true
+ case OP_IPUT_OBJECT:
+ case OP_IPUT_OBJECT_VOLATILE:
+ return op_iput_object();
+ case OP_IPUT_BOOLEAN:
+ return op_iput_boolean();
+ case OP_IPUT_BYTE:
+ return op_iput_byte();
+ case OP_IPUT_CHAR:
+ return op_iput_char();
+ case OP_IPUT_SHORT:
+ return op_iput_short();
+ case OP_SGET:
+ case OP_SGET_VOLATILE:
+ return op_sget();
+ case OP_SGET_WIDE:
+ return op_sget_wide(false); // isVolatile==false
+ case OP_SGET_WIDE_VOLATILE:
+ return op_sget_wide(true); // isVolatile==true
+ case OP_SGET_OBJECT:
+ case OP_SGET_OBJECT_VOLATILE:
+ return op_sget_object();
+ case OP_SGET_BOOLEAN:
+ return op_sget_boolean();
+ case OP_SGET_BYTE:
+ return op_sget_byte();
+ case OP_SGET_CHAR:
+ return op_sget_char();
+ case OP_SGET_SHORT:
+ return op_sget_short();
+ case OP_SPUT:
+ case OP_SPUT_VOLATILE:
+ return op_sput(false);
+ case OP_SPUT_WIDE:
+ return op_sput_wide(false); // isVolatile==false
+ case OP_SPUT_WIDE_VOLATILE:
+ return op_sput_wide(true); // isVolatile==true
+ case OP_SPUT_OBJECT:
+ case OP_SPUT_OBJECT_VOLATILE:
+ return op_sput_object();
+ case OP_SPUT_BOOLEAN:
+ return op_sput_boolean();
+ case OP_SPUT_BYTE:
+ return op_sput_byte();
+ case OP_SPUT_CHAR:
+ return op_sput_char();
+ case OP_SPUT_SHORT:
+ return op_sput_short();
+ case OP_INVOKE_VIRTUAL:
+ return op_invoke_virtual();
+ case OP_INVOKE_SUPER:
+ return op_invoke_super();
+ case OP_INVOKE_DIRECT:
+ return op_invoke_direct();
+ case OP_INVOKE_STATIC:
+ return op_invoke_static();
+ case OP_INVOKE_INTERFACE:
+ return op_invoke_interface();
+ case OP_INVOKE_VIRTUAL_RANGE:
+ return op_invoke_virtual_range();
+ case OP_INVOKE_SUPER_RANGE:
+ return op_invoke_super_range();
+ case OP_INVOKE_DIRECT_RANGE:
+ return op_invoke_direct_range();
+ case OP_INVOKE_STATIC_RANGE:
+ return op_invoke_static_range();
+ case OP_INVOKE_INTERFACE_RANGE:
+ return op_invoke_interface_range();
+ case OP_NEG_INT:
+ return op_neg_int();
+ case OP_NOT_INT:
+ return op_not_int();
+ case OP_NEG_LONG:
+ return op_neg_long();
+ case OP_NOT_LONG:
+ return op_not_long();
+ case OP_NEG_FLOAT:
+ return op_neg_float();
+ case OP_NEG_DOUBLE:
+ return op_neg_double();
+ case OP_INT_TO_LONG:
+ return op_int_to_long();
+ case OP_INT_TO_FLOAT:
+ return op_int_to_float();
+ case OP_INT_TO_DOUBLE:
+ return op_int_to_double();
+ case OP_LONG_TO_INT:
+ return op_long_to_int();
+ case OP_LONG_TO_FLOAT:
+ return op_long_to_float();
+ case OP_LONG_TO_DOUBLE:
+ return op_long_to_double();
+ case OP_FLOAT_TO_INT:
+ return op_float_to_int();
+ case OP_FLOAT_TO_LONG:
+ return op_float_to_long();
+ case OP_FLOAT_TO_DOUBLE:
+ return op_float_to_double();
+ case OP_DOUBLE_TO_INT:
+ return op_double_to_int();
+ case OP_DOUBLE_TO_LONG:
+ return op_double_to_long();
+ case OP_DOUBLE_TO_FLOAT:
+ return op_double_to_float();
+ case OP_INT_TO_BYTE:
+ return op_int_to_byte();
+ case OP_INT_TO_CHAR:
+ return op_int_to_char();
+ case OP_INT_TO_SHORT:
+ return op_int_to_short();
+ case OP_ADD_INT:
+ return op_add_int();
+ case OP_SUB_INT:
+ return op_sub_int();
+ case OP_MUL_INT:
+ return op_mul_int();
+ case OP_DIV_INT:
+ return op_div_int();
+ case OP_REM_INT:
+ return op_rem_int();
+ case OP_AND_INT:
+ return op_and_int();
+ case OP_OR_INT:
+ return op_or_int();
+ case OP_XOR_INT:
+ return op_xor_int();
+ case OP_SHL_INT:
+ return op_shl_int();
+ case OP_SHR_INT:
+ return op_shr_int();
+ case OP_USHR_INT:
+ return op_ushr_int();
+ case OP_ADD_LONG:
+ return op_add_long();
+ case OP_SUB_LONG:
+ return op_sub_long();
+ case OP_MUL_LONG:
+ return op_mul_long();
+ case OP_DIV_LONG:
+ return op_div_long();
+ case OP_REM_LONG:
+ return op_rem_long();
+ case OP_AND_LONG:
+ return op_and_long();
+ case OP_OR_LONG:
+ return op_or_long();
+ case OP_XOR_LONG:
+ return op_xor_long();
+ case OP_SHL_LONG:
+ return op_shl_long();
+ case OP_SHR_LONG:
+ return op_shr_long();
+ case OP_USHR_LONG:
+ return op_ushr_long();
+ case OP_ADD_FLOAT:
+ return op_add_float();
+ case OP_SUB_FLOAT:
+ return op_sub_float();
+ case OP_MUL_FLOAT:
+ return op_mul_float();
+ case OP_DIV_FLOAT:
+ return op_div_float();
+ case OP_REM_FLOAT:
+ return op_rem_float();
+ case OP_ADD_DOUBLE:
+ return op_add_double();
+ case OP_SUB_DOUBLE:
+ return op_sub_double();
+ case OP_MUL_DOUBLE:
+ return op_mul_double();
+ case OP_DIV_DOUBLE:
+ return op_div_double();
+ case OP_REM_DOUBLE:
+ return op_rem_double();
+ case OP_ADD_INT_2ADDR:
+ return op_add_int_2addr();
+ case OP_SUB_INT_2ADDR:
+ return op_sub_int_2addr();
+ case OP_MUL_INT_2ADDR:
+ return op_mul_int_2addr();
+ case OP_DIV_INT_2ADDR:
+ return op_div_int_2addr();
+ case OP_REM_INT_2ADDR:
+ return op_rem_int_2addr();
+ case OP_AND_INT_2ADDR:
+ return op_and_int_2addr();
+ case OP_OR_INT_2ADDR:
+ return op_or_int_2addr();
+ case OP_XOR_INT_2ADDR:
+ return op_xor_int_2addr();
+ case OP_SHL_INT_2ADDR:
+ return op_shl_int_2addr();
+ case OP_SHR_INT_2ADDR:
+ return op_shr_int_2addr();
+ case OP_USHR_INT_2ADDR:
+ return op_ushr_int_2addr();
+ case OP_ADD_LONG_2ADDR:
+ return op_add_long_2addr();
+ case OP_SUB_LONG_2ADDR:
+ return op_sub_long_2addr();
+ case OP_MUL_LONG_2ADDR:
+ return op_mul_long_2addr();
+ case OP_DIV_LONG_2ADDR:
+ return op_div_long_2addr();
+ case OP_REM_LONG_2ADDR:
+ return op_rem_long_2addr();
+ case OP_AND_LONG_2ADDR:
+ return op_and_long_2addr();
+ case OP_OR_LONG_2ADDR:
+ return op_or_long_2addr();
+ case OP_XOR_LONG_2ADDR:
+ return op_xor_long_2addr();
+ case OP_SHL_LONG_2ADDR:
+ return op_shl_long_2addr();
+ case OP_SHR_LONG_2ADDR:
+ return op_shr_long_2addr();
+ case OP_USHR_LONG_2ADDR:
+ return op_ushr_long_2addr();
+ case OP_ADD_FLOAT_2ADDR:
+ return op_add_float_2addr();
+ case OP_SUB_FLOAT_2ADDR:
+ return op_sub_float_2addr();
+ case OP_MUL_FLOAT_2ADDR:
+ return op_mul_float_2addr();
+ case OP_DIV_FLOAT_2ADDR:
+ return op_div_float_2addr();
+ case OP_REM_FLOAT_2ADDR:
+ return op_rem_float_2addr();
+ case OP_ADD_DOUBLE_2ADDR:
+ return op_add_double_2addr();
+ case OP_SUB_DOUBLE_2ADDR:
+ return op_sub_double_2addr();
+ case OP_MUL_DOUBLE_2ADDR:
+ return op_mul_double_2addr();
+ case OP_DIV_DOUBLE_2ADDR:
+ return op_div_double_2addr();
+ case OP_REM_DOUBLE_2ADDR:
+ return op_rem_double_2addr();
+ case OP_ADD_INT_LIT16:
+ return op_add_int_lit16();
+ case OP_RSUB_INT:
+ return op_rsub_int();
+ case OP_MUL_INT_LIT16:
+ return op_mul_int_lit16();
+ case OP_DIV_INT_LIT16:
+ return op_div_int_lit16();
+ case OP_REM_INT_LIT16:
+ return op_rem_int_lit16();
+ case OP_AND_INT_LIT16:
+ return op_and_int_lit16();
+ case OP_OR_INT_LIT16:
+ return op_or_int_lit16();
+ case OP_XOR_INT_LIT16:
+ return op_xor_int_lit16();
+ case OP_ADD_INT_LIT8:
+ return op_add_int_lit8();
+ case OP_RSUB_INT_LIT8:
+ return op_rsub_int_lit8();
+ case OP_MUL_INT_LIT8:
+ return op_mul_int_lit8();
+ case OP_DIV_INT_LIT8:
+ return op_div_int_lit8();
+ case OP_REM_INT_LIT8:
+ return op_rem_int_lit8();
+ case OP_AND_INT_LIT8:
+ return op_and_int_lit8();
+ case OP_OR_INT_LIT8:
+ return op_or_int_lit8();
+ case OP_XOR_INT_LIT8:
+ return op_xor_int_lit8();
+ case OP_SHL_INT_LIT8:
+ return op_shl_int_lit8();
+ case OP_SHR_INT_LIT8:
+ return op_shr_int_lit8();
+ case OP_USHR_INT_LIT8:
+ return op_ushr_int_lit8();
+ case OP_EXECUTE_INLINE:
+ return op_execute_inline(false);
+ case OP_EXECUTE_INLINE_RANGE:
+ return op_execute_inline(true);
+ case OP_BREAKPOINT:
+ ALOGE("found bytecode OP_BREAKPOINT");
+ dvmAbort();
+ case OP_INVOKE_OBJECT_INIT_RANGE:
+ return op_invoke_object_init_range();
+ case OP_IGET_QUICK:
+ return op_iget_quick();
+ case OP_IGET_WIDE_QUICK:
+ return op_iget_wide_quick();
+ case OP_IGET_OBJECT_QUICK:
+ return op_iget_object_quick();
+ case OP_IPUT_QUICK:
+ return op_iput_quick();
+ case OP_IPUT_WIDE_QUICK:
+ return op_iput_wide_quick();
+ case OP_IPUT_OBJECT_QUICK:
+ return op_iput_object_quick();
+ case OP_INVOKE_VIRTUAL_QUICK:
+ return op_invoke_virtual_quick();
+ case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+ return op_invoke_virtual_quick_range();
+ case OP_INVOKE_SUPER_QUICK:
+ return op_invoke_super_quick();
+ case OP_INVOKE_SUPER_QUICK_RANGE:
+ return op_invoke_super_quick_range();
+ }
+
+ ALOGE("No JIT support for bytecode %x at offsetPC %x",
+ INST_INST(inst), offsetPC);
+ return -1;
+}
+int op_nop() {
+ rPC++;
+ return 0;
+}
diff --git a/vm/compiler/codegen/x86/Lower.h b/vm/compiler/codegen/x86/Lower.h
new file mode 100644
index 0000000..630ccb9
--- /dev/null
+++ b/vm/compiler/codegen/x86/Lower.h
@@ -0,0 +1,1240 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file lower.h
+ \brief A header file to define interface between lowering and register allocator
+*/
+
+#ifndef _DALVIK_LOWER
+#define _DALVIK_LOWER
+
+#define CODE_CACHE_PADDING 1024 //code space for a single bytecode
+// comment out for phase 1 porting
+#define PREDICTED_CHAINING
+#define JIT_CHAIN
+
+#define NUM_DEPENDENCIES 24 /* max number of dependencies from a LowOp */
+//compilaton flags used by NCG O1
+#define DUMP_EXCEPTION //to measure performance, required to have correct exception handling
+/*! multiple versions for hardcoded registers */
+#define HARDREG_OPT
+#define CFG_OPT
+/*! remove redundant move ops when accessing virtual registers */
+#define MOVE_OPT
+/*! remove redundant spill of virtual registers */
+#define SPILL_OPT
+#define XFER_OPT
+//#define DSE_OPT //no perf improvement for cme
+/*! use live range analysis to allocate registers */
+#define LIVERANGE_OPT
+/*! remove redundant null check */
+#define NULLCHECK_OPT
+//#define BOUNDCHECK_OPT
+/*! optimize the access to glue structure */
+#define GLUE_OPT
+#define CALL_FIX
+#define NATIVE_FIX
+#define INVOKE_FIX //optimization
+#define GETVR_FIX //optimization
+
+#include "Dalvik.h"
+#include "enc_wrapper.h"
+#include "AnalysisO1.h"
+#include "compiler/CompilerIR.h"
+
+//compilation flags for debugging
+//#define DEBUG_INFO
+//#define DEBUG_CALL_STACK
+//#define DEBUG_IGET_OBJ
+//#define DEBUG_NCG_CODE_SIZE
+//#define DEBUG_NCG
+//#define DEBUG_NCG_1
+//#define DEBUG_LOADING
+//#define USE_INTERPRETER
+//#define DEBUG_EACH_BYTECODE
+
+/*! registers for functions are hardcoded */
+#define HARDCODE_REG_CALL
+#define HARDCODE_REG_SHARE
+#define HARDCODE_REG_HELPER
+
+#define PhysicalReg_FP PhysicalReg_EDI
+#define PhysicalReg_Glue PhysicalReg_EBP
+
+//COPIED from interp/InterpDefs.h
+#define FETCH(_offset) (rPC[(_offset)])
+#define INST_INST(_inst) ((_inst) & 0xff)
+#define INST_A(_inst) (((_inst) >> 8) & 0x0f)
+#define INST_B(_inst) ((_inst) >> 12)
+#define INST_AA(_inst) ((_inst) >> 8)
+
+//#include "vm/mterp/common/asm-constants.h"
+#define offEBP_self 8
+#define offEBP_spill -56
+#define offThread_exception 68
+#define offClassObject_descriptor 24
+#define offArrayObject_length 8
+#ifdef PROFILE_FIELD_ACCESS
+#define offStaticField_value 24
+#define offInstField_byteOffset 24
+#else
+#define offStaticField_value 16
+#define offInstField_byteOffset 16
+#endif
+
+#ifdef EASY_GDB
+#define offStackSaveArea_prevFrame 4
+#define offStackSaveArea_savedPc 8
+#define offStackSaveArea_method 12
+#define offStackSaveArea_localRefTop 16 // -> StackSaveArea.xtra.locakRefCookie
+#define offStackSaveArea_returnAddr 20
+#define offStackSaveArea_isDebugInterpreted 24
+#define sizeofStackSaveArea 24
+#else
+#define offStackSaveArea_prevFrame 0
+#define offStackSaveArea_savedPc 4
+#define offStackSaveArea_method 8
+#define offStackSaveArea_localRefTop 12 // -> StackSaveArea.xtra.locakRefCookie
+#define offStackSaveArea_returnAddr 16
+#define offStackSaveArea_isDebugInterpreted 20
+#define sizeofStackSaveArea 20
+#endif
+
+#define offClassObject_status 44
+#define offClassObject_accessFlags 32
+#ifdef MTERP_NO_UNALIGN_64
+#define offArrayObject_contents 16
+#else
+#define offArrayObject_contents 12
+#endif
+
+#define offField_clazz 0
+#define offObject_clazz 0
+#define offClassObject_vtable 116
+#define offClassObject_pDvmDex 40
+#define offClassObject_super 72
+#define offClassObject_vtableCount 112
+#define offMethod_name 16
+#define offMethod_accessFlags 4
+#define offMethod_methodIndex 8
+#define offMethod_registersSize 10
+#define offMethod_outsSize 12
+#define offGlue_interpStackEnd 32
+#define offThread_inJitCodeCache 124
+#define offThread_jniLocal_nextEntry 168
+#define offMethod_insns 32
+#ifdef ENABLE_TRACING
+#define offMethod_insns_bytecode 44
+#define offMethod_insns_ncg 48
+#endif
+
+#define offGlue_pc 0
+#define offGlue_fp 4
+#define offGlue_retval 8
+
+#define offThread_curFrame 4
+#define offGlue_method 16
+#define offGlue_methodClassDex 20
+#define offGlue_self 24
+#define offGlue_pSelfSuspendCount 36
+#define offGlue_cardTable 40
+#define offGlue_pDebuggerActive 44
+#define offGlue_pActiveProfilers 48
+#define offGlue_entryPoint 52
+#define offGlue_icRechainCount 84
+#define offGlue_espEntry 88
+#define offGlue_spillRegion 92
+#define offDvmDex_pResStrings 8
+#define offDvmDex_pResClasses 12
+#define offDvmDex_pResMethods 16
+#define offDvmDex_pResFields 20
+#define offMethod_clazz 0
+
+// Definitions must be consistent with vm/mterp/x86/header.S
+#define FRAME_SIZE 124
+
+typedef enum ArgsDoneType {
+ ArgsDone_Normal = 0,
+ ArgsDone_Native,
+ ArgsDone_Full
+} ArgsDoneType;
+
+/*! An enum type
+ to list bytecodes for AGET, APUT
+*/
+typedef enum ArrayAccess {
+ AGET, AGET_WIDE, AGET_CHAR, AGET_SHORT, AGET_BOOLEAN, AGET_BYTE,
+ APUT, APUT_WIDE, APUT_CHAR, APUT_SHORT, APUT_BOOLEAN, APUT_BYTE
+} ArrayAccess;
+/*! An enum type
+ to list bytecodes for IGET, IPUT
+*/
+typedef enum InstanceAccess {
+ IGET, IGET_WIDE, IPUT, IPUT_WIDE
+} InstanceAccess;
+/*! An enum type
+ to list bytecodes for SGET, SPUT
+*/
+typedef enum StaticAccess {
+ SGET, SGET_WIDE, SPUT, SPUT_WIDE
+} StaticAccess;
+
+typedef enum JmpCall_type {
+ JmpCall_uncond = 1,
+ JmpCall_cond,
+ JmpCall_reg, //jump reg32
+ JmpCall_call
+} JmpCall_type;
+
+////////////////////////////////////////////////////////////////
+/* data structure for native codes */
+/* Due to space considation, a lowered op (LowOp) has two operands (LowOpnd), depending on
+ the type of the operand, LowOpndReg or LowOpndImm or LowOpndMem will follow */
+/*! type of an operand can be immediate, register or memory */
+typedef enum LowOpndType {
+ LowOpndType_Imm = 0,
+ LowOpndType_Reg,
+ LowOpndType_Mem,
+ LowOpndType_Label,
+ LowOpndType_NCG,
+ LowOpndType_Chain
+} LowOpndType;
+typedef enum LowOpndDefUse {
+ LowOpndDefUse_Def = 0,
+ LowOpndDefUse_Use,
+ LowOpndDefUse_UseDef
+} LowOpndDefUse;
+
+/*!
+\brief base data structure for an operand */
+typedef struct LowOpnd {
+ LowOpndType type;
+ OpndSize size;
+ LowOpndDefUse defuse;
+} LowOpnd;
+/*!
+\brief data structure for a register operand */
+typedef struct LowOpndReg {
+ LowOpndRegType regType;
+ int logicalReg;
+ int physicalReg;
+} LowOpndReg;
+/*!
+\brief data structure for an immediate operand */
+typedef struct LowOpndImm {
+ union {
+ s4 value;
+ unsigned char bytes[4];
+ };
+} LowOpndImm;
+
+typedef struct LowOpndNCG {
+ union {
+ s4 value;
+ unsigned char bytes[4];
+ };
+} LowOpndNCG;
+
+#define LABEL_SIZE 256
+typedef struct LowOpndLabel {
+ char label[LABEL_SIZE];
+ bool isLocal;
+} LowOpndLabel;
+
+/* get ready for optimizations at LIR
+ add MemoryAccessType & virtualRegNum to memory operands */
+typedef enum MemoryAccessType {
+ MemoryAccess_GLUE,
+ MemoryAccess_VR,
+ MemoryAccess_SPILL,
+ MemoryAccess_Unknown
+} MemoryAccessType;
+typedef enum UseDefEntryType {
+ UseDefType_Ctrl = 0,
+ UseDefType_Float,
+ UseDefType_MemVR,
+ UseDefType_MemSpill,
+ UseDefType_MemUnknown,
+ UseDefType_Reg
+} UseDefEntryType;
+typedef struct UseDefProducerEntry {
+ UseDefEntryType type;
+ int index; //enum PhysicalReg for "Reg" type
+ int producerSlot;
+} UseDefProducerEntry;
+#define MAX_USE_PER_ENTRY 50 /* at most 10 uses for each entry */
+typedef struct UseDefUserEntry {
+ UseDefEntryType type;
+ int index;
+ int useSlots[MAX_USE_PER_ENTRY];
+ int num_uses_per_entry;
+} UseDefUserEntry;
+
+/*!
+\brief data structure for a memory operand */
+typedef struct LowOpndMem {
+ LowOpndImm m_disp;
+ LowOpndImm m_scale;
+ LowOpndReg m_index;
+ LowOpndReg m_base;
+ bool hasScale;
+ MemoryAccessType mType;
+ int index;
+} LowOpndMem;
+
+typedef enum AtomOpCode {
+ ATOM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH = -15,
+ ATOM_NORMAL_ALU = -14,
+ ATOM_PSEUDO_ENTRY_BLOCK = -13,
+ ATOM_PSEUDO_EXIT_BLOCK = -12,
+ ATOM_PSEUDO_TARGET_LABEL = -11,
+ ATOM_PSEUDO_CHAINING_CELL_HOT = -10,
+ ATOM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED = -9,
+ ATOM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON = -8,
+ ATOM_PSEUDO_CHAINING_CELL_NORMAL = -7,
+ ATOM_PSEUDO_DALVIK_BYTECODE_BOUNDARY = -6,
+ ATOM_PSEUDO_ALIGN4 = -5,
+ ATOM_PSEUDO_PC_RECONSTRUCTION_CELL = -4,
+ ATOM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL = -3,
+ ATOM_PSEUDO_EH_BLOCK_LABEL = -2,
+ ATOM_PSEUDO_NORMAL_BLOCK_LABEL = -1,
+ ATOM_NORMAL,
+} AtomOpCode;
+
+typedef enum DependencyType {
+ Dependency_RAW,
+ Dependency_WAW,
+ Dependency_WAR,
+ Dependency_FLAG
+} DependencyType;
+typedef struct DependencyStruct {
+ DependencyType dType;
+ int nodeId;
+ int latency;
+} DependencyStruct;
+
+typedef struct LowOpBlock {
+ LIR generic;
+ Mnemonic opCode;
+ AtomOpCode opCode2;
+} LowOpBlock;
+
+/*!
+\brief data structure for a lowered operation */
+typedef struct LowOp {
+ LIR generic;
+ Mnemonic opCode;
+ AtomOpCode opCode2;
+ LowOpnd opnd1;
+ LowOpnd opnd2;
+ int numOperands;
+} LowOp;
+
+typedef struct LowOpLabel {
+ LowOp lop;
+ LowOpndLabel labelOpnd;
+}LowOpLabel;
+
+typedef struct LowOpNCG {
+ LowOp lop;
+ LowOpndNCG ncgOpnd;
+}LowOpNCG;
+
+typedef struct LowOpBlockLabel {
+ LowOpBlock lop;
+ LowOpndImm immOpnd;
+} LowOpBlockLabel;
+
+typedef struct LowOpImm {
+ LowOp lop;
+ LowOpndImm immOpnd;
+} LowOpImm;
+
+typedef struct LowOpMem {
+ LowOp lop;
+ LowOpndMem memOpnd;
+} LowOpMem;
+
+typedef struct LowOpReg {
+ LowOp lop;
+ LowOpndReg regOpnd;
+} LowOpReg;
+
+typedef struct LowOpImmImm {
+ LowOp lop;
+ LowOpndImm immOpnd1;
+ LowOpndImm immOpnd2;
+} LowOpImmImm;
+
+typedef struct LowOpImmReg {
+ LowOp lop;
+ LowOpndImm immOpnd1;
+ LowOpndReg regOpnd2;
+} LowOpImmReg;
+
+typedef struct LowOpImmMem {
+ LowOp lop;
+ LowOpndImm immOpnd1;
+ LowOpndMem memOpnd2;
+} LowOpImmMem;
+
+typedef struct LowOpRegImm {
+ LowOp lop;
+ LowOpndReg regOpnd1;
+ LowOpndImm immOpnd2;
+} LowOpRegImm;
+
+typedef struct LowOpRegReg {
+ LowOp lop;
+ LowOpndReg regOpnd1;
+ LowOpndReg regOpnd2;
+} LowOpRegReg;
+
+typedef struct LowOpRegMem {
+ LowOp lop;
+ LowOpndReg regOpnd1;
+ LowOpndMem memOpnd2;
+} LowOpRegMem;
+
+typedef struct LowOpMemImm {
+ LowOp lop;
+ LowOpndMem memOpnd1;
+ LowOpndImm immOpnd2;
+} LowOpMemImm;
+
+typedef struct LowOpMemReg {
+ LowOp lop;
+ LowOpndMem memOpnd1;
+ LowOpndReg regOpnd2;
+} LowOpMemReg;
+
+typedef struct LowOpMemMem {
+ LowOp lop;
+ LowOpndMem memOpnd1;
+ LowOpndMem memOpnd2;
+} LowOpMemMem;
+
+/*!
+\brief data structure for labels used when lowering a method
+
+four label maps are defined: globalMap globalShortMap globalWorklist globalShortWorklist
+globalMap: global labels where codePtr points to the label
+ freeLabelMap called in clearNCG
+globalWorklist: global labels where codePtr points to an instruciton using the label
+ standalone NCG -------
+ accessed by insertLabelWorklist & performLabelWorklist
+ code cache ------
+ inserted by performLabelWorklist(false),
+ handled & cleared by generateRelocation in NcgFile.c
+globalShortMap: local labels where codePtr points to the label
+ freeShortMap called after generation of one bytecode
+globalShortWorklist: local labels where codePtr points to an instruction using the label
+ accessed by insertShortWorklist & insertLabel
+definition of local label: life time of the label is within a bytecode or within a helper function
+extra label maps are used by code cache:
+ globalDataWorklist VMAPIWorklist
+*/
+typedef struct LabelMap {
+ char label[LABEL_SIZE];
+ char* codePtr; //code corresponding to the label or code that uses the label
+ struct LabelMap* nextItem;
+ OpndSize size;
+ uint addend;
+} LabelMap;
+/*!
+\brief data structure to handle forward jump (GOTO, IF)
+
+accessed by insertNCGWorklist & performNCGWorklist
+*/
+typedef struct NCGWorklist {
+ //when WITH_JIT, relativePC stores the target basic block id
+ s4 relativePC; //relative offset in bytecode
+ int offsetPC; //PC in bytecode
+ int offsetNCG; //PC in native code
+ char* codePtr; //code for native jump instruction
+ struct NCGWorklist* nextItem;
+ OpndSize size;
+}NCGWorklist;
+/*!
+\brief data structure to handle SWITCH & FILL_ARRAY_DATA
+
+two data worklist are defined: globalDataWorklist (used by code cache) & methodDataWorklist
+methodDataWorklist is accessed by insertDataWorklist & performDataWorklist
+*/
+typedef struct DataWorklist {
+ s4 relativePC; //relative offset in bytecode to access the data
+ int offsetPC; //PC in bytecode
+ int offsetNCG; //PC in native code
+ char* codePtr; //code for native instruction add_imm_reg imm, %edx
+ char* codePtr2;//code for native instruction add_reg_reg %eax, %edx for SWITCH
+ // add_imm_reg imm, %edx for FILL_ARRAY_DATA
+ struct DataWorklist* nextItem;
+}DataWorklist;
+#ifdef ENABLE_TRACING
+typedef struct MapWorklist {
+ u4 offsetPC;
+ u4 offsetNCG;
+ int isStartOfPC; //1 --> true 0 --> false
+ struct MapWorklist* nextItem;
+} MapWorklist;
+#endif
+
+#define BUFFER_SIZE 1024 //# of Low Ops buffered
+//the following three numbers are hardcoded, please CHECK
+#define BYTECODE_SIZE_PER_METHOD 81920
+#define NATIVE_SIZE_PER_DEX 19000000 //FIXME for core.jar: 16M --> 18M for O1
+#define NATIVE_SIZE_FOR_VM_STUBS 100000
+#define MAX_HANDLER_OFFSET 1024 //maximal number of handler offsets
+
+extern int LstrClassCastExceptionPtr, LstrInstantiationErrorPtr, LstrInternalError, LstrFilledNewArrayNotImpl;
+extern int LstrArithmeticException, LstrArrayIndexException, LstrArrayStoreException, LstrStringIndexOutOfBoundsException;
+extern int LstrDivideByZero, LstrNegativeArraySizeException, LstrNoSuchMethodError, LstrNullPointerException;
+extern int LdoubNeg, LvaluePosInfLong, LvalueNegInfLong, LvalueNanLong, LshiftMask, Lvalue64, L64bits, LintMax, LintMin;
+
+extern LabelMap* globalMap;
+extern LabelMap* globalShortMap;
+extern LabelMap* globalWorklist;
+extern LabelMap* globalShortWorklist;
+extern NCGWorklist* globalNCGWorklist;
+extern DataWorklist* methodDataWorklist;
+#ifdef ENABLE_TRACING
+extern MapWorklist* methodMapWorklist;
+#endif
+extern PhysicalReg scratchRegs[4];
+
+#define C_SCRATCH_1 scratchRegs[0]
+#define C_SCRATCH_2 scratchRegs[1]
+#define C_SCRATCH_3 scratchRegs[2] //scratch reg inside callee
+
+extern LowOp* ops[BUFFER_SIZE];
+extern bool isScratchPhysical;
+extern u2* rPC;
+extern u2 inst;
+extern int offsetPC;
+extern int offsetNCG;
+extern int mapFromBCtoNCG[BYTECODE_SIZE_PER_METHOD];
+extern char* streamStart;
+
+extern char* streamCode;
+
+extern char* streamMethodStart; //start of the method
+extern char* stream; //current stream pointer
+extern char* streamMisPred;
+extern int lowOpTimeStamp;
+extern Method* currentMethod;
+extern int currentExceptionBlockIdx;
+
+extern int globalMapNum;
+extern int globalWorklistNum;
+extern int globalDataWorklistNum;
+extern int globalPCWorklistNum;
+extern int chainingWorklistNum;
+extern int VMAPIWorklistNum;
+
+extern LabelMap* globalDataWorklist;
+extern LabelMap* globalPCWorklist;
+extern LabelMap* chainingWorklist;
+extern LabelMap* VMAPIWorklist;
+
+extern int ncgClassNum;
+extern int ncgMethodNum;
+
+extern LowOp* lirTable[200]; //Number of LIRs for all bytecodes do not exceed 200
+extern int num_lirs_in_table;
+
+bool existATryBlock(Method* method, int startPC, int endPC);
+// interface between register allocator & lowering
+extern int num_removed_nullCheck;
+
+int registerAlloc(int type, int reg, bool isPhysical, bool updateRef);
+int registerAllocMove(int reg, int type, bool isPhysical, int srcReg);
+int checkVirtualReg(int reg, LowOpndRegType type, int updateRef); //returns the physical register
+int updateRefCount(int reg, LowOpndRegType type);
+int updateRefCount2(int reg, int type, bool isPhysical);
+int spillVirtualReg(int vrNum, LowOpndRegType type, bool updateTable);
+int isVirtualRegConstant(int regNum, LowOpndRegType type, int* valuePtr, bool updateRef);
+int checkTempReg(int reg, int type, bool isPhysical, int vA);
+bool checkTempReg2(int reg, int type, bool isPhysical, int physicalRegForVR);
+int freeReg(bool spillGL);
+int nextVersionOfHardReg(PhysicalReg pReg, int refCount);
+int updateVirtualReg(int reg, LowOpndRegType type);
+void setVRNullCheck(int regNum, OpndSize size);
+bool isVRNullCheck(int regNum, OpndSize size);
+void setVRBoundCheck(int vr_array, int vr_index);
+bool isVRBoundCheck(int vr_array, int vr_index);
+int requestVRFreeDelay(int regNum, u4 reason);
+void cancelVRFreeDelayRequest(int regNum, u4 reason);
+bool getVRFreeDelayRequested(int regNum);
+bool isGlueHandled(int glue_reg);
+void resetGlue(int glue_reg);
+void updateGlue(int reg, bool isPhysical, int glue_reg);
+int updateVRAtUse(int reg, LowOpndRegType pType, int regAll);
+int touchEcx();
+int touchEax();
+int touchEdx();
+int beforeCall(const char* target);
+int afterCall(const char* target);
+void startBranch();
+void endBranch();
+void rememberState(int);
+void goToState(int);
+void transferToState(int);
+void globalVREndOfBB(const Method*);
+void constVREndOfBB();
+void startNativeCode(int num, int type);
+void endNativeCode();
+void donotSpillReg(int physicalReg);
+void doSpillReg(int physicalReg);
+
+#define XMM_1 PhysicalReg_XMM0
+#define XMM_2 PhysicalReg_XMM1
+#define XMM_3 PhysicalReg_XMM2
+#define XMM_4 PhysicalReg_XMM3
+
+/////////////////////////////////////////////////////////////////////////////////
+//LR[reg] = disp + PR[base_reg] or disp + LR[base_reg]
+void load_effective_addr(int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical);
+void load_effective_addr_scale(int base_reg, bool isBasePhysical,
+ int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical);
+void load_fpu_cw(int disp, int base_reg, bool isBasePhysical);
+void store_fpu_cw(bool checkException, int disp, int base_reg, bool isBasePhysical);
+void convert_integer(OpndSize srcSize, OpndSize dstSize);
+void load_fp_stack(LowOp* op, OpndSize size, int disp, int base_reg, bool isBasePhysical);
+void load_int_fp_stack(OpndSize size, int disp, int base_reg, bool isBasePhysical);
+void load_int_fp_stack_imm(OpndSize size, int imm);
+void store_fp_stack(LowOp* op, bool pop, OpndSize size, int disp, int base_reg, bool isBasePhysical);
+void store_int_fp_stack(LowOp* op, bool pop, OpndSize size, int disp, int base_reg, bool isBasePhysical);
+
+void load_fp_stack_VR(OpndSize size, int vA);
+void load_int_fp_stack_VR(OpndSize size, int vA);
+void store_fp_stack_VR(bool pop, OpndSize size, int vA);
+void store_int_fp_stack_VR(bool pop, OpndSize size, int vA);
+void compare_VR_ss_reg(int vA, int reg, bool isPhysical);
+void compare_VR_sd_reg(int vA, int reg, bool isPhysical);
+void fpu_VR(ALU_Opcode opc, OpndSize size, int vA);
+void compare_reg_mem(LowOp* op, OpndSize size, int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical);
+void compare_mem_reg(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical);
+void compare_VR_reg(OpndSize size,
+ int vA,
+ int reg, bool isPhysical);
+void compare_imm_reg(OpndSize size, int imm,
+ int reg, bool isPhysical);
+void compare_imm_mem(OpndSize size, int imm,
+ int disp, int base_reg, bool isBasePhysical);
+void compare_imm_VR(OpndSize size, int imm,
+ int vA);
+void compare_reg_reg(int reg1, bool isPhysical1,
+ int reg2, bool isPhysical2);
+void compare_reg_reg_16(int reg1, bool isPhysical1,
+ int reg2, bool isPhysical2);
+void compare_ss_mem_reg(LowOp* op, int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical);
+void compare_ss_reg_with_reg(LowOp* op, int reg1, bool isPhysical1,
+ int reg2, bool isPhysical2);
+void compare_sd_mem_with_reg(LowOp* op, int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical);
+void compare_sd_reg_with_reg(LowOp* op, int reg1, bool isPhysical1,
+ int reg2, bool isPhysical2);
+void compare_fp_stack(bool pop, int reg, bool isDouble);
+void test_imm_reg(OpndSize size, int imm, int reg, bool isPhysical);
+void test_imm_mem(OpndSize size, int imm, int disp, int reg, bool isPhysical);
+
+void conditional_move_reg_to_reg(OpndSize size, ConditionCode cc, int reg1, bool isPhysical1, int reg, bool isPhysical);
+void move_ss_mem_to_reg(LowOp* op, int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical);
+void move_ss_reg_to_mem(LowOp* op, int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical);
+LowOpRegMem* move_ss_mem_to_reg_noalloc(int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg, bool isPhysical);
+LowOpMemReg* move_ss_reg_to_mem_noalloc(int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex);
+void move_sd_mem_to_reg(int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical);
+void move_sd_reg_to_mem(LowOp* op, int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical);
+
+void conditional_jump(ConditionCode cc, const char* target, bool isShortTerm);
+void unconditional_jump(const char* target, bool isShortTerm);
+void conditional_jump_int(ConditionCode cc, int target, OpndSize size);
+void unconditional_jump_int(int target, OpndSize size);
+void unconditional_jump_reg(int reg, bool isPhysical);
+void call(const char* target);
+void call_reg(int reg, bool isPhysical);
+void call_reg_noalloc(int reg, bool isPhysical);
+void call_mem(int disp, int reg, bool isPhysical);
+void x86_return();
+
+void alu_unary_reg(OpndSize size, ALU_Opcode opc, int reg, bool isPhysical);
+void alu_unary_mem(LowOp* op, OpndSize size, ALU_Opcode opc, int disp, int base_reg, bool isBasePhysical);
+
+void alu_binary_imm_mem(OpndSize size, ALU_Opcode opc,
+ int imm, int disp, int base_reg, bool isBasePhysical);
+void alu_binary_imm_reg(OpndSize size, ALU_Opcode opc, int imm, int reg, bool isPhysical);
+void alu_binary_mem_reg(OpndSize size, ALU_Opcode opc,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical);
+void alu_binary_VR_reg(OpndSize size, ALU_Opcode opc, int vA, int reg, bool isPhysical);
+void alu_sd_binary_VR_reg(ALU_Opcode opc, int vA, int reg, bool isPhysical, bool isSD);
+void alu_binary_reg_reg(OpndSize size, ALU_Opcode opc,
+ int reg1, bool isPhysical1,
+ int reg2, bool isPhysical2);
+void alu_binary_reg_mem(OpndSize size, ALU_Opcode opc,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical);
+
+void fpu_mem(LowOp* op, ALU_Opcode opc, OpndSize size, int disp, int base_reg, bool isBasePhysical);
+void alu_ss_binary_reg_reg(ALU_Opcode opc, int reg, bool isPhysical,
+ int reg2, bool isPhysical2);
+void alu_sd_binary_reg_reg(ALU_Opcode opc, int reg, bool isPhysical,
+ int reg2, bool isPhysical2);
+
+void push_mem_to_stack(OpndSize size, int disp, int base_reg, bool isBasePhysical);
+void push_reg_to_stack(OpndSize size, int reg, bool isPhysical);
+
+//returns the pointer to end of the native code
+void move_reg_to_mem(OpndSize size,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical);
+LowOpRegMem* move_mem_to_reg(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical);
+void movez_mem_to_reg(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical);
+void movez_reg_to_reg(OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2);
+void moves_mem_to_reg(LowOp* op, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical);
+void movez_mem_disp_scale_to_reg(OpndSize size,
+ int base_reg, bool isBasePhysical,
+ int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical);
+void moves_mem_disp_scale_to_reg(OpndSize size,
+ int base_reg, bool isBasePhysical,
+ int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical);
+void move_reg_to_reg(OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2);
+void move_reg_to_reg_noalloc(OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2);
+void move_mem_scale_to_reg(OpndSize size,
+ int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical);
+void move_mem_disp_scale_to_reg(OpndSize size,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical);
+void move_reg_to_mem_scale(OpndSize size,
+ int reg, bool isPhysical,
+ int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale);
+void move_reg_to_mem_disp_scale(OpndSize size,
+ int reg, bool isPhysical,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale);
+void move_imm_to_mem(OpndSize size, int imm,
+ int disp, int base_reg, bool isBasePhysical);
+void set_VR_to_imm(u2 vA, OpndSize size, int imm);
+void set_VR_to_imm_noalloc(u2 vA, OpndSize size, int imm);
+void set_VR_to_imm_noupdateref(LowOp* op, u2 vA, OpndSize size, int imm);
+void move_imm_to_reg(OpndSize size, int imm, int reg, bool isPhysical);
+void move_imm_to_reg_noalloc(OpndSize size, int imm, int reg, bool isPhysical);
+
+//LR[reg] = VR[vB]
+//or
+//PR[reg] = VR[vB]
+void get_virtual_reg(u2 vB, OpndSize size, int reg, bool isPhysical);
+void get_virtual_reg_noalloc(u2 vB, OpndSize size, int reg, bool isPhysical);
+//VR[v] = LR[reg]
+//or
+//VR[v] = PR[reg]
+void set_virtual_reg(u2 vA, OpndSize size, int reg, bool isPhysical);
+void set_virtual_reg_noalloc(u2 vA, OpndSize size, int reg, bool isPhysical);
+void get_VR_ss(int vB, int reg, bool isPhysical);
+void set_VR_ss(int vA, int reg, bool isPhysical);
+void get_VR_sd(int vB, int reg, bool isPhysical);
+void set_VR_sd(int vA, int reg, bool isPhysical);
+
+int spill_reg(int reg, bool isPhysical);
+int unspill_reg(int reg, bool isPhysical);
+
+void move_reg_to_mem_noalloc(OpndSize size,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex);
+LowOpRegMem* move_mem_to_reg_noalloc(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg, bool isPhysical);
+
+//////////////////////////////////////////////////////////////
+int insertLabel(const char* label, bool checkDup);
+int export_pc();
+int simpleNullCheck(int reg, bool isPhysical, int vr);
+int nullCheck(int reg, bool isPhysical, int exceptionNum, int vr);
+int handlePotentialException(
+ ConditionCode code_excep, ConditionCode code_okay,
+ int exceptionNum, const char* errName);
+int get_currentpc(int reg, bool isPhysical);
+int get_self_pointer(int reg, bool isPhysical);
+int get_res_strings(int reg, bool isPhysical);
+int get_res_classes(int reg, bool isPhysical);
+int get_res_fields(int reg, bool isPhysical);
+int get_res_methods(int reg, bool isPhysical);
+int get_glue_method_class(int reg, bool isPhysical);
+int get_glue_method(int reg, bool isPhysical);
+int set_glue_method(int reg, bool isPhysical);
+int get_glue_dvmdex(int reg, bool isPhysical);
+int set_glue_dvmdex(int reg, bool isPhysical);
+int get_suspendCount(int reg, bool isPhysical);
+int get_return_value(OpndSize size, int reg, bool isPhysical);
+int set_return_value(OpndSize size, int reg, bool isPhysical);
+int clear_exception();
+int get_exception(int reg, bool isPhysical);
+int set_exception(int reg, bool isPhysical);
+int save_pc_fp_to_glue();
+int savearea_from_fp(int reg, bool isPhysical);
+
+int call_moddi3();
+int call_divdi3();
+int call_fmod();
+int call_fmodf();
+int call_dvmFindCatchBlock();
+int call_dvmThrowVerificationError();
+int call_dvmAllocObject();
+int call_dvmAllocArrayByClass();
+int call_dvmResolveMethod();
+int call_dvmResolveClass();
+int call_dvmInstanceofNonTrivial();
+int call_dvmThrow();
+int call_dvmThrowWithMessage();
+int call_dvmCheckSuspendPending();
+int call_dvmLockObject();
+int call_dvmUnlockObject();
+int call_dvmInitClass();
+int call_dvmAllocPrimitiveArray();
+int call_dvmInterpHandleFillArrayData();
+int call_dvmNcgHandlePackedSwitch();
+int call_dvmNcgHandleSparseSwitch();
+int call_dvmJitHandlePackedSwitch();
+int call_dvmJitHandleSparseSwitch();
+int call_dvmJitToInterpTraceSelectNoChain();
+int call_dvmJitToPatchPredictedChain();
+int call_dvmJitToInterpNormal();
+int call_dvmJitToInterpTraceSelect();
+int call_dvmQuasiAtomicSwap64();
+int call_dvmQuasiAtomicRead64();
+int call_dvmCanPutArrayElement();
+int call_dvmFindInterfaceMethodInCache();
+int call_dvmHandleStackOverflow();
+int call_dvmResolveString();
+int call_dvmResolveInstField();
+int call_dvmResolveStaticField();
+
+//labels and branches
+//shared branch to resolve class: 2 specialized versions
+//OPTION 1: call & ret
+//OPTION 2: store jump back label in a fixed register or memory
+//jump to .class_resolve, then jump back
+//OPTION 3: share translator code
+/* global variables: ncg_rPC */
+int resolve_class(
+ int startLR/*logical register index*/, bool isPhysical, int tmp/*const pool index*/,
+ int thirdArg);
+/* EXPORT_PC; movl exceptionPtr, -8(%esp); movl descriptor, -4(%esp); lea; call; lea; jmp */
+int throw_exception_message(int exceptionPtr, int obj_reg, bool isPhysical,
+ int startLR/*logical register index*/, bool startPhysical);
+/* EXPORT_PC; movl exceptionPtr, -8(%esp); movl imm, -4(%esp); lea; call; lea; jmp */
+int throw_exception(int exceptionPtr, int imm,
+ int startLR/*logical register index*/, bool startPhysical);
+
+void freeShortMap();
+int insertDataWorklist(s4 relativePC, char* codePtr1);
+#ifdef ENABLE_TRACING
+int insertMapWorklist(s4 BCOffset, s4 NCGOffset, int isStartOfPC);
+#endif
+int performNCGWorklist();
+int performDataWorklist();
+void performLabelWorklist();
+void performMethodLabelWorklist();
+void freeLabelMap();
+void performSharedWorklist();
+void performChainingWorklist();
+void freeNCGWorklist();
+void freeDataWorklist();
+void freeLabelWorklist();
+void freeChainingWorklist();
+
+int common_invokeArgsDone(ArgsDoneType form, bool isJitFull);
+int common_backwardBranch();
+int common_exceptionThrown();
+int common_errNullObject();
+int common_errArrayIndex();
+int common_errArrayStore();
+int common_errNegArraySize();
+int common_errNoSuchMethod();
+int common_errDivideByZero();
+int common_periodicChecks_entry();
+int common_periodicChecks4();
+int common_gotoBail();
+int common_gotoBail_0();
+int common_StringIndexOutOfBounds();
+void goto_invokeArgsDone();
+
+//lower a bytecode
+int lowerByteCode(const Method* method);
+
+int op_nop();
+int op_move();
+int op_move_from16();
+int op_move_16();
+int op_move_wide();
+int op_move_wide_from16();
+int op_move_wide_16();
+int op_move_result();
+int op_move_result_wide();
+int op_move_exception();
+
+int op_return_void();
+int op_return();
+int op_return_wide();
+int op_const_4();
+int op_const_16();
+int op_const();
+int op_const_high16();
+int op_const_wide_16();
+int op_const_wide_32();
+int op_const_wide();
+int op_const_wide_high16();
+int op_const_string();
+int op_const_string_jumbo();
+int op_const_class();
+int op_monitor_enter();
+int op_monitor_exit();
+int op_check_cast();
+int op_instance_of();
+
+int op_array_length();
+int op_new_instance();
+int op_new_array();
+int op_filled_new_array();
+int op_filled_new_array_range();
+int op_fill_array_data();
+int op_throw();
+int op_throw_verification_error();
+int op_goto();
+int op_goto_16();
+int op_goto_32();
+int op_packed_switch();
+int op_sparse_switch();
+int op_if_ge();
+int op_aget();
+int op_aget_wide();
+int op_aget_object();
+int op_aget_boolean();
+int op_aget_byte();
+int op_aget_char();
+int op_aget_short();
+int op_aput();
+int op_aput_wide();
+int op_aput_object();
+int op_aput_boolean();
+int op_aput_byte();
+int op_aput_char();
+int op_aput_short();
+int op_iget();
+int op_iget_wide(bool isVolatile);
+int op_iget_object();
+int op_iget_boolean();
+int op_iget_byte();
+int op_iget_char();
+int op_iget_short();
+int op_iput();
+int op_iput_wide(bool isVolatile);
+int op_iput_object();
+int op_iput_boolean();
+int op_iput_byte();
+int op_iput_char();
+int op_iput_short();
+int op_sget();
+int op_sget_wide(bool isVolatile);
+int op_sget_object();
+int op_sget_boolean();
+int op_sget_byte();
+int op_sget_char();
+int op_sget_short();
+int op_sput(bool isObj);
+int op_sput_wide(bool isVolatile);
+int op_sput_object();
+int op_sput_boolean();
+int op_sput_byte();
+int op_sput_char();
+int op_sput_short();
+int op_invoke_virtual();
+int op_invoke_super();
+int op_invoke_direct();
+int op_invoke_static();
+int op_invoke_interface();
+int op_invoke_virtual_range();
+int op_invoke_super_range();
+int op_invoke_direct_range();
+int op_invoke_static_range();
+int op_invoke_interface_range();
+int op_int_to_long();
+int op_add_long_2addr();
+int op_add_int_lit8();
+int op_cmpl_float();
+int op_cmpg_float();
+int op_cmpl_double();
+int op_cmpg_double();
+int op_cmp_long();
+int op_if_eq();
+int op_if_ne();
+int op_if_lt();
+int op_if_gt();
+int op_if_le();
+int op_if_eqz();
+int op_if_nez();
+int op_if_ltz();
+int op_if_gez();
+int op_if_gtz();
+int op_if_lez();
+int op_neg_int();
+int op_not_int();
+int op_neg_long();
+int op_not_long();
+int op_neg_float();
+int op_neg_double();
+int op_int_to_float();
+int op_int_to_double();
+int op_long_to_int();
+int op_long_to_float();
+int op_long_to_double();
+int op_float_to_int();
+int op_float_to_long();
+int op_float_to_double();
+int op_double_to_int();
+int op_double_to_long();
+int op_double_to_float();
+int op_int_to_byte();
+int op_int_to_char();
+int op_int_to_short();
+int op_add_int();
+int op_sub_int();
+int op_mul_int();
+int op_div_int();
+int op_rem_int();
+int op_and_int();
+int op_or_int();
+int op_xor_int();
+int op_shl_int();
+int op_shr_int();
+int op_ushr_int();
+int op_add_long();
+int op_sub_long();
+int op_mul_long();
+int op_div_long();
+int op_rem_long();
+int op_and_long();
+int op_or_long();
+int op_xor_long();
+int op_shl_long();
+int op_shr_long();
+int op_ushr_long();
+int op_add_float();
+int op_sub_float();
+int op_mul_float();
+int op_div_float();
+int op_rem_float();
+int op_add_double();
+int op_sub_double();
+int op_mul_double();
+int op_div_double();
+int op_rem_double();
+int op_add_int_2addr();
+int op_sub_int_2addr();
+int op_mul_int_2addr();
+int op_div_int_2addr();
+int op_rem_int_2addr();
+int op_and_int_2addr();
+int op_or_int_2addr();
+int op_xor_int_2addr();
+int op_shl_int_2addr();
+int op_shr_int_2addr();
+int op_ushr_int_2addr();
+int op_sub_long_2addr();
+int op_mul_long_2addr();
+int op_div_long_2addr();
+int op_rem_long_2addr();
+int op_and_long_2addr();
+int op_or_long_2addr();
+int op_xor_long_2addr();
+int op_shl_long_2addr();
+int op_shr_long_2addr();
+int op_ushr_long_2addr();
+int op_add_float_2addr();
+int op_sub_float_2addr();
+int op_mul_float_2addr();
+int op_div_float_2addr();
+int op_rem_float_2addr();
+int op_add_double_2addr();
+int op_sub_double_2addr();
+int op_mul_double_2addr();
+int op_div_double_2addr();
+int op_rem_double_2addr();
+int op_add_int_lit16();
+int op_rsub_int();
+int op_mul_int_lit16();
+int op_div_int_lit16();
+int op_rem_int_lit16();
+int op_and_int_lit16();
+int op_or_int_lit16();
+int op_xor_int_lit16();
+int op_rsub_int_lit8();
+int op_mul_int_lit8();
+int op_div_int_lit8();
+int op_rem_int_lit8();
+int op_and_int_lit8();
+int op_or_int_lit8();
+int op_xor_int_lit8();
+int op_shl_int_lit8();
+int op_shr_int_lit8();
+int op_ushr_int_lit8();
+int op_execute_inline(bool isRange);
+int op_invoke_object_init_range();
+int op_iget_quick();
+int op_iget_wide_quick();
+int op_iget_object_quick();
+int op_iput_quick();
+int op_iput_wide_quick();
+int op_iput_object_quick();
+int op_invoke_virtual_quick();
+int op_invoke_virtual_quick_range();
+int op_invoke_super_quick();
+int op_invoke_super_quick_range();
+
+///////////////////////////////////////////////
+void set_reg_opnd(LowOpndReg* op_reg, int reg, bool isPhysical, LowOpndRegType type);
+void set_mem_opnd(LowOpndMem* mem, int disp, int base, bool isPhysical);
+void set_mem_opnd_scale(LowOpndMem* mem, int base, bool isPhysical, int disp, int index, bool indexPhysical, int scale);
+LowOpImm* dump_imm(Mnemonic m, OpndSize size,
+ int imm);
+LowOpNCG* dump_ncg(Mnemonic m, OpndSize size, int imm);
+LowOpImm* dump_imm_with_codeaddr(Mnemonic m, OpndSize size,
+ int imm, char* codePtr);
+LowOpImm* dump_special(AtomOpCode cc, int imm);
+LowOpMem* dump_mem(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical);
+LowOpReg* dump_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int reg, bool isPhysical, LowOpndRegType type);
+LowOpReg* dump_reg_noalloc(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical, LowOpndRegType type);
+LowOpMemImm* dump_imm_mem_noalloc(Mnemonic m, OpndSize size,
+ int imm,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex);
+LowOpRegReg* dump_reg_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2, LowOpndRegType type);
+LowOpRegReg* dump_movez_reg_reg(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2);
+LowOpRegMem* dump_mem_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg, bool isPhysical, LowOpndRegType type);
+LowOpRegMem* dump_mem_reg_noalloc(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg, bool isPhysical, LowOpndRegType type);
+LowOpRegMem* dump_mem_scale_reg(Mnemonic m, OpndSize size,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical, LowOpndRegType type);
+LowOpMemReg* dump_reg_mem_scale(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ LowOpndRegType type);
+LowOpMemReg* dump_reg_mem(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex, LowOpndRegType type);
+LowOpMemReg* dump_reg_mem_noalloc(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex, LowOpndRegType type);
+LowOpRegImm* dump_imm_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int imm, int reg, bool isPhysical, LowOpndRegType type, bool chaining);
+LowOpMemImm* dump_imm_mem(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int imm,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex, bool chaining);
+LowOpMemReg* dump_fp_mem(Mnemonic m, OpndSize size, int reg,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex);
+LowOpRegMem* dump_mem_fp(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg);
+LowOpLabel* dump_label(Mnemonic m, OpndSize size, int imm,
+ const char* label, bool isLocal);
+
+unsigned getJmpCallInstSize(OpndSize size, JmpCall_type type);
+bool lowerByteCodeJit(const Method* method, const u2* codePtr, MIR* mir);
+void startOfBasicBlock(struct BasicBlock* bb);
+extern LowOpBlockLabel* traceLabelList;
+extern struct BasicBlock* traceCurrentBB;
+extern struct MIR* traceCurrentMIR;
+void startOfTrace(const Method* method, LowOpBlockLabel* labelList, int, CompilationUnit*);
+void endOfTrace(bool freeOnly);
+LowOp* jumpToBasicBlock(char* instAddr, int targetId);
+LowOp* condJumpToBasicBlock(char* instAddr, ConditionCode cc, int targetId);
+bool jumpToException(const char* target);
+int codeGenBasicBlockJit(const Method* method, BasicBlock* bb);
+void endOfBasicBlock(struct BasicBlock* bb);
+void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir);
+int insertChainingWorklist(int bbId, char * codeStart);
+void startOfTraceO1(const Method* method, LowOpBlockLabel* labelList, int exceptionBlockId, CompilationUnit *cUnit);
+void endOfTraceO1();
+int isPowerOfTwo(int imm);
+void move_chain_to_mem(OpndSize size, int imm,
+ int disp, int base_reg, bool isBasePhysical);
+void move_chain_to_reg(OpndSize size, int imm, int reg, bool isPhysical);
+
+void dumpImmToMem(int vrNum, OpndSize size, int value);
+bool isInMemory(int regNum, OpndSize size);
+int touchEbx();
+int boundCheck(int vr_array, int reg_array, bool isPhysical_array,
+ int vr_index, int reg_index, bool isPhysical_index,
+ int exceptionNum);
+int getRelativeOffset(const char* target, bool isShortTerm, JmpCall_type type, bool* unknown,
+ OpndSize* immSize);
+int getRelativeNCG(s4 tmp, JmpCall_type type, bool* unknown, OpndSize* size);
+void freeAtomMem();
+OpndSize estOpndSizeFromImm(int target);
+
+void preprocessingBB(BasicBlock* bb);
+void preprocessingTrace();
+void dump_nop(int size);
+#endif
diff --git a/vm/compiler/codegen/x86/LowerAlu.cpp b/vm/compiler/codegen/x86/LowerAlu.cpp
new file mode 100644
index 0000000..2231bac
--- /dev/null
+++ b/vm/compiler/codegen/x86/LowerAlu.cpp
@@ -0,0 +1,1962 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file LowerAlu.cpp
+ \brief This file lowers ALU bytecodes.
+*/
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "Lower.h"
+#include "NcgAot.h"
+#include "enc_wrapper.h"
+
+/////////////////////////////////////////////
+#define P_GPR_1 PhysicalReg_EBX
+//! lower bytecode NEG_INT
+
+//!
+int op_neg_int() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ alu_unary_reg(OpndSize_32, neg_opc, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode NOT_INT
+
+//!
+int op_not_int() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ alu_unary_reg(OpndSize_32, not_opc, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 1;
+ return 0;
+}
+#undef P_GPR_1
+//! lower bytecode NEG_LONG
+
+//! This implementation uses XMM registers
+int op_neg_long() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_64, 1, false);
+ alu_binary_reg_reg(OpndSize_64, xor_opc, 2, false, 2, false);
+ alu_binary_reg_reg(OpndSize_64, sub_opc, 1, false, 2, false);
+ set_virtual_reg(vA, OpndSize_64, 2, false);
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode NOT_LONG
+
+//! This implementation uses XMM registers
+int op_not_long() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_64, 1, false);
+ load_global_data_API("64bits", OpndSize_64, 2, false);
+ alu_binary_reg_reg(OpndSize_64, andn_opc, 2, false, 1, false);
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ rPC += 1;
+ return 0;
+}
+#define P_GPR_1 PhysicalReg_EBX
+//! lower bytecode NEG_FLOAT
+
+//! This implementation uses GPR
+int op_neg_float() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ alu_binary_imm_reg(OpndSize_32, add_opc, 0x80000000, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 1;
+ return 0;
+}
+#undef P_GPR_1
+
+//! lower bytecode NEG_DOUBLE
+
+//! This implementation uses XMM registers
+int op_neg_double() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_64, 1, false);
+ load_global_data_API("doubNeg", OpndSize_64, 2, false);
+ alu_binary_reg_reg(OpndSize_64, xor_opc, 1, false, 2, false);
+ set_virtual_reg(vA, OpndSize_64, 2, false);
+ rPC += 1;
+ return 0;
+}
+
+//! lower bytecode INT_TO_LONG
+
+//! It uses native instruction cdq
+int op_int_to_long() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_32, PhysicalReg_EAX, true);
+ convert_integer(OpndSize_32, OpndSize_64);
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
+ set_virtual_reg(vA+1, OpndSize_32, PhysicalReg_EDX, true);
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode INT_TO_FLOAT
+
+//! This implementation uses FP stack
+int op_int_to_float() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ load_int_fp_stack_VR(OpndSize_32, vB); //fildl
+ store_fp_stack_VR(true, OpndSize_32, vA); //fstps
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode INT_TO_DOUBLE
+
+//! This implementation uses FP stack
+int op_int_to_double() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ load_int_fp_stack_VR(OpndSize_32, vB); //fildl
+ store_fp_stack_VR(true, OpndSize_64, vA); //fstpl
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode LONG_TO_FLOAT
+
+//! This implementation uses FP stack
+int op_long_to_float() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ load_int_fp_stack_VR(OpndSize_64, vB); //fildll
+ store_fp_stack_VR(true, OpndSize_32, vA); //fstps
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode LONG_TO_DOUBLE
+
+//! This implementation uses FP stack
+int op_long_to_double() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ load_int_fp_stack_VR(OpndSize_64, vB); //fildll
+ store_fp_stack_VR(true, OpndSize_64, vA); //fstpl
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode FLOAT_TO_DOUBLE
+
+//! This implementation uses FP stack
+int op_float_to_double() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ load_fp_stack_VR(OpndSize_32, vB); //flds
+ store_fp_stack_VR(true, OpndSize_64, vA); //fstpl
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode DOUBLE_TO_FLOAT
+
+//! This implementation uses FP stack
+int op_double_to_float() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ load_fp_stack_VR(OpndSize_64, vB); //fldl
+ store_fp_stack_VR(true, OpndSize_32, vA); //fstps
+ rPC += 1;
+ return 0;
+}
+#define P_GPR_1 PhysicalReg_EBX
+//! lower bytecode LONG_TO_INT
+
+//! This implementation uses GPR
+int op_long_to_int() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 1;
+ return 0;
+}
+#undef P_GPR_1
+
+//! common code to convert a float or double to integer
+
+//! It uses FP stack
+int common_fp_to_int(bool isDouble, u2 vA, u2 vB) {
+ if(isDouble) {
+ load_fp_stack_VR(OpndSize_64, vB); //fldl
+ }
+ else {
+ load_fp_stack_VR(OpndSize_32, vB); //flds
+ }
+
+ load_fp_stack_global_data_API("intMax", OpndSize_32);
+ load_fp_stack_global_data_API("intMin", OpndSize_32);
+
+ //ST(0) ST(1) ST(2) --> LintMin LintMax value
+ compare_fp_stack(true, 2, false/*isDouble*/); //ST(2)
+ //ST(0) ST(1) --> LintMax value
+ conditional_jump(Condition_AE, ".float_to_int_negInf", true);
+ rememberState(1);
+ compare_fp_stack(true, 1, false/*isDouble*/); //ST(1)
+ //ST(0) --> value
+ rememberState(2);
+ conditional_jump(Condition_C, ".float_to_int_nanInf", true);
+ //fnstcw, orw, fldcw, xorw
+ load_effective_addr(-2, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ store_fpu_cw(false/*checkException*/, 0, PhysicalReg_ESP, true);
+ alu_binary_imm_mem(OpndSize_16, or_opc, 0xc00, 0, PhysicalReg_ESP, true);
+ load_fpu_cw(0, PhysicalReg_ESP, true);
+ alu_binary_imm_mem(OpndSize_16, xor_opc, 0xc00, 0, PhysicalReg_ESP, true);
+ store_int_fp_stack_VR(true/*pop*/, OpndSize_32, vA); //fistpl
+ //fldcw
+ load_fpu_cw(0, PhysicalReg_ESP, true);
+ load_effective_addr(2, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ rememberState(3);
+ unconditional_jump(".float_to_int_okay", true);
+ insertLabel(".float_to_int_nanInf", true);
+ conditional_jump(Condition_NP, ".float_to_int_posInf", true);
+ //fstps CHECK
+ goToState(2);
+ store_fp_stack_VR(true, OpndSize_32, vA);
+ set_VR_to_imm(vA, OpndSize_32, 0);
+ transferToState(3);
+ unconditional_jump(".float_to_int_okay", true);
+ insertLabel(".float_to_int_posInf", true);
+ //fstps CHECK
+ goToState(2);
+ store_fp_stack_VR(true, OpndSize_32, vA);
+ set_VR_to_imm(vA, OpndSize_32, 0x7fffffff);
+ transferToState(3);
+ unconditional_jump(".float_to_int_okay", true);
+ insertLabel(".float_to_int_negInf", true);
+ goToState(1);
+ //fstps CHECK
+ store_fp_stack_VR(true, OpndSize_32, vA);
+ store_fp_stack_VR(true, OpndSize_32, vA);
+ set_VR_to_imm(vA, OpndSize_32, 0x80000000);
+ transferToState(3);
+ insertLabel(".float_to_int_okay", true);
+ return 0;
+}
+//! lower bytecode FLOAT_TO_INT by calling common_fp_to_int
+
+//!
+int op_float_to_int() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ int retval = common_fp_to_int(false, vA, vB);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode DOUBLE_TO_INT by calling common_fp_to_int
+
+//!
+int op_double_to_int() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ int retval = common_fp_to_int(true, vA, vB);
+ rPC += 1;
+ return retval;
+}
+
+//! common code to convert float or double to long
+
+//! It uses FP stack
+int common_fp_to_long(bool isDouble, u2 vA, u2 vB) {
+ if(isDouble) {
+ load_fp_stack_VR(OpndSize_64, vB); //fldl
+ }
+ else {
+ load_fp_stack_VR(OpndSize_32, vB); //flds
+ }
+
+ load_fp_stack_global_data_API("valuePosInfLong", OpndSize_64);
+ load_fp_stack_global_data_API("valueNegInfLong", OpndSize_64);
+
+ //ST(0) ST(1) ST(2) --> LintMin LintMax value
+ compare_fp_stack(true, 2, false/*isDouble*/); //ST(2)
+ //ST(0) ST(1) --> LintMax value
+ conditional_jump(Condition_AE, ".float_to_long_negInf", true);
+ rememberState(1);
+ compare_fp_stack(true, 1, false/*isDouble*/); //ST(1)
+ rememberState(2);
+ //ST(0) --> value
+ conditional_jump(Condition_C, ".float_to_long_nanInf", true);
+ //fnstcw, orw, fldcw, xorw
+ load_effective_addr(-2, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ store_fpu_cw(false/*checkException*/, 0, PhysicalReg_ESP, true);
+ alu_binary_imm_mem(OpndSize_16, or_opc, 0xc00, 0, PhysicalReg_ESP, true);
+ load_fpu_cw(0, PhysicalReg_ESP, true);
+ alu_binary_imm_mem(OpndSize_16, xor_opc, 0xc00, 0, PhysicalReg_ESP, true);
+ store_int_fp_stack_VR(true/*pop*/, OpndSize_64, vA); //fistpll
+ //fldcw
+ load_fpu_cw(0, PhysicalReg_ESP, true);
+ load_effective_addr(2, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ rememberState(3);
+ unconditional_jump(".float_to_long_okay", true);
+ insertLabel(".float_to_long_nanInf", true);
+ conditional_jump(Condition_NP, ".float_to_long_posInf", true);
+ //fstpl??
+ goToState(2);
+
+ load_global_data_API("valueNanLong", OpndSize_64, 1, false);
+
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ transferToState(3);
+ unconditional_jump(".float_to_long_okay", true);
+ insertLabel(".float_to_long_posInf", true);
+ //fstpl
+ goToState(2);
+
+ load_global_data_API("valuePosInfLong", OpndSize_64, 2, false);
+ set_virtual_reg(vA, OpndSize_64, 2, false);
+ transferToState(3);
+ unconditional_jump(".float_to_long_okay", true);
+ insertLabel(".float_to_long_negInf", true);
+ //fstpl
+ //fstpl
+ goToState(1);
+
+ load_global_data_API("valueNegInfLong", OpndSize_64, 3, false);
+ set_virtual_reg(vA, OpndSize_64, 3, false);
+ transferToState(3);
+ insertLabel(".float_to_long_okay", true);
+ return 0;
+}
+//! lower bytecode FLOAT_TO_LONG by calling common_fp_to_long
+
+//!
+int op_float_to_long() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ int retval = common_fp_to_long(false, vA, vB);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode DOUBLE_TO_LONG by calling common_fp_to_long
+
+//!
+int op_double_to_long() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ int retval = common_fp_to_long(true, vA, vB);
+ rPC += 1;
+ return retval;
+}
+#define P_GPR_1 PhysicalReg_EBX
+//! lower bytecode INT_TO_BYTE
+
+//! It uses GPR
+int op_int_to_byte() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ alu_binary_imm_reg(OpndSize_32, sal_opc, 24, 1, false);
+ alu_binary_imm_reg(OpndSize_32, sar_opc, 24, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode INT_TO_CHAR
+
+//! It uses GPR
+int op_int_to_char() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ alu_binary_imm_reg(OpndSize_32, sal_opc, 16, 1, false);
+ alu_binary_imm_reg(OpndSize_32, shr_opc, 16, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode INT_TO_SHORT
+
+//! It uses GPR
+int op_int_to_short() {
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ alu_binary_imm_reg(OpndSize_32, sal_opc, 16, 1, false);
+ alu_binary_imm_reg(OpndSize_32, sar_opc, 16, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 1;
+ return 0;
+}
+//! common code to handle integer ALU ops
+
+//! It uses GPR
+int common_alu_int(ALU_Opcode opc, u2 vA, u2 v1, u2 v2) { //except div and rem
+ get_virtual_reg(v1, OpndSize_32, 1, false);
+ //in encoder, reg is first operand, which is the destination
+ //gpr_1 op v2(rFP) --> gpr_1
+ //shift only works with reg cl, v2 should be in %ecx
+ alu_binary_VR_reg(OpndSize_32, opc, v2, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ return 0;
+}
+#undef P_GPR_1
+#define P_GPR_1 PhysicalReg_EBX
+//! common code to handle integer shift ops
+
+//! It uses GPR
+int common_shift_int(ALU_Opcode opc, u2 vA, u2 v1, u2 v2) {
+ get_virtual_reg(v2, OpndSize_32, PhysicalReg_ECX, true);
+ get_virtual_reg(v1, OpndSize_32, 1, false);
+ //in encoder, reg2 is first operand, which is the destination
+ //gpr_1 op v2(rFP) --> gpr_1
+ //shift only works with reg cl, v2 should be in %ecx
+ alu_binary_reg_reg(OpndSize_32, opc, PhysicalReg_ECX, true, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ return 0;
+}
+#undef p_GPR_1
+//! lower bytecode ADD_INT by calling common_alu_int
+
+//!
+int op_add_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_alu_int(add_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SUB_INT by calling common_alu_int
+
+//!
+int op_sub_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_alu_int(sub_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode MUL_INT by calling common_alu_int
+
+//!
+int op_mul_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_alu_int(imul_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode AND_INT by calling common_alu_int
+
+//!
+int op_and_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_alu_int(and_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode OR_INT by calling common_alu_int
+
+//!
+int op_or_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_alu_int(or_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode XOR_INT by calling common_alu_int
+
+//!
+int op_xor_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_alu_int(xor_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SHL_INT by calling common_shift_int
+
+//!
+int op_shl_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_shift_int(shl_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SHR_INT by calling common_shift_int
+
+//!
+int op_shr_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_shift_int(sar_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode USHR_INT by calling common_shift_int
+
+//!
+int op_ushr_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_shift_int(shr_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode ADD_INT_2ADDR by calling common_alu_int
+
+//!
+int op_add_int_2addr() {
+ u2 vA, v1, v2;
+ vA = INST_A(inst);
+ v1 = vA;
+ v2 = INST_B(inst);
+ int retval = common_alu_int(add_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode SUB_INT_2ADDR by calling common_alu_int
+
+//!
+int op_sub_int_2addr() {
+ u2 vA, v1, v2;
+ vA = INST_A(inst);
+ v1 = vA;
+ v2 = INST_B(inst);
+ int retval = common_alu_int(sub_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode MUL_INT_2ADDR by calling common_alu_int
+
+//!
+int op_mul_int_2addr() {
+ u2 vA, v1, v2;
+ vA = INST_A(inst);
+ v1 = vA;
+ v2 = INST_B(inst);
+ int retval = common_alu_int(imul_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode AND_INT_2ADDR by calling common_alu_int
+
+//!
+int op_and_int_2addr() {
+ u2 vA, v1, v2;
+ vA = INST_A(inst);
+ v1 = vA;
+ v2 = INST_B(inst);
+ int retval = common_alu_int(and_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode OR_INT_2ADDR by calling common_alu_int
+
+//!
+int op_or_int_2addr() {
+ u2 vA, v1, v2;
+ vA = INST_A(inst);
+ v1 = vA;
+ v2 = INST_B(inst);
+ int retval = common_alu_int(or_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode XOR_INT_2ADDR by calling common_alu_int
+
+//!
+int op_xor_int_2addr() {
+ u2 vA, v1, v2;
+ vA = INST_A(inst);
+ v1 = vA;
+ v2 = INST_B(inst);
+ int retval = common_alu_int(xor_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode SHL_INT_2ADDR by calling common_shift_int
+
+//!
+int op_shl_int_2addr() {
+ u2 vA, v1, v2;
+ vA = INST_A(inst);
+ v1 = vA;
+ v2 = INST_B(inst);
+ int retval = common_shift_int(shl_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode SHR_INT_2ADDR by calling common_shift_int
+
+//!
+int op_shr_int_2addr() {
+ u2 vA, v1, v2;
+ vA = INST_A(inst);
+ v1 = vA;
+ v2 = INST_B(inst);
+ int retval = common_shift_int(sar_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode USHR_INT_2ADDR by calling common_shift_int
+
+//!
+int op_ushr_int_2addr() {
+ u2 vA, v1, v2;
+ vA = INST_A(inst);
+ v1 = vA;
+ v2 = INST_B(inst);
+ int retval = common_shift_int(shr_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+#define P_GPR_1 PhysicalReg_EBX
+//!common code to handle integer DIV & REM, it used GPR
+
+//!The special case: when op0 == minint && op1 == -1, return 0 for isRem, return 0x80000000 for isDiv
+//!There are two merge points in the control flow for this bytecode
+//!make sure the reg. alloc. state is the same at merge points by calling transferToState
+int common_div_rem_int(bool isRem, u2 vA, u2 v1, u2 v2) {
+ get_virtual_reg(v1, OpndSize_32, PhysicalReg_EAX, true);
+ get_virtual_reg(v2, OpndSize_32, 2, false);
+ compare_imm_reg(OpndSize_32, 0, 2, false);
+ handlePotentialException(
+ Condition_E, Condition_NE,
+ 1, "common_errDivideByZero");
+ /////////////////// handle special cases
+ //conditional move 0 to $edx for rem for the two special cases
+ //conditional move 0x80000000 to $eax for div
+ //handle -1 special case divide error
+ compare_imm_reg(OpndSize_32, -1, 2, false);
+ conditional_jump(Condition_NE, ".common_div_rem_int_normal", true);
+ //handle min int special case divide error
+ rememberState(1);
+ compare_imm_reg(OpndSize_32, 0x80000000, PhysicalReg_EAX, true);
+ transferToState(1);
+ conditional_jump(Condition_E, ".common_div_rem_int_special", true);
+
+ insertLabel(".common_div_rem_int_normal", true); //merge point
+ convert_integer(OpndSize_32, OpndSize_64); //cdq
+ //idiv: dividend in edx:eax; quotient in eax; remainder in edx
+ alu_unary_reg(OpndSize_32, idiv_opc, 2, false);
+ if(isRem)
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EDX, true);
+ else //divide: quotient in %eax
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
+ rememberState(2);
+ unconditional_jump(".common_div_rem_int_okay", true);
+
+ insertLabel(".common_div_rem_int_special", true);
+ goToState(1);
+ if(isRem)
+ set_VR_to_imm(vA, OpndSize_32, 0);
+ else
+ set_VR_to_imm(vA, OpndSize_32, 0x80000000);
+ transferToState(2);
+ insertLabel(".common_div_rem_int_okay", true); //merge point 2
+ return 0;
+}
+#undef P_GPR_1
+//! lower bytecode DIV_INT by calling common_div_rem_int
+
+//!
+int op_div_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_div_rem_int(false, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode REM_INT by calling common_div_rem_int
+
+//!
+int op_rem_int() {
+ u2 vA, v1, v2;
+ vA = INST_AA(inst);
+ v1 = *((u1*)rPC + 2);
+ v2 = *((u1*)rPC + 3);
+ int retval = common_div_rem_int(true, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode DIV_INT_2ADDR by calling common_div_rem_int
+
+//!
+int op_div_int_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_div_rem_int(false, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode REM_INT_2ADDR by calling common_div_rem_int
+
+//!
+int op_rem_int_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_div_rem_int(true, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+
+#define P_GPR_1 PhysicalReg_EBX
+//! common code to handle integer ALU ops with literal
+
+//! It uses GPR
+int common_alu_int_lit(ALU_Opcode opc, u2 vA, u2 vB, s2 imm) { //except div and rem
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ alu_binary_imm_reg(OpndSize_32, opc, imm, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ return 0;
+}
+//! calls common_alu_int_lit
+int common_shift_int_lit(ALU_Opcode opc, u2 vA, u2 vB, s2 imm) {
+ return common_alu_int_lit(opc, vA, vB, imm);
+}
+#undef p_GPR_1
+//! lower bytecode ADD_INT_LIT16 by calling common_alu_int_lit
+
+//!
+int op_add_int_lit16() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = common_alu_int_lit(add_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+
+int alu_rsub_int(ALU_Opcode opc, u2 vA, s2 imm, u2 vB) {
+ move_imm_to_reg(OpndSize_32, imm, 2, false);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ alu_binary_reg_reg(OpndSize_32, opc, 1, false, 2, false);
+ set_virtual_reg(vA, OpndSize_32, 2, false);
+ return 0;
+}
+
+
+//! lower bytecode RSUB_INT by calling common_alu_int_lit
+
+//!
+int op_rsub_int() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = alu_rsub_int(sub_opc, vA, tmp, vB);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode MUL_INT_LIT16 by calling common_alu_int_lit
+
+//!
+int op_mul_int_lit16() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = common_alu_int_lit(imul_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode AND_INT_LIT16 by calling common_alu_int_lit
+
+//!
+int op_and_int_lit16() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = common_alu_int_lit(and_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode OR_INT_LIT16 by calling common_alu_int_lit
+
+//!
+int op_or_int_lit16() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = common_alu_int_lit(or_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode XOR_INT_LIT16 by calling common_alu_int_lit
+
+//!
+int op_xor_int_lit16() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = common_alu_int_lit(xor_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SHL_INT_LIT16 by calling common_shift_int_lit
+
+//!
+int op_shl_int_lit16() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = common_shift_int_lit(shl_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SHR_INT_LIT16 by calling common_shift_int_lit
+
+//!
+int op_shr_int_lit16() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = common_shift_int_lit(sar_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode USHR_INT_LIT16 by calling common_shift_int_lit
+
+//!
+int op_ushr_int_lit16() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = common_shift_int_lit(shr_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode ADD_INT_LIT8 by calling common_alu_int_lit
+
+//!
+int op_add_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = common_alu_int_lit(add_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode RSUB_INT_LIT8 by calling common_alu_int_lit
+
+//!
+int op_rsub_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = alu_rsub_int(sub_opc, vA, tmp, vB);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode MUL_INT_LIT8 by calling common_alu_int_lit
+
+//!
+int op_mul_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = common_alu_int_lit(imul_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode AND_INT_LIT8 by calling common_alu_int_lit
+
+//!
+int op_and_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = common_alu_int_lit(and_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode OR_INT_LIT8 by calling common_alu_int_lit
+
+//!
+int op_or_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = common_alu_int_lit(or_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode XOR_INT_LIT8 by calling common_alu_int_lit
+
+//!
+int op_xor_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = common_alu_int_lit(xor_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SHL_INT_LIT8 by calling common_shift_int_lit
+
+//!
+int op_shl_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = common_shift_int_lit(shl_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SHR_INT_LIT8 by calling common_shift_int_lit
+
+//!
+int op_shr_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = common_shift_int_lit(sar_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode USHR_INT_LIT8 by calling common_shift_int_lit
+
+//!
+int op_ushr_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = common_shift_int_lit(shr_opc, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+
+int isPowerOfTwo(int imm) {
+ int i;
+ for(i = 1; i < 17; i++) {
+ if(imm == (1 << i)) return i;
+ }
+ return -1;
+}
+
+#define P_GPR_1 PhysicalReg_EBX
+int div_lit_strength_reduction(u2 vA, u2 vB, s2 imm) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ //strength reduction for div by 2,4,8,...
+ int power = isPowerOfTwo(imm);
+ if(power < 1) return 0;
+ //tmp2 is not updated, so it can share with vB
+ get_virtual_reg(vB, OpndSize_32, 2, false);
+ //if imm is 2, power will be 1
+ if(power == 1) {
+ /* mov tmp1, tmp2
+ shrl $31, tmp1
+ addl tmp2, tmp1
+ sarl $1, tmp1 */
+ move_reg_to_reg(OpndSize_32, 2, false, 1, false);
+ alu_binary_imm_reg(OpndSize_32, shr_opc, 31, 1, false);
+ alu_binary_reg_reg(OpndSize_32, add_opc, 2, false, 1, false);
+ alu_binary_imm_reg(OpndSize_32, sar_opc, 1, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ return 1;
+ }
+ //power > 1
+ /* mov tmp1, tmp2
+ sarl $power-1, tmp1
+ shrl 32-$power, tmp1
+ addl tmp2, tmp1
+ sarl $power, tmp1 */
+ move_reg_to_reg(OpndSize_32, 2, false, 1, false);
+ alu_binary_imm_reg(OpndSize_32, sar_opc, power-1, 1, false);
+ alu_binary_imm_reg(OpndSize_32, shr_opc, 32-power, 1, false);
+ alu_binary_reg_reg(OpndSize_32, add_opc, 2, false, 1, false);
+ alu_binary_imm_reg(OpndSize_32, sar_opc, power, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ return 1;
+ }
+ return 0;
+}
+
+////////// throws exception!!!
+//! common code to handle integer DIV & REM with literal
+
+//! It uses GPR
+int common_div_rem_int_lit(bool isRem, u2 vA, u2 vB, s2 imm) {
+ if(!isRem) {
+ int retCode = div_lit_strength_reduction(vA, vB, imm);
+ if(retCode > 0) return 0;
+ }
+ if(imm == 0) {
+ export_pc(); //use %edx
+#ifdef DEBUG_EXCEPTION
+ LOGI("EXTRA code to handle exception");
+#endif
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+ unconditional_jump_global_API(
+ "common_errDivideByZero", false);
+
+ return 0;
+ }
+ get_virtual_reg(vB, OpndSize_32, PhysicalReg_EAX, true);
+ //check against -1 for DIV_INT??
+ if(imm == -1) {
+ compare_imm_reg(OpndSize_32, 0x80000000, PhysicalReg_EAX, true);
+ conditional_jump(Condition_E, ".div_rem_int_lit_special", true);
+ rememberState(1);
+ }
+ move_imm_to_reg(OpndSize_32, imm, 2, false);
+ convert_integer(OpndSize_32, OpndSize_64); //cdq
+ //idiv: dividend in edx:eax; quotient in eax; remainder in edx
+ alu_unary_reg(OpndSize_32, idiv_opc, 2, false);
+ if(isRem)
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EDX, true);
+ else
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
+
+ if(imm == -1) {
+ unconditional_jump(".div_rem_int_lit_okay", true);
+ rememberState(2);
+ insertLabel(".div_rem_int_lit_special", true);
+ goToState(1);
+ if(isRem)
+ set_VR_to_imm(vA, OpndSize_32, 0);
+ else
+ set_VR_to_imm(vA, OpndSize_32, 0x80000000);
+ transferToState(2);
+ }
+
+ insertLabel(".div_rem_int_lit_okay", true); //merge point 2
+ return 0;
+}
+#undef P_GPR_1
+//! lower bytecode DIV_INT_LIT16 by calling common_div_rem_int_lit
+
+//!
+int op_div_int_lit16() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = common_div_rem_int_lit(false, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode REM_INT_LIT16 by calling common_div_rem_int_lit
+
+//!
+int op_rem_int_lit16() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s4 tmp = (s2)FETCH(1);
+ int retval = common_div_rem_int_lit(true, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode DIV_INT_LIT8 by calling common_div_rem_int_lit
+
+//!
+int op_div_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = common_div_rem_int_lit(false, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode REM_INT_LIT8 by calling common_div_rem_int_lit
+
+//!
+int op_rem_int_lit8() {
+ u2 vA = INST_AA(inst);
+ u2 vB = (u2)FETCH(1) & 0xff;
+ s2 tmp = (s2)FETCH(1) >> 8;
+ int retval = common_div_rem_int_lit(true, vA, vB, tmp);
+ rPC += 2;
+ return retval;
+}
+//! common code to hanle long ALU ops
+
+//! It uses XMM
+int common_alu_long(ALU_Opcode opc, u2 vA, u2 v1, u2 v2) { //except div and rem
+ get_virtual_reg(v1, OpndSize_64, 1, false);
+ get_virtual_reg(v2, OpndSize_64, 2, false);
+ alu_binary_reg_reg(OpndSize_64, opc, 2, false, 1, false);
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ return 0;
+}
+//! lower bytecode ADD_LONG by calling common_alu_long
+
+//!
+int op_add_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_long(add_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SUB_LONG by calling common_alu_long
+
+//!
+int op_sub_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_long(sub_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode AND_LONG by calling common_alu_long
+
+//!
+int op_and_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_long(and_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode OR_LONG by calling common_alu_long
+
+//!
+int op_or_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_long(or_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode XOR_LONG by calling common_alu_long
+
+//!
+int op_xor_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_long(xor_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode ADD_LONG_2ADDR by calling common_alu_long
+
+//!
+int op_add_long_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_long(add_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode SUB_LONG_2ADDR by calling common_alu_long
+
+//!
+int op_sub_long_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_long(sub_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode AND_LONG_2ADDR by calling common_alu_long
+
+//!
+int op_and_long_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_long(and_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode OR_LONG_2ADDR by calling common_alu_long
+
+//!
+int op_or_long_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_long(or_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode XOR_LONG_2ADDR by calling common_alu_long
+
+//!
+int op_xor_long_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_long(xor_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+
+//signed vs unsigned imul and mul?
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_ESI
+//! common code to handle multiplication of long
+
+//! It uses GPR
+int common_mul_long(u2 vA, u2 v1, u2 v2) {
+ get_virtual_reg(v2, OpndSize_32, 1, false);
+ move_reg_to_reg(OpndSize_32, 1, false, PhysicalReg_EAX, true);
+ //imul: 2L * 1H update temporary 1
+ alu_binary_VR_reg(OpndSize_32, imul_opc, (v1+1), 1, false);
+ get_virtual_reg(v1, OpndSize_32, 3, false);
+ move_reg_to_reg(OpndSize_32, 3, false, 2, false);
+ //imul: 1L * 2H
+ alu_binary_VR_reg(OpndSize_32, imul_opc, (v2+1), 2, false);
+ alu_binary_reg_reg(OpndSize_32, add_opc, 2, false, 1, false);
+ alu_unary_reg(OpndSize_32, mul_opc, 3, false);
+ alu_binary_reg_reg(OpndSize_32, add_opc, PhysicalReg_EDX, true, 1, false);
+ set_virtual_reg(vA+1, OpndSize_32, 1, false);
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+//! lower bytecode MUL_LONG by calling common_mul_long
+
+//!
+int op_mul_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_mul_long(vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode MUL_LONG_2ADDR by calling common_mul_long
+
+//!
+int op_mul_long_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_mul_long(vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+//! common code to handle DIV & REM of long
+
+//! It uses GPR & XMM; and calls call_moddi3 & call_divdi3
+int common_div_rem_long(bool isRem, u2 vA, u2 v1, u2 v2) {
+ get_virtual_reg(v2, OpndSize_32, 1, false);
+ get_virtual_reg(v2+1, OpndSize_32, 2, false);
+ //save to native stack before changing register P_GPR_1
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 1, false, 8, PhysicalReg_ESP, true);
+ alu_binary_reg_reg(OpndSize_32, or_opc, 2, false, 1, false);
+
+ handlePotentialException(
+ Condition_E, Condition_NE,
+ 1, "common_errDivideByZero");
+ move_reg_to_mem(OpndSize_32, 2, false, 12, PhysicalReg_ESP, true);
+ get_virtual_reg(v1, OpndSize_64, 1, false);
+ move_reg_to_mem(OpndSize_64, 1, false, 0, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ nextVersionOfHardReg(PhysicalReg_EDX, 2); //next version has 2 refs
+ if(isRem)
+ call_moddi3();
+ else
+ call_divdi3();
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ set_virtual_reg(vA+1, OpndSize_32,PhysicalReg_EDX, true);
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+//! lower bytecode DIV_LONG by calling common_div_rem_long
+
+//!
+int op_div_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_div_rem_long(false, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode REM_LONG by calling common_div_rem_long
+
+//!
+int op_rem_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_div_rem_long(true, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode DIV_LONG_2ADDR by calling common_div_rem_long
+
+//!
+int op_div_long_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_div_rem_long(false, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode REM_LONG_2ADDR by calling common_div_rem_long
+
+//!
+int op_rem_long_2addr() { //call __moddi3 instead of __divdi3
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_div_rem_long(true, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+
+//! common code to handle SHL long
+
+//! It uses XMM
+int common_shl_long(u2 vA, u2 v1, u2 v2) {
+ get_VR_ss(v2, 2, false);
+
+ load_global_data_API("shiftMask", OpndSize_64, 3, false);
+
+ get_virtual_reg(v1, OpndSize_64, 1, false);
+ alu_binary_reg_reg(OpndSize_64, and_opc, 3, false, 2, false);
+ alu_binary_reg_reg(OpndSize_64, sll_opc, 2, false, 1, false);
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ return 0;
+}
+
+//! common code to handle SHR long
+
+//! It uses XMM
+int common_shr_long(u2 vA, u2 v1, u2 v2) {
+ get_VR_ss(v2, 2, false);
+
+ load_global_data_API("shiftMask", OpndSize_64, 3, false);
+
+ get_virtual_reg(v1, OpndSize_64, 1, false);
+ alu_binary_reg_reg(OpndSize_64, and_opc, 3, false, 2, false);
+ alu_binary_reg_reg(OpndSize_64, srl_opc, 2, false, 1, false);
+ compare_imm_VR(OpndSize_32, 0, (v1+1));
+ conditional_jump(Condition_GE, ".common_shr_long_special", true);
+ rememberState(1);
+
+ load_global_data_API("value64", OpndSize_64, 4, false);
+
+ alu_binary_reg_reg(OpndSize_64, sub_opc, 2, false, 4, false);
+
+ load_global_data_API("64bits", OpndSize_64, 5, false);
+
+ alu_binary_reg_reg(OpndSize_64, sll_opc, 4, false, 5, false);
+ alu_binary_reg_reg(OpndSize_64, or_opc, 5, false, 1, false);
+ rememberState(2);
+ //check whether the target is next instruction TODO
+ unconditional_jump(".common_shr_long_done", true);
+
+ insertLabel(".common_shr_long_special", true);
+ goToState(1);
+ transferToState(2);
+ insertLabel(".common_shr_long_done", true);
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ return 0;
+}
+
+//! common code to handle USHR long
+
+//! It uses XMM
+int common_ushr_long(u2 vA, u2 v1, u2 v2) {
+ get_VR_sd(v1, 1, false);
+ get_VR_ss(v2, 2, false);
+
+ load_sd_global_data_API("shiftMask", 3, false);
+
+ alu_binary_reg_reg(OpndSize_64, and_opc, 3, false, 2, false);
+ alu_binary_reg_reg(OpndSize_64, srl_opc, 2, false, 1, false);
+ set_VR_sd(vA, 1, false);
+ return 0;
+}
+//! lower bytecode SHL_LONG by calling common_shl_long
+
+//!
+int op_shl_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_shl_long(vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SHL_LONG_2ADDR by calling common_shl_long
+
+//!
+int op_shl_long_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_shl_long(vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode SHR_LONG by calling common_shr_long
+
+//!
+int op_shr_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_shr_long(vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SHR_LONG_2ADDR by calling common_shr_long
+
+//!
+int op_shr_long_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_shr_long(vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode USHR_LONG by calling common_ushr_long
+
+//!
+int op_ushr_long() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_ushr_long(vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode USHR_LONG_2ADDR by calling common_ushr_long
+
+//!
+int op_ushr_long_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_ushr_long(vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+#define USE_MEM_OPERAND
+///////////////////////////////////////////
+//! common code to handle ALU of floats
+
+//! It uses XMM
+int common_alu_float(ALU_Opcode opc, u2 vA, u2 v1, u2 v2) {//add, sub, mul
+ get_VR_ss(v1, 1, false);
+#ifdef USE_MEM_OPERAND
+ alu_sd_binary_VR_reg(opc, v2, 1, false, false/*isSD*/);
+#else
+ get_VR_ss(v2, 2, false);
+ alu_ss_binary_reg_reg(opc, 2, false, 1, false);
+#endif
+ set_VR_ss(vA, 1, false);
+ return 0;
+}
+//! lower bytecode ADD_FLOAT by calling common_alu_float
+
+//!
+int op_add_float() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_float(add_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SUB_FLOAT by calling common_alu_float
+
+//!
+int op_sub_float() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_float(sub_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode MUL_FLOAT by calling common_alu_float
+
+//!
+int op_mul_float() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_float(mul_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode ADD_FLOAT_2ADDR by calling common_alu_float
+
+//!
+int op_add_float_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_float(add_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode SUB_FLOAT_2ADDR by calling common_alu_float
+
+//!
+int op_sub_float_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_float(sub_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode MUL_FLOAT_2ADDR by calling common_alu_float
+
+//!
+int op_mul_float_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_float(mul_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! common code to handle DIV of float
+
+//! It uses FP stack
+int common_div_float(u2 vA, u2 v1, u2 v2) {
+ load_fp_stack_VR(OpndSize_32, v1); //flds
+ fpu_VR(div_opc, OpndSize_32, v2);
+ store_fp_stack_VR(true, OpndSize_32, vA); //fstps
+ return 0;
+}
+//! lower bytecode DIV_FLOAT by calling common_div_float
+
+//!
+int op_div_float() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_float(div_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode DIV_FLOAT_2ADDR by calling common_div_float
+
+//!
+int op_div_float_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_float(div_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! common code to handle DIV of double
+
+//! It uses XMM
+int common_alu_double(ALU_Opcode opc, u2 vA, u2 v1, u2 v2) {//add, sub, mul
+ get_VR_sd(v1, 1, false);
+#ifdef USE_MEM_OPERAND
+ alu_sd_binary_VR_reg(opc, v2, 1, false, true /*isSD*/);
+#else
+ get_VR_sd(v2, 2, false);
+ alu_sd_binary_reg_reg(opc, 2, false, 1, false);
+#endif
+ set_VR_sd(vA, 1, false);
+ return 0;
+}
+//! lower bytecode ADD_DOUBLE by calling common_alu_double
+
+//!
+int op_add_double() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_double(add_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SUB_DOUBLE by calling common_alu_double
+
+//!
+int op_sub_double() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_double(sub_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode MUL_DOUBLE by calling common_alu_double
+
+//!
+int op_mul_double() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_double(mul_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode ADD_DOUBLE_2ADDR by calling common_alu_double
+
+//!
+int op_add_double_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_double(add_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode SUB_DOUBLE_2ADDR by calling common_alu_double
+
+//!
+int op_sub_double_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_double(sub_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode MUL_DOUBLE_2ADDR by calling common_alu_double
+
+//!
+int op_mul_double_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_double(mul_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! common code to handle DIV of double
+
+//! It uses FP stack
+int common_div_double(u2 vA, u2 v1, u2 v2) {
+ load_fp_stack_VR(OpndSize_64, v1); //fldl
+ fpu_VR(div_opc, OpndSize_64, v2); //fdivl
+ store_fp_stack_VR(true, OpndSize_64, vA); //fstpl
+ return 0;
+}
+//! lower bytecode DIV_DOUBLE by calling common_div_double
+
+//!
+int op_div_double() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_alu_double(div_opc, vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode DIV_DOUBLE_2ADDR by calling common_div_double
+
+//!
+int op_div_double_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_alu_double(div_opc, vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+//! common code to handle REM of float
+
+//! It uses GPR & calls call_fmodf
+int common_rem_float(u2 vA, u2 v1, u2 v2) {
+ get_virtual_reg(v1, OpndSize_32, 1, false);
+ get_virtual_reg(v2, OpndSize_32, 2, false);
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 1, false, 0, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 2, false, 4, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ call_fmodf(); //(float x, float y) return float
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ store_fp_stack_VR(true, OpndSize_32, vA); //fstps
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+//! lower bytecode REM_FLOAT by calling common_rem_float
+
+//!
+int op_rem_float() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_rem_float(vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode REM_FLOAT_2ADDR by calling common_rem_float
+
+//!
+int op_rem_float_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_rem_float(vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! common code to handle REM of double
+
+//! It uses XMM & calls call_fmod
+int common_rem_double(u2 vA, u2 v1, u2 v2) {
+ get_virtual_reg(v1, OpndSize_64, 1, false);
+ get_virtual_reg(v2, OpndSize_64, 2, false);
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_64, 1, false, 0, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_64, 2, false, 8, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ call_fmod(); //(long double x, long double y) return double
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ store_fp_stack_VR(true, OpndSize_64, vA); //fstpl
+ return 0;
+}
+//! lower bytecode REM_DOUBLE by calling common_rem_double
+
+//!
+int op_rem_double() {
+ u2 vA = INST_AA(inst);
+ u2 v1 = *((u1*)rPC + 2);
+ u2 v2 = *((u1*)rPC + 3);
+ int retval = common_rem_double(vA, v1, v2);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode REM_DOUBLE_2ADDR by calling common_rem_double
+
+//!
+int op_rem_double_2addr() {
+ u2 vA = INST_A(inst);
+ u2 v1 = vA;
+ u2 v2 = INST_B(inst);
+ int retval = common_rem_double(vA, v1, v2);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode CMPL_FLOAT
+
+//!
+int op_cmpl_float() {
+ u2 vA = INST_AA(inst);
+ u4 v1 = FETCH(1) & 0xff;
+ u4 v2 = FETCH(1) >> 8;
+ get_VR_ss(v1, 1, false); //xmm
+ move_imm_to_reg(OpndSize_32, 0, 1, false);
+ move_imm_to_reg(OpndSize_32, 1, 2, false);
+ move_imm_to_reg(OpndSize_32, 0xffffffff, 3, false);
+ compare_VR_ss_reg(v2, 1, false);
+ //default: 0xffffffff??
+ move_imm_to_reg(OpndSize_32,
+ 0xffffffff, 4, false);
+ //ORDER of cmov matters !!! (Z,P,A)
+ //finalNaN: unordered 0xffffffff
+ conditional_move_reg_to_reg(OpndSize_32, Condition_Z,
+ 1, false, 4, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_P,
+ 3, false, 4, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_A,
+ 2, false, 4, false);
+ set_virtual_reg(vA, OpndSize_32, 4, false);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode CMPG_FLOAT
+
+//!
+int op_cmpg_float() {
+ u2 vA = INST_AA(inst);
+ u4 v1 = FETCH(1) & 0xff;
+ u4 v2 = FETCH(1) >> 8;
+ get_VR_ss(v1, 1, false);
+ compare_VR_ss_reg(v2, 1, false);
+ move_imm_to_reg(OpndSize_32, 0, 1, false);
+ move_imm_to_reg(OpndSize_32, 1, 2, false);
+ //default: 0xffffffff??
+ move_imm_to_reg(OpndSize_32, 0xffffffff, 3, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_Z,
+ 1, false, 3, false);
+ //finalNaN: unordered
+ conditional_move_reg_to_reg(OpndSize_32, Condition_P,
+ 2, false, 3, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_A,
+ 2, false, 3, false);
+ set_virtual_reg(vA, OpndSize_32, 3, false);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode CMPL_DOUBLE
+
+//!
+int op_cmpl_double() {
+ u2 vA = INST_AA(inst);
+ u4 v1 = FETCH(1) & 0xff;
+ u4 v2 = FETCH(1) >> 8;
+ get_VR_sd(v1, 1, false);
+ compare_VR_sd_reg(v2, 1, false);
+ move_imm_to_reg(OpndSize_32, 0, 1, false);
+ move_imm_to_reg(OpndSize_32, 1, 2, false);
+ move_imm_to_reg(OpndSize_32, 0xffffffff, 3, false);
+
+ //default: 0xffffffff??
+ move_imm_to_reg(OpndSize_32, 0xffffffff, 4, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_Z,
+ 1, false, 4, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_P,
+ 3, false, 4, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_A,
+ 2, false, 4, false);
+ set_virtual_reg(vA, OpndSize_32, 4, false);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode CMPG_DOUBLE
+
+//!
+int op_cmpg_double() {
+ u2 vA = INST_AA(inst);
+ u4 v1 = FETCH(1) & 0xff;
+ u4 v2 = FETCH(1) >> 8;
+ get_VR_sd(v1, 1, false);
+ compare_VR_sd_reg(v2, 1, false);
+ move_imm_to_reg(OpndSize_32, 0, 1, false);
+ move_imm_to_reg(OpndSize_32, 1, 2, false);
+
+ //default: 0xffffffff??
+ move_imm_to_reg(OpndSize_32,
+ 0xffffffff, 3, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_Z,
+ 1, false, 3, false);
+ //finalNaN: unordered
+ conditional_move_reg_to_reg(OpndSize_32, Condition_P,
+ 2, false, 3, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_A,
+ 2, false, 3, false);
+ set_virtual_reg(vA, OpndSize_32, 3, false);
+ rPC += 2;
+ return 0;
+}
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_ESI
+#define P_SCRATCH_1 PhysicalReg_EDX
+#define P_SCRATCH_2 PhysicalReg_EAX
+#define OPTION_OLD //for simpler cfg
+//! lower bytecode CMP_LONG
+
+//!
+int op_cmp_long() {
+ u2 vA = INST_AA(inst);
+ u4 v1 = FETCH(1) & 0xff;
+ u4 v2 = FETCH(1) >> 8;
+ get_virtual_reg(v1+1, OpndSize_32, 2, false);
+#ifdef OPTION_OLD
+ move_imm_to_reg(OpndSize_32, 0xffffffff, 3, false);
+ move_imm_to_reg(OpndSize_32, 1, 4, false);
+ move_imm_to_reg(OpndSize_32, 0, 5, false);
+#endif
+ compare_VR_reg(OpndSize_32,
+ v2+1, 2, false);
+#ifndef OPTION_OLD
+ conditional_jump(Condition_L, ".cmp_long_less", true);
+ conditional_jump(Condition_G, ".cmp_long_greater", true);
+#else
+ conditional_jump(Condition_E, ".cmp_long_equal", true);
+ rememberState(1);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_L, //below vs less
+ 3, false, 6, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_G, //above vs greater
+ 4, false, 6, false);
+ set_virtual_reg(vA, OpndSize_32, 6, false);
+ rememberState(2);
+ unconditional_jump(".cmp_long_okay", true);
+ insertLabel(".cmp_long_equal", true);
+ goToState(1);
+#endif
+
+ get_virtual_reg(v1, OpndSize_32, 1, false);
+ compare_VR_reg(OpndSize_32,
+ v2, 1, false);
+#ifdef OPTION_OLD
+ conditional_move_reg_to_reg(OpndSize_32, Condition_E,
+ 5, false, 6, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_B, //below vs less
+ 3, false, 6, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_A, //above vs greater
+ 4, false, 6, false);
+ set_virtual_reg(vA, OpndSize_32, 6, false);
+ transferToState(2);
+#else
+ conditional_jump(Condition_A, ".cmp_long_greater", true);
+ conditional_jump(Condition_NE, ".cmp_long_less", true);
+ set_VR_to_imm(vA, OpndSize_32, 0);
+ unconditional_jump(".cmp_long_okay", true);
+
+ insertLabel(".cmp_long_less", true);
+ set_VR_to_imm(vA, OpndSize_32, 0xffffffff);
+ unconditional_jump(".cmp_long_okay", true);
+
+ insertLabel(".cmp_long_greater", true);
+ set_VR_to_imm(vA, OpndSize_32, 1);
+#endif
+ insertLabel(".cmp_long_okay", true);
+ rPC += 2;
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
diff --git a/vm/compiler/codegen/x86/LowerConst.cpp b/vm/compiler/codegen/x86/LowerConst.cpp
new file mode 100644
index 0000000..62e0ed1
--- /dev/null
+++ b/vm/compiler/codegen/x86/LowerConst.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file LowerConst.cpp
+ \brief This file lowers the following bytecodes: CONST_XXX
+
+ Functions are called from the lowered native sequence:
+ 1> const_string_resolve
+ INPUT: const pool index in %eax
+ OUTPUT: resolved string in %eax
+ The only register that is still live after this function is ebx
+ 2> class_resolve
+ INPUT: const pool index in %eax
+ OUTPUT: resolved class in %eax
+ The only register that is still live after this function is ebx
+*/
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "Lower.h"
+#include "NcgAot.h"
+#include "enc_wrapper.h"
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+
+//! LOWER bytecode CONST_STRING without usage of helper function
+
+//! It calls const_string_resolve (%ebx is live across the call)
+//! Since the register allocator does not handle control flow within the lowered native sequence,
+//! we define an interface between the lowering module and register allocator:
+//! rememberState, gotoState, transferToState
+//! to make sure at the control flow merge point the state of registers is the same
+int const_string_common_nohelper(u4 tmp, u2 vA) {
+ /* for trace-based JIT, the string is already resolved since this code has been executed */
+ void *strPtr = (void*)
+ (currentMethod->clazz->pDvmDex->pResStrings[tmp]);
+ assert(strPtr != NULL);
+ set_VR_to_imm(vA, OpndSize_32, (int) strPtr );
+ return 0;
+}
+//! dispatcher to select either const_string_common_helper or const_string_common_nohelper
+
+//!
+int const_string_common(u4 tmp, u2 vA) {
+ return const_string_common_nohelper(tmp, vA);
+}
+#undef P_GPR_1
+#undef P_GPR_2
+
+//! lower bytecode CONST_4
+
+//!
+int op_const_4() {
+ u2 vA = INST_A(inst);
+ s4 tmp = (s4) (INST_B(inst) << 28) >> 28;
+ set_VR_to_imm(vA, OpndSize_32, tmp);
+ rPC += 1;
+ return 1;
+}
+//! lower bytecode CONST_16
+
+//!
+int op_const_16() {
+ u2 BBBB = FETCH(1);
+ u2 vA = INST_AA(inst);
+ set_VR_to_imm(vA, OpndSize_32, (s2)BBBB);
+ rPC += 2;
+ return 1;
+}
+//! lower bytecode CONST
+
+//!
+int op_const() {
+ u2 vA = INST_AA(inst);
+ u4 tmp = FETCH(1);
+ tmp |= (u4)FETCH(2) << 16;
+ set_VR_to_imm(vA, OpndSize_32, (s4)tmp);
+ rPC += 3;
+ return 1;
+}
+//! lower bytecode CONST_HIGH16
+
+//!
+int op_const_high16() {
+ u2 vA = INST_AA(inst);
+ u2 tmp = FETCH(1);
+ set_VR_to_imm(vA, OpndSize_32, (s4)tmp<<16); //??
+ rPC += 2;
+ return 1;
+}
+//! lower bytecode CONST_WIDE_16
+
+//!
+int op_const_wide_16() {
+ u2 vA = INST_AA(inst);
+ u2 tmp = FETCH(1);
+ set_VR_to_imm(vA, OpndSize_32, (s2)tmp);
+ set_VR_to_imm(vA+1, OpndSize_32, (s2)tmp>>31);
+ rPC += 2;
+ return 2;
+}
+//! lower bytecode CONST_WIDE_32
+
+//!
+int op_const_wide_32() {
+ u2 vA = INST_AA(inst);
+ u4 tmp = FETCH(1);
+ tmp |= (u4)FETCH(2) << 16;
+ set_VR_to_imm(vA, OpndSize_32, (s4)tmp);
+ set_VR_to_imm(vA+1, OpndSize_32, (s4)tmp>>31);
+ rPC += 3;
+ return 2;
+}
+//! lower bytecode CONST_WIDE
+
+//!
+int op_const_wide() {
+ u2 vA = INST_AA(inst);
+ u4 tmp = FETCH(1);
+ tmp |= (u8)FETCH(2) << 16;
+ set_VR_to_imm(vA, OpndSize_32, (s4)tmp);
+ tmp = (u8)FETCH(3);
+ tmp |= (u8)FETCH(4) << 16;
+ set_VR_to_imm(vA+1, OpndSize_32, (s4)tmp);
+ rPC += 5;
+ return 2;
+}
+//! lower bytecode CONST_WIDE_HIGH16
+
+//!
+int op_const_wide_high16() {
+ u2 vA = INST_AA(inst);
+ u2 tmp = FETCH(1);
+ set_VR_to_imm(vA, OpndSize_32, 0);
+ set_VR_to_imm(vA+1, OpndSize_32, (s4)tmp<<16);
+ rPC += 2;
+ return 2;
+}
+//! lower bytecode CONST_STRING
+
+//!
+int op_const_string() {
+ u2 vB = FETCH(1);
+ u2 vA = INST_AA(inst);
+ u4 tmp = vB;
+ int retval = const_string_common(tmp, vA);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode CONST_STRING_JUMBO
+
+//!
+int op_const_string_jumbo() {
+ u2 vA = INST_AA(inst);
+ u4 tmp = FETCH(1);
+ tmp |= (u4)FETCH(2) << 16;
+ int retval = const_string_common(tmp, vA);
+ rPC += 3;
+ return retval;
+}
+
+#define P_GPR_1 PhysicalReg_EBX
+//! LOWER bytecode CONST_CLASS
+
+//! It calls class_resolve (%ebx is live across the call)
+//! Since the register allocator does not handle control flow within the lowered native sequence,
+//! we define an interface between the lowering module and register allocator:
+//! rememberState, gotoState, transferToState
+//! to make sure at the control flow merge point the state of registers is the same
+int op_const_class() {
+ u2 vA = INST_AA(inst);
+ u4 tmp = (u4)FETCH(1);
+ /* for trace-based JIT, the class is already resolved since this code has been executed */
+ void *classPtr = (void*)
+ (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
+ assert(classPtr != NULL);
+ set_VR_to_imm(vA, OpndSize_32, (int) classPtr );
+ rPC += 2;
+ return 0;
+}
+
+#undef P_GPR_1
+
diff --git a/vm/compiler/codegen/x86/LowerGetPut.cpp b/vm/compiler/codegen/x86/LowerGetPut.cpp
new file mode 100644
index 0000000..c87b174
--- /dev/null
+++ b/vm/compiler/codegen/x86/LowerGetPut.cpp
@@ -0,0 +1,933 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file LowerGetPut.cpp
+ \brief This file lowers the following bytecodes: XGET|PUT_XXX
+*/
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "Lower.h"
+#include "NcgAot.h"
+#include "enc_wrapper.h"
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_ESI
+#define P_GPR_4 PhysicalReg_EDX
+//! LOWER bytecode AGET without usage of helper function
+
+//! It has null check and length check
+int aget_common_nohelper(int flag, u2 vA, u2 vref, u2 vindex) {
+ ////////////////////////////
+ // Request VR free delays before register allocation for the temporaries
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK))
+ requestVRFreeDelay(vref,VRDELAY_NULLCHECK);
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ requestVRFreeDelay(vref,VRDELAY_BOUNDCHECK);
+ requestVRFreeDelay(vindex,VRDELAY_BOUNDCHECK);
+ }
+
+ get_virtual_reg(vref, OpndSize_32, 1, false); //array
+ get_virtual_reg(vindex, OpndSize_32, 2, false); //index
+
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
+ //last argument is the exception number for this bytecode
+ nullCheck(1, false, 1, vref); //maybe optimized away, if not, call
+ cancelVRFreeDelayRequest(vref,VRDELAY_NULLCHECK);
+ } else {
+ updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
+ }
+
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ boundCheck(vref, 1, false,
+ vindex, 2, false,
+ 2);
+ cancelVRFreeDelayRequest(vref,VRDELAY_BOUNDCHECK);
+ cancelVRFreeDelayRequest(vindex,VRDELAY_BOUNDCHECK);
+ } else {
+ updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
+ updateRefCount2(2, LowOpndRegType_gp, false); //update reference count for tmp2
+ }
+
+ if(flag == AGET) {
+ move_mem_disp_scale_to_reg(OpndSize_32, 1, false, offArrayObject_contents, 2, false, 4, 4, false);
+ }
+ else if(flag == AGET_WIDE) {
+ move_mem_disp_scale_to_reg(OpndSize_64, 1, false, offArrayObject_contents, 2, false, 8, 1, false);
+ }
+ else if(flag == AGET_CHAR) {
+ movez_mem_disp_scale_to_reg(OpndSize_16, 1, false, offArrayObject_contents, 2, false, 2, 4, false);
+ }
+ else if(flag == AGET_SHORT) {
+ moves_mem_disp_scale_to_reg(OpndSize_16, 1, false, offArrayObject_contents, 2, false, 2, 4, false);
+ }
+ else if(flag == AGET_BOOLEAN) {
+ movez_mem_disp_scale_to_reg(OpndSize_8, 1, false, offArrayObject_contents, 2, false, 1, 4, false);
+ }
+ else if(flag == AGET_BYTE) {
+ moves_mem_disp_scale_to_reg(OpndSize_8, 1, false, offArrayObject_contents, 2, false, 1, 4, false);
+ }
+ if(flag == AGET_WIDE) {
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ }
+ else {
+ set_virtual_reg(vA, OpndSize_32, 4, false);
+ }
+ //////////////////////////////////
+ return 0;
+}
+//! wrapper to call either aget_common_helper or aget_common_nohelper
+
+//!
+int aget_common(int flag, u2 vA, u2 vref, u2 vindex) {
+ return aget_common_nohelper(flag, vA, vref, vindex);
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef P_GPR_4
+//! lower bytecode AGET by calling aget_common
+
+//!
+int op_aget() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aget_common(AGET, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode AGET_WIDE by calling aget_common
+
+//!
+int op_aget_wide() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aget_common(AGET_WIDE, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode AGET_OBJECT by calling aget_common
+
+//!
+int op_aget_object() {
+ return op_aget();
+}
+//! lower bytecode BOOLEAN by calling aget_common
+
+//!
+int op_aget_boolean() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aget_common(AGET_BOOLEAN, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode AGET_BYTE by calling aget_common
+
+//!
+int op_aget_byte() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aget_common(AGET_BYTE, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode AGET_CHAR by calling aget_common
+
+//!
+int op_aget_char() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aget_common(AGET_CHAR, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode AGET_SHORT by calling aget_common
+
+//!
+int op_aget_short() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aget_common(AGET_SHORT, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_ESI
+#define P_GPR_4 PhysicalReg_EDX
+//! LOWER bytecode APUT without usage of helper function
+
+//! It has null check and length check
+int aput_common_nohelper(int flag, u2 vA, u2 vref, u2 vindex) {
+ //////////////////////////////////////
+ // Request VR free delays before register allocation for the temporaries.
+ // No need to request delay for vA since it will be transferred to temporary
+ // after the null check and bound check.
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK))
+ requestVRFreeDelay(vref,VRDELAY_NULLCHECK);
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ requestVRFreeDelay(vref,VRDELAY_BOUNDCHECK);
+ requestVRFreeDelay(vindex,VRDELAY_BOUNDCHECK);
+ }
+
+ get_virtual_reg(vref, OpndSize_32, 1, false); //array
+ get_virtual_reg(vindex, OpndSize_32, 2, false); //index
+
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
+ //last argument is the exception number for this bytecode
+ nullCheck(1, false, 1, vref); //maybe optimized away, if not, call
+ cancelVRFreeDelayRequest(vref,VRDELAY_NULLCHECK);
+ } else {
+ updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
+ }
+
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ boundCheck(vref, 1, false,
+ vindex, 2, false,
+ 2);
+ cancelVRFreeDelayRequest(vref,VRDELAY_BOUNDCHECK);
+ cancelVRFreeDelayRequest(vindex,VRDELAY_BOUNDCHECK);
+ } else {
+ updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
+ updateRefCount2(2, LowOpndRegType_gp, false); //update reference count for tmp2
+ }
+
+ if(flag == APUT_WIDE) {
+ get_virtual_reg(vA, OpndSize_64, 1, false);
+ }
+ else {
+ get_virtual_reg(vA, OpndSize_32, 4, false);
+ }
+ if(flag == APUT)
+ move_reg_to_mem_disp_scale(OpndSize_32, 4, false, 1, false, offArrayObject_contents, 2, false, 4);
+ else if(flag == APUT_WIDE)
+ move_reg_to_mem_disp_scale(OpndSize_64, 1, false, 1, false, offArrayObject_contents, 2, false, 8);
+ else if(flag == APUT_CHAR || flag == APUT_SHORT)
+ move_reg_to_mem_disp_scale(OpndSize_16, 4, false, 1, false, offArrayObject_contents, 2, false, 2);
+ else if(flag == APUT_BOOLEAN || flag == APUT_BYTE)
+ move_reg_to_mem_disp_scale(OpndSize_8, 4, false, 1, false, offArrayObject_contents, 2, false, 1);
+ //////////////////////////////////
+ return 0;
+}
+//! wrapper to call either aput_common_helper or aput_common_nohelper
+
+//!
+int aput_common(int flag, u2 vA, u2 vref, u2 vindex) {
+ return aput_common_nohelper(flag, vA, vref, vindex);
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef P_GPR_4
+//! lower bytecode APUT by calling aput_common
+
+//!
+int op_aput() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aput_common(APUT, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode APUT_WIDE by calling aput_common
+
+//!
+int op_aput_wide() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aput_common(APUT_WIDE, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode APUT_BOOLEAN by calling aput_common
+
+//!
+int op_aput_boolean() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aput_common(APUT_BOOLEAN, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode APUT_BYTE by calling aput_common
+
+//!
+int op_aput_byte() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aput_common(APUT_BYTE, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode APUT_CHAR by calling aput_common
+
+//!
+int op_aput_char() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aput_common(APUT_CHAR, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode APUT_SHORT by calling aput_common
+
+//!
+int op_aput_short() {
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+ int retval = aput_common(APUT_SHORT, vA, vref, vindex);
+ rPC += 2;
+ return retval;
+}
+
+#define P_GPR_1 PhysicalReg_EBX //callee-saved valid after CanPutArray
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_ESI //callee-saved
+#define P_SCRATCH_1 PhysicalReg_EDX
+#define P_SCRATCH_2 PhysicalReg_EAX
+#define P_SCRATCH_3 PhysicalReg_EDX
+
+void markCard_notNull(int tgtAddrReg, int scratchReg, bool isPhysical);
+
+//! lower bytecode APUT_OBJECT
+
+//! Lower the bytecode using helper function ".aput_obj_helper" if helper switch is on
+int op_aput_object() { //type checking
+ u2 vA = INST_AA(inst);
+ u2 vref = FETCH(1) & 0xff;
+ u2 vindex = FETCH(1) >> 8;
+
+ ///////////////////////////
+ // Request VR free delays before register allocation for the temporaries
+ // No need to request delay for vA since it will be transferred to temporary
+ // after the null check and bound check.
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK))
+ requestVRFreeDelay(vref,VRDELAY_NULLCHECK);
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ requestVRFreeDelay(vref,VRDELAY_BOUNDCHECK);
+ requestVRFreeDelay(vindex,VRDELAY_BOUNDCHECK);
+ }
+
+ get_virtual_reg(vref, OpndSize_32, 1, false); //array
+ export_pc(); //use %edx
+
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
+ compare_imm_reg(OpndSize_32, 0, 1, false);
+ conditional_jump_global_API(Condition_E, "common_errNullObject", false);
+ cancelVRFreeDelayRequest(vref,VRDELAY_NULLCHECK);
+ } else {
+ updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
+ }
+
+ get_virtual_reg(vindex, OpndSize_32, 2, false); //index
+ if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ compare_mem_reg(OpndSize_32, offArrayObject_length, 1, false, 2, false);
+ conditional_jump_global_API(Condition_NC, "common_errArrayIndex", false);
+ cancelVRFreeDelayRequest(vref,VRDELAY_BOUNDCHECK);
+ cancelVRFreeDelayRequest(vindex,VRDELAY_BOUNDCHECK);
+ } else {
+ updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
+ updateRefCount2(2, LowOpndRegType_gp, false); //update reference count for tmp2
+ }
+
+ get_virtual_reg(vA, OpndSize_32, 4, false);
+ compare_imm_reg(OpndSize_32, 0, 4, false);
+ conditional_jump(Condition_E, ".aput_object_skip_check", true);
+ rememberState(1);
+ move_mem_to_reg(OpndSize_32, offObject_clazz, 4, false, 5, false);
+ load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 5, false, 0, PhysicalReg_ESP, true);
+ move_mem_to_reg(OpndSize_32, offObject_clazz, 1, false, 6, false);
+ move_reg_to_mem(OpndSize_32, 6, false, 4, PhysicalReg_ESP, true);
+
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ call_dvmCanPutArrayElement(); //scratch??
+ load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump_global_API(Condition_E, "common_errArrayStore", false);
+
+ //NOTE: "2, false" is live through function call
+ move_reg_to_mem_disp_scale(OpndSize_32, 4, false, 1, false, offArrayObject_contents, 2, false, 4);
+ markCard_notNull(1, 11, false);
+ rememberState(2);
+ ////TODO NCG O1 + code cache
+ unconditional_jump(".aput_object_after_check", true);
+
+ insertLabel(".aput_object_skip_check", true);
+ goToState(1);
+ //NOTE: "2, false" is live through function call
+ move_reg_to_mem_disp_scale(OpndSize_32, 4, false, 1, false, offArrayObject_contents, 2, false, 4);
+
+ transferToState(2);
+ insertLabel(".aput_object_after_check", true);
+ ///////////////////////////////
+ rPC += 2;
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef P_SCRATCH_1
+#undef P_SCRATCH_2
+#undef P_SCRATCH_3
+
+//////////////////////////////////////////
+#define P_GPR_1 PhysicalReg_ECX
+#define P_GPR_2 PhysicalReg_EBX //should be callee-saved to avoid overwritten by inst_field_resolve
+#define P_GPR_3 PhysicalReg_ESI
+#define P_SCRATCH_1 PhysicalReg_EDX
+
+/*
+ movl offThread_cardTable(self), scratchReg
+ compare_imm_reg 0, valReg (testl valReg, valReg)
+ je .markCard_skip
+ shrl $GC_CARD_SHIFT, tgtAddrReg
+ movb %, (scratchReg, tgtAddrReg)
+ NOTE: scratchReg can be accessed with the corresponding byte
+ tgtAddrReg will be updated
+ for O1, update the corresponding reference count
+*/
+void markCard(int valReg, int tgtAddrReg, bool targetPhysical, int scratchReg, bool isPhysical) {
+ get_self_pointer(PhysicalReg_SCRATCH_6, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, cardTable), PhysicalReg_SCRATCH_6, isScratchPhysical, scratchReg, isPhysical);
+ compare_imm_reg(OpndSize_32, 0, valReg, isPhysical);
+ conditional_jump(Condition_E, ".markCard_skip", true);
+ alu_binary_imm_reg(OpndSize_32, shr_opc, GC_CARD_SHIFT, tgtAddrReg, targetPhysical);
+ move_reg_to_mem_disp_scale(OpndSize_8, scratchReg, isPhysical, scratchReg, isPhysical, 0, tgtAddrReg, targetPhysical, 1);
+ insertLabel(".markCard_skip", true);
+}
+
+void markCard_notNull(int tgtAddrReg, int scratchReg, bool isPhysical) {
+ get_self_pointer(PhysicalReg_SCRATCH_2, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, cardTable), PhysicalReg_SCRATCH_2, isScratchPhysical, scratchReg, isPhysical);
+ alu_binary_imm_reg(OpndSize_32, shr_opc, GC_CARD_SHIFT, tgtAddrReg, isPhysical);
+ move_reg_to_mem_disp_scale(OpndSize_8, scratchReg, isPhysical, scratchReg, isPhysical, 0, tgtAddrReg, isPhysical, 1);
+}
+
+void markCard_filled(int tgtAddrReg, bool isTgtPhysical, int scratchReg, bool isScratchPhysical) {
+ get_self_pointer(PhysicalReg_SCRATCH_2, false/*isPhysical*/);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, cardTable), PhysicalReg_SCRATCH_2, isScratchPhysical, scratchReg, isScratchPhysical);
+ alu_binary_imm_reg(OpndSize_32, shr_opc, GC_CARD_SHIFT, tgtAddrReg, isTgtPhysical);
+ move_reg_to_mem_disp_scale(OpndSize_8, scratchReg, isScratchPhysical, scratchReg, isScratchPhysical, 0, tgtAddrReg, isTgtPhysical, 1);
+}
+//! LOWER bytecode IGET,IPUT without usage of helper function
+
+//! It has null check and calls assembly function inst_field_resolve
+int iget_iput_common_nohelper(int tmp, int flag, u2 vA, u2 vB, int isObj, bool isVolatile) {
+#ifdef WITH_JIT_INLINING
+ const Method *method = (traceCurrentMIR->OptimizationFlags & MIR_CALLEE) ?
+ traceCurrentMIR->meta.calleeMethod : currentMethod;
+ InstField *pInstField = (InstField *)
+ method->clazz->pDvmDex->pResFields[tmp];
+#else
+ InstField *pInstField = (InstField *)
+ currentMethod->clazz->pDvmDex->pResFields[tmp];
+#endif
+ int fieldOffset;
+
+ assert(pInstField != NULL);
+ fieldOffset = pInstField->byteOffset;
+ move_imm_to_reg(OpndSize_32, fieldOffset, 8, false);
+ // Request VR delay before transfer to temporary. Only vB needs delay.
+ // vA will have non-zero reference count since transfer to temporary for
+ // it happens after null check, thus no delay is needed.
+ requestVRFreeDelay(vB,VRDELAY_NULLCHECK);
+ get_virtual_reg(vB, OpndSize_32, 7, false);
+ nullCheck(7, false, 2, vB); //maybe optimized away, if not, call
+ cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
+ if(flag == IGET) {
+ move_mem_scale_to_reg(OpndSize_32, 7, false, 8, false, 1, 9, false);
+ set_virtual_reg(vA, OpndSize_32, 9, false);
+#ifdef DEBUG_IGET_OBJ
+ if(isObj > 0) {
+ pushAllRegs();
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 9, false, 12, PhysicalReg_ESP, true); //field
+ move_reg_to_mem(OpndSize_32, 7, false, 8, PhysicalReg_ESP, true); //object
+ move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true); //field
+ move_imm_to_mem(OpndSize_32, 0, 0, PhysicalReg_ESP, true); //iget
+ call_dvmDebugIgetIput();
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ popAllRegs();
+ }
+#endif
+ } else if(flag == IGET_WIDE) {
+ if(isVolatile) {
+ /* call dvmQuasiAtomicRead64(addr) */
+ load_effective_addr(fieldOffset, 7, false, 9, false);
+ move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //1st argument
+ load_effective_addr(-4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ nextVersionOfHardReg(PhysicalReg_EAX, 2);
+ nextVersionOfHardReg(PhysicalReg_EDX, 2);
+ scratchRegs[0] = PhysicalReg_SCRATCH_3;
+ call_dvmQuasiAtomicRead64();
+ load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ //memory content in %edx, %eax
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
+ set_virtual_reg(vA+1, OpndSize_32, PhysicalReg_EDX, true);
+ } else {
+ move_mem_scale_to_reg(OpndSize_64, 7, false, 8, false, 1, 1, false); //access field
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ }
+ } else if(flag == IPUT) {
+ get_virtual_reg(vA, OpndSize_32, 9, false);
+ move_reg_to_mem_scale(OpndSize_32, 9, false, 7, false, 8, false, 1); //access field
+ if(isObj) {
+ markCard(9, 7, false, 11, false);
+ }
+ } else if(flag == IPUT_WIDE) {
+ get_virtual_reg(vA, OpndSize_64, 1, false);
+ if(isVolatile) {
+ /* call dvmQuasiAtomicSwap64(val, addr) */
+ load_effective_addr(fieldOffset, 7, false, 9, false);
+ move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //2nd argument
+ move_reg_to_mem(OpndSize_64, 1, false, -12, PhysicalReg_ESP, true); //1st argument
+ load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_3;
+ call_dvmQuasiAtomicSwap64();
+ load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ }
+ else {
+ move_reg_to_mem_scale(OpndSize_64, 1, false, 7, false, 8, false, 1);
+ }
+ }
+ ///////////////////////////
+ return 0;
+}
+//! wrapper to call either iget_iput_common_helper or iget_iput_common_nohelper
+
+//!
+int iget_iput_common(int tmp, int flag, u2 vA, u2 vB, int isObj, bool isVolatile) {
+ return iget_iput_common_nohelper(tmp, flag, vA, vB, isObj, isVolatile);
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef P_SCRATCH_1
+//! lower bytecode IGET by calling iget_iput_common
+
+//!
+int op_iget() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ u2 tmp = FETCH(1);
+ int retval = iget_iput_common(tmp, IGET, vA, vB, 0, false);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode IGET_WIDE by calling iget_iput_common
+
+//!
+int op_iget_wide(bool isVolatile) {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ u2 tmp = FETCH(1);
+ int retval = iget_iput_common(tmp, IGET_WIDE, vA, vB, 0, isVolatile);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode IGET_OBJECT by calling iget_iput_common
+
+//!
+int op_iget_object() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ u2 tmp = FETCH(1);
+ int retval = iget_iput_common(tmp, IGET, vA, vB, 1, false);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode IGET_BOOLEAN by calling iget_iput_common
+
+//!
+int op_iget_boolean() {
+ return op_iget();
+}
+//! lower bytecode IGET_BYTE by calling iget_iput_common
+
+//!
+int op_iget_byte() {
+ return op_iget();
+}
+//! lower bytecode IGET_CHAR by calling iget_iput_common
+
+//!
+int op_iget_char() {
+ return op_iget();
+}
+//! lower bytecode IGET_SHORT by calling iget_iput_common
+
+//!
+int op_iget_short() {
+ return op_iget();
+}
+//! lower bytecode IPUT by calling iget_iput_common
+
+//!
+int op_iput() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ u2 tmp = FETCH(1);
+ int retval = iget_iput_common(tmp, IPUT, vA, vB, 0, false);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode IPUT_WIDE by calling iget_iput_common
+
+//!
+int op_iput_wide(bool isVolatile) {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ u2 tmp = FETCH(1);
+ int retval = iget_iput_common(tmp, IPUT_WIDE, vA, vB, 0, isVolatile);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode IPUT_OBJECT by calling iget_iput_common
+
+//!
+int op_iput_object() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ u2 tmp = FETCH(1);
+ int retval = iget_iput_common(tmp, IPUT, vA, vB, 1, false);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode IPUT_BOOLEAN by calling iget_iput_common
+
+//!
+int op_iput_boolean() {
+ return op_iput();
+}
+//! lower bytecode IPUT_BYTE by calling iget_iput_common
+
+//!
+int op_iput_byte() {
+ return op_iput();
+}
+//! lower bytecode IPUT_CHAR by calling iget_iput_common
+
+//!
+int op_iput_char() {
+ return op_iput();
+}
+//! lower bytecode IPUT_SHORT by calling iget_iput_common
+
+//!
+int op_iput_short() {
+ return op_iput();
+}
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_EDX //used by helper only
+
+//! common section to lower IGET & IPUT
+
+//! It will use helper function sget_helper if the switch is on
+int sget_sput_common(int flag, u2 vA, u2 tmp, bool isObj, bool isVolatile) {
+ //call assembly static_field_resolve
+ //no exception
+ //glue: get_res_fields
+ //hard-coded: eax (one version?)
+ //////////////////////////////////////////
+#ifdef WITH_JIT_INLINING
+ const Method *method = (traceCurrentMIR->OptimizationFlags & MIR_CALLEE) ? traceCurrentMIR->meta.calleeMethod : currentMethod;
+ void *fieldPtr = (void*)
+ (method->clazz->pDvmDex->pResFields[tmp]);
+#else
+ void *fieldPtr = (void*)
+ (currentMethod->clazz->pDvmDex->pResFields[tmp]);
+#endif
+ assert(fieldPtr != NULL);
+ move_imm_to_reg(OpndSize_32, (int)fieldPtr, PhysicalReg_EAX, true);
+ if(flag == SGET) {
+ move_mem_to_reg(OpndSize_32, offStaticField_value, PhysicalReg_EAX, true, 7, false); //access field
+ set_virtual_reg(vA, OpndSize_32, 7, false);
+ } else if(flag == SGET_WIDE) {
+ if(isVolatile) {
+ /* call dvmQuasiAtomicRead64(addr) */
+ load_effective_addr(offStaticField_value, PhysicalReg_EAX, true, 9, false);
+ move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //1st argument
+ load_effective_addr(-4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ nextVersionOfHardReg(PhysicalReg_EAX, 2);
+ nextVersionOfHardReg(PhysicalReg_EDX, 2);
+ scratchRegs[0] = PhysicalReg_SCRATCH_3;
+ call_dvmQuasiAtomicRead64();
+ load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ //memory content in %edx, %eax
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
+ set_virtual_reg(vA+1, OpndSize_32, PhysicalReg_EDX, true);
+ }
+ else {
+ move_mem_to_reg(OpndSize_64, offStaticField_value, PhysicalReg_EAX, true, 1, false); //access field
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ }
+ } else if(flag == SPUT) {
+ get_virtual_reg(vA, OpndSize_32, 7, false);
+ move_reg_to_mem(OpndSize_32, 7, false, offStaticField_value, PhysicalReg_EAX, true); //access field
+ if(isObj) {
+ /* get clazz object, then use clazz object to mark card */
+ move_mem_to_reg(OpndSize_32, offField_clazz, PhysicalReg_EAX, true, 12, false);
+ markCard(7/*valReg*/, 12, false, 11, false);
+ }
+ } else if(flag == SPUT_WIDE) {
+ get_virtual_reg(vA, OpndSize_64, 1, false);
+ if(isVolatile) {
+ /* call dvmQuasiAtomicSwap64(val, addr) */
+ load_effective_addr(offStaticField_value, PhysicalReg_EAX, true, 9, false);
+ move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //2nd argument
+ move_reg_to_mem(OpndSize_64, 1, false, -12, PhysicalReg_ESP, true); //1st argument
+ load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_3;
+ call_dvmQuasiAtomicSwap64();
+ load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ }
+ else {
+ move_reg_to_mem(OpndSize_64, 1, false, offStaticField_value, PhysicalReg_EAX, true); //access field
+ }
+ }
+ //////////////////////////////////////////////
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+//! lower bytecode SGET by calling sget_sput_common
+
+//!
+int op_sget() {
+ u2 vA = INST_AA(inst);
+ u2 tmp = FETCH(1);
+ int retval = sget_sput_common(SGET, vA, tmp, false, false);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SGET_WIDE by calling sget_sput_common
+
+//!
+int op_sget_wide(bool isVolatile) {
+ u2 vA = INST_AA(inst);
+ u2 tmp = FETCH(1);
+ int retval = sget_sput_common(SGET_WIDE, vA, tmp, false, isVolatile);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SGET_OBJECT by calling sget_sput_common
+
+//!
+int op_sget_object() {
+ return op_sget();
+}
+//! lower bytecode SGET_BOOLEAN by calling sget_sput_common
+
+//!
+int op_sget_boolean() {
+ return op_sget();
+}
+//! lower bytecode SGET_BYTE by calling sget_sput_common
+
+//!
+int op_sget_byte() {
+ return op_sget();
+}
+//! lower bytecode SGET_CHAR by calling sget_sput_common
+
+//!
+int op_sget_char() {
+ return op_sget();
+}
+//! lower bytecode SGET_SHORT by calling sget_sput_common
+
+//!
+int op_sget_short() {
+ return op_sget();
+}
+//! lower bytecode SPUT by calling sget_sput_common
+
+//!
+int op_sput(bool isObj) {
+ u2 vA = INST_AA(inst);
+ u2 tmp = FETCH(1);
+ int retval = sget_sput_common(SPUT, vA, tmp, isObj, false);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SPUT_WIDE by calling sget_sput_common
+
+//!
+int op_sput_wide(bool isVolatile) {
+ u2 vA = INST_AA(inst);
+ u2 tmp = FETCH(1);
+ int retval = sget_sput_common(SPUT_WIDE, vA, tmp, false, isVolatile);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode SPUT_OBJECT by calling sget_sput_common
+
+//!
+int op_sput_object() {
+ return op_sput(true);
+}
+//! lower bytecode SPUT_OBJECT by calling sget_sput_common
+
+//!
+int op_sput_boolean() {
+ return op_sput(false);
+}
+//! lower bytecode SPUT_BOOLEAN by calling sget_sput_common
+
+//!
+int op_sput_byte() {
+ return op_sput(false);
+}
+//! lower bytecode SPUT_BYTE by calling sget_sput_common
+
+//!
+int op_sput_char() {
+ return op_sput(false);
+}
+//! lower bytecode SPUT_SHORT by calling sget_sput_common
+
+//!
+int op_sput_short() {
+ return op_sput(false);
+}
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+//! lower bytecode IGET_QUICK
+
+//!
+int op_iget_quick() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst); //object
+ u2 tmp = FETCH(1);
+
+ requestVRFreeDelay(vB,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ nullCheck(1, false, 1, vB); //maybe optimized away, if not, call
+ cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
+
+ move_mem_to_reg(OpndSize_32, tmp, 1, false, 2, false);
+ set_virtual_reg(vA, OpndSize_32, 2, false);
+ rPC += 2;
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#define P_GPR_1 PhysicalReg_EBX
+//! lower bytecode IGET_WIDE_QUICK
+
+//!
+int op_iget_wide_quick() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst); //object
+ u2 tmp = FETCH(1);
+
+ requestVRFreeDelay(vB,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ nullCheck(1, false, 1, vB); //maybe optimized away, if not, call
+ cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
+
+ move_mem_to_reg(OpndSize_64, tmp, 1, false, 1, false);
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ rPC += 2;
+ return 0;
+}
+#undef P_GPR_1
+//! lower bytecode IGET_OBJECT_QUICK
+
+//!
+int op_iget_object_quick() {
+ return op_iget_quick();
+}
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+//! lower bytecode IPUT_QUICK
+
+//!
+int iput_quick_common(bool isObj) {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst); //object
+ u2 tmp = FETCH(1);
+
+ // Request VR delay before transfer to temporary. Only vB needs delay.
+ // vA will have non-zero reference count since transfer to temporary for
+ // it happens after null check, thus no delay is needed.
+ requestVRFreeDelay(vB,VRDELAY_NULLCHECK);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ nullCheck(1, false, 1, vB); //maybe optimized away, if not, call
+ cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
+
+ get_virtual_reg(vA, OpndSize_32, 2, false);
+ move_reg_to_mem(OpndSize_32, 2, false, tmp, 1, false);
+ if(isObj) {
+ markCard(2/*valReg*/, 1, false, 11, false);
+ }
+ rPC += 2;
+ return 0;
+}
+int op_iput_quick() {
+ return iput_quick_common(false);
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#define P_GPR_1 PhysicalReg_EBX
+//! lower bytecode IPUT_WIDE_QUICK
+
+//!
+int op_iput_wide_quick() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst); //object
+ u2 tmp = FETCH(1); //byte offset
+
+ // Request VR delay before transfer to temporary. Only vB needs delay.
+ // vA will have non-zero reference count since transfer to temporary for
+ // it happens after null check, thus no delay is needed.
+ requestVRFreeDelay(vB,VRDELAY_NULLCHECK);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ nullCheck(1, false, 1, vB); //maybe optimized away, if not, call
+ cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
+
+ get_virtual_reg(vA, OpndSize_64, 1, false);
+ move_reg_to_mem(OpndSize_64, 1, false, tmp, 1, false);
+ rPC += 2;
+ return 0;
+}
+#undef P_GPR_1
+//! lower bytecode IPUT_OBJECT_QUICK
+
+//!
+int op_iput_object_quick() {
+ return iput_quick_common(true);
+}
+
diff --git a/vm/compiler/codegen/x86/LowerHelper.cpp b/vm/compiler/codegen/x86/LowerHelper.cpp
new file mode 100644
index 0000000..4539064
--- /dev/null
+++ b/vm/compiler/codegen/x86/LowerHelper.cpp
@@ -0,0 +1,2992 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file LowerHelper.cpp
+ \brief This file implements helper functions for lowering
+
+With NCG O0: all registers are hard-coded ;
+With NCG O1: the lowering module will use variables that will be allocated to a physical register by the register allocator.
+
+register types: FS 32-bit or 64-bit;
+ XMM: SS(32-bit) SD (64-bit);
+ GPR: 8-bit, 16-bit, 32-bit;
+LowOpndRegType tells whether it is gpr, xmm or fs;
+OpndSize can be OpndSize_8, OpndSize_16, OpndSize_32, OpndSize_64
+
+A single native instruction can use multiple physical registers.
+ we can't call freeReg in the middle of emitting a native instruction,
+ since it may free the physical register used by an operand and cause two operands being allocated to the same physical register.
+
+When allocating a physical register for an operand, we can't spill the operands that are already allocated. To avoid that, we call startNativeCode before each native instruction, here flag "canSpill" is set to true for each physical register;
+ when a physical register is allocated, we set its flag "canSpill" to false;
+ at end of each native instruction, call endNativeCode to set flag "canSpill" to true.
+*/
+
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "Lower.h"
+#include "NcgAot.h"
+#include "enc_wrapper.h"
+#include "vm/mterp/Mterp.h"
+#include "NcgHelper.h"
+#include <math.h>
+#include "interp/InterpState.h"
+
+extern "C" int64_t __divdi3(int64_t, int64_t);
+extern "C" int64_t __moddi3(int64_t, int64_t);
+bool isScratchPhysical;
+LowOp* lirTable[200];
+int num_lirs_in_table = 0;
+
+//4 tables are defined: GPR integer ALU ops, ALU ops in FPU, SSE 32-bit, SSE 64-bit
+//the index to the table is the opcode
+//add_opc, or_opc, adc_opc, sbb_opc,
+//and_opc, sub_opc, xor_opc, cmp_opc,
+//mul_opc, imul_opc, div_opc, idiv_opc,
+//sll_opc, srl_opc, sra, (SSE)
+//shl_opc, shr_opc, sal_opc, sar_opc, //integer shift
+//neg_opc, not_opc, andn_opc, (SSE)
+//n_alu
+//!mnemonic for integer ALU operations
+const Mnemonic map_of_alu_opcode_2_mnemonic[] = {
+ Mnemonic_ADD, Mnemonic_OR, Mnemonic_ADC, Mnemonic_SBB,
+ Mnemonic_AND, Mnemonic_SUB, Mnemonic_XOR, Mnemonic_CMP,
+ Mnemonic_MUL, Mnemonic_IMUL, Mnemonic_DIV, Mnemonic_IDIV,
+ Mnemonic_Null, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_SHL, Mnemonic_SHR, Mnemonic_SAL, Mnemonic_SAR,
+ Mnemonic_NEG, Mnemonic_NOT, Mnemonic_Null,
+ Mnemonic_Null
+};
+//!mnemonic for ALU operations in FPU
+const Mnemonic map_of_fpu_opcode_2_mnemonic[] = {
+ Mnemonic_FADD, Mnemonic_Null, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_FSUB, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_FMUL, Mnemonic_Null, Mnemonic_FDIV, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_Null, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_Null
+};
+//!mnemonic for SSE 32-bit
+const Mnemonic map_of_sse_opcode_2_mnemonic[] = {
+ Mnemonic_ADDSD, Mnemonic_Null, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_SUBSD, Mnemonic_XORPD, Mnemonic_Null,
+ Mnemonic_MULSD, Mnemonic_Null, Mnemonic_DIVSD, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_Null, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_Null
+};
+//!mnemonic for SSE 64-bit integer
+const Mnemonic map_of_64_opcode_2_mnemonic[] = {
+ Mnemonic_PADDQ, Mnemonic_POR, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_PAND, Mnemonic_PSUBQ, Mnemonic_PXOR, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_Null, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_PSLLQ, Mnemonic_PSRLQ, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_Null, Mnemonic_Null, Mnemonic_Null,
+ Mnemonic_Null, Mnemonic_Null, Mnemonic_PANDN,
+ Mnemonic_Null
+};
+
+////////////////////////////////////////////////
+//!update fields of LowOpndReg
+
+//!
+void set_reg_opnd(LowOpndReg* op_reg, int reg, bool isPhysical, LowOpndRegType type) {
+ op_reg->regType = type;
+ if(isPhysical) {
+ op_reg->logicalReg = -1;
+ op_reg->physicalReg = reg;
+ }
+ else
+ op_reg->logicalReg = reg;
+ return;
+}
+//!update fields of LowOpndMem
+
+//!
+void set_mem_opnd(LowOpndMem* mem, int disp, int base, bool isPhysical) {
+ mem->m_disp.value = disp;
+ mem->hasScale = false;
+ mem->m_base.regType = LowOpndRegType_gp;
+ if(isPhysical) {
+ mem->m_base.logicalReg = -1;
+ mem->m_base.physicalReg = base;
+ } else {
+ mem->m_base.logicalReg = base;
+ }
+ return;
+}
+//!update fields of LowOpndMem
+
+//!
+void set_mem_opnd_scale(LowOpndMem* mem, int base, bool isPhysical, int disp, int index, bool indexPhysical, int scale) {
+ mem->hasScale = true;
+ mem->m_base.regType = LowOpndRegType_gp;
+ if(isPhysical) {
+ mem->m_base.logicalReg = -1;
+ mem->m_base.physicalReg = base;
+ } else {
+ mem->m_base.logicalReg = base;
+ }
+ if(indexPhysical) {
+ mem->m_index.logicalReg = -1;
+ mem->m_index.physicalReg = index;
+ } else {
+ mem->m_index.logicalReg = index;
+ }
+ mem->m_disp.value = disp;
+ mem->m_scale.value = scale;
+ return;
+}
+//!return either LowOpndRegType_xmm or LowOpndRegType_gp
+
+//!
+inline LowOpndRegType getTypeFromIntSize(OpndSize size) {
+ return size == OpndSize_64 ? LowOpndRegType_xmm : LowOpndRegType_gp;
+}
+
+// copied from JIT compiler
+typedef struct AtomMemBlock {
+ size_t bytesAllocated;
+ struct AtomMemBlock *next;
+ char ptr[0];
+} AtomMemBlock;
+
+#define ATOMBLOCK_DEFAULT_SIZE 4096
+AtomMemBlock *atomMemHead = NULL;
+AtomMemBlock *currentAtomMem = NULL;
+void * atomNew(size_t size) {
+ lowOpTimeStamp++; //one LowOp constructed
+ if(atomMemHead == NULL) {
+ atomMemHead = (AtomMemBlock*)malloc(sizeof(AtomMemBlock) + ATOMBLOCK_DEFAULT_SIZE);
+ if(atomMemHead == NULL) {
+ ALOGE("Memory allocation failed");
+ return NULL;
+ }
+ currentAtomMem = atomMemHead;
+ currentAtomMem->bytesAllocated = 0;
+ currentAtomMem->next = NULL;
+ }
+ size = (size + 3) & ~3;
+ if (size > ATOMBLOCK_DEFAULT_SIZE) {
+ ALOGE("Requesting %d bytes which exceed the maximal size allowed", size);
+ return NULL;
+ }
+retry:
+ if (size + currentAtomMem->bytesAllocated <= ATOMBLOCK_DEFAULT_SIZE) {
+ void *ptr;
+ ptr = ¤tAtomMem->ptr[currentAtomMem->bytesAllocated];
+ return ptr;
+ }
+ if (currentAtomMem->next) {
+ currentAtomMem = currentAtomMem->next;
+ goto retry;
+ }
+ /* Time to allocate a new arena */
+ AtomMemBlock *newAtomMem = (AtomMemBlock*)malloc(sizeof(AtomMemBlock) + ATOMBLOCK_DEFAULT_SIZE);
+ if(newAtomMem == NULL) {
+ ALOGE("Memory allocation failed");
+ return NULL;
+ }
+ newAtomMem->bytesAllocated = 0;
+ newAtomMem->next = NULL;
+ currentAtomMem->next = newAtomMem;
+ currentAtomMem = newAtomMem;
+ goto retry;
+ ALOGE("atomNew requesting %d bytes", size);
+ return NULL;
+}
+
+void freeAtomMem() {
+ //LOGI("free all atom memory");
+ AtomMemBlock * tmpMem = atomMemHead;
+ while(tmpMem != NULL) {
+ tmpMem->bytesAllocated = 0;
+ tmpMem = tmpMem->next;
+ }
+ currentAtomMem = atomMemHead;
+}
+
+LowOpImm* dump_special(AtomOpCode cc, int imm) {
+ LowOpImm* op = (LowOpImm*)atomNew(sizeof(LowOpImm));
+ op->lop.opCode = Mnemonic_NULL;
+ op->lop.opCode2 = cc;
+ op->lop.opnd1.type = LowOpndType_Imm;
+ op->lop.numOperands = 1;
+ op->immOpnd.value = imm;
+ //stream = encoder_imm(m, size, imm, stream);
+ return op;
+}
+
+LowOpLabel* lower_label(Mnemonic m, OpndSize size, int imm, const char* label, bool isLocal) {
+ stream = encoder_imm(m, size, imm, stream);
+ return NULL;
+}
+
+LowOpLabel* dump_label(Mnemonic m, OpndSize size, int imm,
+ const char* label, bool isLocal) {
+ return lower_label(m, size, imm, label, isLocal);
+}
+
+LowOpNCG* dump_ncg(Mnemonic m, OpndSize size, int imm) {
+ stream = encoder_imm(m, size, imm, stream);
+ return NULL;
+}
+
+//!update fields of LowOp and generate a x86 instruction with a single immediate operand
+
+//!
+LowOpImm* lower_imm(Mnemonic m, OpndSize size, int imm, bool updateTable) {
+ stream = encoder_imm(m, size, imm, stream);
+ return NULL;
+}
+
+LowOpImm* dump_imm(Mnemonic m, OpndSize size, int imm) {
+ return lower_imm(m, size, imm, true);
+}
+
+LowOpImm* dump_imm_with_codeaddr(Mnemonic m, OpndSize size,
+ int imm, char* codePtr) {
+ encoder_imm(m, size, imm, codePtr);
+ return NULL;
+}
+
+//!update fields of LowOp and generate a x86 instruction that takes a single memory operand
+
+//!With NCG O1, we call freeReg to free up physical registers, then call registerAlloc to allocate a physical register for memory base
+LowOpMem* lower_mem(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int disp, int base_reg) {
+ stream = encoder_mem(m, size, disp, base_reg, true, stream);
+ return NULL;
+}
+
+LowOpMem* dump_mem(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ freeReg(true);
+ //type of the base is gpr
+ int regAll = registerAlloc(LowOpndRegType_gp, base_reg, isBasePhysical, true);
+ return lower_mem(m, m2, size, disp, regAll);
+ } else {
+ stream = encoder_mem(m, size, disp, base_reg, isBasePhysical, stream);
+ return NULL;
+ }
+}
+//!update fields of LowOp and generate a x86 instruction that takes a single reg operand
+
+//!With NCG O1, wecall freeReg to free up physical registers, then call registerAlloc to allocate a physical register for the single operand
+LowOpReg* lower_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int reg, LowOpndRegType type) {
+ stream = encoder_reg(m, size, reg, true, type, stream);
+ return NULL;
+}
+
+LowOpReg* dump_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int reg, bool isPhysical, LowOpndRegType type) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ freeReg(true);
+ if(m == Mnemonic_MUL || m == Mnemonic_IDIV) {
+ //these two instructions use eax & edx implicitly
+ touchEax();
+ touchEdx();
+ }
+ int regAll = registerAlloc(type, reg, isPhysical, true);
+ return lower_reg(m, m2, size, regAll, type);
+ } else {
+ stream = encoder_reg(m, size, reg, isPhysical, type, stream);
+ return NULL;
+ }
+}
+LowOpReg* dump_reg_noalloc(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical, LowOpndRegType type) {
+ return lower_reg(m, ATOM_NORMAL, size, reg, type);
+}
+
+LowOpRegReg* lower_reg_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int reg, int reg2, LowOpndRegType type) {
+ if(m == Mnemonic_FUCOMP || m == Mnemonic_FUCOM) {
+ stream = encoder_compare_fp_stack(m == Mnemonic_FUCOMP,
+ reg-reg2, size==OpndSize_64, stream);
+ }
+ else {
+ stream = encoder_reg_reg(m, size, reg, true, reg2, true, type, stream);
+ }
+ return NULL;
+}
+
+//!update fields of LowOp and generate a x86 instruction that takes two reg operands
+
+//Here, both registers are physical
+LowOpRegReg* dump_reg_reg_noalloc(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2, LowOpndRegType type) {
+ return lower_reg_reg(m, ATOM_NORMAL, size, reg, reg2, type);
+}
+
+inline bool isMnemonicMove(Mnemonic m) {
+ return (m == Mnemonic_MOV || m == Mnemonic_MOVQ ||
+ m == Mnemonic_MOVSS || m == Mnemonic_MOVSD);
+}
+//!update fields of LowOp and generate a x86 instruction that takes two reg operands
+
+//!here dst reg is already allocated to a physical reg
+//! we should not spill the physical register for dst when allocating for src
+LowOpRegReg* dump_reg_reg_noalloc_dst(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2, LowOpndRegType type) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ int regAll = registerAlloc(type, reg, isPhysical, true);
+ /* remove move from one register to the same register */
+ if(isMnemonicMove(m) && regAll == reg2) return NULL;
+ return lower_reg_reg(m, ATOM_NORMAL, size, regAll, reg2, type);
+ } else {
+ stream = encoder_reg_reg(m, size, reg, isPhysical, reg2, isPhysical2, type, stream);
+ return NULL;
+ }
+}
+//!update fields of LowOp and generate a x86 instruction that takes two reg operands
+
+//!here src reg is already allocated to a physical reg
+LowOpRegReg* dump_reg_reg_noalloc_src(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2, LowOpndRegType type) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ int regAll2;
+ if(isMnemonicMove(m) && checkTempReg2(reg2, type, isPhysical2, reg)) { //dst reg is logical
+ //only from get_virtual_reg_all
+ regAll2 = registerAllocMove(reg2, type, isPhysical2, reg);
+ } else {
+ regAll2 = registerAlloc(type, reg2, isPhysical2, true);
+ return lower_reg_reg(m, m2, size, reg, regAll2, type);
+ }
+ } else {
+ stream = encoder_reg_reg(m, size, reg, isPhysical, reg2, isPhysical2, type, stream);
+ return NULL;
+ }
+ return NULL;
+}
+//!update fields of LowOp and generate a x86 instruction that takes two reg operands
+
+//!
+LowOpRegReg* dump_reg_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2, LowOpndRegType type) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ startNativeCode(-1, -1);
+ //reg is source if m is MOV
+ freeReg(true);
+ int regAll = registerAlloc(type, reg, isPhysical, true);
+ int regAll2;
+ LowOpRegReg* op = NULL;
+#ifdef MOVE_OPT2
+ if(isMnemonicMove(m) &&
+ ((reg != PhysicalReg_EDI && reg != PhysicalReg_ESP && reg != PhysicalReg_EBP) || (!isPhysical)) &&
+ isPhysical2 == false) { //dst reg is logical
+ //called from move_reg_to_reg
+ regAll2 = registerAllocMove(reg2, type, isPhysical2, regAll);
+ } else {
+#endif
+ donotSpillReg(regAll);
+ regAll2 = registerAlloc(type, reg2, isPhysical2, true);
+ op = lower_reg_reg(m, m2, size, regAll, regAll2, type);
+#ifdef MOVE_OPT2
+ }
+#endif
+ endNativeCode();
+ return op;
+ }
+ else {
+ stream = encoder_reg_reg(m, size, reg, isPhysical, reg2, isPhysical2, type, stream);
+ }
+ return NULL;
+}
+
+LowOpRegMem* lower_mem_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int disp, int base_reg,
+ MemoryAccessType mType, int mIndex,
+ int reg, LowOpndRegType type, bool isMoves) {
+ if(m == Mnemonic_MOVSX) {
+ stream = encoder_moves_mem_to_reg(size, disp, base_reg, true,
+ reg, true, stream);
+ }
+ else if(m == Mnemonic_MOVZX) {
+ stream = encoder_movez_mem_to_reg(size, disp, base_reg, true,
+ reg, true, stream);
+ }
+ else {
+ stream = encoder_mem_reg(m, size, disp, base_reg, true,
+ reg, true, type, stream);
+ }
+ return NULL;
+}
+
+//!update fields of LowOp and generate a x86 instruction that takes one reg operand and one mem operand
+
+//!Here, operands are already allocated to physical registers
+LowOpRegMem* dump_mem_reg_noalloc(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg, bool isPhysical, LowOpndRegType type) {
+ return lower_mem_reg(m, ATOM_NORMAL, size, disp, base_reg, mType, mIndex, reg, type, false);
+}
+//!update fields of LowOp and generate a x86 instruction that takes one reg operand and one mem operand
+
+//!Here, memory operand is already allocated to physical register
+LowOpRegMem* dump_mem_reg_noalloc_mem(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg, bool isPhysical, LowOpndRegType type) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ int regAll = registerAlloc(type, reg, isPhysical, true);
+ return lower_mem_reg(m, m2, size, disp, base_reg, mType, mIndex, regAll, type, false);
+ } else {
+ stream = encoder_mem_reg(m, size, disp, base_reg, isBasePhysical,
+ reg, isPhysical, type, stream);
+ }
+ return NULL;
+}
+//!update fields of LowOp and generate a x86 instruction that takes one reg operand and one mem operand
+
+//!
+LowOpRegMem* dump_mem_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg, bool isPhysical, LowOpndRegType type) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int baseAll = registerAlloc(LowOpndRegType_gp, base_reg, isBasePhysical, true);
+ //it is okay to use the same physical register
+ if(isMnemonicMove(m)) {
+ freeReg(true);
+ } else {
+ donotSpillReg(baseAll);
+ }
+ int regAll = registerAlloc(type, reg, isPhysical, true);
+ endNativeCode();
+ return lower_mem_reg(m, m2, size, disp, baseAll, mType, mIndex, regAll, type, false);
+ } else {
+ stream = encoder_mem_reg(m, size, disp, base_reg, isBasePhysical,
+ reg, isPhysical, type, stream);
+ }
+ return NULL;
+}
+//!update fields of LowOp and generate a x86 instruction that takes one reg operand and one mem operand
+
+//!
+LowOpRegMem* dump_moves_mem_reg(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int baseAll = registerAlloc(LowOpndRegType_gp, base_reg, isBasePhysical, true);
+ donotSpillReg(baseAll);
+ int regAll = registerAlloc(LowOpndRegType_gp, reg, isPhysical, true);
+ endNativeCode();
+ return lower_mem_reg(m, ATOM_NORMAL, size, disp, baseAll, MemoryAccess_Unknown, -1,
+ regAll, LowOpndRegType_gp, true/*moves*/);
+ } else {
+ stream = encoder_moves_mem_to_reg(size, disp, base_reg, isBasePhysical, reg, isPhysical, stream);
+ }
+ return NULL;
+}
+//!update fields of LowOp and generate a x86 instruction that takes one reg operand and one mem operand
+
+//!
+LowOpRegMem* dump_movez_mem_reg(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int baseAll = registerAlloc(LowOpndRegType_gp, base_reg, isBasePhysical, true);
+ donotSpillReg(baseAll);
+ int regAll = registerAlloc(LowOpndRegType_gp, reg, isPhysical, true);
+ endNativeCode();
+ return lower_mem_reg(m, ATOM_NORMAL, size, disp, baseAll, MemoryAccess_Unknown, -1,
+ regAll, LowOpndRegType_gp, true/*moves*/);
+ } else {
+ stream = encoder_movez_mem_to_reg(size, disp, base_reg, isBasePhysical, reg, isPhysical, stream);
+ }
+ return NULL;
+}
+
+//!update fields of LowOp and generate a x86 instruction that takes one reg operand and one reg operand
+
+//!
+LowOpRegReg* dump_movez_reg_reg(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2) {
+ LowOpRegReg* op = (LowOpRegReg*)atomNew(sizeof(LowOpRegReg));
+ op->lop.opCode = m;
+ op->lop.opnd1.size = OpndSize_32;
+ op->lop.opnd1.type = LowOpndType_Reg;
+ op->lop.opnd2.size = size;
+ op->lop.opnd2.type = LowOpndType_Reg;
+ set_reg_opnd(&(op->regOpnd1), reg2, isPhysical2, LowOpndRegType_gp);
+ set_reg_opnd(&(op->regOpnd2), reg, isPhysical, LowOpndRegType_gp);
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ startNativeCode(-1, -1);
+ //reg is source if m is MOV
+ freeReg(true);
+ int regAll = registerAlloc(LowOpndRegType_gp, reg, isPhysical, true);
+ donotSpillReg(regAll);
+ int regAll2 = registerAlloc(LowOpndRegType_gp, reg2, isPhysical2, true);
+ stream = encoder_movez_reg_to_reg(size, regAll, true, regAll2, true,
+ LowOpndRegType_gp, stream);
+ endNativeCode();
+ }
+ else {
+ stream = encoder_movez_reg_to_reg(size, reg, isPhysical, reg2,
+ isPhysical2, LowOpndRegType_gp, stream);
+ }
+ return NULL;
+}
+
+//!update fields of LowOp and generate a x86 instruction that takes one reg operand and one mem operand
+
+//!
+LowOpRegMem* lower_mem_scale_reg(Mnemonic m, OpndSize size, int base_reg, int disp, int index_reg,
+ int scale, int reg, LowOpndRegType type) {
+ bool isMovzs = (m == Mnemonic_MOVZX || m == Mnemonic_MOVSX);
+ if(isMovzs)
+ stream = encoder_movzs_mem_disp_scale_reg(m, size, base_reg, true, disp, index_reg, true,
+ scale, reg, true, type, stream);
+ else {
+ if(disp == 0)
+ stream = encoder_mem_scale_reg(m, size, base_reg, true, index_reg, true,
+ scale, reg, true, type, stream);
+ else
+ stream = encoder_mem_disp_scale_reg(m, size, base_reg, true, disp, index_reg, true,
+ scale, reg, true, type, stream);
+ }
+ return NULL;
+}
+
+LowOpRegMem* dump_mem_scale_reg(Mnemonic m, OpndSize size,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical, LowOpndRegType type) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int baseAll = registerAlloc(LowOpndRegType_gp, base_reg, isBasePhysical, true);
+ donotSpillReg(baseAll); //make sure index will not use the same physical reg
+ int indexAll = registerAlloc(LowOpndRegType_gp, index_reg, isIndexPhysical, true);
+ if(isMnemonicMove(m)) {
+ freeReg(true);
+ doSpillReg(baseAll); //base can be used now
+ } else {
+ donotSpillReg(indexAll);
+ }
+ bool isMovzs = (m == Mnemonic_MOVZX || m == Mnemonic_MOVSX);
+ int regAll = registerAlloc(isMovzs ? LowOpndRegType_gp : type, reg, isPhysical, true);
+ endNativeCode();
+ return lower_mem_scale_reg(m, size, baseAll, disp, indexAll, scale, regAll, type);
+ } else {
+ stream = encoder_mem_scale_reg(m, size, base_reg, isBasePhysical, index_reg,
+ isIndexPhysical, scale, reg, isPhysical, type, stream);
+ }
+ return NULL;
+}
+//!update fields of LowOp and generate a x86 instruction that takes one reg operand and one mem operand
+
+//!
+LowOpMemReg* lower_reg_mem_scale(Mnemonic m, OpndSize size, int reg,
+ int base_reg, int disp, int index_reg, int scale, LowOpndRegType type) {
+ if(disp == 0)
+ stream = encoder_reg_mem_scale(m, size, reg, true, base_reg, true,
+ index_reg, true, scale, type, stream);
+ else
+ stream = encoder_reg_mem_disp_scale(m, size, reg, true, base_reg, true,
+ disp, index_reg, true, scale, type, stream);
+ return NULL;
+}
+
+LowOpMemReg* dump_reg_mem_scale(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ LowOpndRegType type) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int baseAll = registerAlloc(LowOpndRegType_gp, base_reg, isBasePhysical, true);
+ donotSpillReg(baseAll);
+ int indexAll = registerAlloc(LowOpndRegType_gp, index_reg, isIndexPhysical, true);
+ donotSpillReg(indexAll);
+ int regAll = registerAlloc(type, reg, isPhysical, true);
+ endNativeCode();
+ return lower_reg_mem_scale(m, size, regAll, baseAll, disp, indexAll, scale, type);
+ } else {
+ stream = encoder_reg_mem_scale(m, size, reg, isPhysical, base_reg, isBasePhysical,
+ index_reg, isIndexPhysical, scale, type, stream);
+ }
+ return NULL;
+}
+//!update fields of LowOp and generate a x86 instruction that takes one reg operand and one mem operand
+
+//!Here operands are already allocated
+LowOpMemReg* lower_reg_mem(Mnemonic m, AtomOpCode m2, OpndSize size, int reg,
+ int disp, int base_reg, MemoryAccessType mType, int mIndex,
+ LowOpndRegType type) {
+ stream = encoder_reg_mem(m, size, reg, true, disp, base_reg, true, type, stream);
+ return NULL;
+}
+
+LowOpMemReg* dump_reg_mem_noalloc(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex, LowOpndRegType type) {
+ return lower_reg_mem(m, ATOM_NORMAL, size, reg, disp, base_reg, mType, mIndex, type);
+}
+//!update fields of LowOp and generate a x86 instruction that takes one reg operand and one mem operand
+
+//!
+LowOpMemReg* dump_reg_mem(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex, LowOpndRegType type) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int baseAll = registerAlloc(LowOpndRegType_gp, base_reg, isBasePhysical, true);
+ donotSpillReg(baseAll);
+ int regAll = registerAlloc(type, reg, isPhysical, true);
+ endNativeCode();
+ return lower_reg_mem(m, m2, size, regAll, disp, baseAll, mType, mIndex, type);
+ } else {
+ stream = encoder_reg_mem(m, size, reg, isPhysical, disp, base_reg, isBasePhysical, type, stream);
+ }
+ return NULL;
+}
+//!update fields of LowOp and generate a x86 instruction that takes one immediate and one reg operand
+
+//!The reg operand is allocated already
+LowOpRegImm* lower_imm_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int imm, int reg, LowOpndRegType type, bool chaining) {
+ stream = encoder_imm_reg(m, size, imm, reg, true, type, stream);
+ return NULL;
+}
+
+LowOpRegImm* dump_imm_reg_noalloc(Mnemonic m, OpndSize size,
+ int imm, int reg, bool isPhysical, LowOpndRegType type) {
+ return lower_imm_reg(m, ATOM_NORMAL, size, imm, reg, type, false);
+}
+//!update fields of LowOp and generate a x86 instruction that takes one immediate and one reg operand
+
+//!
+LowOpRegImm* dump_imm_reg(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int imm, int reg, bool isPhysical, LowOpndRegType type, bool chaining) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ freeReg(true);
+ int regAll = registerAlloc(type, reg, isPhysical, true);
+ return lower_imm_reg(m, m2, size, imm, regAll, type, chaining);
+ } else {
+ stream = encoder_imm_reg(m, size, imm, reg, isPhysical, type, stream);
+ }
+ return NULL;
+}
+//!update fields of LowOp and generate a x86 instruction that takes one immediate and one mem operand
+
+//!The mem operand is already allocated
+LowOpMemImm* lower_imm_mem(Mnemonic m, AtomOpCode m2, OpndSize size, int imm,
+ int disp, int base_reg, MemoryAccessType mType, int mIndex,
+ bool chaining) {
+ stream = encoder_imm_mem(m, size, imm, disp, base_reg, true, stream);
+ return NULL;
+}
+
+LowOpMemImm* dump_imm_mem_noalloc(Mnemonic m, OpndSize size,
+ int imm,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex) {
+ return lower_imm_mem(m, ATOM_NORMAL, size, imm, disp, base_reg, mType, mIndex, false);
+}
+//!update fields of LowOp and generate a x86 instruction that takes one immediate and one mem operand
+
+//!
+LowOpMemImm* dump_imm_mem(Mnemonic m, AtomOpCode m2, OpndSize size,
+ int imm,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex, bool chaining) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ /* do not free register if the base is %edi, %esp, or %ebp
+ make sure dump_imm_mem will only generate a single instruction */
+ if(!isBasePhysical || (base_reg != PhysicalReg_EDI &&
+ base_reg != PhysicalReg_ESP &&
+ base_reg != PhysicalReg_EBP)) {
+ freeReg(true);
+ }
+ int baseAll = registerAlloc(LowOpndRegType_gp, base_reg, isBasePhysical, true);
+ return lower_imm_mem(m, m2, size, imm, disp, baseAll, mType, mIndex, chaining);
+ } else {
+ stream = encoder_imm_mem(m, size, imm, disp, base_reg, isBasePhysical, stream);
+ }
+ return NULL;
+}
+//!update fields of LowOp and generate a x86 instruction that uses the FP stack and takes one mem operand
+
+//!
+LowOpMemReg* lower_fp_mem(Mnemonic m, OpndSize size, int reg,
+ int disp, int base_reg, MemoryAccessType mType, int mIndex) {
+ stream = encoder_fp_mem(m, size, reg, disp, base_reg, true, stream);
+ return NULL;
+}
+
+LowOpMemReg* dump_fp_mem(Mnemonic m, OpndSize size, int reg,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ freeReg(true);
+ int baseAll = registerAlloc(LowOpndRegType_gp, base_reg, isBasePhysical, true);
+ return lower_fp_mem(m, size, reg, disp, baseAll, mType, mIndex);
+ } else {
+ stream = encoder_fp_mem(m, size, reg, disp, base_reg, isBasePhysical, stream);
+ }
+ return NULL;
+}
+//!update fields of LowOp and generate a x86 instruction that uses the FP stack and takes one mem operand
+
+//!
+LowOpRegMem* lower_mem_fp(Mnemonic m, OpndSize size, int disp, int base_reg,
+ MemoryAccessType mType, int mIndex, int reg) {
+ stream = encoder_mem_fp(m, size, disp, base_reg, true, reg, stream);
+ return NULL;
+}
+
+LowOpRegMem* dump_mem_fp(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ freeReg(true);
+ int baseAll = registerAlloc(LowOpndRegType_gp, base_reg, isBasePhysical, true);
+ return lower_mem_fp(m, size, disp, baseAll, mType, mIndex, reg);
+ } else {
+ stream = encoder_mem_fp(m, size, disp, base_reg, isBasePhysical, reg, stream);
+ }
+ return NULL;
+}
+///////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////
+//OPERAND ORDER:
+//LowOp same as EncoderBase destination first
+//parameter order of function: src first
+
+////////////////////////////////// IA32 native instructions //////////////
+//! generate a native instruction lea
+
+//!
+void load_effective_addr(int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_LEA;
+ dump_mem_reg(m, ATOM_NORMAL, OpndSize_32, disp, base_reg, isBasePhysical,
+ MemoryAccess_Unknown, -1, reg, isPhysical, LowOpndRegType_gp);
+}
+//! generate a native instruction lea
+
+//!
+void load_effective_addr_scale(int base_reg, bool isBasePhysical,
+ int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_LEA;
+ dump_mem_scale_reg(m, OpndSize_32,
+ base_reg, isBasePhysical, 0/*disp*/, index_reg, isIndexPhysical, scale,
+ reg, isPhysical, LowOpndRegType_gp);
+}
+//!fldcw
+
+//!
+void load_fpu_cw(int disp, int base_reg, bool isBasePhysical) {
+ Mnemonic m = Mnemonic_FLDCW;
+ dump_mem(m, ATOM_NORMAL, OpndSize_16, disp, base_reg, isBasePhysical);
+}
+//!fnstcw
+
+//!
+void store_fpu_cw(bool checkException, int disp, int base_reg, bool isBasePhysical) {
+ assert(!checkException);
+ Mnemonic m = Mnemonic_FNSTCW;
+ dump_mem(m, ATOM_NORMAL, OpndSize_16, disp, base_reg, isBasePhysical);
+}
+//!cdq
+
+//!
+void convert_integer(OpndSize srcSize, OpndSize dstSize) { //cbw, cwd, cdq
+ assert(srcSize == OpndSize_32 && dstSize == OpndSize_64);
+ Mnemonic m = Mnemonic_CDQ;
+ dump_reg_reg(m, ATOM_NORMAL, OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_EDX, true, LowOpndRegType_gp);
+}
+//!fld: load from memory (float or double) to stack
+
+//!
+void load_fp_stack(LowOp* op, OpndSize size, int disp, int base_reg, bool isBasePhysical) {//fld(s|l)
+ Mnemonic m = Mnemonic_FLD;
+ dump_mem_fp(m, size, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, 0); //ST0
+}
+//! fild: load from memory (int or long) to stack
+
+//!
+void load_int_fp_stack(OpndSize size, int disp, int base_reg, bool isBasePhysical) {//fild(ll|l)
+ Mnemonic m = Mnemonic_FILD;
+ dump_mem_fp(m, size, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, 0); //ST0
+}
+//!fild: load from memory (absolute addr)
+
+//!
+void load_int_fp_stack_imm(OpndSize size, int imm) {//fild(ll|l)
+ return load_int_fp_stack(size, imm, PhysicalReg_Null, true);
+}
+//!fst: store from stack to memory (float or double)
+
+//!
+void store_fp_stack(LowOp* op, bool pop, OpndSize size, int disp, int base_reg, bool isBasePhysical) {//fst(p)(s|l)
+ Mnemonic m = pop ? Mnemonic_FSTP : Mnemonic_FST;
+ dump_fp_mem(m, size, 0, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1);
+}
+//!fist: store from stack to memory (int or long)
+
+//!
+void store_int_fp_stack(LowOp* op, bool pop, OpndSize size, int disp, int base_reg, bool isBasePhysical) {//fist(p)(l)
+ Mnemonic m = pop ? Mnemonic_FISTP : Mnemonic_FIST;
+ dump_fp_mem(m, size, 0, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1);
+}
+//!cmp reg, mem
+
+//!
+void compare_reg_mem(LowOp* op, OpndSize size, int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical) {
+ Mnemonic m = Mnemonic_CMP;
+ dump_reg_mem(m, ATOM_NORMAL, size, reg, isPhysical, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, getTypeFromIntSize(size));
+}
+//!cmp mem, reg
+
+//!
+void compare_mem_reg(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_CMP;
+ dump_mem_reg(m, ATOM_NORMAL, size, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, reg, isPhysical, getTypeFromIntSize(size));
+}
+//! compare a VR with a temporary variable
+
+//!
+void compare_VR_reg_all(OpndSize size,
+ int vA,
+ int reg, bool isPhysical, Mnemonic m) {
+ LowOpndRegType type = getTypeFromIntSize(size);
+ LowOpndRegType pType = type;
+ if(m == Mnemonic_COMISS) {
+ size = OpndSize_32;
+ type = LowOpndRegType_ss;
+ pType = LowOpndRegType_xmm;
+ }
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ int tmpValue[2];
+ int isConst = isVirtualRegConstant(vA, type, tmpValue, true/*updateRefCount*/);
+ if(isConst == 3) {
+ if(m == Mnemonic_COMISS) {
+#ifdef DEBUG_NCG_O1
+ LOGI("VR is const and SS in compare_VR_reg");
+#endif
+ dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ //dumpImmToMem(vA+1, OpndSize_32, 0); //CHECK necessary? will overwrite vA+1!!!
+ dump_mem_reg(m, ATOM_NORMAL, size, 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA, reg, isPhysical, pType);
+ return;
+ }
+ else if(size != OpndSize_64) {
+#ifdef DEBUG_NCG_O1
+ LOGI("VR is const and 32 bits in compare_VR_reg");
+#endif
+ dump_imm_reg(m, ATOM_NORMAL, size, tmpValue[0], reg, isPhysical, pType, false);
+ return;
+ }
+ else if(size == OpndSize_64) {
+#ifdef DEBUG_NCG_O1
+ LOGI("VR is const and 64 bits in compare_VR_reg");
+#endif
+ dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ dumpImmToMem(vA+1, OpndSize_32, tmpValue[1]);
+ dump_mem_reg(m, ATOM_NORMAL, size, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, reg, isPhysical, pType);
+ return;
+ }
+ }
+ if(isConst == 1) dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ if(isConst == 2) dumpImmToMem(vA+1, OpndSize_32, tmpValue[1]);
+ freeReg(true);
+ int regAll = checkVirtualReg(vA, type, 0/*do not update*/);
+ if(regAll != PhysicalReg_Null) { //do not spill regAll when allocating register for dst
+ startNativeCode(-1, -1);
+ donotSpillReg(regAll);
+ dump_reg_reg_noalloc_src(m, ATOM_NORMAL, size, regAll, true, reg, isPhysical, pType);
+ endNativeCode();
+ }
+ else {
+ //virtual register is not allocated to a physical register
+ dump_mem_reg_noalloc_mem(m, ATOM_NORMAL, size, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, reg, isPhysical, pType);
+ }
+ updateRefCount(vA, type);
+ return;
+ } else {
+ dump_mem_reg(m, ATOM_NORMAL, size, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, reg, isPhysical, pType);
+ return;
+ }
+}
+void compare_VR_reg(OpndSize size,
+ int vA,
+ int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_CMP;
+ return compare_VR_reg_all(size, vA, reg, isPhysical, m);
+}
+void compare_VR_ss_reg(int vA, int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_COMISS;
+ return compare_VR_reg_all(OpndSize_32, vA, reg, isPhysical, m);
+}
+void compare_VR_sd_reg(int vA, int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_COMISD;
+ return compare_VR_reg_all(OpndSize_64, vA, reg, isPhysical, m);
+}
+//!load VR to stack
+
+//!
+void load_fp_stack_VR_all(OpndSize size, int vB, Mnemonic m) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ //can't load from immediate to fp stack
+ int tmpValue[2];
+ int isConst = isVirtualRegConstant(vB, getTypeFromIntSize(size), tmpValue, false/*updateRefCount*/);
+ if(isConst > 0) {
+ if(size != OpndSize_64) {
+#ifdef DEBUG_NCG_O1
+ LOGI("VR is const and 32 bits in load_fp_stack");
+#endif
+ dumpImmToMem(vB, OpndSize_32, tmpValue[0]);
+ }
+ else {
+#ifdef DEBUG_NCG_O1
+ LOGI("VR is const and 64 bits in load_fp_stack_VR");
+#endif
+ if(isConst == 1 || isConst == 3) dumpImmToMem(vB, OpndSize_32, tmpValue[0]);
+ if(isConst == 2 || isConst == 3) dumpImmToMem(vB+1, OpndSize_32, tmpValue[1]);
+ }
+ }
+ else { //if VR was updated by a def of gp, a xfer point was inserted
+ //if VR was updated by a def of xmm, a xfer point was inserted
+#if 0
+ int regAll = checkVirtualReg(vB, size, 1);
+ if(regAll != PhysicalReg_Null) //dump from register to memory
+ dump_reg_mem_noalloc(m, size, regAll, true, 4*vB, PhysicalReg_FP, true,
+ MemoryAccess_VR, vB, getTypeFromIntSize(size));
+#endif
+ }
+ dump_mem_fp(m, size, 4*vB, PhysicalReg_FP, true, MemoryAccess_VR, vB, 0);
+ } else {
+ dump_mem_fp(m, size, 4*vB, PhysicalReg_FP, true, MemoryAccess_VR, vB, 0);
+ }
+}
+//!load VR(float or double) to stack
+
+//!
+void load_fp_stack_VR(OpndSize size, int vA) {//fld(s|l)
+ Mnemonic m = Mnemonic_FLD;
+ return load_fp_stack_VR_all(size, vA, m);
+}
+//!load VR(int or long) to stack
+
+//!
+void load_int_fp_stack_VR(OpndSize size, int vA) {//fild(ll|l)
+ Mnemonic m = Mnemonic_FILD;
+ return load_fp_stack_VR_all(size, vA, m);
+}
+//!store from stack to VR (float or double)
+
+//!
+void store_fp_stack_VR(bool pop, OpndSize size, int vA) {//fst(p)(s|l)
+ Mnemonic m = pop ? Mnemonic_FSTP : Mnemonic_FST;
+ dump_fp_mem(m, size, 0, 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA);
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ if(size == OpndSize_32)
+ updateVirtualReg(vA, LowOpndRegType_fs_s);
+ else
+ updateVirtualReg(vA, LowOpndRegType_fs);
+ }
+}
+//!store from stack to VR (int or long)
+
+//!
+void store_int_fp_stack_VR(bool pop, OpndSize size, int vA) {//fist(p)(l)
+ Mnemonic m = pop ? Mnemonic_FISTP : Mnemonic_FIST;
+ dump_fp_mem(m, size, 0, 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA);
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ if(size == OpndSize_32)
+ updateVirtualReg(vA, LowOpndRegType_fs_s);
+ else
+ updateVirtualReg(vA, LowOpndRegType_fs);
+ }
+}
+//! ALU ops in FPU, one operand is a VR
+
+//!
+void fpu_VR(ALU_Opcode opc, OpndSize size, int vA) {
+ Mnemonic m = map_of_fpu_opcode_2_mnemonic[opc];
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ int tmpValue[2];
+ int isConst = isVirtualRegConstant(vA, getTypeFromIntSize(size), tmpValue, false/*updateRefCount*/);
+ if(isConst > 0) {
+ if(size != OpndSize_64) {
+ //allocate a register for dst
+ dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ }
+ else {
+ if((isConst == 1 || isConst == 3) && size == OpndSize_64) {
+ dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ }
+ if((isConst == 2 || isConst == 3) && size == OpndSize_64) {
+ dumpImmToMem(vA+1, OpndSize_32, tmpValue[1]);
+ }
+ }
+ }
+ if(!isInMemory(vA, size)) {
+ ALOGE("fpu_VR");
+ }
+ dump_mem_fp(m, size, 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA, 0);
+ } else {
+ dump_mem_fp(m, size, 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA, 0);
+ }
+}
+//! cmp imm reg
+
+//!
+void compare_imm_reg(OpndSize size, int imm,
+ int reg, bool isPhysical) {
+ if(imm == 0) {
+ LowOpndRegType type = getTypeFromIntSize(size);
+ Mnemonic m = Mnemonic_TEST;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ freeReg(true);
+ int regAll = registerAlloc(type, reg, isPhysical, true);
+ lower_reg_reg(m, ATOM_NORMAL, size, regAll, regAll, type);
+ } else {
+ stream = encoder_reg_reg(m, size, reg, isPhysical, reg, isPhysical, type, stream);
+ }
+ return;
+ }
+ Mnemonic m = Mnemonic_CMP;
+ dump_imm_reg(m, ATOM_NORMAL, size, imm, reg, isPhysical, getTypeFromIntSize(size), false);
+}
+//! cmp imm mem
+
+//!
+void compare_imm_mem(OpndSize size, int imm,
+ int disp, int base_reg, bool isBasePhysical) {
+ Mnemonic m = Mnemonic_CMP;
+ dump_imm_mem(m, ATOM_NORMAL, size, imm, disp,
+ base_reg, isBasePhysical, MemoryAccess_Unknown, -1, false);
+}
+//! cmp imm VR
+
+//!
+void compare_imm_VR(OpndSize size, int imm,
+ int vA) {
+ Mnemonic m = Mnemonic_CMP;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ if(size != OpndSize_32) ALOGE("only 32 bits supported in compare_imm_VR");
+ int tmpValue[2];
+ int isConst = isVirtualRegConstant(vA, getTypeFromIntSize(size), tmpValue, false/*updateRefCount*/);
+ if(isConst > 0) {
+ dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ }
+ int regAll = checkVirtualReg(vA, getTypeFromIntSize(size), 0);
+ if(regAll != PhysicalReg_Null)
+ dump_imm_reg_noalloc(m, size, imm, regAll, true, LowOpndRegType_gp);
+ else
+ dump_imm_mem_noalloc(m, size, imm, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA);
+ updateRefCount(vA, getTypeFromIntSize(size));
+ } else {
+ dump_imm_mem(m, ATOM_NORMAL, size, imm, 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA, false);
+ }
+}
+//! cmp reg reg
+
+//!
+void compare_reg_reg(int reg1, bool isPhysical1,
+ int reg2, bool isPhysical2) {
+ Mnemonic m = Mnemonic_CMP;
+ dump_reg_reg(m, ATOM_NORMAL, OpndSize_32, reg1, isPhysical1, reg2, isPhysical2, LowOpndRegType_gp);
+}
+void compare_reg_reg_16(int reg1, bool isPhysical1,
+ int reg2, bool isPhysical2) {
+ Mnemonic m = Mnemonic_CMP;
+ dump_reg_reg(m, ATOM_NORMAL, OpndSize_16, reg1, isPhysical1, reg2, isPhysical2, LowOpndRegType_gp);
+}
+
+//! comiss mem reg
+
+//!SSE, XMM: comparison of floating point numbers
+void compare_ss_mem_reg(LowOp* op, int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_COMISS;
+ dump_mem_reg(m, ATOM_NORMAL, OpndSize_32, disp, base_reg, isBasePhysical,
+ MemoryAccess_Unknown, -1, reg, isPhysical, LowOpndRegType_xmm);
+}
+//! comiss reg reg
+
+//!
+void compare_ss_reg_with_reg(LowOp* op, int reg1, bool isPhysical1,
+ int reg2, bool isPhysical2) {
+ Mnemonic m = Mnemonic_COMISS;
+ dump_reg_reg(m, ATOM_NORMAL, OpndSize_32, reg1, isPhysical1, reg2, isPhysical2, LowOpndRegType_xmm);
+}
+//! comisd mem reg
+
+//!
+void compare_sd_mem_with_reg(LowOp* op, int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_COMISD;
+ dump_mem_reg(m, ATOM_NORMAL, OpndSize_64, disp, base_reg, isBasePhysical,
+ MemoryAccess_Unknown, -1, reg, isPhysical, LowOpndRegType_xmm);
+}
+//! comisd reg reg
+
+//!
+void compare_sd_reg_with_reg(LowOp* op, int reg1, bool isPhysical1,
+ int reg2, bool isPhysical2) {
+ Mnemonic m = Mnemonic_COMISD;
+ dump_reg_reg(m, ATOM_NORMAL, OpndSize_64, reg1, isPhysical1, reg2, isPhysical2, LowOpndRegType_xmm);
+}
+//! fucom[p]
+
+//!
+void compare_fp_stack(bool pop, int reg, bool isDouble) { //compare ST(0) with ST(reg)
+ Mnemonic m = pop ? Mnemonic_FUCOMP : Mnemonic_FUCOM;
+ lower_reg_reg(m, ATOM_NORMAL, isDouble ? OpndSize_64 : OpndSize_32,
+ PhysicalReg_ST0+reg, PhysicalReg_ST0, LowOpndRegType_fs);
+}
+/*!
+\brief generate a single return instruction
+
+*/
+LowOp* lower_return() {
+ stream = encoder_return(stream);
+ return NULL;
+}
+
+void x86_return() {
+ lower_return();
+}
+
+//!test imm reg
+
+//!
+void test_imm_reg(OpndSize size, int imm, int reg, bool isPhysical) {
+ dump_imm_reg(Mnemonic_TEST, ATOM_NORMAL, size, imm, reg, isPhysical, getTypeFromIntSize(size), false);
+}
+//!test imm mem
+
+//!
+void test_imm_mem(OpndSize size, int imm, int disp, int reg, bool isPhysical) {
+ dump_imm_mem(Mnemonic_TEST, ATOM_NORMAL, size, imm, disp, reg, isPhysical, MemoryAccess_Unknown, -1, false);
+}
+//!alu unary op with one reg operand
+
+//!
+void alu_unary_reg(OpndSize size, ALU_Opcode opc, int reg, bool isPhysical) {
+ Mnemonic m;
+ if(size == OpndSize_64)
+ m = map_of_64_opcode_2_mnemonic[opc];
+ else
+ m = map_of_alu_opcode_2_mnemonic[opc];
+ dump_reg(m, ATOM_NORMAL_ALU, size, reg, isPhysical, getTypeFromIntSize(size));
+}
+//!alu unary op with one mem operand
+
+//!
+void alu_unary_mem(LowOp* op, OpndSize size, ALU_Opcode opc, int disp, int base_reg, bool isBasePhysical) {
+ Mnemonic m;
+ if(size == OpndSize_64)
+ m = map_of_64_opcode_2_mnemonic[opc];
+ else
+ m = map_of_alu_opcode_2_mnemonic[opc];
+ dump_mem(m, ATOM_NORMAL_ALU, size, disp, base_reg, isBasePhysical);
+}
+//!alu binary op with immediate and one mem operand
+
+//!
+void alu_binary_imm_mem(OpndSize size, ALU_Opcode opc, int imm, int disp, int base_reg, bool isBasePhysical) {
+ Mnemonic m;
+ if(size == OpndSize_64)
+ m = map_of_64_opcode_2_mnemonic[opc];
+ else
+ m = map_of_alu_opcode_2_mnemonic[opc];
+ dump_imm_mem(m, ATOM_NORMAL_ALU, size, imm, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, false);
+}
+//!alu binary op with immediate and one reg operand
+
+//!
+void alu_binary_imm_reg(OpndSize size, ALU_Opcode opc, int imm, int reg, bool isPhysical) {
+ Mnemonic m;
+ if(size == OpndSize_64)
+ m = map_of_64_opcode_2_mnemonic[opc];
+ else
+ m = map_of_alu_opcode_2_mnemonic[opc];
+ dump_imm_reg(m, ATOM_NORMAL_ALU, size, imm, reg, isPhysical, getTypeFromIntSize(size), false);
+}
+//!alu binary op with one mem operand and one reg operand
+
+//!
+void alu_binary_mem_reg(OpndSize size, ALU_Opcode opc,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ Mnemonic m;
+ if(size == OpndSize_64)
+ m = map_of_64_opcode_2_mnemonic[opc];
+ else
+ m = map_of_alu_opcode_2_mnemonic[opc];
+ dump_mem_reg(m, ATOM_NORMAL_ALU, size, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, reg, isPhysical, getTypeFromIntSize(size));
+}
+
+void alu_sd_binary_VR_reg(ALU_Opcode opc, int vA, int reg, bool isPhysical, bool isSD) {
+ Mnemonic m;
+ if(isSD) m = map_of_sse_opcode_2_mnemonic[opc];
+ else m = (Mnemonic)(map_of_sse_opcode_2_mnemonic[opc]+1); //from SD to SS
+ OpndSize size = isSD ? OpndSize_64 : OpndSize_32;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ LowOpndRegType type = isSD ? LowOpndRegType_xmm : LowOpndRegType_ss; //type of the mem operand
+ int tmpValue[2];
+ int isConst = isVirtualRegConstant(vA, type, tmpValue,
+ true/*updateRefCount*/);
+ if(isConst == 3 && !isSD) {
+ //isConst can be 0 or 3, mem32, use xmm
+ dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ dump_mem_reg(m, ATOM_NORMAL_ALU, OpndSize_32, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, reg, isPhysical,
+ LowOpndRegType_xmm);
+ return;
+ }
+ if(isConst == 3 && isSD) {
+ dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ dumpImmToMem(vA+1, OpndSize_32, tmpValue[1]);
+ dump_mem_reg(m, ATOM_NORMAL_ALU, OpndSize_64, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, reg, isPhysical, LowOpndRegType_xmm);
+ return;
+ }
+ if(isConst == 1) dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ if(isConst == 2) dumpImmToMem(vA+1, OpndSize_32, tmpValue[1]);
+ freeReg(true);
+
+ int regAll = checkVirtualReg(vA, type, 0/*do not update refCount*/);
+ if(regAll != PhysicalReg_Null) {
+ startNativeCode(-1, -1); //should we use vA, type
+ //CHECK: callupdateVRAtUse
+ donotSpillReg(regAll);
+ dump_reg_reg_noalloc_src(m, ATOM_NORMAL_ALU, size, regAll, true, reg,
+ isPhysical, LowOpndRegType_xmm);
+ endNativeCode();
+ }
+ else {
+ dump_mem_reg_noalloc_mem(m, ATOM_NORMAL_ALU, size, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, reg, isPhysical, LowOpndRegType_xmm);
+ }
+ updateRefCount(vA, type);
+ }
+ else {
+ dump_mem_reg(m, ATOM_NORMAL, size, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, reg, isPhysical, LowOpndRegType_xmm);
+ }
+}
+
+//!alu binary op with a VR and one reg operand
+
+//!
+void alu_binary_VR_reg(OpndSize size, ALU_Opcode opc, int vA, int reg, bool isPhysical) {
+ Mnemonic m;
+ if(size == OpndSize_64)
+ m = map_of_64_opcode_2_mnemonic[opc];
+ else
+ m = map_of_alu_opcode_2_mnemonic[opc];
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ int tmpValue[2];
+ int isConst = isVirtualRegConstant(vA, getTypeFromIntSize(size), tmpValue,
+ true/*updateRefCount*/);
+ if(isConst == 3 && size != OpndSize_64) {
+ //allocate a register for dst
+ dump_imm_reg(m, ATOM_NORMAL_ALU, size, tmpValue[0], reg, isPhysical,
+ getTypeFromIntSize(size), false);
+ return;
+ }
+ if(isConst == 3 && size == OpndSize_64) {
+ dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ dumpImmToMem(vA+1, OpndSize_32, tmpValue[1]);
+ dump_mem_reg(m, ATOM_NORMAL_ALU, size, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, reg, isPhysical, getTypeFromIntSize(size));
+ return;
+ }
+ if(isConst == 1) dumpImmToMem(vA, OpndSize_32, tmpValue[0]);
+ if(isConst == 2) dumpImmToMem(vA+1, OpndSize_32, tmpValue[1]);
+
+ freeReg(true);
+ int regAll = checkVirtualReg(vA, getTypeFromIntSize(size), 0);
+ if(regAll != PhysicalReg_Null) {
+ startNativeCode(-1, -1);
+ donotSpillReg(regAll);
+ dump_reg_reg_noalloc_src(m, ATOM_NORMAL_ALU, size, regAll, true, reg,
+ isPhysical, getTypeFromIntSize(size));
+ endNativeCode();
+ }
+ else {
+ dump_mem_reg_noalloc_mem(m, ATOM_NORMAL_ALU, size, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, reg, isPhysical, getTypeFromIntSize(size));
+ }
+ updateRefCount(vA, getTypeFromIntSize(size));
+ }
+ else {
+ dump_mem_reg(m, ATOM_NORMAL, size, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, reg, isPhysical, getTypeFromIntSize(size));
+ }
+}
+//!alu binary op with two reg operands
+
+//!
+void alu_binary_reg_reg(OpndSize size, ALU_Opcode opc,
+ int reg1, bool isPhysical1,
+ int reg2, bool isPhysical2) {
+ Mnemonic m;
+ if(size == OpndSize_64)
+ m = map_of_64_opcode_2_mnemonic[opc];
+ else
+ m = map_of_alu_opcode_2_mnemonic[opc];
+ dump_reg_reg(m, ATOM_NORMAL_ALU, size, reg1, isPhysical1, reg2, isPhysical2, getTypeFromIntSize(size));
+}
+//!alu binary op with one reg operand and one mem operand
+
+//!
+void alu_binary_reg_mem(OpndSize size, ALU_Opcode opc,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical) { //destination is mem!!
+ Mnemonic m;
+ if(size == OpndSize_64)
+ m = map_of_64_opcode_2_mnemonic[opc];
+ else
+ m = map_of_alu_opcode_2_mnemonic[opc];
+ dump_reg_mem(m, ATOM_NORMAL_ALU, size, reg, isPhysical, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, getTypeFromIntSize(size));
+}
+//!FPU ops with one mem operand
+
+//!
+void fpu_mem(LowOp* op, ALU_Opcode opc, OpndSize size, int disp, int base_reg, bool isBasePhysical) {
+ Mnemonic m = map_of_fpu_opcode_2_mnemonic[opc];
+ dump_mem_fp(m, size, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, 0);
+}
+//!SSE 32-bit ALU
+
+//!
+void alu_ss_binary_reg_reg(ALU_Opcode opc, int reg, bool isPhysical,
+ int reg2, bool isPhysical2) {
+ Mnemonic m = (Mnemonic)(map_of_sse_opcode_2_mnemonic[opc]+1); //from SD to SS
+ dump_reg_reg(m, ATOM_NORMAL_ALU, OpndSize_32, reg, isPhysical, reg2, isPhysical2, LowOpndRegType_xmm);
+}
+//!SSE 64-bit ALU
+
+//!
+void alu_sd_binary_reg_reg(ALU_Opcode opc, int reg, bool isPhysical,
+ int reg2, bool isPhysical2) {
+ Mnemonic m = map_of_sse_opcode_2_mnemonic[opc];
+ dump_reg_reg(m, ATOM_NORMAL_ALU, OpndSize_64, reg, isPhysical, reg2, isPhysical2, LowOpndRegType_xmm);
+}
+//!push reg to native stack
+
+//!
+void push_reg_to_stack(OpndSize size, int reg, bool isPhysical) {
+ dump_reg(Mnemonic_PUSH, ATOM_NORMAL, size, reg, isPhysical, getTypeFromIntSize(size));
+}
+//!push mem to native stack
+
+//!
+void push_mem_to_stack(OpndSize size, int disp, int base_reg, bool isBasePhysical) {
+ dump_mem(Mnemonic_PUSH, ATOM_NORMAL, size, disp, base_reg, isBasePhysical);
+}
+//!move from reg to memory
+
+//!
+void move_reg_to_mem(OpndSize size,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_reg_mem(m, ATOM_NORMAL, size, reg, isPhysical, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, getTypeFromIntSize(size));
+}
+//!move from reg to memory
+
+//!Operands are already allocated
+void move_reg_to_mem_noalloc(OpndSize size,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_reg_mem_noalloc(m, size, reg, isPhysical, disp, base_reg, isBasePhysical, mType, mIndex, getTypeFromIntSize(size));
+}
+//!move from memory to reg
+
+//!
+LowOpRegMem* move_mem_to_reg(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ return dump_mem_reg(m, ATOM_NORMAL, size, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, reg, isPhysical, getTypeFromIntSize(size));
+}
+//!move from memory to reg
+
+//!Operands are already allocated
+LowOpRegMem* move_mem_to_reg_noalloc(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg, bool isPhysical) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ return dump_mem_reg_noalloc(m, size, disp, base_reg, isBasePhysical, mType, mIndex, reg, isPhysical, getTypeFromIntSize(size));
+}
+//!movss from memory to reg
+
+//!Operands are already allocated
+LowOpRegMem* move_ss_mem_to_reg_noalloc(int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex,
+ int reg, bool isPhysical) {
+ return dump_mem_reg_noalloc(Mnemonic_MOVSS, OpndSize_32, disp, base_reg, isBasePhysical, mType, mIndex, reg, isPhysical, LowOpndRegType_xmm);
+}
+//!movss from reg to memory
+
+//!Operands are already allocated
+LowOpMemReg* move_ss_reg_to_mem_noalloc(int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical,
+ MemoryAccessType mType, int mIndex) {
+ return dump_reg_mem_noalloc(Mnemonic_MOVSS, OpndSize_32, reg, isPhysical, disp, base_reg, isBasePhysical, mType, mIndex, LowOpndRegType_xmm);
+}
+//!movzx from memory to reg
+
+//!
+void movez_mem_to_reg(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_MOVZX;
+ dump_movez_mem_reg(m, size, disp, base_reg, isBasePhysical, reg, isPhysical);
+}
+
+//!movzx from one reg to another reg
+
+//!
+void movez_reg_to_reg(OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2) {
+ Mnemonic m = Mnemonic_MOVZX;
+ dump_movez_reg_reg(m, size, reg, isPhysical, reg2, isPhysical2);
+}
+
+void movez_mem_disp_scale_to_reg(OpndSize size,
+ int base_reg, bool isBasePhysical,
+ int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical) {
+ dump_mem_scale_reg(Mnemonic_MOVZX, size, base_reg, isBasePhysical,
+ disp, index_reg, isIndexPhysical, scale,
+ reg, isPhysical, LowOpndRegType_gp);
+}
+void moves_mem_disp_scale_to_reg(OpndSize size,
+ int base_reg, bool isBasePhysical,
+ int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical) {
+ dump_mem_scale_reg(Mnemonic_MOVSX, size, base_reg, isBasePhysical,
+ disp, index_reg, isIndexPhysical, scale,
+ reg, isPhysical, LowOpndRegType_gp);
+}
+
+//!movsx from memory to reg
+
+//!
+void moves_mem_to_reg(LowOp* op, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_MOVSX;
+ dump_moves_mem_reg(m, size, disp, base_reg, isBasePhysical, reg, isPhysical);
+}
+//!mov from one reg to another reg
+
+//!
+void move_reg_to_reg(OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_reg_reg(m, ATOM_NORMAL, size, reg, isPhysical, reg2, isPhysical2, getTypeFromIntSize(size));
+}
+//!mov from one reg to another reg
+
+//!Operands are already allocated
+void move_reg_to_reg_noalloc(OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_reg_reg_noalloc(m, size, reg, isPhysical, reg2, isPhysical2, getTypeFromIntSize(size));
+}
+//!move from memory to reg
+
+//!
+void move_mem_scale_to_reg(OpndSize size,
+ int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_mem_scale_reg(m, size, base_reg, isBasePhysical, 0/*disp*/, index_reg, isIndexPhysical, scale,
+ reg, isPhysical, getTypeFromIntSize(size));
+}
+void move_mem_disp_scale_to_reg(OpndSize size,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_mem_scale_reg(m, size, base_reg, isBasePhysical, disp, index_reg, isIndexPhysical, scale,
+ reg, isPhysical, getTypeFromIntSize(size));
+}
+//!move from reg to memory
+
+//!
+void move_reg_to_mem_scale(OpndSize size,
+ int reg, bool isPhysical,
+ int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_reg_mem_scale(m, size, reg, isPhysical,
+ base_reg, isBasePhysical, 0/*disp*/, index_reg, isIndexPhysical, scale,
+ getTypeFromIntSize(size));
+}
+void move_reg_to_mem_disp_scale(OpndSize size,
+ int reg, bool isPhysical,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_reg_mem_scale(m, size, reg, isPhysical,
+ base_reg, isBasePhysical, disp, index_reg, isIndexPhysical, scale,
+ getTypeFromIntSize(size));
+}
+
+void move_chain_to_mem(OpndSize size, int imm,
+ int disp, int base_reg, bool isBasePhysical) {
+ dump_imm_mem(Mnemonic_MOV, ATOM_NORMAL, size, imm, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, true);
+}
+
+//!move an immediate to memory
+
+//!
+void move_imm_to_mem(OpndSize size, int imm,
+ int disp, int base_reg, bool isBasePhysical) {
+ assert(size != OpndSize_64);
+ if(size == OpndSize_64) ALOGE("move_imm_to_mem with 64 bits");
+ dump_imm_mem(Mnemonic_MOV, ATOM_NORMAL, size, imm, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, false);
+}
+//! set a VR to an immediate
+
+//!
+void set_VR_to_imm(u2 vA, OpndSize size, int imm) {
+ assert(size != OpndSize_64);
+ if(size == OpndSize_64) ALOGE("move_imm_to_mem with 64 bits");
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ int regAll = checkVirtualReg(vA, getTypeFromIntSize(size), 0);
+ if(regAll != PhysicalReg_Null) {
+ dump_imm_reg_noalloc(m, size, imm, regAll, true, LowOpndRegType_gp);
+ updateRefCount(vA, getTypeFromIntSize(size));
+ updateVirtualReg(vA, getTypeFromIntSize(size));
+ return;
+ }
+ //will call freeReg
+ freeReg(true);
+ regAll = registerAlloc(LowOpndRegType_virtual | getTypeFromIntSize(size), vA, false/*dummy*/, true);
+ if(regAll == PhysicalReg_Null) {
+ dump_imm_mem_noalloc(m, size, imm, 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA);
+ return;
+ }
+ dump_imm_reg_noalloc(m, size, imm, regAll, true, LowOpndRegType_gp);
+ updateVirtualReg(vA, getTypeFromIntSize(size));
+ }
+ else {
+ dump_imm_mem(m, ATOM_NORMAL, size, imm, 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA, false);
+ }
+}
+void set_VR_to_imm_noupdateref(LowOp* op, u2 vA, OpndSize size, int imm) {
+ return;
+}
+//! set a VR to an immediate
+
+//! Do not allocate a physical register for the VR
+void set_VR_to_imm_noalloc(u2 vA, OpndSize size, int imm) {
+ assert(size != OpndSize_64);
+ if(size == OpndSize_64) ALOGE("move_imm_to_mem with 64 bits");
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_imm_mem_noalloc(m, size, imm, 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA);
+}
+
+void move_chain_to_reg(OpndSize size, int imm, int reg, bool isPhysical) {
+ dump_imm_reg(Mnemonic_MOV, ATOM_NORMAL, size, imm, reg, isPhysical, LowOpndRegType_gp, true);
+}
+
+//! move an immediate to reg
+
+//!
+void move_imm_to_reg(OpndSize size, int imm, int reg, bool isPhysical) {
+ assert(size != OpndSize_64);
+ if(size == OpndSize_64) ALOGE("move_imm_to_reg with 64 bits");
+ Mnemonic m = Mnemonic_MOV;
+ dump_imm_reg(m, ATOM_NORMAL, size, imm, reg, isPhysical, LowOpndRegType_gp, false);
+}
+//! move an immediate to reg
+
+//! The operand is already allocated
+void move_imm_to_reg_noalloc(OpndSize size, int imm, int reg, bool isPhysical) {
+ assert(size != OpndSize_64);
+ if(size == OpndSize_64) ALOGE("move_imm_to_reg with 64 bits");
+ Mnemonic m = Mnemonic_MOV;
+ dump_imm_reg_noalloc(m, size, imm, reg, isPhysical, LowOpndRegType_gp);
+}
+//!cmov from reg to reg
+
+//!
+void conditional_move_reg_to_reg(OpndSize size, ConditionCode cc, int reg1, bool isPhysical1, int reg, bool isPhysical) {
+ Mnemonic m = (Mnemonic)(Mnemonic_CMOVcc+cc);
+ dump_reg_reg(m, ATOM_NORMAL, size, reg1, isPhysical1, reg, isPhysical, LowOpndRegType_gp);
+}
+//!movss from memory to reg
+
+//!
+void move_ss_mem_to_reg(LowOp* op, int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ dump_mem_reg(Mnemonic_MOVSS, ATOM_NORMAL, OpndSize_32, disp, base_reg, isBasePhysical,
+ MemoryAccess_Unknown, -1, reg, isPhysical, LowOpndRegType_xmm);
+}
+//!movss from reg to memory
+
+//!
+void move_ss_reg_to_mem(LowOp* op, int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical) {
+ dump_reg_mem(Mnemonic_MOVSS, ATOM_NORMAL, OpndSize_32, reg, isPhysical, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, LowOpndRegType_xmm);
+}
+//!movsd from memory to reg
+
+//!
+void move_sd_mem_to_reg(int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical) {
+ dump_mem_reg(Mnemonic_MOVSD, ATOM_NORMAL, OpndSize_64, disp, base_reg, isBasePhysical, MemoryAccess_Unknown, -1, reg, isPhysical, LowOpndRegType_xmm);
+}
+//!movsd from reg to memory
+
+//!
+void move_sd_reg_to_mem(LowOp* op, int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical) {
+ dump_reg_mem(Mnemonic_MOVSD, ATOM_NORMAL, OpndSize_64, reg, isPhysical,
+ disp, base_reg, isBasePhysical,
+ MemoryAccess_Unknown, -1, LowOpndRegType_xmm);
+}
+//!load from VR to a temporary
+
+//!
+void get_virtual_reg_all(u2 vB, OpndSize size, int reg, bool isPhysical, Mnemonic m) {
+ LowOpndRegType type = getTypeFromIntSize(size);
+ LowOpndRegType pType = type;//gp or xmm
+ OpndSize size2 = size;
+ Mnemonic m2 = m;
+ if(m == Mnemonic_MOVSS) {
+ size = OpndSize_32;
+ size2 = OpndSize_64;
+ type = LowOpndRegType_ss;
+ pType = LowOpndRegType_xmm;
+ m2 = Mnemonic_MOVQ; //to move from one xmm register to another
+ }
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ int tmpValue[2];
+ int isConst;
+ isConst = isVirtualRegConstant(vB, type, tmpValue, true/*updateRefCount*/);
+ if(isConst == 3) {
+ if(m == Mnemonic_MOVSS) { //load 32 bits from VR
+ //VR is not mapped to a register but in memory
+ dumpImmToMem(vB, OpndSize_32, tmpValue[0]);
+ //temporary reg has "pType" (which is xmm)
+ dump_mem_reg(m, ATOM_NORMAL, size, 4*vB, PhysicalReg_FP, true,
+ MemoryAccess_VR, vB, reg, isPhysical, pType);
+ return;
+ }
+ else if(m == Mnemonic_MOVSD || size == OpndSize_64) {
+ //VR is not mapped to a register but in memory
+ dumpImmToMem(vB, OpndSize_32, tmpValue[0]);
+ dumpImmToMem(vB+1, OpndSize_32, tmpValue[1]);
+ dump_mem_reg(m, ATOM_NORMAL, size, 4*vB, PhysicalReg_FP, true,
+ MemoryAccess_VR, vB, reg, isPhysical, pType);
+ return;
+ }
+ else if(size != OpndSize_64) {
+ //VR is not mapped to a register
+ dump_imm_reg(m, ATOM_NORMAL, size, tmpValue[0], reg, isPhysical, pType, false);
+ return;
+ }
+ }
+ if(isConst == 1) dumpImmToMem(vB, OpndSize_32, tmpValue[0]);
+ if(isConst == 2) dumpImmToMem(vB+1, OpndSize_32, tmpValue[1]);
+ freeReg(true);
+ int regAll = checkVirtualReg(vB, type, 0);
+ if(regAll != PhysicalReg_Null) {
+ startNativeCode(vB, type);
+ donotSpillReg(regAll);
+ //check XFER_MEM_TO_XMM
+ updateVRAtUse(vB, type, regAll);
+ //temporary reg has "pType"
+ dump_reg_reg_noalloc_src(m2, ATOM_NORMAL, size2, regAll, true, reg, isPhysical, pType); //register allocator handles assembly move
+ endNativeCode();
+ updateRefCount(vB, type);
+ return;
+ }
+ //not allocated to a register yet, no need to check XFER_MEM_TO_XMM
+ regAll = registerAlloc(LowOpndRegType_virtual | type, vB, false/*dummy*/, false);
+ if(regAll == PhysicalReg_Null) {
+ dump_mem_reg_noalloc(m, size, 4*vB, PhysicalReg_FP, true,
+ MemoryAccess_VR, vB, reg, isPhysical, pType);
+ return;
+ }
+
+ //temporary reg has pType
+ if(checkTempReg2(reg, pType, isPhysical, regAll)) {
+ registerAllocMove(reg, pType, isPhysical, regAll);
+ dump_mem_reg_noalloc(m, size, 4*vB, PhysicalReg_FP, true,
+ MemoryAccess_VR, vB, regAll, true, pType);
+ updateRefCount(vB, type);
+ return;
+ }
+ else {
+ dump_mem_reg_noalloc(m, size, 4*vB, PhysicalReg_FP, true,
+ MemoryAccess_VR, vB, regAll, true, pType);
+ //xmm with 32 bits
+ startNativeCode(vB, type);
+ donotSpillReg(regAll);
+ dump_reg_reg_noalloc_src(m2, ATOM_NORMAL, size2, regAll, true, reg, isPhysical, pType);
+ endNativeCode();
+ updateRefCount(vB, type);
+ return;
+ }
+ }
+ else {
+ dump_mem_reg(m, ATOM_NORMAL, size, 4*vB, PhysicalReg_FP, true,
+ MemoryAccess_VR, vB, reg, isPhysical, pType);
+ }
+}
+void get_virtual_reg(u2 vB, OpndSize size, int reg, bool isPhysical) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ return get_virtual_reg_all(vB, size, reg, isPhysical, m);
+}
+void get_virtual_reg_noalloc(u2 vB, OpndSize size, int reg, bool isPhysical) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_mem_reg_noalloc(m, size, 4*vB, PhysicalReg_FP, true,
+ MemoryAccess_VR, vB, reg, isPhysical, getTypeFromIntSize(size));
+}
+//3 cases: gp, xmm, ss
+//ss: the temporary register is xmm
+//!load from a temporary to a VR
+
+//!
+void set_virtual_reg_all(u2 vA, OpndSize size, int reg, bool isPhysical, Mnemonic m) {
+ LowOpndRegType type = getTypeFromIntSize(size);
+ LowOpndRegType pType = type;//gp or xmm
+ OpndSize size2 = size;
+ Mnemonic m2 = m;
+ if(m == Mnemonic_MOVSS) {
+ size = OpndSize_32;
+ size2 = OpndSize_64;
+ type = LowOpndRegType_ss;
+ pType = LowOpndRegType_xmm;
+ m2 = Mnemonic_MOVQ;
+ }
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ //3 cases
+ //1: virtual register is already allocated to a physical register
+ // call dump_reg_reg_noalloc_dst
+ //2: src reg is already allocated, VR is not yet allocated
+ // allocate VR to the same physical register used by src reg
+ // [call registerAllocMove]
+ //3: both not yet allocated
+ // allocate a physical register for the VR
+ // then call dump_reg_reg_noalloc_dst
+ //may need to convert from gp to xmm or the other way
+ freeReg(true);
+ int regAll = checkVirtualReg(vA, type, 0);
+ if(regAll != PhysicalReg_Null) { //case 1
+ startNativeCode(-1, -1);
+ donotSpillReg(regAll);
+ dump_reg_reg_noalloc_dst(m2, size2, reg, isPhysical, regAll, true, pType); //temporary reg is "pType"
+ endNativeCode();
+ updateRefCount(vA, type);
+ updateVirtualReg(vA, type); //will dump VR to memory, should happen afterwards
+ return;
+ }
+ regAll = checkTempReg(reg, pType, isPhysical, vA); //vA is not used inside
+ if(regAll != PhysicalReg_Null) { //case 2
+ registerAllocMove(vA, LowOpndRegType_virtual | type, false, regAll);
+ updateVirtualReg(vA, type); //will dump VR to memory, should happen afterwards
+ return; //next native instruction starts at op
+ }
+ //case 3
+ regAll = registerAlloc(LowOpndRegType_virtual | type, vA, false/*dummy*/, false);
+ if(regAll == PhysicalReg_Null) {
+ dump_reg_mem_noalloc(m, size, reg, isPhysical, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, pType);
+ return;
+ }
+ startNativeCode(-1, -1);
+ donotSpillReg(regAll);
+ dump_reg_reg_noalloc_dst(m2, size2, reg, isPhysical, regAll, true, pType);
+ endNativeCode();
+ updateRefCount(vA, type);
+ updateVirtualReg(vA, type);
+ }
+ else {
+ dump_reg_mem(m, ATOM_NORMAL, size, reg, isPhysical, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, pType);
+ }
+}
+void set_virtual_reg(u2 vA, OpndSize size, int reg, bool isPhysical) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ return set_virtual_reg_all(vA, size, reg, isPhysical, m);
+}
+void set_virtual_reg_noalloc(u2 vA, OpndSize size, int reg, bool isPhysical) {
+ Mnemonic m = (size == OpndSize_64) ? Mnemonic_MOVQ : Mnemonic_MOV;
+ dump_reg_mem_noalloc(m, size, reg, isPhysical, 4*vA, PhysicalReg_FP, true,
+ MemoryAccess_VR, vA, getTypeFromIntSize(size));
+}
+void get_VR_ss(int vB, int reg, bool isPhysical) {
+ return get_virtual_reg_all(vB, OpndSize_64, reg, isPhysical, Mnemonic_MOVSS);
+}
+void set_VR_ss(int vA, int reg, bool isPhysical) {
+ return set_virtual_reg_all(vA, OpndSize_64, reg, isPhysical, Mnemonic_MOVSS);
+}
+void get_VR_sd(int vB, int reg, bool isPhysical) {
+ return get_virtual_reg_all(vB, OpndSize_64, reg, isPhysical, Mnemonic_MOVSD);
+}
+void set_VR_sd(int vA, int reg, bool isPhysical) {
+ return set_virtual_reg_all(vA, OpndSize_64, reg, isPhysical, Mnemonic_MOVSD);
+}
+////////////////////////////////// END: IA32 native instructions //////////////
+//! generate native instructions to get current PC in the stack frame
+
+//!
+int get_currentpc(int reg, bool isPhysical) {
+ move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_localRefTop, PhysicalReg_FP, true, reg, isPhysical);
+ return 1;
+}
+//!generate native code to perform null check
+
+//!This function does not export PC
+int simpleNullCheck(int reg, bool isPhysical, int vr) {
+ if(isVRNullCheck(vr, OpndSize_32)) {
+ updateRefCount2(reg, LowOpndRegType_gp, isPhysical);
+ num_removed_nullCheck++;
+ return 0;
+ }
+ compare_imm_reg(OpndSize_32, 0, reg, isPhysical);
+ conditional_jump_global_API(Condition_E, "common_errNullObject", false);
+ setVRNullCheck(vr, OpndSize_32);
+ return 0;
+}
+
+/* only for O1 code generator */
+int boundCheck(int vr_array, int reg_array, bool isPhysical_array,
+ int vr_index, int reg_index, bool isPhysical_index,
+ int exceptionNum) {
+#ifdef BOUNDCHECK_OPT
+ if(isVRBoundCheck(vr_array, vr_index)) {
+ updateRefCount2(reg_array, LowOpndRegType_gp, isPhysical_array);
+ updateRefCount2(reg_index, LowOpndRegType_gp, isPhysical_index);
+ return 0;
+ }
+#endif
+ compare_mem_reg(OpndSize_32, offArrayObject_length,
+ reg_array, isPhysical_array,
+ reg_index, isPhysical_index);
+
+ char errName[256];
+ sprintf(errName, "common_errArrayIndex");
+ handlePotentialException(
+ Condition_NC, Condition_C,
+ exceptionNum, errName);
+#ifdef BOUNDCHECK_OPT
+ setVRBoundCheck(vr_array, vr_index);
+#endif
+ return 0;
+}
+
+//!generate native code to perform null check
+
+//!
+int nullCheck(int reg, bool isPhysical, int exceptionNum, int vr) {
+ char label[LABEL_SIZE];
+
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ //nullCheck optimization is available in O1 mode only
+ if(isVRNullCheck(vr, OpndSize_32)) {
+ updateRefCount2(reg, LowOpndRegType_gp, isPhysical);
+ if(exceptionNum <= 1) {
+ updateRefCount2(PhysicalReg_EDX, LowOpndRegType_gp, true);
+ updateRefCount2(PhysicalReg_EDX, LowOpndRegType_gp, true);
+ }
+ num_removed_nullCheck++;
+ return 0;
+ }
+ compare_imm_reg(OpndSize_32, 0, reg, isPhysical);
+ rememberState(exceptionNum);
+ snprintf(label, LABEL_SIZE, "after_exception_%d", exceptionNum);
+ conditional_jump(Condition_NE, label, true);
+ if(exceptionNum > 1)
+ nextVersionOfHardReg(PhysicalReg_EDX, 2); //next version has 2 ref count
+ export_pc(); //use %edx
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+ unconditional_jump_global_API("common_errNullObject", false);
+ insertLabel(label, true);
+ goToState(exceptionNum);
+ setVRNullCheck(vr, OpndSize_32);
+ } else {
+ compare_imm_reg(OpndSize_32, 0, reg, isPhysical);
+ snprintf(label, LABEL_SIZE, "after_exception_%d", exceptionNum);
+ conditional_jump(Condition_NE, label, true);
+ export_pc(); //use %edx
+ unconditional_jump_global_API("common_errNullObject", false);
+ insertLabel(label, true);
+ }
+ return 0;
+}
+//!generate native code to handle potential exception
+
+//!
+int handlePotentialException(
+ ConditionCode code_excep, ConditionCode code_okay,
+ int exceptionNum, const char* errName) {
+ char label[LABEL_SIZE];
+
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ rememberState(exceptionNum);
+ snprintf(label, LABEL_SIZE, "after_exception_%d", exceptionNum);
+ conditional_jump(code_okay, label, true);
+ if(exceptionNum > 1)
+ nextVersionOfHardReg(PhysicalReg_EDX, 2); //next version has 2 ref count
+ export_pc(); //use %edx
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+ if(!strcmp(errName, "common_throw_message")) {
+ move_imm_to_reg(OpndSize_32, LstrInstantiationErrorPtr, PhysicalReg_ECX, true);
+ }
+ unconditional_jump_global_API(errName, false);
+ insertLabel(label, true);
+ goToState(exceptionNum);
+ } else {
+ snprintf(label, LABEL_SIZE, "after_exception_%d", exceptionNum);
+ conditional_jump(code_okay, label, true);
+ export_pc(); //use %edx
+ if(!strcmp(errName, "common_throw_message")) {
+ move_imm_to_reg(OpndSize_32, LstrInstantiationErrorPtr, PhysicalReg_ECX, true);
+ }
+ unconditional_jump_global_API(errName, false);
+ insertLabel(label, true);
+ }
+ return 0;
+}
+//!generate native code to get the self pointer from glue
+
+//!It uses one scratch register
+int get_self_pointer(int reg, bool isPhysical) {
+ move_mem_to_reg(OpndSize_32, offEBP_self, PhysicalReg_EBP, true, reg, isPhysical);
+ return 0;
+}
+//!generate native code to get ResStrings from glue
+
+//!It uses two scratch registers
+int get_res_strings(int reg, bool isPhysical) {
+ //if spill_loc_index > 0 || reg != NULL, use registerAlloc
+ if(isGlueHandled(PhysicalReg_GLUE_DVMDEX)) {
+ //if spill_loc_index > 0
+ // load from spilled location, update spill_loc_index & physicalReg
+#if 0
+ updateRefCount2(C_SCRATCH_1, LowOpndRegType_gp, isScratchPhysical);
+ updateRefCount2(C_SCRATCH_1, LowOpndRegType_gp, isScratchPhysical);
+ updateRefCount2(C_SCRATCH_2, LowOpndRegType_gp, isScratchPhysical);
+ updateRefCount2(C_SCRATCH_2, LowOpndRegType_gp, isScratchPhysical);
+#endif
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int regAll = registerAlloc(LowOpndRegType_gp, PhysicalReg_GLUE_DVMDEX, false, false/*updateRefCount*/);
+ donotSpillReg(regAll);
+ dump_mem_reg_noalloc_mem(Mnemonic_MOV, ATOM_NORMAL, OpndSize_32, offDvmDex_pResStrings, regAll, true, MemoryAccess_Unknown, -1, reg, isPhysical, LowOpndRegType_gp);
+ endNativeCode();
+ }
+ else
+ {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, interpSave.methodClassDex), C_SCRATCH_1, isScratchPhysical, C_SCRATCH_2, isScratchPhysical);
+ //glue is not in a physical reg nor in a spilled location
+ updateGlue(C_SCRATCH_2, isScratchPhysical, PhysicalReg_GLUE_DVMDEX); //spill_loc_index is -1, set physicalReg
+ move_mem_to_reg(OpndSize_32, offDvmDex_pResStrings, C_SCRATCH_2, isScratchPhysical, reg, isPhysical);
+ }
+ return 0;
+}
+int get_res_classes(int reg, bool isPhysical) {
+ //if spill_loc_index > 0 || reg != NULL, use registerAlloc
+ if(isGlueHandled(PhysicalReg_GLUE_DVMDEX)) {
+ //if spill_loc_index > 0
+ // load from spilled location, updte spill_loc_index & physicalReg
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int regAll = registerAlloc(LowOpndRegType_gp, PhysicalReg_GLUE_DVMDEX, false, false/*updateRefCount*/);
+ donotSpillReg(regAll);
+ dump_mem_reg_noalloc_mem(Mnemonic_MOV, ATOM_NORMAL, OpndSize_32, offDvmDex_pResClasses, regAll, true, MemoryAccess_Unknown, -1, reg, isPhysical, LowOpndRegType_gp);
+ endNativeCode();
+ }
+ else
+ {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, interpSave.methodClassDex), C_SCRATCH_1, isScratchPhysical, C_SCRATCH_2, isScratchPhysical);
+ //glue is not in a physical reg nor in a spilled location
+ updateGlue(C_SCRATCH_2, isScratchPhysical, PhysicalReg_GLUE_DVMDEX); //spill_loc_index is -1, set physicalReg
+ move_mem_to_reg(OpndSize_32, offDvmDex_pResClasses, C_SCRATCH_2, isScratchPhysical, reg, isPhysical);
+ }
+ return 0;
+}
+//!generate native code to get ResFields from glue
+
+//!It uses two scratch registers
+int get_res_fields(int reg, bool isPhysical) {
+ //if spill_loc_index > 0 || reg != NULL, use registerAlloc
+ if(isGlueHandled(PhysicalReg_GLUE_DVMDEX)) {
+ //if spill_loc_index > 0
+ // load from spilled location, updte spill_loc_index & physicalReg
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int regAll = registerAlloc(LowOpndRegType_gp, PhysicalReg_GLUE_DVMDEX, false, false/*updateRefCount*/);
+ donotSpillReg(regAll);
+ dump_mem_reg_noalloc_mem(Mnemonic_MOV, ATOM_NORMAL, OpndSize_32, offDvmDex_pResFields, regAll, true, MemoryAccess_Unknown, -1, reg, isPhysical, LowOpndRegType_gp);
+ endNativeCode();
+ }
+ else
+ {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, interpSave.methodClassDex), C_SCRATCH_1, isScratchPhysical, C_SCRATCH_2, isScratchPhysical);
+ //glue is not in a physical reg nor in a spilled location
+ updateGlue(C_SCRATCH_2, isScratchPhysical, PhysicalReg_GLUE_DVMDEX); //spill_loc_index is -1, set physicalReg
+ move_mem_to_reg(OpndSize_32, offDvmDex_pResFields, C_SCRATCH_2, isScratchPhysical, reg, isPhysical);
+ }
+ return 0;
+}
+//!generate native code to get ResMethods from glue
+
+//!It uses two scratch registers
+int get_res_methods(int reg, bool isPhysical) {
+ //if spill_loc_index > 0 || reg != NULL, use registerAlloc
+ if(isGlueHandled(PhysicalReg_GLUE_DVMDEX)) {
+ //if spill_loc_index > 0
+ // load from spilled location, updte spill_loc_index & physicalReg
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int regAll = registerAlloc(LowOpndRegType_gp, PhysicalReg_GLUE_DVMDEX, false, false/*updateRefCount*/);
+ donotSpillReg(regAll);
+ dump_mem_reg_noalloc_mem(Mnemonic_MOV, ATOM_NORMAL, OpndSize_32, offDvmDex_pResMethods, regAll, true, MemoryAccess_Unknown, -1, reg, isPhysical, LowOpndRegType_gp);
+ endNativeCode();
+ }
+ else
+ {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, interpSave.methodClassDex), C_SCRATCH_1, isScratchPhysical, C_SCRATCH_2, isScratchPhysical);
+ //glue is not in a physical reg nor in a spilled location
+ updateGlue(C_SCRATCH_2, isScratchPhysical, PhysicalReg_GLUE_DVMDEX); //spill_loc_index is -1, set physicalReg
+ move_mem_to_reg(OpndSize_32, offDvmDex_pResMethods, C_SCRATCH_2, isScratchPhysical, reg, isPhysical);
+ }
+ return 0;
+}
+//!generate native code to get the current class object from glue
+
+//!It uses two scratch registers
+int get_glue_method_class(int reg, bool isPhysical) {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, interpSave.method), C_SCRATCH_1, isScratchPhysical, C_SCRATCH_2, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offMethod_clazz, C_SCRATCH_2, isScratchPhysical, reg, isPhysical);
+ return 0;
+}
+//!generate native code to get the current method from glue
+
+//!It uses one scratch register
+int get_glue_method(int reg, bool isPhysical) {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, interpSave.method), C_SCRATCH_1, isScratchPhysical, reg, isPhysical);
+ return 0;
+}
+//!generate native code to set the current method in glue
+
+//!It uses one scratch register
+int set_glue_method(int reg, bool isPhysical) {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_reg_to_mem(OpndSize_32, reg, isPhysical, offsetof(Thread, interpSave.method), C_SCRATCH_1, isScratchPhysical);
+ return 0;
+}
+
+//!generate native code to get DvmDex from glue
+
+//!It uses one scratch register
+int get_glue_dvmdex(int reg, bool isPhysical) {
+ //if spill_loc_index > 0 || reg != NULL, use registerAlloc
+ if(isGlueHandled(PhysicalReg_GLUE_DVMDEX)) {
+ //if spill_loc_index > 0
+ // load from spilled location, updte spill_loc_index & physicalReg
+ startNativeCode(-1, -1);
+ freeReg(true);
+ int regAll = registerAlloc(LowOpndRegType_gp, PhysicalReg_GLUE_DVMDEX, false, false/*updateRefCount*/);
+ donotSpillReg(regAll);
+ dump_reg_reg_noalloc_src(Mnemonic_MOV, ATOM_NORMAL, OpndSize_32, regAll, true,
+ reg, isPhysical, LowOpndRegType_gp);
+ endNativeCode();
+ }
+ else
+ {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, interpSave.methodClassDex), C_SCRATCH_1, isScratchPhysical, reg, isPhysical);
+ //glue is not in a physical reg nor in a spilled location
+ updateGlue(reg, isPhysical, PhysicalReg_GLUE_DVMDEX); //spill_loc_index is -1, set physicalReg
+ }
+ return 0;
+}
+//!generate native code to set DvmDex in glue
+
+//!It uses one scratch register
+int set_glue_dvmdex(int reg, bool isPhysical) {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_reg_to_mem(OpndSize_32, reg, isPhysical, offsetof(Thread, interpSave.methodClassDex), C_SCRATCH_1, isScratchPhysical);
+ return 0;
+}
+//!generate native code to get SuspendCount from glue
+
+//!It uses one scratch register
+int get_suspendCount(int reg, bool isPhysical) {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, suspendCount), C_SCRATCH_1, isScratchPhysical, reg, isPhysical);
+ return 0;
+}
+
+//!generate native code to get retval from glue
+
+//!It uses one scratch register
+int get_return_value(OpndSize size, int reg, bool isPhysical) {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_mem_to_reg(size, offsetof(Thread, interpSave.retval), C_SCRATCH_1, isScratchPhysical, reg, isPhysical);
+ return 0;
+}
+//!generate native code to set retval in glue
+
+//!It uses one scratch register
+int set_return_value(OpndSize size, int reg, bool isPhysical) {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_reg_to_mem(size, reg, isPhysical, offsetof(Thread, interpSave.retval), C_SCRATCH_1, isScratchPhysical);
+ return 0;
+}
+//!generate native code to clear exception object in glue
+
+//!It uses two scratch registers
+int clear_exception() {
+ get_self_pointer(C_SCRATCH_2, isScratchPhysical);
+ move_imm_to_mem(OpndSize_32, 0, offsetof(Thread, exception), C_SCRATCH_2, isScratchPhysical);
+ return 0;
+}
+//!generate native code to get exception object in glue
+
+//!It uses two scratch registers
+int get_exception(int reg, bool isPhysical) {
+ get_self_pointer(C_SCRATCH_2, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, exception), C_SCRATCH_2, isScratchPhysical, reg, isPhysical);
+ return 0;
+}
+//!generate native code to set exception object in glue
+
+//!It uses two scratch registers
+int set_exception(int reg, bool isPhysical) {
+ get_self_pointer(C_SCRATCH_2, isScratchPhysical);
+ move_reg_to_mem(OpndSize_32, reg, isPhysical, offsetof(Thread, exception), C_SCRATCH_2, isScratchPhysical);
+ return 0;
+}
+//!generate native code to save frame pointer and current PC in stack frame to glue
+
+//!It uses two scratch registers
+int save_pc_fp_to_glue() {
+ get_self_pointer(C_SCRATCH_1, isScratchPhysical);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offsetof(Thread, interpSave.curFrame), C_SCRATCH_1, isScratchPhysical);
+
+ //from stack-save currentPc
+ move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_localRefTop, PhysicalReg_FP, true, C_SCRATCH_2, isScratchPhysical);
+ move_reg_to_mem(OpndSize_32, C_SCRATCH_2, isScratchPhysical, offsetof(Thread, interpSave.pc), C_SCRATCH_1, isScratchPhysical);
+ return 0;
+}
+//! get SaveArea pointer
+
+//!
+int savearea_from_fp(int reg, bool isPhysical) {
+ load_effective_addr(-sizeofStackSaveArea, PhysicalReg_FP, true, reg, isPhysical);
+ return 0;
+}
+
+#ifdef DEBUG_CALL_STACK3
+int call_debug_dumpSwitch() {
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = debug_dumpSwitch;
+ callFuncPtr((int)funcPtr, "debug_dumpSwitch");
+ return 0;
+}
+#endif
+
+int call_dvmQuasiAtomicSwap64() {
+ typedef int64_t (*vmHelper)(int64_t, volatile int64_t*);
+ vmHelper funcPtr = dvmQuasiAtomicSwap64;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmQuasiAtomicSwap64");
+ callFuncPtr((int)funcPtr, "dvmQuasiAtomicSwap64");
+ afterCall("dvmQuasiAtomicSwap64");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmQuasiAtomicSwap64");
+ }
+ return 0;
+}
+
+int call_dvmQuasiAtomicRead64() {
+ typedef int64_t (*vmHelper)(volatile const int64_t*);
+ vmHelper funcPtr = dvmQuasiAtomicRead64;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmQuasiAtomiRead64");
+ callFuncPtr((int)funcPtr, "dvmQuasiAtomicRead64");
+ afterCall("dvmQuasiAtomicRead64");
+ touchEax(); //for return value
+ touchEdx();
+ } else {
+ callFuncPtr((int)funcPtr, "dvmQuasiAtomicRead64");
+ }
+ return 0;
+}
+
+int call_dvmJitToInterpPunt() {
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = dvmJitToInterpPunt;
+ callFuncPtr((int)funcPtr, "dvmJitToInterpPunt");
+ return 0;
+}
+
+int call_dvmJitToInterpNormal() {
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = dvmJitToInterpNormal;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmJitToInterpNormal");
+ callFuncPtr((int)funcPtr, "dvmJitToInterpNormal");
+ afterCall("dvmJitToInterpNormal");
+ touchEbx();
+ } else {
+ callFuncPtr((int)funcPtr, "dvmJitToInterpNormal");
+ }
+ return 0;
+}
+
+int call_dvmJitToInterpTraceSelectNoChain() {
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = dvmJitToInterpTraceSelectNoChain;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmJitToInterpTraceSelectNoChain");
+ callFuncPtr((int)funcPtr, "dvmJitToInterpTraceSelectNoChain");
+ afterCall("dvmJitToInterpTraceSelectNoChain");
+ touchEbx();
+ } else {
+ callFuncPtr((int)funcPtr, "dvmJitToInterpTraceSelectNoChain");
+ }
+ return 0;
+}
+
+int call_dvmJitToInterpTraceSelect() {
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = dvmJitToInterpTraceSelect;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmJitToInterpTraceSelect");
+ callFuncPtr((int)funcPtr, "dvmJitToInterpTraceSelect");
+ afterCall("dvmJitToInterpTraceSelect");
+ touchEbx();
+ } else {
+ callFuncPtr((int)funcPtr, "dvmJitToInterpTraceSelect");
+ }
+ return 0;
+}
+
+int call_dvmJitToPatchPredictedChain() {
+ typedef const Method * (*vmHelper)(const Method *method,
+ Thread *self,
+ PredictedChainingCell *cell,
+ const ClassObject *clazz);
+ vmHelper funcPtr = dvmJitToPatchPredictedChain;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmJitToPatchPredictedChain");
+ callFuncPtr((int)funcPtr, "dvmJitToPatchPredictedChain");
+ afterCall("dvmJitToPatchPredictedChain");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmJitToPatchPredictedChain");
+ }
+ return 0;
+}
+
+//!generate native code to call __moddi3
+
+//!
+int call_moddi3() {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("moddi3");
+ callFuncPtr((intptr_t)__moddi3, "__moddi3");
+ afterCall("moddi3");
+ } else {
+ callFuncPtr((intptr_t)__moddi3, "__moddi3");
+ }
+ return 0;
+}
+//!generate native code to call __divdi3
+
+//!
+int call_divdi3() {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("divdi3");
+ callFuncPtr((intptr_t)__divdi3, "__divdi3");
+ afterCall("divdi3");
+ } else {
+ callFuncPtr((intptr_t)__divdi3, "__divdi3");
+ }
+ return 0;
+}
+
+//!generate native code to call fmod
+
+//!
+int call_fmod() {
+ typedef double (*libHelper)(double, double);
+ libHelper funcPtr = fmod;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("fmod");
+ callFuncPtr((int)funcPtr, "fmod");
+ afterCall("fmod");
+ } else {
+ callFuncPtr((int)funcPtr, "fmod");
+ }
+ return 0;
+}
+//!generate native code to call fmodf
+
+//!
+int call_fmodf() {
+ typedef float (*libHelper)(float, float);
+ libHelper funcPtr = fmodf;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("fmodf");
+ callFuncPtr((int)funcPtr, "fmodf");
+ afterCall("fmodf");
+ } else {
+ callFuncPtr((int)funcPtr, "fmodf");
+ }
+ return 0;
+}
+//!generate native code to call dvmFindCatchBlock
+
+//!
+int call_dvmFindCatchBlock() {
+ //int dvmFindCatchBlock(Thread* self, int relPc, Object* exception,
+ //bool doUnroll, void** newFrame)
+ typedef int (*vmHelper)(Thread*, int, Object*, bool, void**);
+ vmHelper funcPtr = dvmFindCatchBlock;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmFindCatchBlock");
+ callFuncPtr((int)funcPtr, "dvmFindCatchBlock");
+ afterCall("dvmFindCatchBlock");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmFindCatchBlock");
+ }
+ return 0;
+}
+//!generate native code to call dvmThrowVerificationError
+
+//!
+int call_dvmThrowVerificationError() {
+ typedef void (*vmHelper)(const Method*, int, int);
+ vmHelper funcPtr = dvmThrowVerificationError;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmThrowVerificationError");
+ callFuncPtr((int)funcPtr, "dvmThrowVerificationError");
+ afterCall("dvmThrowVerificationError");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmThrowVerificationError");
+ }
+ return 0;
+}
+
+//!generate native code to call dvmResolveMethod
+
+//!
+int call_dvmResolveMethod() {
+ //Method* dvmResolveMethod(const ClassObject* referrer, u4 methodIdx, MethodType methodType);
+ typedef Method* (*vmHelper)(const ClassObject*, u4, MethodType);
+ vmHelper funcPtr = dvmResolveMethod;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmResolveMethod");
+ callFuncPtr((int)funcPtr, "dvmResolveMethod");
+ afterCall("dvmResolveMethod");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmResolveMethod");
+ }
+ return 0;
+}
+//!generate native code to call dvmResolveClass
+
+//!
+int call_dvmResolveClass() {
+ //ClassObject* dvmResolveClass(const ClassObject* referrer, u4 classIdx, bool fromUnverifiedConstant)
+ typedef ClassObject* (*vmHelper)(const ClassObject*, u4, bool);
+ vmHelper funcPtr = dvmResolveClass;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmResolveClass");
+ callFuncPtr((int)funcPtr, "dvmResolveClass");
+ afterCall("dvmResolveClass");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmResolveClass");
+ }
+ return 0;
+}
+
+//!generate native code to call dvmInstanceofNonTrivial
+
+//!
+int call_dvmInstanceofNonTrivial() {
+ typedef int (*vmHelper)(const ClassObject*, const ClassObject*);
+ vmHelper funcPtr = dvmInstanceofNonTrivial;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmInstanceofNonTrivial");
+ callFuncPtr((int)funcPtr, "dvmInstanceofNonTrivial");
+ afterCall("dvmInstanceofNonTrivial");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmInstanceofNonTrivial");
+ }
+ return 0;
+}
+//!generate native code to call dvmThrowException
+
+//!
+int call_dvmThrow() {
+ typedef void (*vmHelper)(ClassObject* exceptionClass, const char*);
+ vmHelper funcPtr = dvmThrowException;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmThrowException");
+ callFuncPtr((int)funcPtr, "dvmThrowException");
+ afterCall("dvmThrowException");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmThrowException");
+ }
+ return 0;
+}
+//!generate native code to call dvmThrowExceptionWithClassMessage
+
+//!
+int call_dvmThrowWithMessage() {
+ typedef void (*vmHelper)(ClassObject* exceptionClass, const char*);
+ vmHelper funcPtr = dvmThrowExceptionWithClassMessage;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmThrowExceptionWithClassMessage");
+ callFuncPtr((int)funcPtr, "dvmThrowExceptionWithClassMessage");
+ afterCall("dvmThrowExceptionWithClassMessage");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmThrowExceptionWithClassMessage");
+ }
+ return 0;
+}
+//!generate native code to call dvmCheckSuspendPending
+
+//!
+int call_dvmCheckSuspendPending() {
+ typedef bool (*vmHelper)(Thread*);
+ vmHelper funcPtr = dvmCheckSuspendPending;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmCheckSuspendPending");
+ callFuncPtr((int)funcPtr, "dvmCheckSuspendPending");
+ afterCall("dvmCheckSuspendPending");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmCheckSuspendPending");
+ }
+ return 0;
+}
+//!generate native code to call dvmLockObject
+
+//!
+int call_dvmLockObject() {
+ typedef void (*vmHelper)(struct Thread*, struct Object*);
+ vmHelper funcPtr = dvmLockObject;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmLockObject");
+ callFuncPtr((int)funcPtr, "dvmLockObject");
+ afterCall("dvmLockObject");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmLockObject");
+ }
+ return 0;
+}
+//!generate native code to call dvmUnlockObject
+
+//!
+int call_dvmUnlockObject() {
+ typedef bool (*vmHelper)(Thread*, Object*);
+ vmHelper funcPtr = dvmUnlockObject;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmUnlockObject");
+ callFuncPtr((int)funcPtr, "dvmUnlockObject");
+ afterCall("dvmUnlockObject");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmUnlockObject");
+ }
+ return 0;
+}
+//!generate native code to call dvmInitClass
+
+//!
+int call_dvmInitClass() {
+ typedef bool (*vmHelper)(ClassObject*);
+ vmHelper funcPtr = dvmInitClass;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmInitClass");
+ callFuncPtr((int)funcPtr, "dvmInitClass");
+ afterCall("dvmInitClass");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmInitClass");
+ }
+ return 0;
+}
+//!generate native code to call dvmAllocObject
+
+//!
+int call_dvmAllocObject() {
+ typedef Object* (*vmHelper)(ClassObject*, int);
+ vmHelper funcPtr = dvmAllocObject;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmAllocObject");
+ callFuncPtr((int)funcPtr, "dvmAllocObject");
+ afterCall("dvmAllocObject");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmAllocObject");
+ }
+ return 0;
+}
+//!generate native code to call dvmAllocArrayByClass
+
+//!
+int call_dvmAllocArrayByClass() {
+ typedef ArrayObject* (*vmHelper)(ClassObject*, size_t, int);
+ vmHelper funcPtr = dvmAllocArrayByClass;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmAllocArrayByClass");
+ callFuncPtr((int)funcPtr, "dvmAllocArrayByClass");
+ afterCall("dvmAllocArrayByClass");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmAllocArrayByClass");
+ }
+ return 0;
+}
+//!generate native code to call dvmAllocPrimitiveArray
+
+//!
+int call_dvmAllocPrimitiveArray() {
+ typedef ArrayObject* (*vmHelper)(char, size_t, int);
+ vmHelper funcPtr = dvmAllocPrimitiveArray;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmAllocPrimitiveArray");
+ callFuncPtr((int)funcPtr, "dvmAllocPrimitiveArray");
+ afterCall("dvmAllocPrimitiveArray");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmAllocPrimitiveArray");
+ }
+ return 0;
+}
+//!generate native code to call dvmInterpHandleFillArrayData
+
+//!
+int call_dvmInterpHandleFillArrayData() {
+ typedef bool (*vmHelper)(ArrayObject*, const u2*);
+ vmHelper funcPtr = dvmInterpHandleFillArrayData;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmInterpHandleFillArrayData"); //before move_imm_to_reg to avoid spilling C_SCRATCH_1
+ callFuncPtr((int)funcPtr, "dvmInterpHandleFillArrayData");
+ afterCall("dvmInterpHandleFillArrayData");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmInterpHandleFillArrayData");
+ }
+ return 0;
+}
+
+//!generate native code to call dvmNcgHandlePackedSwitch
+
+//!
+int call_dvmNcgHandlePackedSwitch() {
+ typedef s4 (*vmHelper)(const s4*, s4, u2, s4);
+ vmHelper funcPtr = dvmNcgHandlePackedSwitch;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmNcgHandlePackedSwitch");
+ callFuncPtr((int)funcPtr, "dvmNcgHandlePackedSwitch");
+ afterCall("dvmNcgHandlePackedSwitch");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmNcgHandlePackedSwitch");
+ }
+ return 0;
+}
+
+int call_dvmJitHandlePackedSwitch() {
+ typedef s4 (*vmHelper)(const s4*, s4, u2, s4);
+ vmHelper funcPtr = dvmJitHandlePackedSwitch;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmJitHandlePackedSwitch");
+ callFuncPtr((int)funcPtr, "dvmJitHandlePackedSwitch");
+ afterCall("dvmJitHandlePackedSwitch");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmJitHandlePackedSwitch");
+ }
+ return 0;
+}
+
+//!generate native code to call dvmNcgHandleSparseSwitch
+
+//!
+int call_dvmNcgHandleSparseSwitch() {
+ typedef s4 (*vmHelper)(const s4*, u2, s4);
+ vmHelper funcPtr = dvmNcgHandleSparseSwitch;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmNcgHandleSparseSwitch");
+ callFuncPtr((int)funcPtr, "dvmNcgHandleSparseSwitch");
+ afterCall("dvmNcgHandleSparseSwitch");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmNcgHandleSparseSwitch");
+ }
+ return 0;
+}
+
+int call_dvmJitHandleSparseSwitch() {
+ typedef s4 (*vmHelper)(const s4*, u2, s4);
+ vmHelper funcPtr = dvmJitHandleSparseSwitch;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmJitHandleSparseSwitch");
+ callFuncPtr((int)funcPtr, "dvmJitHandleSparseSwitch");
+ afterCall("dvmJitHandleSparseSwitch");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmJitHandleSparseSwitch");
+ }
+ return 0;
+}
+
+//!generate native code to call dvmCanPutArrayElement
+
+//!
+int call_dvmCanPutArrayElement() {
+ typedef bool (*vmHelper)(const ClassObject*, const ClassObject*);
+ vmHelper funcPtr = dvmCanPutArrayElement;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmCanPutArrayElement");
+ callFuncPtr((int)funcPtr, "dvmCanPutArrayElement");
+ afterCall("dvmCanPutArrayElement");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmCanPutArrayElement");
+ }
+ return 0;
+}
+
+//!generate native code to call dvmFindInterfaceMethodInCache2
+
+//!
+int call_dvmFindInterfaceMethodInCache() {
+ typedef Method* (*vmHelper)(ClassObject*, u4, const Method*, DvmDex*);
+ vmHelper funcPtr = dvmFindInterfaceMethodInCache2;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmFindInterfaceMethodInCache2");
+ callFuncPtr((int)funcPtr, "dvmFindInterfaceMethodInCache2");
+ afterCall("dvmFindInterfaceMethodInCache2");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmFindInterfaceMethodInCache2");
+ }
+ return 0;
+}
+
+//!generate native code to call dvmHandleStackOverflow
+
+//!
+int call_dvmHandleStackOverflow() {
+ typedef void (*vmHelper)(Thread*, const Method*);
+ vmHelper funcPtr = dvmHandleStackOverflow;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmHandleStackOverflow");
+ callFuncPtr((int)funcPtr, "dvmHandleStackOverflow");
+ afterCall("dvmHandleStackOverflow");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmHandleStackOverflow");
+ }
+ return 0;
+}
+//!generate native code to call dvmResolveString
+
+//!
+int call_dvmResolveString() {
+ //StringObject* dvmResolveString(const ClassObject* referrer, u4 stringIdx)
+ typedef StringObject* (*vmHelper)(const ClassObject*, u4);
+ vmHelper funcPtr = dvmResolveString;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmResolveString");
+ callFuncPtr((int)funcPtr, "dvmResolveString");
+ afterCall("dvmResolveString");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmResolveString");
+ }
+ return 0;
+}
+//!generate native code to call dvmResolveInstField
+
+//!
+int call_dvmResolveInstField() {
+ //InstField* dvmResolveInstField(const ClassObject* referrer, u4 ifieldIdx)
+ typedef InstField* (*vmHelper)(const ClassObject*, u4);
+ vmHelper funcPtr = dvmResolveInstField;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmResolveInstField");
+ callFuncPtr((int)funcPtr, "dvmResolveInstField");
+ afterCall("dvmResolveInstField");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmResolveInstField");
+ }
+ return 0;
+}
+//!generate native code to call dvmResolveStaticField
+
+//!
+int call_dvmResolveStaticField() {
+ //StaticField* dvmResolveStaticField(const ClassObject* referrer, u4 sfieldIdx)
+ typedef StaticField* (*vmHelper)(const ClassObject*, u4);
+ vmHelper funcPtr = dvmResolveStaticField;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall("dvmResolveStaticField");
+ callFuncPtr((int)funcPtr, "dvmResolveStaticField");
+ afterCall("dvmResolveStaticField");
+ } else {
+ callFuncPtr((int)funcPtr, "dvmResolveStaticField");
+ }
+ return 0;
+}
+
+#define P_GPR_2 PhysicalReg_ECX
+/*!
+\brief This function is used to resolve a string reference
+
+INPUT: const pool index in %eax
+
+OUTPUT: resolved string in %eax
+
+The registers are hard-coded, 2 physical registers %esi and %edx are used as scratch registers;
+It calls a C function dvmResolveString;
+The only register that is still live after this function is ebx
+*/
+int const_string_resolve() {
+ scratchRegs[0] = PhysicalReg_ESI; scratchRegs[1] = PhysicalReg_EDX;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ insertLabel(".const_string_resolve", false);
+ //method stored in glue structure as well as on the interpreted stack
+ get_glue_method_class(P_GPR_2, true);
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 4, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, P_GPR_2, true, 0, PhysicalReg_ESP, true);
+ call_dvmResolveString();
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ compare_imm_reg( OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump(Condition_E, "common_exceptionThrown", false);
+ x86_return();
+ return 0;
+}
+#undef P_GPR_2
+/*!
+\brief This function is used to resolve a class
+
+INPUT: const pool index in argument "indexReg" (%eax)
+
+OUTPUT: resolved class in %eax
+
+The registers are hard-coded, 3 physical registers (%esi, %edx, startLR:%eax) are used as scratch registers.
+It calls a C function dvmResolveClass;
+The only register that is still live after this function is ebx
+*/
+int resolve_class2(
+ int startLR/*scratch register*/, bool isPhysical, int indexReg/*const pool index*/,
+ bool indexPhysical, int thirdArg) {
+ insertLabel(".class_resolve", false);
+ scratchRegs[0] = PhysicalReg_ESI; scratchRegs[1] = PhysicalReg_EDX;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+
+ //push index to stack first, to free indexReg
+ load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, indexReg, indexPhysical, 4, PhysicalReg_ESP, true);
+ get_glue_method_class(startLR, isPhysical);
+ move_imm_to_mem(OpndSize_32, thirdArg, 8, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, startLR, isPhysical, 0, PhysicalReg_ESP, true);
+ call_dvmResolveClass();
+ load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump(Condition_E, "common_exceptionThrown", false);
+
+ x86_return();
+ return 0;
+}
+/*!
+\brief This function is used to resolve a method, and it is called once with %eax for both indexReg and startLR
+
+INPUT: const pool index in argument "indexReg" (%eax)
+
+OUTPUT: resolved method in %eax
+
+The registers are hard-coded, 3 physical registers (%esi, %edx, startLR:%eax) are used as scratch registers.
+It calls a C function dvmResolveMethod;
+The only register that is still live after this function is ebx
+*/
+int resolve_method2(
+ int startLR/*logical register index*/, bool isPhysical, int indexReg/*const pool index*/,
+ bool indexPhysical,
+ int thirdArg/*VIRTUAL*/) {
+ if(thirdArg == METHOD_VIRTUAL)
+ insertLabel(".virtual_method_resolve", false);
+ else if(thirdArg == METHOD_DIRECT)
+ insertLabel(".direct_method_resolve", false);
+ else if(thirdArg == METHOD_STATIC)
+ insertLabel(".static_method_resolve", false);
+
+ load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, indexReg, indexPhysical, 4, PhysicalReg_ESP, true);
+
+ scratchRegs[0] = PhysicalReg_ESI; scratchRegs[1] = PhysicalReg_EDX;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ get_glue_method_class(startLR, isPhysical);
+
+ move_imm_to_mem(OpndSize_32, thirdArg, 8, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, startLR, isPhysical, 0, PhysicalReg_ESP, true);
+ call_dvmResolveMethod();
+ load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump(Condition_E, "common_exceptionThrown", false);
+
+ x86_return();
+ return 0;
+}
+/*!
+\brief This function is used to resolve an instance field
+
+INPUT: const pool index in argument "indexReg" (%eax)
+
+OUTPUT: resolved field in %eax
+
+The registers are hard-coded, 3 physical registers (%esi, %edx, startLR:%eax) are used as scratch registers.
+It calls a C function dvmResolveInstField;
+The only register that is still live after this function is ebx
+*/
+int resolve_inst_field2(
+ int startLR/*logical register index*/, bool isPhysical,
+ int indexReg/*const pool index*/, bool indexPhysical) {
+ insertLabel(".inst_field_resolve", false);
+ scratchRegs[0] = PhysicalReg_ESI; scratchRegs[1] = PhysicalReg_EDX;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, indexReg, indexPhysical, 4, PhysicalReg_ESP, true);
+ //method stored in glue structure as well as interpreted stack
+ get_glue_method_class(startLR, isPhysical);
+ move_reg_to_mem(OpndSize_32, startLR, isPhysical, 0, PhysicalReg_ESP, true);
+ call_dvmResolveInstField();
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump(Condition_E, "common_exceptionThrown", false);
+
+ x86_return();
+ return 0;
+}
+/*!
+\brief This function is used to resolve a static field
+
+INPUT: const pool index in argument "indexReg" (%eax)
+
+OUTPUT: resolved field in %eax
+
+The registers are hard-coded, 3 physical registers (%esi, %edx, startLR:%eax) are used as scratch registers.
+It calls a C function dvmResolveStaticField;
+The only register that is still live after this function is ebx
+*/
+int resolve_static_field2(
+ int startLR/*logical register index*/, bool isPhysical, int indexReg/*const pool index*/,
+ bool indexPhysical) {
+ insertLabel(".static_field_resolve", false);
+ scratchRegs[0] = PhysicalReg_ESI; scratchRegs[1] = PhysicalReg_EDX;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, indexReg, indexPhysical, 4, PhysicalReg_ESP, true);
+ get_glue_method_class(startLR, isPhysical);
+ move_reg_to_mem(OpndSize_32, startLR, isPhysical, 0, PhysicalReg_ESP, true);
+ call_dvmResolveStaticField();
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump(Condition_E, "common_exceptionThrown", false);
+
+ x86_return();
+ return 0;
+}
+
+int pushAllRegs() {
+ load_effective_addr(-28, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem_noalloc(OpndSize_32, PhysicalReg_EAX, true, 24, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1);
+ move_reg_to_mem_noalloc(OpndSize_32, PhysicalReg_EBX, true, 20, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1);
+ move_reg_to_mem_noalloc(OpndSize_32, PhysicalReg_ECX, true, 16, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1);
+ move_reg_to_mem_noalloc(OpndSize_32, PhysicalReg_EDX, true, 12, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1);
+ move_reg_to_mem_noalloc(OpndSize_32, PhysicalReg_ESI, true, 8, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1);
+ move_reg_to_mem_noalloc(OpndSize_32, PhysicalReg_EDI, true, 4, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1);
+ move_reg_to_mem_noalloc(OpndSize_32, PhysicalReg_EBP, true, 0, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1);
+ return 0;
+}
+int popAllRegs() {
+ move_mem_to_reg_noalloc(OpndSize_32, 24, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1, PhysicalReg_EAX, true);
+ move_mem_to_reg_noalloc(OpndSize_32, 20, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1, PhysicalReg_EBX, true);
+ move_mem_to_reg_noalloc(OpndSize_32, 16, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1, PhysicalReg_ECX, true);
+ move_mem_to_reg_noalloc(OpndSize_32, 12, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1, PhysicalReg_EDX, true);
+ move_mem_to_reg_noalloc(OpndSize_32, 8, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1, PhysicalReg_ESI, true);
+ move_mem_to_reg_noalloc(OpndSize_32, 4, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1, PhysicalReg_EDI, true);
+ move_mem_to_reg_noalloc(OpndSize_32, 0, PhysicalReg_ESP, true, MemoryAccess_Unknown, -1, PhysicalReg_EBP, true);
+ load_effective_addr(28, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ return 0;
+}
+
+void dump_nop(int size) {
+ switch(size) {
+ case 1:
+ *stream = 0x90;
+ break;
+ case 2:
+ *stream = 0x66;
+ *(stream +1) = 0x90;
+ break;
+ case 3:
+ *stream = 0x0f;
+ *(stream + 1) = 0x1f;
+ *(stream + 2) = 0x00;
+ break;
+ default:
+ //TODO: add more cases.
+ break;
+ }
+ stream += size;
+}
diff --git a/vm/compiler/codegen/x86/LowerInvoke.cpp b/vm/compiler/codegen/x86/LowerInvoke.cpp
new file mode 100644
index 0000000..3d02190
--- /dev/null
+++ b/vm/compiler/codegen/x86/LowerInvoke.cpp
@@ -0,0 +1,1661 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file LowerInvoke.cpp
+ \brief This file lowers the following bytecodes: INVOKE_XXX
+*/
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "mterp/Mterp.h"
+#include "Lower.h"
+#include "NcgAot.h"
+#include "enc_wrapper.h"
+
+char* streamMisPred = NULL;
+
+/* according to callee, decide the ArgsDoneType*/
+ArgsDoneType convertCalleeToType(const Method* calleeMethod) {
+ if(calleeMethod == NULL)
+ return ArgsDone_Full;
+ if(dvmIsNativeMethod(calleeMethod))
+ return ArgsDone_Native;
+ return ArgsDone_Normal;
+}
+int common_invokeMethodRange(ArgsDoneType);
+int common_invokeMethodNoRange(ArgsDoneType);
+void gen_predicted_chain(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg);
+
+//inputs to common_invokeMethodRange: %ecx
+// common_errNoSuchMethod: %edx
+#define P_GPR_1 PhysicalReg_ESI
+#define P_GPR_2 PhysicalReg_EBX
+#define P_GPR_3 PhysicalReg_ECX
+#define P_SCRATCH_1 PhysicalReg_EDX
+#define PP_GPR_1 PhysicalReg_EBX
+#define PP_GPR_2 PhysicalReg_ESI
+#define PP_GPR_3 PhysicalReg_EAX
+#define PP_GPR_4 PhysicalReg_EDX
+
+#ifdef WITH_JIT_INLINING
+/*
+ * The function here takes care the
+ * branch over if prediction is correct and the misprediction target for misPredBranchOver.
+ */
+static void genLandingPadForMispredictedCallee(MIR* mir) {
+ BasicBlock *fallThrough = traceCurrentBB->fallThrough;
+ /* Bypass the move-result block if there is one */
+ if (fallThrough->firstMIRInsn) {
+ assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED);
+ fallThrough = fallThrough->fallThrough;
+ }
+ /* Generate a branch over if the predicted inlining is correct */
+ jumpToBasicBlock(stream, fallThrough->id);
+ /* Hook up the target to the verification branch */
+ int relativeNCG = stream - streamMisPred;
+ unsigned instSize = encoder_get_inst_size(streamMisPred);
+ relativeNCG -= instSize; //size of the instruction
+ updateJumpInst(streamMisPred, OpndSize_8, relativeNCG);
+}
+#endif
+
+//! LOWER bytecode INVOKE_VIRTUAL without usage of helper function
+
+//!
+int common_invoke_virtual_nohelper(bool isRange, u2 tmp, u2 vD) {
+#ifdef WITH_JIT_INLINING
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (traceCurrentMIR->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(); //cUnit, mir, bb, labelList);
+ }
+#endif
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ export_pc();
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+
+ get_virtual_reg(vD, OpndSize_32, 5, false);
+ simpleNullCheck(5, false, vD);
+#ifndef PREDICTED_CHAINING
+ move_mem_to_reg(OpndSize_32, offObject_clazz, 5, false, 6, false); //clazz of "this"
+ move_mem_to_reg(OpndSize_32, offClassObject_vtable, 6, false, 7, false); //vtable
+ /* method is already resolved in trace-based JIT */
+ int methodIndex =
+ currentMethod->clazz->pDvmDex->pResMethods[tmp]->methodIndex;
+ move_mem_to_reg(OpndSize_32, methodIndex*4, 7, false, PhysicalReg_ECX, true);
+ if(isRange) {
+ common_invokeMethodRange(ArgsDone_Full);
+ }
+ else {
+ common_invokeMethodNoRange(ArgsDone_Full);
+ }
+#else
+ int methodIndex =
+ currentMethod->clazz->pDvmDex->pResMethods[tmp]->methodIndex;
+ gen_predicted_chain(isRange, tmp, methodIndex*4, false, 5/*tmp5*/);
+#endif
+ ///////////////////////////////////
+ return 0;
+}
+//! wrapper to call either common_invoke_virtual_helper or common_invoke_virtual_nohelper
+
+//!
+int common_invoke_virtual(bool isRange, u2 tmp, u2 vD) {
+ return common_invoke_virtual_nohelper(isRange, tmp, vD);
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef P_SCRATCH_1
+#undef PP_GPR_1
+#undef PP_GPR_2
+#undef PP_GPR_3
+#undef PP_GPR_4
+
+#define P_GPR_1 PhysicalReg_ESI
+#define P_GPR_2 PhysicalReg_EBX
+#define P_GPR_3 PhysicalReg_EDX
+#define PP_GPR_1 PhysicalReg_EBX
+#define PP_GPR_2 PhysicalReg_ESI
+#define PP_GPR_3 PhysicalReg_EAX
+#define PP_GPR_4 PhysicalReg_EDX
+//! common section to lower INVOKE_SUPER
+
+//! It will use helper function if the switch is on
+int common_invoke_super(bool isRange, u2 tmp) {
+ export_pc();
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+ ///////////////////////
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ /* method is already resolved in trace-based JIT */
+ int mIndex = currentMethod->clazz->pDvmDex->pResMethods[tmp]->methodIndex;
+ const Method *calleeMethod =
+ currentMethod->clazz->super->vtable[mIndex];
+ move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true);
+ if(isRange) {
+ common_invokeMethodRange(convertCalleeToType(calleeMethod));
+ }
+ else {
+ common_invokeMethodNoRange(convertCalleeToType(calleeMethod));
+ }
+ ///////////////////////////////
+ return 0;
+}
+#undef PP_GPR_1
+#undef PP_GPR_2
+#undef PP_GPR_3
+#undef PP_GPR_4
+
+//! helper function to handle no such method error
+
+//!
+int invoke_super_nsm() {
+ insertLabel(".invoke_super_nsm", false);
+ //NOTE: it seems that the name in %edx is not used in common_errNoSuchMethod
+ move_mem_to_reg(OpndSize_32, offMethod_name, PhysicalReg_EAX, true, PhysicalReg_EDX, true); //method name
+ unconditional_jump("common_errNoSuchMethod", false);
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ESI
+#define P_GPR_3 PhysicalReg_ECX
+#define PP_GPR_1 PhysicalReg_EBX
+#define PP_GPR_2 PhysicalReg_ESI
+#define PP_GPR_3 PhysicalReg_EAX
+#define PP_GPR_4 PhysicalReg_EDX
+//! common section to lower INVOKE_DIRECT
+
+//! It will use helper function if the switch is on
+int common_invoke_direct(bool isRange, u2 tmp, u2 vD) {
+ //%ecx can be used as scratch when calling export_pc, get_res_methods and resolve_method
+ export_pc();
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+ ////////////////////////////////////
+ get_virtual_reg(vD, OpndSize_32, 5, false);
+ simpleNullCheck(5, false, vD);
+ /* method is already resolved in trace-based JIT */
+ const Method *calleeMethod =
+ currentMethod->clazz->pDvmDex->pResMethods[tmp];
+ move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true);
+ //%ecx passed to common_invokeMethod...
+ if(isRange) {
+ common_invokeMethodRange(convertCalleeToType(calleeMethod));
+ }
+ else {
+ common_invokeMethodNoRange(convertCalleeToType(calleeMethod));
+ }
+ ////////////////////////////
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef PP_GPR_1
+#undef PP_GPR_2
+#undef PP_GPR_3
+#undef PP_GPR_4
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_3 PhysicalReg_ECX
+#define PP_GPR_1 PhysicalReg_EBX
+#define PP_GPR_2 PhysicalReg_ESI
+#define PP_GPR_3 PhysicalReg_EAX
+#define PP_GPR_4 PhysicalReg_EDX
+//! common section to lower INVOKE_STATIC
+
+//! It will use helper function if the switch is on
+int common_invoke_static(bool isRange, u2 tmp) {
+ //%ecx can be used as scratch when calling export_pc, get_res_methods and resolve_method
+ export_pc();
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+ ////////////////////////////
+ /* method is already resolved in trace-based JIT */
+ const Method *calleeMethod =
+ currentMethod->clazz->pDvmDex->pResMethods[tmp];
+ move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true);
+ //%ecx passed to common_invokeMethod...
+ if(isRange) {
+ common_invokeMethodRange(convertCalleeToType(calleeMethod));
+ }
+ else {
+ common_invokeMethodNoRange(convertCalleeToType(calleeMethod));
+ }
+ ////////////////////////
+ return 0;
+}
+#undef P_GPR_1
+#undef PP_GPR_1
+#undef PP_GPR_2
+#undef PP_GPR_3
+#undef PP_GPR_4
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_EAX //scratch
+#define P_GPR_3 PhysicalReg_ECX
+#define P_SCRATCH_1 PhysicalReg_ESI //clazz of object
+#define PP_GPR_1 PhysicalReg_EBX
+#define PP_GPR_2 PhysicalReg_ESI
+#define PP_GPR_3 PhysicalReg_EAX
+#define PP_GPR_4 PhysicalReg_EDX
+//! common section to lower INVOKE_INTERFACE
+
+//! It will use helper function if the switch is on
+int common_invoke_interface(bool isRange, u2 tmp, u2 vD) {
+#ifdef WITH_JIT_INLINING
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (traceCurrentMIR->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(); //cUnit, mir, bb, labelList);
+ }
+#endif
+ export_pc(); //use %edx
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+ ///////////////////////
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ get_virtual_reg(vD, OpndSize_32, 1, false);
+ simpleNullCheck(1, false, vD);
+
+#ifndef PREDICTED_CHAINING
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true);
+ /* for trace-based JIT, pDvmDex is a constant at JIT time
+ 4th argument to dvmFindInterfaceMethodInCache at -4(%esp) */
+ move_imm_to_mem(OpndSize_32, (int) currentMethod->clazz->pDvmDex, 12, PhysicalReg_ESP, true);
+ move_mem_to_reg(OpndSize_32, offObject_clazz, 1, false, 5, false);
+ /* for trace-based JIT, method is a constant at JIT time
+ 3rd argument to dvmFindInterfaceMethodInCache at 8(%esp) */
+ move_imm_to_mem(OpndSize_32, (int) currentMethod, 8, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 5, false, 0, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_3; scratchRegs[1] = PhysicalReg_Null;
+ call_dvmFindInterfaceMethodInCache();
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+
+ conditional_jump_global_API(Condition_E, "common_exceptionThrown", false);
+ move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true);
+ if(isRange) {
+ common_invokeMethodRange(ArgsDone_Full);
+ }
+ else {
+ common_invokeMethodNoRange(ArgsDone_Full);
+ }
+#else
+ gen_predicted_chain(isRange, tmp, -1, true /*interface*/, 1/*tmp1*/);
+#endif
+ ///////////////////////
+ return 0;
+}
+#undef PP_GPR_1
+#undef PP_GPR_2
+#undef PP_GPR_3
+#undef PP_GPR_4
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef P_SCRATCH_1
+//! lower bytecode INVOKE_VIRTUAL by calling common_invoke_virtual
+
+//!
+int op_invoke_virtual() {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+#endif
+ //B|A|op CCCC G|F|E|D
+ //D: the first argument, which is the "this" pointer
+ //B: argument count
+ //D,E,F,G,A: arguments
+ u2 vD = FETCH(2) & 0xf;
+ u2 tmp = FETCH(1); //method index
+ int retval = common_invoke_virtual(false/*not range*/, tmp, vD);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_SUPER by calling common_invoke_super
+
+//!
+int op_invoke_super() {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+#endif
+ //B|A|op CCCC G|F|E|D
+ //D: the first argument
+ //B: argument count
+ //D,E,F,G,A: arguments
+ u2 tmp = FETCH(1); //method index
+ int retval = common_invoke_super(false/*not range*/, tmp);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_DIRECT by calling common_invoke_direct
+
+//!
+int op_invoke_direct() {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+#endif
+ //B|A|op CCCC G|F|E|D
+ //D: the first argument, which is the "this" pointer
+ //B: argument count
+ //D,E,F,G,A: arguments
+ u2 vD = FETCH(2) & 0xf;
+ u2 tmp = FETCH(1); //method index
+ int retval = common_invoke_direct(false/*not range*/, tmp, vD);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_STATIC by calling common_invoke_static
+
+//!
+int op_invoke_static() {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+#endif
+ //B|A|op CCCC G|F|E|D
+ //D: the first argument
+ //B: argument count
+ //D,E,F,G,A: arguments
+ u2 tmp = FETCH(1); //method index
+ int retval = common_invoke_static(false/*not range*/, tmp);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_INTERFACE by calling common_invoke_interface
+
+//!
+int op_invoke_interface() {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+#endif
+ //B|A|op CCCC G|F|E|D
+ //D: the first argument, which is the "this" pointer
+ //B: argument count
+ //D,E,F,G,A: arguments
+ u2 vD = FETCH(2) & 0xf;
+ u2 tmp = FETCH(1); //method index
+ int retval = common_invoke_interface(false/*not range*/, tmp, vD);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_VIRTUAL_RANGE by calling common_invoke_virtual
+
+//!
+int op_invoke_virtual_range() {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+#endif
+ //AA|op BBBB CCCC
+ //CCCC: the first argument, which is the "this" pointer
+ //AA: argument count
+ u2 tmp = FETCH(1); //BBBB, method index
+ u2 vD = FETCH(2); //the first argument
+ int retval = common_invoke_virtual(true/*range*/, tmp, vD);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_SUPER_RANGE by calling common_invoke_super
+
+//!
+int op_invoke_super_range() {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+#endif
+ u2 tmp = FETCH(1); //BBBB, method index
+ int retval = common_invoke_super(true/*range*/, tmp);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_DIRECT_RANGE by calling common_invoke_direct
+
+//!
+int op_invoke_direct_range() {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+#endif
+ u2 tmp = FETCH(1); //BBBB, method index
+ u2 vD = FETCH(2); //the first argument
+ int retval = common_invoke_direct(true/*range*/, tmp, vD);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_STATIC_RANGE by calling common_invoke_static
+
+//!
+int op_invoke_static_range() {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+#endif
+ u2 tmp = FETCH(1); //BBBB, method index
+ int retval = common_invoke_static(true/*range*/, tmp);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_INTERFACE_RANGE by calling common_invoke_interface
+
+//!
+int op_invoke_interface_range() {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+#endif
+ u2 tmp = FETCH(1); //BBBB, method index
+ u2 vD = FETCH(2); //the first argument
+ int retval = common_invoke_interface(true/*range*/, tmp, vD);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+
+//used %ecx, %edi, %esp %ebp
+#define P_GPR_1 PhysicalReg_EBX
+#define P_SCRATCH_1 PhysicalReg_ESI
+#define P_SCRATCH_2 PhysicalReg_EAX
+#define P_SCRATCH_3 PhysicalReg_EDX
+#define P_SCRATCH_4 PhysicalReg_ESI
+#define P_SCRATCH_5 PhysicalReg_EAX
+//! pass the arguments for invoking method without range
+
+//!
+int common_invokeMethodNoRange_noJmp() {
+ u2 count = INST_B(inst);
+ u2 vD = FETCH(2) & 0xf;
+ u2 vE = (FETCH(2) >> 4) & 0xf;
+ u2 vF = (FETCH(2) >> 8) & 0xf;
+ u2 vG = (FETCH(2) >> 12) & 0xf;
+ u2 vA = INST_A(inst); //5th argument
+ int offsetFromSaveArea = -4;
+ if(count == 5) {
+ get_virtual_reg(vA, OpndSize_32, 22, false);
+ move_reg_to_mem(OpndSize_32, 22, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true);
+ offsetFromSaveArea -= 4;
+ }
+ if(count >= 4) {
+ get_virtual_reg(vG, OpndSize_32, 23, false);
+ move_reg_to_mem(OpndSize_32, 23, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true);
+ offsetFromSaveArea -= 4;
+ }
+ if(count >= 3) {
+ get_virtual_reg(vF, OpndSize_32, 24, false);
+ move_reg_to_mem(OpndSize_32, 24, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true);
+ offsetFromSaveArea -= 4;
+ }
+ if(count >= 2) {
+ get_virtual_reg(vE, OpndSize_32, 25, false);
+ move_reg_to_mem(OpndSize_32, 25, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true);
+ offsetFromSaveArea -= 4;
+ }
+ if(count >= 1) {
+ get_virtual_reg(vD, OpndSize_32, 26, false);
+ move_reg_to_mem(OpndSize_32, 26, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true);
+ }
+ return 0;
+}
+
+int common_invokeMethod_Jmp(ArgsDoneType form) {
+ nextVersionOfHardReg(PhysicalReg_EDX, 1);
+ move_imm_to_reg(OpndSize_32, (int)rPC, PhysicalReg_EDX, true);
+ //arguments needed in ArgsDone:
+ // start of HotChainingCell for next bytecode: -4(%esp)
+ // start of InvokeSingletonChainingCell for callee: -8(%esp)
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ insertChainingWorklist(traceCurrentBB->fallThrough->id, stream);
+ move_chain_to_mem(OpndSize_32, traceCurrentBB->fallThrough->id, 4, PhysicalReg_ESP, true);
+ // for honeycomb: JNI call doesn't need a chaining cell, so the taken branch is null
+ if(traceCurrentBB->taken)
+ insertChainingWorklist(traceCurrentBB->taken->id, stream);
+ int takenId = traceCurrentBB->taken ? traceCurrentBB->taken->id : 0;
+ move_chain_to_mem(OpndSize_32, takenId, 0, PhysicalReg_ESP, true);
+ if(form == ArgsDone_Full)
+ unconditional_jump_global_API(".invokeArgsDone_jit", false);
+ else if(form == ArgsDone_Native)
+ unconditional_jump_global_API(".invokeArgsDone_native", false);
+ else
+ unconditional_jump_global_API(".invokeArgsDone_normal", false);
+ return 0;
+}
+
+int common_invokeMethodNoRange(ArgsDoneType form) {
+ common_invokeMethodNoRange_noJmp();
+ common_invokeMethod_Jmp(form);
+ return 0;
+}
+
+#undef P_GPR_1
+#undef P_SCRATCH_1
+#undef P_SCRATCH_2
+#undef P_SCRATCH_3
+#undef P_SCRATCH_4
+#undef P_SCRATCH_5
+
+//input: %ecx (method to call)
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ESI
+#define P_GPR_3 PhysicalReg_EDX //not used with P_SCRATCH_2
+#define P_SCRATCH_1 PhysicalReg_EAX
+#define P_SCRATCH_2 PhysicalReg_EDX
+#define P_SCRATCH_3 PhysicalReg_EAX
+#define P_SCRATCH_4 PhysicalReg_EDX
+#define P_SCRATCH_5 PhysicalReg_EAX
+#define P_SCRATCH_6 PhysicalReg_EDX
+#define P_SCRATCH_7 PhysicalReg_EAX
+#define P_SCRATCH_8 PhysicalReg_EDX
+#define P_SCRATCH_9 PhysicalReg_EAX
+#define P_SCRATCH_10 PhysicalReg_EDX
+//! pass the arguments for invoking method with range
+
+//! loop is unrolled when count <= 10
+int common_invokeMethodRange_noJmp() {
+ u2 count = INST_AA(inst);
+ u2 vD = FETCH(2); //the first argument
+ savearea_from_fp(21, false);
+ //vD to rFP-4*count-20
+ //vD+1 to rFP-4*count-20+4 = rFP-20-4*(count-1)
+ if(count >= 1 && count <= 10) {
+ get_virtual_reg(vD, OpndSize_32, 22, false);
+ move_reg_to_mem(OpndSize_32, 22, false, -4*count, 21, false);
+ }
+ if(count >= 2 && count <= 10) {
+ get_virtual_reg(vD+1, OpndSize_32, 23, false);
+ move_reg_to_mem(OpndSize_32, 23, false, -4*(count-1), 21, false);
+ }
+ if(count >= 3 && count <= 10) {
+ get_virtual_reg(vD+2, OpndSize_32, 24, false);
+ move_reg_to_mem(OpndSize_32, 24, false, -4*(count-2), 21, false);
+ }
+ if(count >= 4 && count <= 10) {
+ get_virtual_reg(vD+3, OpndSize_32, 25, false);
+ move_reg_to_mem(OpndSize_32, 25, false, -4*(count-3), 21, false);
+ }
+ if(count >= 5 && count <= 10) {
+ get_virtual_reg(vD+4, OpndSize_32, 26, false);
+ move_reg_to_mem(OpndSize_32, 26, false, -4*(count-4), 21, false);
+ }
+ if(count >= 6 && count <= 10) {
+ get_virtual_reg(vD+5, OpndSize_32, 27, false);
+ move_reg_to_mem(OpndSize_32, 27, false, -4*(count-5), 21, false);
+ }
+ if(count >= 7 && count <= 10) {
+ get_virtual_reg(vD+6, OpndSize_32, 28, false);
+ move_reg_to_mem(OpndSize_32, 28, false, -4*(count-6), 21, false);
+ }
+ if(count >= 8 && count <= 10) {
+ get_virtual_reg(vD+7, OpndSize_32, 29, false);
+ move_reg_to_mem(OpndSize_32, 29, false, -4*(count-7), 21, false);
+ }
+ if(count >= 9 && count <= 10) {
+ get_virtual_reg(vD+8, OpndSize_32, 30, false);
+ move_reg_to_mem(OpndSize_32, 30, false, -4*(count-8), 21, false);
+ }
+ if(count == 10) {
+ get_virtual_reg(vD+9, OpndSize_32, 31, false);
+ move_reg_to_mem(OpndSize_32, 31, false, -4*(count-9), 21, false);
+ }
+ if(count > 10) {
+ //dump to memory first, should we set physicalReg to Null?
+ //this bytecodes uses a set of virtual registers (update getVirtualInfo)
+ //this is necessary to correctly insert transfer points
+ int k;
+ for(k = 0; k < count; k++) {
+ spillVirtualReg(vD+k, LowOpndRegType_gp, true); //will update refCount
+ }
+ load_effective_addr(4*vD, PhysicalReg_FP, true, 12, false);
+ alu_binary_imm_reg(OpndSize_32, sub_opc, 4*count, 21, false);
+ move_imm_to_reg(OpndSize_32, count, 13, false);
+ insertLabel(".invokeMethod_1", true); //if checkDup: will perform work from ShortWorklist
+ rememberState(1);
+ move_mem_to_reg(OpndSize_32, 0, 12, false, 14, false);
+ move_reg_to_mem(OpndSize_32, 14, false, 0, 21, false);
+ load_effective_addr(4, 12, false, 12, false);
+ alu_binary_imm_reg(OpndSize_32, sub_opc, 1, 13, false);
+ load_effective_addr(4, 21, false, 21, false);
+ transferToState(1);
+ conditional_jump(Condition_NE, ".invokeMethod_1", true); //backward branch
+ }
+ return 0;
+}
+
+int common_invokeMethodRange(ArgsDoneType form) {
+ common_invokeMethodRange_noJmp();
+ common_invokeMethod_Jmp(form);
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef P_SCRATCH_1
+#undef P_SCRATCH_2
+#undef P_SCRATCH_3
+#undef P_SCRATCH_4
+#undef P_SCRATCH_5
+#undef P_SCRATCH_6
+#undef P_SCRATCH_7
+#undef P_SCRATCH_8
+#undef P_SCRATCH_9
+#undef P_SCRATCH_10
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_3 PhysicalReg_ESI
+#define P_SCRATCH_1 PhysicalReg_EAX
+#define P_SCRATCH_2 PhysicalReg_EDX
+#define P_SCRATCH_3 PhysicalReg_EAX
+#define P_SCRATCH_4 PhysicalReg_EDX
+#define P_SCRATCH_5 PhysicalReg_EAX
+#define P_SCRATCH_6 PhysicalReg_EDX
+
+//! spill a register to native stack
+
+//! decrease %esp by 4, then store a register at 0(%esp)
+int spill_reg(int reg, bool isPhysical) {
+ load_effective_addr(-4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, reg, isPhysical, 0, PhysicalReg_ESP, true);
+ return 0;
+}
+//! get a register from native stack
+
+//! load a register from 0(%esp), then increase %esp by 4
+int unspill_reg(int reg, bool isPhysical) {
+ move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, reg, isPhysical);
+ load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ return 0;
+}
+
+void generate_invokeNative(bool generateForNcg); //forward declaration
+void generate_stackOverflow(); //forward declaration
+
+//! common code to invoke a method after all arguments are handled
+
+//!
+//takes one argument to generate code
+// for invokeNativeSingle (form == ArgsDone_Native)
+// or invokeNonNativeSingle (form == ArgsDone_Normal) when WITH_JIT is true
+// to dynamically determine which one to choose (form == ArgsDone_Full)
+/* common_invokeArgsDone is called at NCG time and
+ at execution time during relocation
+ generate invokeArgsDone for NCG if isJitFull is false && form == Full */
+int common_invokeArgsDone(ArgsDoneType form, bool isJitFull) {
+ bool generateForNcg = false;
+ if(form == ArgsDone_Full) {
+ if(isJitFull)
+ insertLabel(".invokeArgsDone_jit", false);
+ else {
+ insertLabel(".invokeArgsDone", false);
+ generateForNcg = true;
+ }
+ }
+ else if(form == ArgsDone_Normal)
+ insertLabel(".invokeArgsDone_normal", false);
+ else if(form == ArgsDone_Native)
+ insertLabel(".invokeArgsDone_native", false);
+ //%ecx: methodToCall
+ movez_mem_to_reg(OpndSize_16, offMethod_registersSize, PhysicalReg_ECX, true, P_SCRATCH_1, true); //regSize
+ scratchRegs[0] = PhysicalReg_EBX; scratchRegs[1] = PhysicalReg_ESI;
+ scratchRegs[2] = PhysicalReg_EDX; scratchRegs[3] = PhysicalReg_Null;
+ savearea_from_fp(P_GPR_3, true);
+ alu_binary_imm_reg(OpndSize_32, shl_opc, 2, P_SCRATCH_1, true);
+ alu_binary_reg_reg(OpndSize_32, sub_opc, P_SCRATCH_1, true, P_GPR_3, true);
+ //update newSaveArea->savedPc, here P_GPR_3 is new FP
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true, offStackSaveArea_savedPc-sizeofStackSaveArea, P_GPR_3, true);
+ movez_mem_to_reg(OpndSize_16, offMethod_outsSize, PhysicalReg_ECX, true, P_SCRATCH_2, true); //outsSize
+ move_reg_to_reg(OpndSize_32, P_GPR_3, true, P_GPR_1, true); //new FP
+ alu_binary_imm_reg(OpndSize_32, sub_opc, sizeofStackSaveArea, P_GPR_3, true);
+
+ alu_binary_imm_reg(OpndSize_32, shl_opc, 2, P_SCRATCH_2, true);
+ alu_binary_reg_reg(OpndSize_32, sub_opc, P_SCRATCH_2, true, P_GPR_3, true);
+ get_self_pointer(P_SCRATCH_3, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offStackSaveArea_prevFrame-sizeofStackSaveArea, P_GPR_1, true); //set stack->prevFrame
+ compare_mem_reg(OpndSize_32, offsetof(Thread, interpStackEnd), P_SCRATCH_3, true, P_GPR_3, true);
+ conditional_jump(Condition_L, ".stackOverflow", true);
+
+ if(form == ArgsDone_Full) {
+ test_imm_mem(OpndSize_32, ACC_NATIVE, offMethod_accessFlags, PhysicalReg_ECX, true);
+ }
+ move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, offStackSaveArea_method-sizeofStackSaveArea, P_GPR_1, true); //set stack->method
+
+ if(form == ArgsDone_Native || form == ArgsDone_Full) {
+ /* to correctly handle code cache reset:
+ update returnAddr and check returnAddr after done with the native method
+ if returnAddr is set to NULL during code cache reset,
+ the execution will correctly continue with interpreter */
+ //get returnAddr from 4(%esp) and update stack
+ move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true,
+ PhysicalReg_EDX, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true,
+ offStackSaveArea_returnAddr-sizeofStackSaveArea, P_GPR_1, true);
+ }
+ if(form == ArgsDone_Native) {
+ generate_invokeNative(generateForNcg);
+ return 0;
+ }
+ if(form == ArgsDone_Full) {
+ conditional_jump(Condition_NE, ".invokeNative", true);
+ }
+ move_mem_to_reg(OpndSize_32, offMethod_clazz, PhysicalReg_ECX, true, P_SCRATCH_4, true); //get method->claz
+ move_mem_to_reg(OpndSize_32, offClassObject_pDvmDex, P_SCRATCH_4, true, P_SCRATCH_4, true); //get method->clazz->pDvmDex
+ move_reg_to_reg(OpndSize_32, P_GPR_1, true, PhysicalReg_FP, true); //update rFP
+ get_self_pointer(P_GPR_1, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, offsetof(Thread, interpSave.method), P_GPR_1, true); //glue->method
+ move_reg_to_mem(OpndSize_32, P_SCRATCH_4, true, offsetof(Thread, interpSave.methodClassDex), P_GPR_1, true); //set_glue_dvmdex
+ move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offThread_curFrame, P_GPR_1, true); //set glue->self->frame
+ if(!generateForNcg) {
+ /* returnAddr updated already for Full */
+ //get returnAddr from 4(%esp) and update stack
+ if(form == ArgsDone_Normal)
+ move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true,
+ PhysicalReg_EDX, true);
+ //for JIT: starting bytecode in %ebx to invoke JitToInterp
+ move_mem_to_reg(OpndSize_32, offMethod_insns, PhysicalReg_ECX, true, PhysicalReg_EBX, true);
+ if(form == ArgsDone_Normal)
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true,
+ offStackSaveArea_returnAddr-sizeofStackSaveArea, PhysicalReg_FP, true);
+ }
+
+ insertLabel(".invokeInterp", true);
+ if(!generateForNcg) {
+ bool callNoChain = false;
+#ifdef PREDICTED_CHAINING
+ if(form == ArgsDone_Full) callNoChain = true;
+#endif
+ if(callNoChain) {
+ scratchRegs[0] = PhysicalReg_EAX;
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ call_dvmJitToInterpTraceSelectNoChain(); //input: rPC in %ebx
+ } else {
+ //jump to the stub at (%esp)
+ move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true,
+ PhysicalReg_EDX, true);
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ unconditional_jump_reg(PhysicalReg_EDX, true);
+ }
+ }
+
+ if(form == ArgsDone_Full) generate_invokeNative(generateForNcg);
+ generate_stackOverflow();
+ return 0;
+}
+
+/* when WITH_JIT is true,
+ JIT'ed code invokes native method, after invoke, execution will continue
+ with the interpreter or with JIT'ed code if chained
+*/
+void generate_invokeNative(bool generateForNcg) {
+ insertLabel(".invokeNative", true);
+ //if(!generateForNcg)
+ // load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ load_effective_addr(-28, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, P_GPR_1, true, 0, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, P_GPR_1, true, 20, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_EDX;
+ get_self_pointer(P_SCRATCH_1, true); //glue->self
+ move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 8, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, P_SCRATCH_1, true, 12, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, P_SCRATCH_1, true, 24, PhysicalReg_ESP, true);
+ move_mem_to_reg(OpndSize_32, offThread_jniLocal_nextEntry, P_SCRATCH_1, true, P_SCRATCH_2, true); //get self->local_next
+ scratchRegs[1] = PhysicalReg_EAX;
+ move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, offStackSaveArea_localRefTop-sizeofStackSaveArea, P_GPR_1, true); //update jniLocalRef of stack
+ move_reg_to_mem(OpndSize_32, P_GPR_1, true, offThread_curFrame, P_SCRATCH_1, true); //set self->curFrame
+ move_imm_to_mem(OpndSize_32, 0, offThread_inJitCodeCache, P_SCRATCH_1, true); //clear self->inJitCodeCache
+ load_effective_addr(offsetof(Thread, interpSave.retval), P_SCRATCH_1, true, P_SCRATCH_3, true); //self->retval
+ move_reg_to_mem(OpndSize_32, P_SCRATCH_3, true, 4, PhysicalReg_ESP, true);
+ //NOTE: native method checks the interpreted stack for arguments
+ // The immediate arguments on native stack: address of return value, new FP, self
+ call_mem(40, PhysicalReg_ECX, true);//*40(%ecx)
+ //we can't assume the argument stack is unmodified after the function call
+ //duplicate newFP & glue->self on stack: newFP (-28 & -8) glue->self (-16 & -4)
+ move_mem_to_reg(OpndSize_32, 20, PhysicalReg_ESP, true, P_GPR_3, true); //new FP
+ move_mem_to_reg(OpndSize_32, 24, PhysicalReg_ESP, true, P_GPR_1, true); //glue->self
+ load_effective_addr(28, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_mem_to_reg(OpndSize_32, offStackSaveArea_localRefTop-sizeofStackSaveArea, P_GPR_3, true, P_SCRATCH_1, true); //newSaveArea->jniLocal
+ compare_imm_mem(OpndSize_32, 0, offThread_exception, P_GPR_1, true); //self->exception
+ if(!generateForNcg)
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ //NOTE: PhysicalReg_FP should be callee-saved register
+ move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offThread_curFrame, P_GPR_1, true); //set self->curFrame
+ move_reg_to_mem(OpndSize_32, P_SCRATCH_1, true, offThread_jniLocal_nextEntry, P_GPR_1, true); //set self->jniLocal
+ conditional_jump(Condition_NE, "common_exceptionThrown", false);
+ if(!generateForNcg) {
+ //get returnAddr, if it is not NULL,
+ // return to JIT'ed returnAddr after executing the native method
+ /* to correctly handle code cache reset:
+ update returnAddr and check returnAddr after done with the native method
+ if returnAddr is set to NULL during code cache reset,
+ the execution will correctly continue with interpreter */
+ move_mem_to_reg(OpndSize_32, offStackSaveArea_returnAddr-sizeofStackSaveArea, P_GPR_3, true, P_SCRATCH_2, true);
+ //set self->inJitCodeCache to returnAddr (P_GPR_1 is in %ebx)
+ move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, offThread_inJitCodeCache, P_GPR_1, true);
+ move_mem_to_reg(OpndSize_32, offStackSaveArea_savedPc-sizeofStackSaveArea, P_GPR_3, true, PhysicalReg_EBX, true); //savedPc
+ compare_imm_reg(OpndSize_32, 0, P_SCRATCH_2, true);
+ conditional_jump(Condition_E, ".nativeToInterp", true);
+ unconditional_jump_reg(P_SCRATCH_2, true);
+ //if returnAddr is NULL, return to interpreter after executing the native method
+ insertLabel(".nativeToInterp", true);
+ //move rPC by 6 (3 bytecode units for INVOKE)
+ alu_binary_imm_reg(OpndSize_32, add_opc, 6, PhysicalReg_EBX, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_dvmJitToInterpTraceSelectNoChain(); //rPC in %ebx
+ }
+ return;
+}
+void generate_stackOverflow() {
+ insertLabel(".stackOverflow", true);
+ //load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 4, PhysicalReg_ESP, true);
+ get_self_pointer(P_GPR_1, true); //glue->self
+ move_reg_to_mem(OpndSize_32, P_GPR_1, true, 0, PhysicalReg_ESP, true);
+ call_dvmHandleStackOverflow();
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ unconditional_jump("common_exceptionThrown", false);
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef P_SCRATCH_1
+#undef P_SCRATCH_2
+#undef P_SCRATCH_3
+#undef P_SCRATCH_4
+#undef P_SCRATCH_5
+#undef P_SCRATCH_6
+
+/////////////////////////////////////////////
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+#define P_SCRATCH_1 PhysicalReg_ESI
+#define P_SCRATCH_2 PhysicalReg_EDX
+#define P_SCRATCH_3 PhysicalReg_ESI
+#define P_SCRATCH_4 PhysicalReg_EDX
+//! lower bytecode EXECUTE_INLINE
+
+//!
+int op_execute_inline(bool isRange) {
+ //tmp, vC, vD, vE, vF
+ int num;
+ if(!isRange) num = INST_B(inst);
+ else num = INST_AA(inst);
+ u2 tmp = FETCH(1);
+ u2 vC, vD, vE, vF;
+ if(!isRange) {
+ vC = FETCH(2) & 0xf;
+ vD = (FETCH(2) >> 4) & 0xf;
+ vE = (FETCH(2) >> 8) & 0xf;
+ vF = FETCH(2) >> 12;
+ } else {
+ vC = FETCH(2);
+ vD = vC + 1;
+ vE = vC + 2;
+ vF = vC + 3;
+ }
+ export_pc();
+ switch (tmp) {
+ case INLINE_EMPTYINLINEMETHOD:
+ return 0; /* Nop */
+ case INLINE_STRING_LENGTH:
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ compare_imm_reg(OpndSize_32, 0, 1, false);
+ conditional_jump(Condition_NE, ".do_inlined_string_length", true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ jumpToExceptionThrown(1/*exception number*/);
+ insertLabel(".do_inlined_string_length", true);
+ move_mem_to_reg(OpndSize_32, 0x14, 1, false, 2, false);
+ get_self_pointer(3, false);
+ move_reg_to_mem(OpndSize_32, 2, false, offsetof(Thread, interpSave.retval), 3, false);
+ return 0;
+ case INLINE_STRING_IS_EMPTY:
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ compare_imm_reg(OpndSize_32, 0, 1, false);
+ conditional_jump(Condition_NE, ".do_inlined_string_length", true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ jumpToExceptionThrown(1/*exception number*/);
+ insertLabel(".do_inlined_string_length", true);
+ compare_imm_mem(OpndSize_32, 0, 0x14, 1, false);
+ conditional_jump(Condition_E, ".inlined_string_length_return_true",
+ true);
+ get_self_pointer(2, false);
+ move_imm_to_mem(OpndSize_32, 0, offsetof(Thread, interpSave.retval), 2, false);
+ unconditional_jump(".inlined_string_length_done", true);
+ insertLabel(".inlined_string_length_return_true", true);
+ get_self_pointer(2, false);
+ move_imm_to_mem(OpndSize_32, 1, offsetof(Thread, interpSave.retval), 2, false);
+ insertLabel(".inlined_string_length_done", true);
+ return 0;
+ case INLINE_MATH_ABS_INT:
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ move_reg_to_reg(OpndSize_32, 1, false, 2, false);
+ alu_binary_imm_reg(OpndSize_32, sar_opc, 0x1f, 2, false);
+ alu_binary_reg_reg(OpndSize_32, xor_opc, 2, false, 1, false);
+ alu_binary_reg_reg(OpndSize_32, sub_opc, 2, false, 1, false);
+ get_self_pointer(3, false);
+ move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false);
+ return 0;
+ case INLINE_MATH_ABS_LONG:
+ get_virtual_reg(vD, OpndSize_32, 1, false);
+ move_reg_to_reg(OpndSize_32, 1, false, 2, false);
+ alu_binary_imm_reg(OpndSize_32, sar_opc, 0x1f, 1, false);
+ move_reg_to_reg(OpndSize_32, 1, false, 3, false);
+ move_reg_to_reg(OpndSize_32, 1, false, 4, false);
+ get_virtual_reg(vC, OpndSize_32, 5, false);
+ alu_binary_reg_reg(OpndSize_32, xor_opc, 5, false, 1, false);
+ get_self_pointer(6, false);
+ move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 6, false);
+ alu_binary_reg_reg(OpndSize_32, xor_opc, 2, false, 3, false);
+ move_reg_to_mem(OpndSize_32, 3, false, 4 + offsetof(Thread, interpSave.retval), 6, false);
+ alu_binary_reg_mem(OpndSize_32, sub_opc, 4, false, offsetof(Thread, interpSave.retval), 6, false);
+ alu_binary_reg_mem(OpndSize_32, sbb_opc, 4, false, 4 + offsetof(Thread, interpSave.retval), 6, false);
+ return 0;
+ case INLINE_MATH_MAX_INT:
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ get_virtual_reg(vD, OpndSize_32, 2, false);
+ compare_reg_reg(1, false, 2, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_GE, 2,
+ false/*src*/, 1, false/*dst*/);
+ get_self_pointer(3, false);
+ move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false);
+ return 0;
+ case INLINE_MATH_ABS_FLOAT:
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ alu_binary_imm_reg(OpndSize_32, and_opc, 0x7fffffff, 1, false);
+ get_self_pointer(2, false);
+ move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 2, false);
+ return 0;
+ case INLINE_MATH_ABS_DOUBLE:
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ get_virtual_reg(vD, OpndSize_32, 2, false);
+ alu_binary_imm_reg(OpndSize_32, and_opc, 0x7fffffff, 2, false);
+ get_self_pointer(3, false);
+ move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false);
+ move_reg_to_mem(OpndSize_32, 2, false, 4 + offsetof(Thread, interpSave.retval), 3, false);
+ return 0;
+ case INLINE_STRING_FASTINDEXOF_II:
+#if defined(USE_GLOBAL_STRING_DEFS)
+ break;
+#else
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ compare_imm_reg(OpndSize_32, 0, 1, false);
+ get_virtual_reg(vD, OpndSize_32, 2, false);
+ get_virtual_reg(vE, OpndSize_32, 3, false);
+ conditional_jump(Condition_NE, ".do_inlined_string_fastIndexof",
+ true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ jumpToExceptionThrown(1/*exception number*/);
+ insertLabel(".do_inlined_string_fastIndexof", true);
+ move_mem_to_reg(OpndSize_32, 0x14, 1, false, 4, false);
+ move_mem_to_reg(OpndSize_32, 0x8, 1, false, 5, false);
+ move_mem_to_reg(OpndSize_32, 0x10, 1, false, 6, false);
+ alu_binary_reg_reg(OpndSize_32, xor_opc, 1, false, 1, false);
+ compare_imm_reg(OpndSize_32, 0, 3, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_NS, 3, false, 1,
+ false);
+ compare_reg_reg(4, false, 1, false);
+ conditional_jump(Condition_GE,
+ ".do_inlined_string_fastIndexof_exitfalse", true);
+ dump_mem_scale_reg(Mnemonic_LEA, OpndSize_32, 5, false, 0xc/*disp*/,
+ 6, false, 2, 5, false, LowOpndRegType_gp);
+ movez_mem_disp_scale_to_reg(OpndSize_16, 5, false, 0, 1, false, 2,
+ 3, false);
+ compare_reg_reg(3, false, 2, false);
+ conditional_jump(Condition_E, ".do_inlined_string_fastIndexof_exit",
+ true);
+ load_effective_addr(0x1, 1, false, 3, false);
+ load_effective_addr_scale(5, false, 3, false, 2, 5, false);
+ unconditional_jump(".do_inlined_string_fastIndexof_iter", true);
+ insertLabel(".do_inlined_string_fastIndexof_ch_cmp", true);
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ rememberState(1);
+ }
+ movez_mem_to_reg(OpndSize_16, 0, 5, false, 6, false);
+ load_effective_addr(0x2, 5, false, 5, false);
+ compare_reg_reg(6, false, 2, false);
+ conditional_jump(Condition_E, ".do_inlined_string_fastIndexof_exit",
+ true);
+ load_effective_addr(0x1, 3, false, 3, false);
+ insertLabel(".do_inlined_string_fastIndexof_iter", true);
+ compare_reg_reg(4, false, 3, false);
+ move_reg_to_reg(OpndSize_32, 3, false, 1, false);
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ transferToState(1);
+ }
+ conditional_jump(Condition_NE,
+ ".do_inlined_string_fastIndexof_ch_cmp", true);
+ insertLabel(".do_inlined_string_fastIndexof_exitfalse", true);
+ move_imm_to_reg(OpndSize_32, 0xffffffff, 1, false);
+ insertLabel(".do_inlined_string_fastIndexof_exit", true);
+ get_self_pointer(7, false);
+ move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 7, false);
+ return 0;
+ case INLINE_FLOAT_TO_RAW_INT_BITS:
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ get_self_pointer(2, false);
+ move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 2, false);
+ return 0;
+ case INLINE_INT_BITS_TO_FLOAT:
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ get_self_pointer(2, false);
+ move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 2, false);
+ return 0;
+ case INLINE_DOUBLE_TO_RAW_LONG_BITS:
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ get_self_pointer(3, false);
+ move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false);
+ get_virtual_reg(vD, OpndSize_32, 2, false);
+ move_reg_to_mem(OpndSize_32, 2, false, 4 + offsetof(Thread, interpSave.retval), 3, false);
+ return 0;
+ case INLINE_LONG_BITS_TO_DOUBLE:
+ get_virtual_reg(vC, OpndSize_32, 1, false);
+ get_virtual_reg(vD, OpndSize_32, 2, false);
+ get_self_pointer(3, false);
+ move_reg_to_mem(OpndSize_32, 2, false, 4 + offsetof(Thread, interpSave.retval), 3, false);
+ move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false);
+ return 0;
+ default:
+ break;
+ }
+#endif
+ get_self_pointer(PhysicalReg_SCRATCH_1, false);
+ load_effective_addr(offsetof(Thread, interpSave.retval), PhysicalReg_SCRATCH_1, false, 1, false);
+ load_effective_addr(-24, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 1, false, 16, PhysicalReg_ESP, true);
+ if(num >= 1) {
+ get_virtual_reg(vC, OpndSize_32, 2, false);
+ move_reg_to_mem(OpndSize_32, 2, false, 0, PhysicalReg_ESP, true);
+ }
+ if(num >= 2) {
+ get_virtual_reg(vD, OpndSize_32, 3, false);
+ move_reg_to_mem(OpndSize_32, 3, false, 4, PhysicalReg_ESP, true);
+ }
+ if(num >= 3) {
+ get_virtual_reg(vE, OpndSize_32, 4, false);
+ move_reg_to_mem(OpndSize_32, 4, false, 8, PhysicalReg_ESP, true);
+ }
+ if(num >= 4) {
+ get_virtual_reg(vF, OpndSize_32, 5, false);
+ move_reg_to_mem(OpndSize_32, 5, false, 12, PhysicalReg_ESP, true);
+ }
+ beforeCall("execute_inline");
+ load_imm_global_data_API("gDvmInlineOpsTable", OpndSize_32, 6, false);
+ call_mem(16*tmp, 6, false);//
+ afterCall("execute_inline");
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+
+ load_effective_addr(24, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ conditional_jump(Condition_NE, ".execute_inline_done", true);
+ //jump to dvmJitToExceptionThrown
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ jumpToExceptionThrown(1/*exception number*/);
+ insertLabel(".execute_inline_done", true);
+ rPC += 3;
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_SCRATCH_1
+#undef P_SCRATCH_2
+#undef P_SCRATCH_3
+#undef P_SCRATCH_4
+
+//! lower bytecode INVOKE_OBJECT_INIT_RANGE
+
+//!
+int op_invoke_object_init_range() {
+ return -1;
+}
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_SCRATCH_1 PhysicalReg_ESI
+#define P_SCRATCH_2 PhysicalReg_EDX
+#define PP_GPR_1 PhysicalReg_EBX
+#define PP_GPR_2 PhysicalReg_ESI
+#define PP_GPR_3 PhysicalReg_EAX
+#define PP_GPR_4 PhysicalReg_EDX
+//! common code for INVOKE_VIRTUAL_QUICK
+
+//! It uses helper function if the switch is on
+int common_invoke_virtual_quick(bool hasRange, u2 vD, u2 IMMC) {
+#ifdef WITH_JIT_INLINING
+ /* An invoke with the MIR_INLINED is effectively a no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return false;
+ /*
+ * If the invoke has non-null misPredBranchOver, we need to generate
+ * the non-inlined version of the invoke here to handle the
+ * mispredicted case.
+ */
+ if (traceCurrentMIR->meta.callsiteInfo->misPredBranchOver) {
+ genLandingPadForMispredictedCallee(); //cUnit, mir, bb, labelList);
+ }
+#endif
+ export_pc();
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+ /////////////////////////////////////////////////
+ get_virtual_reg(vD, OpndSize_32, 1, false);
+ simpleNullCheck(1, false, vD);
+#ifndef PREDICTED_CHAINING
+ move_mem_to_reg(OpndSize_32, 0, 1, false, 2, false);
+ move_mem_to_reg(OpndSize_32, offClassObject_vtable, 2, false, 3, false);
+ move_mem_to_reg(OpndSize_32, IMMC, 3, false, PhysicalReg_ECX, true);
+
+ if(hasRange) {
+ common_invokeMethodRange(ArgsDone_Full);
+ }
+ else {
+ common_invokeMethodNoRange(ArgsDone_Full);
+ }
+#else
+ gen_predicted_chain(hasRange, -1, IMMC, false, 1/*tmp1*/);
+#endif
+ ////////////////////////
+ return 0;
+}
+#undef P_GPR_1
+#undef P_SCRATCH_1
+#undef P_SCRATCH_2
+#undef PP_GPR_1
+#undef PP_GPR_2
+#undef PP_GPR_3
+#undef PP_GPR_4
+//! lower bytecode INVOKE_VIRTUAL_QUICK by calling common_invoke_virtual_quick
+
+//!
+int op_invoke_virtual_quick() {
+ u2 vD = FETCH(2) & 0xf;
+ u2 IMMC = 4*FETCH(1);
+ int retval = common_invoke_virtual_quick(false, vD, IMMC);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_VIRTUAL_QUICK_RANGE by calling common_invoke_virtual_quick
+
+//!
+int op_invoke_virtual_quick_range() {
+ u2 vD = FETCH(2);
+ u2 IMMC = 4*FETCH(1);
+ int retval = common_invoke_virtual_quick(true, vD, IMMC);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ESI
+#define P_SCRATCH_1 PhysicalReg_EDX
+//! common code to lower INVOKE_SUPER_QUICK
+
+//!
+int common_invoke_super_quick(bool hasRange, u2 vD, u2 IMMC) {
+ export_pc();
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+ compare_imm_VR(OpndSize_32, 0, vD);
+
+ conditional_jump_global_API(Condition_E, "common_errNullObject", false);
+ /* for trace-based JIT, callee is already resolved */
+ int mIndex = IMMC/4;
+ const Method *calleeMethod = currentMethod->clazz->super->vtable[mIndex];
+ move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true);
+ if(hasRange) {
+ common_invokeMethodRange(convertCalleeToType(calleeMethod));
+ }
+ else {
+ common_invokeMethodNoRange(convertCalleeToType(calleeMethod));
+ }
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_SCRATCH_1
+//! lower bytecode INVOKE_SUPER_QUICK by calling common_invoke_super_quick
+
+//!
+int op_invoke_super_quick() {
+ u2 vD = FETCH(2) & 0xf;
+ u2 IMMC = 4*FETCH(1);
+ int retval = common_invoke_super_quick(false, vD, IMMC);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+//! lower bytecode INVOKE_SUPER_QUICK_RANGE by calling common_invoke_super_quick
+
+//!
+int op_invoke_super_quick_range() {
+ u2 vD = FETCH(2);
+ u2 IMMC = 4*FETCH(1);
+ int retval = common_invoke_super_quick(true, vD, IMMC);
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
+#endif
+ rPC += 3;
+ return retval;
+}
+/////// code to predict the callee method for invoke_virtual & invoke_interface
+#define offChainingCell_clazz 8
+#define offChainingCell_method 12
+#define offChainingCell_counter 16
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_EAX
+#define P_GPR_3 PhysicalReg_ESI
+#define P_SCRATCH_2 PhysicalReg_EDX
+/* TODO gingerbread: implemented for O1, but not for O0:
+ valid input to JitToPatch & use icRechainCount */
+/* update predicted method for invoke interface */
+// 2 inputs: ChainingCell in P_GPR_1, current class object in P_GPR_3
+void predicted_chain_interface_O0(u2 tmp) {
+ ALOGI("TODO chain_interface_O0");
+
+ /* set up arguments to dvmFindInterfaceMethodInCache */
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, (int) currentMethod->clazz->pDvmDex, 12, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, (int) currentMethod, 8, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, P_GPR_3, true, 0, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_EDX;
+ call_dvmFindInterfaceMethodInCache();
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+
+ /* if dvmFindInterfaceMethodInCache returns NULL, throw exception
+ otherwise, jump to .find_interface_done */
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump(Condition_NE, ".find_interface_done", true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ jumpToExceptionThrown(1/*exception number*/);
+
+ /* the interface method is found */
+ insertLabel(".find_interface_done", true);
+ /* reduce counter in chaining cell by 1 */
+ move_mem_to_reg(OpndSize_32, offChainingCell_counter, P_GPR_1, true, P_SCRATCH_2, true); //counter
+ alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, P_SCRATCH_2, true);
+ move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, offChainingCell_counter, P_GPR_1, true);
+
+ /* if counter is still greater than zero, skip prediction
+ if it is zero, update predicted method */
+ compare_imm_reg(OpndSize_32, 0, P_SCRATCH_2, true);
+ conditional_jump(Condition_G, ".skipPrediction", true);
+
+ /* call dvmJitToPatchPredictedChain to update predicted method */
+ //%ecx has callee method for virtual, %eax has callee for interface
+ /* set up arguments for dvmJitToPatchPredictedChain */
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 0, PhysicalReg_ESP, true);
+ insertChainingWorklist(traceCurrentBB->taken->id, stream);
+ move_chain_to_mem(OpndSize_32, traceCurrentBB->taken->id, 8, PhysicalReg_ESP, true); //predictedChainCell
+ move_reg_to_mem(OpndSize_32, P_GPR_3, true, 12, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ insertLabel(".skipPrediction", true);
+ move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true);
+}
+
+// 2 inputs: ChainingCell in temp 41, current class object in temp 40
+void predicted_chain_interface_O1(u2 tmp) {
+
+ /* set up arguments to dvmFindInterfaceMethodInCache */
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, (int) currentMethod->clazz->pDvmDex, 12, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, (int) currentMethod, 8, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 40, false, 0, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_10;
+ call_dvmFindInterfaceMethodInCache();
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+
+ /* if dvmFindInterfaceMethodInCache returns NULL, throw exception
+ otherwise, jump to .find_interface_done */
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump(Condition_NE, ".find_interface_done", true);
+ rememberState(3);
+ scratchRegs[0] = PhysicalReg_SCRATCH_9;
+ jumpToExceptionThrown(1/*exception number*/);
+
+ goToState(3);
+ /* the interface method is found */
+ insertLabel(".find_interface_done", true);
+#if 1 //
+ /* for gingerbread, counter is stored in glue structure
+ if clazz is not initialized, set icRechainCount to 0, otherwise, reduce it by 1 */
+ /* for gingerbread: t43 = 0 t44 = t33 t33-- cmov_ne t43 = t33 cmov_ne t44 = t33 */
+ move_mem_to_reg(OpndSize_32, offChainingCell_clazz, 41, false, 45, false);
+ move_imm_to_reg(OpndSize_32, 0, 43, false);
+ get_self_pointer(PhysicalReg_SCRATCH_7, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical, 33, false); //counter
+ move_reg_to_reg(OpndSize_32, 33, false, 44, false);
+ alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, 33, false);
+ /* sub_opc will update control flags, so compare_imm_reg must happen after */
+ compare_imm_reg(OpndSize_32, 0, 45, false);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 43, false/*dst*/);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 44, false/*dst*/);
+ move_reg_to_mem(OpndSize_32, 44, false, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical);
+#else
+ /* reduce counter in chaining cell by 1 */
+ move_mem_to_reg(OpndSize_32, offChainingCell_counter, 41, false, 33, false); //counter
+ alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, 33, false);
+ move_reg_to_mem(OpndSize_32, 33, false, offChainingCell_counter, 41, false);
+#endif
+
+ /* if counter is still greater than zero, skip prediction
+ if it is zero, update predicted method */
+ compare_imm_reg(OpndSize_32, 0, 43, false);
+ conditional_jump(Condition_G, ".skipPrediction", true);
+
+ rememberState(4);
+ /* call dvmJitToPatchPredictedChain to update predicted method */
+ //%ecx has callee method for virtual, %eax has callee for interface
+ /* set up arguments for dvmJitToPatchPredictedChain */
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 0, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_SCRATCH_7, isScratchPhysical, 4, PhysicalReg_ESP, true);
+ insertChainingWorklist(traceCurrentBB->taken->id, stream);
+ move_chain_to_mem(OpndSize_32, traceCurrentBB->taken->id, 8, PhysicalReg_ESP, true); //predictedChainCell
+ move_reg_to_mem(OpndSize_32, 40, false, 12, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_8;
+ call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ transferToState(4);
+
+ insertLabel(".skipPrediction", true);
+ move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true);
+}
+
+/* update predicted method for invoke virtual */
+// 2 inputs: ChainingCell in P_GPR_1, current class object in P_GPR_3
+void predicted_chain_virtual_O0(u2 IMMC) {
+ ALOGI("TODO chain_virtual_O0");
+
+ /* reduce counter in chaining cell by 1 */
+ move_mem_to_reg(OpndSize_32, offChainingCell_counter, P_GPR_1, true, P_GPR_2, true); //counter
+ move_mem_to_reg(OpndSize_32, offClassObject_vtable, P_GPR_3, true, P_SCRATCH_2, true);
+ alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, P_GPR_2, true);
+ move_mem_to_reg(OpndSize_32, IMMC, P_SCRATCH_2, true, PhysicalReg_ECX, true);
+ move_reg_to_mem(OpndSize_32, P_GPR_2, true, offChainingCell_counter, P_GPR_1, true);
+
+ /* if counter is still greater than zero, skip prediction
+ if it is zero, update predicted method */
+ compare_imm_reg(OpndSize_32, 0, P_GPR_2, true);
+ conditional_jump(Condition_G, ".skipPrediction", true);
+
+ /* call dvmJitToPatchPredictedChain to update predicted method */
+ //%ecx has callee method for virtual, %eax has callee for interface
+ /* set up arguments for dvmJitToPatchPredictedChain */
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 0, PhysicalReg_ESP, true);
+ insertChainingWorklist(traceCurrentBB->taken->id, stream);
+ move_chain_to_mem(OpndSize_32, traceCurrentBB->taken->id, 8, PhysicalReg_ESP, true); //predictedChainCell
+ move_reg_to_mem(OpndSize_32, P_GPR_3, true, 12, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+
+ //callee method in %ecx for invoke virtual
+ move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true);
+ insertLabel(".skipPrediction", true);
+}
+
+// 2 inputs: ChainingCell in temp 41, current class object in temp 40
+// extra input: predicted clazz in temp 32
+void predicted_chain_virtual_O1(u2 IMMC) {
+
+ /* reduce counter in chaining cell by 1 */
+ /* for gingerbread: t43 = 0 t44 = t33 t33-- cmov_ne t43 = t33 cmov_ne t44 = t33 */
+ get_self_pointer(PhysicalReg_SCRATCH_7, isScratchPhysical);
+ move_imm_to_reg(OpndSize_32, 0, 43, false);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical, 33, false); //counter
+ move_mem_to_reg(OpndSize_32, offClassObject_vtable, 40, false, 34, false);
+ move_reg_to_reg(OpndSize_32, 33, false, 44, false);
+ alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, 33, false);
+ compare_imm_reg(OpndSize_32, 0, 32, false); // after sub_opc
+ move_mem_to_reg(OpndSize_32, IMMC, 34, false, PhysicalReg_ECX, true);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 43, false/*dst*/);
+ conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 44, false/*dst*/);
+ move_reg_to_mem(OpndSize_32, 44, false, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical);
+
+ /* if counter is still greater than zero, skip prediction
+ if it is zero, update predicted method */
+ compare_imm_reg(OpndSize_32, 0, 43, false);
+ conditional_jump(Condition_G, ".skipPrediction", true);
+
+ rememberState(2);
+ /* call dvmJitToPatchPredictedChain to update predicted method */
+ //%ecx has callee method for virtual, %eax has callee for interface
+ /* set up arguments for dvmJitToPatchPredictedChain */
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 0, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_SCRATCH_7, isScratchPhysical, 4, PhysicalReg_ESP, true);
+ if(traceCurrentBB->taken)
+ insertChainingWorklist(traceCurrentBB->taken->id, stream);
+ int traceTakenId = traceCurrentBB->taken ? traceCurrentBB->taken->id : 0;
+ move_chain_to_mem(OpndSize_32, traceTakenId, 8, PhysicalReg_ESP, true); //predictedChainCell
+ move_reg_to_mem(OpndSize_32, 40, false, 12, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_10;
+ call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+
+ //callee method in %ecx for invoke virtual
+ move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true);
+ transferToState(2);
+
+ insertLabel(".skipPrediction", true);
+}
+
+static int invokeChain_inst = 0;
+/* object "this" is in %ebx */
+void gen_predicted_chain_O0(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg) {
+ ALOGI("TODO predicted_chain_O0");
+
+ /* get current class object */
+ move_mem_to_reg(OpndSize_32, offObject_clazz, PhysicalReg_EBX, true,
+ P_GPR_3, true);
+#ifdef DEBUG_CALL_STACK3
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_debug_dumpSwitch(); //%ebx, %eax, %edx
+ move_imm_to_reg(OpndSize_32, 0xdd11, PhysicalReg_EBX, true);
+ call_debug_dumpSwitch();
+#endif
+
+ /* get predicted clazz
+ get predicted method
+ */
+ insertChainingWorklist(traceCurrentBB->taken->id, stream);
+ move_chain_to_reg(OpndSize_32, traceCurrentBB->taken->id, P_GPR_1, true); //predictedChainCell
+ move_mem_to_reg(OpndSize_32, offChainingCell_clazz, P_GPR_1, true, P_SCRATCH_2, true);//predicted clazz
+ move_mem_to_reg(OpndSize_32, offChainingCell_method, P_GPR_1, true, PhysicalReg_ECX, true);//predicted method
+
+#ifdef DEBUG_CALL_STACK3
+ load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, P_GPR_1, true, 8, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, 4, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, P_GPR_3, true, 0, PhysicalReg_ESP, true);
+
+ move_reg_to_reg(OpndSize_32, P_SCRATCH_2, true, PhysicalReg_EBX, true);
+ call_debug_dumpSwitch();
+ move_imm_to_reg(OpndSize_32, 0xdd22, PhysicalReg_EBX, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_debug_dumpSwitch(); //%ebx, %eax, %edx
+ move_reg_to_reg(OpndSize_32, P_GPR_3, true, PhysicalReg_EBX, true);
+ call_debug_dumpSwitch();
+ move_reg_to_reg(OpndSize_32, PhysicalReg_ECX, true, PhysicalReg_EBX, true);
+ call_debug_dumpSwitch();
+
+ move_mem_to_reg(OpndSize_32, 8, PhysicalReg_ESP, true, P_GPR_1, true);
+ move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true, P_SCRATCH_2, true);
+ move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, P_GPR_3, true);
+ load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+#endif
+
+ /* compare current class object against predicted clazz
+ if equal, prediction is still valid, jump to .invokeChain */
+ //live registers: P_GPR_1, P_GPR_3, P_SCRATCH_2
+ compare_reg_reg(P_GPR_3, true, P_SCRATCH_2, true);
+ conditional_jump(Condition_E, ".invokeChain", true);
+ invokeChain_inst++;
+
+ //get callee method and update predicted method if necessary
+ if(isInterface) {
+ predicted_chain_interface_O0(tmp);
+ } else {
+ predicted_chain_virtual_O0(IMMC);
+ }
+
+#ifdef DEBUG_CALL_STACK3
+ move_imm_to_reg(OpndSize_32, 0xeeee, PhysicalReg_EBX, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_debug_dumpSwitch(); //%ebx, %eax, %edx
+ insertChainingWorklist(traceCurrentBB->taken->id, stream);
+ move_chain_to_reg(OpndSize_32, traceCurrentBB->taken->id, PhysicalReg_EBX, true);
+ call_debug_dumpSwitch();
+#endif
+
+ if(isRange) {
+ common_invokeMethodRange(ArgsDone_Full);
+ }
+ else {
+ common_invokeMethodNoRange(ArgsDone_Full);
+ }
+
+ insertLabel(".invokeChain", true);
+#ifdef DEBUG_CALL_STACK3
+ move_imm_to_reg(OpndSize_32, 0xdddd, PhysicalReg_EBX, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_debug_dumpSwitch(); //%ebx, %eax, %edx
+ insertChainingWorklist(traceCurrentBB->taken->id, stream);
+ move_chain_to_reg(OpndSize_32, traceCurrentBB->taken->id, PhysicalReg_EBX, true);
+ call_debug_dumpSwitch();
+ move_reg_to_reg(OpndSize_32, PhysicalReg_ECX, true, PhysicalReg_EBX, true);
+ call_debug_dumpSwitch();
+#endif
+
+ if(isRange) {
+ common_invokeMethodRange(ArgsDone_Normal);
+ }
+ else {
+ common_invokeMethodNoRange(ArgsDone_Normal);
+ }
+}
+
+/* object "this" is in inputReg: 5 for virtual, 1 for interface, 1 for virtual_quick */
+void gen_predicted_chain_O1(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg) {
+
+ /* get current class object */
+ move_mem_to_reg(OpndSize_32, offObject_clazz, inputReg, false,
+ 40, false);
+
+ /* get predicted clazz
+ get predicted method
+ */
+ if(traceCurrentBB->taken)
+ insertChainingWorklist(traceCurrentBB->taken->id, stream);
+ int traceTakenId = traceCurrentBB->taken ? traceCurrentBB->taken->id : 0;
+ move_chain_to_reg(OpndSize_32, traceTakenId, 41, false); //predictedChainCell
+ move_mem_to_reg(OpndSize_32, offChainingCell_clazz, 41, false, 32, false);//predicted clazz
+ move_mem_to_reg(OpndSize_32, offChainingCell_method, 41, false, PhysicalReg_ECX, true);//predicted method
+
+ /* update stack with parameters first, then decide the callee */
+ if(isRange) common_invokeMethodRange_noJmp();
+ else common_invokeMethodNoRange_noJmp();
+
+ /* compare current class object against predicted clazz
+ if equal, prediction is still valid, jump to .invokeChain */
+ compare_reg_reg(40, false, 32, false);
+ conditional_jump(Condition_E, ".invokeChain", true);
+ rememberState(1);
+ invokeChain_inst++;
+
+ //get callee method and update predicted method if necessary
+ if(isInterface) {
+ predicted_chain_interface_O1(tmp);
+ } else {
+ predicted_chain_virtual_O1(IMMC);
+ }
+
+ common_invokeMethod_Jmp(ArgsDone_Full); //will touch %ecx
+
+ insertLabel(".invokeChain", true);
+ goToState(1);
+ common_invokeMethod_Jmp(ArgsDone_Normal);
+}
+
+void gen_predicted_chain(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg) {
+ return gen_predicted_chain_O1(isRange, tmp, IMMC, isInterface, inputReg);
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef P_SCRATCH_2
diff --git a/vm/compiler/codegen/x86/LowerJump.cpp b/vm/compiler/codegen/x86/LowerJump.cpp
new file mode 100644
index 0000000..2b10d6b
--- /dev/null
+++ b/vm/compiler/codegen/x86/LowerJump.cpp
@@ -0,0 +1,1568 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file LowerJump.cpp
+ \brief This file lowers the following bytecodes: IF_XXX, GOTO
+*/
+#include <math.h>
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "Lower.h"
+#include "NcgAot.h"
+#include "enc_wrapper.h"
+#include "interp/InterpDefs.h"
+#include "NcgHelper.h"
+
+LabelMap* globalMap;
+LabelMap* globalShortMap;//make sure for each bytecode, there is no duplicated label
+LabelMap* globalWorklist = NULL;
+LabelMap* globalShortWorklist;
+
+int globalMapNum;
+int globalWorklistNum;
+int globalDataWorklistNum;
+int VMAPIWorklistNum;
+int globalPCWorklistNum;
+int chainingWorklistNum;
+
+LabelMap* globalDataWorklist = NULL;
+LabelMap* globalPCWorklist = NULL;
+LabelMap* chainingWorklist = NULL;
+LabelMap* VMAPIWorklist = NULL;
+
+char* ncgClassData;
+char* ncgClassDataPtr;
+char* ncgMethodData;
+char* ncgMethodDataPtr;
+int ncgClassNum;
+int ncgMethodNum;
+
+NCGWorklist* globalNCGWorklist;
+DataWorklist* methodDataWorklist;
+#ifdef ENABLE_TRACING
+MapWorklist* methodMapWorklist;
+#endif
+/*!
+\brief search globalShortMap to find the entry for the given label
+
+*/
+LabelMap* findItemForShortLabel(const char* label) {
+ LabelMap* ptr = globalShortMap;
+ while(ptr != NULL) {
+ if(!strcmp(label, ptr->label)) {
+ return ptr;
+ }
+ ptr = ptr->nextItem;
+ }
+ return NULL;
+}
+//assume size of "jump reg" is 2
+#define JUMP_REG_SIZE 2
+#define ADD_REG_REG_SIZE 3
+/*!
+\brief update value of the immediate in the given jump instruction
+
+check whether the immediate is out of range for the pre-set size
+*/
+int updateJumpInst(char* jumpInst, OpndSize immSize, int relativeNCG) {
+#ifdef DEBUG_NCG_JUMP
+ ALOGI("update jump inst @ %p with %d", jumpInst, relativeNCG);
+#endif
+ if(immSize == OpndSize_8) { //-128 to 127
+ if(relativeNCG >= 128 || relativeNCG < -128) {
+ ALOGE("pre-allocated space for a forward jump is not big enough");
+ dvmAbort();
+ }
+ }
+ if(immSize == OpndSize_16) { //-2^16 to 2^16-1
+ if(relativeNCG >= 32768 || relativeNCG < -32768) {
+ ALOGE("pre-allocated space for a forward jump is not big enough");
+ dvmAbort();
+ }
+ }
+ encoder_update_imm(relativeNCG, jumpInst);
+ return 0;
+}
+
+/*!
+\brief insert a label
+
+It takes argument checkDup, if checkDup is true, an entry is created in globalShortMap, entries in globalShortWorklist are checked, if there exists a match, the immediate in the jump instruction is updated and the entry is removed from globalShortWorklist;
+otherwise, an entry is created in globalMap.
+*/
+int insertLabel(const char* label, bool checkDup) {
+ LabelMap* item = NULL;
+ if(!checkDup) {
+ item = (LabelMap*)malloc(sizeof(LabelMap));
+ if(item == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ snprintf(item->label, LABEL_SIZE, "%s", label);
+ item->codePtr = stream;
+ item->nextItem = globalMap;
+ globalMap = item;
+#ifdef DEBUG_NCG_CODE_SIZE
+ ALOGI("insert global label %s %p", label, stream);
+#endif
+ globalMapNum++;
+ return 0;
+ }
+
+ item = (LabelMap*)malloc(sizeof(LabelMap));
+ if(item == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ snprintf(item->label, LABEL_SIZE, "%s", label);
+ item->codePtr = stream;
+ item->nextItem = globalShortMap;
+ globalShortMap = item;
+#ifdef DEBUG_NCG
+ ALOGI("insert short-term label %s %p", label, stream);
+#endif
+ LabelMap* ptr = globalShortWorklist;
+ LabelMap* ptr_prevItem = NULL;
+ while(ptr != NULL) {
+ if(!strcmp(ptr->label, label)) {
+ //perform work
+ int relativeNCG = stream - ptr->codePtr;
+ unsigned instSize = encoder_get_inst_size(ptr->codePtr);
+ relativeNCG -= instSize; //size of the instruction
+#ifdef DEBUG_NCG
+ ALOGI("perform work short-term %p for label %s relative %d", ptr->codePtr, label, relativeNCG);
+#endif
+ updateJumpInst(ptr->codePtr, ptr->size, relativeNCG);
+ //remove work
+ if(ptr_prevItem == NULL) {
+ globalShortWorklist = ptr->nextItem;
+ free(ptr);
+ ptr = globalShortWorklist; //ptr_prevItem is still NULL
+ }
+ else {
+ ptr_prevItem->nextItem = ptr->nextItem;
+ free(ptr);
+ ptr = ptr_prevItem->nextItem;
+ }
+ }
+ else {
+ ptr_prevItem = ptr;
+ ptr = ptr->nextItem;
+ }
+ } //while
+ return 0;
+}
+/*!
+\brief search globalMap to find the entry for the given label
+
+*/
+char* findCodeForLabel(const char* label) {
+ LabelMap* ptr = globalMap;
+ while(ptr != NULL) {
+ if(!strcmp(label, ptr->label)) {
+ return ptr->codePtr;
+ }
+ ptr = ptr->nextItem;
+ }
+ return NULL;
+}
+/*!
+\brief search globalShortMap to find the entry for the given label
+
+*/
+char* findCodeForShortLabel(const char* label) {
+ LabelMap* ptr = globalShortMap;
+ while(ptr != NULL) {
+ if(!strcmp(label, ptr->label)) {
+ return ptr->codePtr;
+ }
+ ptr = ptr->nextItem;
+ }
+ return NULL;
+}
+int insertLabelWorklist(const char* label, OpndSize immSize) {
+ LabelMap* item = (LabelMap*)malloc(sizeof(LabelMap));
+ if(item == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ snprintf(item->label, LABEL_SIZE, "%s", label);
+ item->codePtr = stream;
+ item->size = immSize;
+ item->nextItem = globalWorklist;
+ globalWorklist = item;
+#ifdef DEBUG_NCG
+ ALOGI("insert globalWorklist: %s %p", label, stream);
+#endif
+ return 0;
+}
+
+int insertShortWorklist(const char* label, OpndSize immSize) {
+ LabelMap* item = (LabelMap*)malloc(sizeof(LabelMap));
+ if(item == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ snprintf(item->label, LABEL_SIZE, "%s", label);
+ item->codePtr = stream;
+ item->size = immSize;
+ item->nextItem = globalShortWorklist;
+ globalShortWorklist = item;
+#ifdef DEBUG_NCG
+ ALOGI("insert globalShortWorklist: %s %p", label, stream);
+#endif
+ return 0;
+}
+/*!
+\brief free memory allocated for globalMap
+
+*/
+void freeLabelMap() {
+ LabelMap* ptr = globalMap;
+ while(ptr != NULL) {
+ globalMap = ptr->nextItem;
+ free(ptr);
+ ptr = globalMap;
+ }
+}
+/*!
+\brief free memory allocated for globalShortMap
+
+*/
+void freeShortMap() {
+ LabelMap* ptr = globalShortMap;
+ while(ptr != NULL) {
+ globalShortMap = ptr->nextItem;
+ free(ptr);
+ ptr = globalShortMap;
+ }
+ globalShortMap = NULL;
+}
+
+int insertGlobalPCWorklist(char * offset, char * codeStart)
+{
+ LabelMap* item = (LabelMap*)malloc(sizeof(LabelMap));
+ if(item == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ snprintf(item->label, LABEL_SIZE, "%s", "export_pc");
+ item->size = OpndSize_32;
+ item->codePtr = offset; //points to the immediate operand
+ item->addend = codeStart - streamMethodStart; //relative code pointer
+ item->nextItem = globalPCWorklist;
+ globalPCWorklist = item;
+ globalPCWorklistNum ++;
+
+#ifdef DEBUG_NCG
+ ALOGI("insert globalPCWorklist: %p %p %p %x %p", globalDvmNcg->streamCode, codeStart, streamCode, item->addend, item->codePtr);
+#endif
+ return 0;
+}
+
+int insertChainingWorklist(int bbId, char * codeStart)
+{
+ LabelMap* item = (LabelMap*)malloc(sizeof(LabelMap));
+ if(item == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ item->size = OpndSize_32;
+ item->codePtr = codeStart; //points to the move instruction
+ item->addend = bbId; //relative code pointer
+ item->nextItem = chainingWorklist;
+ chainingWorklist = item;
+
+#ifdef DEBUG_NCG
+ ALOGI("insertChainingWorklist: %p basic block %d", codeStart, bbId);
+#endif
+ return 0;
+}
+
+int insertGlobalDataWorklist(char * offset, const char* label)
+{
+ LabelMap* item = (LabelMap*)malloc(sizeof(LabelMap));
+ if(item == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ snprintf(item->label, LABEL_SIZE, "%s", label);
+ item->codePtr = offset;
+ item->size = OpndSize_32;
+ item->nextItem = globalDataWorklist;
+ globalDataWorklist = item;
+ globalDataWorklistNum ++;
+
+#ifdef DEBUG_NCG
+ ALOGI("insert globalDataWorklist: %s %p", label, offset);
+#endif
+
+ return 0;
+}
+
+int insertVMAPIWorklist(char * offset, const char* label)
+{
+ LabelMap* item = (LabelMap*)malloc(sizeof(LabelMap));
+ if(item == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ snprintf(item->label, LABEL_SIZE, "%s", label);
+ item->codePtr = offset;
+ item->size = OpndSize_32;
+
+ item->nextItem = VMAPIWorklist;
+ VMAPIWorklist = item;
+
+ VMAPIWorklistNum ++;
+
+#ifdef DEBUG_NCG
+ ALOGI("insert VMAPIWorklist: %s %p", label, offset);
+#endif
+ return 0;
+}
+////////////////////////////////////////////////
+
+
+int updateImmRMInst(char* moveInst, const char* label, int relativeNCG); //forward declaration
+//////////////////// performLabelWorklist is defined differently for code cache
+void performChainingWorklist() {
+ LabelMap* ptr = chainingWorklist;
+ while(ptr != NULL) {
+ int tmpNCG = traceLabelList[ptr->addend].lop.generic.offset;
+ char* NCGaddr = streamMethodStart + tmpNCG;
+ updateImmRMInst(ptr->codePtr, "", (int)NCGaddr);
+ chainingWorklist = ptr->nextItem;
+ free(ptr);
+ ptr = chainingWorklist;
+ }
+}
+void freeChainingWorklist() {
+ LabelMap* ptr = chainingWorklist;
+ while(ptr != NULL) {
+ chainingWorklist = ptr->nextItem;
+ free(ptr);
+ ptr = chainingWorklist;
+ }
+}
+
+//Work only for initNCG
+void performLabelWorklist() {
+ LabelMap* ptr = globalWorklist;
+ while(ptr != NULL) {
+#ifdef DEBUG_NCG
+ ALOGI("perform work global %p for label %s", ptr->codePtr, ptr->label);
+#endif
+ char* targetCode = findCodeForLabel(ptr->label);
+ assert(targetCode != NULL);
+ int relativeNCG = targetCode - ptr->codePtr;
+ unsigned instSize = encoder_get_inst_size(ptr->codePtr);
+ relativeNCG -= instSize; //size of the instruction
+ updateJumpInst(ptr->codePtr, ptr->size, relativeNCG);
+ globalWorklist = ptr->nextItem;
+ free(ptr);
+ ptr = globalWorklist;
+ }
+}
+void freeLabelWorklist() {
+ LabelMap* ptr = globalWorklist;
+ while(ptr != NULL) {
+ globalWorklist = ptr->nextItem;
+ free(ptr);
+ ptr = globalWorklist;
+ }
+}
+
+///////////////////////////////////////////////////
+/*!
+\brief update value of the immediate in the given move instruction
+
+*/
+int updateImmRMInst(char* moveInst, const char* label, int relativeNCG) {
+#ifdef DEBUG_NCG
+ ALOGI("perform work ImmRM inst @ %p for label %s with %d", moveInst, label, relativeNCG);
+#endif
+ encoder_update_imm_rm(relativeNCG, moveInst);
+ return 0;
+}
+//! maximum instruction size for jump,jcc,call: 6 for jcc rel32
+#define MAX_JCC_SIZE 6
+//! minimum instruction size for jump,jcc,call: 2
+#define MIN_JCC_SIZE 2
+/*!
+\brief estimate size of the immediate
+
+Somehow, 16 bit jump does not work. This function will return either 8 bit or 32 bit
+EXAMPLE:
+ native code at A: ...
+ native code at B: jump relOffset (target is A)
+ native code at B':
+ --> relOffset = A - B' = A - B - size of the jump instruction
+ Argument "target" is equal to A - B. To determine size of the immediate, we check tha value of "target - size of the jump instructoin"
+*/
+OpndSize estOpndSizeFromImm(int target) {
+ if(target-MIN_JCC_SIZE < 128 && target-MAX_JCC_SIZE >= -128) return OpndSize_8;
+#ifdef SUPPORT_IMM_16
+ if(target-MIN_JCC_SIZE < 32768 && target-MAX_JCC_SIZE >= -32768) return OpndSize_16;
+#endif
+ return OpndSize_32;
+}
+/*!
+\brief return size of a jump or call instruction
+
+*/
+unsigned getJmpCallInstSize(OpndSize size, JmpCall_type type) {
+ if(type == JmpCall_uncond) {
+ if(size == OpndSize_8) return 2;
+ if(size == OpndSize_16) return 4;
+ return 5;
+ }
+ if(type == JmpCall_cond) {
+ if(size == OpndSize_8) return 2;
+ if(size == OpndSize_16) return 5;
+ return 6;
+ }
+ if(type == JmpCall_reg) {
+ assert(size == OpndSize_32);
+ return JUMP_REG_SIZE;
+ }
+ if(type == JmpCall_call) {
+ assert(size != OpndSize_8);
+ if(size == OpndSize_16) return 4;
+ return 5;
+ }
+ return 0;
+}
+/*!
+\brief check whether a branch target is already handled, if yes, return the size of the immediate; otherwise, call insertShortWorklist or insertLabelWorklist.
+
+If the branch target is not handled, call insertShortWorklist or insertLabelWorklist depending on isShortTerm, unknown is set to true, immSize is set to 32 if isShortTerm is false, set to 32 if isShortTerm is true and target is check_cast_null, set to 8 otherwise.
+
+If the branch target is handled, call estOpndSizeFromImm to set immSize for jump instruction, returns the value of the immediate
+*/
+int getRelativeOffset(const char* target, bool isShortTerm, JmpCall_type type, bool* unknown, OpndSize* immSize) {
+ char* targetPtrInStream = NULL;
+ if(isShortTerm) targetPtrInStream = findCodeForShortLabel(target);
+ else targetPtrInStream = findCodeForLabel(target);
+
+ int relOffset;
+ *unknown = false;
+ if(targetPtrInStream == NULL) {
+ //branch target is not handled yet
+ relOffset = 0;
+ *unknown = true;
+ if(isShortTerm) {
+ /* for backward jump, at this point, we don't know how far the target is from this jump
+ since the lable is only used within a single bytecode, we assume OpndSize_8 is big enough
+ but there are special cases where we should use 32 bit offset
+ */
+ if(!strcmp(target, ".check_cast_null") || !strcmp(target, ".stackOverflow") ||
+ !strcmp(target, ".invokeChain") ||
+ !strcmp(target, ".new_instance_done") ||
+ !strcmp(target, ".new_array_done") ||
+ !strcmp(target, ".fill_array_data_done") ||
+ !strcmp(target, ".inlined_string_compare_done") ||
+ !strncmp(target, "after_exception", 15)) {
+#ifdef SUPPORT_IMM_16
+ *immSize = OpndSize_16;
+#else
+ *immSize = OpndSize_32;
+#endif
+ } else {
+ *immSize = OpndSize_8;
+ }
+#ifdef DEBUG_NCG_JUMP
+ ALOGI("insert to short worklist %s %d", target, *immSize);
+#endif
+ insertShortWorklist(target, *immSize);
+ }
+ else {
+#ifdef SUPPORT_IMM_16
+ *immSize = OpndSize_16;
+#else
+ *immSize = OpndSize_32;
+#endif
+ insertLabelWorklist(target, *immSize);
+ }
+ if(type == JmpCall_call) { //call sz16 does not work in gdb
+ *immSize = OpndSize_32;
+ }
+ return 0;
+ }
+ else if (!isShortTerm) {
+#ifdef SUPPORT_IMM_16
+ *immSize = OpndSize_16;
+#else
+ *immSize = OpndSize_32;
+#endif
+ insertLabelWorklist(target, *immSize);
+ }
+
+#ifdef DEBUG_NCG
+ ALOGI("backward branch @ %p for label %s", stream, target);
+#endif
+ relOffset = targetPtrInStream - stream;
+ if(type == JmpCall_call) *immSize = OpndSize_32;
+ else
+ *immSize = estOpndSizeFromImm(relOffset);
+
+ relOffset -= getJmpCallInstSize(*immSize, type);
+ return relOffset;
+}
+
+/*!
+\brief generate a single native instruction "jcc imm" to jump to a label
+
+*/
+void conditional_jump(ConditionCode cc, const char* target, bool isShortTerm) {
+ if(jumpToException(target) && currentExceptionBlockIdx >= 0) { //jump to the exceptionThrow block
+ condJumpToBasicBlock(stream, cc, currentExceptionBlockIdx);
+ return;
+ }
+ Mnemonic m = (Mnemonic)(Mnemonic_Jcc + cc);
+ bool unknown;
+ OpndSize size;
+ int imm = 0;
+ imm = getRelativeOffset(target, isShortTerm, JmpCall_cond, &unknown, &size);
+ dump_label(m, size, imm, target, isShortTerm);
+}
+/*!
+\brief generate a single native instruction "jmp imm" to jump to ".invokeArgsDone"
+
+*/
+void goto_invokeArgsDone() {
+ unconditional_jump_global_API(".invokeArgsDone", false);
+}
+/*!
+\brief generate a single native instruction "jmp imm" to jump to a label
+
+If the target is ".invokeArgsDone" and mode is NCG O1, extra work is performed to dump content of virtual registers to memory.
+*/
+void unconditional_jump(const char* target, bool isShortTerm) {
+ if(jumpToException(target) && currentExceptionBlockIdx >= 0) { //jump to the exceptionThrow block
+ jumpToBasicBlock(stream, currentExceptionBlockIdx);
+ return;
+ }
+ Mnemonic m = Mnemonic_JMP;
+ bool unknown;
+ OpndSize size;
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ //for other three labels used by JIT: invokeArgsDone_formal, _native, _jit
+ if(!strncmp(target, ".invokeArgsDone", 15)) {
+ touchEcx(); //keep ecx live, if ecx was spilled, it is loaded here
+ beforeCall(target); //
+ }
+ if(!strcmp(target, ".invokeArgsDone")) {
+ nextVersionOfHardReg(PhysicalReg_EDX, 1); //edx will be used in a function
+ call("ncgGetEIP"); //must be immediately before JMP
+ }
+ }
+ int imm = 0;
+ imm = getRelativeOffset(target, isShortTerm, JmpCall_uncond, &unknown, &size);
+ dump_label(m, size, imm, target, isShortTerm);
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ if(!strncmp(target, ".invokeArgsDone", 15)) {
+ afterCall(target); //un-spill before executing the next bytecode
+ }
+ }
+}
+/*!
+\brief generate a single native instruction "jcc imm"
+
+*/
+void conditional_jump_int(ConditionCode cc, int target, OpndSize size) {
+ Mnemonic m = (Mnemonic)(Mnemonic_Jcc + cc);
+ dump_ncg(m, size, target);
+}
+/*!
+\brief generate a single native instruction "jmp imm"
+
+*/
+void unconditional_jump_int(int target, OpndSize size) {
+ Mnemonic m = Mnemonic_JMP;
+ dump_ncg(m, size, target);
+}
+/*!
+\brief generate a single native instruction "jmp reg"
+
+*/
+void unconditional_jump_reg(int reg, bool isPhysical) {
+ dump_reg(Mnemonic_JMP, ATOM_NORMAL, OpndSize_32, reg, isPhysical, LowOpndRegType_gp);
+}
+
+/*!
+\brief generate a single native instruction to call a function
+
+If mode is NCG O1, extra work is performed to dump content of virtual registers to memory.
+*/
+void call(const char* target) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ beforeCall(target);
+ }
+ Mnemonic m = Mnemonic_CALL;
+ bool dummy;
+ OpndSize size;
+ int relOffset = 0;
+ relOffset = getRelativeOffset(target, false, JmpCall_call, &dummy, &size);
+ dump_label(m, size, relOffset, target, false);
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ afterCall(target);
+ }
+}
+/*!
+\brief generate a single native instruction to call a function
+
+*/
+void call_reg(int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_CALL;
+ dump_reg(m, ATOM_NORMAL, OpndSize_32, reg, isPhysical, LowOpndRegType_gp);
+}
+void call_reg_noalloc(int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_CALL;
+ dump_reg_noalloc(m, OpndSize_32, reg, isPhysical, LowOpndRegType_gp);
+}
+
+/*!
+\brief generate a single native instruction to call a function
+
+*/
+void call_mem(int disp, int reg, bool isPhysical) {
+ Mnemonic m = Mnemonic_CALL;
+ dump_mem(m, ATOM_NORMAL, OpndSize_32, disp, reg, isPhysical);
+}
+
+/*!
+\brief insert an entry to globalNCGWorklist
+
+*/
+int insertNCGWorklist(s4 relativePC, OpndSize immSize) {
+ int offsetNCG2 = stream - streamMethodStart;
+#ifdef DEBUG_NCG
+ ALOGI("insert NCGWorklist (goto forward) @ %p offsetPC %x relativePC %x offsetNCG %x", stream, offsetPC, relativePC, offsetNCG2);
+#endif
+ NCGWorklist* item = (NCGWorklist*)malloc(sizeof(NCGWorklist));
+ if(item == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ item->relativePC = relativePC;
+ item->offsetPC = offsetPC;
+ item->offsetNCG = offsetNCG2;
+ item->codePtr = stream;
+ item->size = immSize;
+ item->nextItem = globalNCGWorklist;
+ globalNCGWorklist = item;
+ return 0;
+}
+#ifdef ENABLE_TRACING
+int insertMapWorklist(s4 BCOffset, s4 NCGOffset, int isStartOfPC) {
+ return 0;
+}
+#endif
+/*!
+\brief insert an entry to methodDataWorklist
+
+This function is used by bytecode FILL_ARRAY_DATA, PACKED_SWITCH, SPARSE_SWITCH
+*/
+int insertDataWorklist(s4 relativePC, char* codePtr1) {
+ //insert according to offsetPC+relativePC, smallest at the head
+ DataWorklist* item = (DataWorklist*)malloc(sizeof(DataWorklist));
+ if(item == NULL) {
+ ALOGE("Memory allocation failed");
+ return -1;
+ }
+ item->relativePC = relativePC;
+ item->offsetPC = offsetPC;
+ item->codePtr = codePtr1;
+ item->codePtr2 = stream; //jump_reg for switch
+ DataWorklist* ptr = methodDataWorklist;
+ DataWorklist* prev_ptr = NULL;
+ while(ptr != NULL) {
+ int tmpPC = ptr->offsetPC + ptr->relativePC;
+ int tmpPC2 = relativePC + offsetPC;
+ if(tmpPC2 < tmpPC) {
+ break;
+ }
+ prev_ptr = ptr;
+ ptr = ptr->nextItem;
+ }
+ //insert item before ptr
+ if(prev_ptr != NULL) {
+ prev_ptr->nextItem = item;
+ }
+ else methodDataWorklist = item;
+ item->nextItem = ptr;
+ return 0;
+}
+
+/*!
+\brief work on globalNCGWorklist
+
+*/
+int performNCGWorklist() {
+ NCGWorklist* ptr = globalNCGWorklist;
+ while(ptr != NULL) {
+ ALOGV("perform NCG worklist: @ %p target block %d target NCG %x",
+ ptr->codePtr, ptr->relativePC, traceLabelList[ptr->relativePC].lop.generic.offset);
+ int tmpNCG = traceLabelList[ptr->relativePC].lop.generic.offset;
+ assert(tmpNCG >= 0);
+ int relativeNCG = tmpNCG - ptr->offsetNCG;
+ unsigned instSize = encoder_get_inst_size(ptr->codePtr);
+ relativeNCG -= instSize;
+ updateJumpInst(ptr->codePtr, ptr->size, relativeNCG);
+ globalNCGWorklist = ptr->nextItem;
+ free(ptr);
+ ptr = globalNCGWorklist;
+ }
+ return 0;
+}
+void freeNCGWorklist() {
+ NCGWorklist* ptr = globalNCGWorklist;
+ while(ptr != NULL) {
+ globalNCGWorklist = ptr->nextItem;
+ free(ptr);
+ ptr = globalNCGWorklist;
+ }
+}
+
+/*!
+\brief used by bytecode SWITCH
+
+targetPC points to start of the data section
+Code sequence for SWITCH
+ call ncgGetEIP
+ @codeInst: add_reg_reg %eax, %edx
+ jump_reg %edx
+This function returns the offset in native code between add_reg_reg and the data section
+*/
+int getRelativeNCGForSwitch(int targetPC, char* codeInst) {
+ int tmpNCG = mapFromBCtoNCG[targetPC];
+ int offsetNCG2 = codeInst - streamMethodStart;
+ int relativeOff = tmpNCG - offsetNCG2;
+ return relativeOff;
+}
+/*!
+\brief work on methodDataWorklist
+
+*/
+int performDataWorklist() {
+ DataWorklist* ptr = methodDataWorklist;
+ if(ptr == NULL) return 0;
+
+ char* codeCacheEnd = ((char *) gDvmJit.codeCache) + gDvmJit.codeCacheSize - CODE_CACHE_PADDING;
+ u2 insnsSize = dvmGetMethodInsnsSize(currentMethod); //bytecode
+ //align stream to multiple of 4
+ int alignBytes = (int)stream & 3;
+ if(alignBytes != 0) alignBytes = 4-alignBytes;
+ stream += alignBytes;
+
+ while(ptr != NULL) {
+ int tmpPC = ptr->offsetPC + ptr->relativePC;
+ int endPC = insnsSize;
+ if(ptr->nextItem != NULL) endPC = ptr->nextItem->offsetPC + ptr->nextItem->relativePC;
+ mapFromBCtoNCG[tmpPC] = stream - streamMethodStart; //offsetNCG in byte
+
+ //handle fill_array_data, packed switch & sparse switch
+ u2 tmpInst = *(currentMethod->insns + ptr->offsetPC);
+ u2* sizePtr;
+ s4* entryPtr_bytecode;
+ u2 tSize, iVer;
+ u4 sz;
+
+ if (gDvmJit.codeCacheFull == true) {
+ // We are out of code cache space. Skip writing data/code to
+ // code cache. Simply free the item.
+ methodDataWorklist = ptr->nextItem;
+ free(ptr);
+ ptr = methodDataWorklist;
+ }
+
+ switch (INST_INST(tmpInst)) {
+ case OP_FILL_ARRAY_DATA:
+ sz = (endPC-tmpPC)*sizeof(u2);
+ if ((stream + sz) < codeCacheEnd) {
+ memcpy(stream, (u2*)currentMethod->insns+tmpPC, sz);
+#ifdef DEBUG_NCG_CODE_SIZE
+ ALOGI("copy data section to stream %p: start at %d, %d bytes", stream, tmpPC, sz);
+#endif
+#ifdef DEBUG_NCG
+ ALOGI("update data section at %p with %d", ptr->codePtr, stream-ptr->codePtr);
+#endif
+ updateImmRMInst(ptr->codePtr, "", stream - ptr->codePtr);
+ stream += sz;
+ } else {
+ gDvmJit.codeCacheFull = true;
+ }
+ break;
+ case OP_PACKED_SWITCH:
+ updateImmRMInst(ptr->codePtr, "", stream-ptr->codePtr);
+ sizePtr = (u2*)currentMethod->insns+tmpPC + 1 /*signature*/;
+ entryPtr_bytecode = (s4*)(sizePtr + 1 /*size*/ + 2 /*firstKey*/);
+ tSize = *(sizePtr);
+ sz = tSize * 4; /* expected size needed in stream */
+ if ((stream + sz) < codeCacheEnd) {
+ for(iVer = 0; iVer < tSize; iVer++) {
+ //update entries
+ s4 relativePC = *entryPtr_bytecode; //relative to ptr->offsetPC
+ //need stream, offsetPC,
+ int relativeNCG = getRelativeNCGForSwitch(relativePC+ptr->offsetPC, ptr->codePtr2);
+#ifdef DEBUG_NCG_CODE_SIZE
+ ALOGI("convert target from %d to %d", relativePC+ptr->offsetPC, relativeNCG);
+#endif
+ *((s4*)stream) = relativeNCG;
+ stream += 4;
+ entryPtr_bytecode++;
+ }
+ } else {
+ gDvmJit.codeCacheFull = true;
+ }
+ break;
+ case OP_SPARSE_SWITCH:
+ updateImmRMInst(ptr->codePtr, "", stream-ptr->codePtr);
+ sizePtr = (u2*)currentMethod->insns+tmpPC + 1 /*signature*/;
+ s4* keyPtr_bytecode = (s4*)(sizePtr + 1 /*size*/);
+ tSize = *(sizePtr);
+ entryPtr_bytecode = (s4*)(keyPtr_bytecode + tSize);
+ sz = tSize * (sizeof(s4) + 4); /* expected size needed in stream */
+ if ((stream + sz) < codeCacheEnd) {
+ memcpy(stream, keyPtr_bytecode, tSize*sizeof(s4));
+ stream += tSize*sizeof(s4);
+ for(iVer = 0; iVer < tSize; iVer++) {
+ //update entries
+ s4 relativePC = *entryPtr_bytecode; //relative to ptr->offsetPC
+ //need stream, offsetPC,
+ int relativeNCG = getRelativeNCGForSwitch(relativePC+ptr->offsetPC, ptr->codePtr2);
+ *((s4*)stream) = relativeNCG;
+ stream += 4;
+ entryPtr_bytecode++;
+ }
+ } else {
+ gDvmJit.codeCacheFull = true;
+ }
+ break;
+ }
+
+ //remove the item
+ methodDataWorklist = ptr->nextItem;
+ free(ptr);
+ ptr = methodDataWorklist;
+ }
+ return 0;
+}
+void freeDataWorklist() {
+ DataWorklist* ptr = methodDataWorklist;
+ while(ptr != NULL) {
+ methodDataWorklist = ptr->nextItem;
+ free(ptr);
+ ptr = methodDataWorklist;
+ }
+}
+
+//////////////////////////
+/*!
+\brief check whether a branch target (specified by relative offset in bytecode) is already handled, if yes, return the size of the immediate; otherwise, call insertNCGWorklist.
+
+If the branch target is not handled, call insertNCGWorklist, unknown is set to true, immSize is set to 32.
+
+If the branch target is handled, call estOpndSizeFromImm to set immSize for jump instruction, returns the value of the immediate
+*/
+int getRelativeNCG(s4 tmp, JmpCall_type type, bool* unknown, OpndSize* size) {//tmp: relativePC
+ int tmpNCG = traceLabelList[tmp].lop.generic.offset;
+
+ *unknown = false;
+ if(tmpNCG <0) {
+ *unknown = true;
+#ifdef SUPPORT_IMM_16
+ *size = OpndSize_16;
+#else
+ *size = OpndSize_32;
+#endif
+ insertNCGWorklist(tmp, *size);
+ return 0;
+ }
+ int offsetNCG2 = stream - streamMethodStart;
+#ifdef DEBUG_NCG
+ ALOGI("goto backward @ %p offsetPC %d relativePC %d offsetNCG %d relativeNCG %d", stream, offsetPC, tmp, offsetNCG2, tmpNCG-offsetNCG2);
+#endif
+ int relativeOff = tmpNCG - offsetNCG2;
+ *size = estOpndSizeFromImm(relativeOff);
+ return relativeOff - getJmpCallInstSize(*size, type);
+}
+/*!
+\brief a helper function to handle backward branch
+
+input: jump target in %eax; at end of the function, jump to %eax
+*/
+int common_backwardBranch() {
+ insertLabel("common_backwardBranch", false);
+ spill_reg(PhysicalReg_EAX, true);
+ call("common_periodicChecks_entry");
+ unspill_reg(PhysicalReg_EAX, true);
+ unconditional_jump_reg(PhysicalReg_EAX, true);
+ return 0;
+}
+//when this is called from JIT, there is no need to check GC
+int common_goto(s4 tmp) { //tmp: target basic block id
+ bool unknown;
+ OpndSize size;
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+
+ int relativeNCG = tmp;
+ relativeNCG = getRelativeNCG(tmp, JmpCall_uncond, &unknown, &size);
+ unconditional_jump_int(relativeNCG, size);
+ return 1;
+}
+int common_if(s4 tmp, ConditionCode cc_next, ConditionCode cc) {
+ bool unknown;
+ OpndSize size;
+ int relativeNCG = traceCurrentBB->taken ? traceCurrentBB->taken->id : 0;
+
+ if(traceCurrentBB->taken)
+ relativeNCG = getRelativeNCG(traceCurrentBB->taken->id, JmpCall_cond, &unknown, &size);
+ conditional_jump_int(cc, relativeNCG, size);
+ relativeNCG = traceCurrentBB->fallThrough ? traceCurrentBB->fallThrough->id : 0;
+ if(traceCurrentBB->fallThrough)
+ relativeNCG = getRelativeNCG(traceCurrentBB->fallThrough->id, JmpCall_uncond, &unknown, &size);
+ unconditional_jump_int(relativeNCG, size);
+ return 2;
+}
+
+/*!
+\brief helper function to handle null object error
+
+*/
+int common_errNullObject() {
+ insertLabel("common_errNullObject", false);
+ move_imm_to_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ move_imm_to_reg(OpndSize_32, LstrNullPointerException, PhysicalReg_ECX, true);
+ unconditional_jump("common_throw", false);
+ return 0;
+}
+/*!
+\brief helper function to handle string index error
+
+*/
+int common_StringIndexOutOfBounds() {
+ insertLabel("common_StringIndexOutOfBounds", false);
+ move_imm_to_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ move_imm_to_reg(OpndSize_32, LstrStringIndexOutOfBoundsException, PhysicalReg_ECX, true);
+ unconditional_jump("common_throw", false);
+ return 0;
+}
+
+/*!
+\brief helper function to handle array index error
+
+*/
+int common_errArrayIndex() {
+ insertLabel("common_errArrayIndex", false);
+ move_imm_to_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ move_imm_to_reg(OpndSize_32, LstrArrayIndexException, PhysicalReg_ECX, true);
+ unconditional_jump("common_throw", false);
+ return 0;
+}
+/*!
+\brief helper function to handle array store error
+
+*/
+int common_errArrayStore() {
+ insertLabel("common_errArrayStore", false);
+ move_imm_to_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ move_imm_to_reg(OpndSize_32, LstrArrayStoreException, PhysicalReg_ECX, true);
+ unconditional_jump("common_throw", false);
+ return 0;
+}
+/*!
+\brief helper function to handle negative array size error
+
+*/
+int common_errNegArraySize() {
+ insertLabel("common_errNegArraySize", false);
+ move_imm_to_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ move_imm_to_reg(OpndSize_32, LstrNegativeArraySizeException, PhysicalReg_ECX, true);
+ unconditional_jump("common_throw", false);
+ return 0;
+}
+/*!
+\brief helper function to handle divide-by-zero error
+
+*/
+int common_errDivideByZero() {
+ insertLabel("common_errDivideByZero", false);
+ move_imm_to_reg(OpndSize_32, LstrDivideByZero, PhysicalReg_EAX, true);
+ move_imm_to_reg(OpndSize_32, LstrArithmeticException, PhysicalReg_ECX, true);
+ unconditional_jump("common_throw", false);
+ return 0;
+}
+/*!
+\brief helper function to handle no such method error
+
+*/
+int common_errNoSuchMethod() {
+ insertLabel("common_errNoSuchMethod", false);
+ move_imm_to_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ move_imm_to_reg(OpndSize_32, LstrNoSuchMethodError, PhysicalReg_ECX, true);
+ unconditional_jump("common_throw", false);
+ return 0;
+}
+int call_dvmFindCatchBlock();
+
+#define P_GPR_1 PhysicalReg_ESI //self callee-saved
+#define P_GPR_2 PhysicalReg_EBX //exception callee-saved
+#define P_GPR_3 PhysicalReg_EAX //method that caused exception
+/*!
+\brief helper function common_exceptionThrown
+
+*/
+int common_exceptionThrown() {
+ insertLabel("common_exceptionThrown", false);
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = dvmJitToExceptionThrown;
+ move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
+ unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+
+/*!
+\brief helper function to throw an exception with message
+
+INPUT: obj_reg(%eax), exceptionPtrReg(%ecx)
+SCRATCH: C_SCRATCH_1(%esi) & C_SCRATCH_2(%edx)
+OUTPUT: no
+*/
+int throw_exception_message(int exceptionPtrReg, int obj_reg, bool isPhysical,
+ int startLR/*logical register index*/, bool startPhysical) {
+ insertLabel("common_throw_message", false);
+ scratchRegs[0] = PhysicalReg_ESI; scratchRegs[1] = PhysicalReg_EDX;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+
+ move_mem_to_reg(OpndSize_32, offObject_clazz, obj_reg, isPhysical, C_SCRATCH_1, isScratchPhysical);
+ move_mem_to_reg(OpndSize_32, offClassObject_descriptor, C_SCRATCH_1, isScratchPhysical, C_SCRATCH_2, isScratchPhysical);
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, C_SCRATCH_2, isScratchPhysical, 4, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, exceptionPtrReg, true, 0, PhysicalReg_ESP, true);
+ call_dvmThrowWithMessage();
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ unconditional_jump("common_exceptionThrown", false);
+ return 0;
+}
+/*!
+\brief helper function to throw an exception
+
+scratch: C_SCRATCH_1(%edx)
+*/
+int throw_exception(int exceptionPtrReg, int immReg,
+ int startLR/*logical register index*/, bool startPhysical) {
+ insertLabel("common_throw", false);
+ scratchRegs[0] = PhysicalReg_EDX; scratchRegs[1] = PhysicalReg_Null;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, immReg, true, 4, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, exceptionPtrReg, true, 0, PhysicalReg_ESP, true);
+ call_dvmThrow();
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ unconditional_jump("common_exceptionThrown", false);
+ return 0;
+}
+
+//! lower bytecode GOTO
+
+//!
+int op_goto() {
+ s2 tmp = traceCurrentBB->taken->id;
+ int retval = common_goto(tmp);
+ rPC += 1;
+ return retval;
+}
+//! lower bytecode GOTO_16
+
+//!
+int op_goto_16() {
+ s2 tmp = traceCurrentBB->taken->id;
+ int retval = common_goto(tmp);
+ rPC += 2;
+ return retval;
+}
+//! lower bytecode GOTO_32
+
+//!
+int op_goto_32() {
+ s2 tmp = traceCurrentBB->taken->id;
+ int retval = common_goto((s4)tmp);
+ rPC += 3;
+ return retval;
+}
+#define P_GPR_1 PhysicalReg_EBX
+//! lower bytecode PACKED_SWITCH
+
+//!
+int op_packed_switch() {
+ u4 tmp = (u4)FETCH(1);
+ tmp |= (u4)FETCH(2) << 16;
+ u2 vA = INST_AA(inst);
+
+#ifdef DEBUG_EACH_BYTECODE
+ u2 tSize = 0;
+ s4 firstKey = 0;
+ s4* entries = NULL;
+#else
+ u2* switchData = rPC + (s4)tmp;
+ if (*switchData++ != kPackedSwitchSignature) {
+ /* should have been caught by verifier */
+ dvmThrowInternalError(
+ "bad packed switch magic");
+ return 0; //no_op
+ }
+ u2 tSize = *switchData++;
+ assert(tSize > 0);
+ s4 firstKey = *switchData++;
+ firstKey |= (*switchData++) << 16;
+ s4* entries = (s4*) switchData;
+ assert(((u4)entries & 0x3) == 0);
+#endif
+
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ //dvmNcgHandlePackedSwitch: testVal, size, first_key, targets
+ load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, tSize, 8, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, firstKey, 4, PhysicalReg_ESP, true);
+
+ /* "entries" is constant for JIT
+ it is the 1st argument to dvmJitHandlePackedSwitch */
+ move_imm_to_mem(OpndSize_32, (int)entries, 0, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 1, false, 12, PhysicalReg_ESP, true);
+
+ //if value out of range, fall through (no_op)
+ //return targets[testVal - first_key]
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ call_dvmJitHandlePackedSwitch();
+ load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ //TODO: eax should be absolute address, call globalVREndOfBB, constVREndOfBB
+ //conditional_jump_global_API(Condition_LE, "common_backwardBranch", false);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod); //update GG VRs
+ //get rPC, %eax has the relative PC offset
+ alu_binary_imm_reg(OpndSize_32, add_opc, (int)rPC, PhysicalReg_EAX, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_2;
+ jumpToInterpNoChain();
+ rPC += 3;
+ return 0;
+}
+#undef P_GPR_1
+
+#define P_GPR_1 PhysicalReg_EBX
+//! lower bytecode SPARSE_SWITCH
+
+//!
+int op_sparse_switch() {
+ u4 tmp = (u4)FETCH(1);
+ tmp |= (u4)FETCH(2) << 16;
+ u2 vA = INST_AA(inst);
+#ifdef DEBUG_EACH_BYTECODE
+ u2 tSize = 0;
+ const s4* keys = NULL;
+ s4* entries = NULL;
+#else
+ u2* switchData = rPC + (s4)tmp;
+
+ if (*switchData++ != kSparseSwitchSignature) {
+ /* should have been caught by verifier */
+ dvmThrowInternalError(
+ "bad sparse switch magic");
+ return 0; //no_op
+ }
+ u2 tSize = *switchData++;
+ assert(tSize > 0);
+ const s4* keys = (const s4*) switchData;
+ assert(((u4)keys & 0x3) == 0);
+ s4* entries = (s4*)switchData + tSize;
+ assert(((u4)entries & 0x3) == 0);
+#endif
+
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ //dvmNcgHandleSparseSwitch: keys, size, testVal
+ load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, tSize, 4, PhysicalReg_ESP, true);
+
+ /* "keys" is constant for JIT
+ it is the 1st argument to dvmJitHandleSparseSwitch */
+ move_imm_to_mem(OpndSize_32, (int)keys, 0, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 1, false, 8, PhysicalReg_ESP, true);
+
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ //if testVal is in keys, return the corresponding target
+ //otherwise, fall through (no_op)
+ call_dvmJitHandleSparseSwitch();
+ load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ //TODO: eax should be absolute address, call globalVREndOfBB constVREndOfBB
+ //conditional_jump_global_API(Condition_LE, "common_backwardBranch", false);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ //get rPC, %eax has the relative PC offset
+ alu_binary_imm_reg(OpndSize_32, add_opc, (int)rPC, PhysicalReg_EAX, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_2;
+ jumpToInterpNoChain();
+ rPC += 3;
+ return 0;
+}
+
+#undef P_GPR_1
+
+#define P_GPR_1 PhysicalReg_EBX
+//! lower bytecode IF_EQ
+
+//!
+int op_if_eq() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s2 tmp = (s2)FETCH(1);
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ compare_VR_reg(OpndSize_32, vB, 1, false);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_NE, Condition_E);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode IF_NE
+
+//!
+int op_if_ne() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s2 tmp = (s2)FETCH(1);
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ compare_VR_reg(OpndSize_32, vB, 1, false);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_E, Condition_NE);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode IF_LT
+
+//!
+int op_if_lt() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s2 tmp = (s2)FETCH(1);
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ compare_VR_reg(OpndSize_32, vB, 1, false);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_GE, Condition_L);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode IF_GE
+
+//!
+int op_if_ge() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s2 tmp = (s2)FETCH(1);
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ compare_VR_reg(OpndSize_32, vB, 1, false);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_L, Condition_GE);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode IF_GT
+
+//!
+int op_if_gt() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s2 tmp = (s2)FETCH(1);
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ compare_VR_reg(OpndSize_32, vB, 1, false);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_LE, Condition_G);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode IF_LE
+
+//!
+int op_if_le() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ s2 tmp = (s2)FETCH(1);
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ compare_VR_reg(OpndSize_32, vB, 1, false);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_G, Condition_LE);
+ rPC += 2;
+ return 0;
+}
+#undef P_GPR_1
+//! lower bytecode IF_EQZ
+
+//!
+int op_if_eqz() {
+ u2 vA = INST_AA(inst);
+ s2 tmp = (s2)FETCH(1);
+ compare_imm_VR(OpndSize_32,
+ 0, vA);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_NE, Condition_E);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode IF_NEZ
+
+//!
+int op_if_nez() {
+ u2 vA = INST_AA(inst);
+ s2 tmp = (s2)FETCH(1);
+ compare_imm_VR(OpndSize_32,
+ 0, vA);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_E, Condition_NE);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode IF_LTZ
+
+//!
+int op_if_ltz() {
+ u2 vA = INST_AA(inst);
+ s2 tmp = (s2)FETCH(1);
+ compare_imm_VR(OpndSize_32,
+ 0, vA);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_GE, Condition_L);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode IF_GEZ
+
+//!
+int op_if_gez() {
+ u2 vA = INST_AA(inst);
+ s2 tmp = (s2)FETCH(1);
+ compare_imm_VR(OpndSize_32,
+ 0, vA);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_L, Condition_GE);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode IF_GTZ
+
+//!
+int op_if_gtz() {
+ u2 vA = INST_AA(inst);
+ s2 tmp = (s2)FETCH(1);
+ compare_imm_VR(OpndSize_32,
+ 0, vA);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_LE, Condition_G);
+ rPC += 2;
+ return 0;
+}
+//! lower bytecode IF_LEZ
+
+//!
+int op_if_lez() {
+ u2 vA = INST_AA(inst);
+ s2 tmp = (s2)FETCH(1);
+ compare_imm_VR(OpndSize_32,
+ 0, vA);
+ constVREndOfBB();
+ globalVREndOfBB(currentMethod);
+ common_if(tmp, Condition_G, Condition_LE);
+ rPC += 2;
+ return 0;
+}
+
+#define P_GPR_1 PhysicalReg_ECX
+#define P_GPR_2 PhysicalReg_EBX
+/*!
+\brief helper function common_periodicChecks4 to check GC request
+BCOffset in %edx
+*/
+int common_periodicChecks4() {
+ insertLabel("common_periodicChecks4", false);
+#if (!defined(ENABLE_TRACING))
+ get_self_pointer(PhysicalReg_ECX, true);
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, suspendCount), PhysicalReg_ECX, true, PhysicalReg_EAX, true);
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true); //suspendCount
+ conditional_jump(Condition_NE, "common_handleSuspend4", true); //called once
+ x86_return();
+
+ insertLabel("common_handleSuspend4", true);
+ push_reg_to_stack(OpndSize_32, PhysicalReg_ECX, true);
+ call_dvmCheckSuspendPending();
+ load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ x86_return();
+
+#else
+ ///////////////////
+ //get debuggerActive: 3 memory accesses, and $7
+ move_mem_to_reg(OpndSize_32, offGlue_pSelfSuspendCount, PhysicalReg_Glue, true, P_GPR_1, true);
+ move_mem_to_reg(OpndSize_32, offGlue_pIntoDebugger, PhysicalReg_Glue, true, P_GPR_2, true);
+
+ compare_imm_mem(OpndSize_32, 0, 0, P_GPR_1, true); //suspendCount
+ conditional_jump(Condition_NE, "common_handleSuspend4_1", true); //called once
+
+ compare_imm_mem(OpndSize_32, 0, 0, P_GPR_2, true); //debugger active
+
+ conditional_jump(Condition_NE, "common_debuggerActive4", true);
+
+ //recover registers and return
+ x86_return();
+
+ insertLabel("common_handleSuspend4_1", true);
+ push_mem_to_stack(OpndSize_32, offGlue_self, PhysicalReg_Glue, true);
+ call_dvmCheckSuspendPending();
+ load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ x86_return();
+
+ insertLabel("common_debuggerActive4", true);
+ //%edx: offsetBC (at run time, get method->insns_bytecode, then calculate BCPointer)
+ move_mem_to_reg(OpndSize_32, offGlue_method, PhysicalReg_Glue, true, P_GPR_1, true);
+ move_mem_to_reg(OpndSize_32, offMethod_insns_bytecode, P_GPR_1, true, P_GPR_2, true);
+ alu_binary_reg_reg(OpndSize_32, add_opc, P_GPR_2, true, PhysicalReg_EDX, true);
+ move_imm_to_mem(OpndSize_32, 0, offGlue_entryPoint, PhysicalReg_Glue, true);
+ unconditional_jump("common_gotoBail", false); //update glue->rPC with edx
+#endif
+ return 0;
+}
+//input: %edx PC adjustment
+//CHECK: should %edx be saved before calling dvmCheckSuspendPending?
+/*!
+\brief helper function common_periodicChecks_entry to check GC request
+
+*/
+int common_periodicChecks_entry() {
+ insertLabel("common_periodicChecks_entry", false);
+ scratchRegs[0] = PhysicalReg_ESI; scratchRegs[1] = PhysicalReg_EAX;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ get_suspendCount(P_GPR_1, true);
+
+ //get debuggerActive: 3 memory accesses, and $7
+#if 0 //defined(WITH_DEBUGGER)
+ get_debuggerActive(P_GPR_2, true);
+#endif
+
+ compare_imm_reg(OpndSize_32, 0, P_GPR_1, true); //suspendCount
+ conditional_jump(Condition_NE, "common_handleSuspend", true); //called once
+
+#if 0 //defined(WITH_DEBUGGER)
+#ifdef NCG_DEBUG
+ compare_imm_reg(OpndSize_32, 0, P_GPR_2, true); //debugger active
+ conditional_jump(Condition_NE, "common_debuggerActive", true);
+#endif
+#endif
+
+ //recover registers and return
+ x86_return();
+ insertLabel("common_handleSuspend", true);
+ get_self_pointer(P_GPR_1, true);
+ load_effective_addr(-4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, P_GPR_1, true, 0, PhysicalReg_ESP, true);
+ call_dvmCheckSuspendPending();
+ load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ x86_return();
+#ifdef NCG_DEBUG
+ insertLabel("common_debuggerActive", true);
+ //adjust PC!!! use 0(%esp) TODO
+ set_glue_entryPoint_imm(0); //kInterpEntryInstr);
+ unconditional_jump("common_gotoBail", false);
+#endif
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+/*!
+\brief helper function common_gotoBail
+ input: %edx: BCPointer %esi: Glue
+ set %eax to 1 (switch interpreter = true), recover the callee-saved registers and return
+*/
+int common_gotoBail() {
+ insertLabel("common_gotoBail", false);
+ //scratchRegs[0] = PhysicalReg_EDX; scratchRegs[1] = PhysicalReg_ESI;
+ //scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ //save_pc_fp_to_glue();
+ get_self_pointer(PhysicalReg_EAX, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offsetof(Thread, interpSave.curFrame), PhysicalReg_EAX, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true, offsetof(Thread, interpSave.pc), PhysicalReg_EAX, true);
+
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, interpSave.bailPtr), PhysicalReg_EAX, true, PhysicalReg_ESP, true);
+ move_reg_to_reg(OpndSize_32, PhysicalReg_ESP, true, PhysicalReg_EBP, true);
+ load_effective_addr(FRAME_SIZE-4, PhysicalReg_EBP, true, PhysicalReg_EBP, true);
+ move_imm_to_reg(OpndSize_32, 1, PhysicalReg_EAX, true); //return value
+ move_mem_to_reg(OpndSize_32, -4, PhysicalReg_EBP, true, PhysicalReg_EDI, true);
+ move_mem_to_reg(OpndSize_32, -8, PhysicalReg_EBP, true, PhysicalReg_ESI, true);
+ move_mem_to_reg(OpndSize_32, -12, PhysicalReg_EBP, true, PhysicalReg_EBX, true);
+ move_reg_to_reg(OpndSize_32, PhysicalReg_EBP, true, PhysicalReg_ESP, true);
+ move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, PhysicalReg_EBP, true);
+ load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ x86_return();
+ return 0;
+}
+/*!
+\brief helper function common_gotoBail_0
+
+ set %eax to 0, recover the callee-saved registers and return
+*/
+int common_gotoBail_0() {
+ insertLabel("common_gotoBail_0", false);
+
+ get_self_pointer(PhysicalReg_EAX, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offsetof(Thread, interpSave.curFrame), PhysicalReg_EAX, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true, offsetof(Thread, interpSave.pc), PhysicalReg_EAX, true);
+
+ /*
+ movl offThread_bailPtr(%ecx),%esp # Restore "setjmp" esp
+ movl %esp,%ebp
+ addl $(FRAME_SIZE-4), %ebp # Restore %ebp at point of setjmp
+ movl EDI_SPILL(%ebp),%edi
+ movl ESI_SPILL(%ebp),%esi
+ movl EBX_SPILL(%ebp),%ebx
+ movl %ebp, %esp # strip frame
+ pop %ebp # restore caller's ebp
+ ret # return to dvmMterpStdRun's caller
+ */
+ move_mem_to_reg(OpndSize_32, offsetof(Thread, interpSave.bailPtr), PhysicalReg_EAX, true, PhysicalReg_ESP, true);
+ move_reg_to_reg(OpndSize_32, PhysicalReg_ESP, true, PhysicalReg_EBP, true);
+ load_effective_addr(FRAME_SIZE-4, PhysicalReg_EBP, true, PhysicalReg_EBP, true);
+ move_imm_to_reg(OpndSize_32, 0, PhysicalReg_EAX, true); //return value
+ move_mem_to_reg(OpndSize_32, -4, PhysicalReg_EBP, true, PhysicalReg_EDI, true);
+ move_mem_to_reg(OpndSize_32, -8, PhysicalReg_EBP, true, PhysicalReg_ESI, true);
+ move_mem_to_reg(OpndSize_32, -12, PhysicalReg_EBP, true, PhysicalReg_EBX, true);
+ move_reg_to_reg(OpndSize_32, PhysicalReg_EBP, true, PhysicalReg_ESP, true);
+ move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, PhysicalReg_EBP, true);
+ load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ x86_return();
+ return 0;
+}
diff --git a/vm/compiler/codegen/x86/LowerMove.cpp b/vm/compiler/codegen/x86/LowerMove.cpp
new file mode 100644
index 0000000..2f0b5bc
--- /dev/null
+++ b/vm/compiler/codegen/x86/LowerMove.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file LowerMove.cpp
+ \brief This file lowers the following bytecodes: MOVE_XXX
+*/
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "Lower.h"
+#include "enc_wrapper.h"
+
+#define P_GPR_1 PhysicalReg_EBX
+//! lower bytecode MOVE
+
+//!
+int op_move() {
+ u2 vA, vB;
+ vA = INST_A(inst);
+ vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_32, 1, false/*isPhysical*/);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 1;
+ return 2;
+}
+//! lower bytecode MOVE_FROM16
+
+//!
+int op_move_from16() {
+ u2 vA, vB;
+ vA = INST_AA(inst);
+ vB = FETCH(1);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 2;
+ return 2;
+}
+//! lower bytecode MOVE_16
+
+//!
+int op_move_16() {
+ u2 vA, vB;
+ vA = FETCH(1);
+ vB = FETCH(2);
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 3;
+ return 2;
+}
+#undef P_GPR_1
+//! lower bytecode MOVE_WIDE
+
+//!
+int op_move_wide() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ get_virtual_reg(vB, OpndSize_64, 1, false);
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ rPC += 1;
+ return 2;
+}
+//! lower bytecode MOVE_WIDE_FROM16
+
+//!
+int op_move_wide_from16() {
+ u2 vA = INST_AA(inst);
+ u2 vB = FETCH(1);
+ get_virtual_reg(vB, OpndSize_64, 1, false);
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ rPC += 2;
+ return 2;
+}
+//! lower bytecode MOVE_WIDE_16
+
+//!
+int op_move_wide_16() {
+ u2 vA = FETCH(1);
+ u2 vB = FETCH(2);
+ get_virtual_reg(vB, OpndSize_64, 1, false);
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ rPC += 3;
+ return 2;
+}
+//! lower bytecode MOVE_RESULT.
+
+//! the return value from bytecode INVOKE is stored in the glue structure
+int op_move_result() {
+#ifdef WITH_JIT_INLINING
+ /* An inlined move result is effectively no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return 0;
+#endif
+ u2 vA = INST_AA(inst);
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ get_return_value(OpndSize_32, 1, false);
+ set_virtual_reg(vA, OpndSize_32, 1, false);
+ rPC += 1;
+ return 0;
+}
+//! lower bytecode MOVE_RESULT_WIDE.
+
+//! the return value from bytecode INVOKE is stored in the glue structure
+int op_move_result_wide() {
+#ifdef WITH_JIT_INLINING
+ /* An inlined move result is effectively no-op */
+ if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
+ return 0;
+#endif
+ u2 vA = INST_AA(inst);
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ get_return_value(OpndSize_64, 1, false);
+ set_virtual_reg(vA, OpndSize_64, 1, false);
+ rPC += 1;
+ return 0;
+}
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+//!lower bytecode MOVE_RESULT_EXCEPTION
+
+//!update a virtual register with exception from glue structure;
+//!clear the exception from glue structure
+int op_move_exception() {
+ u2 vA = INST_AA(inst);
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_Null;
+ get_self_pointer(2, false);
+ move_mem_to_reg(OpndSize_32, offThread_exception, 2, false, 3, false);
+ move_imm_to_mem(OpndSize_32, 0, offThread_exception, 2, false);
+ set_virtual_reg(vA, OpndSize_32, 3, false);
+ rPC += 1;
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+
diff --git a/vm/compiler/codegen/x86/LowerObject.cpp b/vm/compiler/codegen/x86/LowerObject.cpp
new file mode 100644
index 0000000..67c4044
--- /dev/null
+++ b/vm/compiler/codegen/x86/LowerObject.cpp
@@ -0,0 +1,682 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*! \file LowerObject.cpp
+ \brief This file lowers the following bytecodes: CHECK_CAST,
+*/
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "Lower.h"
+#include "NcgAot.h"
+#include "enc_wrapper.h"
+
+extern void markCard_filled(int tgtAddrReg, bool isTgtPhysical, int scratchReg, bool isScratchPhysical);
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_ESI
+//! LOWER bytecode CHECK_CAST and INSTANCE_OF
+//! CALL class_resolve (%ebx is live across the call)
+//! dvmInstanceofNonTrivial
+//! NO register is live through function check_cast_helper
+int check_cast_nohelper(u2 vA, u4 tmp, bool instance, u2 vDest) {
+ get_virtual_reg(vA, OpndSize_32, 1, false); //object
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ /* for trace-based JIT, it is likely that the class is already resolved */
+ bool needToResolve = true;
+ ClassObject *classPtr =
+ (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
+ ALOGV("in check_cast, class is resolved to %p", classPtr);
+ if(classPtr != NULL) {
+ needToResolve = false;
+ ALOGV("check_cast class %s", classPtr->descriptor);
+ }
+ if(needToResolve) {
+ //get_res_classes is moved here for NCG O1 to improve performance of GLUE optimization
+ scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
+ get_res_classes(4, false);
+ }
+ compare_imm_reg(OpndSize_32, 0, 1, false);
+
+ rememberState(1);
+ //for private code cache, previously it jumped to .instance_of_okay_1
+ //if object reference is null, jump to the handler for this special case
+ if(instance) {
+ conditional_jump(Condition_E, ".instance_of_null", true);
+ }
+ else {
+ conditional_jump(Condition_E, ".check_cast_null", true);
+ }
+ //check whether the class is already resolved
+ //if yes, jump to check_cast_resolved
+ //if not, call class_resolve
+ if(needToResolve) {
+ move_mem_to_reg(OpndSize_32, tmp*4, 4, false, PhysicalReg_EAX, true);
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ if(instance)
+ conditional_jump(Condition_NE, ".instance_of_resolved", true);
+ else
+ conditional_jump(Condition_NE, ".check_cast_resolved", true);
+ //try to resolve the class
+ rememberState(2);
+ move_imm_to_reg(OpndSize_32, tmp, PhysicalReg_EAX, true);
+ export_pc(); //trying to resolve the class
+ call_helper_API(".class_resolve");
+ transferToState(2);
+ } //needToResolve
+ else {
+ /* the class is already resolved and is constant */
+ move_imm_to_reg(OpndSize_32, (int)classPtr, PhysicalReg_EAX, true);
+ }
+ //class is resolved, and it is in %eax
+ if(!instance) {
+ insertLabel(".check_cast_resolved", true);
+ }
+ else insertLabel(".instance_of_resolved", true);
+
+ move_mem_to_reg(OpndSize_32, offObject_clazz, 1, false, 6, false); //object->clazz
+
+ //%eax: resolved class
+ //compare resolved class and object->clazz
+ //if the same, jump to the handler for this special case
+ compare_reg_reg(PhysicalReg_EAX, true, 6, false);
+ rememberState(3);
+ if(instance) {
+ conditional_jump(Condition_E, ".instance_of_equal", true);
+ } else {
+ conditional_jump(Condition_E, ".check_cast_equal", true);
+ }
+
+ //prepare to call dvmInstanceofNonTrivial
+ //INPUT: the resolved class & object reference
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 6, false, 0, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 4, PhysicalReg_ESP, true); //resolved class
+ scratchRegs[0] = PhysicalReg_SCRATCH_3;
+ nextVersionOfHardReg(PhysicalReg_EAX, 2); //next version has 2 refs
+ call_dvmInstanceofNonTrivial();
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ //
+ if(instance) {
+ //move return value to P_GPR_2
+ move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, 3, false);
+ rememberState(4);
+ unconditional_jump(".instance_of_okay", true);
+ } else {
+ //if return value of dvmInstanceofNonTrivial is zero, throw exception
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ rememberState(4);
+ conditional_jump(Condition_NE, ".check_cast_okay", true);
+ //two inputs for common_throw_message: object reference in eax, exception pointer in ecx
+ nextVersionOfHardReg(PhysicalReg_EAX, 1); //next version has 1 ref
+ move_reg_to_reg(OpndSize_32, 1, false, PhysicalReg_EAX, true);
+
+ load_imm_global_data_API("strClassCastExceptionPtr", OpndSize_32, PhysicalReg_ECX, true);
+
+ nextVersionOfHardReg(PhysicalReg_EDX, 2); //next version has 2 ref count
+ export_pc();
+
+ unconditional_jump_global_API("common_throw_message", false);
+ }
+ //handler for speical case where object reference is null
+ if(instance)
+ insertLabel(".instance_of_null", true);
+ else insertLabel(".check_cast_null", true);
+ goToState(1);
+ if(instance) {
+ move_imm_to_reg(OpndSize_32, 0, 3, false);
+ }
+ transferToState(4);
+ if(instance)
+ unconditional_jump(".instance_of_okay", true);
+ else
+ unconditional_jump(".check_cast_okay", true);
+
+ //handler for special case where class of object is the same as the resolved class
+ if(instance)
+ insertLabel(".instance_of_equal", true);
+ else insertLabel(".check_cast_equal", true);
+ goToState(3);
+ if(instance) {
+ move_imm_to_reg(OpndSize_32, 1, 3, false);
+ }
+ transferToState(4);
+ if(instance)
+ insertLabel(".instance_of_okay", true);
+ else insertLabel(".check_cast_okay", true);
+ //all cases merge here and the value is put to virtual register
+ if(instance) {
+ set_virtual_reg(vDest, OpndSize_32, 3, false);
+ }
+ return 0;
+}
+//! common code to lower CHECK_CAST & INSTANCE_OF
+
+//!
+int common_check_cast_instance_of(u2 vA, u4 tmp, bool instance, u2 vDest) {
+ return check_cast_nohelper(vA, tmp, instance, vDest);
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+
+//! LOWER bytecode CHECK_CAST
+
+//!
+int op_check_cast() {
+ u2 vA = INST_AA(inst);
+ u4 tmp = (u4)FETCH(1);
+ common_check_cast_instance_of(vA, tmp, false, 0);
+ rPC += 2;
+ return 0;
+}
+//!LOWER bytecode INSTANCE_OF
+
+//!
+int op_instance_of() {
+ u2 vB = INST_B(inst);
+ u2 vA = INST_A(inst);
+ u4 tmp = (u4)FETCH(1);
+ common_check_cast_instance_of(vB, tmp, true, vA);
+ rPC += 2;
+ return 0;
+}
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+//! LOWER bytecode MONITOR_ENTER without usage of helper function
+
+//! CALL dvmLockObject
+int monitor_enter_nohelper(u2 vA) {
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+
+ requestVRFreeDelay(vA,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
+ //get_self_pointer is separated
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ //to optimize redundant null check, NCG O1 wraps up null check in a function: nullCheck
+ get_self_pointer(3, false);
+ nullCheck(1, false, 1, vA); //maybe optimized away
+ cancelVRFreeDelayRequest(vA,VRDELAY_NULLCHECK);
+
+ /////////////////////////////
+ //prepare to call dvmLockObject, inputs: object reference and self
+ // TODO: Should reset inJitCodeCache before calling dvmLockObject
+ // so that code cache can be reset if needed when locking object
+ // taking a long time. Not resetting inJitCodeCache may delay
+ // code cache reset when code cache is full, preventing traces from
+ // JIT compilation. This has performance implication.
+ // However, after resetting inJitCodeCache, the code should be
+ // wrapped in a helper instead of directly inlined in code cache.
+ // If the code after dvmLockObject call is in code cache and the code
+ // cache is reset during dvmLockObject call, execution after
+ // dvmLockObject will return to a cleared code cache region,
+ // resulting in seg fault.
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 1, false, 4, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 3, false, 0, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_2;
+ call_dvmLockObject();
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ /////////////////////////////
+ return 0;
+}
+//! lower bytecode MONITOR_ENTER
+
+//! It will use helper function if switch is on
+int op_monitor_enter() {
+ u2 vA = INST_AA(inst);
+ export_pc();
+ monitor_enter_nohelper(vA);
+ rPC += 1;
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+//! lower bytecode MONITOR_EXIT
+
+//! It will use helper function if switch is on
+int op_monitor_exit() {
+ u2 vA = INST_AA(inst);
+ ////////////////////
+ //LOWER bytecode MONITOR_EXIT without helper function
+ // CALL dvmUnlockObject
+ scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ requestVRFreeDelay(vA,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ nullCheck(1, false, 1, vA); //maybe optimized away
+ cancelVRFreeDelayRequest(vA,VRDELAY_NULLCHECK);
+
+ /////////////////////////////
+ //prepare to call dvmUnlockObject, inputs: object reference and self
+ push_reg_to_stack(OpndSize_32, 1, false);
+ push_mem_to_stack(OpndSize_32, offEBP_self, PhysicalReg_EBP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_2;
+ call_dvmUnlockObject();
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+
+ conditional_jump(Condition_NE, ".unlock_object_done", true);
+ //jump to dvmJitToExceptionThrown
+ scratchRegs[0] = PhysicalReg_SCRATCH_3;
+ jumpToExceptionThrown(2/*exception number*/);
+ insertLabel(".unlock_object_done", true);
+ ///////////////////////////
+ rPC += 1;
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_EDX /*vA*/
+//! LOWER bytecode ARRAY_LENGTH
+
+//! It will use helper function if switch is on
+int op_array_length() {
+ u2 vA = INST_A(inst);
+ u2 vB = INST_B(inst);
+ ////////////////////
+ //no usage of helper function
+ requestVRFreeDelay(vB,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
+ get_virtual_reg(vB, OpndSize_32, 1, false);
+ nullCheck(1, false, 1, vB); //maybe optimized away
+ cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
+
+ move_mem_to_reg(OpndSize_32, offArrayObject_length, 1, false, 2, false);
+ set_virtual_reg(vA, OpndSize_32, 2, false);
+ ///////////////////////
+ rPC += 1;
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_ESI
+//! lower bytecode NEW_INSTANCE
+
+//! It will use helper function if switch is on
+int op_new_instance() {
+ u4 tmp = (u4)FETCH(1);
+ u2 vA = INST_AA(inst);
+ export_pc();
+ /* for trace-based JIT, class is already resolved */
+ ClassObject *classPtr =
+ (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
+ assert(classPtr != NULL);
+ assert(classPtr->status & CLASS_INITIALIZED);
+ /*
+ * If it is going to throw, it should not make to the trace to begin
+ * with. However, Alloc might throw, so we need to genExportPC()
+ */
+ assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
+ //prepare to call dvmAllocObject, inputs: resolved class & flag ALLOC_DONT_TRACK
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ /* 1st argument to dvmAllocObject at -8(%esp) */
+ move_imm_to_mem(OpndSize_32, (int)classPtr, 0, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, ALLOC_DONT_TRACK, 4, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_3;
+ nextVersionOfHardReg(PhysicalReg_EAX, 3); //next version has 3 refs
+ call_dvmAllocObject();
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ //return value of dvmAllocObject is in %eax
+ //if return value is null, throw exception
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump(Condition_NE, ".new_instance_done", true);
+ //jump to dvmJitToExceptionThrown
+ scratchRegs[0] = PhysicalReg_SCRATCH_4;
+ jumpToExceptionThrown(3/*exception number*/);
+ insertLabel(".new_instance_done", true);
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
+ rPC += 2;
+ return 0;
+}
+
+//! function to initialize a class
+
+//!INPUT: %eax (class object) %eax is recovered before return
+//!OUTPUT: none
+//!CALL: dvmInitClass
+//!%eax, %esi, %ebx are live through function new_instance_needinit
+int new_instance_needinit() {
+ insertLabel(".new_instance_needinit", false);
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 0, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 4, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_ECX;
+ call_dvmInitClass();
+ //if return value of dvmInitClass is zero, throw exception
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ //recover EAX with the class object
+ move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true, PhysicalReg_EAX, true);
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ conditional_jump(Condition_E, "common_exceptionThrown", false);
+ x86_return();
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+
+#define P_GPR_1 PhysicalReg_EBX //live through C function, must in callee-saved reg
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_EDX
+//! lower bytecode NEW_ARRAY
+
+//! It will use helper function if switch is on
+int op_new_array() {
+ u4 tmp = (u4)FETCH(1);
+ u2 vA = INST_A(inst); //destination
+ u2 vB = INST_B(inst); //length
+ /////////////////////////
+ // REGS used: %esi, %eax, P_GPR_1, P_GPR_2
+ // CALL class_resolve, dvmAllocArrayByClass
+ export_pc(); //use %edx
+ //check size of the array, if negative, throw exception
+ get_virtual_reg(vB, OpndSize_32, 5, false);
+ compare_imm_reg(OpndSize_32, 0, 5, false);
+ handlePotentialException(Condition_S, Condition_NS,
+ 1, "common_errNegArraySize");
+ void *classPtr = (void*)
+ (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
+ assert(classPtr != NULL);
+ //here, class is already resolved, the class object is in %eax
+ //prepare to call dvmAllocArrayByClass with inputs: resolved class, array length, flag ALLOC_DONT_TRACK
+ insertLabel(".new_array_resolved", true);
+ load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ /* 1st argument to dvmAllocArrayByClass at 0(%esp) */
+ move_imm_to_mem(OpndSize_32, (int)classPtr, 0, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 5, false, 4, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, ALLOC_DONT_TRACK, 8, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_3;
+ nextVersionOfHardReg(PhysicalReg_EAX, 3); //next version has 3 refs
+ call_dvmAllocArrayByClass();
+ load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+
+ //the allocated object is in %eax
+ //check whether it is null, throw exception if null
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump(Condition_NE, ".new_array_done", true);
+ //jump to dvmJitToExceptionThrown
+ scratchRegs[0] = PhysicalReg_SCRATCH_4;
+ jumpToExceptionThrown(2/*exception number*/);
+ insertLabel(".new_array_done", true);
+ set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
+ //////////////////////////////////////
+ rPC += 2;
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+
+#define P_GPR_1 PhysicalReg_EBX
+#define P_GPR_2 PhysicalReg_ECX
+#define P_GPR_3 PhysicalReg_ESI
+//! common code to lower FILLED_NEW_ARRAY
+
+//! call: class_resolve call_dvmAllocPrimitiveArray
+//! exception: filled_new_array_notimpl common_exceptionThrown
+int common_filled_new_array(u2 length, u4 tmp, bool hasRange) {
+ ClassObject *classPtr =
+ (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
+ if(classPtr != NULL) ALOGI("FILLED_NEW_ARRAY class %s", classPtr->descriptor);
+ //check whether class is resolved, if yes, jump to resolved
+ //if not, call class_resolve
+ scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ get_res_classes(3, false);
+ move_mem_to_reg(OpndSize_32, tmp*4, 3, false, PhysicalReg_EAX, true);
+ export_pc();
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true); //resolved class
+ conditional_jump(Condition_NE, ".filled_new_array_resolved", true);
+ rememberState(1);
+ move_imm_to_reg(OpndSize_32, tmp, PhysicalReg_EAX, true);
+ call_helper_API(".class_resolve");
+ transferToState(1);
+ //here, class is already resolved
+ insertLabel(".filled_new_array_resolved", true);
+ //check descriptor of the class object, if not implemented, throws exception
+ move_mem_to_reg(OpndSize_32, 24, PhysicalReg_EAX, true, 5, false);
+ //load a single byte of the descriptor
+ movez_mem_to_reg(OpndSize_8, 1, 5, false, 6, false);
+ compare_imm_reg(OpndSize_32, 'I', 6, false);
+ conditional_jump(Condition_E, ".filled_new_array_impl", true);
+ compare_imm_reg(OpndSize_32, 'L', 6, false);
+ conditional_jump(Condition_E, ".filled_new_array_impl", true);
+ compare_imm_reg(OpndSize_32, '[', 6, false);
+ conditional_jump(Condition_NE, ".filled_new_array_notimpl", false);
+
+ insertLabel(".filled_new_array_impl", true);
+ //prepare to call dvmAllocArrayByClass with inputs: classObject, length, flag ALLOC_DONT_TRACK
+ load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, (int)classPtr, 0, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, length, 4, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, ALLOC_DONT_TRACK, 8, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_3; scratchRegs[1] = PhysicalReg_Null;
+ if(hasRange) {
+ nextVersionOfHardReg(PhysicalReg_EAX, 5+(length >= 1 ? LOOP_COUNT : 0)); //next version
+ }
+ else {
+ nextVersionOfHardReg(PhysicalReg_EAX, 5+length); //next version
+ }
+ call_dvmAllocArrayByClass();
+ load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ //return value of dvmAllocPrimitiveArray is in %eax
+ //if the return value is null, throw exception
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ handlePotentialException(
+ Condition_E, Condition_NE,
+ 3, "common_exceptionThrown");
+
+ /* we need to mark the card of the new array, if it's not an int */
+ compare_imm_reg(OpndSize_32, 'I', 6, false);
+ conditional_jump(Condition_E, ".dont_mark_filled_new_array", true);
+
+ // Need to make copy of EAX, because it's used later in op_filled_new_array()
+ move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, 6, false);
+
+ markCard_filled(6, false, PhysicalReg_SCRATCH_4, false);
+
+ insertLabel(".dont_mark_filled_new_array", true);
+
+ //return value of bytecode FILLED_NEW_ARRAY is in GLUE structure
+ scratchRegs[0] = PhysicalReg_SCRATCH_4; scratchRegs[1] = PhysicalReg_Null;
+ set_return_value(OpndSize_32, PhysicalReg_EAX, true);
+ return 0;
+}
+//! LOWER bytecode FILLED_NEW_ARRAY
+
+//!
+int op_filled_new_array() {
+ u2 length = INST_B(inst);
+ u4 tmp = (u4)FETCH(1);
+ u2 v5 = INST_A(inst);
+ u2 vv = FETCH(2);
+ u2 v1 = vv & 0xf;
+ u2 v2 = (vv >> 4) & 0xf;
+ u2 v3 = (vv >> 8) & 0xf;
+ u2 v4 = (vv >> 12) & 0xf;
+ common_filled_new_array(length, tmp, false);
+ if(length >= 1) {
+ //move from virtual register to contents of array object
+ get_virtual_reg(v1, OpndSize_32, 7, false);
+ move_reg_to_mem(OpndSize_32, 7, false, offArrayObject_contents, PhysicalReg_EAX, true);
+ }
+ if(length >= 2) {
+ //move from virtual register to contents of array object
+ get_virtual_reg(v2, OpndSize_32, 8, false);
+ move_reg_to_mem(OpndSize_32, 8, false, offArrayObject_contents+4, PhysicalReg_EAX, true);
+ }
+ if(length >= 3) {
+ //move from virtual register to contents of array object
+ get_virtual_reg(v3, OpndSize_32, 9, false);
+ move_reg_to_mem(OpndSize_32, 9, false, offArrayObject_contents+8, PhysicalReg_EAX, true);
+ }
+ if(length >= 4) {
+ //move from virtual register to contents of array object
+ get_virtual_reg(v4, OpndSize_32, 10, false);
+ move_reg_to_mem(OpndSize_32, 10, false, offArrayObject_contents+12, PhysicalReg_EAX, true);
+ }
+ if(length >= 5) {
+ //move from virtual register to contents of array object
+ get_virtual_reg(v5, OpndSize_32, 11, false);
+ move_reg_to_mem(OpndSize_32, 11, false, offArrayObject_contents+16, PhysicalReg_EAX, true);
+ }
+ rPC += 3;
+ return 0;
+}
+//! function to handle the error of array not implemented
+
+//!
+int filled_new_array_notimpl() {
+ //two inputs for common_throw:
+ insertLabel(".filled_new_array_notimpl", false);
+ move_imm_to_reg(OpndSize_32, LstrFilledNewArrayNotImpl, PhysicalReg_EAX, true);
+ move_imm_to_reg(OpndSize_32, (int) gDvm.exInternalError, PhysicalReg_ECX, true);
+ unconditional_jump("common_throw", false);
+ return 0;
+}
+
+#define P_SCRATCH_1 PhysicalReg_EDX
+//! LOWER bytecode FILLED_NEW_ARRAY_RANGE
+
+//!
+int op_filled_new_array_range() {
+ u2 length = INST_AA(inst);
+ u4 tmp = (u4)FETCH(1);
+ u4 vC = (u4)FETCH(2);
+ common_filled_new_array(length, tmp, true/*hasRange*/);
+ //here, %eax points to the array object
+ if(length >= 1) {
+ //dump all virtual registers used by this bytecode to stack, for NCG O1
+ int k;
+ for(k = 0; k < length; k++) {
+ spillVirtualReg(vC+k, LowOpndRegType_gp, true); //will update refCount
+ }
+ //address of the first virtual register that will be moved to the array object
+ load_effective_addr(vC*4, PhysicalReg_FP, true, 7, false); //addr
+ //start address for contents of the array object
+ load_effective_addr(offArrayObject_contents, PhysicalReg_EAX, true, 8, false); //addr
+ //loop counter
+ move_imm_to_reg(OpndSize_32, length-1, 9, false); //counter
+ //start of the loop
+ insertLabel(".filled_new_array_range_loop1", true);
+ rememberState(1);
+ move_mem_to_reg(OpndSize_32, 0, 7, false, 10, false);
+ load_effective_addr(4, 7, false, 7, false);
+ move_reg_to_mem(OpndSize_32, 10, false, 0, 8, false);
+ load_effective_addr(4, 8, false, 8, false);
+ alu_binary_imm_reg(OpndSize_32, sub_opc, 1, 9, false);
+ transferToState(1);
+ //jump back to the loop start
+ conditional_jump(Condition_NS, ".filled_new_array_range_loop1", true);
+ }
+ rPC += 3;
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_GPR_3
+#undef P_SCRATCH_1
+
+#define P_GPR_1 PhysicalReg_EBX
+//! LOWER bytecode FILL_ARRAY_DATA
+
+//!use 1 GPR and scratch regs (export_pc dvmInterpHandleFillArrayData)
+//!CALL: dvmInterpHandleFillArrayData
+int op_fill_array_data() {
+ u2 vA = INST_AA(inst);
+ u4 tmp = (u4)FETCH(1);
+ tmp |= (u4)FETCH(2) << 16;
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ scratchRegs[1] = PhysicalReg_Null;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ //prepare to call dvmInterpHandleFillArrayData, input: array object, address of the data
+ load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 1, false, 0, PhysicalReg_ESP, true);
+ /* 2nd argument to dvmInterpHandleFillArrayData at 4(%esp) */
+ move_imm_to_mem(OpndSize_32, (int)(rPC+tmp), 4, PhysicalReg_ESP, true);
+ call_dvmInterpHandleFillArrayData();
+ load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+
+ //check return value of dvmInterpHandleFillArrayData, if zero, throw exception
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
+ conditional_jump(Condition_NE, ".fill_array_data_done", true);
+ //jump to dvmJitToExceptionThrown
+ scratchRegs[0] = PhysicalReg_SCRATCH_2;
+ jumpToExceptionThrown(2/*exception number*/);
+ insertLabel(".fill_array_data_done", true);
+ rPC += 3;
+ return 0;
+}
+#undef P_GPR_1
+
+#define P_GPR_1 PhysicalReg_EBX
+//! LOWER bytecode THROW
+
+//!
+int op_throw() {
+ u2 vA = INST_AA(inst);
+ export_pc();
+ get_virtual_reg(vA, OpndSize_32, 1, false);
+ //null check
+ compare_imm_reg(OpndSize_32, 0, 1, false);
+ conditional_jump(Condition_E, "common_errNullObject", false);
+ //set glue->exception & throw exception
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
+ set_exception(1, false);
+ unconditional_jump("common_exceptionThrown", false);
+ rPC += 1;
+ return 0;
+}
+#undef P_GPR_1
+#define P_GPR_1 PhysicalReg_EBX
+//! LOWER bytecode THROW_VERIFICATION_ERROR
+
+//! op AA, ref@BBBB
+int op_throw_verification_error() {
+ u2 vA, vB;
+ vA = INST_AA(inst);
+ vB = FETCH(1);
+
+ export_pc();
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ get_glue_method(1, false);
+
+ load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, vB, 8, PhysicalReg_ESP, true);
+ move_imm_to_mem(OpndSize_32, vA, 4, PhysicalReg_ESP, true);
+ move_reg_to_mem(OpndSize_32, 1, false, 0, PhysicalReg_ESP, true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_2;
+ call_dvmThrowVerificationError();
+ load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
+
+ unconditional_jump("common_exceptionThrown", false);
+ rPC += 2;
+ return 0;
+}
+#undef P_GPR_1
diff --git a/vm/compiler/codegen/x86/LowerReturn.cpp b/vm/compiler/codegen/x86/LowerReturn.cpp
new file mode 100644
index 0000000..928c05c
--- /dev/null
+++ b/vm/compiler/codegen/x86/LowerReturn.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*! \file LowerReturn.cpp
+ \brief This file lowers the following bytecodes: RETURN
+
+*/
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexFile.h"
+#include "mterp/Mterp.h"
+#include "Lower.h"
+#include "enc_wrapper.h"
+#include "NcgHelper.h"
+
+//4 GPRs and scratch registers used in get_self_pointer, set_glue_method and set_glue_dvmdex
+//will jump to "gotoBail" if caller method is NULL or if debugger is active
+//what is %edx for each case? for the latter case, it is 1
+#define P_GPR_1 PhysicalReg_ECX //must be ecx
+#define P_GPR_2 PhysicalReg_EBX
+#define P_SCRATCH_1 PhysicalReg_EDX
+#define P_OLD_FP PhysicalReg_EAX
+/*!
+\brief common section to return from a method
+
+If the helper switch is on, this will generate a helper function
+*/
+int common_returnFromMethod() {
+#if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
+ insertMapWorklist(offsetPC, mapFromBCtoNCG[offsetPC], 1); //check when helper switch is on
+#endif
+
+ scratchRegs[0] = PhysicalReg_SCRATCH_7;
+ get_self_pointer(2, false);
+
+ //update rFP to caller stack frame
+ move_reg_to_reg(OpndSize_32, PhysicalReg_FP, true, 10, false);
+ move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_prevFrame, PhysicalReg_FP, true, PhysicalReg_FP, true); //update rFP
+ //get caller method by accessing the stack save area
+ move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_method, PhysicalReg_FP, true, 6, false);
+ compare_imm_reg(OpndSize_32, 0, 6, false);
+ conditional_jump(Condition_E, "common_gotoBail_0", false);
+ get_self_pointer(3, false);
+ //update glue->method
+ move_reg_to_mem(OpndSize_32, 6, false, offsetof(Thread, interpSave.method), 2, false);
+ //get clazz of caller method
+ move_mem_to_reg(OpndSize_32, offMethod_clazz, 6, false, 14, false);
+ //update self->frame
+ move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offThread_curFrame, 3, false);
+ //get method->clazz->pDvmDex
+ move_mem_to_reg(OpndSize_32, offClassObject_pDvmDex, 14, false, 7, false);
+ move_reg_to_mem(OpndSize_32, 7, false, offsetof(Thread, interpSave.methodClassDex), 2, false);
+
+ compare_imm_mem(OpndSize_32, 0, offsetof(Thread, suspendCount), 2, false); /* suspendCount */
+ move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_returnAddr, 10, false, PhysicalReg_EBX, true);
+ move_imm_to_reg(OpndSize_32, 0, 17, false);
+ /* if suspendCount is not zero, clear the chaining cell address */
+ conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 17, false/*src*/, PhysicalReg_EBX, true/*dst*/);
+ move_mem_to_reg(OpndSize_32, -sizeofStackSaveArea+offStackSaveArea_savedPc, 10, false, PhysicalReg_EAX, true);
+ //if returnAddr is not NULL, the thread is still in code cache
+ move_reg_to_mem(OpndSize_32, PhysicalReg_EBX, true, offThread_inJitCodeCache, 3, false);
+
+ insertLabel(".LreturnToInterp", true); //local label
+ //move rPC by 6 (3 bytecode units for INVOKE)
+ alu_binary_imm_reg(OpndSize_32, add_opc, 6, PhysicalReg_EAX, true);
+
+ //returnAddr in %ebx, if not zero, jump to returnAddr
+ compare_imm_reg(OpndSize_32, 0, PhysicalReg_EBX, true);
+ conditional_jump(Condition_E, ".LcontinueToInterp", true);
+#ifdef DEBUG_CALL_STACK3
+ move_reg_to_reg(OpndSize_32, PhysicalReg_EBX, true, PhysicalReg_ESI, true);
+ move_imm_to_reg(OpndSize_32, 0xaabb, PhysicalReg_EBX, true);
+ scratchRegs[0] = PhysicalReg_EAX;
+ call_debug_dumpSwitch(); //%ebx, %eax, %edx
+ move_reg_to_reg(OpndSize_32, PhysicalReg_ESI, true, PhysicalReg_EBX, true);
+ call_debug_dumpSwitch();
+ move_reg_to_reg(OpndSize_32, PhysicalReg_ESI, true, PhysicalReg_EBX, true);
+#endif
+ unconditional_jump_reg(PhysicalReg_EBX, true);
+ insertLabel(".LcontinueToInterp", true);
+ scratchRegs[0] = PhysicalReg_SCRATCH_4;
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = dvmJitToInterpNoChainNoProfile; //%eax is the input
+ move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
+
+ unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
+ touchEax();
+ return 0;
+}
+#undef P_GPR_1
+#undef P_GPR_2
+#undef P_SCRATCH_1
+
+//! lower bytecode RETURN_VOID
+
+//! It seems that shared code cache does not support helper switch
+int op_return_void() {
+ int retval;
+ retval = common_returnFromMethod();
+ rPC += 1;
+ return retval;
+}
+
+//! lower bytecode RETURN
+
+//! It seems that shared code cache does not support helper switch
+//! The return value is stored to glue->retval first
+int op_return() {
+ u2 vA = INST_AA(inst);
+
+ get_virtual_reg(vA, OpndSize_32, 22, false);
+ scratchRegs[0] = PhysicalReg_SCRATCH_1;
+ set_return_value(OpndSize_32, 22, false);
+
+ common_returnFromMethod();
+ rPC += 1;
+ return 0;
+}
+
+//! lower bytecode RETURN_WIDE
+
+//! It seems that shared code cache does not support helper switch
+//! The return value is stored to glue->retval first
+int op_return_wide() {
+ u2 vA = INST_AA(inst);
+ get_virtual_reg(vA, OpndSize_64, 1, false);
+ scratchRegs[0] = PhysicalReg_SCRATCH_10; scratchRegs[1] = PhysicalReg_Null;
+ scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
+ set_return_value(OpndSize_64, 1, false);
+
+ common_returnFromMethod();
+ rPC += 1;
+ return 0;
+}
diff --git a/vm/compiler/codegen/x86/NcgAot.cpp b/vm/compiler/codegen/x86/NcgAot.cpp
new file mode 100644
index 0000000..7c29b6d
--- /dev/null
+++ b/vm/compiler/codegen/x86/NcgAot.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "Lower.h"
+#include "NcgAot.h"
+#include "NcgHelper.h"
+
+//returns # of ops generated by this function
+//entries relocatable: eip + relativePC
+int get_eip_API() {
+ call("ncgGetEIP");//%edx //will push eip to stack
+ return 1;
+}
+#define NEW_EXPORT_PC
+//!update current PC in the stack frame with %eip
+
+//!
+int export_pc() {
+ /* for trace-based JIT, pc points to bytecode
+ for NCG, pc points to native code */
+ move_imm_to_mem(OpndSize_32, (int)rPC,
+ -sizeofStackSaveArea+offStackSaveArea_localRefTop, PhysicalReg_FP, true);
+ return 1; //return number of ops
+}
+
+/* jump from JIT'ed code to interpreter without chaining */
+int jumpToInterpNoChain() {
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = dvmJitToInterpNoChain;
+ move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
+
+ unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
+ if(gDvm.executionMode == kExecutionModeNcgO1) touchEax();
+ return 0;
+}
+
+/* jump from JIT'ed code to interpreter becaues of exception */
+int jumpToInterpPunt() {
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = dvmJitToInterpPunt;
+ move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
+
+ unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
+ //if(gDvm.executionMode == kExecutionModeNcgO1) touchEax();
+ return 0;
+}
+
+/* jump to common_exceptionThrown from JIT'ed code */
+int jumpToExceptionThrown(int exceptionNum) {
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ rememberState(exceptionNum);
+ export_pc();
+ constVREndOfBB();
+ beforeCall("exception"); //dump GG, GL VRs
+ }
+
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = dvmJitToExceptionThrown;
+ move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
+ unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
+
+ if(gDvm.executionMode == kExecutionModeNcgO1) {
+ goToState(exceptionNum);
+ }
+ return 0;
+}
+
+//! generate native code to call dvmNcgInvokeInterpreter
+
+//!the interpreter will start execution from %eax
+int invokeInterpreter(bool fromApp)
+{
+ typedef void (*vmHelper)(int);
+ vmHelper funcPtr = dvmNcgInvokeInterpreter;
+
+ move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
+
+ unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
+ if(gDvm.executionMode == kExecutionModeNcgO1) touchEax();
+ return 0;
+}
+
+//!work to do before calling a function pointer with code cache enabled
+
+//!
+void callFuncPtr(int funcPtr, const char* funcName) {
+
+ move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
+ call_reg(C_SCRATCH_1, isScratchPhysical);
+}
+//.const_string_resolve: input in %eax, output in %eax
+//.const_string_helper:
+//.class_resolve: input in %eax, output in %eax
+int call_helper_API(const char* helperName) {
+ call(helperName);
+ return 1;
+}
+
+/* check whether we are throwing an exception */
+bool jumpToException(const char* target) {
+ bool isException = false;
+ if(!strncmp(target, "common_err", 10)) isException = true;
+ if(!strncmp(target, "common_throw", 12)) isException = true;
+ if(!strncmp(target, "common_exception", 16)) isException = true;
+ return isException;
+}
+
+int conditional_jump_global_API(
+ ConditionCode cc, const char* target,
+ bool isShortTerm) {
+ if(jumpToException(target) && currentExceptionBlockIdx >= 0) { //jump to the exceptionThrow block
+ condJumpToBasicBlock(stream, cc, currentExceptionBlockIdx);
+ return 1; //return number of ops
+ }
+ conditional_jump(cc, target, isShortTerm);
+ return 1;
+}
+int unconditional_jump_global_API(
+ const char* target, bool isShortTerm) {
+ if(jumpToException(target) && currentExceptionBlockIdx >= 0) { //jump to the exceptionThrow block
+ jumpToBasicBlock(stream, currentExceptionBlockIdx);
+ return 1; //return number of ops
+ }
+ unconditional_jump(target, isShortTerm);
+ return 1;
+}
+int getGlobalDataAddr(const char* dataName) {
+ int dataAddr = -1;
+ if(!strcmp(dataName, "doubNeg")) dataAddr = LdoubNeg;
+ else if(!strcmp(dataName, "intMax")) dataAddr = LintMax;
+ else if(!strcmp(dataName, "intMin")) dataAddr = LintMin;
+ else if(!strcmp(dataName, "valueNanLong")) dataAddr = LvalueNanLong;
+ else if(!strcmp(dataName, "valuePosInfLong")) dataAddr = LvaluePosInfLong;
+ else if(!strcmp(dataName, "valueNegInfLong")) dataAddr = LvalueNegInfLong;
+ else if(!strcmp(dataName, "shiftMask")) dataAddr = LshiftMask;
+ else if(!strcmp(dataName, "value64")) dataAddr = Lvalue64;
+ else if(!strcmp(dataName, "64bits")) dataAddr = L64bits;
+ else if(!strcmp(dataName, "strClassCastExceptionPtr")) dataAddr = LstrClassCastExceptionPtr;
+ else if(!strcmp(dataName, "strInstantiationError")) dataAddr = LstrInstantiationErrorPtr;
+ else if(!strcmp(dataName, "gDvmInlineOpsTable")) dataAddr = (int)gDvmInlineOpsTable;
+ else ALOGE("global data %s not supported", dataName);
+ return dataAddr;
+}
+
+//for shared code cache, we use scratchRegs[0] & [1]
+int load_imm_global_data_API(const char* dataName,
+ OpndSize size,
+ int reg, bool isPhysical) {
+
+ //find the address from name
+ int dataAddr = getGlobalDataAddr(dataName);
+ move_imm_to_reg(size, dataAddr, reg, isPhysical);
+ return 0;
+}
+//for shared code cache, we use scratchRegs[0] & [1] & [2]
+//FIXME: [2] is assumed to be hard-coded register
+int load_global_data_API(const char* dataName,
+ OpndSize size,
+ int reg, bool isPhysical) {
+
+ //find the address from name
+ int dataAddr = getGlobalDataAddr(dataName);
+ move_mem_to_reg(size, dataAddr, PhysicalReg_Null, true, reg, isPhysical);
+ return 0;
+}
+int load_sd_global_data_API(const char* dataName,
+ int reg, bool isPhysical) {
+
+ //find the address from name
+ int dataAddr = getGlobalDataAddr(dataName);
+ move_sd_mem_to_reg(dataAddr, PhysicalReg_Null, true, reg, isPhysical);
+ return 0;
+}
+
+int load_fp_stack_global_data_API(const char* dataName,
+ OpndSize size) {
+
+ int dataAddr = getGlobalDataAddr(dataName);
+ load_int_fp_stack_imm(size, dataAddr); //fildl
+ return 0;
+}
diff --git a/vm/compiler/codegen/x86/NcgAot.h b/vm/compiler/codegen/x86/NcgAot.h
new file mode 100644
index 0000000..99bcc13
--- /dev/null
+++ b/vm/compiler/codegen/x86/NcgAot.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+#ifndef _DALVIK_NCG_AOT
+#define _DALVIK_NCG_AOT
+int ncgAppGetEIP();
+int get_eip_API();
+int invokeInterpreter(bool fromApp);
+int invokeNcg(bool fromApp);
+int jumpToInterpNoChain();
+int jumpToInterpPunt();
+int jumpToExceptionThrown(int exceptionNum);
+void callFuncPtr(int funcPtr, const char* funcName);
+int call_helper_API(const char* helperName);
+int conditional_jump_global_API(
+ ConditionCode cc, const char* target,
+ bool isShortTerm);
+int unconditional_jump_global_API(
+ const char* target, bool isShortTerm);
+int load_imm_global_data_API(const char* dataName,
+ OpndSize size,
+ int reg, bool isPhysical);
+int load_global_data_API(const char* dataName,
+ OpndSize size,
+ int reg, bool isPhysical);
+int load_sd_global_data_API(const char* dataName,
+ int reg, bool isPhysical);
+int load_fp_stack_global_data_API(const char* dataName,
+ OpndSize size);
+#endif
+
diff --git a/vm/compiler/codegen/x86/NcgHelper.cpp b/vm/compiler/codegen/x86/NcgHelper.cpp
new file mode 100644
index 0000000..f9192db
--- /dev/null
+++ b/vm/compiler/codegen/x86/NcgHelper.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "Dalvik.h"
+#include "NcgHelper.h"
+#include "interp/InterpDefs.h"
+
+
+/*
+ * Find the matching case. Returns the offset to the handler instructions.
+ *
+ * Returns 3 if we don't find a match (it's the size of the packed-switch
+ * instruction).
+ */
+s4 dvmNcgHandlePackedSwitch(const s4* entries, s4 firstKey, u2 size, s4 testVal)
+{
+ //skip add_reg_reg (ADD_REG_REG_SIZE) and jump_reg (JUMP_REG_SIZE)
+ const int kInstrLen = 4; //default to next bytecode
+ if (testVal < firstKey || testVal >= firstKey + size) {
+ LOGVV("Value %d not found in switch (%d-%d)",
+ testVal, firstKey, firstKey+size-1);
+ return kInstrLen;
+ }
+
+ assert(testVal - firstKey >= 0 && testVal - firstKey < size);
+ LOGVV("Value %d found in slot %d (goto 0x%02x)",
+ testVal, testVal - firstKey,
+ s4FromSwitchData(&entries[testVal - firstKey]));
+ return s4FromSwitchData(&entries[testVal - firstKey]);
+
+}
+/* return the number of bytes to increase the bytecode pointer by */
+s4 dvmJitHandlePackedSwitch(const s4* entries, s4 firstKey, u2 size, s4 testVal)
+{
+ if (testVal < firstKey || testVal >= firstKey + size) {
+ LOGVV("Value %d not found in switch (%d-%d)",
+ testVal, firstKey, firstKey+size-1);
+ return 2*3;//bytecode packed_switch is 6(2*3) bytes long
+ }
+
+ LOGVV("Value %d found in slot %d (goto 0x%02x)",
+ testVal, testVal - firstKey,
+ s4FromSwitchData(&entries[testVal - firstKey]));
+ return 2*s4FromSwitchData(&entries[testVal - firstKey]); //convert from u2 to byte
+
+}
+/*
+ * Find the matching case. Returns the offset to the handler instructions.
+ *
+ * Returns 3 if we don't find a match (it's the size of the sparse-switch
+ * instruction).
+ */
+s4 dvmNcgHandleSparseSwitch(const s4* keys, u2 size, s4 testVal)
+{
+ const int kInstrLen = 4; //CHECK
+ const s4* entries = keys + size;
+ int i;
+ for (i = 0; i < size; i++) {
+ s4 k = s4FromSwitchData(&keys[i]);
+ if (k == testVal) {
+ LOGVV("Value %d found in entry %d (goto 0x%02x)",
+ testVal, i, s4FromSwitchData(&entries[i]));
+ return s4FromSwitchData(&entries[i]);
+ } else if (k > testVal) {
+ break;
+ }
+ }
+
+ LOGVV("Value %d not found in switch", testVal);
+ return kInstrLen;
+}
+/* return the number of bytes to increase the bytecode pointer by */
+s4 dvmJitHandleSparseSwitch(const s4* keys, u2 size, s4 testVal)
+{
+ const s4* entries = keys + size;
+ int i;
+ for (i = 0; i < size; i++) {
+ s4 k = s4FromSwitchData(&keys[i]);
+ if (k == testVal) {
+ LOGVV("Value %d found in entry %d (goto 0x%02x)",
+ testVal, i, s4FromSwitchData(&entries[i]));
+ return 2*s4FromSwitchData(&entries[i]); //convert from u2 to byte
+ } else if (k > testVal) {
+ break;
+ }
+ }
+
+ LOGVV("Value %d not found in switch", testVal);
+ return 2*3; //bytecode sparse_switch is 6(2*3) bytes long
+}
+/*
+ * Look up an interface on a class using the cache.
+ */
+/*INLINE*/ Method* dvmFindInterfaceMethodInCache2(ClassObject* thisClass,
+ u4 methodIdx, const Method* method, DvmDex* methodClassDex)
+{
+#define ATOMIC_CACHE_CALC \
+ dvmInterpFindInterfaceMethod(thisClass, methodIdx, method, methodClassDex)
+
+ return (Method*) ATOMIC_CACHE_LOOKUP(methodClassDex->pInterfaceCache,
+ DEX_INTERFACE_CACHE_SIZE, thisClass, methodIdx);
+
+#undef ATOMIC_CACHE_CALC
+}
diff --git a/vm/compiler/codegen/x86/NcgHelper.h b/vm/compiler/codegen/x86/NcgHelper.h
new file mode 100644
index 0000000..888cb61
--- /dev/null
+++ b/vm/compiler/codegen/x86/NcgHelper.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef _DALVIK_NCG_HELPER
+#define _DALVIK_NCG_HELPER
+#include "mterp/Mterp.h"
+s4 dvmNcgHandlePackedSwitch(const s4*, s4, u2, s4);
+s4 dvmNcgHandleSparseSwitch(const s4*, u2, s4);
+s4 dvmJitHandlePackedSwitch(const s4*, s4, u2, s4);
+s4 dvmJitHandleSparseSwitch(const s4*, u2, s4);
+/*
+ * Look up an interface on a class using the cache.
+ */
+Method* dvmFindInterfaceMethodInCache2(ClassObject* thisClass,
+ u4 methodIdx, const Method* method, DvmDex* methodClassDex);
+/*
+ * Find an interface method.
+ */
+#if 0
+bool dvmNcgStdRun(MterpGlue* glue);
+#endif
+extern "C" void dvmNcgInvokeInterpreter(int pc); //interpreter to execute at pc
+extern "C" void dvmNcgInvokeNcg(int pc);
+extern "C" void dvmJitToInterpNormal(int targetpc); //in %ebx
+extern "C" void dvmJitToInterpTraceSelect(int targetpc); //in %ebx
+extern "C" void dvmJitToInterpTraceSelectNoChain(int targetpc); //in %ebx
+extern "C" void dvmJitToInterpNoChain(int targetpc); //in %eax
+extern "C" void dvmJitToInterpNoChainNoProfile(int targetpc); //in %eax
+extern "C" void dvmJitToInterpPunt(int targetpc); //in currentPc
+extern "C" void dvmJitToExceptionThrown(int targetpc); //in currentPc
+#ifdef DEBUG_CALL_STACK3
+void debug_dumpSwitch(int); //in %ebx
+#endif
+
+const Method *dvmJitToPatchPredictedChain(const Method *method,
+ Thread *self,
+ PredictedChainingCell *cell,
+ const ClassObject *clazz);
+#endif /*_DALVIK_NCG_HELPER*/
diff --git a/vm/compiler/codegen/x86/Translator.h b/vm/compiler/codegen/x86/Translator.h
new file mode 100644
index 0000000..0d7ef32
--- /dev/null
+++ b/vm/compiler/codegen/x86/Translator.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+#ifndef _DALVIK_TRANSLATOR
+#define _DALVIK_TRANSLATOR
+
+#include "Dalvik.h"
+#include "enc_wrapper.h"
+
+/* initialization for trace-based JIT */
+void initJIT(const char* curFileName, DvmDex *pDvmDex);
+
+#endif
diff --git a/vm/compiler/codegen/x86/X86LIR.h b/vm/compiler/codegen/x86/X86LIR.h
deleted file mode 100644
index 863aeab..0000000
--- a/vm/compiler/codegen/x86/X86LIR.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DALVIK_VM_COMPILER_CODEGEN_X86_X86LIR_H_
-#define DALVIK_VM_COMPILER_CODEGEN_X86_X86LIR_H_
-
-#include "Dalvik.h"
-#include "compiler/CompilerInternals.h"
-
-/*
- * For both JIT & interpreter:
- * esi is Dalvik FP
- * ebp is native FP
- * esp is native SP
- *
- * For interpreter:
- * edi is Dalvik PC (rPC)
- * ebx is rINST
- *
- * For JIT:
- * eax, edx, ecx are scratch & caller-save
- * ebx, edi are scratch & callee-save
- *
- * Calling conventions:
- * 32-bit return in eax
- * 64-bit return in edx:eax
- * fp on top of fp stack st(0)
- * Parameters passed on stack, pushed left to right
- * On entry to target, first parm is at 4(%esp).
- * For performance, we'll maintain 16-byte stack alignment
- *
- * When transitioning from code cache to interp:
- * materialize Dalvik PC of target in rPC/%edx
- * Preload rINST/%ebx such that high 24 bits are zero and
- * bl contains the non-opcode 8-bits of the 16-bit Dalvik
- * instruction at (rPC)
- */
-
-/* Keys for target-specific scheduling and other optimizations here */
-typedef enum X86TargetOptHints {
- kMaxHoistDistance,
-} X86TargetOptHints;
-
- /*
- * Data structure tracking the mapping between a Dalvik register (pair) and a
- * native register (pair). The idea is to reuse the previously loaded value
- * if possible, otherwise to keep the value in a native register as long as
- * possible.
- */
-typedef struct RegisterInfo {
- int reg; // Reg number
- bool inUse; // Has it been allocated?
- bool pair; // Part of a register pair?
- int partner; // If pair, other reg of pair
- bool live; // Is there an associated SSA name?
- bool dirty; // If live, is it dirty?
- int sReg; // Name of live value
- struct LIR *defStart; // Starting inst in last def sequence
- struct LIR *defEnd; // Ending inst in last def sequence
-} RegisterInfo;
-
-typedef struct RegisterPool {
- BitVector *nullCheckedRegs; // Track which registers have been null-checked
- int numCoreTemps;
- RegisterInfo *coreTemps;
- int nextCoreTemp;
- int numFPTemps;
- RegisterInfo *FPTemps;
- int nextFPTemp;
-} RegisterPool;
-
-typedef enum OpSize {
- kWord,
- kLong,
- kSingle,
- kDouble,
- kUnsignedHalf,
- kSignedHalf,
- kUnsignedByte,
- kSignedByte,
-} OpSize;
-
-typedef enum OpKind {
- kOpMov,
- kOpCmp,
- kOpLsl,
- kOpLsr,
- kOpAsr,
- kOpRor,
- kOpNot,
- kOpAnd,
- kOpOr,
- kOpXor,
- kOpNeg,
- kOpAdd,
- kOpAdc,
- kOpSub,
- kOpSbc,
- kOpMul,
- kOpDiv,
- kOpRem,
- kOpTst,
- kOpCall,
- kOpPush,
- kOpPop,
- kOp2Char,
- kOp2Short,
- kOp2Byte,
- kOpCondBr,
- kOpUncondBr,
-} OpKind;
-
-#define FP_REG_OFFSET 8
-
-typedef enum NativeRegisterPool {
- rEAX = 0,
- rECX = 1,
- rEDX = 2,
- rEBX = 3,
- rESP = 4,
- rEBP = 5,
- rESI = 6,
- rEDI = 7,
- rXMM0 = 0 + FP_REG_OFFSET,
- rXMM1 = 1 + FP_REG_OFFSET,
- rXMM2 = 2 + FP_REG_OFFSET,
- rXMM3 = 3 + FP_REG_OFFSET,
- rXMM4 = 4 + FP_REG_OFFSET,
- rXMM5 = 5 + FP_REG_OFFSET,
- rXMM6 = 6 + FP_REG_OFFSET,
- rXMM7 = 7 + FP_REG_OFFSET,
-} NativeRegisterPool;
-
-#define rPC rEDI
-#define rFP rESI
-#define rINST rEBX
-
-#define OUT_ARG0 0
-#define OUT_ARG1 4
-#define OUT_ARG2 8
-#define OUT_ARG3 12
-#define OUT_ARG4 16
-
-typedef struct X86LIR {
- LIR generic;
- //X86Opcode opcode;
- int operands[4]; // [0..3] = [dest, src1, src2, extra]
- bool isNop; // LIR is optimized away
- bool branchInsertSV;// mark for insertion of branch before this instruction,
- // used to identify mem ops for self verification mode
- int age; // default is 0, set lazily by the optimizer
- int aliasInfo; // For Dalvik register access & litpool disambiguation
- u8 useMask; // Resource mask for use
- u8 defMask; // Resource mask for def
-} X86LIR;
-
-/* Utility macros to traverse the LIR/X86LIR list */
-#define NEXT_LIR(lir) ((X86LIR *) lir->generic.next)
-#define PREV_LIR(lir) ((X86LIR *) lir->generic.prev)
-
-#define NEXT_LIR_LVALUE(lir) (lir)->generic.next
-#define PREV_LIR_LVALUE(lir) (lir)->generic.prev
-
-#define CHAIN_CELL_OFFSET_TAG 0xcdab
-
-#define CHAIN_CELL_NORMAL_SIZE 12
-#define CHAIN_CELL_PREDICTED_SIZE 16
-
-#endif // DALVIK_VM_COMPILER_CODEGEN_X86_X86LIR_H_
diff --git a/vm/compiler/codegen/x86/ia32/ArchVariant.cpp b/vm/compiler/codegen/x86/ia32/ArchVariant.cpp
deleted file mode 100644
index ff97d95..0000000
--- a/vm/compiler/codegen/x86/ia32/ArchVariant.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-extern "C" void dvmCompilerTemplateStart(void);
-
-/*
- * This file is included by Codegen-x86.c, and implements architecture
- * variant-specific code.
- */
-
-/*
- * Determine the initial instruction set to be used for this trace.
- * Later components may decide to change this.
- */
-JitInstructionSetType dvmCompilerInstructionSet(void)
-{
- return DALVIK_JIT_IA32;
-}
-
-/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
-#define JIT_TEMPLATE(X) extern "C" void dvmCompiler_TEMPLATE_##X();
-#include "../../../template/ia32/TemplateOpList.h"
-#undef JIT_TEMPLATE
-
-/* Architecture-specific initializations and checks go here */
-bool dvmCompilerArchVariantInit(void)
-{
- int i = 0;
-
- /*
- * Then, populate the templateEntryOffsets array with the offsets from the
- * the dvmCompilerTemplateStart symbol for each template.
- */
-#define JIT_TEMPLATE(X) templateEntryOffsets[i++] = \
- (intptr_t) dvmCompiler_TEMPLATE_##X - (intptr_t) dvmCompilerTemplateStart;
-#include "../../../template/ia32/TemplateOpList.h"
-#undef JIT_TEMPLATE
-
- /* Target-specific configuration */
- gDvmJit.jitTableSize = 1 << 9; // 512
- gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
- gDvmJit.threshold = 200;
- gDvmJit.codeCacheSize = 512*1024;
-
-#if defined(WITH_SELF_VERIFICATION)
- /* Force into blocking mode */
- gDvmJit.blockingMode = true;
- gDvm.nativeDebuggerActive = true;
-#endif
-
- /* Codegen-specific assumptions */
- assert(OFFSETOF_MEMBER(ClassObject, vtable) < 128 &&
- (OFFSETOF_MEMBER(ClassObject, vtable) & 0x3) == 0);
- assert(OFFSETOF_MEMBER(ArrayObject, length) < 128 &&
- (OFFSETOF_MEMBER(ArrayObject, length) & 0x3) == 0);
- assert(OFFSETOF_MEMBER(ArrayObject, contents) < 256);
-
- /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
- assert(sizeof(StackSaveArea) < 236);
-
- /*
- * EA is calculated by doing "Rn + imm5 << 2", make sure that the last
- * offset from the struct is less than 128.
- */
- assert((offsetof(Thread, jitToInterpEntries) +
- sizeof(struct JitToInterpEntries)) <= 128);
-
- // Make sure all threads have current values
- dvmJitUpdateThreadStateAll();
- return true;
-}
-
-int dvmCompilerTargetOptHint(int key)
-{
- int res;
- switch (key) {
- case kMaxHoistDistance:
- res = 2;
- break;
- default:
- ALOGE("Unknown target optimization hint key: %d",key);
- res = 0;
- }
- return res;
-}
-
-void dvmCompilerGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
-{
-}
diff --git a/vm/compiler/codegen/x86/ia32/ArchVariant.h b/vm/compiler/codegen/x86/ia32/ArchVariant.h
deleted file mode 100644
index f1c21d3..0000000
--- a/vm/compiler/codegen/x86/ia32/ArchVariant.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DALVIK_VM_COMPILER_CODEGEN_X86_IA32_ARCHVARIANT_H_
-#define DALVIK_VM_COMPILER_CODEGEN_X86_IA32_ARCHVARIANT_H_
-
-/* Create the TemplateOpcode enum */
-#define JIT_TEMPLATE(X) TEMPLATE_##X,
-enum TemplateOpcode {
-#include "../../../template/ia32/TemplateOpList.h"
-/*
- * For example,
- * TEMPLATE_CMP_LONG,
- * TEMPLATE_RETURN,
- * ...
- */
- TEMPLATE_LAST_MARK,
-};
-#undef JIT_TEMPLATE
-
-#endif // DALVIK_VM_COMPILER_CODEGEN_X86_IA32_ARCHVARIANT_H_
diff --git a/vm/compiler/codegen/x86/ia32/CallingConvention.S b/vm/compiler/codegen/x86/ia32/CallingConvention.S
deleted file mode 100644
index cc4187a..0000000
--- a/vm/compiler/codegen/x86/ia32/CallingConvention.S
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Save & restore for callee-save FP registers.
- * On entry:
- * tos : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
- */
- .text
- .align 2
- .global dvmJitCalleeSave
- .type dvmJitCalleeSave, %function
-dvmJitCalleeSave:
- ret
-
- .global dvmJitCalleeRestore
- .type dvmJitCalleeRestore, %function
-dvmJitCalleeRestore:
- ret
diff --git a/vm/compiler/codegen/x86/ia32/Codegen.cpp b/vm/compiler/codegen/x86/ia32/Codegen.cpp
deleted file mode 100644
index ae55cd1..0000000
--- a/vm/compiler/codegen/x86/ia32/Codegen.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _CODEGEN_C
-#define _IA32
-
-#include "Dalvik.h"
-#include "interp/InterpDefs.h"
-#include "libdex/DexOpcodes.h"
-#include "compiler/CompilerInternals.h"
-#include "compiler/codegen/x86/X86LIR.h"
-#include "mterp/common/FindInterface.h"
-//#include "compiler/codegen/x86/Ralloc.h"
-#include "compiler/codegen/x86/Codegen.h"
-#include "compiler/Loop.h"
-#include "ArchVariant.h"
-
-/* Architectural independent building blocks */
-//#include "../CodegenCommon.cpp"
-
-/* Architectural independent building blocks */
-//#include "../Thumb/Factory.cpp"
-/* Factory utilities dependent on arch-specific features */
-//#include "../CodegenFactory.cpp"
-
-/* ia32 register allocation */
-//#include "../ia32/Ralloc.cpp"
-
-/* MIR2LIR dispatcher and architectural independent codegen routines */
-#include "../CodegenDriver.cpp"
-
-/* Architecture manifest */
-#include "ArchVariant.cpp"
diff --git a/vm/compiler/codegen/x86/libenc/Android.mk b/vm/compiler/codegen/x86/libenc/Android.mk
new file mode 100644
index 0000000..6fe9cdb
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/Android.mk
@@ -0,0 +1,65 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Only include the x86 encoder/decoder for x86 architecture
+ifeq ($(TARGET_ARCH),x86)
+
+LOCAL_PATH:= $(call my-dir)
+
+ifneq ($(LIBENC_INCLUDED),true)
+
+LIBENC_INCLUDED := true
+
+enc_src_files := \
+ enc_base.cpp \
+ dec_base.cpp \
+ enc_wrapper.cpp \
+ enc_tabl.cpp
+
+enc_include_files :=
+
+##
+##
+## Build the device version of libenc
+##
+##
+ifneq ($(SDK_ONLY),true) # SDK_only doesn't need device version
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(enc_src_files)
+LOCAL_C_INCLUDES += $(enc_include_files)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libenc
+include $(BUILD_STATIC_LIBRARY)
+
+endif # !SDK_ONLY
+
+
+##
+##
+## Build the host version of libenc
+##
+##
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(enc_src_files)
+LOCAL_C_INCLUDES += $(enc_include_files)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libenc
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+endif # ifneq ($(LIBENC_INCLUDED),true)
+
+endif # ifeq ($(TARGET_ARCH),x86)
diff --git a/vm/compiler/codegen/x86/libenc/README.txt b/vm/compiler/codegen/x86/libenc/README.txt
new file mode 100644
index 0000000..30df760
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/README.txt
@@ -0,0 +1,26 @@
+Original source from Apache Harmony 5.0M15 (r991518 from 2010-09-01) at
+http://harmony.apache.org/.
+
+The following files are from drlvm/vm/port/src/encoder/ia32_em64t.
+
+ dec_base.cpp
+ dec_base.h
+ enc_base.cpp
+ enc_base.h
+ enc_defs.h
+ enc_prvt.h
+ enc_tabl.cpp
+ encoder.cpp
+ encoder.h
+ encoder.inl
+
+The following files are derived partially from the original Apache
+Harmony files.
+
+ enc_defs_ext.h -- derived from enc_defs.h
+ enc_wrapper.h -- derived from encoder.h
+
+
+
+
+
diff --git a/vm/compiler/codegen/x86/libenc/dec_base.cpp b/vm/compiler/codegen/x86/libenc/dec_base.cpp
new file mode 100644
index 0000000..e0edc10
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/dec_base.cpp
@@ -0,0 +1,540 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+
+/**
+ * @file
+ * @brief Main decoding (disassembling) routines implementation.
+ */
+
+#include "dec_base.h"
+#include "enc_prvt.h"
+#include <stdio.h>
+//#include "open/common.h"
+
+bool DecoderBase::is_prefix(const unsigned char * bytes)
+{
+ unsigned char b0 = *bytes;
+ unsigned char b1 = *(bytes+1);
+ if (b0 == 0xF0) { // LOCK
+ return true;
+ }
+ if (b0==0xF2 || b0==0xF3) { // REPNZ/REPZ prefixes
+ if (b1 == 0x0F) { // .... but may be a part of SIMD opcode
+ return false;
+ }
+ return true;
+ }
+ if (b0 == 0x2E || b0 == 0x36 || b0==0x3E || b0==0x26 || b0==0x64 || b0==0x3E) {
+ // branch hints, segment prefixes
+ return true;
+ }
+ if (b0==0x66) { // operand-size prefix
+ if (b1 == 0x0F) { // .... but may be a part of SIMD opcode
+ return false;
+ }
+ return false; //XXX - currently considered as part of opcode//true;
+ }
+ if (b0==0x67) { // address size prefix
+ return true;
+ }
+ return false;
+}
+
+// Returns prefix count from 0 to 4, or ((unsigned int)-1) on error
+unsigned int DecoderBase::fill_prefs(const unsigned char * bytes, Inst * pinst)
+{
+ const unsigned char * my_bytes = bytes;
+
+ while( 1 )
+ {
+ unsigned char by1 = *my_bytes;
+ unsigned char by2 = *(my_bytes + 1);
+ Inst::PrefGroups where;
+
+ switch( by1 )
+ {
+ case InstPrefix_REPNE:
+ case InstPrefix_REP:
+ {
+ if( 0x0F == by2)
+ {
+ return pinst->prefc;
+ }
+ }
+ case InstPrefix_LOCK:
+ {
+ where = Inst::Group1;
+ break;
+ }
+ case InstPrefix_CS:
+ case InstPrefix_SS:
+ case InstPrefix_DS:
+ case InstPrefix_ES:
+ case InstPrefix_FS:
+ case InstPrefix_GS:
+// case InstPrefix_HintTaken: the same as CS override
+// case InstPrefix_HintNotTaken: the same as DS override
+ {
+ where = Inst::Group2;
+ break;
+ }
+ case InstPrefix_OpndSize:
+ {
+//NOTE: prefix does not work for JMP Sz16, the opcode is 0x66 0xe9
+// here 0x66 will be treated as prefix, try_mn will try to match the code starting at 0xe9
+// it will match JMP Sz32 ...
+//HACK: assume it is the last prefix, return any way
+ if( 0x0F == by2)
+ {
+ return pinst->prefc;
+ }
+ return pinst->prefc;
+ where = Inst::Group3;
+ break;
+ }
+ case InstPrefix_AddrSize:
+ {
+ where = Inst::Group4;
+ break;
+ }
+ default:
+ {
+ return pinst->prefc;
+ }
+ }
+ // Assertions are not allowed here.
+ // Error situations should result in returning error status
+ if (InstPrefix_Null != pinst->pref[where]) //only one prefix in each group
+ return (unsigned int)-1;
+
+ pinst->pref[where] = (InstPrefix)by1;
+
+ if (pinst->prefc >= 4) //no more than 4 prefixes
+ return (unsigned int)-1;
+
+ pinst->prefc++;
+ ++my_bytes;
+ }
+}
+
+
+
+unsigned DecoderBase::decode(const void * addr, Inst * pinst)
+{
+ Inst tmp;
+
+ //assert( *(unsigned char*)addr != 0x66);
+
+ const unsigned char * bytes = (unsigned char*)addr;
+
+ // Load up to 4 prefixes
+ // for each Mnemonic
+ unsigned int pref_count = fill_prefs(bytes, &tmp);
+
+ if (pref_count == (unsigned int)-1) // Wrong prefix sequence, or >4 prefixes
+ return 0; // Error
+
+ bytes += pref_count;
+
+ // for each opcodedesc
+ // if (raw_len == 0) memcmp(, raw_len)
+ // else check the mixed state which is one of the following:
+ // /digit /i /rw /rd /rb
+
+ bool found = false;
+ const unsigned char * saveBytes = bytes;
+ for (unsigned mn=1; mn<Mnemonic_Count; mn++) {
+ bytes = saveBytes;
+ found=try_mn((Mnemonic)mn, &bytes, &tmp);
+ if (found) {
+ tmp.mn = (Mnemonic)mn;
+ break;
+ }
+ }
+ if (!found) {
+ // Unknown opcode
+ return 0;
+ }
+ tmp.size = (unsigned)(bytes-(const unsigned char*)addr);
+ if (pinst) {
+ *pinst = tmp;
+ }
+ return tmp.size;
+}
+
+#ifdef _EM64T_
+#define EXTEND_REG(reg, flag) \
+ ((NULL == rex || 0 == rex->flag) ? reg : (reg + 8))
+#else
+#define EXTEND_REG(reg, flag) (reg)
+#endif
+
+//don't know the use of rex, seems not used when _EM64T_ is not enabled
+bool DecoderBase::decode_aux(const EncoderBase::OpcodeDesc& odesc, unsigned aux,
+ const unsigned char ** pbuf, Inst * pinst
+#ifdef _EM64T_
+ , const Rex UNREF *rex
+#endif
+ )
+{
+ OpcodeByteKind kind = (OpcodeByteKind)(aux & OpcodeByteKind_KindMask);
+ unsigned byte = (aux & OpcodeByteKind_OpcodeMask);
+ unsigned data_byte = **pbuf;
+ EncoderBase::Operand& opnd = pinst->operands[pinst->argc];
+ const EncoderBase::OpndDesc& opndDesc = odesc.opnds[pinst->argc];
+
+ switch (kind) {
+ case OpcodeByteKind_SlashR:
+ {
+ RegName reg;
+ OpndKind okind;
+ const ModRM& modrm = *(ModRM*)*pbuf;
+ if (opndDesc.kind & OpndKind_Mem) { // 1st operand is memory
+#ifdef _EM64T_
+ decodeModRM(odesc, pbuf, pinst, rex);
+#else
+ decodeModRM(odesc, pbuf, pinst);
+#endif
+ ++pinst->argc;
+ const EncoderBase::OpndDesc& opndDesc2 = odesc.opnds[pinst->argc];
+ okind = ((opndDesc2.kind & OpndKind_XMMReg) || opndDesc2.size==OpndSize_64) ? OpndKind_XMMReg : OpndKind_GPReg;
+ EncoderBase::Operand& regOpnd = pinst->operands[pinst->argc];
+ reg = getRegName(okind, opndDesc2.size, EXTEND_REG(modrm.reg, r));
+ regOpnd = EncoderBase::Operand(reg);
+ } else { // 2nd operand is memory
+ okind = ((opndDesc.kind & OpndKind_XMMReg) || opndDesc.size==OpndSize_64) ? OpndKind_XMMReg : OpndKind_GPReg;
+ EncoderBase::Operand& regOpnd = pinst->operands[pinst->argc];
+ reg = getRegName(okind, opndDesc.size, EXTEND_REG(modrm.reg, r));
+ regOpnd = EncoderBase::Operand(reg);
+ ++pinst->argc;
+#ifdef _EM64T_
+ decodeModRM(odesc, pbuf, pinst, rex);
+#else
+ decodeModRM(odesc, pbuf, pinst);
+#endif
+ }
+ ++pinst->argc;
+ }
+ return true;
+ case OpcodeByteKind_rb:
+ case OpcodeByteKind_rw:
+ case OpcodeByteKind_rd:
+ {
+ // Gregory -
+ // Here we don't parse register because for current needs
+ // disassembler doesn't require to parse all operands
+ unsigned regid = data_byte - byte;
+ if (regid>7) {
+ return false;
+ }
+ OpndSize opnd_size;
+ switch(kind)
+ {
+ case OpcodeByteKind_rb:
+ {
+ opnd_size = OpndSize_8;
+ break;
+ }
+ case OpcodeByteKind_rw:
+ {
+ opnd_size = OpndSize_16;
+ break;
+ }
+ case OpcodeByteKind_rd:
+ {
+ opnd_size = OpndSize_32;
+ break;
+ }
+ default:
+ opnd_size = OpndSize_32; // so there is no compiler warning
+ assert( false );
+ }
+ opnd = EncoderBase::Operand( getRegName(OpndKind_GPReg, opnd_size, regid) );
+
+ ++pinst->argc;
+ ++*pbuf;
+ return true;
+ }
+ case OpcodeByteKind_cb:
+ {
+ char offset = *(char*)*pbuf;
+ *pbuf += 1;
+ opnd = EncoderBase::Operand(offset);
+ ++pinst->argc;
+ //pinst->direct_addr = (void*)(pinst->offset + *pbuf);
+ }
+ return true;
+ case OpcodeByteKind_cw:
+ // not an error, but not expected in current env
+ // Android x86
+ {
+ short offset = *(short*)*pbuf;
+ *pbuf += 2;
+ opnd = EncoderBase::Operand(offset);
+ ++pinst->argc;
+ }
+ return true;
+ //return false;
+ case OpcodeByteKind_cd:
+ {
+ int offset = *(int*)*pbuf;
+ *pbuf += 4;
+ opnd = EncoderBase::Operand(offset);
+ ++pinst->argc;
+ }
+ return true;
+ case OpcodeByteKind_SlashNum:
+ {
+ const ModRM& modrm = *(ModRM*)*pbuf;
+ if (modrm.reg != byte) {
+ return false;
+ }
+ decodeModRM(odesc, pbuf, pinst
+#ifdef _EM64T_
+ , rex
+#endif
+ );
+ ++pinst->argc;
+ }
+ return true;
+ case OpcodeByteKind_ib:
+ {
+ char ival = *(char*)*pbuf;
+ opnd = EncoderBase::Operand(ival);
+ ++pinst->argc;
+ *pbuf += 1;
+ }
+ return true;
+ case OpcodeByteKind_iw:
+ {
+ short ival = *(short*)*pbuf;
+ opnd = EncoderBase::Operand(ival);
+ ++pinst->argc;
+ *pbuf += 2;
+ }
+ return true;
+ case OpcodeByteKind_id:
+ {
+ int ival = *(int*)*pbuf;
+ opnd = EncoderBase::Operand(ival);
+ ++pinst->argc;
+ *pbuf += 4;
+ }
+ return true;
+#ifdef _EM64T_
+ case OpcodeByteKind_io:
+ {
+ long long int ival = *(long long int*)*pbuf;
+ opnd = EncoderBase::Operand(OpndSize_64, ival);
+ ++pinst->argc;
+ *pbuf += 8;
+ }
+ return true;
+#endif
+ case OpcodeByteKind_plus_i:
+ {
+ unsigned regid = data_byte - byte;
+ if (regid>7) {
+ return false;
+ }
+ ++*pbuf;
+ return true;
+ }
+ case OpcodeByteKind_ZeroOpcodeByte: // cant be here
+ return false;
+ default:
+ // unknown kind ? how comes ?
+ break;
+ }
+ return false;
+}
+
+bool DecoderBase::try_mn(Mnemonic mn, const unsigned char ** pbuf, Inst * pinst) {
+ const unsigned char * save_pbuf = *pbuf;
+ EncoderBase::OpcodeDesc * opcodes = EncoderBase::opcodes[mn];
+
+ for (unsigned i=0; !opcodes[i].last; i++) {
+ const EncoderBase::OpcodeDesc& odesc = opcodes[i];
+ char *opcode_ptr = const_cast<char *>(odesc.opcode);
+ int opcode_len = odesc.opcode_len;
+#ifdef _EM64T_
+ Rex *prex = NULL;
+ Rex rex;
+#endif
+
+ *pbuf = save_pbuf;
+#ifdef _EM64T_
+ // Match REX prefixes
+ unsigned char rex_byte = (*pbuf)[0];
+ if ((rex_byte & 0xf0) == 0x40)
+ {
+ if ((rex_byte & 0x08) != 0)
+ {
+ // Have REX.W
+ if (opcode_len > 0 && opcode_ptr[0] == 0x48)
+ {
+ // Have REX.W in opcode. All mnemonics that allow
+ // REX.W have to have specified it in opcode,
+ // otherwise it is not allowed
+ rex = *(Rex *)*pbuf;
+ prex = &rex;
+ (*pbuf)++;
+ opcode_ptr++;
+ opcode_len--;
+ }
+ }
+ else
+ {
+ // No REX.W, so it doesn't have to be in opcode. We
+ // have REX.B, REX.X, REX.R or their combination, but
+ // not in opcode, they may extend any part of the
+ // instruction
+ rex = *(Rex *)*pbuf;
+ prex = &rex;
+ (*pbuf)++;
+ }
+ }
+#endif
+ if (opcode_len != 0) {
+ if (memcmp(*pbuf, opcode_ptr, opcode_len)) {
+ continue;
+ }
+ *pbuf += opcode_len;
+ }
+ if (odesc.aux0 != 0) {
+
+ if (!decode_aux(odesc, odesc.aux0, pbuf, pinst
+#ifdef _EM64T_
+ , prex
+#endif
+ )) {
+ continue;
+ }
+ if (odesc.aux1 != 0) {
+ if (!decode_aux(odesc, odesc.aux1, pbuf, pinst
+#ifdef _EM64T_
+ , prex
+#endif
+ )) {
+ continue;
+ }
+ }
+ pinst->odesc = &opcodes[i];
+ return true;
+ }
+ else {
+ // Can't have empty opcode
+ assert(opcode_len != 0);
+ pinst->odesc = &opcodes[i];
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DecoderBase::decodeModRM(const EncoderBase::OpcodeDesc& odesc,
+ const unsigned char ** pbuf, Inst * pinst
+#ifdef _EM64T_
+ , const Rex *rex
+#endif
+ )
+{
+ EncoderBase::Operand& opnd = pinst->operands[pinst->argc];
+ const EncoderBase::OpndDesc& opndDesc = odesc.opnds[pinst->argc];
+
+ //XXX debug ///assert(0x66 != *(*pbuf-2));
+ const ModRM& modrm = *(ModRM*)*pbuf;
+ *pbuf += 1;
+
+ RegName base = RegName_Null;
+ RegName index = RegName_Null;
+ int disp = 0;
+ unsigned scale = 0;
+
+ // On x86_64 all mnemonics that allow REX.W have REX.W in opcode.
+ // Therefore REX.W is simply ignored, and opndDesc.size is used
+
+ if (modrm.mod == 3) {
+ // we have only modrm. no sib, no disp.
+ // Android x86: Use XMMReg for 64b operand.
+ OpndKind okind = ((opndDesc.kind & OpndKind_XMMReg) || opndDesc.size == OpndSize_64) ? OpndKind_XMMReg : OpndKind_GPReg;
+ RegName reg = getRegName(okind, opndDesc.size, EXTEND_REG(modrm.rm, b));
+ opnd = EncoderBase::Operand(reg);
+ return true;
+ }
+ //Android x86: m16, m32, m64: mean a byte[word|doubleword] operand in memory
+ //base and index should be 32 bits!!!
+ const SIB& sib = *(SIB*)*pbuf;
+ // check whether we have a sib
+ if (modrm.rm == 4) {
+ // yes, we have SIB
+ *pbuf += 1;
+ // scale = sib.scale == 0 ? 0 : (1<<sib.scale);
+ scale = (1<<sib.scale);
+ if (sib.index != 4) {
+ index = getRegName(OpndKind_GPReg, OpndSize_32, EXTEND_REG(sib.index, x)); //Android x86: OpndDesc.size
+ } else {
+ // (sib.index == 4) => no index
+ //%esp can't be sib.index
+ }
+
+ if (sib.base != 5 || modrm.mod != 0) {
+ base = getRegName(OpndKind_GPReg, OpndSize_32, EXTEND_REG(sib.base, b)); //Android x86: OpndDesc.size
+ } else {
+ // (sib.base == 5 && modrm.mod == 0) => no base
+ }
+ }
+ else {
+ if (modrm.mod != 0 || modrm.rm != 5) {
+ base = getRegName(OpndKind_GPReg, OpndSize_32, EXTEND_REG(modrm.rm, b)); //Android x86: OpndDesc.size
+ }
+ else {
+ // mod=0 && rm == 5 => only disp32
+ }
+ }
+
+ //update disp and pbuf
+ if (modrm.mod == 2) {
+ // have disp32
+ disp = *(int*)*pbuf;
+ *pbuf += 4;
+ }
+ else if (modrm.mod == 1) {
+ // have disp8
+ disp = *(char*)*pbuf;
+ *pbuf += 1;
+ }
+ else {
+ assert(modrm.mod == 0);
+ if (modrm.rm == 5) {
+ // have disp32 w/o sib
+ disp = *(int*)*pbuf;
+ *pbuf += 4;
+ }
+ else if (modrm.rm == 4 && sib.base == 5) {
+ // have disp32 with SI in sib
+ disp = *(int*)*pbuf;
+ *pbuf += 4;
+ }
+ }
+ opnd = EncoderBase::Operand(opndDesc.size, base, index, scale, disp);
+ return true;
+}
+
diff --git a/vm/compiler/codegen/x86/libenc/dec_base.h b/vm/compiler/codegen/x86/libenc/dec_base.h
new file mode 100644
index 0000000..909c743
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/dec_base.h
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+
+/**
+ * @file
+ * @brief Main decoding (disassembling) routines and structures.
+ *
+ * @note Quick and rough implementation, subject for a change.
+ */
+
+#ifndef __DEC_BASE_H_INCLUDED__
+#define __DEC_BASE_H_INCLUDED__
+
+
+#include "enc_base.h"
+#include "enc_prvt.h"
+
+#ifdef ENCODER_ISOLATE
+using namespace enc_ia32;
+#endif
+
+#define IF_CONDITIONAL (0x00000000)
+#define IF_SYMMETRIC (0x00000000)
+#define IF_BRANCH (0x00000000)
+
+struct Inst {
+ Inst() {
+ mn = Mnemonic_Null;
+ prefc = 0;
+ size = 0;
+ flags = 0;
+ //offset = 0;
+ //direct_addr = NULL;
+ argc = 0;
+ for(int i = 0; i < 4; ++i)
+ {
+ pref[i] = InstPrefix_Null;
+ }
+ }
+ /**
+ * Mnemonic of the instruction.s
+ */
+ Mnemonic mn;
+ /**
+ * Enumerating of indexes in the pref array.
+ */
+ enum PrefGroups
+ {
+ Group1 = 0,
+ Group2,
+ Group3,
+ Group4
+ };
+ /**
+ * Number of prefixes (1 byte each).
+ */
+ unsigned int prefc;
+ /**
+ * Instruction prefixes. Prefix should be placed here according to its group.
+ */
+ InstPrefix pref[4];
+ /**
+ * Size, in bytes, of the instruction.
+ */
+ unsigned size;
+ /**
+ * Flags of the instruction.
+ * @see MF_
+ */
+ unsigned flags;
+ /**
+ * An offset of target address, in case of 'CALL offset',
+ * 'JMP/Jcc offset'.
+ */
+ //int offset;
+ /**
+ * Direct address of the target (on Intel64/IA-32 is 'instruction IP' +
+ * 'instruction length' + offset).
+ */
+ //void * direct_addr;
+ /**
+ * Number of arguments of the instruction.
+ */
+ unsigned argc;
+ //
+ EncoderBase::Operand operands[3];
+ //
+ const EncoderBase::OpcodeDesc * odesc;
+};
+
+inline bool is_jcc(Mnemonic mn)
+{
+ return Mnemonic_JO <= mn && mn<=Mnemonic_JG;
+}
+
+class DecoderBase {
+public:
+ static unsigned decode(const void * addr, Inst * pinst);
+private:
+ static bool decodeModRM(const EncoderBase::OpcodeDesc& odesc,
+ const unsigned char ** pbuf, Inst * pinst
+#ifdef _EM64T_
+ , const Rex *rex
+#endif
+ );
+ static bool decode_aux(const EncoderBase::OpcodeDesc& odesc,
+ unsigned aux, const unsigned char ** pbuf,
+ Inst * pinst
+#ifdef _EM64T_
+ , const Rex *rex
+#endif
+ );
+ static bool try_mn(Mnemonic mn, const unsigned char ** pbuf, Inst * pinst);
+ static unsigned int fill_prefs( const unsigned char * bytes, Inst * pinst);
+ static bool is_prefix(const unsigned char * bytes);
+};
+
+#endif // ~ __DEC_BASE_H_INCLUDED__
+
diff --git a/vm/compiler/codegen/x86/libenc/enc_base.cpp b/vm/compiler/codegen/x86/libenc/enc_base.cpp
new file mode 100644
index 0000000..d141e1f
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/enc_base.cpp
@@ -0,0 +1,1153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+#include "enc_base.h"
+//#include <climits>
+#include <string.h>
+#define USE_ENCODER_DEFINES
+#include "enc_prvt.h"
+#include <stdio.h>
+
+//#define JET_PROTO
+
+#ifdef JET_PROTO
+#include "dec_base.h"
+#include "jvmti_dasm.h"
+#endif
+
+ENCODER_NAMESPACE_START
+
+/**
+ * @file
+ * @brief Main encoding routines and structures.
+ */
+
+#ifndef _WIN32
+ #define strcmpi strcasecmp
+#endif
+
+int EncoderBase::dummy = EncoderBase::buildTable();
+
+const unsigned char EncoderBase::size_hash[OpndSize_64+1] = {
+ //
+ 0xFF, // OpndSize_Null = 0,
+ 3, // OpndSize_8 = 0x1,
+ 2, // OpndSize_16 = 0x2,
+ 0xFF, // 0x3
+ 1, // OpndSize_32 = 0x4,
+ 0xFF, // 0x5
+ 0xFF, // 0x6
+ 0xFF, // 0x7
+ 0, // OpndSize_64 = 0x8,
+ //
+};
+
+const unsigned char EncoderBase::kind_hash[OpndKind_Mem+1] = {
+ //
+ //gp reg -> 000 = 0
+ //memory -> 001 = 1
+ //immediate -> 010 = 2
+ //xmm reg -> 011 = 3
+ //segment regs -> 100 = 4
+ //fp reg -> 101 = 5
+ //mmx reg -> 110 = 6
+ //
+ 0xFF, // 0 OpndKind_Null=0,
+ 0<<2, // 1 OpndKind_GPReg =
+ // OpndKind_MinRegKind=0x1,
+ 4<<2, // 2 OpndKind_SReg=0x2,
+
+#ifdef _HAVE_MMX_
+ 6<<2, // 3
+#else
+ 0xFF, // 3
+#endif
+
+ 5<<2, // 4 OpndKind_FPReg=0x4,
+ 0xFF, 0xFF, 0xFF, // 5, 6, 7
+ 3<<2, // OpndKind_XMMReg=0x8,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9, 0xA, 0xB, 0xC, 0xD,
+ // 0xE, 0xF
+ 0xFF, // OpndKind_MaxRegKind =
+ // OpndKind_StatusReg =
+ // OpndKind_OtherReg=0x10,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x11-0x18
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x19-0x1F
+ 2<<2, // OpndKind_Immediate=0x20,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x21-0x28
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x29-0x30
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x31-0x38
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x39-0x3F
+ 1<<2, // OpndKind_Memory=0x40
+};
+
+char * EncoderBase::curRelOpnd[3];
+
+char* EncoderBase::encode_aux(char* stream, unsigned aux,
+ const Operands& opnds, const OpcodeDesc * odesc,
+ unsigned * pargsCount, Rex * prex)
+{
+ const unsigned byte = aux;
+ OpcodeByteKind kind = (OpcodeByteKind)(byte & OpcodeByteKind_KindMask);
+ // The '>>' here is to force the switch to be table-based) instead of
+ // set of CMP+Jcc.
+ if (*pargsCount >= COUNTOF(opnds)) {
+ assert(false);
+ return stream;
+ }
+ switch(kind>>8) {
+ case OpcodeByteKind_SlashR>>8:
+ // /r - Indicates that the ModR/M byte of the instruction contains
+ // both a register operand and an r/m operand.
+ {
+ assert(opnds.count() > 1);
+ // not true anymore for MOVQ xmm<->r
+ //assert((odesc->opnds[0].kind & OpndKind_Mem) ||
+ // (odesc->opnds[1].kind & OpndKind_Mem));
+ unsigned memidx = odesc->opnds[0].kind & OpndKind_Mem ? 0 : 1;
+ unsigned regidx = memidx == 0 ? 1 : 0;
+ memidx += *pargsCount;
+ regidx += *pargsCount;
+ ModRM& modrm = *(ModRM*)stream;
+ if (memidx >= COUNTOF(opnds) || regidx >= COUNTOF(opnds)) {
+ assert(false);
+ break;
+ }
+ if (opnds[memidx].is_mem()) {
+ stream = encodeModRM(stream, opnds, memidx, odesc, prex);
+ }
+ else {
+ modrm.mod = 3; // 11
+ modrm.rm = getHWRegIndex(opnds[memidx].reg());
+#ifdef _EM64T_
+ if (opnds[memidx].need_rex() && needs_rex_r(opnds[memidx].reg())) {
+ prex->b = 1;
+ }
+#endif
+ ++stream;
+ }
+ modrm.reg = getHWRegIndex(opnds[regidx].reg());
+#ifdef _EM64T_
+ if (opnds[regidx].need_rex() && needs_rex_r(opnds[regidx].reg())) {
+ prex->r = 1;
+ }
+#endif
+ *pargsCount += 2;
+ }
+ break;
+ case OpcodeByteKind_SlashNum>>8:
+ // /digit - A digit between 0 and 7 indicates that the
+ // ModR/M byte of the instruction uses only the r/m
+ // (register or memory) operand. The reg field contains
+ // the digit that provides an extension to the instruction's
+ // opcode.
+ {
+ const unsigned lowByte = (byte & OpcodeByteKind_OpcodeMask);
+ assert(lowByte <= 7);
+ ModRM& modrm = *(ModRM*)stream;
+ unsigned idx = *pargsCount;
+ assert(opnds[idx].is_mem() || opnds[idx].is_reg());
+ if (opnds[idx].is_mem()) {
+ stream = encodeModRM(stream, opnds, idx, odesc, prex);
+ }
+ else {
+ modrm.mod = 3; // 11
+ modrm.rm = getHWRegIndex(opnds[idx].reg());
+#ifdef _EM64T_
+ if (opnds[idx].need_rex() && needs_rex_r(opnds[idx].reg())) {
+ prex->b = 1;
+ }
+#endif
+ ++stream;
+ }
+ modrm.reg = (char)lowByte;
+ *pargsCount += 1;
+ }
+ break;
+ case OpcodeByteKind_plus_i>>8:
+ // +i - A number used in floating-point instructions when one
+ // of the operands is ST(i) from the FPU register stack. The
+ // number i (which can range from 0 to 7) is added to the
+ // hexadecimal byte given at the left of the plus sign to form
+ // a single opcode byte.
+ {
+ unsigned idx = *pargsCount;
+ const unsigned lowByte = (byte & OpcodeByteKind_OpcodeMask);
+ *stream = (char)lowByte + getHWRegIndex(opnds[idx].reg());
+ ++stream;
+ *pargsCount += 1;
+ }
+ break;
+ case OpcodeByteKind_ib>>8:
+ case OpcodeByteKind_iw>>8:
+ case OpcodeByteKind_id>>8:
+#ifdef _EM64T_
+ case OpcodeByteKind_io>>8:
+#endif //_EM64T_
+ // ib, iw, id - A 1-byte (ib), 2-byte (iw), or 4-byte (id)
+ // immediate operand to the instruction that follows the
+ // opcode, ModR/M bytes or scale-indexing bytes. The opcode
+ // determines if the operand is a signed value. All words
+ // and double words are given with the low-order byte first.
+ {
+ unsigned idx = *pargsCount;
+ *pargsCount += 1;
+ assert(opnds[idx].is_imm());
+ if (kind == OpcodeByteKind_ib) {
+ *(unsigned char*)stream = (unsigned char)opnds[idx].imm();
+ curRelOpnd[idx] = stream;
+ stream += 1;
+ }
+ else if (kind == OpcodeByteKind_iw) {
+ *(unsigned short*)stream = (unsigned short)opnds[idx].imm();
+ curRelOpnd[idx] = stream;
+ stream += 2;
+ }
+ else if (kind == OpcodeByteKind_id) {
+ *(unsigned*)stream = (unsigned)opnds[idx].imm();
+ curRelOpnd[idx] = stream;
+ stream += 4;
+ }
+#ifdef _EM64T_
+ else {
+ assert(kind == OpcodeByteKind_io);
+ *(long long*)stream = (long long)opnds[idx].imm();
+ curRelOpnd[idx] = stream;
+ stream += 8;
+ }
+#else
+ else {
+ assert(false);
+ }
+#endif
+ }
+ break;
+ case OpcodeByteKind_cb>>8:
+ assert(opnds[*pargsCount].is_imm());
+ *(unsigned char*)stream = (unsigned char)opnds[*pargsCount].imm();
+ curRelOpnd[*pargsCount]= stream;
+ stream += 1;
+ *pargsCount += 1;
+ break;
+ case OpcodeByteKind_cw>>8:
+ assert(opnds[*pargsCount].is_imm());
+ *(unsigned short*)stream = (unsigned short)opnds[*pargsCount].imm();
+ curRelOpnd[*pargsCount]= stream;
+ stream += 2;
+ *pargsCount += 1;
+ break;
+ case OpcodeByteKind_cd>>8:
+ assert(opnds[*pargsCount].is_imm());
+ *(unsigned*)stream = (unsigned)opnds[*pargsCount].imm();
+ curRelOpnd[*pargsCount]= stream;
+ stream += 4;
+ *pargsCount += 1;
+ break;
+ //OpcodeByteKind_cp = 0x0B00,
+ //OpcodeByteKind_co = 0x0C00,
+ //OpcodeByteKind_ct = 0x0D00,
+ case OpcodeByteKind_rb>>8:
+ case OpcodeByteKind_rw>>8:
+ case OpcodeByteKind_rd>>8:
+ // +rb, +rw, +rd - A register code, from 0 through 7,
+ // added to the hexadecimal byte given at the left of
+ // the plus sign to form a single opcode byte.
+ assert(opnds.count() > 0);
+ assert(opnds[*pargsCount].is_reg());
+ {
+ const unsigned lowByte = (byte & OpcodeByteKind_OpcodeMask);
+ *(unsigned char*)stream = (unsigned char)lowByte +
+ getHWRegIndex(opnds[*pargsCount].reg());
+#ifdef _EM64T_
+ if (opnds[*pargsCount].need_rex() && needs_rex_r(opnds[*pargsCount].reg())) {
+ prex->b = 1;
+ }
+#endif
+ ++stream;
+ *pargsCount += 1;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ return stream;
+}
+
+char * EncoderBase::encode(char * stream, Mnemonic mn, const Operands& opnds)
+{
+#ifdef _DEBUG
+ if (opnds.count() > 0) {
+ if (opnds[0].is_mem()) {
+ assert(getRegKind(opnds[0].base()) != OpndKind_SReg);
+ }
+ else if (opnds.count() >1 && opnds[1].is_mem()) {
+ assert(getRegKind(opnds[1].base()) != OpndKind_SReg);
+ }
+ }
+#endif
+
+#ifdef JET_PROTO
+ char* saveStream = stream;
+#endif
+
+ const OpcodeDesc * odesc = lookup(mn, opnds);
+#if !defined(_EM64T_)
+ bool copy_opcode = true;
+ Rex *prex = NULL;
+#else
+ // We need rex if
+ // either of registers used as operand or address form is new extended register
+ // it's explicitly specified by opcode
+ // So, if we don't have REX in opcode but need_rex, then set rex here
+ // otherwise, wait until opcode is set, and then update REX
+
+ bool copy_opcode = true;
+ unsigned char _1st = odesc->opcode[0];
+
+ Rex *prex = (Rex*)stream;
+ if (opnds.need_rex() &&
+ ((_1st == 0x66) || (_1st == 0xF2 || _1st == 0xF3) && odesc->opcode[1] == 0x0F)) {
+ // Special processing
+ //
+ copy_opcode = false;
+ //
+ *(unsigned char*)stream = _1st;
+ ++stream;
+ //
+ prex = (Rex*)stream;
+ prex->dummy = 4;
+ prex->w = 0;
+ prex->b = 0;
+ prex->x = 0;
+ prex->r = 0;
+ ++stream;
+ //
+ memcpy(stream, &odesc->opcode[1], odesc->opcode_len-1);
+ stream += odesc->opcode_len-1;
+ }
+ else if (_1st != 0x48 && opnds.need_rex()) {
+ prex = (Rex*)stream;
+ prex->dummy = 4;
+ prex->w = 0;
+ prex->b = 0;
+ prex->x = 0;
+ prex->r = 0;
+ ++stream;
+ }
+#endif // ifndef EM64T
+
+ if (copy_opcode) {
+ if (odesc->opcode_len==1) {
+ *(unsigned char*)stream = *(unsigned char*)&odesc->opcode;
+ }
+ else if (odesc->opcode_len==2) {
+ *(unsigned short*)stream = *(unsigned short*)&odesc->opcode;
+ }
+ else if (odesc->opcode_len==3) {
+ *(unsigned short*)stream = *(unsigned short*)&odesc->opcode;
+ *(unsigned char*)(stream+2) = odesc->opcode[2];
+ }
+ else if (odesc->opcode_len==4) {
+ *(unsigned*)stream = *(unsigned*)&odesc->opcode;
+ }
+ stream += odesc->opcode_len;
+ }
+
+ unsigned argsCount = odesc->first_opnd;
+
+ if (odesc->aux0) {
+ stream = encode_aux(stream, odesc->aux0, opnds, odesc, &argsCount, prex);
+ if (odesc->aux1) {
+ stream = encode_aux(stream, odesc->aux1, opnds, odesc, &argsCount, prex);
+ }
+ }
+#ifdef JET_PROTO
+ //saveStream
+ Inst inst;
+ unsigned len = DecoderBase::decode(saveStream, &inst);
+ assert(inst.mn == mn);
+ assert(len == (unsigned)(stream-saveStream));
+ if (mn == Mnemonic_CALL || mn == Mnemonic_JMP ||
+ Mnemonic_RET == mn ||
+ (Mnemonic_JO<=mn && mn<=Mnemonic_JG)) {
+ assert(inst.argc == opnds.count());
+
+ InstructionDisassembler idi(saveStream);
+
+ for (unsigned i=0; i<inst.argc; i++) {
+ const EncoderBase::Operand& original = opnds[i];
+ const EncoderBase::Operand& decoded = inst.operands[i];
+ assert(original.kind() == decoded.kind());
+ assert(original.size() == decoded.size());
+ if (original.is_imm()) {
+ assert(original.imm() == decoded.imm());
+ assert(idi.get_opnd(0).kind == InstructionDisassembler::Kind_Imm);
+ if (mn == Mnemonic_CALL) {
+ assert(idi.get_type() == InstructionDisassembler::RELATIVE_CALL);
+ }
+ else if (mn == Mnemonic_JMP) {
+ assert(idi.get_type() == InstructionDisassembler::RELATIVE_JUMP);
+ }
+ else if (mn == Mnemonic_RET) {
+ assert(idi.get_type() == InstructionDisassembler::RET);
+ }
+ else {
+ assert(idi.get_type() == InstructionDisassembler::RELATIVE_COND_JUMP);
+ }
+ }
+ else if (original.is_mem()) {
+ assert(original.base() == decoded.base());
+ assert(original.index() == decoded.index());
+ assert(original.scale() == decoded.scale());
+ assert(original.disp() == decoded.disp());
+ assert(idi.get_opnd(0).kind == InstructionDisassembler::Kind_Mem);
+ if (mn == Mnemonic_CALL) {
+ assert(idi.get_type() == InstructionDisassembler::INDIRECT_CALL);
+ }
+ else if (mn == Mnemonic_JMP) {
+ assert(idi.get_type() == InstructionDisassembler::INDIRECT_JUMP);
+ }
+ else {
+ assert(false);
+ }
+ }
+ else {
+ assert(original.is_reg());
+ assert(original.reg() == decoded.reg());
+ assert(idi.get_opnd(0).kind == InstructionDisassembler::Kind_Reg);
+ if (mn == Mnemonic_CALL) {
+ assert(idi.get_type() == InstructionDisassembler::INDIRECT_CALL);
+ }
+ else if (mn == Mnemonic_JMP) {
+ assert(idi.get_type() == InstructionDisassembler::INDIRECT_JUMP);
+ }
+ else {
+ assert(false);
+ }
+ }
+ }
+
+ Inst inst2;
+ len = DecoderBase::decode(saveStream, &inst2);
+ }
+
+ // if(idi.get_length_with_prefix() != (int)len) {
+ //__asm { int 3 };
+ // }
+#endif
+
+ return stream;
+}
+
+char* EncoderBase::encodeModRM(char* stream, const Operands& opnds,
+ unsigned idx, const OpcodeDesc * odesc,
+ Rex * prex)
+{
+ const Operand& op = opnds[idx];
+ assert(op.is_mem());
+ assert(idx < COUNTOF(curRelOpnd));
+ ModRM& modrm = *(ModRM*)stream;
+ ++stream;
+ SIB& sib = *(SIB*)stream;
+
+ // we need SIB if
+ // we have index & scale (nb: having index w/o base and w/o scale
+ // treated as error)
+ // the base is EBP w/o disp, BUT let's use a fake disp8
+ // the base is ESP (nb: cant have ESP as index)
+
+ RegName base = op.base();
+ // only disp ?..
+ if (base == RegName_Null && op.index() == RegName_Null) {
+ assert(op.scale() == 0); // 'scale!=0' has no meaning without index
+ // ... yes - only have disp
+ // On EM64T, the simply [disp] addressing means 'RIP-based' one -
+ // must have to use SIB to encode 'DS: based'
+#ifdef _EM64T_
+ modrm.mod = 0; // 00 - ..
+ modrm.rm = 4; // 100 - have SIB
+
+ sib.base = 5; // 101 - none
+ sib.index = 4; // 100 - none
+ sib.scale = 0; //
+ ++stream; // bypass SIB
+#else
+ // ignore disp_fits8, always use disp32.
+ modrm.mod = 0;
+ modrm.rm = 5;
+#endif
+ *(unsigned*)stream = (unsigned)op.disp();
+ curRelOpnd[idx]= stream;
+ stream += 4;
+ return stream;
+ }
+
+ //climits: error when targeting compal
+#define CHAR_MIN -127
+#define CHAR_MAX 127
+ const bool disp_fits8 = CHAR_MIN <= op.disp() && op.disp() <= CHAR_MAX;
+ /*&& op.base() != RegName_Null - just checked above*/
+ if (op.index() == RegName_Null && getHWRegIndex(op.base()) != getHWRegIndex(REG_STACK)) {
+ assert(op.scale() == 0); // 'scale!=0' has no meaning without index
+ // ... luckily no SIB, only base and may be a disp
+
+ // EBP base is a special case. Need to use [EBP] + disp8 form
+ if (op.disp() == 0 && getHWRegIndex(op.base()) != getHWRegIndex(RegName_EBP)) {
+ modrm.mod = 0; // mod=00, no disp et all
+ }
+ else if (disp_fits8) {
+ modrm.mod = 1; // mod=01, use disp8
+ *(unsigned char*)stream = (unsigned char)op.disp();
+ curRelOpnd[idx]= stream;
+ ++stream;
+ }
+ else {
+ modrm.mod = 2; // mod=10, use disp32
+ *(unsigned*)stream = (unsigned)op.disp();
+ curRelOpnd[idx]= stream;
+ stream += 4;
+ }
+ modrm.rm = getHWRegIndex(op.base());
+ if (is_em64t_extra_reg(op.base())) {
+ prex->b = 1;
+ }
+ return stream;
+ }
+
+ // cool, we do have SIB.
+ ++stream; // bypass SIB in stream
+
+ // {E|R}SP cannot be scaled index, however, R12 which has the same index in modrm - can
+ assert(op.index() == RegName_Null || !equals(op.index(), REG_STACK));
+
+ // Only GPRegs can be encoded in the SIB
+ assert(op.base() == RegName_Null ||
+ getRegKind(op.base()) == OpndKind_GPReg);
+ assert(op.index() == RegName_Null ||
+ getRegKind(op.index()) == OpndKind_GPReg);
+
+ modrm.rm = 4; // r/m = 100, means 'we have SIB here'
+ if (op.base() == RegName_Null) {
+ // no base.
+ // already checked above if
+ // the first if() //assert(op.index() != RegName_Null);
+
+ modrm.mod = 0; // mod=00 - here it means 'no base, but disp32'
+ sib.base = 5; // 101 with mod=00 ^^^
+
+ // encode at least fake disp32 to avoid having [base=ebp]
+ *(unsigned*)stream = op.disp();
+ curRelOpnd[idx]= stream;
+ stream += 4;
+
+ unsigned sc = op.scale();
+ if (sc == 1 || sc==0) { sib.scale = 0; } // SS=00
+ else if (sc == 2) { sib.scale = 1; } // SS=01
+ else if (sc == 4) { sib.scale = 2; } // SS=10
+ else if (sc == 8) { sib.scale = 3; } // SS=11
+ sib.index = getHWRegIndex(op.index());
+ if (is_em64t_extra_reg(op.index())) {
+ prex->x = 1;
+ }
+
+ return stream;
+ }
+
+ if (op.disp() == 0 && getHWRegIndex(op.base()) != getHWRegIndex(RegName_EBP)) {
+ modrm.mod = 0; // mod=00, no disp
+ }
+ else if (disp_fits8) {
+ modrm.mod = 1; // mod=01, use disp8
+ *(unsigned char*)stream = (unsigned char)op.disp();
+ curRelOpnd[idx]= stream;
+ stream += 1;
+ }
+ else {
+ modrm.mod = 2; // mod=10, use disp32
+ *(unsigned*)stream = (unsigned)op.disp();
+ curRelOpnd[idx]= stream;
+ stream += 4;
+ }
+
+ if (op.index() == RegName_Null) {
+ assert(op.scale() == 0); // 'scale!=0' has no meaning without index
+ // the only reason we're here without index, is that we have {E|R}SP
+ // or R12 as a base. Another possible reason - EBP without a disp -
+ // is handled above by adding a fake disp8
+#ifdef _EM64T_
+ assert(op.base() != RegName_Null && (equals(op.base(), REG_STACK) ||
+ equals(op.base(), RegName_R12)));
+#else // _EM64T_
+ assert(op.base() != RegName_Null && equals(op.base(), REG_STACK));
+#endif //_EM64T_
+ sib.scale = 0; // SS = 00
+ sib.index = 4; // SS + index=100 means 'no index'
+ }
+ else {
+ unsigned sc = op.scale();
+ if (sc == 1 || sc==0) { sib.scale = 0; } // SS=00
+ else if (sc == 2) { sib.scale = 1; } // SS=01
+ else if (sc == 4) { sib.scale = 2; } // SS=10
+ else if (sc == 8) { sib.scale = 3; } // SS=11
+ sib.index = getHWRegIndex(op.index());
+ if (is_em64t_extra_reg(op.index())) {
+ prex->x = 1;
+ }
+ // not an error by itself, but the usage of [index*1] instead
+ // of [base] is discouraged
+ assert(op.base() != RegName_Null || op.scale() != 1);
+ }
+ sib.base = getHWRegIndex(op.base());
+ if (is_em64t_extra_reg(op.base())) {
+ prex->b = 1;
+ }
+ return stream;
+}
+
+char * EncoderBase::nops(char * stream, unsigned howMany)
+{
+ // Recommended multi-byte NOPs from the Intel architecture manual
+ static const unsigned char nops[10][9] = {
+ { 0, }, // 0, this line is dummy and not used in the loop below
+ { 0x90, }, // 1-byte NOP
+ { 0x66, 0x90, }, // 2
+ { 0x0F, 0x1F, 0x00, }, // 3
+ { 0x0F, 0x1F, 0x40, 0x00, }, // 4
+ { 0x0F, 0x1F, 0x44, 0x00, 0x00, }, // 5
+ { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00, }, // 6
+ { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00, }, // 7
+ { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 8
+ { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 9-byte NOP
+ };
+
+ // Start from delivering the longest possible NOPs, then proceed with shorter ones
+ for (unsigned nopSize=9; nopSize!=0; nopSize--) {
+ while(howMany>=nopSize) {
+ const unsigned char* nopBytes = nops[nopSize];
+ for (unsigned i=0; i<nopSize; i++) {
+ stream[i] = nopBytes[i];
+ }
+ stream += nopSize;
+ howMany -= nopSize;
+ }
+ }
+ char* end = stream + howMany;
+ return end;
+}
+
+char * EncoderBase::prefix(char* stream, InstPrefix pref)
+{
+ if (pref== InstPrefix_Null) {
+ // nothing to do
+ return stream;
+ }
+ *stream = (char)pref;
+ return stream + 1;
+}
+
+
+/**
+ *
+ */
+bool EncoderBase::extAllowed(OpndExt opndExt, OpndExt instExt) {
+ if (instExt == opndExt || instExt == OpndExt_Any || opndExt == OpndExt_Any) {
+ return true;
+ }
+//asm("int3");
+assert(0);
+ return false;
+}
+
+/**
+ *
+ */
+static bool match(const EncoderBase::OpcodeDesc& odesc,
+ const EncoderBase::Operands& opnds) {
+
+ assert(odesc.roles.count == opnds.count());
+
+ for(unsigned j = 0; j < odesc.roles.count; j++) {
+ const EncoderBase::OpndDesc& desc = odesc.opnds[j];
+ const EncoderBase::Operand& op = opnds[j];
+ // location must match exactly
+ if ((desc.kind & op.kind()) != op.kind()) {
+//assert(0);
+ return false;
+ }
+ // size must match exactly
+ if (desc.size != op.size()) {
+//assert(0);
+ return false;
+ }
+ // extentions should be consistent
+ if (!EncoderBase::extAllowed(op.ext(), desc.ext)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+static bool try_match(const EncoderBase::OpcodeDesc& odesc,
+ const EncoderBase::Operands& opnds, bool strict) {
+
+ assert(odesc.roles.count == opnds.count());
+
+ for(unsigned j=0; j<odesc.roles.count; j++) {
+ // - the location must match exactly
+ if ((odesc.opnds[j].kind & opnds[j].kind()) != opnds[j].kind()) {
+ return false;
+ }
+ if (strict) {
+ // the size must match exactly
+ if (odesc.opnds[j].size != opnds[j].size()) {
+ return false;
+ }
+ }
+ else {
+ // must match only for def operands, and dont care about use ones
+ // situations like 'mov r8, imm32/mov r32, imm8' so the
+ // destination operand defines the overall size
+ if (EncoderBase::getOpndRoles(odesc.roles, j) & OpndRole_Def) {
+ if (odesc.opnds[j].size != opnds[j].size()) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+//
+//Subhash implementaion - may be useful in case of many misses during fast
+//opcode lookup.
+//
+
+#ifdef ENCODER_USE_SUBHASH
+static unsigned subHash[32];
+
+static unsigned find(Mnemonic mn, unsigned hash)
+{
+ unsigned key = hash % COUNTOF(subHash);
+ unsigned pack = subHash[key];
+ unsigned _hash = pack & 0xFFFF;
+ if (_hash != hash) {
+ stat.miss(mn);
+ return EncoderBase::NOHASH;
+ }
+ unsigned _mn = (pack >> 24)&0xFF;
+ if (_mn != _mn) {
+ stat.miss(mn);
+ return EncoderBase::NOHASH;
+ }
+ unsigned idx = (pack >> 16) & 0xFF;
+ stat.hit(mn);
+ return idx;
+}
+
+static void put(Mnemonic mn, unsigned hash, unsigned idx)
+{
+ unsigned pack = hash | (idx<<16) | (mn << 24);
+ unsigned key = hash % COUNTOF(subHash);
+ subHash[key] = pack;
+}
+#endif
+
+const EncoderBase::OpcodeDesc *
+EncoderBase::lookup(Mnemonic mn, const Operands& opnds)
+{
+ const unsigned hash = opnds.hash();
+ unsigned opcodeIndex = opcodesHashMap[mn][hash];
+#ifdef ENCODER_USE_SUBHASH
+ if (opcodeIndex == NOHASH) {
+ opcodeIndex = find(mn, hash);
+ }
+#endif
+
+ if (opcodeIndex == NOHASH) {
+ // fast-path did no work. try to lookup sequentially
+ const OpcodeDesc * odesc = opcodes[mn];
+ int idx = -1;
+ bool found = false;
+ for (idx=0; !odesc[idx].last; idx++) {
+ const OpcodeDesc& opcode = odesc[idx];
+ if (opcode.platf == OpcodeInfo::decoder) {
+ continue;
+ }
+ if (opcode.roles.count != opnds.count()) {
+ continue;
+ }
+ if (try_match(opcode, opnds, true)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ for (idx=0; !odesc[idx].last; idx++) {
+ const OpcodeDesc& opcode = odesc[idx];
+ if (opcode.platf == OpcodeInfo::decoder) {
+ continue;
+ }
+ if (opcode.roles.count != opnds.count()) {
+ continue;
+ }
+ if (try_match(opcode, opnds, false)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ assert(found);
+ opcodeIndex = idx;
+#ifdef ENCODER_USE_SUBHASH
+ put(mn, hash, opcodeIndex);
+#endif
+ }
+ assert(opcodeIndex != NOHASH);
+ const OpcodeDesc * odesc = &opcodes[mn][opcodeIndex];
+ assert(!odesc->last);
+ assert(odesc->roles.count == opnds.count());
+ assert(odesc->platf != OpcodeInfo::decoder);
+#if !defined(_EM64T_)
+ // tuning was done for IA32 only, so no size restriction on EM64T
+ //assert(sizeof(OpcodeDesc)==128);
+#endif
+ return odesc;
+}
+
+char* EncoderBase::getOpndLocation(int index) {
+ assert(index < 3);
+ return curRelOpnd[index];
+}
+
+
+Mnemonic EncoderBase::str2mnemonic(const char * mn_name)
+{
+ for (unsigned m = 1; m<Mnemonic_Count; m++) {
+ if (!strcmpi(mnemonics[m].name, mn_name)) {
+ return (Mnemonic)m;
+ }
+ }
+ return Mnemonic_Null;
+}
+
+static const char * conditionStrings[ConditionMnemonic_Count] = {
+ "O",
+ "NO",
+ "B",
+ "AE",
+ "Z",
+ "NZ",
+ "BE",
+ "A",
+
+ "S",
+ "NS",
+ "P",
+ "NP",
+ "L",
+ "GE",
+ "LE",
+ "G",
+};
+
+const char * getConditionString(ConditionMnemonic cm) {
+ return conditionStrings[cm];
+}
+
+static const struct {
+ char sizeString[12];
+ OpndSize size;
+}
+sizes[] = {
+ { "Sz8", OpndSize_8 },
+ { "Sz16", OpndSize_16 },
+ { "Sz32", OpndSize_32 },
+ { "Sz64", OpndSize_64 },
+#if !defined(TESTING_ENCODER)
+ { "Sz80", OpndSize_80 },
+ { "Sz128", OpndSize_128 },
+#endif
+ { "SzAny", OpndSize_Any },
+};
+
+
+OpndSize getOpndSize(const char * sizeString)
+{
+ assert(sizeString);
+ for (unsigned i = 0; i<COUNTOF(sizes); i++) {
+ if (!strcmpi(sizeString, sizes[i].sizeString)) {
+ return sizes[i].size;
+ }
+ }
+ return OpndSize_Null;
+}
+
+const char * getOpndSizeString(OpndSize size) {
+ for( unsigned i = 0; i<COUNTOF(sizes); i++ ) {
+ if( sizes[i].size==size ) {
+ return sizes[i].sizeString;
+ }
+ }
+ return NULL;
+}
+
+static const struct {
+ char kindString[16];
+ OpndKind kind;
+}
+kinds[] = {
+ { "Null", OpndKind_Null },
+ { "GPReg", OpndKind_GPReg },
+ { "SReg", OpndKind_SReg },
+ { "FPReg", OpndKind_FPReg },
+ { "XMMReg", OpndKind_XMMReg },
+#ifdef _HAVE_MMX_
+ { "MMXReg", OpndKind_MMXReg },
+#endif
+ { "StatusReg", OpndKind_StatusReg },
+ { "Reg", OpndKind_Reg },
+ { "Imm", OpndKind_Imm },
+ { "Mem", OpndKind_Mem },
+ { "Any", OpndKind_Any },
+};
+
+const char * getOpndKindString(OpndKind kind)
+{
+ for (unsigned i = 0; i<COUNTOF(kinds); i++) {
+ if (kinds[i].kind==kind) {
+ return kinds[i].kindString;
+ }
+ }
+ return NULL;
+}
+
+OpndKind getOpndKind(const char * kindString)
+{
+ assert(kindString);
+ for (unsigned i = 0; i<COUNTOF(kinds); i++) {
+ if (!strcmpi(kindString, kinds[i].kindString)) {
+ return kinds[i].kind;
+ }
+ }
+ return OpndKind_Null;
+}
+
+/**
+ * A mapping between register string representation and its RegName constant.
+ */
+static const struct {
+ char regstring[7];
+ RegName regname;
+}
+
+registers[] = {
+#ifdef _EM64T_
+ {"RAX", RegName_RAX},
+ {"RBX", RegName_RBX},
+ {"RCX", RegName_RCX},
+ {"RDX", RegName_RDX},
+ {"RBP", RegName_RBP},
+ {"RSI", RegName_RSI},
+ {"RDI", RegName_RDI},
+ {"RSP", RegName_RSP},
+ {"R8", RegName_R8},
+ {"R9", RegName_R9},
+ {"R10", RegName_R10},
+ {"R11", RegName_R11},
+ {"R12", RegName_R12},
+ {"R13", RegName_R13},
+ {"R14", RegName_R14},
+ {"R15", RegName_R15},
+#endif
+
+ {"EAX", RegName_EAX},
+ {"ECX", RegName_ECX},
+ {"EDX", RegName_EDX},
+ {"EBX", RegName_EBX},
+ {"ESP", RegName_ESP},
+ {"EBP", RegName_EBP},
+ {"ESI", RegName_ESI},
+ {"EDI", RegName_EDI},
+#ifdef _EM64T_
+ {"R8D", RegName_R8D},
+ {"R9D", RegName_R9D},
+ {"R10D", RegName_R10D},
+ {"R11D", RegName_R11D},
+ {"R12D", RegName_R12D},
+ {"R13D", RegName_R13D},
+ {"R14D", RegName_R14D},
+ {"R15D", RegName_R15D},
+#endif
+
+ {"AX", RegName_AX},
+ {"CX", RegName_CX},
+ {"DX", RegName_DX},
+ {"BX", RegName_BX},
+ {"SP", RegName_SP},
+ {"BP", RegName_BP},
+ {"SI", RegName_SI},
+ {"DI", RegName_DI},
+
+ {"AL", RegName_AL},
+ {"CL", RegName_CL},
+ {"DL", RegName_DL},
+ {"BL", RegName_BL},
+#if !defined(_EM64T_)
+ {"AH", RegName_AH},
+ {"CH", RegName_CH},
+ {"DH", RegName_DH},
+ {"BH", RegName_BH},
+#else
+ {"SPL", RegName_SPL},
+ {"BPL", RegName_BPL},
+ {"SIL", RegName_SIL},
+ {"DIL", RegName_DIL},
+ {"R8L", RegName_R8L},
+ {"R9L", RegName_R9L},
+ {"R10L", RegName_R10L},
+ {"R11L", RegName_R11L},
+ {"R12L", RegName_R12L},
+ {"R13L", RegName_R13L},
+ {"R14L", RegName_R14L},
+ {"R15L", RegName_R15L},
+#endif
+ {"ES", RegName_ES},
+ {"CS", RegName_CS},
+ {"SS", RegName_SS},
+ {"DS", RegName_DS},
+ {"FS", RegName_FS},
+ {"GS", RegName_GS},
+
+ {"FP0", RegName_FP0},
+/*
+ {"FP1", RegName_FP1},
+ {"FP2", RegName_FP2},
+ {"FP3", RegName_FP3},
+ {"FP4", RegName_FP4},
+ {"FP5", RegName_FP5},
+ {"FP6", RegName_FP6},
+ {"FP7", RegName_FP7},
+*/
+ {"FP0S", RegName_FP0S},
+ {"FP1S", RegName_FP1S},
+ {"FP2S", RegName_FP2S},
+ {"FP3S", RegName_FP3S},
+ {"FP4S", RegName_FP4S},
+ {"FP5S", RegName_FP5S},
+ {"FP6S", RegName_FP6S},
+ {"FP7S", RegName_FP7S},
+
+ {"FP0D", RegName_FP0D},
+ {"FP1D", RegName_FP1D},
+ {"FP2D", RegName_FP2D},
+ {"FP3D", RegName_FP3D},
+ {"FP4D", RegName_FP4D},
+ {"FP5D", RegName_FP5D},
+ {"FP6D", RegName_FP6D},
+ {"FP7D", RegName_FP7D},
+
+ {"XMM0", RegName_XMM0},
+ {"XMM1", RegName_XMM1},
+ {"XMM2", RegName_XMM2},
+ {"XMM3", RegName_XMM3},
+ {"XMM4", RegName_XMM4},
+ {"XMM5", RegName_XMM5},
+ {"XMM6", RegName_XMM6},
+ {"XMM7", RegName_XMM7},
+#ifdef _EM64T_
+ {"XMM8", RegName_XMM8},
+ {"XMM9", RegName_XMM9},
+ {"XMM10", RegName_XMM10},
+ {"XMM11", RegName_XMM11},
+ {"XMM12", RegName_XMM12},
+ {"XMM13", RegName_XMM13},
+ {"XMM14", RegName_XMM14},
+ {"XMM15", RegName_XMM15},
+#endif
+
+
+ {"XMM0S", RegName_XMM0S},
+ {"XMM1S", RegName_XMM1S},
+ {"XMM2S", RegName_XMM2S},
+ {"XMM3S", RegName_XMM3S},
+ {"XMM4S", RegName_XMM4S},
+ {"XMM5S", RegName_XMM5S},
+ {"XMM6S", RegName_XMM6S},
+ {"XMM7S", RegName_XMM7S},
+#ifdef _EM64T_
+ {"XMM8S", RegName_XMM8S},
+ {"XMM9S", RegName_XMM9S},
+ {"XMM10S", RegName_XMM10S},
+ {"XMM11S", RegName_XMM11S},
+ {"XMM12S", RegName_XMM12S},
+ {"XMM13S", RegName_XMM13S},
+ {"XMM14S", RegName_XMM14S},
+ {"XMM15S", RegName_XMM15S},
+#endif
+
+ {"XMM0D", RegName_XMM0D},
+ {"XMM1D", RegName_XMM1D},
+ {"XMM2D", RegName_XMM2D},
+ {"XMM3D", RegName_XMM3D},
+ {"XMM4D", RegName_XMM4D},
+ {"XMM5D", RegName_XMM5D},
+ {"XMM6D", RegName_XMM6D},
+ {"XMM7D", RegName_XMM7D},
+#ifdef _EM64T_
+ {"XMM8D", RegName_XMM8D},
+ {"XMM9D", RegName_XMM9D},
+ {"XMM10D", RegName_XMM10D},
+ {"XMM11D", RegName_XMM11D},
+ {"XMM12D", RegName_XMM12D},
+ {"XMM13D", RegName_XMM13D},
+ {"XMM14D", RegName_XMM14D},
+ {"XMM15D", RegName_XMM15D},
+#endif
+
+ {"EFLGS", RegName_EFLAGS},
+};
+
+
+const char * getRegNameString(RegName reg)
+{
+ for (unsigned i = 0; i<COUNTOF(registers); i++) {
+ if (registers[i].regname == reg) {
+ return registers[i].regstring;
+ }
+ }
+ return NULL;
+}
+
+RegName getRegName(const char * regname)
+{
+ if (NULL == regname) {
+ return RegName_Null;
+ }
+
+ for (unsigned i = 0; i<COUNTOF(registers); i++) {
+ if (!strcmpi(regname,registers[i].regstring)) {
+ return registers[i].regname;
+ }
+ }
+ return RegName_Null;
+}
+
+ENCODER_NAMESPACE_END
diff --git a/vm/compiler/codegen/x86/libenc/enc_base.h b/vm/compiler/codegen/x86/libenc/enc_base.h
new file mode 100644
index 0000000..e90ad2b
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/enc_base.h
@@ -0,0 +1,740 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+
+/**
+ * @file
+ * @brief Main encoding routines and structures.
+ */
+
+#ifndef __ENC_BASE_H_INCLUDED__
+#define __ENC_BASE_H_INCLUDED__
+
+#include "enc_defs.h"
+
+
+#include <stdlib.h>
+#include <assert.h>
+#include <memory.h>
+
+ENCODER_NAMESPACE_START
+struct MnemonicInfo;
+struct OpcodeInfo;
+struct Rex;
+
+/**
+ * @brief Basic facilities for generation of processor's instructions.
+ *
+ * The class EncoderBase represents the basic facilities for the encoding of
+ * processor's instructions on IA32 and EM64T platforms.
+ *
+ * The class provides general interface to generate the instructions as well
+ * as to retrieve some static data about instructions (number of arguments,
+ * their roles, etc).
+ *
+ * Currently, the EncoderBase class is used for both LIL and Jitrino code
+ * generators. Each of these code generators has its own wrapper to adapt
+ * this general interface for specific needs - see encoder.h for LIL wrappers
+ * and Ia32Encoder.h for Jitrino's adapter.
+ *
+ * Interface is provided through static methods, no instances of EncoderBase
+ * to be created.
+ *
+ * @todo RIP-based addressing on EM64T - it's not yet supported currently.
+ */
+class EncoderBase {
+public:
+ class Operands;
+ struct MnemonicDesc;
+ /**
+ * @brief Generates processor's instruction.
+ *
+ * @param stream - a buffer to generate into
+ * @param mn - \link Mnemonic mnemonic \endlink of the instruction
+ * @param opnds - operands for the instruction
+ * @returns (stream + length of the just generated instruction)
+ */
+ static char * encode(char * stream, Mnemonic mn, const Operands& opnds);
+ static char * getOpndLocation(int index);
+
+ /**
+ * @brief Generates the smallest possible number of NOP-s.
+ *
+ * Effectively generates the smallest possible number of instructions,
+ * which are NOP-s for CPU. Normally used to make a code alignment.
+ *
+ * The method inserts exactly number of bytes specified. It's a caller's
+ * responsibility to make sure the buffer is big enough.
+ *
+ * @param stream - buffer where to generate code into, can not be NULL
+ * @param howMany - how many bytes to fill with NOP-s
+ * @return \c (stream+howMany)
+ */
+ static char * nops(char * stream, unsigned howMany);
+
+ /**
+ * @brief Inserts a prefix into the code buffer.
+ *
+ * The method writes no more than one byte into the buffer. This is a
+ * caller's responsibility to make sure the buffer is big enough.
+ *
+ * @param stream - buffer where to insert the prefix
+ * @param pref - prefix to be inserted. If it's InstPrefix_Null, then
+ * no action performed and return value is \c stream.
+ * @return \c (stream+1) if pref is not InstPrefix_Null, or \c stream
+ * otherwise
+ */
+ static char * prefix(char* stream, InstPrefix pref);
+
+ /**
+ * @brief Determines if operand with opndExt suites the position with instExt.
+ */
+ static bool extAllowed(OpndExt opndExt, OpndExt instExt);
+
+ /**
+ * @brief Returns #MnemonicDesc by the given Mnemonic.
+ */
+ static const MnemonicDesc * getMnemonicDesc(Mnemonic mn)
+ {
+ assert(mn < Mnemonic_Count);
+ return mnemonics + mn;
+ }
+
+ /**
+ * @brief Returns a Mnemonic for the given name.
+ *
+ * The lookup is case insensitive, if no mnemonic found for the given
+ * string, then Mnemonic_Null returned.
+ */
+ static Mnemonic str2mnemonic(const char * mn_name);
+
+ /**
+ * @brief Returns a string representation of the given Mnemonic.
+ *
+ * If invalid mnemonic passed, then the behavior is unpredictable.
+ */
+ static const char * getMnemonicString(Mnemonic mn)
+ {
+ return getMnemonicDesc(mn)->name;
+ }
+
+ static const char * toStr(Mnemonic mn)
+ {
+ return getMnemonicDesc(mn)->name;
+ }
+
+
+ /**
+ * @brief Description of operand.
+ *
+ * Description of an operand in opcode - its kind, size or RegName if
+ * operand must be a particular register.
+ */
+ struct OpndDesc {
+ /**
+ * @brief Location of the operand.
+ *
+ * May be a mask, i.e. OpndKind_Imm|OpndKind_Mem.
+ */
+ OpndKind kind;
+ /**
+ * @brief Size of the operand.
+ */
+ OpndSize size;
+ /**
+ * @brief Extention of the operand.
+ */
+ OpndExt ext;
+ /**
+ * @brief Appropriate RegName if operand must reside on a particular
+ * register (i.e. CWD/CDQ instructions), RegName_Null
+ * otherwise.
+ */
+ RegName reg;
+ };
+
+ /**
+ * @brief Description of operands' roles in instruction.
+ */
+ struct OpndRolesDesc {
+ /**
+ * @brief Total number of operands in the operation.
+ */
+ unsigned count;
+ /**
+ * @brief Number of defs in the operation.
+ */
+ unsigned defCount;
+ /**
+ * @brief Number of uses in the operation.
+ */
+ unsigned useCount;
+ /**
+ * @brief Operand roles, bit-packed.
+ *
+ * A bit-packed info about operands' roles. Each operand's role is
+ * described by two bits, counted from right-to-left - the less
+ * significant bits (0,1) represent operand#0.
+ *
+ * The mask is build by ORing #OpndRole_Def and #OpndRole_Use
+ * appropriately and shifting left, i.e. operand#0's role would be
+ * - '(OpndRole_Def|OpndRole_Use)'
+ * - opnd#1's role would be 'OpndRole_Use<<2'
+ * - and operand#2's role would be, say, 'OpndRole_Def<<4'.
+ */
+ unsigned roles;
+ };
+
+ /**
+ * @brief Extracts appropriate OpndRole for a given operand.
+ *
+ * The order of operands is left-to-right, i.e. for MOV, it
+ * would be 'MOV op0, op1'
+ */
+ static OpndRole getOpndRoles(OpndRolesDesc ord, unsigned idx)
+ {
+ assert(idx < ord.count);
+ return (OpndRole)(ord.roles>>((ord.count-1-idx)*2) & 0x3);
+ }
+
+ /**
+ * @brief Info about single opcode - its opcode bytes, operands,
+ * operands' roles.
+ */
+ union OpcodeDesc {
+ char dummy[128]; // To make total size a power of 2
+
+ struct {
+ /**
+ * @brief Raw opcode bytes.
+ *
+ * 'Raw' opcode bytes which do not require any analysis and are
+ * independent from arguments/sizes/etc (may include opcode size
+ * prefix).
+ */
+ char opcode[5];
+ unsigned opcode_len;
+ unsigned aux0;
+ unsigned aux1;
+ /**
+ * @brief Info about opcode's operands.
+ *
+ * The [3] mostly comes from IDIV/IMUL which both may have up to 3
+ * operands.
+ */
+ OpndDesc opnds[3];
+ unsigned first_opnd;
+ /**
+ * @brief Info about operands - total number, number of uses/defs,
+ * operands' roles.
+ */
+ OpndRolesDesc roles;
+ /**
+ * @brief If not zero, then this is final OpcodeDesc structure in
+ * the list of opcodes for a given mnemonic.
+ */
+ char last;
+ char platf;
+ };
+ };
+public:
+ /**
+ * @brief General info about mnemonic.
+ */
+ struct MnemonicDesc {
+ /**
+ * @brief The mnemonic itself.
+ */
+ Mnemonic mn;
+ /**
+ * Various characteristics of mnemonic.
+ * @see MF_
+ */
+ unsigned flags;
+ /**
+ * @brief Operation's operand's count and roles.
+ *
+ * For the operations whose opcodes may use different number of
+ * operands (i.e. IMUL/SHL) either most common value used, or empty
+ * value left.
+ */
+ OpndRolesDesc roles;
+ /**
+ * @brief Print name of the mnemonic.
+ */
+ const char * name;
+ };
+
+
+ /**
+ * @brief Magic number, shows a maximum value a hash code can take.
+ *
+ * For meaning and arithmetics see enc_tabl.cpp.
+ *
+ * The value was increased from '5155' to '8192' to make it aligned
+ * for faster access in EncoderBase::lookup().
+ */
+ static const unsigned int HASH_MAX = 8192; //5155;
+ /**
+ * @brief Empty value, used in hash-to-opcode map to show an empty slot.
+ */
+ static const unsigned char NOHASH = 0xFF;
+ /**
+ * @brief The name says it all.
+ */
+ static const unsigned char HASH_BITS_PER_OPERAND = 5;
+
+ /**
+ * @brief Contains info about a single instructions's operand - its
+ * location, size and a value for immediate or RegName for
+ * register operands.
+ */
+ class Operand {
+ public:
+ /**
+ * @brief Initializes the instance with empty size and kind.
+ */
+ Operand() : m_kind(OpndKind_Null), m_size(OpndSize_Null), m_ext(OpndExt_None), m_need_rex(false) {}
+ /**
+ * @brief Creates register operand from given RegName.
+ */
+ Operand(RegName reg, OpndExt ext = OpndExt_None) : m_kind(getRegKind(reg)),
+ m_size(getRegSize(reg)),
+ m_ext(ext), m_reg(reg)
+ {
+ hash_it();
+ }
+ /**
+ * @brief Creates register operand from given RegName and with the
+ * specified size and kind.
+ *
+ * Used to speedup Operand creation as there is no need to extract
+ * size and kind from the RegName.
+ * The provided size and kind must match the RegName's ones though.
+ */
+ Operand(OpndSize sz, OpndKind kind, RegName reg, OpndExt ext = OpndExt_None) :
+ m_kind(kind), m_size(sz), m_ext(ext), m_reg(reg)
+ {
+ assert(m_size == getRegSize(reg));
+ assert(m_kind == getRegKind(reg));
+ hash_it();
+ }
+ /**
+ * @brief Creates immediate operand with the given size and value.
+ */
+ Operand(OpndSize size, long long ival, OpndExt ext = OpndExt_None) :
+ m_kind(OpndKind_Imm), m_size(size), m_ext(ext), m_imm64(ival)
+ {
+ hash_it();
+ }
+ /**
+ * @brief Creates immediate operand of OpndSize_32.
+ */
+ Operand(int ival, OpndExt ext = OpndExt_None) :
+ m_kind(OpndKind_Imm), m_size(OpndSize_32), m_ext(ext), m_imm64(ival)
+ {
+ hash_it();
+ }
+ /**
+ * @brief Creates immediate operand of OpndSize_16.
+ */
+ Operand(short ival, OpndExt ext = OpndExt_None) :
+ m_kind(OpndKind_Imm), m_size(OpndSize_16), m_ext(ext), m_imm64(ival)
+ {
+ hash_it();
+ }
+
+ /**
+ * @brief Creates immediate operand of OpndSize_8.
+ */
+ Operand(char ival, OpndExt ext = OpndExt_None) :
+ m_kind(OpndKind_Imm), m_size(OpndSize_8), m_ext(ext), m_imm64(ival)
+ {
+ hash_it();
+ }
+
+ /**
+ * @brief Creates memory operand.
+ */
+ Operand(OpndSize size, RegName base, RegName index, unsigned scale,
+ int disp, OpndExt ext = OpndExt_None) : m_kind(OpndKind_Mem), m_size(size), m_ext(ext)
+ {
+ m_base = base;
+ m_index = index;
+ m_scale = scale;
+ m_disp = disp;
+ hash_it();
+ }
+
+ /**
+ * @brief Creates memory operand with only base and displacement.
+ */
+ Operand(OpndSize size, RegName base, int disp, OpndExt ext = OpndExt_None) :
+ m_kind(OpndKind_Mem), m_size(size), m_ext(ext)
+ {
+ m_base = base;
+ m_index = RegName_Null;
+ m_scale = 0;
+ m_disp = disp;
+ hash_it();
+ }
+ //
+ // general info
+ //
+ /**
+ * @brief Returns kind of the operand.
+ */
+ OpndKind kind(void) const { return m_kind; }
+ /**
+ * @brief Returns size of the operand.
+ */
+ OpndSize size(void) const { return m_size; }
+ /**
+ * @brief Returns extention of the operand.
+ */
+ OpndExt ext(void) const { return m_ext; }
+ /**
+ * @brief Returns hash of the operand.
+ */
+ unsigned hash(void) const { return m_hash; }
+ //
+#ifdef _EM64T_
+ bool need_rex(void) const { return m_need_rex; }
+#else
+ bool need_rex(void) const { return false; }
+#endif
+ /**
+ * @brief Tests whether operand is memory operand.
+ */
+ bool is_mem(void) const { return is_placed_in(OpndKind_Mem); }
+ /**
+ * @brief Tests whether operand is immediate operand.
+ */
+ bool is_imm(void) const { return is_placed_in(OpndKind_Imm); }
+ /**
+ * @brief Tests whether operand is register operand.
+ */
+ bool is_reg(void) const { return is_placed_in(OpndKind_Reg); }
+ /**
+ * @brief Tests whether operand is general-purpose register operand.
+ */
+ bool is_gpreg(void) const { return is_placed_in(OpndKind_GPReg); }
+ /**
+ * @brief Tests whether operand is float-point pseudo-register operand.
+ */
+ bool is_fpreg(void) const { return is_placed_in(OpndKind_FPReg); }
+ /**
+ * @brief Tests whether operand is XMM register operand.
+ */
+ bool is_xmmreg(void) const { return is_placed_in(OpndKind_XMMReg); }
+#ifdef _HAVE_MMX_
+ /**
+ * @brief Tests whether operand is MMX register operand.
+ */
+ bool is_mmxreg(void) const { return is_placed_in(OpndKind_MMXReg); }
+#endif
+ /**
+ * @brief Tests whether operand is signed immediate operand.
+ */
+ //bool is_signed(void) const { assert(is_imm()); return m_is_signed; }
+
+ /**
+ * @brief Returns base of memory operand (RegName_Null if not memory).
+ */
+ RegName base(void) const { return is_mem() ? m_base : RegName_Null; }
+ /**
+ * @brief Returns index of memory operand (RegName_Null if not memory).
+ */
+ RegName index(void) const { return is_mem() ? m_index : RegName_Null; }
+ /**
+ * @brief Returns scale of memory operand (0 if not memory).
+ */
+ unsigned scale(void) const { return is_mem() ? m_scale : 0; }
+ /**
+ * @brief Returns displacement of memory operand (0 if not memory).
+ */
+ int disp(void) const { return is_mem() ? m_disp : 0; }
+ /**
+ * @brief Returns RegName of register operand (RegName_Null if not
+ * register).
+ */
+ RegName reg(void) const { return is_reg() ? m_reg : RegName_Null; }
+ /**
+ * @brief Returns value of immediate operand (0 if not immediate).
+ */
+ long long imm(void) const { return is_imm() ? m_imm64 : 0; }
+ private:
+ bool is_placed_in(OpndKind kd) const
+ {
+ return kd == OpndKind_Reg ?
+ m_kind == OpndKind_GPReg ||
+#ifdef _HAVE_MMX_
+ m_kind == OpndKind_MMXReg ||
+#endif
+ m_kind == OpndKind_FPReg ||
+ m_kind == OpndKind_XMMReg
+ : kd == m_kind;
+ }
+ void hash_it(void)
+ {
+ m_hash = get_size_hash(m_size) | get_kind_hash(m_kind);
+#ifdef _EM64T_
+ m_need_rex = false;
+ if (is_reg() && is_em64t_extra_reg(m_reg)) {
+ m_need_rex = true;
+ }
+ else if (is_mem() && (is_em64t_extra_reg(m_base) ||
+ is_em64t_extra_reg(m_index))) {
+ m_need_rex = true;
+ }
+#endif
+ }
+ // general info
+ OpndKind m_kind;
+ OpndSize m_size;
+ OpndExt m_ext;
+ // complex address form support
+ RegName m_base;
+ RegName m_index;
+ unsigned m_scale;
+ union {
+ int m_disp;
+ RegName m_reg;
+ long long m_imm64;
+ };
+ unsigned m_hash;
+ bool m_need_rex;
+ friend class EncoderBase::Operands;
+ };
+ /**
+ * @brief Simple container for up to 3 Operand-s.
+ */
+ class Operands {
+ public:
+ Operands(void)
+ {
+ clear();
+ }
+ Operands(const Operand& op0)
+ {
+ clear();
+ add(op0);
+ }
+
+ Operands(const Operand& op0, const Operand& op1)
+ {
+ clear();
+ add(op0); add(op1);
+ }
+
+ Operands(const Operand& op0, const Operand& op1, const Operand& op2)
+ {
+ clear();
+ add(op0); add(op1); add(op2);
+ }
+
+ unsigned count(void) const { return m_count; }
+ unsigned hash(void) const { return m_hash; }
+ const Operand& operator[](unsigned idx) const
+ {
+ assert(idx<m_count);
+ return m_operands[idx];
+ }
+
+ void add(const Operand& op)
+ {
+ assert(m_count < COUNTOF(m_operands));
+ m_hash = (m_hash<<HASH_BITS_PER_OPERAND) | op.hash();
+ m_operands[m_count++] = op;
+ m_need_rex = m_need_rex || op.m_need_rex;
+ }
+#ifdef _EM64T_
+ bool need_rex(void) const { return m_need_rex; }
+#else
+ bool need_rex(void) const { return false; }
+#endif
+ void clear(void)
+ {
+ m_count = 0; m_hash = 0; m_need_rex = false;
+ }
+ private:
+ unsigned m_count;
+ Operand m_operands[COUNTOF( ((OpcodeDesc*)NULL)->opnds )];
+ unsigned m_hash;
+ bool m_need_rex;
+ };
+public:
+#ifdef _DEBUG
+ /**
+ * Verifies some presumptions about encoding data table.
+ * Called automaticaly during statics initialization.
+ */
+ static int verify(void);
+#endif
+
+private:
+ /**
+ * @brief Returns found OpcodeDesc by the given Mnemonic and operands.
+ */
+ static const OpcodeDesc * lookup(Mnemonic mn, const Operands& opnds);
+ /**
+ * @brief Encodes mod/rm byte.
+ */
+ static char* encodeModRM(char* stream, const Operands& opnds,
+ unsigned idx, const OpcodeDesc * odesc, Rex * prex);
+ /**
+ * @brief Encodes special things of opcode description - '/r', 'ib', etc.
+ */
+ static char* encode_aux(char* stream, unsigned aux,
+ const Operands& opnds, const OpcodeDesc * odesc,
+ unsigned * pargsCount, Rex* prex);
+#ifdef _EM64T_
+ /**
+ * @brief Returns true if the 'reg' argument represents one of the new
+ * EM64T registers - R8(D)-R15(D).
+ *
+ * The 64 bits versions of 'old-fashion' registers, i.e. RAX are not
+ * considered as 'extra'.
+ */
+ static bool is_em64t_extra_reg(const RegName reg)
+ {
+ if (needs_rex_r(reg)) {
+ return true;
+ }
+ if (RegName_SPL <= reg && reg <= RegName_R15L) {
+ return true;
+ }
+ return false;
+ }
+ static bool needs_rex_r(const RegName reg)
+ {
+ if (RegName_R8 <= reg && reg <= RegName_R15) {
+ return true;
+ }
+ if (RegName_R8D <= reg && reg <= RegName_R15D) {
+ return true;
+ }
+ if (RegName_R8S <= reg && reg <= RegName_R15S) {
+ return true;
+ }
+ if (RegName_R8L <= reg && reg <= RegName_R15L) {
+ return true;
+ }
+ if (RegName_XMM8 <= reg && reg <= RegName_XMM15) {
+ return true;
+ }
+ if (RegName_XMM8D <= reg && reg <= RegName_XMM15D) {
+ return true;
+ }
+ if (RegName_XMM8S <= reg && reg <= RegName_XMM15S) {
+ return true;
+ }
+ return false;
+ }
+ /**
+ * @brief Returns an 'processor's index' of the register - the index
+ * used to encode the register in ModRM/SIB bytes.
+ *
+ * For the new EM64T registers the 'HW index' differs from the index
+ * encoded in RegName. For old-fashion registers it's effectively the
+ * same as ::getRegIndex(RegName).
+ */
+ static unsigned char getHWRegIndex(const RegName reg)
+ {
+ if (getRegKind(reg) != OpndKind_GPReg) {
+ return getRegIndex(reg);
+ }
+ if (RegName_SPL <= reg && reg<=RegName_DIL) {
+ return getRegIndex(reg);
+ }
+ if (RegName_R8L<= reg && reg<=RegName_R15L) {
+ return getRegIndex(reg) - getRegIndex(RegName_R8L);
+ }
+ return is_em64t_extra_reg(reg) ?
+ getRegIndex(reg)-getRegIndex(RegName_R8D) : getRegIndex(reg);
+ }
+#else
+ static unsigned char getHWRegIndex(const RegName reg)
+ {
+ return getRegIndex(reg);
+ }
+ static bool is_em64t_extra_reg(const RegName reg)
+ {
+ return false;
+ }
+#endif
+public:
+ static unsigned char get_size_hash(OpndSize size) {
+ return (size <= OpndSize_64) ? size_hash[size] : 0xFF;
+ }
+ static unsigned char get_kind_hash(OpndKind kind) {
+ return (kind <= OpndKind_Mem) ? kind_hash[kind] : 0xFF;
+ }
+
+ /**
+ * @brief A table used for the fast computation of hash value.
+ *
+ * A change must be strictly balanced with hash-related functions and data
+ * in enc_base.h/.cpp.
+ */
+ static const unsigned char size_hash[OpndSize_64+1];
+ /**
+ * @brief A table used for the fast computation of hash value.
+ *
+ * A change must be strictly balanced with hash-related functions and data
+ * in enc_base.h/.cpp.
+ */
+ static const unsigned char kind_hash[OpndKind_Mem+1];
+ /**
+ * @brief Maximum number of opcodes used for a single mnemonic.
+ *
+ * No arithmetics behind the number, simply estimated.
+ */
+ static const unsigned int MAX_OPCODES = 32; //20;
+ /**
+ * @brief Mapping between operands hash code and operands.
+ */
+ static unsigned char opcodesHashMap[Mnemonic_Count][HASH_MAX];
+ /**
+ * @brief Array of mnemonics.
+ */
+ static MnemonicDesc mnemonics[Mnemonic_Count];
+ /**
+ * @brief Array of available opcodes.
+ */
+ static OpcodeDesc opcodes[Mnemonic_Count][MAX_OPCODES];
+
+ static int buildTable(void);
+ static void buildMnemonicDesc(const MnemonicInfo * minfo);
+ /**
+ * @brief Computes hash value for the given operands.
+ */
+ static unsigned short getHash(const OpcodeInfo* odesc);
+ /**
+ * @brief Dummy variable, for automatic invocation of buildTable() at
+ * startup.
+ */
+ static int dummy;
+
+ static char * curRelOpnd[3];
+};
+
+ENCODER_NAMESPACE_END
+
+#endif // ifndef __ENC_BASE_H_INCLUDED__
diff --git a/vm/compiler/codegen/x86/libenc/enc_defs.h b/vm/compiler/codegen/x86/libenc/enc_defs.h
new file mode 100644
index 0000000..ac0bb3b
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/enc_defs.h
@@ -0,0 +1,786 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+#ifndef _ENCODER_DEFS_H_
+#define _ENCODER_DEFS_H_
+
+
+// Used to isolate experimental or being tuned encoder into a separate
+// namespace so it can coexist with a stable one in the same bundle.
+#ifdef ENCODER_ISOLATE
+ #define ENCODER_NAMESPACE_START namespace enc_ia32 {
+ #define ENCODER_NAMESPACE_END };
+#else
+ #define ENCODER_NAMESPACE_START
+ #define ENCODER_NAMESPACE_END
+#endif
+
+#include <assert.h>
+#include "enc_defs_ext.h"
+
+#ifndef COUNTOF
+ /**
+ * Number of items in an array.
+ */
+ #define COUNTOF(a) (sizeof(a)/sizeof(a[0]))
+#endif
+
+#ifdef _EM64T_
+ /**
+ * A stack pointer of default platform's size.
+ */
+ #define REG_STACK RegName_RSP
+ /**
+ * A max GP register (with a highest index number)
+ */
+ #define REG_MAX RegName_R15
+ /**
+ * Total number of GP registers including stack pointer.
+ */
+ #define MAX_REGS 15
+#else
+ #define REG_STACK RegName_ESP
+ #define REG_MAX RegName_EDI
+ #define MAX_REGS 8
+#endif
+
+ENCODER_NAMESPACE_START
+
+/**
+ * A number of bytes 'eaten' by an ordinary PUSH/POP.
+ */
+#define STACK_SLOT_SIZE (sizeof(void*))
+
+
+/**
+ * A recommended by Intel Arch Manual aligment for instructions that
+ * are targets for jmps.
+ */
+#define JMP_TARGET_ALIGMENT (16)
+/**
+ * A maximum possible size of native instruction.
+ */
+#define MAX_NATIVE_INST_SIZE (15)
+/**
+ * The enum OpndKind describes an operand's location - memory, immediate or a register.
+ * It can be used as a bit mask.
+ */
+typedef enum OpndKind {
+ /**
+ * A change must be balanced with at least the following places:
+ * Ia32::Constraint-s use the OpndKind as a mask
+ * encoder.cpp & encoder_master_info.cpp uses OpndKind as an index for hashing
+ * - perhaps there are much more places
+ *
+ * NOTE: an MMXReg kind is incompatible with the current constraints framework,
+ * as it's not encoded as a mask.
+ */
+ OpndKind_Null=0,
+ OpndKind_GPReg = 0x01, OpndKind_MinRegKind = OpndKind_GPReg,
+ OpndKind_SReg = 0x02,
+#ifdef _HAVE_MMX_
+ OpndKind_MMXReg = 0x03,
+#endif
+ OpndKind_FPReg = 0x04,
+ OpndKind_XMMReg = 0x08,
+ OpndKind_OtherReg = 0x10,
+ OpndKind_StatusReg = OpndKind_OtherReg,
+ OpndKind_MaxRegKind = OpndKind_StatusReg, // a max existing kind of register
+ OpndKind_MaxReg, // -'- + 1 to be used in array defs
+ //
+ OpndKind_Immediate = 0x20, OpndKind_Imm=OpndKind_Immediate,
+ OpndKind_Memory = 0x40, OpndKind_Mem=OpndKind_Memory,
+ //
+ OpndKind_Reg = 0x1F,
+ OpndKind_Any = 0x7F,
+ // syntetic constants. Normally not used anywhere, but are used for
+ // human-readable showing under the debugger
+ OpndKind_GPReg_Mem = OpndKind_GPReg|OpndKind_Mem,
+#ifdef _HAVE_MMX_
+ OpndKind_MMXReg_Mem = OpndKind_MMXReg|OpndKind_Mem,
+#endif
+ OpndKind_XMMReg_Mem = OpndKind_XMMReg|OpndKind_Mem,
+} OpndKind;
+
+/**
+ * Defines type of extention allowed for particular operand.
+ * For example imul r32,r_m32,imm8 sign extend imm8 before performing multiplication.
+ * To satisfy instruction constraints immediate operand should be either OpndExt_Signed
+ * or OpndExt_Any.
+ */
+typedef enum OpndExt {
+ OpndExt_None = 0x0,
+ OpndExt_Signed = 0x1,
+ OpndExt_Zero = 0x2,
+ OpndExt_Any = 0x3,
+}OpndExt;
+
+/**
+ * enum OpndRole defines the role of an operand in an instruction
+ * Can be used as mask to combine def and use. The complete def+use
+ * info can be combined in 2 bits which is used, say in Encoder::OpndRole.
+ */
+//TODO: this duplicates an Role used in the Ia32::Inst. That duplicate enum should be removed.
+typedef enum OpndRole {
+ OpndRole_Null=0,
+ OpndRole_Use=0x1,
+ OpndRole_Def=0x2,
+ OpndRole_UseDef=OpndRole_Use|OpndRole_Def,
+ OpndRole_All=0xffff,
+} OpndRole;
+
+
+#define REGNAME(k,s,i) ( ((k & OpndKind_Any)<<24) | ((s & OpndSize_Any)<<16) | (i&0xFF) )
+
+// Gregory -
+// It is critical that all register indexes (3rd number) inside of the
+// following table go in ascending order. That is R8 goes after
+// RDI. It is necessary for decoder when extending registers from RAX-RDI
+// to R8-R15 by simply adding 8 to the index on EM64T architecture
+typedef enum RegName {
+
+ RegName_Null = 0,
+
+#ifdef _EM64T_
+ /*
+ An index part of the RegName-s for RAX-RDI, EAX-ESI, AX-SI and AL-BH is
+ the same as the index used during instructions encoding. The same rule
+ applies for XMM regsters for IA32.
+ For new EM64T registers (both GP and XMM) the index need to be corrected to
+ obtain the index used in processor's instructions.
+ */
+ RegName_RAX = REGNAME(OpndKind_GPReg,OpndSize_64,0),
+ RegName_RCX = REGNAME(OpndKind_GPReg,OpndSize_64,1),
+ RegName_RDX = REGNAME(OpndKind_GPReg,OpndSize_64,2),
+ RegName_RBX = REGNAME(OpndKind_GPReg,OpndSize_64,3),
+ RegName_RSP = REGNAME(OpndKind_GPReg,OpndSize_64,4),
+ RegName_RBP = REGNAME(OpndKind_GPReg,OpndSize_64,5),
+ RegName_RSI = REGNAME(OpndKind_GPReg,OpndSize_64,6),
+ RegName_RDI = REGNAME(OpndKind_GPReg,OpndSize_64,7),
+
+ RegName_R8 = REGNAME(OpndKind_GPReg,OpndSize_64,8),
+ RegName_R9 = REGNAME(OpndKind_GPReg,OpndSize_64,9),
+ RegName_R10 = REGNAME(OpndKind_GPReg,OpndSize_64,10),
+ RegName_R11 = REGNAME(OpndKind_GPReg,OpndSize_64,11),
+ RegName_R12 = REGNAME(OpndKind_GPReg,OpndSize_64,12),
+ RegName_R13 = REGNAME(OpndKind_GPReg,OpndSize_64,13),
+ RegName_R14 = REGNAME(OpndKind_GPReg,OpndSize_64,14),
+ RegName_R15 = REGNAME(OpndKind_GPReg,OpndSize_64,15),
+#endif //~_EM64T_
+
+ RegName_EAX=REGNAME(OpndKind_GPReg,OpndSize_32,0),
+ RegName_ECX=REGNAME(OpndKind_GPReg,OpndSize_32,1),
+ RegName_EDX=REGNAME(OpndKind_GPReg,OpndSize_32,2),
+ RegName_EBX=REGNAME(OpndKind_GPReg,OpndSize_32,3),
+ RegName_ESP=REGNAME(OpndKind_GPReg,OpndSize_32,4),
+ RegName_EBP=REGNAME(OpndKind_GPReg,OpndSize_32,5),
+ RegName_ESI=REGNAME(OpndKind_GPReg,OpndSize_32,6),
+ RegName_EDI=REGNAME(OpndKind_GPReg,OpndSize_32,7),
+
+#ifdef _EM64T_
+ RegName_R8D = REGNAME(OpndKind_GPReg,OpndSize_32,8),
+ RegName_R9D = REGNAME(OpndKind_GPReg,OpndSize_32,9),
+ RegName_R10D = REGNAME(OpndKind_GPReg,OpndSize_32,10),
+ RegName_R11D = REGNAME(OpndKind_GPReg,OpndSize_32,11),
+ RegName_R12D = REGNAME(OpndKind_GPReg,OpndSize_32,12),
+ RegName_R13D = REGNAME(OpndKind_GPReg,OpndSize_32,13),
+ RegName_R14D = REGNAME(OpndKind_GPReg,OpndSize_32,14),
+ RegName_R15D = REGNAME(OpndKind_GPReg,OpndSize_32,15),
+#endif //~_EM64T_
+
+ RegName_AX=REGNAME(OpndKind_GPReg,OpndSize_16,0),
+ RegName_CX=REGNAME(OpndKind_GPReg,OpndSize_16,1),
+ RegName_DX=REGNAME(OpndKind_GPReg,OpndSize_16,2),
+ RegName_BX=REGNAME(OpndKind_GPReg,OpndSize_16,3),
+ RegName_SP=REGNAME(OpndKind_GPReg,OpndSize_16,4),
+ RegName_BP=REGNAME(OpndKind_GPReg,OpndSize_16,5),
+ RegName_SI=REGNAME(OpndKind_GPReg,OpndSize_16,6),
+ RegName_DI=REGNAME(OpndKind_GPReg,OpndSize_16,7),
+
+#ifdef _EM64T_
+ RegName_R8S = REGNAME(OpndKind_GPReg,OpndSize_16,8),
+ RegName_R9S = REGNAME(OpndKind_GPReg,OpndSize_16,9),
+ RegName_R10S = REGNAME(OpndKind_GPReg,OpndSize_16,10),
+ RegName_R11S = REGNAME(OpndKind_GPReg,OpndSize_16,11),
+ RegName_R12S = REGNAME(OpndKind_GPReg,OpndSize_16,12),
+ RegName_R13S = REGNAME(OpndKind_GPReg,OpndSize_16,13),
+ RegName_R14S = REGNAME(OpndKind_GPReg,OpndSize_16,14),
+ RegName_R15S = REGNAME(OpndKind_GPReg,OpndSize_16,15),
+#endif //~_EM64T_
+
+ RegName_AL=REGNAME(OpndKind_GPReg,OpndSize_8,0),
+ RegName_CL=REGNAME(OpndKind_GPReg,OpndSize_8,1),
+ RegName_DL=REGNAME(OpndKind_GPReg,OpndSize_8,2),
+ RegName_BL=REGNAME(OpndKind_GPReg,OpndSize_8,3),
+ // FIXME: Used in enc_tabl.cpp
+ // AH is not accessible on EM64T, instead encoded register is SPL, so decoded
+ // register will return incorrect enum
+ RegName_AH=REGNAME(OpndKind_GPReg,OpndSize_8,4),
+#if !defined(_EM64T_)
+ RegName_CH=REGNAME(OpndKind_GPReg,OpndSize_8,5),
+ RegName_DH=REGNAME(OpndKind_GPReg,OpndSize_8,6),
+ RegName_BH=REGNAME(OpndKind_GPReg,OpndSize_8,7),
+#else
+ RegName_SPL=REGNAME(OpndKind_GPReg,OpndSize_8,4),
+ RegName_BPL=REGNAME(OpndKind_GPReg,OpndSize_8,5),
+ RegName_SIL=REGNAME(OpndKind_GPReg,OpndSize_8,6),
+ RegName_DIL=REGNAME(OpndKind_GPReg,OpndSize_8,7),
+ RegName_R8L=REGNAME(OpndKind_GPReg,OpndSize_8,8),
+ RegName_R9L=REGNAME(OpndKind_GPReg,OpndSize_8,9),
+ RegName_R10L=REGNAME(OpndKind_GPReg,OpndSize_8,10),
+ RegName_R11L=REGNAME(OpndKind_GPReg,OpndSize_8,11),
+ RegName_R12L=REGNAME(OpndKind_GPReg,OpndSize_8,12),
+ RegName_R13L=REGNAME(OpndKind_GPReg,OpndSize_8,13),
+ RegName_R14L=REGNAME(OpndKind_GPReg,OpndSize_8,14),
+ RegName_R15L=REGNAME(OpndKind_GPReg,OpndSize_8,15),
+#endif
+
+ RegName_ES=REGNAME(OpndKind_SReg,OpndSize_16,0),
+ RegName_CS=REGNAME(OpndKind_SReg,OpndSize_16,1),
+ RegName_SS=REGNAME(OpndKind_SReg,OpndSize_16,2),
+ RegName_DS=REGNAME(OpndKind_SReg,OpndSize_16,3),
+ RegName_FS=REGNAME(OpndKind_SReg,OpndSize_16,4),
+ RegName_GS=REGNAME(OpndKind_SReg,OpndSize_16,5),
+
+ RegName_EFLAGS=REGNAME(OpndKind_StatusReg,OpndSize_32,0),
+
+#if !defined(TESTING_ENCODER)
+ RegName_FP0=REGNAME(OpndKind_FPReg,OpndSize_80,0),
+ RegName_FP1=REGNAME(OpndKind_FPReg,OpndSize_80,1),
+ RegName_FP2=REGNAME(OpndKind_FPReg,OpndSize_80,2),
+ RegName_FP3=REGNAME(OpndKind_FPReg,OpndSize_80,3),
+ RegName_FP4=REGNAME(OpndKind_FPReg,OpndSize_80,4),
+ RegName_FP5=REGNAME(OpndKind_FPReg,OpndSize_80,5),
+ RegName_FP6=REGNAME(OpndKind_FPReg,OpndSize_80,6),
+ RegName_FP7=REGNAME(OpndKind_FPReg,OpndSize_80,7),
+#endif
+ RegName_FP0S=REGNAME(OpndKind_FPReg,OpndSize_32,0),
+ RegName_FP1S=REGNAME(OpndKind_FPReg,OpndSize_32,1),
+ RegName_FP2S=REGNAME(OpndKind_FPReg,OpndSize_32,2),
+ RegName_FP3S=REGNAME(OpndKind_FPReg,OpndSize_32,3),
+ RegName_FP4S=REGNAME(OpndKind_FPReg,OpndSize_32,4),
+ RegName_FP5S=REGNAME(OpndKind_FPReg,OpndSize_32,5),
+ RegName_FP6S=REGNAME(OpndKind_FPReg,OpndSize_32,6),
+ RegName_FP7S=REGNAME(OpndKind_FPReg,OpndSize_32,7),
+
+ RegName_FP0D=REGNAME(OpndKind_FPReg,OpndSize_64,0),
+ RegName_FP1D=REGNAME(OpndKind_FPReg,OpndSize_64,1),
+ RegName_FP2D=REGNAME(OpndKind_FPReg,OpndSize_64,2),
+ RegName_FP3D=REGNAME(OpndKind_FPReg,OpndSize_64,3),
+ RegName_FP4D=REGNAME(OpndKind_FPReg,OpndSize_64,4),
+ RegName_FP5D=REGNAME(OpndKind_FPReg,OpndSize_64,5),
+ RegName_FP6D=REGNAME(OpndKind_FPReg,OpndSize_64,6),
+ RegName_FP7D=REGNAME(OpndKind_FPReg,OpndSize_64,7),
+
+#if !defined(TESTING_ENCODER)
+ RegName_XMM0=REGNAME(OpndKind_XMMReg,OpndSize_128,0),
+ RegName_XMM1=REGNAME(OpndKind_XMMReg,OpndSize_128,1),
+ RegName_XMM2=REGNAME(OpndKind_XMMReg,OpndSize_128,2),
+ RegName_XMM3=REGNAME(OpndKind_XMMReg,OpndSize_128,3),
+ RegName_XMM4=REGNAME(OpndKind_XMMReg,OpndSize_128,4),
+ RegName_XMM5=REGNAME(OpndKind_XMMReg,OpndSize_128,5),
+ RegName_XMM6=REGNAME(OpndKind_XMMReg,OpndSize_128,6),
+ RegName_XMM7=REGNAME(OpndKind_XMMReg,OpndSize_128,7),
+
+#ifdef _EM64T_
+ RegName_XMM8 = REGNAME(OpndKind_XMMReg,OpndSize_128,0),
+ RegName_XMM9 = REGNAME(OpndKind_XMMReg,OpndSize_128,1),
+ RegName_XMM10 = REGNAME(OpndKind_XMMReg,OpndSize_128,2),
+ RegName_XMM11 = REGNAME(OpndKind_XMMReg,OpndSize_128,3),
+ RegName_XMM12 = REGNAME(OpndKind_XMMReg,OpndSize_128,4),
+ RegName_XMM13 = REGNAME(OpndKind_XMMReg,OpndSize_128,5),
+ RegName_XMM14 = REGNAME(OpndKind_XMMReg,OpndSize_128,6),
+ RegName_XMM15 = REGNAME(OpndKind_XMMReg,OpndSize_128,7),
+#endif //~_EM64T_
+
+#endif // ~TESTING_ENCODER
+
+ RegName_XMM0S=REGNAME(OpndKind_XMMReg,OpndSize_32,0),
+ RegName_XMM1S=REGNAME(OpndKind_XMMReg,OpndSize_32,1),
+ RegName_XMM2S=REGNAME(OpndKind_XMMReg,OpndSize_32,2),
+ RegName_XMM3S=REGNAME(OpndKind_XMMReg,OpndSize_32,3),
+ RegName_XMM4S=REGNAME(OpndKind_XMMReg,OpndSize_32,4),
+ RegName_XMM5S=REGNAME(OpndKind_XMMReg,OpndSize_32,5),
+ RegName_XMM6S=REGNAME(OpndKind_XMMReg,OpndSize_32,6),
+ RegName_XMM7S=REGNAME(OpndKind_XMMReg,OpndSize_32,7),
+#ifdef _EM64T_
+ RegName_XMM8S=REGNAME(OpndKind_XMMReg,OpndSize_32,8),
+ RegName_XMM9S=REGNAME(OpndKind_XMMReg,OpndSize_32,9),
+ RegName_XMM10S=REGNAME(OpndKind_XMMReg,OpndSize_32,10),
+ RegName_XMM11S=REGNAME(OpndKind_XMMReg,OpndSize_32,11),
+ RegName_XMM12S=REGNAME(OpndKind_XMMReg,OpndSize_32,12),
+ RegName_XMM13S=REGNAME(OpndKind_XMMReg,OpndSize_32,13),
+ RegName_XMM14S=REGNAME(OpndKind_XMMReg,OpndSize_32,14),
+ RegName_XMM15S=REGNAME(OpndKind_XMMReg,OpndSize_32,15),
+#endif // ifdef _EM64T_
+ RegName_XMM0D=REGNAME(OpndKind_XMMReg,OpndSize_64,0),
+ RegName_XMM1D=REGNAME(OpndKind_XMMReg,OpndSize_64,1),
+ RegName_XMM2D=REGNAME(OpndKind_XMMReg,OpndSize_64,2),
+ RegName_XMM3D=REGNAME(OpndKind_XMMReg,OpndSize_64,3),
+ RegName_XMM4D=REGNAME(OpndKind_XMMReg,OpndSize_64,4),
+ RegName_XMM5D=REGNAME(OpndKind_XMMReg,OpndSize_64,5),
+ RegName_XMM6D=REGNAME(OpndKind_XMMReg,OpndSize_64,6),
+ RegName_XMM7D=REGNAME(OpndKind_XMMReg,OpndSize_64,7),
+#ifdef _EM64T_
+ RegName_XMM8D=REGNAME(OpndKind_XMMReg,OpndSize_64,8),
+ RegName_XMM9D=REGNAME(OpndKind_XMMReg,OpndSize_64,9),
+ RegName_XMM10D=REGNAME(OpndKind_XMMReg,OpndSize_64,10),
+ RegName_XMM11D=REGNAME(OpndKind_XMMReg,OpndSize_64,11),
+ RegName_XMM12D=REGNAME(OpndKind_XMMReg,OpndSize_64,12),
+ RegName_XMM13D=REGNAME(OpndKind_XMMReg,OpndSize_64,13),
+ RegName_XMM14D=REGNAME(OpndKind_XMMReg,OpndSize_64,14),
+ RegName_XMM15D=REGNAME(OpndKind_XMMReg,OpndSize_64,15),
+#endif // ifdef _EM64T_
+#ifdef _HAVE_MMX_
+ RegName_MMX0=REGNAME(OpndKind_MMXReg,OpndSize_64,0),
+ RegName_MMX1=REGNAME(OpndKind_MMXReg,OpndSize_64,1),
+ RegName_MMX2=REGNAME(OpndKind_MMXReg,OpndSize_64,2),
+ RegName_MMX3=REGNAME(OpndKind_MMXReg,OpndSize_64,3),
+ RegName_MMX4=REGNAME(OpndKind_MMXReg,OpndSize_64,4),
+ RegName_MMX5=REGNAME(OpndKind_MMXReg,OpndSize_64,5),
+ RegName_MMX6=REGNAME(OpndKind_MMXReg,OpndSize_64,6),
+ RegName_MMX7=REGNAME(OpndKind_MMXReg,OpndSize_64,7),
+#endif // _HAVE_MMX_
+} RegName;
+
+#if 0 // Android x86: use mnemonics defined in enc_defs_ext.h
+/**
+ * Conditional mnemonics.
+ * The values match the 'real' (==processor's) values of the appropriate
+ * condition values used in the opcodes.
+ */
+enum ConditionMnemonic {
+
+ ConditionMnemonic_O=0,
+ ConditionMnemonic_NO=1,
+ ConditionMnemonic_B=2, ConditionMnemonic_NAE=ConditionMnemonic_B, ConditionMnemonic_C=ConditionMnemonic_B,
+ ConditionMnemonic_NB=3, ConditionMnemonic_AE=ConditionMnemonic_NB, ConditionMnemonic_NC=ConditionMnemonic_NB,
+ ConditionMnemonic_Z=4, ConditionMnemonic_E=ConditionMnemonic_Z,
+ ConditionMnemonic_NZ=5, ConditionMnemonic_NE=ConditionMnemonic_NZ,
+ ConditionMnemonic_BE=6, ConditionMnemonic_NA=ConditionMnemonic_BE,
+ ConditionMnemonic_NBE=7, ConditionMnemonic_A=ConditionMnemonic_NBE,
+
+ ConditionMnemonic_S=8,
+ ConditionMnemonic_NS=9,
+ ConditionMnemonic_P=10, ConditionMnemonic_PE=ConditionMnemonic_P,
+ ConditionMnemonic_NP=11, ConditionMnemonic_PO=ConditionMnemonic_NP,
+ ConditionMnemonic_L=12, ConditionMnemonic_NGE=ConditionMnemonic_L,
+ ConditionMnemonic_NL=13, ConditionMnemonic_GE=ConditionMnemonic_NL,
+ ConditionMnemonic_LE=14, ConditionMnemonic_NG=ConditionMnemonic_LE,
+ ConditionMnemonic_NLE=15, ConditionMnemonic_G=ConditionMnemonic_NLE,
+ ConditionMnemonic_Count=16
+};
+
+
+#define CCM(prefix,cond) Mnemonic_##prefix##cond=Mnemonic_##prefix##cc+ConditionMnemonic_##cond
+
+//=========================================================================================================
+enum Mnemonic {
+
+Mnemonic_NULL=0, Mnemonic_Null=Mnemonic_NULL,
+Mnemonic_ADC, // Add with Carry
+Mnemonic_ADD, // Add
+Mnemonic_ADDSD, // Add Scalar Double-Precision Floating-Point Values
+Mnemonic_ADDSS, // Add Scalar Single-Precision Floating-Point Values
+Mnemonic_AND, // Logical AND
+
+Mnemonic_BSF, // Bit scan forward
+Mnemonic_BSR, // Bit scan reverse
+
+Mnemonic_CALL, // Call Procedure
+Mnemonic_CMC, // Complement Carry Flag
+Mnemonic_CWD, Mnemonic_CDQ=Mnemonic_CWD,// Convert Word to Doubleword/Convert Doubleword to Qua T dword
+Mnemonic_CMOVcc, // Conditional Move
+ CCM(CMOV,O),
+ CCM(CMOV,NO),
+ CCM(CMOV,B), CCM(CMOV,NAE), CCM(CMOV,C),
+ CCM(CMOV,NB), CCM(CMOV,AE), CCM(CMOV,NC),
+ CCM(CMOV,Z), CCM(CMOV,E),
+ CCM(CMOV,NZ), CCM(CMOV,NE),
+ CCM(CMOV,BE), CCM(CMOV,NA),
+ CCM(CMOV,NBE), CCM(CMOV,A),
+
+ CCM(CMOV,S),
+ CCM(CMOV,NS),
+ CCM(CMOV,P), CCM(CMOV,PE),
+ CCM(CMOV,NP), CCM(CMOV,PO),
+ CCM(CMOV,L), CCM(CMOV,NGE),
+ CCM(CMOV,NL), CCM(CMOV,GE),
+ CCM(CMOV,LE), CCM(CMOV,NG),
+ CCM(CMOV,NLE), CCM(CMOV,G),
+
+Mnemonic_CMP, // Compare Two Operands
+Mnemonic_CMPXCHG, // Compare and exchange
+Mnemonic_CMPXCHG8B, // Compare and Exchange 8 Bytes
+Mnemonic_CMPSB, // Compare Two Bytes at DS:ESI and ES:EDI
+Mnemonic_CMPSW, // Compare Two Words at DS:ESI and ES:EDI
+Mnemonic_CMPSD, // Compare Two Doublewords at DS:ESI and ES:EDI
+//
+// double -> float
+Mnemonic_CVTSD2SS, // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value
+// double -> I_32
+Mnemonic_CVTSD2SI, // Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer
+// double [truncated] -> I_32
+Mnemonic_CVTTSD2SI, // Convert with Truncation Scalar Double-Precision Floating-Point Value to Signed Doubleword Integer
+//
+// float -> double
+Mnemonic_CVTSS2SD, // Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value
+// float -> I_32
+Mnemonic_CVTSS2SI, // Convert Scalar Single-Precision Floating-Point Value to Doubleword Integer
+// float [truncated] -> I_32
+Mnemonic_CVTTSS2SI, // Convert with Truncation Scalar Single-Precision Floating-Point Value to Doubleword Integer
+//
+// I_32 -> double
+Mnemonic_CVTSI2SD, // Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value
+// I_32 -> float
+Mnemonic_CVTSI2SS, // Convert Doubleword Integer to Scalar Single-Precision Floating-Point Value
+
+Mnemonic_COMISD, // Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS
+Mnemonic_COMISS, // Compare Scalar Ordered Single-Precision Floating-Point Values and Set EFLAGS
+Mnemonic_DEC, // Decrement by 1
+//Mnemonic_DIV, // Unsigned Divide
+Mnemonic_DIVSD, // Divide Scalar Double-Precision Floating-Point Values
+Mnemonic_DIVSS, // Divide Scalar Single-Precision Floating-Point Values
+
+#ifdef _HAVE_MMX_
+Mnemonic_EMMS, // Empty MMX Technology State
+#endif
+
+Mnemonic_ENTER, // ENTER-Make Stack Frame for Procedure Parameters
+Mnemonic_FLDCW, // Load FPU control word
+Mnemonic_FADDP,
+Mnemonic_FLDZ,
+Mnemonic_FADD,
+Mnemonic_FSUBP,
+Mnemonic_FSUB,
+Mnemonic_FISUB,
+Mnemonic_FMUL,
+Mnemonic_FMULP,
+Mnemonic_FDIVP,
+Mnemonic_FDIV,
+Mnemonic_FUCOMPP,
+Mnemonic_FRNDINT,
+Mnemonic_FNSTCW, // Store FPU control word
+Mnemonic_FSTSW, // Store FPU status word
+Mnemonic_FNSTSW, // Store FPU status word
+//Mnemonic_FDECSTP, // Decrement Stack-Top Pointer
+Mnemonic_FILD, // Load Integer
+Mnemonic_FLD, // Load Floating Point Value
+Mnemonic_FLDLG2,
+Mnemonic_FLDLN2,
+Mnemonic_FLD1,
+
+Mnemonic_FCLEX, // Clear Exceptions
+Mnemonic_FCHS, // Change sign of ST0
+Mnemonic_FNCLEX, // Clear Exceptions
+
+//Mnemonic_FINCSTP, // Increment Stack-Top Pointer
+Mnemonic_FIST, // Store Integer
+Mnemonic_FISTP, // Store Integer, pop FPU stack
+Mnemonic_FISTTP, // Store Integer with Truncation
+Mnemonic_FPREM, // Partial Remainder
+Mnemonic_FPREM1, // Partial Remainder
+Mnemonic_FST, // Store Floating Point Value
+Mnemonic_FSTP, // Store Floating Point Value and pop the FP stack
+Mnemonic_FSQRT, //Computes the square root of the source value in the stack and pop the FP stack
+Mnemonic_FABS, //Computes the absolute value of the source value in the stack and pop the FP stack
+Mnemonic_FSIN, //Computes the sine of the source value in the stack and pop the FP stack
+Mnemonic_FCOS, //Computes the cosine of the source value in the stack and pop the FP stack
+Mnemonic_FPTAN, //Computes the tangent of the source value in the stack and pop the FP stack
+Mnemonic_FYL2X,
+Mnemonic_FYL2XP1,
+Mnemonic_F2XM1,
+Mnemonic_FPATAN,
+Mnemonic_FXCH,
+Mnemonic_FSCALE,
+
+Mnemonic_XCHG,
+Mnemonic_DIV, // Unsigned Divide
+Mnemonic_IDIV, // Signed Divide
+Mnemonic_MUL, // Unsigned Multiply
+Mnemonic_IMUL, // Signed Multiply
+Mnemonic_INC, // Increment by 1
+Mnemonic_INT3, // Call break point
+Mnemonic_Jcc, // Jump if Condition Is Met
+ CCM(J,O),
+ CCM(J,NO),
+ CCM(J,B), CCM(J,NAE), CCM(J,C),
+ CCM(J,NB), CCM(J,AE), CCM(J,NC),
+ CCM(J,Z), CCM(J,E),
+ CCM(J,NZ), CCM(J,NE),
+ CCM(J,BE), CCM(J,NA),
+ CCM(J,NBE), CCM(J,A),
+ CCM(J,S),
+ CCM(J,NS),
+ CCM(J,P), CCM(J,PE),
+ CCM(J,NP), CCM(J,PO),
+ CCM(J,L), CCM(J,NGE),
+ CCM(J,NL), CCM(J,GE),
+ CCM(J,LE), CCM(J,NG),
+ CCM(J,NLE), CCM(J,G),
+Mnemonic_JMP, // Jump
+Mnemonic_LEA, // Load Effective Address
+Mnemonic_LEAVE, // High Level Procedure Exit
+Mnemonic_LOOP, // Loop according to ECX counter
+Mnemonic_LOOPE, // Loop according to ECX counter
+Mnemonic_LOOPNE, Mnemonic_LOOPNZ = Mnemonic_LOOPNE, // Loop according to ECX
+Mnemonic_LAHF, // Load Flags into AH
+Mnemonic_MOV, // Move
+Mnemonic_MOVD, // Move Double word
+Mnemonic_MOVQ, // Move Quadword
+/*Mnemonic_MOVS, // Move Data from String to String*/
+// MOVS is a special case: see encoding table for more details,
+Mnemonic_MOVS8, Mnemonic_MOVS16, Mnemonic_MOVS32, Mnemonic_MOVS64,
+//
+Mnemonic_MOVAPD, // Move Scalar Double-Precision Floating-Point Value
+Mnemonic_MOVSD, // Move Scalar Double-Precision Floating-Point Value
+Mnemonic_MOVSS, // Move Scalar Single-Precision Floating-Point Values
+Mnemonic_MOVSX, // Move with Sign-Extension
+Mnemonic_MOVZX, // Move with Zero-Extend
+//Mnemonic_MUL, // Unsigned Multiply
+Mnemonic_MULSD, // Multiply Scalar Double-Precision Floating-Point Values
+Mnemonic_MULSS, // Multiply Scalar Single-Precision Floating-Point Values
+Mnemonic_NEG, // Two's Complement Negation
+Mnemonic_NOP, // No Operation
+Mnemonic_NOT, // One's Complement Negation
+Mnemonic_OR, // Logical Inclusive OR
+Mnemonic_PREFETCH, // prefetch
+
+#ifdef _HAVE_MMX_
+ Mnemonic_PADDQ, // Add Packed Quadword Integers
+ Mnemonic_PAND, // Logical AND
+ Mnemonic_POR, // Bitwise Logical OR
+ Mnemonic_PSUBQ, // Subtract Packed Quadword Integers
+#endif
+
+Mnemonic_PXOR, // Logical Exclusive OR
+Mnemonic_POP, // Pop a Value from the Stack
+Mnemonic_POPFD, // Pop a Value of EFLAGS register from the Stack
+Mnemonic_PUSH, // Push Word or Doubleword Onto the Stack
+Mnemonic_PUSHFD, // Push EFLAGS Doubleword Onto the Stack
+Mnemonic_RET, // Return from Procedure
+
+Mnemonic_SETcc, // Set Byte on Condition
+ CCM(SET,O),
+ CCM(SET,NO),
+ CCM(SET,B), CCM(SET,NAE), CCM(SET,C),
+ CCM(SET,NB), CCM(SET,AE), CCM(SET,NC),
+ CCM(SET,Z), CCM(SET,E),
+ CCM(SET,NZ), CCM(SET,NE),
+ CCM(SET,BE), CCM(SET,NA),
+ CCM(SET,NBE), CCM(SET,A),
+ CCM(SET,S),
+ CCM(SET,NS),
+ CCM(SET,P), CCM(SET,PE),
+ CCM(SET,NP), CCM(SET,PO),
+ CCM(SET,L), CCM(SET,NGE),
+ CCM(SET,NL), CCM(SET,GE),
+ CCM(SET,LE), CCM(SET,NG),
+ CCM(SET,NLE), CCM(SET,G),
+
+Mnemonic_SAL, Mnemonic_SHL=Mnemonic_SAL,// Shift left
+Mnemonic_SAR, // Shift right
+Mnemonic_ROR, // Rotate right
+Mnemonic_RCR, // Rotate right through CARRY flag
+Mnemonic_ROL, // Rotate left
+Mnemonic_RCL, // Rotate left through CARRY flag
+Mnemonic_SHR, // Unsigned shift right
+Mnemonic_SHRD, // Double Precision Shift Right
+Mnemonic_SHLD, // Double Precision Shift Left
+
+Mnemonic_SBB, // Integer Subtraction with Borrow
+Mnemonic_SUB, // Subtract
+Mnemonic_SUBSD, // Subtract Scalar Double-Precision Floating-Point Values
+Mnemonic_SUBSS, // Subtract Scalar Single-Precision Floating-Point Values
+
+Mnemonic_TEST, // Logical Compare
+
+Mnemonic_UCOMISD, // Unordered Compare Scalar Double-Precision Floating-Point Values and Set EFLAGS
+Mnemonic_UCOMISS, // Unordered Compare Scalar Single-Precision Floating-Point Values and Set EFLAGS
+
+Mnemonic_XOR, // Logical Exclusive OR
+//
+// packed things,
+//
+Mnemonic_XORPD, // Bitwise Logical XOR for Double-Precision Floating-Point Values
+Mnemonic_XORPS, // Bitwise Logical XOR for Single-Precision Floating-Point Values
+
+Mnemonic_CVTDQ2PD, // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values
+Mnemonic_CVTTPD2DQ, // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers
+
+Mnemonic_CVTDQ2PS, // Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values
+Mnemonic_CVTTPS2DQ, // Convert with Truncation Packed Single-Precision Floating-Point Values to Packed Doubleword Integers
+//
+// String operations
+//
+Mnemonic_STD, // Set direction flag
+Mnemonic_CLD, // Clear direction flag
+Mnemonic_SCAS, // Scan string
+Mnemonic_STOS, // Store string
+
+//
+Mnemonic_WAIT, // Check pending pending unmasked floating-point exception
+//
+Mnemonic_Count
+};
+
+#undef CCM
+#endif
+
+/**
+ * @brief Instruction prefixes, according to arch manual.
+ */
+typedef enum InstPrefix {
+ InstPrefix_Null = 0,
+ // Group 1
+ InstPrefix_LOCK = 0xF0,
+ InstPrefix_REPNE = 0xF2,
+ InstPrefix_REPNZ = InstPrefix_REPNE,
+ InstPrefix_REP = 0xF3, InstPrefix_REPZ = InstPrefix_REP,
+ // Group 2
+ InstPrefix_CS = 0x2E,
+ InstPrefix_SS = 0x36,
+ InstPrefix_DS = 0x3E,
+ InstPrefix_ES = 0x26,
+ InstPrefix_FS = 0x64,
+ InstPrefix_GS = 0x65,
+ //
+ InstPrefix_HintTaken = 0x3E,
+ InstPrefix_HintNotTaken = 0x2E,
+ // Group 3
+ InstPrefix_OpndSize = 0x66,
+ // Group 4
+ InstPrefix_AddrSize = 0x67
+} InstPrefix;
+
+inline unsigned getSizeBytes(OpndSize sz)
+{
+ if (sz==OpndSize_64) { return 8; }
+ if (sz==OpndSize_32) { return 4; }
+ if (sz==OpndSize_16) { return 2; }
+ if (sz==OpndSize_8) { return 1; }
+ assert(false);
+ return 0;
+}
+
+inline bool isRegKind(OpndKind kind)
+{
+ return OpndKind_GPReg<= kind && kind<=OpndKind_MaxRegKind;
+}
+
+/**
+ * @brief Returns #RegName for a given name.
+ *
+ * Name is case-insensitive.
+ * @param regname - string name of a register
+ * @return #RegName for the given name, or #RegName_Null if name is invalid
+ */
+RegName getRegName(const char * regname);
+/**
+ * Constructs RegName from the given OpndKind, size and index.
+ */
+inline RegName getRegName(OpndKind k, OpndSize s, int idx)
+{
+ return (RegName)REGNAME(k,s,idx);
+}
+/**
+ * Extracts a bit mask with a bit set at the position of the register's index.
+ */
+inline unsigned getRegMask(RegName reg)
+{
+ return 1<<(reg&0xff);
+}
+/**
+ * @brief Extracts #RegKind from the #RegName.
+ */
+inline OpndKind getRegKind(RegName reg)
+{
+ return (OpndKind)(reg>>24);
+}
+/**
+ * @brief Extracts #OpndSize from #RegName.
+ */
+inline OpndSize getRegSize(RegName reg)
+{
+ return (OpndSize)((reg>>16)&0xFF);
+}
+/**
+ * Extracts an index from the given RegName.
+ */
+inline unsigned char getRegIndex(RegName reg)
+{
+ return (unsigned char)(reg&0xFF);
+}
+/**
+ * Returns a string name of the given RegName. The name returned is in upper-case.
+ * Returns NULL if invalid RegName specified.
+ */
+const char * getRegNameString(RegName reg);
+/**
+ * Returns string name of a given OpndSize.
+ * Returns NULL if invalid OpndSize passed.
+ */
+const char * getOpndSizeString(OpndSize size);
+/**
+ * Returns OpndSize passed by its string representation (case insensitive).
+ * Returns OpndSize_Null if invalid string specified.
+ * The 'sizeString' can not be NULL.
+ */
+OpndSize getOpndSize(const char * sizeString);
+/**
+ * Returns string name of a given OpndKind.
+ * Returns NULL if the passed kind is invalid.
+ */
+const char * getOpndKindString(OpndKind kind);
+/**
+ * Returns OpndKind found by its string representation (case insensitive).
+ * Returns OpndKind_Null if the name is invalid.
+ * The 'kindString' can not be NULL.
+ */
+OpndKind getOpndKind(const char * kindString);
+/**
+ *
+ */
+const char * getConditionString(ConditionMnemonic cm);
+
+/**
+ * Constructs an RegName with the same index and kind, but with a different size from
+ * the given RegName (i.e. getRegAlias(EAX, OpndSize_16) => AX; getRegAlias(BL, OpndSize_32) => EBX).
+ * The constructed RegName is not checked in any way and thus may be invalid.
+ * Note, that the aliasing does not work for at least AH,BH,CH,DH, ESI, EDI, ESP and EBP regs.
+ */
+inline RegName getAliasReg(RegName reg, OpndSize sz)
+{
+ return (RegName)REGNAME(getRegKind(reg), sz, getRegIndex(reg));
+}
+
+/**
+ * brief Tests two RegName-s of the same kind for equality.
+ *
+ * @note Does work for 8 bit general purpose registers (AH, AL, BH, BL, etc).
+ */
+inline bool equals(RegName r0, RegName r1)
+{
+ return getRegKind(r0) == getRegKind(r1) &&
+ getRegIndex(r0) == getRegIndex(r1);
+}
+
+ENCODER_NAMESPACE_END
+
+#endif // ifndef _ENCODER_DEFS_H_
diff --git a/vm/compiler/codegen/x86/libenc/enc_defs_ext.h b/vm/compiler/codegen/x86/libenc/enc_defs_ext.h
new file mode 100644
index 0000000..3592513
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/enc_defs_ext.h
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ENCODER_DEFS_EXT_H_
+#define _ENCODER_DEFS_EXT_H_
+
+
+// Used to isolate experimental or being tuned encoder into a separate
+// namespace so it can coexist with a stable one in the same bundle.
+#ifdef ENCODER_ISOLATE
+ #define ENCODER_NAMESPACE_START namespace enc_ia32 {
+ #define ENCODER_NAMESPACE_END };
+#else
+ #define ENCODER_NAMESPACE_START
+ #define ENCODER_NAMESPACE_END
+#endif
+
+ENCODER_NAMESPACE_START
+typedef enum OpndSize {
+ /**
+ * A change must be balanced with at least the following places:
+ * Ia32IRConstants.h :: getByteSize() uses some presumptions about OpndSize_ values
+ * Ia32::Constraint-s use the OpndSize as a mask
+ * encoder.cpp & encoder_master_info.cpp uses OpndSize as an index for hashing
+ * - perhaps there are much more places
+ */
+ OpndSize_Null = 0,
+ OpndSize_8 = 0x01,
+ OpndSize_16 = 0x02,
+ OpndSize_32 = 0x04,
+ OpndSize_64 = 0x08,
+#if !defined(TESTING_ENCODER)
+ OpndSize_80 = 0x10,
+ OpndSize_128 = 0x20,
+#endif
+ OpndSize_Max,
+ OpndSize_Any = 0x3F,
+ OpndSize_Default = OpndSize_Any
+} OpndSize;
+
+/**
+ * Conditional mnemonics.
+ * The values match the 'real' (==processor's) values of the appropriate
+ * condition values used in the opcodes.
+ */
+typedef enum ConditionMnemonic {
+
+ ConditionMnemonic_O=0,
+ ConditionMnemonic_NO=1,
+ ConditionMnemonic_B=2, ConditionMnemonic_NAE=ConditionMnemonic_B, ConditionMnemonic_C=ConditionMnemonic_B,
+ ConditionMnemonic_NB=3, ConditionMnemonic_AE=ConditionMnemonic_NB, ConditionMnemonic_NC=ConditionMnemonic_NB,
+ ConditionMnemonic_Z=4, ConditionMnemonic_E=ConditionMnemonic_Z,
+ ConditionMnemonic_NZ=5, ConditionMnemonic_NE=ConditionMnemonic_NZ,
+ ConditionMnemonic_BE=6, ConditionMnemonic_NA=ConditionMnemonic_BE,
+ ConditionMnemonic_NBE=7, ConditionMnemonic_A=ConditionMnemonic_NBE,
+
+ ConditionMnemonic_S=8,
+ ConditionMnemonic_NS=9,
+ ConditionMnemonic_P=10, ConditionMnemonic_PE=ConditionMnemonic_P,
+ ConditionMnemonic_NP=11, ConditionMnemonic_PO=ConditionMnemonic_NP,
+ ConditionMnemonic_L=12, ConditionMnemonic_NGE=ConditionMnemonic_L,
+ ConditionMnemonic_NL=13, ConditionMnemonic_GE=ConditionMnemonic_NL,
+ ConditionMnemonic_LE=14, ConditionMnemonic_NG=ConditionMnemonic_LE,
+ ConditionMnemonic_NLE=15, ConditionMnemonic_G=ConditionMnemonic_NLE,
+ ConditionMnemonic_Count=16
+} ConditionMnemonic;
+
+
+#define CCM(prefix,cond) Mnemonic_##prefix##cond=Mnemonic_##prefix##cc+ConditionMnemonic_##cond
+
+//=========================================================================================================
+typedef enum Mnemonic {
+
+Mnemonic_NULL=0, Mnemonic_Null=Mnemonic_NULL,
+Mnemonic_ADC, // Add with Carry
+Mnemonic_ADD, // Add
+Mnemonic_ADDSD, // Add Scalar Double-Precision Floating-Point Values
+Mnemonic_ADDSS, // Add Scalar Single-Precision Floating-Point Values
+Mnemonic_AND, // Logical AND
+
+Mnemonic_BSF, // Bit scan forward
+Mnemonic_BSR, // Bit scan reverse
+
+Mnemonic_CALL, // Call Procedure
+Mnemonic_CMC, // Complement Carry Flag
+Mnemonic_CWD, Mnemonic_CDQ=Mnemonic_CWD,// Convert Word to Doubleword/Convert Doubleword to Qua T dword
+Mnemonic_CMOVcc, // Conditional Move
+ CCM(CMOV,O),
+ CCM(CMOV,NO),
+ CCM(CMOV,B), CCM(CMOV,NAE), CCM(CMOV,C),
+ CCM(CMOV,NB), CCM(CMOV,AE), CCM(CMOV,NC),
+ CCM(CMOV,Z), CCM(CMOV,E),
+ CCM(CMOV,NZ), CCM(CMOV,NE),
+ CCM(CMOV,BE), CCM(CMOV,NA),
+ CCM(CMOV,NBE), CCM(CMOV,A),
+
+ CCM(CMOV,S),
+ CCM(CMOV,NS),
+ CCM(CMOV,P), CCM(CMOV,PE),
+ CCM(CMOV,NP), CCM(CMOV,PO),
+ CCM(CMOV,L), CCM(CMOV,NGE),
+ CCM(CMOV,NL), CCM(CMOV,GE),
+ CCM(CMOV,LE), CCM(CMOV,NG),
+ CCM(CMOV,NLE), CCM(CMOV,G),
+
+Mnemonic_CMP, // Compare Two Operands
+Mnemonic_CMPXCHG, // Compare and exchange
+Mnemonic_CMPXCHG8B, // Compare and Exchange 8 Bytes
+Mnemonic_CMPSB, // Compare Two Bytes at DS:ESI and ES:EDI
+Mnemonic_CMPSW, // Compare Two Words at DS:ESI and ES:EDI
+Mnemonic_CMPSD, // Compare Two Doublewords at DS:ESI and ES:EDI
+//
+// double -> float
+Mnemonic_CVTSD2SS, // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value
+// double -> I_32
+Mnemonic_CVTSD2SI, // Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer
+// double [truncated] -> I_32
+Mnemonic_CVTTSD2SI, // Convert with Truncation Scalar Double-Precision Floating-Point Value to Signed Doubleword Integer
+//
+// float -> double
+Mnemonic_CVTSS2SD, // Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value
+// float -> I_32
+Mnemonic_CVTSS2SI, // Convert Scalar Single-Precision Floating-Point Value to Doubleword Integer
+// float [truncated] -> I_32
+Mnemonic_CVTTSS2SI, // Convert with Truncation Scalar Single-Precision Floating-Point Value to Doubleword Integer
+//
+// I_32 -> double
+Mnemonic_CVTSI2SD, // Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value
+// I_32 -> float
+Mnemonic_CVTSI2SS, // Convert Doubleword Integer to Scalar Single-Precision Floating-Point Value
+
+Mnemonic_COMISD, // Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS
+Mnemonic_COMISS, // Compare Scalar Ordered Single-Precision Floating-Point Values and Set EFLAGS
+Mnemonic_DEC, // Decrement by 1
+//Mnemonic_DIV, // Unsigned Divide
+Mnemonic_DIVSD, // Divide Scalar Double-Precision Floating-Point Values
+Mnemonic_DIVSS, // Divide Scalar Single-Precision Floating-Point Values
+
+#ifdef _HAVE_MMX_
+Mnemonic_EMMS, // Empty MMX Technology State
+#endif
+
+Mnemonic_ENTER, // ENTER-Make Stack Frame for Procedure Parameters
+Mnemonic_FLDCW, // Load FPU control word
+Mnemonic_FADDP,
+Mnemonic_FLDZ,
+Mnemonic_FADD,
+Mnemonic_FSUBP,
+Mnemonic_FSUB,
+Mnemonic_FISUB,
+Mnemonic_FMUL,
+Mnemonic_FMULP,
+Mnemonic_FDIVP,
+Mnemonic_FDIV,
+Mnemonic_FUCOM,
+Mnemonic_FUCOMI,
+Mnemonic_FUCOMP,
+Mnemonic_FUCOMIP,
+Mnemonic_FUCOMPP,
+Mnemonic_FRNDINT,
+Mnemonic_FNSTCW, // Store FPU control word
+Mnemonic_FSTSW, // Store FPU status word
+Mnemonic_FNSTSW, // Store FPU status word
+//Mnemonic_FDECSTP, // Decrement Stack-Top Pointer
+Mnemonic_FILD, // Load Integer
+Mnemonic_FLD, // Load Floating Point Value
+Mnemonic_FLDLG2,
+Mnemonic_FLDLN2,
+Mnemonic_FLD1,
+
+Mnemonic_FCLEX, // Clear Exceptions
+Mnemonic_FCHS, // Change sign of ST0
+Mnemonic_FNCLEX, // Clear Exceptions
+
+//Mnemonic_FINCSTP, // Increment Stack-Top Pointer
+Mnemonic_FIST, // Store Integer
+Mnemonic_FISTP, // Store Integer, pop FPU stack
+Mnemonic_FISTTP, // Store Integer with Truncation
+Mnemonic_FPREM, // Partial Remainder
+Mnemonic_FPREM1, // Partial Remainder
+Mnemonic_FST, // Store Floating Point Value
+Mnemonic_FSTP, // Store Floating Point Value and pop the FP stack
+Mnemonic_FSQRT, //Computes the square root of the source value in the stack and pop the FP stack
+Mnemonic_FABS, //Computes the absolute value of the source value in the stack and pop the FP stack
+Mnemonic_FSIN, //Computes the sine of the source value in the stack and pop the FP stack
+Mnemonic_FCOS, //Computes the cosine of the source value in the stack and pop the FP stack
+Mnemonic_FPTAN, //Computes the tangent of the source value in the stack and pop the FP stack
+Mnemonic_FYL2X,
+Mnemonic_FYL2XP1,
+Mnemonic_F2XM1,
+Mnemonic_FPATAN,
+Mnemonic_FXCH,
+Mnemonic_FSCALE,
+
+Mnemonic_XCHG,
+Mnemonic_DIV, // Unsigned Divide
+Mnemonic_IDIV, // Signed Divide
+Mnemonic_MUL, // Unsigned Multiply
+Mnemonic_IMUL, // Signed Multiply
+Mnemonic_INC, // Increment by 1
+Mnemonic_INT3, // Call break point
+Mnemonic_Jcc, // Jump if Condition Is Met
+ CCM(J,O),
+ CCM(J,NO),
+ CCM(J,B), CCM(J,NAE), CCM(J,C),
+ CCM(J,NB), CCM(J,AE), CCM(J,NC),
+ CCM(J,Z), CCM(J,E),
+ CCM(J,NZ), CCM(J,NE),
+ CCM(J,BE), CCM(J,NA),
+ CCM(J,NBE), CCM(J,A),
+ CCM(J,S),
+ CCM(J,NS),
+ CCM(J,P), CCM(J,PE),
+ CCM(J,NP), CCM(J,PO),
+ CCM(J,L), CCM(J,NGE),
+ CCM(J,NL), CCM(J,GE),
+ CCM(J,LE), CCM(J,NG),
+ CCM(J,NLE), CCM(J,G),
+Mnemonic_JMP, // Jump
+Mnemonic_LEA, // Load Effective Address
+Mnemonic_LEAVE, // High Level Procedure Exit
+Mnemonic_LOOP, // Loop according to ECX counter
+Mnemonic_LOOPE, // Loop according to ECX counter
+Mnemonic_LOOPNE, Mnemonic_LOOPNZ = Mnemonic_LOOPNE, // Loop according to ECX
+Mnemonic_LAHF, // Load Flags into AH
+Mnemonic_MOV, // Move
+Mnemonic_MOVD, // Move Double word
+Mnemonic_MOVQ, // Move Quadword
+/*Mnemonic_MOVS, // Move Data from String to String*/
+// MOVS is a special case: see encoding table for more details,
+Mnemonic_MOVS8, Mnemonic_MOVS16, Mnemonic_MOVS32, Mnemonic_MOVS64,
+//
+Mnemonic_MOVAPD, // Move Scalar Double-Precision Floating-Point Value
+Mnemonic_MOVSD, // Move Scalar Double-Precision Floating-Point Value
+Mnemonic_MOVSS, // Move Scalar Single-Precision Floating-Point Values
+Mnemonic_MOVSX, // Move with Sign-Extension
+Mnemonic_MOVZX, // Move with Zero-Extend
+//Mnemonic_MUL, // Unsigned Multiply
+Mnemonic_MULSD, // Multiply Scalar Double-Precision Floating-Point Values
+Mnemonic_MULSS, // Multiply Scalar Single-Precision Floating-Point Values
+Mnemonic_NEG, // Two's Complement Negation
+Mnemonic_NOP, // No Operation
+Mnemonic_NOT, // One's Complement Negation
+Mnemonic_OR, // Logical Inclusive OR
+Mnemonic_PREFETCH, // prefetch
+
+#if 1 //def _HAVE_MMX_
+ Mnemonic_PADDQ, // Add Packed Quadword Integers
+ Mnemonic_PAND, // Logical AND
+ Mnemonic_POR, // Bitwise Logical OR
+ Mnemonic_PSUBQ, // Subtract Packed Quadword Integers
+#endif
+Mnemonic_PANDN,
+Mnemonic_PSLLQ,
+Mnemonic_PSRLQ,
+Mnemonic_PXOR, // Logical Exclusive OR
+Mnemonic_POP, // Pop a Value from the Stack
+Mnemonic_POPFD, // Pop a Value of EFLAGS register from the Stack
+Mnemonic_PUSH, // Push Word or Doubleword Onto the Stack
+Mnemonic_PUSHFD, // Push EFLAGS Doubleword Onto the Stack
+Mnemonic_RET, // Return from Procedure
+
+Mnemonic_SETcc, // Set Byte on Condition
+ CCM(SET,O),
+ CCM(SET,NO),
+ CCM(SET,B), CCM(SET,NAE), CCM(SET,C),
+ CCM(SET,NB), CCM(SET,AE), CCM(SET,NC),
+ CCM(SET,Z), CCM(SET,E),
+ CCM(SET,NZ), CCM(SET,NE),
+ CCM(SET,BE), CCM(SET,NA),
+ CCM(SET,NBE), CCM(SET,A),
+ CCM(SET,S),
+ CCM(SET,NS),
+ CCM(SET,P), CCM(SET,PE),
+ CCM(SET,NP), CCM(SET,PO),
+ CCM(SET,L), CCM(SET,NGE),
+ CCM(SET,NL), CCM(SET,GE),
+ CCM(SET,LE), CCM(SET,NG),
+ CCM(SET,NLE), CCM(SET,G),
+
+Mnemonic_SAL, Mnemonic_SHL=Mnemonic_SAL,// Shift left
+Mnemonic_SAR, // Unsigned shift right
+Mnemonic_ROR, // Rotate right
+Mnemonic_RCR, // Rotate right through CARRY flag
+Mnemonic_ROL, // Rotate left
+Mnemonic_RCL, // Rotate left through CARRY flag
+Mnemonic_SHR, // Signed shift right
+Mnemonic_SHRD, // Double Precision Shift Right
+Mnemonic_SHLD, // Double Precision Shift Left
+
+Mnemonic_SBB, // Integer Subtraction with Borrow
+Mnemonic_SUB, // Subtract
+Mnemonic_SUBSD, // Subtract Scalar Double-Precision Floating-Point Values
+Mnemonic_SUBSS, // Subtract Scalar Single-Precision Floating-Point Values
+
+Mnemonic_TEST, // Logical Compare
+
+Mnemonic_UCOMISD, // Unordered Compare Scalar Double-Precision Floating-Point Values and Set EFLAGS
+Mnemonic_UCOMISS, // Unordered Compare Scalar Single-Precision Floating-Point Values and Set EFLAGS
+
+Mnemonic_XOR, // Logical Exclusive OR
+//
+// packed things,
+//
+Mnemonic_XORPD, // Bitwise Logical XOR for Double-Precision Floating-Point Values
+Mnemonic_XORPS, // Bitwise Logical XOR for Single-Precision Floating-Point Values
+
+Mnemonic_CVTDQ2PD, // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values
+Mnemonic_CVTTPD2DQ, // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers
+
+Mnemonic_CVTDQ2PS, // Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values
+Mnemonic_CVTTPS2DQ, // Convert with Truncation Packed Single-Precision Floating-Point Values to Packed Doubleword Integers
+//
+// String operations
+//
+Mnemonic_STD, // Set direction flag
+Mnemonic_CLD, // Clear direction flag
+Mnemonic_SCAS, // Scan string
+Mnemonic_STOS, // Store string
+
+//
+Mnemonic_WAIT, // Check pending pending unmasked floating-point exception
+//
+Mnemonic_Count
+} Mnemonic;
+
+#undef CCM
+
+ENCODER_NAMESPACE_END
+
+#endif // ifndef _ENCODER_DEFS_EXT_H_
diff --git a/vm/compiler/codegen/x86/libenc/enc_prvt.h b/vm/compiler/codegen/x86/libenc/enc_prvt.h
new file mode 100644
index 0000000..4300574
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/enc_prvt.h
@@ -0,0 +1,382 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+#ifndef __ENC_PRVT_H_INCLUDED__
+#define __ENC_PRVT_H_INCLUDED__
+
+#include "enc_base.h"
+
+ENCODER_NAMESPACE_START
+/*
+ * @file
+ * @brief Contains some definitions/constants and other stuff used by the
+ * Encoder internally.
+ */
+
+enum OpcodeByteKind {
+ //OpcodeByteKind_Opcode = 0x0000,
+ OpcodeByteKind_ZeroOpcodeByte = 0x0100,
+ //
+ // The names _SlashR, _SlahsNum, _ib, _iw, etc
+ // represent the appropriate abbreviations used
+ // in the mnemonic descriptions in the Intel's arch manual.
+ //
+ OpcodeByteKind_SlashR = 0x0200,
+ OpcodeByteKind_SlashNum = 0x0300,
+ OpcodeByteKind_ib = 0x0400,
+ OpcodeByteKind_iw = 0x0500,
+ OpcodeByteKind_id = 0x0600,
+#ifdef _EM64T_
+ OpcodeByteKind_io = 0x0700,
+#endif
+ OpcodeByteKind_cb = 0x0800,
+ OpcodeByteKind_cw = 0x0900,
+ OpcodeByteKind_cd = 0x0A00,
+ //OpcodeByteKind_cp = 0x0B00,
+ //OpcodeByteKind_co = 0x0C00,
+ //OpcodeByteKind_ct = 0x0D00,
+
+ OpcodeByteKind_rb = 0x0E00,
+ OpcodeByteKind_rw = 0x0F00,
+ OpcodeByteKind_rd = 0x1000,
+#ifdef _EM64T_
+ OpcodeByteKind_ro = 0x1100,
+ //OpcodeByteKind_REX = 0x1200,
+ OpcodeByteKind_REX_W = 0x1300,
+#endif
+ OpcodeByteKind_plus_i = 0x1400,
+ /**
+ * a special marker, means 'no opcode on the given position'
+ * used in opcodes array, to specify the empty slot, say
+ * to fill an em64t-specific opcode on ia32.
+ * last 'e' made lowercase to avoid a mess with 'F' in
+ * OpcodeByteKind_LAST .
+ */
+ OpcodeByteKind_EMPTY = 0xFFFE,
+ /**
+ * a special marker, means 'no more opcodes in the array'
+ * used in in opcodes array to show that there are no more
+ * opcodes in the array for a given mnemonic.
+ */
+ OpcodeByteKind_LAST = 0xFFFF,
+ /**
+ * a mask to extract the OpcodeByteKind
+ */
+ OpcodeByteKind_KindMask = 0xFF00,
+ /**
+ * a mask to extract the opcode byte when presented
+ */
+ OpcodeByteKind_OpcodeMask = 0x00FF
+};
+
+#ifdef USE_ENCODER_DEFINES
+
+#define N {0, 0, 0, 0 }
+#define U {1, 0, 1, OpndRole_Use }
+#define D {1, 1, 0, OpndRole_Def }
+#define DU {1, 1, 1, OpndRole_Def|OpndRole_Use }
+
+#define U_U {2, 0, 2, OpndRole_Use<<2 | OpndRole_Use }
+#define D_U {2, 1, 1, OpndRole_Def<<2 | OpndRole_Use }
+#define D_DU {2, 2, 1, OpndRole_Def<<2 | (OpndRole_Def|OpndRole_Use) }
+#define DU_U {2, 1, 2, ((OpndRole_Def|OpndRole_Use)<<2 | OpndRole_Use) }
+#define DU_DU {2, 2, 2, ((OpndRole_Def|OpndRole_Use)<<2 | (OpndRole_Def|OpndRole_Use)) }
+
+#define DU_DU_DU {3, 3, 3, ((OpndRole_Def|OpndRole_Use)<<4) | ((OpndRole_Def|OpndRole_Use)<<2) | (OpndRole_Def|OpndRole_Use) }
+#define DU_DU_U {3, 2, 3, (((OpndRole_Def|OpndRole_Use)<<4) | ((OpndRole_Def|OpndRole_Use)<<2) | OpndRole_Use) }
+#define D_DU_U {3, 2, 2, (((OpndRole_Def)<<4) | ((OpndRole_Def|OpndRole_Use)<<2) | OpndRole_Use) }
+#define D_U_U {3, 1, 2, (((OpndRole_Def)<<4) | ((OpndRole_Use)<<2) | OpndRole_Use) }
+
+// Special encoding of 0x00 opcode byte. Note: it's all O-s, not zeros.
+#define OxOO OpcodeByteKind_ZeroOpcodeByte
+
+#define Size16 InstPrefix_OpndSize
+
+#define _r OpcodeByteKind_SlashR
+
+#define _0 OpcodeByteKind_SlashNum|0
+#define _1 OpcodeByteKind_SlashNum|1
+#define _2 OpcodeByteKind_SlashNum|2
+#define _3 OpcodeByteKind_SlashNum|3
+#define _4 OpcodeByteKind_SlashNum|4
+#define _5 OpcodeByteKind_SlashNum|5
+#define _6 OpcodeByteKind_SlashNum|6
+#define _7 OpcodeByteKind_SlashNum|7
+
+// '+i' for floating-point instructions
+#define _i OpcodeByteKind_plus_i
+
+
+#define ib OpcodeByteKind_ib
+#define iw OpcodeByteKind_iw
+#define id OpcodeByteKind_id
+
+#define cb OpcodeByteKind_cb
+#define cw OpcodeByteKind_cw
+#define cd OpcodeByteKind_cd
+
+#define rb OpcodeByteKind_rb
+#define rw OpcodeByteKind_rw
+#define rd OpcodeByteKind_rd
+
+#define AL {OpndKind_GPReg, OpndSize_8, OpndExt_Any, RegName_AL}
+#define AH {OpndKind_GPReg, OpndSize_8, OpndExt_Any, RegName_AH}
+#define AX {OpndKind_GPReg, OpndSize_16, OpndExt_Any, RegName_AX}
+#define EAX {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_EAX}
+#ifdef _EM64T_
+ #define RAX {OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_RAX }
+#endif
+
+#define CL {OpndKind_GPReg, OpndSize_8, OpndExt_Any, RegName_CL}
+#define ECX {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_ECX}
+#ifdef _EM64T_
+ #define RCX {OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_RCX}
+#endif
+
+#define DX {OpndKind_GPReg, OpndSize_16, OpndExt_Any, RegName_DX}
+#define EDX {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_EDX}
+#ifdef _EM64T_
+ #define RDX { OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_RDX }
+#endif
+
+#define ESI {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_ESI}
+#ifdef _EM64T_
+ #define RSI { OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_RSI }
+#endif
+
+#define EDI {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_EDI}
+#ifdef _EM64T_
+ #define RDI { OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_RDI }
+#endif
+
+#define r8 {OpndKind_GPReg, OpndSize_8, OpndExt_Any, RegName_Null}
+#define r16 {OpndKind_GPReg, OpndSize_16, OpndExt_Any, RegName_Null}
+#define r32 {OpndKind_GPReg, OpndSize_32, OpndExt_Any, RegName_Null}
+#ifdef _EM64T_
+ #define r64 { OpndKind_GPReg, OpndSize_64, OpndExt_Any, RegName_Null }
+#endif
+
+#define r_m8 {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_8, OpndExt_Any, RegName_Null}
+#define r_m16 {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_16, OpndExt_Any, RegName_Null}
+#define r_m32 {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_32, OpndExt_Any, RegName_Null}
+
+#define r_m8s {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_8, OpndExt_Signed, RegName_Null}
+#define r_m16s {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_16, OpndExt_Signed, RegName_Null}
+#define r_m32s {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_32, OpndExt_Signed, RegName_Null}
+
+#define r_m8u {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_8, OpndExt_Zero, RegName_Null}
+#define r_m16u {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_16, OpndExt_Zero, RegName_Null}
+#define r_m32u {(OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_32, OpndExt_Zero, RegName_Null}
+
+//'m' was only used in LEA mnemonic, but is replaced with
+// set of exact sizes. See more comments for LEA instruction in TheTable.
+//#define m {OpndKind_Mem, OpndSize_Null, RegName_Null}
+#define m8 {OpndKind_Mem, OpndSize_8, OpndExt_Any, RegName_Null}
+#define m16 {OpndKind_Mem, OpndSize_16, OpndExt_Any, RegName_Null}
+#define m32 {OpndKind_Mem, OpndSize_32, OpndExt_Any, RegName_Null}
+#define m64 {OpndKind_Mem, OpndSize_64, OpndExt_Any, RegName_Null}
+#ifdef _EM64T_
+ #define r_m64 { (OpndKind)(OpndKind_GPReg|OpndKind_Mem), OpndSize_64, OpndExt_Any, RegName_Null }
+#endif
+
+#define imm8 {OpndKind_Imm, OpndSize_8, OpndExt_Any, RegName_Null}
+#define imm16 {OpndKind_Imm, OpndSize_16, OpndExt_Any, RegName_Null}
+#define imm32 {OpndKind_Imm, OpndSize_32, OpndExt_Any, RegName_Null}
+
+#define imm8s {OpndKind_Imm, OpndSize_8, OpndExt_Signed, RegName_Null}
+#define imm16s {OpndKind_Imm, OpndSize_16, OpndExt_Signed, RegName_Null}
+#define imm32s {OpndKind_Imm, OpndSize_32, OpndExt_Signed, RegName_Null}
+
+#define imm8u {OpndKind_Imm, OpndSize_8, OpndExt_Zero, RegName_Null}
+#define imm16u {OpndKind_Imm, OpndSize_16, OpndExt_Zero, RegName_Null}
+#define imm32u {OpndKind_Imm, OpndSize_32, OpndExt_Zero, RegName_Null}
+
+#ifdef _EM64T_
+ #define imm64 {OpndKind_Imm, OpndSize_64, OpndExt_Any, RegName_Null }
+#endif
+
+//FIXME: moff-s are in fact memory refs, but presented as immediate.
+// Need to specify this in OpndDesc.
+#define moff8 {OpndKind_Imm, OpndSize_32, OpndExt_Any, RegName_Null}
+#define moff16 {OpndKind_Imm, OpndSize_32, OpndExt_Any, RegName_Null}
+#define moff32 {OpndKind_Imm, OpndSize_32, OpndExt_Any, RegName_Null}
+#ifdef _EM64T_
+ #define moff64 {OpndKind_Imm, OpndSize_64, OpndExt_Any, RegName_Null}
+#endif
+
+
+#define rel8 {OpndKind_Imm, OpndSize_8, OpndExt_Any, RegName_Null}
+#define rel16 {OpndKind_Imm, OpndSize_16, OpndExt_Any, RegName_Null}
+#define rel32 {OpndKind_Imm, OpndSize_32, OpndExt_Any, RegName_Null}
+
+#define mm64 {OpndKind_MMXReg, OpndSize_64, OpndExt_Any, RegName_Null}
+#define mm_m64 {(OpndKind)(OpndKind_MMXReg|OpndKind_Mem), OpndSize_64, OpndExt_Any, RegName_Null}
+
+#define xmm64 {OpndKind_XMMReg, OpndSize_64, OpndExt_Any, RegName_Null}
+#define xmm_m64 {(OpndKind)(OpndKind_XMMReg|OpndKind_Mem), OpndSize_64, OpndExt_Any, RegName_Null}
+
+#define xmm32 {OpndKind_XMMReg, OpndSize_32, OpndExt_Any, RegName_Null}
+#define xmm_m32 {(OpndKind)(OpndKind_XMMReg|OpndKind_Mem), OpndSize_32, OpndExt_Any, RegName_Null}
+
+#define FP0S {OpndKind_FPReg, OpndSize_32, OpndExt_Any, RegName_FP0S}
+#define FP0D {OpndKind_FPReg, OpndSize_64, OpndExt_Any, RegName_FP0D}
+#define FP1S {OpndKind_FPReg, OpndSize_32, OpndExt_Any, RegName_FP1S}
+#define FP1D {OpndKind_FPReg, OpndSize_64, OpndExt_Any, RegName_FP1D}
+#define fp32 {OpndKind_FPReg, OpndSize_32, OpndExt_Any, RegName_Null}
+#define fp64 {OpndKind_FPReg, OpndSize_64, OpndExt_Any, RegName_Null}
+
+#ifdef _EM64T_
+ #define io OpcodeByteKind_io
+ #define REX_W OpcodeByteKind_REX_W
+
+#endif
+
+#endif // USE_ENCODER_DEFINES
+
+/**
+ * @brief Represents the REX part of instruction.
+ */
+struct Rex {
+ unsigned char b : 1;
+ unsigned char x : 1;
+ unsigned char r : 1;
+ unsigned char w : 1;
+ unsigned char dummy : 4; // must be '0100'b
+ unsigned int :24;
+};
+
+/**
+ * @brief Describes SIB (scale,index,base) byte.
+ */
+struct SIB {
+ unsigned char base:3;
+ unsigned char index:3;
+ unsigned char scale:2;
+ unsigned int padding:24;
+};
+/**
+ * @brief Describes ModRM byte.
+ */
+struct ModRM
+{
+ unsigned char rm:3;
+ unsigned char reg:3;
+ unsigned char mod:2;
+ unsigned int padding:24;
+};
+
+
+
+/**
+* exactly the same as EncoderBase::OpcodeDesc, but also holds info about
+* platform on which the opcode is applicable.
+*/
+struct OpcodeInfo {
+ enum platform {
+ /// an opcode is valid on all platforms
+ all,
+ // opcode is valid on IA-32 only
+ em64t,
+ // opcode is valid on Intel64 only
+ ia32,
+ // opcode is added for the sake of disassembling, should not be used in encoding
+ decoder,
+ // only appears in master table, replaced with 'decoder' in hashed version
+ decoder32,
+ // only appears in master table, replaced with 'decoder' in hashed version
+ decoder64,
+ };
+ platform platf;
+ unsigned opcode[4+1+1];
+ EncoderBase::OpndDesc opnds[3];
+ EncoderBase::OpndRolesDesc roles;
+};
+
+/**
+ * @defgroup MF_ Mnemonic flags
+*/
+
+ /**
+ * Operation has no special properties.
+ */
+#define MF_NONE (0x00000000)
+ /**
+ * Operation affects flags
+ */
+#define MF_AFFECTS_FLAGS (0x00000001)
+ /**
+ * Operation uses flags - conditional operations, ADC/SBB/ETC
+ */
+#define MF_USES_FLAGS (0x00000002)
+ /**
+ * Operation is conditional - MOVcc/SETcc/Jcc/ETC
+ */
+#define MF_CONDITIONAL (0x00000004)
+/**
+ * Operation is symmetric - its args can be swapped (ADD/MUL/etc).
+ */
+#define MF_SYMMETRIC (0x00000008)
+/**
+ * Operation is XOR-like - XOR, SUB - operations of 'arg,arg' is pure def,
+ * without use.
+ */
+#define MF_SAME_ARG_NO_USE (0x00000010)
+
+///@} // ~MNF
+
+/**
+ * @see same structure as EncoderBase::MnemonicDesc, but carries
+ * MnemonicInfo::OpcodeInfo[] instead of OpcodeDesc[].
+ * Only used during prebuilding the encoding tables, thus it's hidden under
+ * the appropriate define.
+ */
+struct MnemonicInfo {
+ /**
+ * The mnemonic itself
+ */
+ Mnemonic mn;
+ /**
+ * Various characteristics of mnemonic.
+ * @see MF_
+ */
+ unsigned flags;
+ /**
+ * Number of args/des/uses/roles for the operation. For the operations
+ * which may use different number of operands (i.e. IMUL/SHL) use the
+ * most common value, or leave '0' if you are sure this info is not
+ * required.
+ */
+ EncoderBase::OpndRolesDesc roles;
+ /**
+ * Print name of the mnemonic
+ */
+ const char * name;
+ /**
+ * Array of opcodes.
+ * The terminating opcode description always have OpcodeByteKind_LAST
+ * at the opcodes[i].opcode[0].
+ * The size of '25' has nothing behind it, just counted the max
+ * number of opcodes currently used (MOV instruction).
+ */
+ OpcodeInfo opcodes[25];
+};
+
+ENCODER_NAMESPACE_END
+
+#endif // ~__ENC_PRVT_H_INCLUDED__
diff --git a/vm/compiler/codegen/x86/libenc/enc_tabl.cpp b/vm/compiler/codegen/x86/libenc/enc_tabl.cpp
new file mode 100644
index 0000000..8a0789a
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/enc_tabl.cpp
@@ -0,0 +1,1975 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h> //qsort
+#include <string.h>
+#include <memory.h>
+#include <errno.h>
+#include <stdlib.h>
+
+
+// need to use EM64T-specifics - new registers, defines from enc_prvt, etc...
+#if !defined(_EM64T_)
+ #define UNDEF_EM64T
+ #define _EM64T_
+#endif
+
+#define USE_ENCODER_DEFINES
+#include "enc_prvt.h"
+#include "enc_defs.h"
+
+#ifdef UNDEF_EM64T
+ #undef _EM64T_
+#endif
+
+//Android x86
+#if 0 //!defined(_HAVE_MMX_)
+ #define Mnemonic_PADDQ Mnemonic_Null
+ #define Mnemonic_PAND Mnemonic_Null
+ #define Mnemonic_POR Mnemonic_Null
+ #define Mnemonic_PSUBQ Mnemonic_Null
+#endif
+
+ENCODER_NAMESPACE_START
+
+
+EncoderBase::MnemonicDesc EncoderBase::mnemonics[Mnemonic_Count];
+EncoderBase::OpcodeDesc EncoderBase::opcodes[Mnemonic_Count][MAX_OPCODES];
+unsigned char EncoderBase::opcodesHashMap[Mnemonic_Count][HASH_MAX];
+
+
+/**
+ * @file
+ * @brief 'Master' copy of encoding data.
+ */
+
+/*
+This file contains a 'master copy' of encoding table - this is the info used
+by both generator of native instructions (EncoderBase class) and by
+disassembling routines. The first one uses an info how to encode the
+instruction, and the second does an opposite - several separate tables are
+built at runtime from this main table.
+
+=============================================================================
+
+The table was designed for easy support and maintenance. Thus, it was made as
+much close as possible to the Intel's IA32 Architecture Manual descriptions.
+The info is based on the latest (at the moment of writing) revision which is
+June 2005, order number 253666-016.
+
+Normally, almost all of opcodes in the 'master' table represented exactly as
+they are shown in the Intel's Architecture manual (well, with slashes
+replaced with underscore). There are several exclusions especially marked.
+
+Normally, to add an opcode/instruction, one only need to copy the whole
+string from the manual, and simply replace '/' with '_'.
+
+I.e., TheManual reads for DEC:
+ (1) FE /1 DEC r/m8 Valid Valid Decrement r/m8 by 1.
+ (2) REX + FE /1 DEC r/m8* Valid N.E. Decrement r/m8 by 1.
+ (3) REX.W + FF /1 DEC r/m64 Valid N.E. Decrement r/m64 by 1.
+
+1. Note, that there is no need to explicitly specify REX-based opcodes for
+ instruction to handle additional registers on EM64T:
+
+ (1) FE /1 DEC r/m8 Valid Valid Decrement r/m8 by 1.
+ (3) REX.W + FF /1 DEC r/m64 Valid N.E. Decrement r/m64 by 1.
+
+2. Copy the string, strip off the text comments, replace '/'=>'_'. Note, that
+ the second line is for EM64T only
+
+ (1) FE /1 DEC r/m8
+ (3) REX.W + FF /1 DEC r/m64
+
+3. Fill out the mnemonic, opcode parameters parts
+
+ BEGIN_MNEMONIC(DEC, MF_AFFECTS_FLAGS, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xFE, _1}, {r_m8}, DU },
+ {OpcodeInfo::em64t, {REX_W, 0xFF, _1}, {r_m64}, DU },
+
+ DU here - one argument, it's used and defined
+
+4. That's it, that simple !
+
+The operand roles (DU here) are used by Jitrino's optimizing engine to
+perform data flow analysis. It also used to store/obtain number of operands.
+
+Special cases are (see the table for details):
+LEA
+Some FPU operations (i.e. FSTP)
+packed things (XORPD, XORPS, CVTDQ2PD, CVTTPD2DQ)
+
+Also, the Jitrino's needs require to specify all operands - including
+implicit ones (see IMUL).
+
+The master table iself does not need to be ordered - it's get sorted before
+processing. It's recommended (though it's not a law) to group similar
+instructions together - i.e. FPU instructions, MMX, etc.
+
+=============================================================================
+
+The encoding engine builds several tables basing on the 'master' one (here
+'mnemonic' is a kind of synonim for 'instruction'):
+
+- list of mnemonics which holds general info about instructions
+ (EncoderBase::mnemonics)
+- an array of opcodes descriptions (EncodeBase::opcodes)
+- a mapping between a hash value and an opcode description record for a given
+ mnemonic (EncoderBase::opcodesHashMap)
+
+The EncoderBase::mnemonics holds general info about instructions.
+The EncoderBase::opcodesHashMap is used for fast opcode selection basing on
+a hash value.
+The EncodeBase::opcodes is used for the encoding itself.
+
+=============================================================================
+The hash value is calculated and used as follows:
+
+JIT-ted code uses the following operand sizes: 8-, 16-, 32- and 64-bits and
+size for an operand can be encoded in just 2 bits.
+
+The following operand locations are available: one of registers - GP, FP,
+MMX, XMM (not taking segment registers), a memory and an immediate, which
+gives us 6 variants and can be enumerated in 3 bits.
+
+As a grand total, the the whole operand's info needed for opcode selection
+can be packed in 5 bits. Taking into account the IMUL mnemonic with its 3
+operands (including implicit ones), we're getting 15 bits per instruction and
+the complete table is about 32768 items per single instruction.
+
+Seems too many, but luckily, the 15 bit limit will never be reached: the
+worst case is IMUL with its 3 operands:
+(IMUL r64, r/m64, imm32)/(IMUL r32, r/m32, imm32).
+So, assigning lowest value to GP register, the max value of hash can be
+reduced.
+
+The hash values to use are:
+sizes:
+ 8 -> 11
+ 16 -> 10
+ 32 -> 01
+ 64 -> 00
+locations:
+ gp reg -> 000
+ memory -> 001
+ fp reg -> 010
+ mmx reg -> 011
+ xmm reg -> 100
+ immediate -> 101
+and the grand total for the worst case would be
+[ GP 32] [GP 32] [Imm 32]
+[000-01] [000-01] [101 01] = 1077
+
+However, the implicit operands adds additional value, and the worstest case
+is 'SHLD r_m32, r32, CL=r8'. This gives us the maximum number of:
+
+[mem 32] [GP 32] [GP 8b]
+[001-01] [000-01] [000-11] = 5155.
+
+The max number is pretty big and the hash functions is quite rare, thus it
+is not resonable to use a direct addressing i.e.
+OpcodeDesc[mnemonic][hash_code] - there would be a huge waste of space.
+
+Instead, we use a kind of mapping: the opcodes info is stored in packed
+(here: non rare) array. The max number of opcodes will not exceed 255 for
+each instruction. And we have an index array in which we store a mapping
+between a hash code value and opcode position for each given instruction.
+
+Sounds a bit sophisticated, but in real is simple, the opcode gets selected
+in 2 simple steps:
+
+1. Select [hash,mnemonic] => 'n'.
+
+The array is pretty rare - many cells contain 0xFF which
+means 'invalid hash - no opcode with given characteristics'
+
+char EnbcoderBase::opcodesHashMap[Mnemonic_Count][HASH_MAX] =
+
++----+----+----+----+----+----+
+| 00 | 05 | FF | FF | 03 | 12 | ...
+|---------+-------------------+
+| 12 | FF | FF | n | 04 | 25 | ... <- Mnemonic
+|-----------------------------+
+| FF | 11 | FF | 10 | 13 | .. | ...
++-----------------------------+
+ ... ^
+ |
+ hash
+
+2. Select [n,mnemonic] => 'opcode_desc11'
+
+OpcodeDesc EncoderBase::opcodes[Mnemonic_Count][MAX_OPCODES] =
+
++---------------+---------------+---------------+---------------+
+| opcode_desc00 | opcode_desc01 | opcode_desc02 | last_opcode | ...
++---------------+---------------+---------------+---------------+
+| opcode_desc10 | opcode_desc11 | last_opcode | xxx | <- Mnemonic
++---------------+---------------+---------------+---------------+
+| opcode_desc20 | opcode_desc21 | opcode_desc22 | opcode_desc23 | ...
++---------------+---------------+---------------+---------------+
+ ...
+ ^
+ |
+ n
+
+Now, use 'opcode_desc11'.
+
+=============================================================================
+The array of opcodes descriptions (EncodeBase::opcodes) is specially prepared
+to maximize performance - the EncoderBase::encode() is quite hot on client
+applications for the Jitrino/Jitrino.JET.
+The preparation is that opcode descriptions from the 'master' encoding table
+are preprocessed and a special set of OpcodeDesc prepared:
+First, the 'raw' opcode bytes are extracted. Here, 'raw' means the bytes that
+do not depened on any operands values, do not require any analysis and can be
+simply copied into the output buffer during encoding. Also, number of these
+'raw' bytes is counted. The fields are OpcodeDesc::opcode and
+OpcodeDesc::opcode_len.
+
+Then the fisrt non-implicit operand found and its index is stored in
+OpcodeDesc::first_opnd.
+
+The bytes that require processing and analysis ('/r', '+i', etc) are
+extracted and stored in OpcodeDesc::aux0 and OpcodeDesc::aux1 fields.
+
+Here, a special trick is performed:
+ Some opcodes have register/memory operand, but this is not reflected in
+ opcode column - for example, (MOVQ xmm64, xmm_m64). In this case, a fake
+ '_r' added to OpcodeDesc::aux field.
+ Some other opcodes have immediate operands, but this is again not
+ reflected in opcode column - for example, CALL cd or PUSH imm32.
+ In this case, a fake '/cd' or fake '/id' added to appropriate
+ OpcodeDesc::aux field.
+
+The OpcodeDesc::last is non-zero for the final OpcodeDesc record (which does
+not have valid data itself).
+*/
+
+// TODO: To extend flexibility, replace bool fields in MnemonicDesc &
+// MnemonicInfo with a set of flags packed into integer field.
+
+unsigned short EncoderBase::getHash(const OpcodeInfo* odesc)
+{
+ /*
+ NOTE: any changes in the hash computation must be stricty balanced with
+ EncoderBase::Operand::hash_it and EncoderBase::Operands()
+ */
+ unsigned short hash = 0;
+ // The hash computation, uses fast way - table selection instead of if-s.
+ if (odesc->roles.count > 0) {
+ OpndKind kind = odesc->opnds[0].kind;
+ OpndSize size = odesc->opnds[0].size;
+ assert(kind<COUNTOF(kind_hash));
+ assert(size<COUNTOF(size_hash));
+ hash = get_kind_hash(kind) | get_size_hash(size);
+ }
+
+ if (odesc->roles.count > 1) {
+ OpndKind kind = odesc->opnds[1].kind;
+ OpndSize size = odesc->opnds[1].size;
+ assert(kind<COUNTOF(kind_hash));
+ assert(size<COUNTOF(size_hash));
+ hash = (hash<<HASH_BITS_PER_OPERAND) |
+ (get_kind_hash(kind) | get_size_hash(size));
+ }
+
+ if (odesc->roles.count > 2) {
+ OpndKind kind = odesc->opnds[2].kind;
+ OpndSize size = odesc->opnds[2].size;
+ assert(kind<COUNTOF(kind_hash));
+ assert(size<COUNTOF(size_hash));
+ hash = (hash<<HASH_BITS_PER_OPERAND) |
+ (get_kind_hash(kind) | get_size_hash(size));
+ }
+ assert(hash <= HASH_MAX);
+ return hash;
+}
+
+
+#define BEGIN_MNEMONIC(mn, flags, roles) \
+ { Mnemonic_##mn, flags, roles, #mn,
+#define END_MNEMONIC() },
+#define BEGIN_OPCODES() {
+#define END_OPCODES() { OpcodeInfo::all, {OpcodeByteKind_LAST} }}
+
+//#define BEGIN_MNEMONIC(mn, affflags, ulags, cond, symm, roles) \
+// { Mnemonic_##mn, affflags, ulags, cond, symm, roles, #mn,
+
+
+static MnemonicInfo masterEncodingTable[] = {
+//
+// Null
+//
+BEGIN_MNEMONIC(Null, MF_NONE, N)
+BEGIN_OPCODES()
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(LAHF, MF_USES_FLAGS, D)
+BEGIN_OPCODES()
+// TheManual says it's not always supported in em64t mode, thus excluding it
+ {OpcodeInfo::ia32, {0x9F}, {EAX}, D },
+END_OPCODES()
+END_MNEMONIC()
+//
+// ALU mnemonics - add, adc, or, xor, and, cmp, sub, sbb
+// as they differ only in the opcode extention (/digit) number and
+// in which number the opcode start from, the opcode definitions
+// for those instructions are packed together
+//
+// The 'opcode_starts_from' and 'opcode_ext' in DEFINE_ALU_OPCODES()
+// are enough to define OpcodeInfo::all opcodes and the 'first_opcode'
+// parameter is only due to ADD instruction, which requires an zero opcode
+// byte which, in turn, is coded especially in the current coding scheme.
+//
+
+#define DEFINE_ALU_OPCODES( opc_ext, opcode_starts_from, first_opcode, def_use ) \
+\
+ {OpcodeInfo::decoder, {opcode_starts_from + 4, ib}, {AL, imm8}, DU_U },\
+ {OpcodeInfo::decoder, {Size16, opcode_starts_from + 5, iw}, {AX, imm16}, DU_U },\
+ {OpcodeInfo::decoder, {opcode_starts_from + 5, id}, {EAX, imm32}, DU_U },\
+ {OpcodeInfo::decoder64, {REX_W, opcode_starts_from+5, id}, {RAX, imm32s},DU_U },\
+\
+ {OpcodeInfo::all, {0x80, opc_ext, ib}, {r_m8, imm8}, def_use },\
+ {OpcodeInfo::all, {Size16, 0x81, opc_ext, iw}, {r_m16, imm16}, def_use },\
+ {OpcodeInfo::all, {0x81, opc_ext, id}, {r_m32, imm32}, def_use },\
+ {OpcodeInfo::em64t, {REX_W, 0x81, opc_ext, id}, {r_m64, imm32s}, def_use },\
+\
+ {OpcodeInfo::all, {Size16, 0x83, opc_ext, ib}, {r_m16, imm8s}, def_use },\
+ {OpcodeInfo::all, {0x83, opc_ext, ib}, {r_m32, imm8s}, def_use },\
+ {OpcodeInfo::em64t, {REX_W, 0x83, opc_ext, ib}, {r_m64, imm8s}, def_use },\
+\
+ {OpcodeInfo::all, {first_opcode, _r}, {r_m8, r8}, def_use },\
+\
+ {OpcodeInfo::all, {Size16, opcode_starts_from+1, _r}, {r_m16, r16}, def_use },\
+ {OpcodeInfo::all, {opcode_starts_from+1, _r}, {r_m32, r32}, def_use },\
+ {OpcodeInfo::em64t, {REX_W, opcode_starts_from+1, _r}, {r_m64, r64}, def_use },\
+\
+ {OpcodeInfo::all, {opcode_starts_from+2, _r}, {r8, r_m8}, def_use },\
+\
+ {OpcodeInfo::all, {Size16, opcode_starts_from+3, _r}, {r16, r_m16}, def_use },\
+ {OpcodeInfo::all, {opcode_starts_from+3, _r}, {r32, r_m32}, def_use },\
+ {OpcodeInfo::em64t, {REX_W, opcode_starts_from+3, _r}, {r64, r_m64}, def_use },
+
+BEGIN_MNEMONIC(ADD, MF_AFFECTS_FLAGS|MF_SYMMETRIC, DU_U)
+BEGIN_OPCODES()
+ DEFINE_ALU_OPCODES(_0, 0x00, OxOO, DU_U )
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(OR, MF_AFFECTS_FLAGS|MF_SYMMETRIC, DU_U)
+BEGIN_OPCODES()
+ DEFINE_ALU_OPCODES(_1, 0x08, 0x08, DU_U )
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(ADC, MF_AFFECTS_FLAGS|MF_USES_FLAGS|MF_SYMMETRIC, DU_U)
+BEGIN_OPCODES()
+ DEFINE_ALU_OPCODES(_2, 0x10, 0x10, DU_U )
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(SBB, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U)
+BEGIN_OPCODES()
+ DEFINE_ALU_OPCODES(_3, 0x18, 0x18, DU_U )
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(AND, MF_AFFECTS_FLAGS|MF_SYMMETRIC, DU_U)
+BEGIN_OPCODES()
+ DEFINE_ALU_OPCODES(_4, 0x20, 0x20, DU_U )
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(SUB, MF_AFFECTS_FLAGS|MF_SAME_ARG_NO_USE, DU_U)
+BEGIN_OPCODES()
+ DEFINE_ALU_OPCODES(_5, 0x28, 0x28, DU_U )
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(XOR, MF_AFFECTS_FLAGS|MF_SYMMETRIC|MF_SAME_ARG_NO_USE, DU_U)
+BEGIN_OPCODES()
+ DEFINE_ALU_OPCODES( _6, 0x30, 0x30, DU_U )
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CMP, MF_AFFECTS_FLAGS, U_U)
+BEGIN_OPCODES()
+ DEFINE_ALU_OPCODES( _7, 0x38, 0x38, U_U )
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CMPXCHG, MF_AFFECTS_FLAGS, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x0F, 0xB0, _r}, {r_m8, r8, AL}, DU_DU_DU },
+ {OpcodeInfo::all, {Size16, 0x0F, 0xB1, _r}, {r_m16, r16, AX}, DU_DU_DU },
+ {OpcodeInfo::all, {0x0F, 0xB1, _r}, {r_m32, r32, EAX}, DU_DU_DU},
+ {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB1, _r}, {r_m64, r64, RAX}, DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CMPXCHG8B, MF_AFFECTS_FLAGS, D)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x0F, 0xC7, _1}, {m64}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+#undef DEFINE_ALU_OPCODES
+//
+//
+//
+BEGIN_MNEMONIC(ADDSD, MF_NONE, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF2, 0x0F, 0x58, _r}, {xmm64, xmm_m64}, DU_U},
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(ADDSS, MF_NONE, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x58, _r}, {xmm32, xmm_m32}, DU_U},
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(BSF, MF_AFFECTS_FLAGS, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x0F, 0xBC}, {r32, r_m32}, D_U},
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(BSR, MF_AFFECTS_FLAGS, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x0F, 0xBD}, {r32, r_m32}, D_U},
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(CALL, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xE8, cd}, {rel32}, U },
+ {OpcodeInfo::ia32, {Size16, 0xE8, cw}, {rel16}, U },
+ {OpcodeInfo::ia32, {0xFF, _2}, {r_m32}, U },
+ {OpcodeInfo::em64t, {0xFF, _2}, {r_m64}, U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CMC, MF_USES_FLAGS|MF_AFFECTS_FLAGS, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::decoder, {0xF5}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+//TODO: Workaround. Actually, it's D_DU, but Jitrino's CG thinks it's D_U
+BEGIN_MNEMONIC(CDQ, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x99}, {DX, AX}, D_U },
+ {OpcodeInfo::all, {0x99}, {EDX, EAX}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x99}, {RDX, RAX}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+#define DEFINE_CMOVcc_MNEMONIC( cc ) \
+ BEGIN_MNEMONIC(CMOV##cc, MF_USES_FLAGS|MF_CONDITIONAL, DU_U ) \
+BEGIN_OPCODES() \
+ {OpcodeInfo::all, {Size16, 0x0F, 0x40 + ConditionMnemonic_##cc, _r}, {r16, r_m16}, DU_U }, \
+ {OpcodeInfo::all, {0x0F, 0x40 + ConditionMnemonic_##cc, _r}, {r32, r_m32}, DU_U }, \
+ {OpcodeInfo::em64t, {REX_W, 0x0F, 0x40 + ConditionMnemonic_##cc, _r}, {r64, r_m64}, DU_U }, \
+END_OPCODES() \
+END_MNEMONIC()
+
+DEFINE_CMOVcc_MNEMONIC(O)
+DEFINE_CMOVcc_MNEMONIC(NO)
+DEFINE_CMOVcc_MNEMONIC(B)
+DEFINE_CMOVcc_MNEMONIC(NB)
+DEFINE_CMOVcc_MNEMONIC(Z)
+DEFINE_CMOVcc_MNEMONIC(NZ)
+DEFINE_CMOVcc_MNEMONIC(BE)
+DEFINE_CMOVcc_MNEMONIC(NBE)
+DEFINE_CMOVcc_MNEMONIC(S)
+DEFINE_CMOVcc_MNEMONIC(NS)
+DEFINE_CMOVcc_MNEMONIC(P)
+DEFINE_CMOVcc_MNEMONIC(NP)
+DEFINE_CMOVcc_MNEMONIC(L)
+DEFINE_CMOVcc_MNEMONIC(NL)
+DEFINE_CMOVcc_MNEMONIC(LE)
+DEFINE_CMOVcc_MNEMONIC(NLE)
+
+#undef DEFINE_CMOVcc_MNEMONIC
+
+/*****************************************************************************
+ ***** SSE conversion routines *****
+*****************************************************************************/
+//
+// double -> float
+BEGIN_MNEMONIC(CVTSD2SS, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF2, 0x0F, 0x5A, _r}, {xmm32, xmm_m64}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+// double -> I_32
+BEGIN_MNEMONIC(CVTSD2SI, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF2, 0x0F, 0x2D, _r}, {r32, xmm_m64}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0xF2, 0x0F, 0x2D, _r}, {r64, xmm_m64}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+// double [truncated] -> I_32
+BEGIN_MNEMONIC(CVTTSD2SI, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF2, 0x0F, 0x2C, _r}, {r32, xmm_m64}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0xF2, 0x0F, 0x2C, _r}, {r64, xmm_m64}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+// float -> double
+BEGIN_MNEMONIC(CVTSS2SD, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x5A, _r}, {xmm64, xmm_m32}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+// float -> I_32
+BEGIN_MNEMONIC(CVTSS2SI, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x2D, _r}, {r32, xmm_m32}, D_U},
+ {OpcodeInfo::em64t, {REX_W, 0xF3, 0x0F, 0x2D, _r}, {r64, xmm_m32}, D_U},
+END_OPCODES()
+END_MNEMONIC()
+
+// float [truncated] -> I_32
+BEGIN_MNEMONIC(CVTTSS2SI, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x2C, _r}, {r32, xmm_m32}, D_U},
+ {OpcodeInfo::em64t, {REX_W, 0xF3, 0x0F, 0x2C, _r}, {r64, xmm_m32}, D_U},
+END_OPCODES()
+END_MNEMONIC()
+
+// I_32 -> double
+BEGIN_MNEMONIC(CVTSI2SD, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF2, 0x0F, 0x2A, _r}, {xmm64, r_m32}, D_U},
+ {OpcodeInfo::em64t, {REX_W, 0xF2, 0x0F, 0x2A, _r}, {xmm64, r_m64}, D_U},
+END_OPCODES()
+END_MNEMONIC()
+
+// I_32 -> float
+BEGIN_MNEMONIC(CVTSI2SS, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x2A, _r}, {xmm32, r_m32}, D_U},
+ {OpcodeInfo::em64t, {REX_W, 0xF3, 0x0F, 0x2A, _r}, {xmm32, r_m64}, D_U},
+END_OPCODES()
+END_MNEMONIC()
+
+//
+// ~ SSE conversions
+//
+
+BEGIN_MNEMONIC(DEC, MF_AFFECTS_FLAGS, DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xFE, _1}, {r_m8}, DU },
+
+ {OpcodeInfo::all, {Size16, 0xFF, _1}, {r_m16}, DU },
+ {OpcodeInfo::all, {0xFF, _1}, {r_m32}, DU },
+ {OpcodeInfo::em64t, {REX_W, 0xFF, _1}, {r_m64}, DU },
+
+ {OpcodeInfo::ia32, {Size16, 0x48|rw}, {r16}, DU },
+ {OpcodeInfo::ia32, {0x48|rd}, {r32}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(DIVSD, MF_NONE, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF2, 0x0F, 0x5E, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(DIVSS, MF_NONE, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x5E, _r}, {xmm32, xmm_m32}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+/****************************************************************************
+ ***** FPU operations *****
+****************************************************************************/
+
+BEGIN_MNEMONIC(FADDP, MF_NONE, DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDE, 0xC1}, {FP0D}, DU },
+ {OpcodeInfo::all, {0xDE, 0xC1}, {FP0S}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FLDZ, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xEE}, {FP0D}, D },
+ {OpcodeInfo::all, {0xD9, 0xEE}, {FP0S}, D },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FADD, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDC, _0}, {FP0D, m64}, DU_U },
+ {OpcodeInfo::all, {0xD8, _0}, {FP0S, m32}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FSUBP, MF_NONE, DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDE, 0xE9}, {FP0D}, DU },
+ {OpcodeInfo::all, {0xDE, 0xE9}, {FP0S}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FSUB, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDC, _4}, {FP0D, m64}, DU_U },
+ {OpcodeInfo::all, {0xD8, _4}, {FP0S, m32}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FISUB, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDA, _4}, {FP0S, m32}, DU_U },
+// {OpcodeInfo::all, {0xDE, _4}, {FP0S, m16}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+
+
+BEGIN_MNEMONIC(FMUL, MF_NONE, DU_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD8, _1}, {FP0S, m32}, DU_U },
+ {OpcodeInfo::all, {0xDC, _1}, {FP0D, m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FMULP, MF_NONE, DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDE, 0xC9}, {FP0D}, DU },
+ {OpcodeInfo::all, {0xDE, 0xC9}, {FP0S}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FDIVP, MF_NONE, DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDE, 0xF9}, {FP0D}, DU },
+ {OpcodeInfo::all, {0xDE, 0xF9}, {FP0S}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FDIV, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDC, _6}, {FP0D, m64}, DU_U },
+ {OpcodeInfo::all, {0xD8, _6}, {FP0S, m32}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(FUCOM, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDD, 0xE1}, {FP0D, FP1D}, DU_U },
+ {OpcodeInfo::all, {0xDD, 0xE1}, {FP0S, FP1S}, DU_U },
+ // A little trick: actually, these 2 opcodes take only index of the
+ // needed register. To make the things similar to other instructions
+ // we encode here as if they took FPREG.
+ {OpcodeInfo::all, {0xDD, 0xE0|_i}, {fp32}, DU },
+ {OpcodeInfo::all, {0xDD, 0xE0|_i}, {fp64}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FUCOMI, MF_NONE, D_U )
+BEGIN_OPCODES()
+ // A little trick: actually, these 2 opcodes take only index of the
+ // needed register. To make the things similar to other instructions
+ // we encode here as if they took FPREG.
+ {OpcodeInfo::all, {0xDB, 0xE8|_i}, {fp32}, DU },
+ {OpcodeInfo::all, {0xDB, 0xE8|_i}, {fp64}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FUCOMP, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDD, 0xE9}, {FP0D, FP1D}, DU_U },
+ {OpcodeInfo::all, {0xDD, 0xE9}, {FP0S, FP1S}, DU_U },
+ // A little trick: actually, these 2 opcodes take only index of the
+ // needed register. To make the things similar to other instructions
+ // we encode here as if they took FPREG.
+ {OpcodeInfo::all, {0xDD, 0xE8|_i}, {fp32}, DU },
+ {OpcodeInfo::all, {0xDD, 0xE8|_i}, {fp64}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FUCOMIP, MF_NONE, D_U )
+BEGIN_OPCODES()
+ // A little trick: actually, these 2 opcodes take only index of the
+ // needed register. To make the things similar to other instructions
+ // we encode here as if they took FPREG.
+ {OpcodeInfo::all, {0xDF, 0xE8|_i}, {fp32}, DU },
+ {OpcodeInfo::all, {0xDF, 0xE8|_i}, {fp64}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FUCOMPP, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDA, 0xE9}, {FP0D, FP1D}, DU_U },
+ {OpcodeInfo::all, {0xDA, 0xE9}, {FP0S, FP1S}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FLDCW, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, _5}, {m16}, U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FNSTCW, MF_NONE, D)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, _7}, {m16}, D },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FSTSW, MF_NONE, D)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x9B, 0xDF, 0xE0}, {EAX}, D },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FNSTSW, MF_NONE, D)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDF, 0xE0}, {EAX}, D },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FCHS, MF_NONE, DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xE0}, {FP0D}, DU },
+ {OpcodeInfo::all, {0xD9, 0xE0}, {FP0S}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FCLEX, MF_NONE, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x9B, 0xDB, 0xE2}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FNCLEX, MF_NONE, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDB, 0xE2}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+//BEGIN_MNEMONIC(FDECSTP, MF_NONE, N)
+// BEGIN_OPCODES()
+// {OpcodeInfo::all, {0xD9, 0xF6}, {}, N },
+// END_OPCODES()
+//END_MNEMONIC()
+
+BEGIN_MNEMONIC(FILD, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDB, _0}, {FP0S, m32}, D_U },
+ {OpcodeInfo::all, {0xDF, _5}, {FP0D, m64}, D_U },
+ {OpcodeInfo::all, {0xDB, _0}, {FP0S, m32}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+//BEGIN_MNEMONIC(FINCSTP, MF_NONE, N)
+// BEGIN_OPCODES()
+// {OpcodeInfo::all, {0xD9, 0xF7}, {}, N },
+// END_OPCODES()
+//END_MNEMONIC()
+
+BEGIN_MNEMONIC(FIST, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDB, _2}, {m32, FP0S}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FISTP, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDB, _3}, {m32, FP0S}, D_U },
+ {OpcodeInfo::all, {0xDF, _7}, {m64, FP0D}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FISTTP, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xDD, _1}, {m64, FP0D}, D_U },
+ {OpcodeInfo::all, {0xDB, _1}, {m32, FP0S}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FRNDINT, MF_NONE, DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xFC}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xFC}, {FP0D}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FLD, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, _0}, {FP0S, m32}, D_U },
+ {OpcodeInfo::all, {0xDD, _0}, {FP0D, m64}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FLDLG2, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xEC}, {FP0S}, D },
+ {OpcodeInfo::all, {0xD9, 0xEC}, {FP0D}, D },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FLDLN2, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xED}, {FP0S}, D },
+ {OpcodeInfo::all, {0xD9, 0xED}, {FP0D}, D },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FLD1, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xE8}, {FP0S}, D },
+ {OpcodeInfo::all, {0xD9, 0xE8}, {FP0D}, D },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(FPREM, MF_NONE, N)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xF8}, {}, N },
+ END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FPREM1, MF_NONE, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xF5}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FST, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, _2}, {m32, FP0S}, D_U },
+ {OpcodeInfo::all, {0xDD, _2}, {m64, FP0D}, D_U },
+ // A little trick: actually, these 2 opcodes take only index of the
+ // needed register. To make the things similar to other instructions
+ // we encode here as if they took FPREG.
+ {OpcodeInfo::all, {0xDD, 0xD0|_i}, {fp32}, D },
+ {OpcodeInfo::all, {0xDD, 0xD0|_i}, {fp64}, D },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FSTP, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, _3}, {m32, FP0S}, D_U },
+ {OpcodeInfo::all, {0xDD, _3}, {m64, FP0D}, D_U },
+ // A little trick: actually, these 2 opcodes take only index of the
+ // needed register. To make the things similar to other instructions
+ // we encode here as if they took FPREG.
+ {OpcodeInfo::all, {0xDD, 0xD8|_i}, {fp32}, D },
+ {OpcodeInfo::all, {0xDD, 0xD8|_i}, {fp64}, D },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FSQRT, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xFA}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xFA}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(FYL2X, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xF1}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xF1}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(FYL2XP1, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xF9}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xF9}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(F2XM1, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xF0}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xF0}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FPATAN, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xF3}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xF3}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FXCH, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xC9}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xC9}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FSCALE, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xFD}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xFD}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FABS, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xE1}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xE1}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FSIN, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xFE}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xFE}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FCOS, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xFF}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xFF}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(FPTAN, MF_NONE, DU)
+ BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xD9, 0xF2}, {FP0S}, DU },
+ {OpcodeInfo::all, {0xD9, 0xF2}, {FP0D}, DU },
+ END_OPCODES()
+END_MNEMONIC()
+
+//
+// ~ FPU
+//
+
+BEGIN_MNEMONIC(DIV, MF_AFFECTS_FLAGS, DU_DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF7, _6}, {EDX, EAX, r_m32}, DU_DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(IDIV, MF_AFFECTS_FLAGS, DU_DU_U)
+BEGIN_OPCODES()
+#if !defined(_EM64T_)
+ {OpcodeInfo::all, {0xF6, _7}, {AH, AL, r_m8}, DU_DU_U },
+ {OpcodeInfo::all, {Size16, 0xF7, _7}, {DX, AX, r_m16}, DU_DU_U },
+#endif
+ {OpcodeInfo::all, {0xF7, _7}, {EDX, EAX, r_m32}, DU_DU_U },
+ {OpcodeInfo::em64t, {REX_W, 0xF7, _7}, {RDX, RAX, r_m64}, DU_DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(IMUL, MF_AFFECTS_FLAGS, D_DU_U)
+BEGIN_OPCODES()
+ /*{OpcodeInfo::all, {0xF6, _5}, {AH, AL, r_m8}, D_DU_U },
+ {OpcodeInfo::all, {Size16, 0xF7, _5}, {DX, AX, r_m16}, D_DU_U },
+ */
+ //
+ {OpcodeInfo::all, {0xF7, _5}, {EDX, EAX, r_m32}, D_DU_U },
+ //todo: this opcode's hash conflicts with IMUL r64,r_m64 - they're both 0.
+ // this particular is not currently used, so we may safely drop it, but need to
+ // revisit the hash implementation
+ // {OpcodeInfo::em64t, {REX_W, 0xF7, _5}, {RDX, RAX, r_m64}, D_DU_U },
+ //
+ {OpcodeInfo::all, {Size16, 0x0F, 0xAF, _r}, {r16,r_m16}, DU_U },
+ {OpcodeInfo::all, {0x0F, 0xAF, _r}, {r32,r_m32}, DU_U },
+ {OpcodeInfo::em64t, {REX_W, 0x0F, 0xAF, _r}, {r64,r_m64}, DU_U },
+ {OpcodeInfo::all, {Size16, 0x6B, _r, ib}, {r16,r_m16,imm8s}, D_DU_U },
+ {OpcodeInfo::all, {0x6B, _r, ib}, {r32,r_m32,imm8s}, D_DU_U },
+ {OpcodeInfo::em64t, {REX_W, 0x6B, _r, ib}, {r64,r_m64,imm8s}, D_DU_U },
+ {OpcodeInfo::all, {Size16, 0x6B, _r, ib}, {r16,imm8s}, DU_U },
+ {OpcodeInfo::all, {0x6B, _r, ib}, {r32,imm8s}, DU_U },
+ {OpcodeInfo::em64t, {REX_W, 0x6B, _r, ib}, {r64,imm8s}, DU_U },
+ {OpcodeInfo::all, {Size16, 0x69, _r, iw}, {r16,r_m16,imm16}, D_U_U },
+ {OpcodeInfo::all, {0x69, _r, id}, {r32,r_m32,imm32}, D_U_U },
+ {OpcodeInfo::em64t, {REX_W, 0x69, _r, id}, {r64,r_m64,imm32s}, D_U_U },
+ {OpcodeInfo::all, {Size16, 0x69, _r, iw}, {r16,imm16}, DU_U },
+ {OpcodeInfo::all, {0x69, _r, id}, {r32,imm32}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MUL, MF_AFFECTS_FLAGS, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF6, _4}, {AX, AL, r_m8}, D_DU_U },
+ {OpcodeInfo::all, {Size16, 0xF7, _4}, {DX, AX, r_m16}, D_DU_U },
+ {OpcodeInfo::all, {0xF7, _4}, {EDX, EAX, r_m32}, D_DU_U },
+ {OpcodeInfo::em64t, {REX_W, 0xF7, _4}, {RDX, RAX, r_m64}, D_DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(INC, MF_AFFECTS_FLAGS, DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xFE, _0}, {r_m8}, DU },
+ {OpcodeInfo::all, {Size16, 0xFF, _0}, {r_m16}, DU },
+ {OpcodeInfo::all, {0xFF, _0}, {r_m32}, DU },
+ {OpcodeInfo::em64t, {REX_W, 0xFF, _0}, {r_m64}, DU },
+ {OpcodeInfo::ia32, {Size16, 0x40|rw}, {r16}, DU },
+ {OpcodeInfo::ia32, {0x40|rd}, {r32}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(INT3, MF_NONE, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xCC}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+#define DEFINE_Jcc_MNEMONIC( cc ) \
+ BEGIN_MNEMONIC(J##cc, MF_USES_FLAGS|MF_CONDITIONAL, U ) \
+BEGIN_OPCODES() \
+ {OpcodeInfo::all, {0x70 + ConditionMnemonic_##cc, cb }, { rel8 }, U }, \
+ {OpcodeInfo::ia32, {Size16, 0x0F, 0x80 + ConditionMnemonic_##cc, cw}, { rel16 }, U }, \
+ {OpcodeInfo::all, {0x0F, 0x80 + ConditionMnemonic_##cc, cd}, { rel32 }, U }, \
+END_OPCODES() \
+END_MNEMONIC()
+
+
+DEFINE_Jcc_MNEMONIC(O)
+DEFINE_Jcc_MNEMONIC(NO)
+DEFINE_Jcc_MNEMONIC(B)
+DEFINE_Jcc_MNEMONIC(NB)
+DEFINE_Jcc_MNEMONIC(Z)
+DEFINE_Jcc_MNEMONIC(NZ)
+DEFINE_Jcc_MNEMONIC(BE)
+DEFINE_Jcc_MNEMONIC(NBE)
+
+DEFINE_Jcc_MNEMONIC(S)
+DEFINE_Jcc_MNEMONIC(NS)
+DEFINE_Jcc_MNEMONIC(P)
+DEFINE_Jcc_MNEMONIC(NP)
+DEFINE_Jcc_MNEMONIC(L)
+DEFINE_Jcc_MNEMONIC(NL)
+DEFINE_Jcc_MNEMONIC(LE)
+DEFINE_Jcc_MNEMONIC(NLE)
+
+#undef DEFINE_Jcc_MNEMONIC
+
+BEGIN_MNEMONIC(JMP, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xEB, cb}, {rel8}, U },
+ {OpcodeInfo::ia32, {Size16, 0xE9, cw}, {rel16}, U },
+ {OpcodeInfo::all, {0xE9, cd}, {rel32}, U },
+ {OpcodeInfo::ia32, {Size16, 0xFF, _4}, {r_m16}, U },
+ {OpcodeInfo::ia32, {0xFF, _4}, {r_m32}, U },
+ {OpcodeInfo::em64t, {0xFF, _4}, {r_m64}, U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(LEA, MF_NONE, D_U )
+BEGIN_OPCODES()
+ /*
+ A special case: the LEA instruction itself does not care about size of
+ second operand. This is obviuos why it is, and thus in The Manual, a
+ simple 'm' without size is used.
+ However, in the Jitrino's instrucitons we'll have an operand with a size.
+ Also, the hashing scheme is not supposed to handle OpndSize_Null, and
+ making it to do so will lead to unnecessary complication of hashing
+ scheme. Thus, instead of handling it as a special case, we simply make
+ copies of the opcodes with sizes set.
+ {OpcodeInfo::all, {0x8D, _r}, {r32, m}, D_U },
+ {OpcodeInfo::em64t, {0x8D, _r}, {r64, m}, D_U },
+ */
+ //Android x86: keep r32, m32 only, otherwise, will have decoding error
+ //{OpcodeInfo::all, {0x8D, _r}, {r32, m8}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m8}, D_U },
+ //{OpcodeInfo::all, {0x8D, _r}, {r32, m16}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m16}, D_U },
+ {OpcodeInfo::all, {0x8D, _r}, {r32, m32}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m32}, D_U },
+ {OpcodeInfo::all, {0x8D, _r}, {r32, m64}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m64}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(LOOP, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xE2, cb}, {ECX, rel8}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(LOOPE, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xE1, cb}, {ECX, rel8}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(LOOPNE, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xE0, cb}, {ECX, rel8}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MOV, MF_NONE, D_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x88, _r}, {r_m8,r8}, D_U },
+
+ {OpcodeInfo::all, {Size16, 0x89, _r}, {r_m16,r16}, D_U },
+ {OpcodeInfo::all, {0x89, _r}, {r_m32,r32}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x89, _r}, {r_m64,r64}, D_U },
+ {OpcodeInfo::all, {0x8A, _r}, {r8,r_m8}, D_U },
+
+ {OpcodeInfo::all, {Size16, 0x8B, _r}, {r16,r_m16}, D_U },
+ {OpcodeInfo::all, {0x8B, _r}, {r32,r_m32}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x8B, _r}, {r64,r_m64}, D_U },
+
+ {OpcodeInfo::all, {0xB0|rb}, {r8,imm8}, D_U },
+
+ {OpcodeInfo::all, {Size16, 0xB8|rw}, {r16,imm16}, D_U },
+ {OpcodeInfo::all, {0xB8|rd}, {r32,imm32}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0xB8|rd}, {r64,imm64}, D_U },
+ {OpcodeInfo::all, {0xC6, _0}, {r_m8,imm8}, D_U },
+
+ {OpcodeInfo::all, {Size16, 0xC7, _0}, {r_m16,imm16}, D_U },
+ {OpcodeInfo::all, {0xC7, _0}, {r_m32,imm32}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0xC7, _0}, {r_m64,imm32s}, D_U },
+
+ {OpcodeInfo::decoder, {0xA0}, {AL, moff8}, D_U },
+ {OpcodeInfo::decoder, {Size16, 0xA1}, {AX, moff16}, D_U },
+ {OpcodeInfo::decoder, {0xA1}, {EAX, moff32}, D_U },
+ //{OpcodeInfo::decoder64, {REX_W, 0xA1}, {RAX, moff64}, D_U },
+
+ {OpcodeInfo::decoder, {0xA2}, {moff8, AL}, D_U },
+ {OpcodeInfo::decoder, {Size16, 0xA3}, {moff16, AX}, D_U },
+ {OpcodeInfo::decoder, {0xA3}, {moff32, EAX}, D_U },
+ //{OpcodeInfo::decoder64, {REX_W, 0xA3}, {moff64, RAX}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+
+
+BEGIN_MNEMONIC(XCHG, MF_NONE, DU_DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x87, _r}, {r_m32,r32}, DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(MOVQ, MF_NONE, D_U )
+BEGIN_OPCODES()
+#ifdef _HAVE_MMX_
+ {OpcodeInfo::all, {0x0F, 0x6F, _r}, {mm64, mm_m64}, D_U },
+ {OpcodeInfo::all, {0x0F, 0x7F, _r}, {mm_m64, mm64}, D_U },
+#endif
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x7E }, {xmm64, xmm_m64}, D_U },
+ {OpcodeInfo::all, {0x66, 0x0F, 0xD6 }, {xmm_m64, xmm64}, D_U },
+// {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x6E, _r}, {xmm64, r_m64}, D_U },
+// {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x7E, _r}, {r_m64, xmm64}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x6E, _r}, {xmm64, r64}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x7E, _r}, {r64, xmm64}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(MOVD, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x66, 0x0F, 0x6E, _r}, {xmm32, r_m32}, D_U },
+ {OpcodeInfo::all, {0x66, 0x0F, 0x7E, _r}, {r_m32, xmm32}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+//
+// A bunch of MMX instructions
+//
+#ifdef _HAVE_MMX_
+
+BEGIN_MNEMONIC(EMMS, MF_NONE, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x0F, 0x77}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+#endif
+
+BEGIN_MNEMONIC(PADDQ, MF_NONE, DU_U)
+BEGIN_OPCODES()
+#ifdef _HAVE_MMX_
+ {OpcodeInfo::all, {0x0F, 0xD4, _r}, {mm64, mm_m64}, DU_U },
+#endif
+ {OpcodeInfo::all, {0x66, 0x0F, 0xD4, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(PAND, MF_NONE, DU_U)
+BEGIN_OPCODES()
+#ifdef _HAVE_MMX_
+ {OpcodeInfo::all, {0x0F, 0xDB, _r}, {mm64, mm_m64}, DU_U },
+#endif
+ {OpcodeInfo::all, {0x66, 0x0F, 0xDB, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(POR, MF_NONE, DU_U)
+BEGIN_OPCODES()
+#ifdef _HAVE_MMX_
+ {OpcodeInfo::all, {0x0F, 0xEB, _r}, {mm64, mm_m64}, DU_U },
+#endif
+ {OpcodeInfo::all, {0x66, 0x0F, 0xEB, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(PSUBQ, MF_NONE, DU_U)
+BEGIN_OPCODES()
+#ifdef _HAVE_MMX_
+ {OpcodeInfo::all, {0x0F, 0xFB, _r}, {mm64, mm_m64}, DU_U },
+#endif
+ {OpcodeInfo::all, {0x66, 0x0F, 0xFB, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(PANDN, MF_NONE, DU_U)
+BEGIN_OPCODES()
+#ifdef _HAVE_MMX_
+ {OpcodeInfo::all, {0x0F, 0xDF, _r}, {mm64, mm_m64}, DU_U },
+#endif
+ {OpcodeInfo::all, {0x66, 0x0F, 0xDF, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+BEGIN_MNEMONIC(PSLLQ, MF_NONE, DU_U)
+BEGIN_OPCODES()
+#ifdef _HAVE_MMX_
+ {OpcodeInfo::all, {0x0F, 0xF3, _r}, {mm64, mm_m64}, DU_U },
+#endif
+ {OpcodeInfo::all, {0x66, 0x0F, 0xF3, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+BEGIN_MNEMONIC(PSRLQ, MF_NONE, DU_U)
+BEGIN_OPCODES()
+#ifdef _HAVE_MMX_
+ {OpcodeInfo::all, {0x0F, 0xD3, _r}, {mm64, mm_m64}, DU_U },
+#endif
+ {OpcodeInfo::all, {0x66, 0x0F, 0xD3, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(PXOR, MF_NONE, DU_U)
+BEGIN_OPCODES()
+#ifdef _HAVE_MMX_
+ {OpcodeInfo::all, {0x0F, 0xEF, _r}, {mm64, mm_m64}, DU_U },
+#endif
+ {OpcodeInfo::all, {0x66, 0x0F, 0xEF, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(MOVAPD, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x66, 0x0F, 0x28, _r}, {xmm64, xmm_m64}, D_U },
+ {OpcodeInfo::all, {0x66, 0x0F, 0x29, _r}, {xmm_m64, xmm64}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(MOVSD, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF2, 0x0F, 0x10, _r}, {xmm64, xmm_m64}, D_U },
+ {OpcodeInfo::all, {0xF2, 0x0F, 0x11, _r}, {xmm_m64, xmm64}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MOVSS, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x10, _r}, {xmm32, xmm_m32}, D_U },
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x11, _r}, {xmm_m32, xmm32}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MOVSX, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {Size16, 0x0F, 0xBE, _r}, {r16, r_m8s}, D_U },
+ {OpcodeInfo::all, {0x0F, 0xBE, _r}, {r32, r_m8s}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x0F, 0xBE, _r}, {r64, r_m8s}, D_U },
+
+ {OpcodeInfo::all, {0x0F, 0xBF, _r}, {r32, r_m16s}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x0F, 0xBF, _r}, {r64, r_m16s}, D_U },
+
+ {OpcodeInfo::em64t, {REX_W, 0x63, _r}, {r64, r_m32s}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MOVZX, MF_NONE, D_U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {Size16, 0x0F, 0xB6, _r}, {r16, r_m8u}, D_U },
+ {OpcodeInfo::all, {0x0F, 0xB6, _r}, {r32, r_m8u}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB6, _r}, {r64, r_m8u}, D_U },
+
+ {OpcodeInfo::all, {0x0F, 0xB7, _r}, {r32, r_m16u}, D_U },
+ {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB7, _r}, {r64, r_m16u}, D_U },
+ //workaround to get r/rm32->r64 ZX mov functionality:
+ //simple 32bit reg copying zeros high bits in 64bit reg
+ {OpcodeInfo::em64t, {0x8B, _r}, {r64, r_m32u}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MULSD, MF_NONE, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF2, 0x0F, 0x59, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MULSS, MF_NONE, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x59, _r}, {xmm32, xmm_m32}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(NEG, MF_AFFECTS_FLAGS, DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF6, _3}, {r_m8}, DU },
+
+ {OpcodeInfo::all, {Size16, 0xF7, _3}, {r_m16}, DU },
+ {OpcodeInfo::all, {0xF7, _3}, {r_m32}, DU },
+ {OpcodeInfo::em64t, {REX_W, 0xF7, _3}, {r_m64}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(NOP, MF_NONE, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x90}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(NOT, MF_AFFECTS_FLAGS, DU )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF6, _2}, {r_m8}, DU },
+ {OpcodeInfo::all, {Size16, 0xF7, _2}, {r_m16}, DU },
+ {OpcodeInfo::all, {0xF7, _2}, {r_m32}, DU },
+ {OpcodeInfo::em64t, {REX_W, 0xF7, _2}, {r_m64}, DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(POP, MF_NONE, D)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {Size16, 0x8F, _0}, {r_m16}, D },
+ {OpcodeInfo::ia32, {0x8F, _0}, {r_m32}, D },
+ {OpcodeInfo::em64t, {0x8F, _0}, {r_m64}, D },
+
+ {OpcodeInfo::all, {Size16, 0x58|rw }, {r16}, D },
+ {OpcodeInfo::ia32, {0x58|rd }, {r32}, D },
+ {OpcodeInfo::em64t, {0x58|rd }, {r64}, D },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(POPFD, MF_AFFECTS_FLAGS, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x9D}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(PREFETCH, MF_NONE, U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x0F, 0x18, _0}, {m8}, U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(PUSH, MF_NONE, U )
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {Size16, 0xFF, _6}, {r_m16}, U },
+ {OpcodeInfo::ia32, {0xFF, _6}, {r_m32}, U },
+ {OpcodeInfo::em64t, {0xFF, _6}, {r_m64}, U },
+
+ {OpcodeInfo::all, {Size16, 0x50|rw }, {r16}, U },
+ {OpcodeInfo::ia32, {0x50|rd }, {r32}, U },
+ {OpcodeInfo::em64t, {0x50|rd }, {r64}, U },
+
+ {OpcodeInfo::all, {0x6A}, {imm8}, U },
+ {OpcodeInfo::all, {Size16, 0x68}, {imm16}, U },
+ {OpcodeInfo::ia32, {0x68}, {imm32}, U },
+// {OpcodeInfo::em64t, {0x68}, {imm64}, U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(PUSHFD, MF_USES_FLAGS, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x9C}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(RET, MF_NONE, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xC3}, {}, N },
+ {OpcodeInfo::all, {0xC2, iw}, {imm16}, U },
+END_OPCODES()
+END_MNEMONIC()
+
+#define DEFINE_SETcc_MNEMONIC( cc ) \
+ BEGIN_MNEMONIC(SET##cc, MF_USES_FLAGS|MF_CONDITIONAL, DU) \
+BEGIN_OPCODES() \
+ {OpcodeInfo::all, {0x0F, 0x90 + ConditionMnemonic_##cc}, {r_m8}, DU }, \
+END_OPCODES() \
+END_MNEMONIC()
+
+DEFINE_SETcc_MNEMONIC(O)
+DEFINE_SETcc_MNEMONIC(NO)
+DEFINE_SETcc_MNEMONIC(B)
+DEFINE_SETcc_MNEMONIC(NB)
+DEFINE_SETcc_MNEMONIC(Z)
+DEFINE_SETcc_MNEMONIC(NZ)
+DEFINE_SETcc_MNEMONIC(BE)
+DEFINE_SETcc_MNEMONIC(NBE)
+
+DEFINE_SETcc_MNEMONIC(S)
+DEFINE_SETcc_MNEMONIC(NS)
+DEFINE_SETcc_MNEMONIC(P)
+DEFINE_SETcc_MNEMONIC(NP)
+DEFINE_SETcc_MNEMONIC(L)
+DEFINE_SETcc_MNEMONIC(NL)
+DEFINE_SETcc_MNEMONIC(LE)
+DEFINE_SETcc_MNEMONIC(NLE)
+
+#undef DEFINE_SETcc_MNEMONIC
+
+#define DEFINE_SHIFT_MNEMONIC(nam, slash_num, flags) \
+BEGIN_MNEMONIC(nam, flags, DU_U) \
+BEGIN_OPCODES()\
+ /* D0 & D1 opcodes are added w/o 2nd operand (1) because */\
+ /* they are used for decoding only so only instruction length is needed */\
+ {OpcodeInfo::decoder, {0xD0, slash_num}, {r_m8/*,const_1*/}, DU },\
+ {OpcodeInfo::all, {0xD2, slash_num}, {r_m8, CL}, DU_U },\
+ {OpcodeInfo::all, {0xC0, slash_num, ib}, {r_m8, imm8}, DU_U },\
+\
+ {OpcodeInfo::decoder, {Size16, 0xD1, slash_num}, {r_m16/*,const_1*/}, DU },\
+ {OpcodeInfo::all, {Size16, 0xD3, slash_num}, {r_m16, CL}, DU_U },\
+ {OpcodeInfo::all, {Size16, 0xC1, slash_num, ib}, {r_m16, imm8 }, DU_U },\
+\
+ {OpcodeInfo::decoder, {0xD1, slash_num}, {r_m32/*,const_1*/}, DU },\
+ {OpcodeInfo::decoder64, {REX_W, 0xD1, slash_num}, {r_m64/*,const_1*/}, DU },\
+\
+ {OpcodeInfo::all, {0xD3, slash_num}, {r_m32, CL}, DU_U },\
+ {OpcodeInfo::em64t, {REX_W, 0xD3, slash_num}, {r_m64, CL}, DU_U },\
+\
+ {OpcodeInfo::all, {0xC1, slash_num, ib}, {r_m32, imm8}, DU_U },\
+ {OpcodeInfo::em64t, {REX_W, 0xC1, slash_num, ib}, {r_m64, imm8}, DU_U },\
+END_OPCODES()\
+END_MNEMONIC()
+
+
+DEFINE_SHIFT_MNEMONIC(ROL, _0, MF_AFFECTS_FLAGS)
+DEFINE_SHIFT_MNEMONIC(ROR, _1, MF_AFFECTS_FLAGS)
+DEFINE_SHIFT_MNEMONIC(RCL, _2, MF_AFFECTS_FLAGS|MF_USES_FLAGS)
+DEFINE_SHIFT_MNEMONIC(RCR, _3, MF_AFFECTS_FLAGS|MF_USES_FLAGS)
+
+DEFINE_SHIFT_MNEMONIC(SAL, _4, MF_AFFECTS_FLAGS)
+DEFINE_SHIFT_MNEMONIC(SHR, _5, MF_AFFECTS_FLAGS)
+DEFINE_SHIFT_MNEMONIC(SAR, _7, MF_AFFECTS_FLAGS)
+
+#undef DEFINE_SHIFT_MNEMONIC
+
+BEGIN_MNEMONIC(SHLD, MF_AFFECTS_FLAGS, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x0F, 0xA5}, {r_m32, r32, CL}, DU_DU_U },
+ {OpcodeInfo::all, {0x0F, 0xA4}, {r_m32, r32, imm8}, DU_DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(SHRD, MF_AFFECTS_FLAGS, N)
+// TODO: the def/use info is wrong
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x0F, 0xAD}, {r_m32, r32, CL}, DU_DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(SUBSD, MF_NONE, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF2, 0x0F, 0x5C, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(SUBSS, MF_NONE, DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x5C, _r}, {xmm32, xmm_m32}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(TEST, MF_AFFECTS_FLAGS, U_U)
+BEGIN_OPCODES()
+
+ {OpcodeInfo::decoder, {0xA8, ib}, { AL, imm8}, U_U },
+ {OpcodeInfo::decoder, {0xA9, iw}, { AX, imm16}, U_U },
+ {OpcodeInfo::decoder, {0xA9, id}, { EAX, imm32}, U_U },
+ {OpcodeInfo::decoder64, {REX_W, 0xA9, id}, { RAX, imm32s}, U_U },
+
+ {OpcodeInfo::all, {0xF6, _0, ib}, {r_m8,imm8}, U_U },
+
+ {OpcodeInfo::all, {Size16, 0xF7, _0, iw}, {r_m16,imm16}, U_U },
+ {OpcodeInfo::all, {0xF7, _0, id}, {r_m32,imm32}, U_U },
+ {OpcodeInfo::em64t, {REX_W, 0xF7, _0, id}, {r_m64,imm32s}, U_U },
+
+ {OpcodeInfo::all, {0x84, _r}, {r_m8,r8}, U_U },
+
+ {OpcodeInfo::all, {Size16, 0x85, _r}, {r_m16,r16}, U_U },
+ {OpcodeInfo::all, {0x85, _r}, {r_m32,r32}, U_U },
+ {OpcodeInfo::em64t, {REX_W, 0x85, _r}, {r_m64,r64}, U_U },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(UCOMISD, MF_AFFECTS_FLAGS, U_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x66, 0x0F, 0x2E, _r}, {xmm64, xmm_m64}, U_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(UCOMISS, MF_AFFECTS_FLAGS, U_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x0F, 0x2E, _r}, {xmm32, xmm_m32}, U_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(COMISD, MF_AFFECTS_FLAGS, U_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x66, 0x0F, 0x2F, _r}, {xmm64, xmm_m64}, U_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(COMISS, MF_AFFECTS_FLAGS, U_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x0F, 0x2F, _r}, {xmm32, xmm_m32}, U_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(XORPD, MF_SAME_ARG_NO_USE|MF_SYMMETRIC, DU_U)
+BEGIN_OPCODES()
+ //Note: they're actually 128 bits
+ {OpcodeInfo::all, {0x66, 0x0F, 0x57, _r}, {xmm64, xmm_m64}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(XORPS, MF_SAME_ARG_NO_USE|MF_SYMMETRIC, DU_U)
+BEGIN_OPCODES()
+ //Note: they're actually 128 bits
+ {OpcodeInfo::all, {0x0F, 0x57, _r}, {xmm32, xmm_m32}, DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CVTDQ2PD, MF_NONE, D_U )
+BEGIN_OPCODES()
+ //Note: they're actually 128 bits
+ {OpcodeInfo::all, {0xF3, 0x0F, 0xE6}, {xmm64, xmm_m64}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CVTDQ2PS, MF_NONE, D_U )
+BEGIN_OPCODES()
+ //Note: they're actually 128 bits
+ {OpcodeInfo::all, {0x0F, 0x5B, _r}, {xmm32, xmm_m32}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CVTTPD2DQ, MF_NONE, D_U )
+BEGIN_OPCODES()
+ //Note: they're actually 128 bits
+ {OpcodeInfo::all, {0x66, 0x0F, 0xE6}, {xmm64, xmm_m64}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CVTTPS2DQ, MF_NONE, D_U )
+BEGIN_OPCODES()
+ //Note: they're actually 128 bits
+ {OpcodeInfo::all, {0xF3, 0x0F, 0x5B, _r}, {xmm32, xmm_m32}, D_U },
+END_OPCODES()
+END_MNEMONIC()
+
+//
+// String operations
+//
+BEGIN_MNEMONIC(STD, MF_AFFECTS_FLAGS, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xFD}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CLD, MF_AFFECTS_FLAGS, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xFC}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(SCAS, MF_AFFECTS_FLAGS, N)
+// to be symmetric, this mnemonic must have either m32 or RegName_EAX
+// but as long, as Jitrino's CG does not use the mnemonic, leaving it
+// in its natural form
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xAF}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(STOS, MF_AFFECTS_FLAGS, DU_DU_U)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0xAB}, {EDI, ECX, EAX}, DU_DU_U },
+ {OpcodeInfo::all, {0xAA}, {EDI, ECX, AL}, DU_DU_U },
+ {OpcodeInfo::em64t, {REX_W, 0xAB}, {RDI, RCX, RAX}, DU_DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
+/*
+MOVS and CMPS are the special cases.
+Most the code in both CG and Encoder do not expect 2 memory operands.
+Also, they are not supposed to setup constrains on which register the
+memory reference must reside - m8,m8 or m32,m32 is not the choice.
+We can't use r8,r8 either - will have problem with 8bit EDI, ESI.
+So, as the workaround we do r32,r32 and specify size of the operand through
+the specific mnemonic - the same is in the codegen.
+*/
+BEGIN_MNEMONIC(MOVS8, MF_NONE, DU_DU_DU)
+BEGIN_OPCODES()
+ {OpcodeInfo::ia32, {0xA4}, {r32,r32,ECX}, DU_DU_DU },
+ {OpcodeInfo::em64t, {0xA4}, {r64,r64,RCX}, DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MOVS16, MF_NONE, DU_DU_DU)
+BEGIN_OPCODES()
+ {OpcodeInfo::ia32, {Size16, 0xA5}, {r32,r32,ECX}, DU_DU_DU },
+ {OpcodeInfo::em64t, {Size16, 0xA5}, {r64,r64,RCX}, DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MOVS32, MF_NONE, DU_DU_DU)
+BEGIN_OPCODES()
+ {OpcodeInfo::ia32, {0xA5}, {r32,r32,ECX}, DU_DU_DU },
+ {OpcodeInfo::em64t, {0xA5}, {r64,r64,RCX}, DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MOVS64, MF_NONE, DU_DU_DU)
+BEGIN_OPCODES()
+ {OpcodeInfo::em64t, {REX_W,0xA5}, {r64,r64,RCX}, DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CMPSB, MF_AFFECTS_FLAGS, DU_DU_DU)
+BEGIN_OPCODES()
+ {OpcodeInfo::ia32, {0xA6}, {ESI,EDI,ECX}, DU_DU_DU },
+ {OpcodeInfo::em64t, {0xA6}, {RSI,RDI,RCX}, DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CMPSW, MF_AFFECTS_FLAGS, DU_DU_DU)
+BEGIN_OPCODES()
+ {OpcodeInfo::ia32, {Size16, 0xA7}, {ESI,EDI,ECX}, DU_DU_DU },
+ {OpcodeInfo::em64t, {Size16, 0xA7}, {RSI,RDI,RCX}, DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(CMPSD, MF_AFFECTS_FLAGS, DU_DU_DU)
+BEGIN_OPCODES()
+ {OpcodeInfo::ia32, {0xA7}, {ESI,EDI,ECX}, DU_DU_DU },
+ {OpcodeInfo::em64t, {0xA7}, {RSI,RDI,RCX}, DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+
+BEGIN_MNEMONIC(WAIT, MF_AFFECTS_FLAGS, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::all, {0x9B}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+//
+// ~String operations
+//
+
+//
+//Note: the instructions below added for the sake of disassembling routine.
+// They need to have flags, params and params usage to be defined more precisely.
+//
+BEGIN_MNEMONIC(LEAVE, MF_NONE, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::decoder, {0xC9}, {}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(ENTER, MF_NONE, N)
+BEGIN_OPCODES()
+ {OpcodeInfo::decoder, {0xC8, iw, ib}, {imm16, imm8}, N },
+END_OPCODES()
+END_MNEMONIC()
+
+}; // ~masterEncodingTable[]
+
+ENCODER_NAMESPACE_END
+
+//#include <algorithm>
+
+ENCODER_NAMESPACE_START
+
+static bool mnemonic_info_comparator(const MnemonicInfo& one,
+ const MnemonicInfo& two)
+{
+ return one.mn < two.mn;
+}
+
+
+static int compareMnemonicInfo(const void* info1, const void* info2)
+{
+ Mnemonic id1, id2;
+
+ id1 = ((const MnemonicInfo*) info1)->mn;
+ id2 = ((const MnemonicInfo*) info2)->mn;
+ if (id1 < id2)
+ return -1;
+ if (id1 > id2)
+ return 1;
+ return 0;
+}
+
+int EncoderBase::buildTable(void)
+{
+ // A check: all mnemonics must be covered
+ assert(COUNTOF(masterEncodingTable) == Mnemonic_Count);
+ // sort out the mnemonics so the list become ordered
+#if 0 //Android x86
+ std::sort(masterEncodingTable, masterEncodingTable+Mnemonic_Count,
+ mnemonic_info_comparator);
+#else
+ qsort(masterEncodingTable, Mnemonic_Count, sizeof(MnemonicInfo), compareMnemonicInfo);
+#endif
+ //
+ // clear the things
+ //
+ memset(opcodesHashMap, NOHASH, sizeof(opcodesHashMap));
+ memset(opcodes, 0, sizeof(opcodes));
+ //
+ // and, finally, build it
+ for (unsigned i=0; i<Mnemonic_Count; i++) {
+ assert((Mnemonic)i == (masterEncodingTable + i)->mn);
+ buildMnemonicDesc(masterEncodingTable+i);
+ }
+ return 0;
+}
+
+void EncoderBase::buildMnemonicDesc(const MnemonicInfo * minfo)
+{
+ MnemonicDesc& mdesc = mnemonics[minfo->mn];
+ mdesc.mn = minfo->mn;
+ mdesc.flags = minfo->flags;
+ mdesc.roles = minfo->roles;
+ mdesc.name = minfo->name;
+
+ //
+ // fill the used opcodes
+ //
+ for (unsigned i=0, oindex=0; i<COUNTOF(minfo->opcodes); i++) {
+
+ const OpcodeInfo& oinfo = minfo->opcodes[i];
+ OpcodeDesc& odesc = opcodes[minfo->mn][oindex];
+ // last opcode ?
+ if (oinfo.opcode[0] == OpcodeByteKind_LAST) {
+ // mark the opcode 'last', exit
+ odesc.opcode_len = 0;
+ odesc.last = 1;
+ break;
+ }
+ odesc.last = 0;
+#ifdef _EM64T_
+ if (oinfo.platf == OpcodeInfo::ia32) { continue; }
+ if (oinfo.platf == OpcodeInfo::decoder32) { continue; }
+#else
+ if (oinfo.platf == OpcodeInfo::em64t) { continue; }
+ if (oinfo.platf == OpcodeInfo::decoder64) { continue; }
+#endif
+ if (oinfo.platf == OpcodeInfo::decoder64 ||
+ oinfo.platf == OpcodeInfo::decoder32) {
+ odesc.platf = OpcodeInfo::decoder;
+ }
+ else {
+ odesc.platf = (char)oinfo.platf;
+ }
+ //
+ // fill out opcodes
+ //
+ unsigned j = 0;
+ odesc.opcode_len = 0;
+ for(; oinfo.opcode[j]; j++) {
+ unsigned opcod = oinfo.opcode[j];
+ unsigned kind = opcod&OpcodeByteKind_KindMask;
+ if (kind == OpcodeByteKind_REX_W) {
+ odesc.opcode[odesc.opcode_len++] = (unsigned char)0x48;
+ continue;
+ }
+ else if(kind != 0 && kind != OpcodeByteKind_ZeroOpcodeByte) {
+ break;
+ }
+ unsigned lowByte = (opcod & OpcodeByteKind_OpcodeMask);
+ odesc.opcode[odesc.opcode_len++] = (unsigned char)lowByte;
+ }
+ assert(odesc.opcode_len<5);
+ odesc.aux0 = odesc.aux1 = 0;
+ if (oinfo.opcode[j] != 0) {
+ odesc.aux0 = oinfo.opcode[j];
+ assert((odesc.aux0 & OpcodeByteKind_KindMask) != 0);
+ ++j;
+ if(oinfo.opcode[j] != 0) {
+ odesc.aux1 = oinfo.opcode[j];
+ assert((odesc.aux1 & OpcodeByteKind_KindMask) != 0);
+ }
+ }
+ else if (oinfo.roles.count>=2) {
+ if (((oinfo.opnds[0].kind&OpndKind_Mem) &&
+ (isRegKind(oinfo.opnds[1].kind))) ||
+ ((oinfo.opnds[1].kind&OpndKind_Mem) &&
+ (isRegKind(oinfo.opnds[0].kind)))) {
+ // Example: MOVQ xmm1, xmm/m64 has only opcodes
+ // same with SHRD
+ // Adding fake /r
+ odesc.aux0 = _r;
+ }
+ }
+ else if (oinfo.roles.count==1) {
+ if (oinfo.opnds[0].kind&OpndKind_Mem) {
+ // Example: SETcc r/m8, adding fake /0
+ odesc.aux0 = _0;
+ }
+ }
+ // check imm
+ if (oinfo.roles.count > 0 &&
+ (oinfo.opnds[0].kind == OpndKind_Imm ||
+ oinfo.opnds[oinfo.roles.count-1].kind == OpndKind_Imm)) {
+ // Example: CALL cd, PUSH imm32 - they fit both opnds[0] and
+ // opnds[oinfo.roles.count-1].
+ // The A3 opcode fits only opnds[0] - it's currently have
+ // MOV imm32, EAX. Looks ridiculous, but this is how the
+ // moffset is currently implemented. Will need to fix together
+ // with other usages of moff.
+ // adding fake /cd or fake /id
+ unsigned imm_opnd_index =
+ oinfo.opnds[0].kind == OpndKind_Imm ? 0 : oinfo.roles.count-1;
+ OpndSize sz = oinfo.opnds[imm_opnd_index].size;
+ unsigned imm_encode, coff_encode;
+ if (sz==OpndSize_8) {imm_encode = ib; coff_encode=cb; }
+ else if (sz==OpndSize_16) {imm_encode = iw; coff_encode=cw;}
+ else if (sz==OpndSize_32) {imm_encode = id; coff_encode=cd; }
+ else if (sz==OpndSize_64) {imm_encode = io; coff_encode=0xCC; }
+ else { assert(false); imm_encode=0xCC; coff_encode=0xCC; }
+ if (odesc.aux1 == 0) {
+ if (odesc.aux0==0) {
+ odesc.aux0 = imm_encode;
+ }
+ else {
+ if (odesc.aux0 != imm_encode && odesc.aux0 != coff_encode) {
+ odesc.aux1 = imm_encode;
+ }
+ }
+ }
+ else {
+ assert(odesc.aux1==imm_encode);
+ }
+
+ }
+
+ assert(sizeof(odesc.opnds) == sizeof(oinfo.opnds));
+ memcpy(odesc.opnds, oinfo.opnds, sizeof(odesc.opnds));
+ odesc.roles = oinfo.roles;
+ odesc.first_opnd = 0;
+ if (odesc.opnds[0].reg != RegName_Null) {
+ ++odesc.first_opnd;
+ if (odesc.opnds[1].reg != RegName_Null) {
+ ++odesc.first_opnd;
+ }
+ }
+
+ if (odesc.platf == OpcodeInfo::decoder) {
+ // if the opcode is only for decoding info, then do not hash it.
+ ++oindex;
+ continue;
+ }
+
+ //
+ // check whether the operand info is a mask (i.e. r_m*).
+ // in this case, split the info to have separate entries for 'r'
+ // and for 'm'.
+ // the good news is that there can be only one such operand.
+ //
+ int opnd2split = -1;
+ for (unsigned k=0; k<oinfo.roles.count; k++) {
+ if ((oinfo.opnds[k].kind & OpndKind_Mem) &&
+ (OpndKind_Mem != oinfo.opnds[k].kind)) {
+ opnd2split = k;
+ break;
+ }
+ };
+
+ if (opnd2split == -1) {
+ // not a mask, hash it, store it, continue.
+ unsigned short hash = getHash(&oinfo);
+ opcodesHashMap[minfo->mn][hash] = (unsigned char)oindex;
+ ++oindex;
+ continue;
+ };
+
+ OpcodeInfo storeItem = oinfo;
+ unsigned short hash;
+
+ // remove the memory part of the mask, and store only 'r' part
+ storeItem.opnds[opnd2split].kind = (OpndKind)(storeItem.opnds[opnd2split].kind & ~OpndKind_Mem);
+ hash = getHash(&storeItem);
+ if (opcodesHashMap[minfo->mn][hash] == NOHASH) {
+ opcodesHashMap[minfo->mn][hash] = (unsigned char)oindex;
+ }
+ // else {
+ // do not overwrite if there is something there, just check that operands match
+ // the reason is that for some instructions there are several possibilities:
+ // say 'DEC r' may be encode as either '48+r' or 'FF /1', and I believe
+ // the first one is better for 'dec r'.
+ // as we're currently processing an opcode with memory part in operand,
+ // leave already filled items intact, so if there is 'OP reg' there, this
+ // better choice will be left in the table instead of 'OP r_m'
+ // }
+
+ // compute hash of memory-based operand, 'm' part in 'r_m'
+ storeItem.opnds[opnd2split].kind = OpndKind_Mem;
+ hash = getHash(&storeItem);
+ // should not happen: for the r_m opcodes, there is a possibility
+ // that hash value of 'r' part intersects with 'OP r' value, but it's
+ // impossible for 'm' part.
+ assert(opcodesHashMap[minfo->mn][hash] == NOHASH);
+ opcodesHashMap[minfo->mn][hash] = (unsigned char)oindex;
+
+ ++oindex;
+ }
+}
+
+ENCODER_NAMESPACE_END
diff --git a/vm/compiler/codegen/x86/libenc/enc_wrapper.cpp b/vm/compiler/codegen/x86/libenc/enc_wrapper.cpp
new file mode 100644
index 0000000..cf53cea
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/enc_wrapper.cpp
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include "enc_base.h"
+#include "enc_wrapper.h"
+#include "dec_base.h"
+#include "utils/Log.h"
+
+//#define PRINT_ENCODER_STREAM
+bool dump_x86_inst = false;
+//map_reg
+const RegName map_of_regno_2_regname[] = {
+ RegName_EAX, RegName_EBX, RegName_ECX, RegName_EDX,
+ RegName_EDI, RegName_ESI, RegName_ESP, RegName_EBP,
+ RegName_XMM0, RegName_XMM1, RegName_XMM2, RegName_XMM3,
+ RegName_XMM4, RegName_XMM5, RegName_XMM6, RegName_XMM7,
+ RegName_Null, RegName_Null, RegName_Null, RegName_Null,
+ RegName_Null, RegName_Null, RegName_Null, RegName_Null,
+ RegName_Null,
+ RegName_Null, RegName_Null, RegName_Null, RegName_Null, RegName_Null,
+ RegName_Null, RegName_Null, RegName_Null, RegName_Null,
+ RegName_Null, RegName_Null, RegName_Null, RegName_Null,
+ RegName_Null, RegName_Null, //SCRATCH
+ RegName_Null, RegName_Null, RegName_Null, RegName_Null
+};
+
+//getRegSize, getAliasReg:
+//OpndSize, RegName, OpndExt: enum enc_defs.h
+inline void add_r(EncoderBase::Operands & args, int physicalReg, OpndSize sz, OpndExt ext = OpndExt_None) {
+ RegName reg = map_of_regno_2_regname[physicalReg];
+ if (sz != getRegSize(reg)) {
+ reg = getAliasReg(reg, sz);
+ }
+ args.add(EncoderBase::Operand(reg, ext));
+}
+inline void add_m(EncoderBase::Operands & args, int baseReg, int disp, OpndSize sz, OpndExt ext = OpndExt_None) {
+ args.add(EncoderBase::Operand(sz,
+ map_of_regno_2_regname[baseReg],
+ RegName_Null, 0,
+ disp, ext));
+}
+inline void add_m_scale(EncoderBase::Operands & args, int baseReg, int indexReg, int scale,
+ OpndSize sz, OpndExt ext = OpndExt_None) {
+ args.add(EncoderBase::Operand(sz,
+ map_of_regno_2_regname[baseReg],
+ map_of_regno_2_regname[indexReg], scale,
+ 0, ext));
+}
+inline void add_m_disp_scale(EncoderBase::Operands & args, int baseReg, int disp, int indexReg, int scale,
+ OpndSize sz, OpndExt ext = OpndExt_None) {
+ args.add(EncoderBase::Operand(sz,
+ map_of_regno_2_regname[baseReg],
+ map_of_regno_2_regname[indexReg], scale,
+ disp, ext));
+}
+
+inline void add_fp(EncoderBase::Operands & args, unsigned i, bool dbl) {
+ return args.add((RegName)( (dbl ? RegName_FP0D : RegName_FP0S) + i));
+}
+inline void add_imm(EncoderBase::Operands & args, OpndSize sz, int value, bool is_signed) {
+ //assert(n_size != imm.get_size());
+ args.add(EncoderBase::Operand(sz, value,
+ is_signed ? OpndExt_Signed : OpndExt_Zero));
+}
+
+#define MAX_DECODED_STRING_LEN 1024
+char tmpBuffer[MAX_DECODED_STRING_LEN];
+
+void printOperand(const EncoderBase::Operand & opnd) {
+ unsigned int sz;
+ if(!dump_x86_inst) return;
+ sz = strlen(tmpBuffer);
+ if(opnd.size() != OpndSize_32) {
+ sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%s ",
+ getOpndSizeString(opnd.size()));
+ }
+ if(opnd.is_mem()) {
+ if(opnd.scale() != 0) {
+ sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz,
+ "%d(%s,%s,%d)", opnd.disp(),
+ getRegNameString(opnd.base()),
+ getRegNameString(opnd.index()), opnd.scale());
+ } else {
+ sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%d(%s)",
+ opnd.disp(), getRegNameString(opnd.base()));
+ }
+ }
+ if(opnd.is_imm()) {
+ sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "#%x",
+ (int)opnd.imm());
+ }
+ if(opnd.is_reg()) {
+ sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%s",
+ getRegNameString(opnd.reg()));
+ }
+}
+//TODO: the order of operands
+//to make the printout have the same order as assembly in .S
+//I reverse the order here
+void printDecoderInst(Inst & decInst) {
+ unsigned int sz;
+ if(!dump_x86_inst) return;
+ sz = strlen(tmpBuffer);
+ sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%s ",
+ EncoderBase::toStr(decInst.mn));
+ for(unsigned int k = 0; k < decInst.argc; k++) {
+ if(k > 0) {
+ sz = strlen(tmpBuffer);
+ sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, ", ");
+ }
+ printOperand(decInst.operands[decInst.argc-1-k]);
+ }
+ ALOGE("%s", tmpBuffer);
+}
+void printOperands(EncoderBase::Operands& opnds) {
+ unsigned int sz;
+ if(!dump_x86_inst) return;
+ for(unsigned int k = 0; k < opnds.count(); k++) {
+ if(k > 0) {
+ sz = strlen(tmpBuffer);
+ sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, ", ");
+ }
+ printOperand(opnds[opnds.count()-1-k]);
+ }
+}
+void printEncoderInst(Mnemonic m, EncoderBase::Operands& opnds) {
+ if(!dump_x86_inst) return;
+ snprintf(tmpBuffer, MAX_DECODED_STRING_LEN, "--- ENC %s ",
+ EncoderBase::toStr(m));
+ printOperands(opnds);
+ ALOGE("%s", tmpBuffer);
+}
+int decodeThenPrint(char* stream_start) {
+ if(!dump_x86_inst) return 0;
+ snprintf(tmpBuffer, MAX_DECODED_STRING_LEN, "--- INST @ %p: ",
+ stream_start);
+ Inst decInst;
+ unsigned numBytes = DecoderBase::decode(stream_start, &decInst);
+ printDecoderInst(decInst);
+ return numBytes;
+}
+
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm(Mnemonic m, OpndSize size, int imm, char * stream) {
+ EncoderBase::Operands args;
+ //assert(imm.get_size() == size_32);
+ add_imm(args, size, imm, true/*is_signed*/);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT unsigned encoder_get_inst_size(char * stream) {
+ Inst decInst;
+ unsigned numBytes = DecoderBase::decode(stream, &decInst);
+ return numBytes;
+}
+
+extern "C" ENCODER_DECLARE_EXPORT unsigned encoder_get_cur_operand_offset(int opnd_id)
+{
+ return (unsigned)EncoderBase::getOpndLocation(opnd_id);
+}
+
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_update_imm(int imm, char * stream) {
+ Inst decInst;
+ unsigned numBytes = DecoderBase::decode(stream, &decInst);
+ EncoderBase::Operands args;
+ //assert(imm.get_size() == size_32);
+ add_imm(args, decInst.operands[0].size(), imm, true/*is_signed*/);
+ char* stream_next = (char *)EncoderBase::encode(stream, decInst.mn, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(decInst.mn, args);
+ decodeThenPrint(stream);
+#endif
+ return stream_next;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical, char * stream) {
+ EncoderBase::Operands args;
+ add_m(args, base_reg, disp, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical, LowOpndRegType type, char * stream) {
+ EncoderBase::Operands args;
+ if(m == Mnemonic_IDIV || m == Mnemonic_MUL || m == Mnemonic_IMUL) {
+ add_r(args, 0/*eax*/, size);
+ add_r(args, 3/*edx*/, size);
+ }
+ add_r(args, reg, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+//both operands have same size
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg_reg(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2, LowOpndRegType type, char * stream) {
+ if((m == Mnemonic_MOV || m == Mnemonic_MOVQ) && reg == reg2) return stream;
+ EncoderBase::Operands args;
+ add_r(args, reg2, size); //destination
+ if(m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL || m == Mnemonic_SAR)
+ add_r(args, reg, OpndSize_8);
+ else
+ add_r(args, reg, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_reg(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical, LowOpndRegType type, char * stream) {
+ EncoderBase::Operands args;
+ add_r(args, reg, size);
+ add_m(args, base_reg, disp, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_scale_reg(Mnemonic m, OpndSize size,
+ int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical, LowOpndRegType type, char * stream) {
+ EncoderBase::Operands args;
+ add_r(args, reg, size);
+ add_m_scale(args, base_reg, index_reg, scale, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg_mem_scale(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale,
+ LowOpndRegType type, char * stream) {
+ EncoderBase::Operands args;
+ add_m_scale(args, base_reg, index_reg, scale, size);
+ add_r(args, reg, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_disp_scale_reg(Mnemonic m, OpndSize size,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical, LowOpndRegType type, char * stream) {
+ EncoderBase::Operands args;
+ add_r(args, reg, size);
+ add_m_disp_scale(args, base_reg, disp, index_reg, scale, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_movzs_mem_disp_scale_reg(Mnemonic m, OpndSize size,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical, LowOpndRegType type, char * stream) {
+ EncoderBase::Operands args;
+ add_r(args, reg, OpndSize_32);
+ add_m_disp_scale(args, base_reg, disp, index_reg, scale, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+
+extern "C" ENCODER_DECLARE_EXPORT char* encoder_reg_mem_disp_scale(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ LowOpndRegType type, char* stream) {
+ EncoderBase::Operands args;
+ add_m_disp_scale(args, base_reg, disp, index_reg, scale, size);
+ add_r(args, reg, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg_mem(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical, LowOpndRegType type, char * stream) {
+ EncoderBase::Operands args;
+ add_m(args, base_reg, disp, size);
+ add_r(args, reg, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm_reg(Mnemonic m, OpndSize size,
+ int imm, int reg, bool isPhysical, LowOpndRegType type, char * stream) {
+ EncoderBase::Operands args;
+ add_r(args, reg, size); //dst
+ if(m == Mnemonic_IMUL) add_r(args, reg, size); //src CHECK
+ if(m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL
+ || m == Mnemonic_SAR || m == Mnemonic_ROR) //fix for shift opcodes
+ add_imm(args, OpndSize_8, imm, true/*is_signed*/);
+ else
+ add_imm(args, size, imm, true/*is_signed*/);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_update_imm_rm(int imm, char * stream) {
+ Inst decInst;
+ unsigned numBytes = DecoderBase::decode(stream, &decInst);
+ EncoderBase::Operands args;
+ args.add(decInst.operands[0]);
+ add_imm(args, decInst.operands[1].size(), imm, true/*is_signed*/);
+ char* stream_next = (char *)EncoderBase::encode(stream, decInst.mn, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(decInst.mn, args);
+ decodeThenPrint(stream);
+#endif
+ return stream_next;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm_mem(Mnemonic m, OpndSize size,
+ int imm,
+ int disp, int base_reg, bool isBasePhysical, char * stream) {
+ EncoderBase::Operands args;
+ add_m(args, base_reg, disp, size);
+ if (m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL
+ || m == Mnemonic_SAR || m == Mnemonic_ROR)
+ size = OpndSize_8;
+ add_imm(args, size, imm, true);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_fp_mem(Mnemonic m, OpndSize size, int reg,
+ int disp, int base_reg, bool isBasePhysical, char * stream) {
+ EncoderBase::Operands args;
+ add_m(args, base_reg, disp, size);
+ // a fake FP register as operand
+ add_fp(args, reg, size == OpndSize_64/*is_double*/);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_fp(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, char * stream) {
+ EncoderBase::Operands args;
+ // a fake FP register as operand
+ add_fp(args, reg, size == OpndSize_64/*is_double*/);
+ add_m(args, base_reg, disp, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_return(char * stream) {
+ EncoderBase::Operands args;
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, Mnemonic_RET, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(Mnemonic_RET, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_compare_fp_stack(bool pop, int reg, bool isDouble, char * stream) {
+ //Mnemonic m = pop ? Mnemonic_FUCOMP : Mnemonic_FUCOM;
+ Mnemonic m = pop ? Mnemonic_FUCOMIP : Mnemonic_FUCOMI;
+ //a single operand or 2 operands?
+ //FST ST(i) has a single operand in encoder.inl?
+ EncoderBase::Operands args;
+ add_fp(args, reg, isDouble);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, m, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(m, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_movez_mem_to_reg(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical, char * stream) {
+ EncoderBase::Operands args;
+ add_r(args, reg, OpndSize_32);
+ add_m(args, base_reg, disp, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVZX, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(Mnemonic_MOVZX, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_moves_mem_to_reg(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical, char * stream) {
+ EncoderBase::Operands args;
+ add_r(args, reg, OpndSize_32);
+ add_m(args, base_reg, disp, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVSX, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(Mnemonic_MOVSX, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_movez_reg_to_reg(OpndSize size,
+ int reg, bool isPhysical, int reg2,
+ bool isPhysical2, LowOpndRegType type, char * stream) {
+ EncoderBase::Operands args;
+ add_r(args, reg2, OpndSize_32); //destination
+ add_r(args, reg, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVZX, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(Mnemonic_MOVZX, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+extern "C" ENCODER_DECLARE_EXPORT char * encoder_moves_reg_to_reg(OpndSize size,
+ int reg, bool isPhysical,int reg2,
+ bool isPhysical2, LowOpndRegType type, char * stream) {
+ EncoderBase::Operands args;
+ add_r(args, reg2, OpndSize_32); //destination
+ add_r(args, reg, size);
+ char* stream_start = stream;
+ stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVSX, args);
+#ifdef PRINT_ENCODER_STREAM
+ printEncoderInst(Mnemonic_MOVSX, args);
+ decodeThenPrint(stream_start);
+#endif
+ return stream;
+}
+
+// Disassemble the operand "opnd" and put the readable format in "strbuf"
+// up to a string length of "len".
+unsigned int DisassembleOperandToBuf(const EncoderBase::Operand& opnd, char* strbuf, unsigned int len)
+{
+ unsigned int sz = 0;
+ if(opnd.size() != OpndSize_32) {
+ sz += snprintf(&strbuf[sz], len-sz, "%s ",
+ getOpndSizeString(opnd.size()));
+ }
+ if(opnd.is_mem()) {
+ if(opnd.scale() != 0) {
+ sz += snprintf(&strbuf[sz], len-sz, "%d(%s,%s,%d)", opnd.disp(),
+ getRegNameString(opnd.base()),
+ getRegNameString(opnd.index()), opnd.scale());
+ } else {
+ sz += snprintf(&strbuf[sz], len-sz, "%d(%s)",
+ opnd.disp(), getRegNameString(opnd.base()));
+ }
+ } else if(opnd.is_imm()) {
+ sz += snprintf(&strbuf[sz], len-sz, "#%x", (int)opnd.imm());
+ } else if(opnd.is_reg()) {
+ sz += snprintf(&strbuf[sz], len-sz, "%s",
+ getRegNameString(opnd.reg()));
+ }
+ return sz;
+}
+
+// Disassemble the instruction "decInst" and put the readable format
+// in "strbuf" up to a string length of "len".
+void DisassembleInstToBuf(Inst& decInst, char* strbuf, unsigned int len)
+{
+ unsigned int sz = 0;
+ int k;
+ sz += snprintf(&strbuf[sz], len-sz, "%s ", EncoderBase::toStr(decInst.mn));
+ if (decInst.argc > 0) {
+ sz += DisassembleOperandToBuf(decInst.operands[decInst.argc-1],
+ &strbuf[sz], len-sz);
+ for(k = decInst.argc-2; k >= 0; k--) {
+ sz += snprintf(&strbuf[sz], len-sz, ", ");
+ sz += DisassembleOperandToBuf(decInst.operands[k], &strbuf[sz], len-sz);
+ }
+ }
+}
+
+// Disassmble the x86 instruction pointed to by code pointer "stream."
+// Put the disassemble text in the "strbuf" up to string length "len".
+// Return the code pointer after the disassemble x86 instruction.
+extern "C" ENCODER_DECLARE_EXPORT
+char* decoder_disassemble_instr(char* stream, char* strbuf, unsigned int len)
+{
+ Inst decInst;
+ unsigned numBytes = DecoderBase::decode(stream, &decInst);
+ DisassembleInstToBuf(decInst, strbuf, len);
+ return (stream + numBytes);
+}
diff --git a/vm/compiler/codegen/x86/libenc/enc_wrapper.h b/vm/compiler/codegen/x86/libenc/enc_wrapper.h
new file mode 100644
index 0000000..a2a223e
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/enc_wrapper.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _VM_ENC_WRAPPER_H_
+#define _VM_ENC_WRAPPER_H_
+
+#include "enc_defs_ext.h"
+
+extern bool dump_x86_inst;
+typedef enum PhysicalReg {
+ PhysicalReg_EAX = 0, PhysicalReg_EBX, PhysicalReg_ECX, PhysicalReg_EDX,
+ PhysicalReg_EDI, PhysicalReg_ESI, PhysicalReg_ESP, PhysicalReg_EBP,
+ PhysicalReg_XMM0, PhysicalReg_XMM1, PhysicalReg_XMM2, PhysicalReg_XMM3,
+ PhysicalReg_XMM4, PhysicalReg_XMM5, PhysicalReg_XMM6, PhysicalReg_XMM7,
+ PhysicalReg_ST0, PhysicalReg_ST1, PhysicalReg_ST2, PhysicalReg_ST3,
+ PhysicalReg_ST4, PhysicalReg_ST5, PhysicalReg_ST6, PhysicalReg_ST7,
+ PhysicalReg_Null,
+ //used as scratch logical register in NCG O1
+ //should not overlap with regular logical register, start from 100
+ PhysicalReg_SCRATCH_1 = 100, PhysicalReg_SCRATCH_2, PhysicalReg_SCRATCH_3, PhysicalReg_SCRATCH_4,
+ PhysicalReg_SCRATCH_5, PhysicalReg_SCRATCH_6, PhysicalReg_SCRATCH_7, PhysicalReg_SCRATCH_8,
+ PhysicalReg_SCRATCH_9, PhysicalReg_SCRATCH_10,
+ PhysicalReg_GLUE_DVMDEX = 900,
+ PhysicalReg_GLUE = 901
+} PhysicalReg;
+
+typedef enum Reg_No {
+#ifdef _EM64T_
+ rax_reg = 0,rbx_reg, rcx_reg, rdx_reg,
+ rdi_reg, rsi_reg, rsp_reg, rbp_reg,
+ r8_reg, r9_reg, r10_reg, r11_reg,
+ r12_reg, r13_reg, r14_reg, r15_reg,
+ xmm0_reg, xmm1_reg, xmm2_reg, xmm3_reg,
+ xmm4_reg, xmm5_reg, xmm6_reg, xmm7_reg,
+ xmm8_reg, xmm9_reg, xmm10_reg, xmm11_reg,
+ xmm12_reg, xmm13_reg, xmm14_reg, xmm15_reg,
+
+#else // !defined(_EM64T_)
+
+ eax_reg = 0,ebx_reg, ecx_reg, edx_reg,
+ edi_reg, esi_reg, esp_reg, ebp_reg,
+ xmm0_reg, xmm1_reg, xmm2_reg, xmm3_reg,
+ xmm4_reg, xmm5_reg, xmm6_reg, xmm7_reg,
+ fs_reg,
+#endif
+ /** @brief Total number of registers.*/
+ n_reg
+} Reg_No;
+//
+// instruction operand sizes: 8,16,32,64 bits
+//
+typedef enum Opnd_Size {
+ size_8 = 0,
+ size_16,
+ size_32,
+ size_64,
+ n_size,
+#ifdef _EM64T_
+ size_platf = size_64
+#else
+ size_platf = size_32
+#endif
+} Opnd_Size;
+
+//
+// opcodes for alu instructions
+//
+typedef enum ALU_Opcode {
+ add_opc = 0,or_opc, adc_opc, sbb_opc,
+ and_opc, sub_opc, xor_opc, cmp_opc,
+ mul_opc, imul_opc, div_opc, idiv_opc,
+ sll_opc, srl_opc, sra_opc, //shift right arithmetic
+ shl_opc, shr_opc,
+ sal_opc, sar_opc,
+ neg_opc, not_opc, andn_opc,
+ n_alu
+} ALU_Opcode;
+
+typedef enum ConditionCode {
+ Condition_O = 0,
+ Condition_NO = 1,
+ Condition_B = 2,
+ Condition_NAE = Condition_B,
+ Condition_C = Condition_B,
+ Condition_NB = 3,
+ Condition_AE = Condition_NB,
+ Condition_NC = Condition_NB,
+ Condition_Z = 4,
+ Condition_E = Condition_Z,
+ Condition_NZ = 5,
+ Condition_NE = Condition_NZ,
+ Condition_BE = 6,
+ Condition_NA = Condition_BE,
+ Condition_NBE = 7,
+ Condition_A = Condition_NBE,
+
+ Condition_S = 8,
+ Condition_NS = 9,
+ Condition_P = 10,
+ Condition_PE = Condition_P,
+ Condition_NP = 11,
+ Condition_PO = Condition_NP,
+ Condition_L = 12,
+ Condition_NGE = Condition_L,
+ Condition_NL = 13,
+ Condition_GE = Condition_NL,
+ Condition_LE = 14,
+ Condition_NG = Condition_LE,
+ Condition_NLE = 15,
+ Condition_G = Condition_NLE,
+ Condition_Count = 16
+} ConditionCode;
+
+//
+// prefix code
+//
+typedef enum InstrPrefix {
+ no_prefix,
+ lock_prefix = 0xF0,
+ hint_branch_taken_prefix = 0x2E,
+ hint_branch_not_taken_prefix = 0x3E,
+ prefix_repne = 0xF2,
+ prefix_repnz = prefix_repne,
+ prefix_repe = 0xF3,
+ prefix_repz = prefix_repe,
+ prefix_rep = 0xF3,
+ prefix_cs = 0x2E,
+ prefix_ss = 0x36,
+ prefix_ds = 0x3E,
+ prefix_es = 0x26,
+ prefix_fs = 0x64,
+ prefix_gs = 0x65
+} InstrPrefix;
+
+//last 2 bits: decide xmm, gp, fs
+//virtual, scratch, temp, hard match with ncg_o1_data.h
+typedef enum LowOpndRegType {
+ LowOpndRegType_gp = 0,
+ LowOpndRegType_fs = 1,
+ LowOpndRegType_xmm = 2,
+ LowOpndRegType_fs_s = 3,
+ LowOpndRegType_ss = 4,
+ LowOpndRegType_scratch = 8, //used by NCG O1
+ LowOpndRegType_temp = 16,
+ LowOpndRegType_hard = 32, //NCG O1
+ LowOpndRegType_virtual = 64, //used by NCG O1
+ LowOpndRegType_glue = 128
+} LowOpndRegType;
+
+//if inline, separte enc_wrapper.cpp into two files, one of them is .inl
+// enc_wrapper.cpp needs to handle both cases
+#ifdef ENCODER_INLINE
+ #define ENCODER_DECLARE_EXPORT inline
+ #include "enc_wrapper.inl"
+#else
+ #define ENCODER_DECLARE_EXPORT
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+ENCODER_DECLARE_EXPORT char* encoder_imm(Mnemonic m, OpndSize size,
+ int imm, char* stream);
+ENCODER_DECLARE_EXPORT unsigned encoder_get_inst_size(char * stream);
+ENCODER_DECLARE_EXPORT char* encoder_update_imm(int imm, char * stream);
+ENCODER_DECLARE_EXPORT char* encoder_mem(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_reg(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical, LowOpndRegType type, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_reg_reg(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int reg2, bool isPhysical2, LowOpndRegType type, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_mem_reg(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical, LowOpndRegType type, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_mem_scale_reg(Mnemonic m, OpndSize size,
+ int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical, LowOpndRegType type, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_reg_mem_scale(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale,
+ LowOpndRegType type, char* stream);
+ENCODER_DECLARE_EXPORT char * encoder_mem_disp_scale_reg(Mnemonic m, OpndSize size,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical, LowOpndRegType type, char * stream);
+ENCODER_DECLARE_EXPORT char * encoder_movzs_mem_disp_scale_reg(Mnemonic m, OpndSize size,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ int reg, bool isPhysical, LowOpndRegType type, char * stream);
+ENCODER_DECLARE_EXPORT char* encoder_reg_mem_disp_scale(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
+ LowOpndRegType type, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_reg_mem(Mnemonic m, OpndSize size,
+ int reg, bool isPhysical,
+ int disp, int base_reg, bool isBasePhysical, LowOpndRegType type, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_imm_reg(Mnemonic m, OpndSize size,
+ int imm, int reg, bool isPhysical, LowOpndRegType type, char* stream);
+ENCODER_DECLARE_EXPORT char * encoder_update_imm_rm(int imm, char * stream);
+ENCODER_DECLARE_EXPORT char* encoder_imm_mem(Mnemonic m, OpndSize size,
+ int imm,
+ int disp, int base_reg, bool isBasePhysical, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_fp_mem(Mnemonic m, OpndSize size, int reg,
+ int disp, int base_reg, bool isBasePhysical, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_mem_fp(Mnemonic m, OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_return(char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_compare_fp_stack(bool pop, int reg, bool isDouble, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_movez_mem_to_reg(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical, char* stream);
+ENCODER_DECLARE_EXPORT char* encoder_moves_mem_to_reg(OpndSize size,
+ int disp, int base_reg, bool isBasePhysical,
+ int reg, bool isPhysical, char* stream);
+ENCODER_DECLARE_EXPORT char * encoder_movez_reg_to_reg(OpndSize size,
+ int reg, bool isPhysical, int reg2,
+ bool isPhysical2, LowOpndRegType type, char * stream);
+ENCODER_DECLARE_EXPORT char * encoder_moves_reg_to_reg(OpndSize size,
+ int reg, bool isPhysical, int reg2,
+ bool isPhysical2, LowOpndRegType type, char * stream);
+ENCODER_DECLARE_EXPORT int decodeThenPrint(char* stream_start);
+ENCODER_DECLARE_EXPORT char* decoder_disassemble_instr(char* stream, char* strbuf, unsigned int len);
+#ifdef __cplusplus
+}
+#endif
+#endif // _VM_ENC_WRAPPER_H_
diff --git a/vm/compiler/codegen/x86/libenc/encoder.cpp b/vm/compiler/codegen/x86/libenc/encoder.cpp
new file mode 100644
index 0000000..ef08a4d
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/encoder.cpp
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+#include <stdio.h>
+#include <assert.h>
+
+#include <limits.h>
+
+#include "enc_base.h"
+
+#ifdef NO_ENCODER_INLINE
+ #include "encoder.h"
+ #include "encoder.inl"
+#else
+ #define NO_ENCODER_INLINE
+ #include "encoder.h"
+ #undef NO_ENCODER_INLINE
+#endif
+
+
+
+#ifdef _EM64T_
+
+R_Opnd rax_opnd(rax_reg);
+R_Opnd rcx_opnd(rcx_reg);
+R_Opnd rdx_opnd(rdx_reg);
+R_Opnd rbx_opnd(rbx_reg);
+R_Opnd rsp_opnd(rsp_reg);
+R_Opnd rbp_opnd(rbp_reg);
+R_Opnd rsi_opnd(rsi_reg);
+R_Opnd rdi_opnd(rdi_reg);
+
+R_Opnd r8_opnd(r8_reg);
+R_Opnd r9_opnd(r9_reg);
+R_Opnd r10_opnd(r10_reg);
+R_Opnd r11_opnd(r11_reg);
+R_Opnd r12_opnd(r12_reg);
+R_Opnd r13_opnd(r13_reg);
+R_Opnd r14_opnd(r14_reg);
+R_Opnd r15_opnd(r15_reg);
+
+XMM_Opnd xmm8_opnd(xmm8_reg);
+XMM_Opnd xmm9_opnd(xmm9_reg);
+XMM_Opnd xmm10_opnd(xmm10_reg);
+XMM_Opnd xmm11_opnd(xmm11_reg);
+XMM_Opnd xmm12_opnd(xmm12_reg);
+XMM_Opnd xmm13_opnd(xmm13_reg);
+XMM_Opnd xmm14_opnd(xmm14_reg);
+XMM_Opnd xmm15_opnd(xmm15_reg);
+
+#else
+
+R_Opnd eax_opnd(eax_reg);
+R_Opnd ecx_opnd(ecx_reg);
+R_Opnd edx_opnd(edx_reg);
+R_Opnd ebx_opnd(ebx_reg);
+R_Opnd esp_opnd(esp_reg);
+R_Opnd ebp_opnd(ebp_reg);
+R_Opnd esi_opnd(esi_reg);
+R_Opnd edi_opnd(edi_reg);
+
+#endif //_EM64T_
+
+XMM_Opnd xmm0_opnd(xmm0_reg);
+XMM_Opnd xmm1_opnd(xmm1_reg);
+XMM_Opnd xmm2_opnd(xmm2_reg);
+XMM_Opnd xmm3_opnd(xmm3_reg);
+XMM_Opnd xmm4_opnd(xmm4_reg);
+XMM_Opnd xmm5_opnd(xmm5_reg);
+XMM_Opnd xmm6_opnd(xmm6_reg);
+XMM_Opnd xmm7_opnd(xmm7_reg);
+
+
+#define countof(a) (sizeof(a)/sizeof(a[0]))
+
+extern const RegName map_of_regno_2_regname[];
+extern const OpndSize map_of_EncoderOpndSize_2_RealOpndSize[];
+extern const Mnemonic map_of_alu_opcode_2_mnemonic[];
+extern const Mnemonic map_of_shift_opcode_2_mnemonic[];
+
+const RegName map_of_regno_2_regname [] = {
+#ifdef _EM64T_
+ RegName_RAX, RegName_RBX, RegName_RCX, RegName_RDX,
+ RegName_RDI, RegName_RSI, RegName_RSP, RegName_RBP,
+ RegName_R8, RegName_R9, RegName_R10, RegName_R11,
+ RegName_R12, RegName_R13, RegName_R14, RegName_R15,
+ RegName_XMM0, RegName_XMM1, RegName_XMM2, RegName_XMM3,
+ RegName_XMM4, RegName_XMM5, RegName_XMM6, RegName_XMM7,
+ RegName_XMM8, RegName_XMM9, RegName_XMM10, RegName_XMM11,
+ RegName_XMM12, RegName_XMM13, RegName_XMM14, RegName_XMM15,
+
+#else
+ RegName_EAX, RegName_EBX, RegName_ECX, RegName_EDX,
+ RegName_EDI, RegName_ESI, RegName_ESP, RegName_EBP,
+ RegName_XMM0, RegName_XMM1, RegName_XMM2, RegName_XMM3,
+ RegName_XMM4, RegName_XMM5, RegName_XMM6, RegName_XMM7,
+ RegName_FS,
+#endif // _EM64T_
+
+ RegName_Null,
+};
+
+const OpndSize map_of_EncoderOpndSize_2_RealOpndSize[] = {
+ OpndSize_8, OpndSize_16, OpndSize_32, OpndSize_64, OpndSize_Any
+};
+
+const Mnemonic map_of_alu_opcode_2_mnemonic[] = {
+ //add_opc=0, or_opc, adc_opc, sbb_opc,
+ //and_opc, sub_opc, xor_opc, cmp_opc,
+ //n_alu
+ Mnemonic_ADD, Mnemonic_OR, Mnemonic_ADC, Mnemonic_SBB,
+ Mnemonic_AND, Mnemonic_SUB, Mnemonic_XOR, Mnemonic_CMP,
+};
+
+const Mnemonic map_of_shift_opcode_2_mnemonic[] = {
+ //shld_opc, shrd_opc,
+ // shl_opc, shr_opc, sar_opc, ror_opc, max_shift_opcode=6,
+ // n_shift = 6
+ Mnemonic_SHLD, Mnemonic_SHRD,
+ Mnemonic_SHL, Mnemonic_SHR, Mnemonic_SAR, Mnemonic_ROR
+};
+
+#ifdef _DEBUG
+
+static int debug_check() {
+ // Checks some assumptions.
+
+ // 1. all items of Encoder.h:enum Reg_No must be mapped plus n_reg->RegName_Null
+ assert(countof(map_of_regno_2_regname) == n_reg + 1);
+ assert(countof(map_of_alu_opcode_2_mnemonic) == n_alu);
+ assert(countof(map_of_shift_opcode_2_mnemonic) == n_shift);
+ return 0;
+}
+
+static int dummy = debug_check();
+
+// can have this - initialization order problems.... static int dummy_run_the_debug_test = debug_check();
+
+#endif
diff --git a/vm/compiler/codegen/x86/libenc/encoder.h b/vm/compiler/codegen/x86/libenc/encoder.h
new file mode 100644
index 0000000..e29efce
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/encoder.h
@@ -0,0 +1,716 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+/**
+ * @file
+ * @brief Simple interface for generating processor instructions.
+ *
+ * The interface works for both IA32 and EM64T. By default, only IA32
+ * capabilities are presented. To enable EM64T feature, the _EM64T_ macro
+ * must be defined (and, of course, a proper library version to be used).
+ *
+ * The interface is based on the original ia32.h encoder interface,
+ * with some simplifications and add-ons - EM64T-specific, SSE and SSE2.
+ *
+ * The interface mostly intended for existing legacy code like LIL code
+ * generator. From the implementation point of view, it's just a wrapper
+ * around the EncoderBase functionality.
+ */
+
+#ifndef _VM_ENCODER_H_
+#define _VM_ENCODER_H_
+
+#include <limits.h>
+#include "enc_base.h"
+//#include "open/types.h"
+
+#ifdef _EM64T_
+// size of general-purpose value on the stack in bytes
+#define GR_STACK_SIZE 8
+// size of floating-point value on the stack in bytes
+#define FR_STACK_SIZE 8
+
+#if defined(WIN32) || defined(_WIN64)
+ // maximum number of GP registers for inputs
+ const int MAX_GR = 4;
+ // maximum number of FP registers for inputs
+ const int MAX_FR = 4;
+ // WIN64 reserves 4 words for shadow space
+ const int SHADOW = 4 * GR_STACK_SIZE;
+#else
+ // maximum number of GP registers for inputs
+ const int MAX_GR = 6;
+ // maximum number of FP registers for inputs
+ const int MAX_FR = 8;
+ // Linux x64 doesn't reserve shadow space
+ const int SHADOW = 0;
+#endif
+
+#else
+// size of general-purpose value on the stack in bytes
+#define GR_STACK_SIZE 4
+// size of general-purpose value on the stack in bytes
+#define FR_STACK_SIZE 8
+
+// maximum number of GP registers for inputs
+const int MAX_GR = 0;
+// maximum number of FP registers for inputs
+const int MAX_FR = 0;
+#endif
+
+typedef enum Reg_No {
+#ifdef _EM64T_
+ rax_reg = 0,rbx_reg, rcx_reg, rdx_reg,
+ rdi_reg, rsi_reg, rsp_reg, rbp_reg,
+ r8_reg, r9_reg, r10_reg, r11_reg,
+ r12_reg, r13_reg, r14_reg, r15_reg,
+ xmm0_reg, xmm1_reg, xmm2_reg, xmm3_reg,
+ xmm4_reg, xmm5_reg, xmm6_reg, xmm7_reg,
+ xmm8_reg, xmm9_reg, xmm10_reg, xmm11_reg,
+ xmm12_reg, xmm13_reg, xmm14_reg, xmm15_reg,
+
+#else // !defined(_EM64T_)
+
+ eax_reg = 0,ebx_reg, ecx_reg, edx_reg,
+ edi_reg, esi_reg, esp_reg, ebp_reg,
+ xmm0_reg, xmm1_reg, xmm2_reg, xmm3_reg,
+ xmm4_reg, xmm5_reg, xmm6_reg, xmm7_reg,
+ fs_reg,
+#endif
+ /** @brief Total number of registers.*/
+ n_reg
+} Reg_No;
+//
+// instruction operand sizes: 8,16,32,64 bits
+//
+typedef enum Opnd_Size {
+ size_8 = 0,
+ size_16,
+ size_32,
+ size_64,
+ n_size,
+#ifdef _EM64T_
+ size_platf = size_64
+#else
+ size_platf = size_32
+#endif
+} Opnd_Size;
+
+//
+// opcodes for alu instructions
+//
+typedef enum ALU_Opcode {
+ add_opc = 0,or_opc, adc_opc, sbb_opc,
+ and_opc, sub_opc, xor_opc, cmp_opc,
+ n_alu
+} ALU_Opcode;
+
+//
+// opcodes for shift instructions
+//
+typedef enum Shift_Opcode {
+ shld_opc, shrd_opc, shl_opc, shr_opc,
+ sar_opc, ror_opc, max_shift_opcode=6, n_shift = 6
+} Shift_Opcode;
+
+typedef enum ConditionCode {
+ Condition_O = 0,
+ Condition_NO = 1,
+ Condition_B = 2,
+ Condition_NAE = Condition_B,
+ Condition_C = Condition_B,
+ Condition_NB = 3,
+ Condition_AE = Condition_NB,
+ Condition_NC = Condition_NB,
+ Condition_Z = 4,
+ Condition_E = Condition_Z,
+ Condition_NZ = 5,
+ Condition_NE = Condition_NZ,
+ Condition_BE = 6,
+ Condition_NA = Condition_BE,
+ Condition_NBE = 7,
+ Condition_A = Condition_NBE,
+
+ Condition_S = 8,
+ Condition_NS = 9,
+ Condition_P = 10,
+ Condition_PE = Condition_P,
+ Condition_NP = 11,
+ Condition_PO = Condition_NP,
+ Condition_L = 12,
+ Condition_NGE = Condition_L,
+ Condition_NL = 13,
+ Condition_GE = Condition_NL,
+ Condition_LE = 14,
+ Condition_NG = Condition_LE,
+ Condition_NLE = 15,
+ Condition_G = Condition_NLE,
+ Condition_Count = 16
+} ConditionCode;
+
+//
+// prefix code
+//
+typedef enum InstrPrefix {
+ no_prefix,
+ lock_prefix = 0xF0,
+ hint_branch_taken_prefix = 0x2E,
+ hint_branch_not_taken_prefix = 0x3E,
+ prefix_repne = 0xF2,
+ prefix_repnz = prefix_repne,
+ prefix_repe = 0xF3,
+ prefix_repz = prefix_repe,
+ prefix_rep = 0xF3,
+ prefix_cs = 0x2E,
+ prefix_ss = 0x36,
+ prefix_ds = 0x3E,
+ prefix_es = 0x26,
+ prefix_fs = 0x64,
+ prefix_gs = 0x65
+} InstrPrefix;
+
+
+//
+// an instruction operand
+//
+class Opnd {
+
+protected:
+ enum Tag { SignedImm, UnsignedImm, Reg, Mem, FP, XMM };
+
+ const Tag tag;
+
+ Opnd(Tag t): tag(t) {}
+
+public:
+ void * operator new(size_t, void * mem) {
+ return mem;
+ }
+
+ void operator delete(void *) {}
+
+ void operator delete(void *, void *) {}
+
+private:
+ // disallow copying
+ Opnd(const Opnd &): tag(Mem) { assert(false); }
+ Opnd& operator=(const Opnd &) { assert(false); return *this; }
+};
+typedef int I_32;
+class Imm_Opnd: public Opnd {
+
+protected:
+ union {
+#ifdef _EM64T_
+ int64 value;
+ unsigned char bytes[8];
+#else
+ I_32 value;
+ unsigned char bytes[4];
+#endif
+ };
+ Opnd_Size size;
+
+public:
+ Imm_Opnd(I_32 val, bool isSigned = true):
+ Opnd(isSigned ? SignedImm : UnsignedImm), value(val), size(size_32) {
+ if (isSigned) {
+ if (CHAR_MIN <= val && val <= CHAR_MAX) {
+ size = size_8;
+ } else if (SHRT_MIN <= val && val <= SHRT_MAX) {
+ size = size_16;
+ }
+ } else {
+ assert(val >= 0);
+ if (val <= UCHAR_MAX) {
+ size = size_8;
+ } else if (val <= USHRT_MAX) {
+ size = size_16;
+ }
+ }
+ }
+ Imm_Opnd(const Imm_Opnd& that): Opnd(that.tag), value(that.value), size(that.size) {};
+
+#ifdef _EM64T_
+ Imm_Opnd(Opnd_Size sz, int64 val, bool isSigned = true):
+ Opnd(isSigned ? SignedImm : UnsignedImm), value(val), size(sz) {
+#ifndef NDEBUG
+ switch (size) {
+ case size_8:
+ assert(val == (int64)(I_8)val);
+ break;
+ case size_16:
+ assert(val == (int64)(int16)val);
+ break;
+ case size_32:
+ assert(val == (int64)(I_32)val);
+ break;
+ case size_64:
+ break;
+ case n_size:
+ assert(false);
+ break;
+ }
+#endif // NDEBUG
+ }
+
+ int64 get_value() const { return value; }
+
+#else
+
+ Imm_Opnd(Opnd_Size sz, I_32 val, int isSigned = true):
+ Opnd(isSigned ? SignedImm : UnsignedImm), value(val), size(sz) {
+#ifndef NDEBUG
+ switch (size) {
+ case size_8:
+ assert((I_32)val == (I_32)(I_8)val);
+ break;
+ case size_16:
+ assert((I_32)val == (I_32)(int16)val);
+ break;
+ case size_32:
+ break;
+ case size_64:
+ case n_size:
+ assert(false);
+ break;
+ }
+#endif // NDEBUG
+ }
+
+ I_32 get_value() const { return value; }
+
+#endif
+ Opnd_Size get_size() const { return size; }
+ bool is_signed() const { return tag == SignedImm; }
+};
+
+class RM_Opnd: public Opnd {
+
+public:
+ bool is_reg() const { return tag != SignedImm && tag != UnsignedImm && tag != Mem; }
+
+protected:
+ RM_Opnd(Tag t): Opnd(t) {}
+
+private:
+ // disallow copying
+ RM_Opnd(const RM_Opnd &): Opnd(Reg) { assert(false); }
+};
+
+class R_Opnd: public RM_Opnd {
+
+protected:
+ Reg_No _reg_no;
+
+public:
+ R_Opnd(Reg_No r): RM_Opnd(Reg), _reg_no(r) {}
+ Reg_No reg_no() const { return _reg_no; }
+
+private:
+ // disallow copying
+ R_Opnd(const R_Opnd &): RM_Opnd(Reg) { assert(false); }
+};
+
+//
+// a memory operand with displacement
+// Can also serve as a full memory operand with base,index, displacement and scale.
+// Use n_reg to specify 'no register', say, for index.
+class M_Opnd: public RM_Opnd {
+
+protected:
+ Imm_Opnd m_disp;
+ Imm_Opnd m_scale;
+ R_Opnd m_index;
+ R_Opnd m_base;
+
+public:
+ //M_Opnd(Opnd_Size sz): RM_Opnd(Mem, K_M, sz), m_disp(0), m_scale(0), m_index(n_reg), m_base(n_reg) {}
+ M_Opnd(I_32 disp):
+ RM_Opnd(Mem), m_disp(disp), m_scale(0), m_index(n_reg), m_base(n_reg) {}
+ M_Opnd(Reg_No rbase, I_32 rdisp):
+ RM_Opnd(Mem), m_disp(rdisp), m_scale(0), m_index(n_reg), m_base(rbase) {}
+ M_Opnd(I_32 disp, Reg_No rbase, Reg_No rindex, unsigned scale):
+ RM_Opnd(Mem), m_disp(disp), m_scale(scale), m_index(rindex), m_base(rbase) {}
+ M_Opnd(const M_Opnd & that) : RM_Opnd(Mem),
+ m_disp((int)that.m_disp.get_value()), m_scale((int)that.m_scale.get_value()),
+ m_index(that.m_index.reg_no()), m_base(that.m_base.reg_no())
+ {}
+ //
+ inline const R_Opnd & base(void) const { return m_base; }
+ inline const R_Opnd & index(void) const { return m_index; }
+ inline const Imm_Opnd & scale(void) const { return m_scale; }
+ inline const Imm_Opnd & disp(void) const { return m_disp; }
+};
+
+//
+// a memory operand with base register and displacement
+//
+class M_Base_Opnd: public M_Opnd {
+
+public:
+ M_Base_Opnd(Reg_No base, I_32 disp) : M_Opnd(disp, base, n_reg, 0) {}
+
+private:
+ // disallow copying - but it leads to ICC errors #734 in encoder.inl
+ // M_Base_Opnd(const M_Base_Opnd &): M_Opnd(0) { assert(false); }
+};
+
+//
+// a memory operand with base register, scaled index register
+// and displacement.
+//
+class M_Index_Opnd : public M_Opnd {
+
+public:
+ M_Index_Opnd(Reg_No base, Reg_No index, I_32 disp, unsigned scale):
+ M_Opnd(disp, base, index, scale) {}
+
+private:
+ // disallow copying - but it leads to ICC errors #734 in encoder.inl
+ // M_Index_Opnd(const M_Index_Opnd &): M_Opnd(0) { assert(false); }
+};
+
+class XMM_Opnd : public Opnd {
+
+protected:
+ unsigned m_idx;
+
+public:
+ XMM_Opnd(unsigned _idx): Opnd(XMM), m_idx(_idx) {};
+ unsigned get_idx( void ) const { return m_idx; };
+
+private:
+ // disallow copying
+ XMM_Opnd(const XMM_Opnd &): Opnd(XMM) { assert(false); }
+};
+
+//
+// operand structures for ia32 registers
+//
+#ifdef _EM64T_
+
+extern R_Opnd rax_opnd;
+extern R_Opnd rcx_opnd;
+extern R_Opnd rdx_opnd;
+extern R_Opnd rbx_opnd;
+extern R_Opnd rdi_opnd;
+extern R_Opnd rsi_opnd;
+extern R_Opnd rsp_opnd;
+extern R_Opnd rbp_opnd;
+
+extern R_Opnd r8_opnd;
+extern R_Opnd r9_opnd;
+extern R_Opnd r10_opnd;
+extern R_Opnd r11_opnd;
+extern R_Opnd r12_opnd;
+extern R_Opnd r13_opnd;
+extern R_Opnd r14_opnd;
+extern R_Opnd r15_opnd;
+
+extern XMM_Opnd xmm8_opnd;
+extern XMM_Opnd xmm9_opnd;
+extern XMM_Opnd xmm10_opnd;
+extern XMM_Opnd xmm11_opnd;
+extern XMM_Opnd xmm12_opnd;
+extern XMM_Opnd xmm13_opnd;
+extern XMM_Opnd xmm14_opnd;
+extern XMM_Opnd xmm15_opnd;
+#else
+
+extern R_Opnd eax_opnd;
+extern R_Opnd ecx_opnd;
+extern R_Opnd edx_opnd;
+extern R_Opnd ebx_opnd;
+extern R_Opnd esp_opnd;
+extern R_Opnd ebp_opnd;
+extern R_Opnd esi_opnd;
+extern R_Opnd edi_opnd;
+
+#endif // _EM64T_
+
+extern XMM_Opnd xmm0_opnd;
+extern XMM_Opnd xmm1_opnd;
+extern XMM_Opnd xmm2_opnd;
+extern XMM_Opnd xmm3_opnd;
+extern XMM_Opnd xmm4_opnd;
+extern XMM_Opnd xmm5_opnd;
+extern XMM_Opnd xmm6_opnd;
+extern XMM_Opnd xmm7_opnd;
+
+#ifdef NO_ENCODER_INLINE
+ #define ENCODER_DECLARE_EXPORT
+#else
+ #define ENCODER_DECLARE_EXPORT inline
+ #include "encoder.inl"
+#endif
+
+// prefix
+ENCODER_DECLARE_EXPORT char * prefix(char * stream, InstrPrefix p);
+
+// stack push and pop instructions
+ENCODER_DECLARE_EXPORT char * push(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * push(char * stream, const Imm_Opnd & imm);
+ENCODER_DECLARE_EXPORT char * pop(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+
+// cmpxchg or xchg
+ENCODER_DECLARE_EXPORT char * cmpxchg(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * xchg(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz = size_platf);
+
+// inc(rement), dec(rement), not, neg(ate) instructions
+ENCODER_DECLARE_EXPORT char * inc(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * dec(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * _not(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * neg(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * nop(char * stream);
+ENCODER_DECLARE_EXPORT char * int3(char * stream);
+
+// alu instructions: add, or, adc, sbb, and, sub, xor, cmp
+ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const M_Opnd & m, const R_Opnd & r, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+
+// test instruction
+ENCODER_DECLARE_EXPORT char * test(char * stream, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * test(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz = size_platf);
+
+// shift instructions: shl, shr, sar, shld, shrd, ror
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode opc, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode opc, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode opc, const RM_Opnd & rm, const R_Opnd & r, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode opc, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz = size_platf);
+
+// multiply instructions: mul, imul
+ENCODER_DECLARE_EXPORT char * mul(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const RM_Opnd & rm, const Imm_Opnd& imm, Opnd_Size sz = size_platf);
+
+// divide instructions: div, idiv
+ENCODER_DECLARE_EXPORT char * idiv(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+
+// data movement: mov
+ENCODER_DECLARE_EXPORT char * mov(char * stream, const M_Opnd & m, const R_Opnd & r, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * mov(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * mov(char * stream, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz = size_platf);
+
+ENCODER_DECLARE_EXPORT char * movsx( char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * movzx( char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+
+ENCODER_DECLARE_EXPORT char * movd(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm);
+ENCODER_DECLARE_EXPORT char * movd(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm);
+ENCODER_DECLARE_EXPORT char * movq(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm);
+ENCODER_DECLARE_EXPORT char * movq(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm);
+
+// sse mov
+ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const M_Opnd & mem, const XMM_Opnd & xmm, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
+
+// sse add, sub, mul, div
+ENCODER_DECLARE_EXPORT char * sse_add(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_add(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
+
+ENCODER_DECLARE_EXPORT char * sse_sub(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_sub(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
+
+ENCODER_DECLARE_EXPORT char * sse_mul(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_mul(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
+
+ENCODER_DECLARE_EXPORT char * sse_div(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_div(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
+
+// xor, compare
+ENCODER_DECLARE_EXPORT char * sse_xor(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1);
+
+ENCODER_DECLARE_EXPORT char * sse_compare(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_compare(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem, bool dbl);
+
+// sse conversions
+ENCODER_DECLARE_EXPORT char * sse_cvt_si(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_cvtt2si(char * stream, const R_Opnd & reg, const M_Opnd & mem, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_cvtt2si(char * stream, const R_Opnd & reg, const XMM_Opnd & xmm, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_cvt_fp2dq(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_cvt_dq2fp(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl);
+ENCODER_DECLARE_EXPORT char * sse_d2s(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem64);
+ENCODER_DECLARE_EXPORT char * sse_d2s(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1);
+ENCODER_DECLARE_EXPORT char * sse_s2d(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem32);
+ENCODER_DECLARE_EXPORT char * sse_s2d(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1);
+
+// condition operations
+ENCODER_DECLARE_EXPORT char * cmov(char * stream, ConditionCode cc, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * setcc(char * stream, ConditionCode cc, const RM_Opnd & rm8);
+
+// load effective address: lea
+ENCODER_DECLARE_EXPORT char * lea(char * stream, const R_Opnd & r, const M_Opnd & m, Opnd_Size sz = size_platf);
+ENCODER_DECLARE_EXPORT char * cdq(char * stream);
+ENCODER_DECLARE_EXPORT char * wait(char * stream);
+
+// control-flow instructions
+ENCODER_DECLARE_EXPORT char * loop(char * stream, const Imm_Opnd & imm);
+
+// jump with 8-bit relative
+ENCODER_DECLARE_EXPORT char * jump8(char * stream, const Imm_Opnd & imm);
+
+// jump with 32-bit relative
+ENCODER_DECLARE_EXPORT char * jump32(char * stream, const Imm_Opnd & imm);
+
+// register indirect jump
+ENCODER_DECLARE_EXPORT char * jump(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+
+// jump to target address
+ENCODER_DECLARE_EXPORT char *jump(char * stream, char *target);
+
+// jump with displacement
+//char * jump(char * stream, I_32 disp);
+
+// conditional branch with 8-bit branch offset
+ENCODER_DECLARE_EXPORT char * branch8(char * stream, ConditionCode cc, const Imm_Opnd & imm, InstrPrefix prefix = no_prefix);
+
+// conditional branch with 32-bit branch offset
+ENCODER_DECLARE_EXPORT char * branch32(char * stream, ConditionCode cc, const Imm_Opnd & imm, InstrPrefix prefix = no_prefix);
+
+// conditional branch with target label address
+//char * branch(char * stream, ConditionCode cc, const char * target, InstrPrefix prefix = no_prefix);
+
+// conditional branch with displacement immediate
+ENCODER_DECLARE_EXPORT char * branch(char * stream, ConditionCode cc, I_32 disp, InstrPrefix prefix = no_prefix);
+
+// call with displacement
+ENCODER_DECLARE_EXPORT char * call(char * stream, const Imm_Opnd & imm);
+
+// indirect call through register or memory location
+ENCODER_DECLARE_EXPORT char * call(char * stream, const RM_Opnd & rm, Opnd_Size sz = size_platf);
+
+// call target address
+ENCODER_DECLARE_EXPORT char * call(char * stream, const char * target);
+
+// return instruction
+ENCODER_DECLARE_EXPORT char * ret(char * stream);
+ENCODER_DECLARE_EXPORT char * ret(char * stream, unsigned short pop);
+ENCODER_DECLARE_EXPORT char * ret(char * stream, const Imm_Opnd & imm);
+
+// string operations
+ENCODER_DECLARE_EXPORT char * set_d(char * stream, bool set);
+ENCODER_DECLARE_EXPORT char * scas(char * stream, unsigned char prefix);
+ENCODER_DECLARE_EXPORT char * stos(char * stream, unsigned char prefix);
+
+// floating-point instructions
+
+// st(0) = st(0) fp_op m{32,64}real
+//!char * fp_op_mem(char * stream, FP_Opcode opc,const M_Opnd& mem,int is_double);
+
+// st(0) = st(0) fp_op st(i)
+//!char *fp_op(char * stream, FP_Opcode opc,unsigned i);
+
+// st(i) = st(i) fp_op st(0) ; optionally pop stack
+//!char * fp_op(char * stream, FP_Opcode opc,unsigned i,unsigned pop_stk);
+
+// compare st(0),st(1) and pop stack twice
+//!char * fcompp(char * stream);
+ENCODER_DECLARE_EXPORT char * fldcw(char * stream, const M_Opnd & mem);
+ENCODER_DECLARE_EXPORT char * fnstcw(char * stream, const M_Opnd & mem);
+ENCODER_DECLARE_EXPORT char * fnstsw(char * stream);
+//!char * fchs(char * stream);
+//!char * frem(char * stream);
+//!char * fxch(char * stream,unsigned i);
+//!char * fcomip(char * stream, unsigned i);
+
+// load from memory (as fp) into fp register stack
+ENCODER_DECLARE_EXPORT char * fld(char * stream, const M_Opnd & m, bool is_double);
+//!char *fld80(char * stream,const M_Opnd& mem);
+
+// load from memory (as int) into fp register stack
+//!char * fild(char * stream,const M_Opnd& mem,int is_long);
+
+// push st(i) onto fp register stack
+//!char * fld(char * stream,unsigned i);
+
+// push the constants 0.0 and 1.0 onto the fp register stack
+//!char * fldz(char * stream);
+//!char * fld1(char * stream);
+
+// store stack to memory (as int), always popping the stack
+ENCODER_DECLARE_EXPORT char * fist(char * stream, const M_Opnd & mem, bool is_long, bool pop_stk);
+// store stack to to memory (as fp), optionally popping the stack
+ENCODER_DECLARE_EXPORT char * fst(char * stream, const M_Opnd & m, bool is_double, bool pop_stk);
+// store ST(0) to ST(i), optionally popping the stack. Takes 1 clock
+ENCODER_DECLARE_EXPORT char * fst(char * stream, unsigned i, bool pop_stk);
+
+//!char * pushad(char * stream);
+//!char * pushfd(char * stream);
+//!char * popad(char * stream);
+//!char * popfd(char * stream);
+
+// stack frame allocation instructions: enter & leave
+//
+// enter frame_size
+//
+// is equivalent to:
+//
+// push ebp
+// mov ebp,esp
+// sub esp,frame_size
+//
+//!char *enter(char * stream,const Imm_Opnd& imm);
+
+// leave
+// is equivalent to:
+//
+// mov esp,ebp
+// pop ebp
+//!char *leave(char * stream);
+
+// sahf loads SF, ZF, AF, PF, and CF flags from eax
+//!char *sahf(char * stream);
+
+// Intrinsic FP math functions
+
+//!char *math_fsin(char * stream);
+//!char *math_fcos(char * stream);
+//!char *math_fabs(char * stream);
+//!char *math_fpatan(char * stream);
+ENCODER_DECLARE_EXPORT char * fprem(char * stream);
+ENCODER_DECLARE_EXPORT char * fprem1(char * stream);
+//!char *math_frndint(char * stream);
+//!char *math_fptan(char * stream);
+
+//
+// Add 1-7 bytes padding, with as few instructions as possible,
+// with no effect on the processor state (e.g., registers, flags)
+//
+//!char *padding(char * stream, unsigned num);
+
+// prolog and epilog code generation
+//- char *prolog(char * stream,unsigned frame_size,unsigned reg_save_mask);
+//- char *epilog(char * stream,unsigned reg_save_mask);
+
+//!extern R_Opnd reg_operand_array[];
+
+// fsave and frstor
+//!char *fsave(char * stream);
+//!char *frstor(char * stream);
+
+// lahf : Load Status Flags into AH Register
+//!char *lahf(char * stream);
+
+// mfence : Memory Fence
+//!char *mfence(char * stream);
+
+#endif // _VM_ENCODER_H_
diff --git a/vm/compiler/codegen/x86/libenc/encoder.inl b/vm/compiler/codegen/x86/libenc/encoder.inl
new file mode 100644
index 0000000..663d492
--- /dev/null
+++ b/vm/compiler/codegen/x86/libenc/encoder.inl
@@ -0,0 +1,850 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+
+extern const RegName map_of_regno_2_regname[];
+extern const OpndSize map_of_EncoderOpndSize_2_RealOpndSize[];
+extern const Mnemonic map_of_alu_opcode_2_mnemonic[];
+extern const Mnemonic map_of_shift_opcode_2_mnemonic[];
+
+// S_ stands for 'Signed'
+extern const Mnemonic S_map_of_condition_code_2_branch_mnemonic[];
+// U_ stands for 'Unsigned'
+extern const Mnemonic U_map_of_condition_code_2_branch_mnemonic[];
+
+inline static RegName map_reg(Reg_No r) {
+ assert(r >= 0 && r <= n_reg);
+ return map_of_regno_2_regname[r];
+}
+
+inline static OpndSize map_size(Opnd_Size o_size) {
+ assert(o_size >= 0 && o_size <= n_size);
+ return map_of_EncoderOpndSize_2_RealOpndSize[o_size];
+}
+
+inline static Mnemonic map_alu(ALU_Opcode alu) {
+ assert(alu >= 0 && alu < n_alu);
+ return map_of_alu_opcode_2_mnemonic[alu];
+}
+
+inline static Mnemonic map_shift(Shift_Opcode shc) {
+ assert(shc >= 0 && shc < n_shift);
+ return map_of_shift_opcode_2_mnemonic[shc];
+}
+
+inline bool fit8(int64 val) {
+ return (CHAR_MIN <= val) && (val <= CHAR_MAX);
+}
+
+inline bool fit32(int64 val) {
+ return (INT_MIN <= val) && (val <= INT_MAX);
+}
+
+inline static void add_r(EncoderBase::Operands & args, const R_Opnd & r, Opnd_Size sz, OpndExt ext = OpndExt_None) {
+ RegName reg = map_reg(r.reg_no());
+ if (sz != n_size) {
+ OpndSize size = map_size(sz);
+ if (size != getRegSize(reg)) {
+ reg = getAliasReg(reg, size);
+ }
+ }
+ args.add(EncoderBase::Operand(reg, ext));
+}
+
+inline static void add_m(EncoderBase::Operands & args, const M_Opnd & m, Opnd_Size sz, OpndExt ext = OpndExt_None) {
+ assert(n_size != sz);
+ args.add(EncoderBase::Operand(map_size(sz),
+ map_reg(m.base().reg_no()), map_reg(m.index().reg_no()),
+ (unsigned)m.scale().get_value(), (int)m.disp().get_value(), ext));
+}
+
+inline static void add_rm(EncoderBase::Operands & args, const RM_Opnd & rm, Opnd_Size sz, OpndExt ext = OpndExt_None) {
+ rm.is_reg() ? add_r(args, (R_Opnd &)rm, sz, ext) : add_m(args, (M_Opnd &)rm, sz, ext);
+}
+
+inline static void add_xmm(EncoderBase::Operands & args, const XMM_Opnd & xmm, bool dbl) {
+ // Gregory -
+ // XMM registers indexes in Reg_No enum are shifted by xmm0_reg, their indexes
+ // don't start with 0, so it is necessary to subtract xmm0_reg index from
+ // xmm.get_idx() value
+ assert(xmm.get_idx() >= xmm0_reg);
+ return args.add((RegName)( (dbl ? RegName_XMM0D : RegName_XMM0S) + xmm.get_idx() -
+ xmm0_reg));
+}
+
+inline static void add_fp(EncoderBase::Operands & args, unsigned i, bool dbl) {
+ return args.add((RegName)( (dbl ? RegName_FP0D : RegName_FP0S) + i));
+}
+
+inline static void add_imm(EncoderBase::Operands & args, const Imm_Opnd & imm) {
+ assert(n_size != imm.get_size());
+ args.add(EncoderBase::Operand(map_size(imm.get_size()), imm.get_value(),
+ imm.is_signed() ? OpndExt_Signed : OpndExt_Zero));
+}
+
+ENCODER_DECLARE_EXPORT char * prefix(char * stream, InstrPrefix p) {
+ *stream = (char)p;
+ return stream + 1;
+}
+
+// stack push and pop instructions
+ENCODER_DECLARE_EXPORT char * push(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_PUSH, args);
+}
+
+ENCODER_DECLARE_EXPORT char * push(char * stream, const Imm_Opnd & imm) {
+ EncoderBase::Operands args;
+#ifdef _EM64T_
+ add_imm(args, imm);
+#else
+ // we need this workaround to be compatible with the former ia32 encoder implementation
+ add_imm(args, Imm_Opnd(size_32, imm.get_value()));
+#endif
+ return EncoderBase::encode(stream, Mnemonic_PUSH, args);
+}
+
+ENCODER_DECLARE_EXPORT char * pop(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_POP, args);
+}
+
+// cmpxchg or xchg
+ENCODER_DECLARE_EXPORT char * cmpxchg(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_r(args, r, sz);
+ RegName implicitReg = getAliasReg(RegName_EAX, map_size(sz));
+ args.add(implicitReg);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CMPXCHG, args);
+}
+
+ENCODER_DECLARE_EXPORT char * xchg(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_r(args, r, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_XCHG, args);
+}
+
+// inc(rement), dec(rement), not, neg(ate) instructions
+ENCODER_DECLARE_EXPORT char * inc(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_INC, args);
+}
+
+ENCODER_DECLARE_EXPORT char * dec(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_DEC, args);
+}
+
+ENCODER_DECLARE_EXPORT char * _not(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_NOT, args);
+}
+
+ENCODER_DECLARE_EXPORT char * neg(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_NEG, args);
+}
+
+ENCODER_DECLARE_EXPORT char * nop(char * stream) {
+ EncoderBase::Operands args;
+ return (char*)EncoderBase::encode(stream, Mnemonic_NOP, args);
+}
+
+ENCODER_DECLARE_EXPORT char * int3(char * stream) {
+ EncoderBase::Operands args;
+ return (char*)EncoderBase::encode(stream, Mnemonic_INT3, args);
+}
+
+// alu instructions: add, or, adc, sbb, and, sub, xor, cmp
+ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, map_alu(opc), args);
+};
+
+ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const M_Opnd & m, const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, m, sz);
+ add_rm(args, r, sz);
+ return (char*)EncoderBase::encode(stream, map_alu(opc), args);
+}
+
+ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, r, sz);
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, map_alu(opc), args);
+}
+
+// test instruction
+ENCODER_DECLARE_EXPORT char * test(char * stream, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ assert(imm.get_size() <= sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_TEST, args);
+}
+
+ENCODER_DECLARE_EXPORT char * test(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_r(args, r, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_TEST, args);
+}
+
+// shift instructions: shl, shr, sar, shld, shrd
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, map_shift(shc), args);
+}
+
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ args.add(RegName_CL);
+ return (char*)EncoderBase::encode(stream, map_shift(shc), args);
+}
+
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm,
+ const R_Opnd & r, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ assert(shc == shld_opc || shc == shrd_opc);
+ add_rm(args, rm, sz);
+ add_r(args, r, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, map_shift(shc), args);
+}
+
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm,
+ const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ assert(shc == shld_opc || shc == shrd_opc);
+ add_rm(args, rm, sz);
+ add_r(args, r, sz);
+ args.add(RegName_CL);
+ return (char*)EncoderBase::encode(stream, map_shift(shc), args);
+}
+
+// multiply instructions: mul, imul
+ENCODER_DECLARE_EXPORT char * mul(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ args.add(RegName_EDX);
+ args.add(RegName_EAX);
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MUL, args);
+}
+
+ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_IMUL, args);
+}
+
+ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_IMUL, args);
+}
+
+ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const RM_Opnd & rm,
+ const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_rm(args, rm, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_IMUL, args);
+}
+
+// divide instructions: div, idiv
+ENCODER_DECLARE_EXPORT char * idiv(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+#ifdef _EM64T_
+ add_r(args, rdx_opnd, sz);
+ add_r(args, rax_opnd, sz);
+#else
+ add_r(args, edx_opnd, sz);
+ add_r(args, eax_opnd, sz);
+#endif
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_IDIV, args);
+}
+
+// data movement: mov
+ENCODER_DECLARE_EXPORT char * mov(char * stream, const M_Opnd & m, const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_m(args, m, sz);
+ add_r(args, r, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOV, args);
+}
+
+ENCODER_DECLARE_EXPORT char * mov(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOV, args);
+}
+
+ENCODER_DECLARE_EXPORT char * mov(char * stream, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOV, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movd(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, size_32);
+ add_xmm(args, xmm, false);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVD, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movd(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, false);
+ add_rm(args, rm, size_32);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVD, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movq(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, size_64);
+ add_xmm(args, xmm, true);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVQ, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movq(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, true);
+ add_rm(args, rm, size_64);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVQ, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movsx(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, n_size);
+ add_rm(args, rm, sz, OpndExt_Signed);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVSX, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movzx(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, n_size);
+ // movzx r64, r/m32 is not available on em64t
+ // mov r32, r/m32 should zero out upper bytes
+ assert(sz <= size_16);
+ add_rm(args, rm, sz, OpndExt_Zero);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVZX, args);
+}
+
+// sse mov
+ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MOVSD : Mnemonic_MOVSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const M_Opnd & mem, const XMM_Opnd & xmm, bool dbl) {
+ EncoderBase::Operands args;
+ add_m(args, mem, dbl ? size_64 : size_32);
+ add_xmm(args, xmm, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MOVSD : Mnemonic_MOVSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MOVSD : Mnemonic_MOVSS, args );
+}
+
+// sse add, sub, mul, div
+ENCODER_DECLARE_EXPORT char * sse_add(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_ADDSD : Mnemonic_ADDSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_add(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_ADDSD : Mnemonic_ADDSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_sub(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_SUBSD : Mnemonic_SUBSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_sub(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_SUBSD : Mnemonic_SUBSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_mul( char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MULSD : Mnemonic_MULSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_mul(char * stream, const XMM_Opnd& xmm0, const XMM_Opnd& xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MULSD : Mnemonic_MULSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_div(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_DIVSD : Mnemonic_DIVSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_div(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_DIVSD : Mnemonic_DIVSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_xor(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, true);
+ add_xmm(args, xmm1, true);
+ return (char*)EncoderBase::encode(stream, Mnemonic_PXOR, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_compare(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, true);
+ add_xmm(args, xmm1, true);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_COMISD : Mnemonic_COMISS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_compare(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_COMISD : Mnemonic_COMISS, args);
+}
+
+// sse conversions
+ENCODER_DECLARE_EXPORT char * sse_cvt_si(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTSI2SD : Mnemonic_CVTSI2SS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_cvtt2si(char * stream, const R_Opnd & reg, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_rm(args, reg, size_32);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTTSD2SI : Mnemonic_CVTTSS2SI, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_cvtt2si(char * stream, const R_Opnd & reg, const XMM_Opnd & xmm, bool dbl) {
+ EncoderBase::Operands args;
+ add_rm(args, reg, size_32);
+ add_xmm(args, xmm, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTTSD2SI : Mnemonic_CVTTSS2SI, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_cvt_fp2dq(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTTPD2DQ : Mnemonic_CVTTPS2DQ, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_cvt_dq2fp(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTDQ2PD : Mnemonic_CVTDQ2PS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_d2s(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem64) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, false);
+ add_m(args, mem64, size_64);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CVTSD2SS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_d2s(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, false);
+ add_xmm(args, xmm1, true);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CVTSD2SS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_s2d(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem32) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, true);
+ add_m(args, mem32, size_32);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CVTSS2SD, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_s2d(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, true);
+ add_xmm(args, xmm1, false);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CVTSS2SD, args);
+}
+
+// condition operations
+ENCODER_DECLARE_EXPORT char *cmov(char * stream, ConditionCode cc, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, (Mnemonic)(Mnemonic_CMOVcc + cc), args);
+}
+
+ENCODER_DECLARE_EXPORT char * setcc(char * stream, ConditionCode cc, const RM_Opnd & rm8) {
+ EncoderBase::Operands args;
+ add_rm(args, rm8, size_8);
+ return (char*)EncoderBase::encode(stream, (Mnemonic)(Mnemonic_SETcc + cc), args);
+}
+
+// load effective address: lea
+ENCODER_DECLARE_EXPORT char * lea(char * stream, const R_Opnd & r, const M_Opnd & m, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_m(args, m, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_LEA, args);
+}
+
+ENCODER_DECLARE_EXPORT char * cdq(char * stream) {
+ EncoderBase::Operands args;
+ args.add(RegName_EDX);
+ args.add(RegName_EAX);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CDQ, args);
+}
+
+ENCODER_DECLARE_EXPORT char * wait(char * stream) {
+ return (char*)EncoderBase::encode(stream, Mnemonic_WAIT, EncoderBase::Operands());
+}
+
+// control-flow instructions
+
+// loop
+ENCODER_DECLARE_EXPORT char * loop(char * stream, const Imm_Opnd & imm) {
+ EncoderBase::Operands args;
+ assert(imm.get_size() == size_8);
+ args.add(RegName_ECX);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_LOOP, args);
+}
+
+// jump
+ENCODER_DECLARE_EXPORT char * jump8(char * stream, const Imm_Opnd & imm) {
+ EncoderBase::Operands args;
+ assert(imm.get_size() == size_8);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_JMP, args);
+}
+
+ENCODER_DECLARE_EXPORT char * jump32(char * stream, const Imm_Opnd & imm) {
+ EncoderBase::Operands args;
+ assert(imm.get_size() == size_32);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_JMP, args);
+}
+
+ENCODER_DECLARE_EXPORT char * jump(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_JMP, args);
+}
+
+/**
+ * @note On EM64T: if target lies beyond 2G (does not fit into 32 bit
+ * offset) then generates indirect jump using RAX (whose content is
+ * destroyed).
+ */
+ENCODER_DECLARE_EXPORT char * jump(char * stream, char * target) {
+#ifdef _EM64T_
+ int64 offset = target - stream;
+ // sub 2 bytes for the short version
+ offset -= 2;
+ if (fit8(offset)) {
+ // use 8-bit signed relative form
+ return jump8(stream, Imm_Opnd(size_8, offset));
+ } else if (fit32(offset)) {
+ // sub 5 (3 + 2)bytes for the long version
+ offset -= 3;
+ // use 32-bit signed relative form
+ return jump32(stream, Imm_Opnd(size_32, offset));
+ }
+ // need to use absolute indirect jump
+ stream = mov(stream, rax_opnd, Imm_Opnd(size_64, (int64)target), size_64);
+ return jump(stream, rax_opnd, size_64);
+#else
+ I_32 offset = target - stream;
+ // sub 2 bytes for the short version
+ offset -= 2;
+ if (fit8(offset)) {
+ // use 8-bit signed relative form
+ return jump8(stream, Imm_Opnd(size_8, offset));
+ }
+ // sub 5 (3 + 2) bytes for the long version
+ offset -= 3;
+ // use 32-bit signed relative form
+ return jump32(stream, Imm_Opnd(size_32, offset));
+#endif
+}
+
+// branch
+ENCODER_DECLARE_EXPORT char * branch8(char * stream, ConditionCode cond,
+ const Imm_Opnd & imm,
+ InstrPrefix pref)
+{
+ if (pref != no_prefix) {
+ assert(pref == hint_branch_taken_prefix || pref == hint_branch_taken_prefix);
+ stream = prefix(stream, pref);
+ }
+ Mnemonic m = (Mnemonic)(Mnemonic_Jcc + cond);
+ EncoderBase::Operands args;
+ assert(imm.get_size() == size_8);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, m, args);
+}
+
+ENCODER_DECLARE_EXPORT char * branch32(char * stream, ConditionCode cond,
+ const Imm_Opnd & imm,
+ InstrPrefix pref)
+{
+ if (pref != no_prefix) {
+ assert(pref == hint_branch_taken_prefix || pref == hint_branch_taken_prefix);
+ stream = prefix(stream, pref);
+ }
+ Mnemonic m = (Mnemonic)(Mnemonic_Jcc + cond);
+ EncoderBase::Operands args;
+ assert(imm.get_size() == size_32);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, m, args);
+}
+
+/*
+ENCODER_DECLARE_EXPORT char * branch(char * stream, ConditionCode cc, const char * target, InstrPrefix prefix) {
+// sub 2 bytes for the short version
+int64 offset = stream-target-2;
+if( fit8(offset) ) {
+return branch8(stream, cc, Imm_Opnd(size_8, (char)offset), is_signed);
+}
+return branch32(stream, cc, Imm_Opnd(size_32, (int)offset), is_signed);
+}
+*/
+
+// call
+ENCODER_DECLARE_EXPORT char * call(char * stream, const Imm_Opnd & imm)
+{
+ EncoderBase::Operands args;
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CALL, args);
+}
+
+ENCODER_DECLARE_EXPORT char * call(char * stream, const RM_Opnd & rm,
+ Opnd_Size sz)
+{
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CALL, args);
+}
+
+/**
+* @note On EM64T: if target lies beyond 2G (does not fit into 32 bit
+* offset) then generates indirect jump using RAX (whose content is
+* destroyed).
+*/
+ENCODER_DECLARE_EXPORT char * call(char * stream, const char * target)
+{
+#ifdef _EM64T_
+ int64 offset = target - stream;
+ if (fit32(offset)) {
+ offset -= 5; // sub 5 bytes for this instruction
+ Imm_Opnd imm(size_32, offset);
+ return call(stream, imm);
+ }
+ // need to use absolute indirect call
+ stream = mov(stream, rax_opnd, Imm_Opnd(size_64, (int64)target), size_64);
+ return call(stream, rax_opnd, size_64);
+#else
+ I_32 offset = target - stream;
+ offset -= 5; // sub 5 bytes for this instruction
+ Imm_Opnd imm(size_32, offset);
+ return call(stream, imm);
+#endif
+}
+
+// return instruction
+ENCODER_DECLARE_EXPORT char * ret(char * stream)
+{
+ EncoderBase::Operands args;
+ return (char*)EncoderBase::encode(stream, Mnemonic_RET, args);
+}
+
+ENCODER_DECLARE_EXPORT char * ret(char * stream, const Imm_Opnd & imm)
+{
+ EncoderBase::Operands args;
+ // TheManual says imm can be 16-bit only
+ //assert(imm.get_size() <= size_16);
+ args.add(EncoderBase::Operand(map_size(size_16), imm.get_value()));
+ return (char*)EncoderBase::encode(stream, Mnemonic_RET, args);
+}
+
+ENCODER_DECLARE_EXPORT char * ret(char * stream, unsigned short pop)
+{
+ // TheManual says it can only be imm16
+ EncoderBase::Operands args(EncoderBase::Operand(OpndSize_16, pop, OpndExt_Zero));
+ return (char*)EncoderBase::encode(stream, Mnemonic_RET, args);
+}
+
+// floating-point instructions
+ENCODER_DECLARE_EXPORT char * fld(char * stream, const M_Opnd & m,
+ bool is_double) {
+ EncoderBase::Operands args;
+ // a fake FP register as operand
+ add_fp(args, 0, is_double);
+ add_m(args, m, is_double ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, Mnemonic_FLD, args);
+}
+
+ENCODER_DECLARE_EXPORT char * fist(char * stream, const M_Opnd & mem,
+ bool is_long, bool pop_stk)
+{
+ EncoderBase::Operands args;
+ if (pop_stk) {
+ add_m(args, mem, is_long ? size_64 : size_32);
+ // a fake FP register as operand
+ add_fp(args, 0, is_long);
+ return (char*)EncoderBase::encode(stream, Mnemonic_FISTP, args);
+ }
+ // only 32-bit operands are supported
+ assert(is_long == false);
+ add_m(args, mem, size_32);
+ add_fp(args, 0, false);
+ return (char*)EncoderBase::encode(stream, Mnemonic_FIST, args);
+}
+
+ENCODER_DECLARE_EXPORT char * fst(char * stream, const M_Opnd & m,
+ bool is_double, bool pop_stk)
+{
+ EncoderBase::Operands args;
+ add_m(args, m, is_double ? size_64 : size_32);
+ // a fake FP register as operand
+ add_fp(args, 0, is_double);
+ return (char*)EncoderBase::encode(stream,
+ pop_stk ? Mnemonic_FSTP : Mnemonic_FST,
+ args);
+}
+
+ENCODER_DECLARE_EXPORT char * fst(char * stream, unsigned i, bool pop_stk)
+{
+ EncoderBase::Operands args;
+ add_fp(args, i, true);
+ return (char*)EncoderBase::encode(stream,
+ pop_stk ? Mnemonic_FSTP : Mnemonic_FST,
+ args);
+}
+
+ENCODER_DECLARE_EXPORT char * fldcw(char * stream, const M_Opnd & mem) {
+ EncoderBase::Operands args;
+ add_m(args, mem, size_16);
+ return (char*)EncoderBase::encode(stream, Mnemonic_FLDCW, args);
+}
+
+ENCODER_DECLARE_EXPORT char * fnstcw(char * stream, const M_Opnd & mem) {
+ EncoderBase::Operands args;
+ add_m(args, mem, size_16);
+ return (char*)EncoderBase::encode(stream, Mnemonic_FNSTCW, args);
+}
+
+ENCODER_DECLARE_EXPORT char * fnstsw(char * stream)
+{
+ return (char*)EncoderBase::encode(stream, Mnemonic_FNSTCW,
+ EncoderBase::Operands());
+}
+
+// string operations
+ENCODER_DECLARE_EXPORT char * set_d(char * stream, bool set) {
+ EncoderBase::Operands args;
+ return (char*)EncoderBase::encode(stream,
+ set ? Mnemonic_STD : Mnemonic_CLD,
+ args);
+}
+
+ENCODER_DECLARE_EXPORT char * scas(char * stream, unsigned char prefix)
+{
+ EncoderBase::Operands args;
+ if (prefix != no_prefix) {
+ assert(prefix == prefix_repnz || prefix == prefix_repz);
+ *stream = prefix;
+ ++stream;
+ }
+ return (char*)EncoderBase::encode(stream, Mnemonic_SCAS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * stos(char * stream, unsigned char prefix)
+{
+ if (prefix != no_prefix) {
+ assert(prefix == prefix_rep);
+ *stream = prefix;
+ ++stream;
+ }
+
+ EncoderBase::Operands args;
+ return (char*)EncoderBase::encode(stream, Mnemonic_STOS, args);
+}
+
+// Intrinsic FP math functions
+
+ENCODER_DECLARE_EXPORT char * fprem(char * stream) {
+ return (char*)EncoderBase::encode(stream, Mnemonic_FPREM,
+ EncoderBase::Operands());
+}
+
+ENCODER_DECLARE_EXPORT char * fprem1(char * stream) {
+ return (char*)EncoderBase::encode(stream, Mnemonic_FPREM1,
+ EncoderBase::Operands());
+}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S b/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S
index 4fd5a71..23614e9 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S
@@ -16,8 +16,8 @@
/* op vAA, vBB, vCC */
push {r0-r3} @ save operands
mov r11, lr @ save return address
- mov lr, pc
- ldr pc, .L__aeabi_cdcmple @ PIC way of "bl __aeabi_cdcmple"
+ ldr ip, .L__aeabi_cdcmple @ PIC way of "bl __aeabi_cdcmple"
+ blx ip
bhi .L${opcode}_gt_or_nan @ C set and Z clear, disambiguate
mvncc r0, #0 @ (less than) r1<- -1
moveq r0, #0 @ (equal) r1<- 0, trumps less than
@@ -30,8 +30,8 @@
.L${opcode}_gt_or_nan:
pop {r2-r3} @ restore operands in reverse order
pop {r0-r1} @ restore operands in reverse order
- mov lr, pc
- ldr pc, .L__aeabi_cdcmple @ r0<- Z set if eq, C clear if <
+ ldr ip, .L__aeabi_cdcmple @ r0<- Z set if eq, C clear if <
+ blx ip
movcc r0, #1 @ (greater than) r1<- 1
bxcc r11
$naninst @ r1<- 1 or -1 for NaN
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S b/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S
index d0f2bec..f9293e6 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S
@@ -36,8 +36,8 @@
mov r9, r0 @ Save copies - we may need to redo
mov r10, r1
mov r11, lr @ save return address
- mov lr, pc
- ldr pc, .L__aeabi_cfcmple @ cmp <=: C clear if <, Z set if eq
+ ldr ip, .L__aeabi_cfcmple @ cmp <=: C clear if <, Z set if eq
+ blx ip
bhi .L${opcode}_gt_or_nan @ C set and Z clear, disambiguate
mvncc r0, #0 @ (less than) r0<- -1
moveq r0, #0 @ (equal) r0<- 0, trumps less than
@@ -48,8 +48,8 @@
.L${opcode}_gt_or_nan:
mov r0, r10 @ restore in reverse order
mov r1, r9
- mov lr, pc
- ldr pc, .L__aeabi_cfcmple @ r0<- Z set if eq, C clear if <
+ ldr ip, .L__aeabi_cfcmple @ r0<- Z set if eq, C clear if <
+ blx ip
movcc r0, #1 @ (greater than) r1<- 1
bxcc r11
$naninst @ r1<- 1 or -1 for NaN
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S
index 03b97a4..99a17ab 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S
@@ -41,8 +41,8 @@
stmfd sp!, {r0-r2,lr} @ preserve clobbered live registers
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore registers
#endif
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
index 2a73c22..d8661d9 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
@@ -44,8 +44,8 @@
mov r0, r2
mov r1, r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -54,8 +54,8 @@
#if defined(TEMPLATE_INLINE_PROFILING)
ldmfd sp!, {r0-r1} @ restore r2 and r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
#endif
@ native return; r10=newSaveArea
@ equivalent to dvmPopJniLocals
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S
index a7a0961..b7015eb 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S
@@ -48,8 +48,8 @@
stmfd sp!, {r0-r3} @ preserve r0-r3
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -57,4 +57,4 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
- mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
+ bx r10 @ dvmJitToInterpTraceSelectNoChain
diff --git a/vm/compiler/template/armv5te/TEMPLATE_RETURN.S b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
index d074c9e..b10afcf 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
@@ -9,8 +9,8 @@
stmfd sp!, {r0-r2,lr} @ preserve live registers
mov r0, r6
@ r0=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceExit
+ ldr ip, .LdvmFastMethodTraceExit
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore live registers
#endif
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
diff --git a/vm/compiler/template/armv5te/footer.S b/vm/compiler/template/armv5te/footer.S
index 16660ae..b567a90 100644
--- a/vm/compiler/template/armv5te/footer.S
+++ b/vm/compiler/template/armv5te/footer.S
@@ -4,7 +4,7 @@
* ===========================================================================
*/
- .text
+ .section .data.rel.ro
.align 2
.LinvokeNative:
@ Prep for the native call
@@ -29,20 +29,20 @@
stmfd sp!, {r0-r3}
mov r0, r2
mov r1, r6
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3}
- mov lr, pc
- ldr pc, [r2, #offMethod_nativeFunc]
+ ldr ip, [r2, #offMethod_nativeFunc]
+ blx ip
ldmfd sp!, {r0-r1}
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
b 212f
121:
- mov lr, pc
- ldr pc, [r2, #offMethod_nativeFunc]
+ ldr ip, [r2, #offMethod_nativeFunc]
+ blx ip
212:
@ native return; r10=newSaveArea
@@ -68,7 +68,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
- mov pc, r1
+ bx r1
/*
* On entry:
@@ -85,7 +85,7 @@
ldr r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
ldr rIBASE, .LdvmAsmInstructionStart @ same as above
mov rPC, r0 @ reload the faulting Dalvik address
- mov pc, r1 @ branch to dvmMterpCommonExceptionThrown
+ bx r1 @ branch to dvmMterpCommonExceptionThrown
.align 2
.LdvmAsmInstructionStart:
diff --git a/vm/compiler/template/config-mips b/vm/compiler/template/config-mips
new file mode 100644
index 0000000..f212150
--- /dev/null
+++ b/vm/compiler/template/config-mips
@@ -0,0 +1,93 @@
+
+# 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.
+
+#
+# Configuration for ARMv5TE architecture targets.
+#
+
+# file header and basic definitions
+#import c/header.c
+import mips/header.S
+
+# C pre-processor defines for stub C instructions
+#import cstubs/stubdefs.c
+
+# highly-platform-specific defs
+import mips/platform.S
+
+# common defs for the C helpers; include this before the instruction handlers
+#import c/opcommon.c
+
+# opcode list; argument to op-start is default directory
+op-start mips
+
+ op TEMPLATE_SHL_LONG mips
+ op TEMPLATE_SHR_LONG mips
+ op TEMPLATE_USHR_LONG mips
+ op TEMPLATE_INT_TO_DOUBLE_VFP mips
+ op TEMPLATE_FLOAT_TO_DOUBLE_VFP mips
+ op TEMPLATE_ADD_DOUBLE_VFP mips
+ op TEMPLATE_DIV_DOUBLE_VFP mips
+ op TEMPLATE_MUL_DOUBLE_VFP mips
+ op TEMPLATE_SUB_DOUBLE_VFP mips
+ op TEMPLATE_ADD_FLOAT_VFP mips
+ op TEMPLATE_DIV_FLOAT_VFP mips
+ op TEMPLATE_MUL_FLOAT_VFP mips
+ op TEMPLATE_SUB_FLOAT_VFP mips
+ op TEMPLATE_FLOAT_TO_INT_VFP mips
+ op TEMPLATE_INT_TO_FLOAT_VFP mips
+ op TEMPLATE_DOUBLE_TO_FLOAT_VFP mips
+ op TEMPLATE_DOUBLE_TO_INT_VFP mips
+ op TEMPLATE_CMP_LONG mips
+ op TEMPLATE_CMPL_FLOAT_VFP mips
+ op TEMPLATE_CMPL_DOUBLE_VFP mips
+ op TEMPLATE_CMPG_FLOAT_VFP mips
+ op TEMPLATE_CMPG_DOUBLE_VFP mips
+ op TEMPLATE_MUL_LONG mips
+ op TEMPLATE_INTERPRET mips
+ op TEMPLATE_THROW_EXCEPTION_COMMON mips
+ op TEMPLATE_SQRT_DOUBLE_VFP mips
+ op TEMPLATE_SAVE_STATE mips
+ op TEMPLATE_RESTORE_STATE mips
+ op TEMPLATE_RETURN mips
+ op TEMPLATE_STRING_COMPARETO mips
+ op TEMPLATE_STRING_INDEXOF mips
+ op TEMPLATE_MEM_OP_DECODE mips
+ op TEMPLATE_MONITOR_ENTER mips
+ op TEMPLATE_MONITOR_ENTER_DEBUG mips
+ op TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN mips
+ op TEMPLATE_INVOKE_METHOD_CHAIN mips
+ op TEMPLATE_INVOKE_METHOD_NATIVE mips
+ op TEMPLATE_INVOKE_METHOD_NO_OPT mips
+
+ # New templates for ICS
+ op TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF mips
+ op TEMPLATE_INVOKE_METHOD_CHAIN_PROF mips
+ op TEMPLATE_INVOKE_METHOD_NATIVE_PROF mips
+ op TEMPLATE_INVOKE_METHOD_NO_OPT_PROF mips
+ op TEMPLATE_PERIODIC_PROFILING mips
+ op TEMPLATE_RETURN_PROF mips
+
+op-end
+
+# "helper" code for C; include if you use any of the C stubs (this generates
+# object code, so it's normally excluded)
+##import c/gotoTargets.c
+
+# end of defs; include this when cstubs/stubdefs.c is included
+#import cstubs/enddefs.c
+
+# common subroutines for asm
+import mips/footer.S
diff --git a/vm/compiler/template/gen-template.py b/vm/compiler/template/gen-template.py
index 02e9107..9122fd5 100755
--- a/vm/compiler/template/gen-template.py
+++ b/vm/compiler/template/gen-template.py
@@ -172,7 +172,7 @@
# point dvmAsmInstructionStart at the first handler or stub
asm_fp.write("\n .global dvmCompilerTemplateStart\n")
asm_fp.write(" .type dvmCompilerTemplateStart, %function\n")
- asm_fp.write(" .text\n\n")
+ asm_fp.write(" .section .data.rel.ro\n\n")
asm_fp.write("dvmCompilerTemplateStart:\n\n")
for i in xrange(len(opcodes)):
diff --git a/vm/compiler/template/ia32/footer.S b/vm/compiler/template/ia32/footer.S
index d350c77..226e928 100644
--- a/vm/compiler/template/ia32/footer.S
+++ b/vm/compiler/template/ia32/footer.S
@@ -4,7 +4,7 @@
* ===========================================================================
*/
- .text
+ .section .data.rel.ro
.align 4
.global dmvCompilerTemplateEnd
diff --git a/vm/compiler/template/mips/TEMPLATE_ADD_DOUBLE_VFP.S b/vm/compiler/template/mips/TEMPLATE_ADD_DOUBLE_VFP.S
new file mode 100644
index 0000000..56a02e3
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_ADD_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/fbinopWide.S" {"instr":"JAL(__adddf3)","instr_f":"add.d fv0, fa0, fa1"}
diff --git a/vm/compiler/template/mips/TEMPLATE_ADD_FLOAT_VFP.S b/vm/compiler/template/mips/TEMPLATE_ADD_FLOAT_VFP.S
new file mode 100644
index 0000000..b0cbb31
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_ADD_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/fbinop.S" {"instr":"JAL(__addsf3)", "instr_f":"add.s fv0, fa0, fa1"}
diff --git a/vm/compiler/template/mips/TEMPLATE_CMPG_DOUBLE_VFP.S b/vm/compiler/template/mips/TEMPLATE_CMPG_DOUBLE_VFP.S
new file mode 100644
index 0000000..f5fa114
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_CMPG_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/TEMPLATE_CMPL_DOUBLE_VFP.S" { "naninst":"li rTEMP, 1" }
diff --git a/vm/compiler/template/mips/TEMPLATE_CMPG_FLOAT_VFP.S b/vm/compiler/template/mips/TEMPLATE_CMPG_FLOAT_VFP.S
new file mode 100644
index 0000000..c239a75
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_CMPG_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/TEMPLATE_CMPL_FLOAT_VFP.S" { "naninst":"li rTEMP, 1" }
diff --git a/vm/compiler/template/mips/TEMPLATE_CMPL_DOUBLE_VFP.S b/vm/compiler/template/mips/TEMPLATE_CMPL_DOUBLE_VFP.S
new file mode 100644
index 0000000..0a1dd68
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_CMPL_DOUBLE_VFP.S
@@ -0,0 +1,68 @@
+%default { "naninst":"li rTEMP, -1" }
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two double precision floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * On entry:
+ * a0 = &op1 [vBB]
+ * a1 = &op2 [vCC]
+ *
+ * for: cmpl-double, cmpg-double
+ */
+ /* op vAA, vBB, vCC */
+
+ /* "clasic" form */
+#ifdef SOFT_FLOAT
+ move rOBJ, a0 # save a0
+ move rBIX, a1 # save a1
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3<- vCC/vCC+1
+ JAL(__eqdf2) # v0<- (vBB == vCC)
+ li rTEMP, 0 # vAA<- 0
+ beqz v0, ${opcode}_finish
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3<- vCC/vCC+1
+ JAL(__ltdf2) # a0<- (vBB < vCC)
+ li rTEMP, -1 # vAA<- -1
+ bltz v0, ${opcode}_finish
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3<- vCC/vCC+1
+ JAL(__gtdf2) # v0<- (vBB > vCC)
+ li rTEMP, 1 # vAA<- 1
+ bgtz v0, ${opcode}_finish
+#else
+ LOAD64_F(fs0, fs0f, a0) # fs0<- vBB
+ LOAD64_F(fs1, fs1f, a1) # fs1<- vCC
+ c.olt.d fcc0, fs0, fs1 # Is fs0 < fs1
+ li rTEMP, -1
+ bc1t fcc0, ${opcode}_finish
+ c.olt.d fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, ${opcode}_finish
+ c.eq.d fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, ${opcode}_finish
+#endif
+
+ $naninst
+
+${opcode}_finish:
+ move v0, rTEMP # v0<- vAA
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_CMPL_FLOAT_VFP.S b/vm/compiler/template/mips/TEMPLATE_CMPL_FLOAT_VFP.S
new file mode 100644
index 0000000..7ef7723
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_CMPL_FLOAT_VFP.S
@@ -0,0 +1,68 @@
+%default { "naninst":"li rTEMP, -1" }
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * On entry:
+ * a0 = &op1 [vBB]
+ * a1 = &op2 [vCC]
+ *
+ * for: cmpl-float, cmpg-float
+ */
+ /* op vAA, vBB, vCC */
+
+ /* "clasic" form */
+#ifdef SOFT_FLOAT
+ LOAD(rOBJ, a0) # rOBJ<- vBB
+ LOAD(rBIX, a1) # rBIX<- vCC
+ move a0, rOBJ # a0<- vBB
+ move a1, rBIX # a1<- vCC
+ JAL(__eqsf2) # v0<- (vBB == vCC)
+ li rTEMP, 0 # vAA<- 0
+ beqz v0, ${opcode}_finish
+ move a0, rOBJ # a0<- vBB
+ move a1, rBIX # a1<- vCC
+ JAL(__ltsf2) # a0<- (vBB < vCC)
+ li rTEMP, -1 # vAA<- -1
+ bltz v0, ${opcode}_finish
+ move a0, rOBJ # a0<- vBB
+ move a1, rBIX # a1<- vCC
+ JAL(__gtsf2) # v0<- (vBB > vCC)
+ li rTEMP, 1 # vAA<- 1
+ bgtz v0, ${opcode}_finish
+#else
+ LOAD_F(fs0, a0) # fs0<- vBB
+ LOAD_F(fs1, a1) # fs1<- vCC
+ c.olt.s fcc0, fs0, fs1 #Is fs0 < fs1
+ li rTEMP, -1
+ bc1t fcc0, ${opcode}_finish
+ c.olt.s fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, ${opcode}_finish
+ c.eq.s fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, ${opcode}_finish
+#endif
+
+ $naninst
+
+${opcode}_finish:
+ move v0, rTEMP # v0<- vAA
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_CMP_LONG.S b/vm/compiler/template/mips/TEMPLATE_CMP_LONG.S
new file mode 100644
index 0000000..9ecb069
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_CMP_LONG.S
@@ -0,0 +1,27 @@
+%verify "endianess"
+ /*
+ * Compare two 64-bit values
+ * x = y return 0
+ * x < y return -1
+ * x > y return 1
+ *
+ * I think I can improve on the ARM code by the following observation
+ * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
+ * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
+ * subu v0, t0, t1 # v0= -1:1:0 for [ < > = ]
+ *
+ * This code assumes the register pair ordering will depend on endianess (a1:a0 or a0:a1).
+ * a1:a0 => vBB
+ * a3:a2 => vCC
+ */
+ /* cmp-long vAA, vBB, vCC */
+ slt t0, rARG1, rARG3 # compare hi
+ sgt t1, rARG1, rARG3
+ subu v0, t1, t0 # v0<- (-1,1,0)
+ bnez v0, .L${opcode}_finish
+ # at this point x.hi==y.hi
+ sltu t0, rARG0, rARG2 # compare lo
+ sgtu t1, rARG0, rARG2
+ subu v0, t1, t0 # v0<- (-1,1,0) for [< > =]
+.L${opcode}_finish:
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_DIV_DOUBLE_VFP.S b/vm/compiler/template/mips/TEMPLATE_DIV_DOUBLE_VFP.S
new file mode 100644
index 0000000..a951f93
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_DIV_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/fbinopWide.S" {"instr":"JAL(__divdf3)","instr_f":"div.d fv0, fa0, fa1"}
diff --git a/vm/compiler/template/mips/TEMPLATE_DIV_FLOAT_VFP.S b/vm/compiler/template/mips/TEMPLATE_DIV_FLOAT_VFP.S
new file mode 100644
index 0000000..11b3da6
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_DIV_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/fbinop.S" {"instr":"JAL(__divsf3)", "instr_f":"div.s fv0, fa0, fa1"}
diff --git a/vm/compiler/template/mips/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S b/vm/compiler/template/mips/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S
new file mode 100644
index 0000000..51b1e96
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/funopNarrower.S" {"instr":"JAL(__truncdfsf2)","instr_f":"cvt.s.d fv0,fa0"}
diff --git a/vm/compiler/template/mips/TEMPLATE_DOUBLE_TO_INT_VFP.S b/vm/compiler/template/mips/TEMPLATE_DOUBLE_TO_INT_VFP.S
new file mode 100644
index 0000000..4774bb1
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_DOUBLE_TO_INT_VFP.S
@@ -0,0 +1,79 @@
+%verify "executed"
+%include "mips/funopNarrower.S" {"instr":"b d2i_doconv","instr_f":"b d2i_doconv"}
+
+/*
+ * Convert the double in a0/a1 to an int in a0.
+ *
+ * We have to clip values to int min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ * Use rBIX / rOBJ as global to hold arguments (they are not bound to a global var)
+ */
+
+d2i_doconv:
+#ifdef SOFT_FLOAT
+ la t0, .LDOUBLE_TO_INT_max
+ LOAD64(rARG2, rARG3, t0)
+ move rBIX, rARG0 # save a0
+ move rOBJ, rARG1 # and a1
+ JAL(__gedf2) # is arg >= maxint?
+
+ move t0, v0
+ li v0, ~0x80000000 # return maxint (7fffffff)
+ bgez t0, .L${opcode}_set_vreg # nonzero == yes
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rOBJ
+ la t0, .LDOUBLE_TO_INT_min
+ LOAD64(rARG2, rARG3, t0)
+ JAL(__ledf2) # is arg <= minint?
+
+ move t0, v0
+ li v0, 0x80000000 # return minint (80000000)
+ blez t0, .L${opcode}_set_vreg # nonzero == yes
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rOBJ
+ move rARG2, rBIX # compare against self
+ move rARG3, rOBJ
+ JAL(__nedf2) # is arg == self?
+
+ move t0, v0 # zero == no
+ li v0, 0
+ bnez t0, .L${opcode}_set_vreg # return zero for NaN
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rOBJ
+ JAL(__fixdfsi) # convert double to int
+ b .L${opcode}_set_vreg
+#else
+ la t0, .LDOUBLE_TO_INT_max
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa1, fa0
+ l.s fv0, .LDOUBLE_TO_INT_maxret
+ bc1t .L${opcode}_set_vreg_f
+
+ la t0, .LDOUBLE_TO_INT_min
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa0, fa1
+ l.s fv0, .LDOUBLE_TO_INT_minret
+ bc1t .L${opcode}_set_vreg_f
+
+ mov.d fa1, fa0
+ c.un.d fcc0, fa0, fa1
+ li.s fv0, 0
+ bc1t .L${opcode}_set_vreg_f
+
+ trunc.w.d fv0, fa0
+ b .L${opcode}_set_vreg_f
+#endif
+
+
+.LDOUBLE_TO_INT_max:
+ .dword 0x41dfffffffc00000
+.LDOUBLE_TO_INT_min:
+ .dword 0xc1e0000000000000 # minint, as a double (high word)
+.LDOUBLE_TO_INT_maxret:
+ .word 0x7fffffff
+.LDOUBLE_TO_INT_minret:
+ .word 0x80000000
diff --git a/vm/compiler/template/mips/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S b/vm/compiler/template/mips/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S
new file mode 100644
index 0000000..66d14ce
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/funopWider.S" {"instr":"JAL(__extendsfdf2)","instr_f":"cvt.d.s fv0, fa0"}
diff --git a/vm/compiler/template/mips/TEMPLATE_FLOAT_TO_INT_VFP.S b/vm/compiler/template/mips/TEMPLATE_FLOAT_TO_INT_VFP.S
new file mode 100644
index 0000000..6eaaab9
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_FLOAT_TO_INT_VFP.S
@@ -0,0 +1,62 @@
+%verify "executed"
+%include "mips/funop.S" {"instr":"b f2i_doconv","instr_f":"b f2i_doconv"}
+
+/*
+ * Not an entry point as it is used only once !!
+ */
+f2i_doconv:
+#ifdef SOFT_FLOAT
+ li a1, 0x4f000000 # (float)maxint
+ move rBIX, a0
+ JAL(__gesf2) # is arg >= maxint?
+ move t0, v0
+ li v0, ~0x80000000 # return maxint (7fffffff)
+ bgez t0, .L${opcode}_set_vreg
+
+ move a0, rBIX # recover arg
+ li a1, 0xcf000000 # (float)minint
+ JAL(__lesf2)
+
+ move t0, v0
+ li v0, 0x80000000 # return minint (80000000)
+ blez t0, .L${opcode}_set_vreg
+ move a0, rBIX
+ move a1, rBIX
+ JAL(__nesf2)
+
+ move t0, v0
+ li v0, 0 # return zero for NaN
+ bnez t0, .L${opcode}_set_vreg
+
+ move a0, rBIX
+ JAL(__fixsfsi)
+ b .L${opcode}_set_vreg
+#else
+ l.s fa1, .LFLOAT_TO_INT_max
+ c.ole.s fcc0, fa1, fa0
+ l.s fv0, .LFLOAT_TO_INT_ret_max
+ bc1t .L${opcode}_set_vreg_f
+
+ l.s fa1, .LFLOAT_TO_INT_min
+ c.ole.s fcc0, fa0, fa1
+ l.s fv0, .LFLOAT_TO_INT_ret_min
+ bc1t .L${opcode}_set_vreg_f
+
+ mov.s fa1, fa0
+ c.un.s fcc0, fa0, fa1
+ li.s fv0, 0
+ bc1t .L${opcode}_set_vreg_f
+
+ trunc.w.s fv0, fa0
+ b .L${opcode}_set_vreg_f
+#endif
+
+.LFLOAT_TO_INT_max:
+ .word 0x4f000000
+.LFLOAT_TO_INT_min:
+ .word 0xcf000000
+.LFLOAT_TO_INT_ret_max:
+ .word 0x7fffffff
+.LFLOAT_TO_INT_ret_min:
+ .word 0x80000000
+
diff --git a/vm/compiler/template/mips/TEMPLATE_INTERPRET.S b/vm/compiler/template/mips/TEMPLATE_INTERPRET.S
new file mode 100644
index 0000000..1284621
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INTERPRET.S
@@ -0,0 +1,21 @@
+ /*
+ * This handler transfers control to the interpeter without performing
+ * any lookups. It may be called either as part of a normal chaining
+ * operation, or from the transition code in header.S. We distinquish
+ * the two cases by looking at the link register. If called from a
+ * translation chain, it will point to the chaining Dalvik PC.
+ * On entry:
+ * ra - if NULL:
+ * a1 - the Dalvik PC to begin interpretation.
+ * else
+ * [ra] contains Dalvik PC to begin interpretation
+ * rSELF - pointer to thread
+ * rFP - Dalvik frame pointer
+ */
+ la t0, dvmJitToInterpPunt
+ move a0, a1
+ beq ra, zero, 1f
+ lw a0, 0(ra)
+1:
+ jr t0
+ # doesn't return
diff --git a/vm/compiler/template/mips/TEMPLATE_INT_TO_DOUBLE_VFP.S b/vm/compiler/template/mips/TEMPLATE_INT_TO_DOUBLE_VFP.S
new file mode 100644
index 0000000..0dca600
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INT_TO_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/funopWider.S" {"instr":"JAL(__floatsidf)","instr_f":"cvt.d.w fv0, fa0"}
diff --git a/vm/compiler/template/mips/TEMPLATE_INT_TO_FLOAT_VFP.S b/vm/compiler/template/mips/TEMPLATE_INT_TO_FLOAT_VFP.S
new file mode 100644
index 0000000..384c207
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INT_TO_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/funop.S" {"instr":"JAL(__floatsisf)","instr_f":"cvt.s.w fv0, fa0"}
diff --git a/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_CHAIN.S b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_CHAIN.S
new file mode 100644
index 0000000..c1e03ce
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_CHAIN.S
@@ -0,0 +1,67 @@
+%default { "chaintgt" : ".LinvokeChain" }
+ /*
+ * For monomorphic callsite, setup the Dalvik frame and return to the
+ * Thumb code through the link register to transfer control to the callee
+ * method through a dedicated chaining cell.
+ */
+ # a0 = methodToCall, a1 = returnCell, rPC = dalvikCallsite
+ # methodToCall is guaranteed to be non-native
+$chaintgt:
+ lh t7, offMethod_registersSize(a0) # t7<- methodToCall->regsSize
+ lh a2, offMethod_outsSize(a0) # a2<- methodToCall->outsSize
+ lw t9, offThread_interpStackEnd(rSELF) # t9<- interpStackEnd
+ lbu t8, offThread_breakFlags(rSELF) # t8<- breakFlags
+ move a3, a1 # a3<- returnCell
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- stack save area
+ sll t6, t7, 2 # multiply regsSize by 4 (4 bytes per reg)
+ sub a1, a1, t6 # a1<- newFp(old savearea-regsSize)
+ SAVEAREA_FROM_FP(t0, a1) # t0<- stack save area
+ add t2, ra, 8 # setup the punt-to-interp address
+ # 8 bytes skips branch and delay slot
+ sll t6, a2, 2 # multiply outsSize by 4 (4 bytes per reg)
+ sub t0, t0, t6 # t0<- bottom (newsave-outsSize)
+ bgeu t0, t9, 1f # bottom < interpStackEnd?
+ jr t2 # return to raise stack overflow excep.
+
+1:
+ # a1 = newFP, a0 = methodToCall, a3 = returnCell, rPC = dalvikCallsite
+ lw t9, offMethod_clazz(a0) # t9<- methodToCall->clazz
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+ sw rPC, (offStackSaveArea_savedPc - sizeofStackSaveArea)(a1)
+ lw rPC, offMethod_insns(a0) # rPC<- methodToCall->insns
+
+ # set up newSaveArea
+ sw rFP, (offStackSaveArea_prevFrame - sizeofStackSaveArea)(a1)
+ sw a3, (offStackSaveArea_returnAddr - sizeofStackSaveArea)(a1)
+ sw a0, (offStackSaveArea_method - sizeofStackSaveArea)(a1)
+ beqz t8, 2f # breakFlags != 0
+ jr t2 # bail to the interpreter
+
+2:
+ lw a3, offClassObject_pDvmDex(t9) # a3<- methodToCall->clazz->pDvmDex
+
+ # Update "thread" values for the new method
+ sw a0, offThread_method(rSELF) # self->method = methodToCall
+ sw a3, offThread_methodClassDex(rSELF) # self->methodClassDex = ...
+ move rFP, a1 # fp = newFp
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # preserve a0-a2 and ra
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(ra, 12)
+
+ move a1, rSELF
+ # a0=methodToCall, a1=rSELF
+ la t9, dvmFastMethodTraceEnter
+ jalr t9
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a2 and ra
+ SCRATCH_LOAD(ra, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+#endif
+ RETURN # return to the callee-chaining cell
diff --git a/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S
new file mode 100644
index 0000000..797ff03
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S
@@ -0,0 +1,3 @@
+#define TEMPLATE_INLINE_PROFILING
+%include "mips/TEMPLATE_INVOKE_METHOD_CHAIN.S" { "chaintgt" : ".LinvokeChainProf" }
+#undef TEMPLATE_INLINE_PROFILING
diff --git a/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NATIVE.S b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NATIVE.S
new file mode 100644
index 0000000..2579ff9
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NATIVE.S
@@ -0,0 +1,104 @@
+ # a0 = methodToCall, a1 = returnCell, rPC = dalvikCallsite
+ lh t7, offMethod_registersSize(a0) # t7<- methodToCall->regsSize
+ lw t9, offThread_interpStackEnd(rSELF) # t9<- interpStackEnd
+ lbu t8, offThread_breakFlags(rSELF) # t8<- breakFlags
+ move a3, a1 # a3<- returnCell
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- stack save area
+ sll t6, t7, 2 # multiply regsSize by 4 (4 bytes per reg)
+ sub a1, a1, t6 # a1<- newFp(old savearea-regsSize)
+ SAVEAREA_FROM_FP(t0, a1) # t0<- stack save area
+ bgeu t0, t9, 1f # bottom < interpStackEnd?
+ RETURN # return to raise stack overflow excep.
+
+1:
+ # a1 = newFP, a0 = methodToCall, a3 = returnCell, rPC = dalvikCallsite
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+ sw rPC, (offStackSaveArea_savedPc - sizeofStackSaveArea)(a1)
+ lw rPC, offMethod_insns(a0) # rPC<- methodToCall->insns
+
+ # set up newSaveArea
+ sw rFP, (offStackSaveArea_prevFrame - sizeofStackSaveArea)(a1)
+ sw a3, (offStackSaveArea_returnAddr - sizeofStackSaveArea)(a1)
+ sw a0, (offStackSaveArea_method - sizeofStackSaveArea)(a1)
+ lw rTEMP, offMethod_nativeFunc(a0) # t9<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+ beqz t8, 2f # breakFlags != 0
+ RETURN # bail to the interpreter
+2:
+#else
+ RETURN # bail to the interpreter unconditionally
+#endif
+
+ # go ahead and transfer control to the native code
+ lw t6, offThread_jniLocal_topCookie(rSELF) # t6<- thread->localRef->...
+ sw a1, offThread_curFrame(rSELF) # self->curFrame = newFp
+ sw zero, offThread_inJitCodeCache(rSELF) # not in the jit code cache
+ sw t6, (offStackSaveArea_localRefCookie - sizeofStackSaveArea)(a1)
+ # newFp->localRefCookie=top
+ SAVEAREA_FROM_FP(rBIX, a1) # rBIX<- new stack save area
+ move a2, a0 # a2<- methodToCall
+ move a0, a1 # a0<- newFp
+ add a1, rSELF, offThread_retval # a1<- &retval
+ move a3, rSELF # a3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # a2: methodToCall
+ # preserve a0-a3
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+
+ move a0, a2
+ move a1, rSELF
+ # a0=JNIMethod, a1=rSELF
+ la t9, dvmFastMethodTraceEnter
+ JALR(t9) # off to the native code
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a3
+ SCRATCH_LOAD(a3, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+
+ move rOBJ, a2 # save a2
+#endif
+
+ JALR(rTEMP) # off to the native code
+ lw gp, STACK_OFFSET_GP(sp)
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+ move a0, rOBJ
+ move a1, rSELF
+ # a0=JNIMethod, a1=rSELF
+ la t9, dvmFastNativeMethodTraceExit
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+#endif
+
+ # native return; rBIX=newSaveArea
+ # equivalent to dvmPopJniLocals
+ lw a2, offStackSaveArea_returnAddr(rBIX) # a2 = chaining cell ret addr
+ lw a0, offStackSaveArea_localRefCookie(rBIX) # a0<- saved->top
+ lw a1, offThread_exception(rSELF) # check for exception
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = fp
+ sw a0, offThread_jniLocal_topCookie(rSELF) # new top <- old top
+ lw a0, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+
+ # a0 = dalvikCallsitePC
+ bnez a1, .LhandleException # handle exception if any
+
+ sw a2, offThread_inJitCodeCache(rSELF) # set the mode properly
+ beqz a2, 3f
+ jr a2 # go if return chaining cell still exist
+
+3:
+ # continue executing the next instruction through the interpreter
+ la a1, .LdvmJitToInterpTraceSelectNoChain # defined in footer.S
+ lw a1, (a1)
+ add rPC, a0, 3*2 # reconstruct new rPC (advance 3 dalvik instr)
+
+#if defined(WITH_JIT_TUNING)
+ li a0, kCallsiteInterpreted
+#endif
+ jr a1
diff --git a/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S
new file mode 100644
index 0000000..e167996
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S
@@ -0,0 +1,3 @@
+#define TEMPLATE_INLINE_PROFILING
+%include "mips/TEMPLATE_INVOKE_METHOD_NATIVE.S"
+#undef TEMPLATE_INLINE_PROFILING
diff --git a/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NO_OPT.S b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NO_OPT.S
new file mode 100644
index 0000000..d513d1c
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NO_OPT.S
@@ -0,0 +1,80 @@
+ /*
+ * For polymorphic callsites - setup the Dalvik frame and load Dalvik PC
+ * into rPC then jump to dvmJitToInterpNoChain to dispatch the
+ * runtime-resolved callee.
+ */
+ # a0 = methodToCall, a1 = returnCell, rPC = dalvikCallsite
+ lh t7, offMethod_registersSize(a0) # t7<- methodToCall->regsSize
+ lh a2, offMethod_outsSize(a0) # a2<- methodToCall->outsSize
+ lw t9, offThread_interpStackEnd(rSELF) # t9<- interpStackEnd
+ lbu t8, offThread_breakFlags(rSELF) # t8<- breakFlags
+ move a3, a1 # a3<- returnCell
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- stack save area
+ sll t6, t7, 2 # multiply regsSize by 4 (4 bytes per reg)
+ sub a1, a1, t6 # a1<- newFp(old savearea-regsSize)
+ SAVEAREA_FROM_FP(t0, a1) # t0<- stack save area
+ sll t6, a2, 2 # multiply outsSize by 4 (4 bytes per reg)
+ sub t0, t0, t6 # t0<- bottom (newsave-outsSize)
+ bgeu t0, t9, 1f # bottom < interpStackEnd?
+ RETURN # return to raise stack overflow excep.
+
+1:
+ # a1 = newFP, a0 = methodToCall, a3 = returnCell, rPC = dalvikCallsite
+ lw t9, offMethod_clazz(a0) # t9<- methodToCall->clazz
+ lw t0, offMethod_accessFlags(a0) # t0<- methodToCall->accessFlags
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+ sw rPC, (offStackSaveArea_savedPc - sizeofStackSaveArea)(a1)
+ lw rPC, offMethod_insns(a0) # rPC<- methodToCall->insns
+
+ # set up newSaveArea
+ sw rFP, (offStackSaveArea_prevFrame - sizeofStackSaveArea)(a1)
+ sw a3, (offStackSaveArea_returnAddr - sizeofStackSaveArea)(a1)
+ sw a0, (offStackSaveArea_method - sizeofStackSaveArea)(a1)
+ beqz t8, 2f # breakFlags != 0
+ RETURN # bail to the interpreter
+
+2:
+ and t6, t0, ACC_NATIVE
+ beqz t6, 3f
+#if !defined(WITH_SELF_VERIFICATION)
+ j .LinvokeNative
+#else
+ RETURN # bail to the interpreter
+#endif
+
+3:
+ # continue executing the next instruction through the interpreter
+ la t0, .LdvmJitToInterpTraceSelectNoChain # defined in footer.S
+ lw rTEMP, (t0)
+ lw a3, offClassObject_pDvmDex(t9) # a3<- method->clazz->pDvmDex
+
+ # Update "thread" values for the new method
+ sw a0, offThread_method(rSELF) # self->method = methodToCall
+ sw a3, offThread_methodClassDex(rSELF) # self->methodClassDex = ...
+ move rFP, a1 # fp = newFp
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # preserve a0-a3
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+
+ # a0=methodToCall, a1=rSELF
+ move a1, rSELF
+ la t9, dvmFastMethodTraceEnter
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a3
+ SCRATCH_LOAD(a3, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+#endif
+
+ # Start executing the callee
+#if defined(WITH_JIT_TUNING)
+ li a0, kInlineCacheMiss
+#endif
+ jr rTEMP # dvmJitToInterpTraceSelectNoChain
diff --git a/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S
new file mode 100644
index 0000000..386ce63
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S
@@ -0,0 +1,3 @@
+#define TEMPLATE_INLINE_PROFILING
+%include "mips/TEMPLATE_INVOKE_METHOD_NO_OPT.S"
+#undef TEMPLATE_INLINE_PROFILING
diff --git a/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S
new file mode 100644
index 0000000..e95ab32
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S
@@ -0,0 +1,59 @@
+%default { "chaintgt" : ".LinvokeChain" }
+ /*
+ * For polymorphic callsite, check whether the cached class pointer matches
+ * the current one. If so setup the Dalvik frame and return to the
+ * Thumb code through the link register to transfer control to the callee
+ * method through a dedicated chaining cell.
+ *
+ * The predicted chaining cell is declared in ArmLIR.h with the
+ * following layout:
+ *
+ * typedef struct PredictedChainingCell {
+ * u4 branch;
+ * u4 delay_slot;
+ * const ClassObject *clazz;
+ * const Method *method;
+ * u4 counter;
+ * } PredictedChainingCell;
+ *
+ * Upon returning to the callsite:
+ * - lr : to branch to the chaining cell
+ * - lr+8 : to punt to the interpreter
+ * - lr+16: to fully resolve the callee and may rechain.
+ * a3 <- class
+ */
+ # a0 = this, a1 = returnCell, a2 = predictedChainCell, rPC = dalvikCallsite
+ lw a3, offObject_clazz(a0) # a3 <- this->class
+ lw rIBASE, 8(a2) # t0 <- predictedChainCell->clazz
+ lw a0, 12(a2) # a0 <- predictedChainCell->method
+ lw t1, offThread_icRechainCount(rSELF) # t1 <- shared rechainCount
+
+#if defined(WITH_JIT_TUNING)
+ la rINST, .LdvmICHitCount
+ #add t2, t2, 1
+ bne a3, rIBASE, 1f
+ nop
+ lw t2, 0(rINST)
+ add t2, t2, 1
+ sw t2, 0(rINST)
+1:
+ #add t2, t2, 1
+#endif
+ beq a3, rIBASE, $chaintgt # branch if predicted chain is valid
+ lw rINST, offClassObject_vtable(a3) # rINST <- this->class->vtable
+ beqz rIBASE, 2f # initialized class or not
+ sub a1, t1, 1 # count--
+ sw a1, offThread_icRechainCount(rSELF) # write back to InterpState
+ b 3f
+2:
+ move a1, zero
+3:
+ add ra, ra, 16 # return to fully-resolve landing pad
+ /*
+ * a1 <- count
+ * a2 <- &predictedChainCell
+ * a3 <- this->class
+ * rPC <- dPC
+ * rINST <- this->class->vtable
+ */
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S
new file mode 100644
index 0000000..39d6452
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S
@@ -0,0 +1,3 @@
+#define TEMPLATE_INLINE_PROFILING
+%include "mips/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S" { "chaintgt" : ".LinvokeChainProf" }
+#undef TEMPLATE_INLINE_PROFILING
diff --git a/vm/compiler/template/mips/TEMPLATE_MEM_OP_DECODE.S b/vm/compiler/template/mips/TEMPLATE_MEM_OP_DECODE.S
new file mode 100644
index 0000000..038ccfd
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_MEM_OP_DECODE.S
@@ -0,0 +1,165 @@
+#if defined(WITH_SELF_VERIFICATION)
+ /*
+ * This handler encapsulates heap memory ops for selfVerification mode.
+ *
+ * The call to the handler is inserted prior to a heap memory operation.
+ * This handler then calls a function to decode the memory op, and process
+ * it accordingly. Afterwards, the handler changes the return address to
+ * skip the memory op so it never gets executed.
+ */
+#ifdef HARD_FLOAT
+ /* push f0-f31 onto stack */
+ sw f0, fr0*-4(sp) # push f0
+ sw f1, fr1*-4(sp) # push f1
+ sw f2, fr2*-4(sp) # push f2
+ sw f3, fr3*-4(sp) # push f3
+ sw f4, fr4*-4(sp) # push f4
+ sw f5, fr5*-4(sp) # push f5
+ sw f6, fr6*-4(sp) # push f6
+ sw f7, fr7*-4(sp) # push f7
+ sw f8, fr8*-4(sp) # push f8
+ sw f9, fr9*-4(sp) # push f9
+ sw f10, fr10*-4(sp) # push f10
+ sw f11, fr11*-4(sp) # push f11
+ sw f12, fr12*-4(sp) # push f12
+ sw f13, fr13*-4(sp) # push f13
+ sw f14, fr14*-4(sp) # push f14
+ sw f15, fr15*-4(sp) # push f15
+ sw f16, fr16*-4(sp) # push f16
+ sw f17, fr17*-4(sp) # push f17
+ sw f18, fr18*-4(sp) # push f18
+ sw f19, fr19*-4(sp) # push f19
+ sw f20, fr20*-4(sp) # push f20
+ sw f21, fr21*-4(sp) # push f21
+ sw f22, fr22*-4(sp) # push f22
+ sw f23, fr23*-4(sp) # push f23
+ sw f24, fr24*-4(sp) # push f24
+ sw f25, fr25*-4(sp) # push f25
+ sw f26, fr26*-4(sp) # push f26
+ sw f27, fr27*-4(sp) # push f27
+ sw f28, fr28*-4(sp) # push f28
+ sw f29, fr29*-4(sp) # push f29
+ sw f30, fr30*-4(sp) # push f30
+ sw f31, fr31*-4(sp) # push f31
+
+ sub sp, (32-0)*4 # adjust stack pointer
+#endif
+
+ /* push gp registers (except zero, gp, sp, and fp) */
+ .set noat
+ sw AT, r_AT*-4(sp) # push at
+ .set at
+ sw v0, r_V0*-4(sp) # push v0
+ sw v1, r_V1*-4(sp) # push v1
+ sw a0, r_A0*-4(sp) # push a0
+ sw a1, r_A1*-4(sp) # push a1
+ sw a2, r_A2*-4(sp) # push a2
+ sw a3, r_A3*-4(sp) # push a3
+ sw t0, r_T0*-4(sp) # push t0
+ sw t1, r_T1*-4(sp) # push t1
+ sw t2, r_T2*-4(sp) # push t2
+ sw t3, r_T3*-4(sp) # push t3
+ sw t4, r_T4*-4(sp) # push t4
+ sw t5, r_T5*-4(sp) # push t5
+ sw t6, r_T6*-4(sp) # push t6
+ sw t7, r_T7*-4(sp) # push t7
+ sw s0, r_S0*-4(sp) # push s0
+ sw s1, r_S1*-4(sp) # push s1
+ sw s2, r_S2*-4(sp) # push s2
+ sw s3, r_S3*-4(sp) # push s3
+ sw s4, r_S4*-4(sp) # push s4
+ sw s5, r_S5*-4(sp) # push s5
+ sw s6, r_S6*-4(sp) # push s6
+ sw s7, r_S7*-4(sp) # push s7
+ sw t8, r_T8*-4(sp) # push t8
+ sw t9, r_T9*-4(sp) # push t9
+ sw k0, r_K0*-4(sp) # push k0
+ sw k1, r_K1*-4(sp) # push k1
+ sw ra, r_RA*-4(sp) # push RA
+
+ # Note: even if we don't save all 32 registers, we still need to
+ # adjust SP by 32 registers due to the way we are storing
+ # the registers on the stack.
+ sub sp, (32-0)*4 # adjust stack pointer
+
+ la a2, .LdvmSelfVerificationMemOpDecode # defined in footer.S
+ lw a2, (a2)
+ move a0, ra # a0<- link register
+ move a1, sp # a1<- stack pointer
+ JALR(a2)
+
+ /* pop gp registers (except zero, gp, sp, and fp) */
+ # Note: even if we don't save all 32 registers, we still need to
+ # adjust SP by 32 registers due to the way we are storing
+ # the registers on the stack.
+ add sp, (32-0)*4 # adjust stack pointer
+ .set noat
+ lw AT, r_AT*-4(sp) # pop at
+ .set at
+ lw v0, r_V0*-4(sp) # pop v0
+ lw v1, r_V1*-4(sp) # pop v1
+ lw a0, r_A0*-4(sp) # pop a0
+ lw a1, r_A1*-4(sp) # pop a1
+ lw a2, r_A2*-4(sp) # pop a2
+ lw a3, r_A3*-4(sp) # pop a3
+ lw t0, r_T0*-4(sp) # pop t0
+ lw t1, r_T1*-4(sp) # pop t1
+ lw t2, r_T2*-4(sp) # pop t2
+ lw t3, r_T3*-4(sp) # pop t3
+ lw t4, r_T4*-4(sp) # pop t4
+ lw t5, r_T5*-4(sp) # pop t5
+ lw t6, r_T6*-4(sp) # pop t6
+ lw t7, r_T7*-4(sp) # pop t7
+ lw s0, r_S0*-4(sp) # pop s0
+ lw s1, r_S1*-4(sp) # pop s1
+ lw s2, r_S2*-4(sp) # pop s2
+ lw s3, r_S3*-4(sp) # pop s3
+ lw s4, r_S4*-4(sp) # pop s4
+ lw s5, r_S5*-4(sp) # pop s5
+ lw s6, r_S6*-4(sp) # pop s6
+ lw s7, r_S7*-4(sp) # pop s7
+ lw t8, r_T8*-4(sp) # pop t8
+ lw t9, r_T9*-4(sp) # pop t9
+ lw k0, r_K0*-4(sp) # pop k0
+ lw k1, r_K1*-4(sp) # pop k1
+ lw ra, r_RA*-4(sp) # pop RA
+
+#ifdef HARD_FLOAT
+ /* pop f0-f31 from stack */
+ add sp, (32-0)*4 # adjust stack pointer
+ lw f0, fr0*-4(sp) # pop f0
+ lw f1, fr1*-4(sp) # pop f1
+ lw f2, fr2*-4(sp) # pop f2
+ lw f3, fr3*-4(sp) # pop f3
+ lw f4, fr4*-4(sp) # pop f4
+ lw f5, fr5*-4(sp) # pop f5
+ lw f6, fr6*-4(sp) # pop f6
+ lw f7, fr7*-4(sp) # pop f7
+ lw f8, fr8*-4(sp) # pop f8
+ lw f9, fr9*-4(sp) # pop f9
+ lw f10, fr10*-4(sp) # pop f10
+ lw f11, fr11*-4(sp) # pop f11
+ lw f12, fr12*-4(sp) # pop f12
+ lw f13, fr13*-4(sp) # pop f13
+ lw f14, fr14*-4(sp) # pop f14
+ lw f15, fr15*-4(sp) # pop f15
+ lw f16, fr16*-4(sp) # pop f16
+ lw f17, fr17*-4(sp) # pop f17
+ lw f18, fr18*-4(sp) # pop f18
+ lw f19, fr19*-4(sp) # pop f19
+ lw f20, fr20*-4(sp) # pop f20
+ lw f21, fr21*-4(sp) # pop f21
+ lw f22, fr22*-4(sp) # pop f22
+ lw f23, fr23*-4(sp) # pop f23
+ lw f24, fr24*-4(sp) # pop f24
+ lw f25, fr25*-4(sp) # pop f25
+ lw f26, fr26*-4(sp) # pop f26
+ lw f27, fr27*-4(sp) # pop f27
+ lw f28, fr28*-4(sp) # pop f28
+ lw f29, fr29*-4(sp) # pop f29
+ lw f30, fr30*-4(sp) # pop f30
+ lw f31, fr31*-4(sp) # pop f31
+#endif
+
+ RETURN
+#endif
diff --git a/vm/compiler/template/mips/TEMPLATE_MONITOR_ENTER.S b/vm/compiler/template/mips/TEMPLATE_MONITOR_ENTER.S
new file mode 100644
index 0000000..902cdb7
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_MONITOR_ENTER.S
@@ -0,0 +1,25 @@
+ /*
+ * Call out to the runtime to lock an object. Because this thread
+ * may have been suspended in THREAD_MONITOR state and the Jit's
+ * translation cache subsequently cleared, we cannot return directly.
+ * Instead, unconditionally transition to the interpreter to resume.
+ *
+ * On entry:
+ * a0 - self pointer
+ * a1 - the object (which has already been null-checked by the caller
+ * rPC - the Dalvik PC of the following instruction.
+ */
+ la a2, .LdvmLockObject
+ lw t9, (a2)
+ sw zero, offThread_inJitCodeCache(a0) # record that we're not returning
+ JALR(t9) # dvmLockObject(self, obj)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ la a2, .LdvmJitToInterpNoChain
+ lw a2, (a2)
+
+ # Bail to interpreter - no chain [note - rPC still contains dPC]
+#if defined(WITH_JIT_TUNING)
+ li a0, kHeavyweightMonitor
+#endif
+ jr a2
diff --git a/vm/compiler/template/mips/TEMPLATE_MONITOR_ENTER_DEBUG.S b/vm/compiler/template/mips/TEMPLATE_MONITOR_ENTER_DEBUG.S
new file mode 100644
index 0000000..23bf661
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_MONITOR_ENTER_DEBUG.S
@@ -0,0 +1,30 @@
+ /*
+ * To support deadlock prediction, this version of MONITOR_ENTER
+ * will always call the heavyweight dvmLockObject, check for an
+ * exception and then bail out to the interpreter.
+ *
+ * On entry:
+ * a0 - self pointer
+ * a1 - the object (which has already been null-checked by the caller
+ * rPC - the Dalvik PC of the following instruction.
+ *
+ */
+ la a2, .LdvmLockObject
+ lw t9, (a2)
+ sw zero, offThread_inJitCodeCache(a0) # record that we're not returning
+ JALR(t9) # dvmLockObject(self, obj)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # test for exception
+ lw a1, offThread_exception(rSELF)
+ beqz a1, 1f
+ sub a0, rPC, 2 # roll dPC back to this monitor instruction
+ j .LhandleException
+1:
+ # Bail to interpreter - no chain [note - rPC still contains dPC]
+#if defined(WITH_JIT_TUNING)
+ li a0, kHeavyweightMonitor
+#endif
+ la a2, .LdvmJitToInterpNoChain
+ lw a2, (a2)
+ jr a2
diff --git a/vm/compiler/template/mips/TEMPLATE_MUL_DOUBLE_VFP.S b/vm/compiler/template/mips/TEMPLATE_MUL_DOUBLE_VFP.S
new file mode 100644
index 0000000..9254d76
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_MUL_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/fbinopWide.S" {"instr":"JAL(__muldf3)","instr_f":"mul.d fv0, fa0, fa1"}
diff --git a/vm/compiler/template/mips/TEMPLATE_MUL_FLOAT_VFP.S b/vm/compiler/template/mips/TEMPLATE_MUL_FLOAT_VFP.S
new file mode 100644
index 0000000..c1517b3
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_MUL_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/fbinop.S" {"instr":"JAL(__mulsf3)","instr_f":"mul.s fv0, fa0, fa1"}
diff --git a/vm/compiler/template/mips/TEMPLATE_MUL_LONG.S b/vm/compiler/template/mips/TEMPLATE_MUL_LONG.S
new file mode 100644
index 0000000..d91dcb8
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_MUL_LONG.S
@@ -0,0 +1,27 @@
+%verify "executed"
+ /*
+ * Signed 64-bit integer multiply.
+ *
+ * For JIT: op1 in a0/a1, op2 in a2/a3, return in v0/v1
+ *
+ * Consider WXxYZ (a1a0 x a3a2) with a long multiply:
+ *
+ * a1 a0
+ * x a3 a2
+ * -------------
+ * a2a1 a2a0
+ * a3a0
+ * a3a1 (<= unused)
+ * ---------------
+ * v1 v0
+ *
+ */
+ /* mul-long vAA, vBB, vCC */
+ mul rRESULT1,rARG3,rARG0 # v1= a3a0
+ multu rARG2,rARG0
+ mfhi t1
+ mflo rRESULT0 # v0= a2a0
+ mul t0,rARG2,rARG1 # t0= a2a1
+ addu rRESULT1,rRESULT1,t1 # v1= a3a0 + hi(a2a0)
+ addu rRESULT1,rRESULT1,t0 # v1= a3a0 + hi(a2a0) + a2a1;
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_PERIODIC_PROFILING.S b/vm/compiler/template/mips/TEMPLATE_PERIODIC_PROFILING.S
new file mode 100644
index 0000000..89031fd
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_PERIODIC_PROFILING.S
@@ -0,0 +1,28 @@
+ /*
+ * Increment profile counter for this trace, and decrement
+ * sample counter. If sample counter goes below zero, turn
+ * off profiling.
+ *
+ * On entry
+ * (ra-16) is address of pointer to counter. Note: the counter
+ * actually exists 16 bytes before the return target for mips.
+ * - 4 bytes for prof count addr.
+ * - 4 bytes for chain cell offset (2bytes 32 bit aligned).
+ * - 4 bytes for call TEMPLATE_PERIODIC_PROFILING.
+ * - 4 bytes for call delay slot.
+ */
+ lw a0, -16(ra)
+ lw a1, offThread_pProfileCountdown(rSELF)
+ lw a2, 0(a0) # get counter
+ lw a3, 0(a1) # get countdown timer
+ addu a2, 1
+ sub a3, 1 # FIXME - bug in ARM code???
+ bltz a3, .L${opcode}_disable_profiling
+ sw a2, 0(a0)
+ sw a3, 0(a1)
+ RETURN
+.L${opcode}_disable_profiling:
+ move rTEMP, ra # preserve ra
+ la a0, dvmJitTraceProfilingOff
+ JALR(a0)
+ jr rTEMP
diff --git a/vm/compiler/template/mips/TEMPLATE_RESTORE_STATE.S b/vm/compiler/template/mips/TEMPLATE_RESTORE_STATE.S
new file mode 100644
index 0000000..a4c505b
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_RESTORE_STATE.S
@@ -0,0 +1,91 @@
+ /*
+ * This handler restores state following a selfVerification memory access.
+ * On entry:
+ * a0 - offset from rSELF to the 1st element of the coreRegs save array.
+ * Note: the following registers are not restored
+ * zero, AT, gp, sp, fp, ra
+ */
+
+ add a0, a0, rSELF # pointer to heapArgSpace.coreRegs[0]
+#if 0
+ lw zero, r_ZERO*4(a0) # restore zero
+#endif
+ .set noat
+ lw AT, r_AT*4(a0) # restore at
+ .set at
+ lw v0, r_V0*4(a0) # restore v0
+ lw v1, r_V1*4(a0) # restore v1
+
+ lw a1, r_A1*4(a0) # restore a1
+ lw a2, r_A2*4(a0) # restore a2
+ lw a3, r_A3*4(a0) # restore a3
+
+ lw t0, r_T0*4(a0) # restore t0
+ lw t1, r_T1*4(a0) # restore t1
+ lw t2, r_T2*4(a0) # restore t2
+ lw t3, r_T3*4(a0) # restore t3
+ lw t4, r_T4*4(a0) # restore t4
+ lw t5, r_T5*4(a0) # restore t5
+ lw t6, r_T6*4(a0) # restore t6
+ lw t7, r_T7*4(a0) # restore t7
+
+ lw s0, r_S0*4(a0) # restore s0
+ lw s1, r_S1*4(a0) # restore s1
+ lw s2, r_S2*4(a0) # restore s2
+ lw s3, r_S3*4(a0) # restore s3
+ lw s4, r_S4*4(a0) # restore s4
+ lw s5, r_S5*4(a0) # restore s5
+ lw s6, r_S6*4(a0) # restore s6
+ lw s7, r_S7*4(a0) # restore s7
+
+ lw t8, r_T8*4(a0) # restore t8
+ lw t9, r_T9*4(a0) # restore t9
+
+ lw k0, r_K0*4(a0) # restore k0
+ lw k1, r_K1*4(a0) # restore k1
+
+#if 0
+ lw gp, r_GP*4(a0) # restore gp
+ lw sp, r_SP*4(a0) # restore sp
+ lw fp, r_FP*4(a0) # restore fp
+ lw ra, r_RA*4(a0) # restore ra
+#endif
+
+/* #ifdef HARD_FLOAT */
+#if 0
+ lw f0, fr0*4(a0) # restore f0
+ lw f1, fr1*4(a0) # restore f1
+ lw f2, fr2*4(a0) # restore f2
+ lw f3, fr3*4(a0) # restore f3
+ lw f4, fr4*4(a0) # restore f4
+ lw f5, fr5*4(a0) # restore f5
+ lw f6, fr6*4(a0) # restore f6
+ lw f7, fr7*4(a0) # restore f7
+ lw f8, fr8*4(a0) # restore f8
+ lw f9, fr9*4(a0) # restore f9
+ lw f10, fr10*4(a0) # restore f10
+ lw f11, fr11*4(a0) # restore f11
+ lw f12, fr12*4(a0) # restore f12
+ lw f13, fr13*4(a0) # restore f13
+ lw f14, fr14*4(a0) # restore f14
+ lw f15, fr15*4(a0) # restore f15
+ lw f16, fr16*4(a0) # restore f16
+ lw f17, fr17*4(a0) # restore f17
+ lw f18, fr18*4(a0) # restore f18
+ lw f19, fr19*4(a0) # restore f19
+ lw f20, fr20*4(a0) # restore f20
+ lw f21, fr21*4(a0) # restore f21
+ lw f22, fr22*4(a0) # restore f22
+ lw f23, fr23*4(a0) # restore f23
+ lw f24, fr24*4(a0) # restore f24
+ lw f25, fr25*4(a0) # restore f25
+ lw f26, fr26*4(a0) # restore f26
+ lw f27, fr27*4(a0) # restore f27
+ lw f28, fr28*4(a0) # restore f28
+ lw f29, fr29*4(a0) # restore f29
+ lw f30, fr30*4(a0) # restore f30
+ lw f31, fr31*4(a0) # restore f31
+#endif
+
+ lw a0, r_A1*4(a0) # restore a0
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_RETURN.S b/vm/compiler/template/mips/TEMPLATE_RETURN.S
new file mode 100644
index 0000000..e9cee05
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_RETURN.S
@@ -0,0 +1,77 @@
+ /*
+ * Unwind a frame from the Dalvik stack for compiled OP_RETURN_XXX.
+ * If the stored value in returnAddr
+ * is non-zero, the caller is compiled by the JIT thus return to the
+ * address in the code cache following the invoke instruction. Otherwise
+ * return to the special dvmJitToInterpNoChain entry point.
+ */
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # preserve a0-a2 and ra
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(ra, 12)
+
+ # a0=rSELF
+ move a0, rSELF
+ la t9, dvmFastMethodTraceExit
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a2 and ra
+ SCRATCH_LOAD(ra, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+#endif
+ SAVEAREA_FROM_FP(a0, rFP) # a0<- saveArea (old)
+ lw t0, offStackSaveArea_prevFrame(a0) # t0<- saveArea->prevFrame
+ lbu t1, offThread_breakFlags(rSELF) # t1<- breakFlags
+ lw rPC, offStackSaveArea_savedPc(a0) # rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+ lw t2, offStackSaveArea_returnAddr(a0) # t2<- chaining cell ret
+#else
+ move t2, zero # disable chaining
+#endif
+ lw a2, offStackSaveArea_method - sizeofStackSaveArea(t0)
+ # a2<- method we're returning to
+#if !defined(WITH_SELF_VERIFICATION)
+ beq a2, zero, 1f # bail to interpreter
+#else
+ bne a2, zero, 2f
+ JALR(ra) # punt to interpreter and compare state
+ # DOUG: assume this does not return ???
+2:
+#endif
+ la t4, .LdvmJitToInterpNoChainNoProfile # defined in footer.S
+ lw a1, (t4)
+ move rFP, t0 # publish new FP
+ beq a2, zero, 4f
+ lw t0, offMethod_clazz(a2) # t0<- method->clazz
+4:
+
+ sw a2, offThread_method(rSELF) # self->method = newSave->method
+ lw a0, offClassObject_pDvmDex(t0) # a0<- method->clazz->pDvmDex
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = fp
+ add rPC, rPC, 3*2 # publish new rPC
+ sw a0, offThread_methodClassDex(rSELF)
+ movn t2, zero, t1 # check the breadFlags and
+ # clear the chaining cell address
+ sw t2, offThread_inJitCodeCache(rSELF) # in code cache or not
+ beq t2, zero, 3f # chaining cell exists?
+ JALR(t2) # jump to the chaining cell
+ # DOUG: assume this does not return ???
+3:
+#if defined(WITH_JIT_TUNING)
+ li a0, kCallsiteInterpreted
+#endif
+ j a1 # callsite is interpreted
+1:
+ sw zero, offThread_inJitCodeCache(rSELF) # reset inJitCodeCache
+ SAVE_PC_TO_SELF() # SAVE_PC_FP_TO_SELF()
+ SAVE_FP_TO_SELF()
+ la t4, .LdvmMterpStdBail # defined in footer.S
+ lw a2, (t4)
+ move a0, rSELF # Expecting rSELF in a0
+ JALR(a2) # exit the interpreter
+ # DOUG: assume this does not return ???
diff --git a/vm/compiler/template/mips/TEMPLATE_RETURN_PROF.S b/vm/compiler/template/mips/TEMPLATE_RETURN_PROF.S
new file mode 100644
index 0000000..b4e0754
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_RETURN_PROF.S
@@ -0,0 +1,3 @@
+#define TEMPLATE_INLINE_PROFILING
+%include "mips/TEMPLATE_RETURN.S"
+#undef TEMPLATE_INLINE_PROFILING
diff --git a/vm/compiler/template/mips/TEMPLATE_SAVE_STATE.S b/vm/compiler/template/mips/TEMPLATE_SAVE_STATE.S
new file mode 100644
index 0000000..2e74481
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_SAVE_STATE.S
@@ -0,0 +1,105 @@
+ /*
+ * This handler performs a register save for selfVerification mode.
+ * On entry:
+ * Top of stack + 4: a1 value to save
+ * Top of stack + 0: a0 value to save
+ * a0 - offset from rSELF to the beginning of the heapArgSpace record
+ * a1 - the value of regMap
+ *
+ * The handler must save regMap, r0-r31, f0-f31 if FPU, and then return with
+ * r0-r31 with their original values (note that this means a0 and a1 must take
+ * the values on the stack - not the ones in those registers on entry.
+ * Finally, the two registers previously pushed must be popped.
+ * Note: the following registers are not saved
+ * zero, AT, gp, sp, fp, ra
+ */
+ add a0, a0, rSELF # pointer to heapArgSpace
+ sw a1, 0(a0) # save regMap
+ add a0, a0, 4 # pointer to coreRegs
+#if 0
+ sw zero, r_ZERO*4(a0) # save zero
+#endif
+ .set noat
+ sw AT, r_AT*4(a0) # save at
+ .set at
+ sw v0, r_V0*4(a0) # save v0
+ sw v1, r_V1*4(a0) # save v1
+
+ lw a1, 0(sp) # recover a0 value
+ sw a1, r_A0*4(a0) # save a0
+ lw a1, 4(sp) # recover a1 value
+ sw a1, r_A1*4(a0) # save a1
+ sw a2, r_A2*4(a0) # save a2
+ sw a3, r_A3*4(a0) # save a3
+
+ sw t0, r_T0*4(a0) # save t0
+ sw t1, r_T1*4(a0) # save t1
+ sw t2, r_T2*4(a0) # save t2
+ sw t3, r_T3*4(a0) # save t3
+ sw t4, r_T4*4(a0) # save t4
+ sw t5, r_T5*4(a0) # save t5
+ sw t6, r_T6*4(a0) # save t6
+ sw t7, r_T7*4(a0) # save t7
+
+ sw s0, r_S0*4(a0) # save s0
+ sw s1, r_S1*4(a0) # save s1
+ sw s2, r_S2*4(a0) # save s2
+ sw s3, r_S3*4(a0) # save s3
+ sw s4, r_S4*4(a0) # save s4
+ sw s5, r_S5*4(a0) # save s5
+ sw s6, r_S6*4(a0) # save s6
+ sw s7, r_S7*4(a0) # save s7
+
+ sw t8, r_T8*4(a0) # save t8
+ sw t9, r_T9*4(a0) # save t9
+
+ sw k0, r_K0*4(a0) # save k0
+ sw k1, r_K1*4(a0) # save k1
+
+#if 0
+ sw gp, r_GP*4(a0) # save gp
+ sw sp, r_SP*4(a0) # save sp (need to adjust??? )
+ sw fp, r_FP*4(a0) # save fp
+ sw ra, r_RA*4(a0) # save ra
+#endif
+
+/* #ifdef HARD_FLOAT */
+#if 0
+ sw f0, fr0*4(a0) # save f0
+ sw f1, fr1*4(a0) # save f1
+ sw f2, fr2*4(a0) # save f2
+ sw f3, fr3*4(a0) # save f3
+ sw f4, fr4*4(a0) # save f4
+ sw f5, fr5*4(a0) # save f5
+ sw f6, fr6*4(a0) # save f6
+ sw f7, fr7*4(a0) # save f7
+ sw f8, fr8*4(a0) # save f8
+ sw f9, fr9*4(a0) # save f9
+ sw f10, fr10*4(a0) # save f10
+ sw f11, fr11*4(a0) # save f11
+ sw f12, fr12*4(a0) # save f12
+ sw f13, fr13*4(a0) # save f13
+ sw f14, fr14*4(a0) # save f14
+ sw f15, fr15*4(a0) # save f15
+ sw f16, fr16*4(a0) # save f16
+ sw f17, fr17*4(a0) # save f17
+ sw f18, fr18*4(a0) # save f18
+ sw f19, fr19*4(a0) # save f19
+ sw f20, fr20*4(a0) # save f20
+ sw f21, fr21*4(a0) # save f21
+ sw f22, fr22*4(a0) # save f22
+ sw f23, fr23*4(a0) # save f23
+ sw f24, fr24*4(a0) # save f24
+ sw f25, fr25*4(a0) # save f25
+ sw f26, fr26*4(a0) # save f26
+ sw f27, fr27*4(a0) # save f27
+ sw f28, fr28*4(a0) # save f28
+ sw f29, fr29*4(a0) # save f29
+ sw f30, fr30*4(a0) # save f30
+ sw f31, fr31*4(a0) # save f31
+#endif
+
+ lw a1, 0(sp) # recover a0 value
+ lw a1, 4(sp) # recover a1 value
+ sub sp, sp, 8 # adjust stack ptr
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_SHL_LONG.S b/vm/compiler/template/mips/TEMPLATE_SHL_LONG.S
new file mode 100644
index 0000000..b15f0c3
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_SHL_LONG.S
@@ -0,0 +1,17 @@
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* shl-long vAA:vBB(rARG1:rARG0), vCC(a2) - result in (rRESULT1:rRESULT0) */
+ sll rRESULT0, rARG0, a2 # rlo<- alo << (shift&31)
+ not rRESULT1, a2 # rhi<- 31-shift (shift is 5b)
+ srl rARG0, 1
+ srl rARG0, rRESULT1 # alo<- alo >> (32-(shift&31))
+ sll rRESULT1, rARG1, a2 # rhi<- ahi << (shift&31)
+ or rRESULT1, rARG0 # rhi<- rhi | alo
+ andi a2, 0x20 # shift< shift & 0x20
+ movn rRESULT1, rRESULT0, a2 # rhi<- rlo (if shift&0x20)
+ movn rRESULT0, zero, a2 # rlo<- 0 (if shift&0x20)
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_SHR_LONG.S b/vm/compiler/template/mips/TEMPLATE_SHR_LONG.S
new file mode 100644
index 0000000..e59686d
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_SHR_LONG.S
@@ -0,0 +1,18 @@
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* shr-long vAA:vBB(rARG1:rARG0), vCC(a2) - result in (rRESULT1:rRESULT0) */
+ sra rRESULT1, rARG1, a2 # rhi<- ahi >> (shift&31)
+ srl rRESULT0, rARG0, a2 # rlo<- alo >> (shift&31)
+ sra a3, rARG1, 31 # a3<- sign(ah)
+ not rARG0, a2 # alo<- 31-shift (shift is 5b)
+ sll rARG1, 1
+ sll rARG1, rARG0 # ahi<- ahi << (32-(shift&31))
+ or rRESULT0, rARG1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn rRESULT0, rRESULT1, a2 # rlo<- rhi (if shift&0x20)
+ movn rRESULT1, a3, a2 # rhi<- sign(ahi) (if shift&0x20)
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_SQRT_DOUBLE_VFP.S b/vm/compiler/template/mips/TEMPLATE_SQRT_DOUBLE_VFP.S
new file mode 100644
index 0000000..253a4a4
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_SQRT_DOUBLE_VFP.S
@@ -0,0 +1,23 @@
+%verify "executed"
+
+ /*
+ * 64-bit floating point sqrt operation.
+ * If the result is a NaN, bail out to library code to do
+ * the right thing.
+ *
+ * On entry:
+ * a2 src addr of op1
+ * On exit:
+ * v0,v1/fv0 = res
+ */
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a2) # a0/a1<- vBB/vBB+1
+#else
+ LOAD64_F(fa0, fa0f, a2) # fa0/fa0f<- vBB/vBB+1
+ sqrt.d fv0, fa0
+ c.eq.d fv0, fv0
+ bc1t 1f
+#endif
+ JAL(sqrt)
+1:
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_STRING_COMPARETO.S b/vm/compiler/template/mips/TEMPLATE_STRING_COMPARETO.S
new file mode 100644
index 0000000..a514351
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_STRING_COMPARETO.S
@@ -0,0 +1,146 @@
+ /*
+ * String's compareTo.
+ *
+ * Requires a0/a1 to have been previously checked for null. Will
+ * return negative if this's string is < comp, 0 if they are the
+ * same and positive if >.
+ *
+ * IMPORTANT NOTE:
+ *
+ * This code relies on hard-coded offsets for string objects, and must be
+ * kept in sync with definitions in UtfString.h. See asm-constants.h
+ *
+ * On entry:
+ * a0: this object pointer
+ * a1: comp object pointer
+ *
+ */
+
+ subu v0, a0, a1 # Same?
+ bnez v0, 1f
+ RETURN
+1:
+ lw t0, STRING_FIELDOFF_OFFSET(a0)
+ lw t1, STRING_FIELDOFF_OFFSET(a1)
+ lw t2, STRING_FIELDOFF_COUNT(a0)
+ lw a2, STRING_FIELDOFF_COUNT(a1)
+ lw a0, STRING_FIELDOFF_VALUE(a0)
+ lw a1, STRING_FIELDOFF_VALUE(a1)
+
+ /*
+ * At this point, we have this/comp:
+ * offset: t0/t1
+ * count: t2/a2
+ * value: a0/a1
+ * We're going to compute
+ * a3 <- countDiff
+ * a2 <- minCount
+ */
+ subu a3, t2, a2 # a3<- countDiff
+ sleu t7, t2, a2
+ movn a2, t2, t7 # a2<- minCount
+
+ /*
+ * Note: data pointers point to first element.
+ */
+ addu a0, 16 # point to contents[0]
+ addu a1, 16 # point to contents[0]
+
+ /* Now, build pointers to the string data */
+ sll t7, t0, 1 # multiply offset by 2
+ addu a0, a0, t7
+ sll t7, t1, 1 # multiply offset by 2
+ addu a1, a1, t7
+
+ /*
+ * At this point we have:
+ * a0: *this string data
+ * a1: *comp string data
+ * a2: iteration count for comparison
+ * a3: value to return if the first part of the string is equal
+ * v0: reserved for result
+ * t0-t5 available for loading string data
+ */
+
+ subu a2, 2
+ bltz a2, do_remainder2
+
+ /*
+ * Unroll the first two checks so we can quickly catch early mismatch
+ * on long strings (but preserve incoming alignment)
+ */
+ lhu t0, 0(a0)
+ lhu t1, 0(a1)
+ subu v0, t0, t1
+ beqz v0, 1f
+ RETURN
+1:
+ lhu t2, 2(a0)
+ lhu t3, 2(a1)
+ subu v0, t2, t3
+ beqz v0, 2f
+ RETURN
+2:
+ addu a0, 4 # offset to contents[2]
+ addu a1, 4 # offset to contents[2]
+ li t7, 28
+ bgt a2, t7, do_memcmp16
+ subu a2, 3
+ bltz a2, do_remainder
+
+loopback_triple:
+ lhu t0, 0(a0)
+ lhu t1, 0(a1)
+ subu v0, t0, t1
+ beqz v0, 1f
+ RETURN
+1:
+ lhu t2, 2(a0)
+ lhu t3, 2(a1)
+ subu v0, t2, t3
+ beqz v0, 2f
+ RETURN
+2:
+ lhu t4, 4(a0)
+ lhu t5, 4(a1)
+ subu v0, t4, t5
+ beqz v0, 3f
+ RETURN
+3:
+ addu a0, 6 # offset to contents[i+3]
+ addu a1, 6 # offset to contents[i+3]
+ subu a2, 3
+ bgez a2, loopback_triple
+
+do_remainder:
+ addu a2, 3
+ beqz a2, returnDiff
+
+loopback_single:
+ lhu t0, 0(a0)
+ lhu t1, 0(a1)
+ subu v0, t0, t1
+ bnez v0, 1f
+ addu a0, 2 # offset to contents[i+1]
+ addu a1, 2 # offset to contents[i+1]
+ subu a2, 1
+ bnez a2, loopback_single
+
+returnDiff:
+ move v0, a3
+1:
+ RETURN
+
+do_remainder2:
+ addu a2, 2
+ bnez a2, loopback_single
+ move v0, a3
+ RETURN
+
+ /* Long string case */
+do_memcmp16:
+ move rOBJ, a3 # save return value if strings are equal
+ JAL(__memcmp16)
+ seq t0, v0, zero
+ movn v0, rOBJ, t0 # overwrite return value if strings are equal
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_STRING_INDEXOF.S b/vm/compiler/template/mips/TEMPLATE_STRING_INDEXOF.S
new file mode 100644
index 0000000..9d9cd60
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_STRING_INDEXOF.S
@@ -0,0 +1,111 @@
+ /*
+ * String's indexOf.
+ *
+ * Requires a0 to have been previously checked for null. Will
+ * return index of match of a1 in v0.
+ *
+ * IMPORTANT NOTE:
+ *
+ * This code relies on hard-coded offsets for string objects, and must be
+ * kept in sync wth definitions in UtfString.h See asm-constants.h
+ *
+ * On entry:
+ * a0: string object pointer
+ * a1: char to match
+ * a2: Starting offset in string data
+ */
+
+ lw t0, STRING_FIELDOFF_OFFSET(a0)
+ lw t1, STRING_FIELDOFF_COUNT(a0)
+ lw v0, STRING_FIELDOFF_VALUE(a0)
+
+ /*
+ * At this point, we have:
+ * v0: object pointer
+ * a1: char to match
+ * a2: starting offset
+ * t0: offset
+ * t1: string length
+ */
+
+ /* Point to first element */
+ addu v0, 16 # point to contents[0]
+
+ /* Build pointer to start of string data */
+ sll t7, t0, 1 # multiply offset by 2
+ addu v0, v0, t7
+
+ /* Save a copy of starting data in v1 */
+ move v1, v0
+
+ /* Clamp start to [0..count] */
+ slt t7, a2, zero
+ movn a2, zero, t7
+ sgt t7, a2, t1
+ movn a2, t1, t7
+
+ /* Build pointer to start of data to compare */
+ sll t7, a2, 1 # multiply offset by 2
+ addu v0, v0, t7
+
+ /* Compute iteration count */
+ subu a3, t1, a2
+
+ /*
+ * At this point we have:
+ * v0: start of data to test
+ * a1: char to compare
+ * a3: iteration count
+ * v1: original start of string
+ * t0-t7 available for loading string data
+ */
+ subu a3, 4
+ bltz a3, indexof_remainder
+
+indexof_loop4:
+ lhu t0, 0(v0)
+ beq t0, a1, match_0
+ lhu t0, 2(v0)
+ beq t0, a1, match_1
+ lhu t0, 4(v0)
+ beq t0, a1, match_2
+ lhu t0, 6(v0)
+ beq t0, a1, match_3
+ addu v0, 8 # offset to contents[i+4]
+ subu a3, 4
+ bgez a3, indexof_loop4
+
+indexof_remainder:
+ addu a3, 4
+ beqz a3, indexof_nomatch
+
+indexof_loop1:
+ lhu t0, 0(v0)
+ beq t0, a1, match_0
+ addu v0, 2 # offset to contents[i+1]
+ subu a3, 1
+ bnez a3, indexof_loop1
+
+indexof_nomatch:
+ li v0, -1
+ RETURN
+
+match_0:
+ subu v0, v1
+ sra v0, v0, 1 # divide by 2
+ RETURN
+match_1:
+ addu v0, 2
+ subu v0, v1
+ sra v0, v0, 1 # divide by 2
+ RETURN
+match_2:
+ addu v0, 4
+ subu v0, v1
+ sra v0, v0, 1 # divide by 2
+ RETURN
+match_3:
+ addu v0, 6
+ subu v0, v1
+ sra v0, v0, 1 # divide by 2
+ RETURN
diff --git a/vm/compiler/template/mips/TEMPLATE_SUB_DOUBLE_VFP.S b/vm/compiler/template/mips/TEMPLATE_SUB_DOUBLE_VFP.S
new file mode 100644
index 0000000..b07bf44
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_SUB_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/fbinopWide.S" {"instr":"JAL(__subdf3)","instr_f":"sub.d fv0, fa0, fa1"}
diff --git a/vm/compiler/template/mips/TEMPLATE_SUB_FLOAT_VFP.S b/vm/compiler/template/mips/TEMPLATE_SUB_FLOAT_VFP.S
new file mode 100644
index 0000000..b0333cd
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_SUB_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/fbinop.S" {"instr":"JAL(__subsf3)","instr_f":"sub.s fv0, fa0, fa1"}
diff --git a/vm/compiler/template/mips/TEMPLATE_THROW_EXCEPTION_COMMON.S b/vm/compiler/template/mips/TEMPLATE_THROW_EXCEPTION_COMMON.S
new file mode 100644
index 0000000..d6e8b2e
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_THROW_EXCEPTION_COMMON.S
@@ -0,0 +1,6 @@
+ /*
+ * Throw an exception from JIT'ed code.
+ * On entry:
+ * a0 Dalvik PC that raises the exception
+ */
+ j .LhandleException
diff --git a/vm/compiler/template/mips/TEMPLATE_USHR_LONG.S b/vm/compiler/template/mips/TEMPLATE_USHR_LONG.S
new file mode 100644
index 0000000..f2a9ddb
--- /dev/null
+++ b/vm/compiler/template/mips/TEMPLATE_USHR_LONG.S
@@ -0,0 +1,17 @@
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* ushr-long vAA:vBB(rARG1:rARG0), vCC(a2) - result in (rRESULT1:rRESULT0) */
+ srl rRESULT1, rARG1, a2 # rhi<- ahi >> (shift&31)
+ srl rRESULT0, rARG0, a2 # rlo<- alo >> (shift&31)
+ not rARG0, a2 # alo<- 31-n (shift is 5b)
+ sll rARG1, 1
+ sll rARG1, rARG0 # ahi<- ahi << (32-(shift&31))
+ or rRESULT0, rARG1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn rRESULT0, rRESULT1, a2 # rlo<- rhi (if shift&0x20)
+ movn rRESULT1, zero, a2 # rhi<- 0 (if shift&0x20)
+ RETURN
diff --git a/vm/compiler/template/mips/TemplateOpList.h b/vm/compiler/template/mips/TemplateOpList.h
new file mode 100644
index 0000000..6aabdba
--- /dev/null
+++ b/vm/compiler/template/mips/TemplateOpList.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik opcode list that uses additional templates to complete JIT execution.
+ */
+#ifndef JIT_TEMPLATE
+#define JIT_TEMPLATE(X)
+#endif
+
+JIT_TEMPLATE(CMP_LONG)
+JIT_TEMPLATE(RETURN)
+JIT_TEMPLATE(INVOKE_METHOD_NO_OPT)
+JIT_TEMPLATE(INVOKE_METHOD_CHAIN)
+JIT_TEMPLATE(INVOKE_METHOD_PREDICTED_CHAIN)
+JIT_TEMPLATE(INVOKE_METHOD_NATIVE)
+JIT_TEMPLATE(MUL_LONG)
+JIT_TEMPLATE(SHL_LONG)
+JIT_TEMPLATE(SHR_LONG)
+JIT_TEMPLATE(USHR_LONG)
+JIT_TEMPLATE(ADD_FLOAT_VFP)
+JIT_TEMPLATE(SUB_FLOAT_VFP)
+JIT_TEMPLATE(MUL_FLOAT_VFP)
+JIT_TEMPLATE(DIV_FLOAT_VFP)
+JIT_TEMPLATE(ADD_DOUBLE_VFP)
+JIT_TEMPLATE(SUB_DOUBLE_VFP)
+JIT_TEMPLATE(MUL_DOUBLE_VFP)
+JIT_TEMPLATE(DIV_DOUBLE_VFP)
+JIT_TEMPLATE(DOUBLE_TO_FLOAT_VFP)
+JIT_TEMPLATE(DOUBLE_TO_INT_VFP)
+JIT_TEMPLATE(FLOAT_TO_DOUBLE_VFP)
+JIT_TEMPLATE(FLOAT_TO_INT_VFP)
+JIT_TEMPLATE(INT_TO_DOUBLE_VFP)
+JIT_TEMPLATE(INT_TO_FLOAT_VFP)
+JIT_TEMPLATE(CMPG_DOUBLE_VFP)
+JIT_TEMPLATE(CMPL_DOUBLE_VFP)
+JIT_TEMPLATE(CMPG_FLOAT_VFP)
+JIT_TEMPLATE(CMPL_FLOAT_VFP)
+JIT_TEMPLATE(SQRT_DOUBLE_VFP)
+JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
+JIT_TEMPLATE(MEM_OP_DECODE)
+JIT_TEMPLATE(STRING_COMPARETO)
+JIT_TEMPLATE(STRING_INDEXOF)
+JIT_TEMPLATE(INTERPRET)
+JIT_TEMPLATE(MONITOR_ENTER)
+JIT_TEMPLATE(MONITOR_ENTER_DEBUG)
+JIT_TEMPLATE(RESTORE_STATE)
+JIT_TEMPLATE(SAVE_STATE)
+JIT_TEMPLATE(PERIODIC_PROFILING)
+JIT_TEMPLATE(RETURN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_NO_OPT_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_CHAIN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_PREDICTED_CHAIN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_NATIVE_PROF)
diff --git a/vm/compiler/template/mips/fbinop.S b/vm/compiler/template/mips/fbinop.S
new file mode 100644
index 0000000..e9ccf0a
--- /dev/null
+++ b/vm/compiler/template/mips/fbinop.S
@@ -0,0 +1,38 @@
+%default {"preinstr":"", "chkzero":"0"}
+ /*
+ * Generic 32-bit binary float operation. a0 = a1 op a2.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = op1 address
+ * a2 = op2 address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ *
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vBB
+ LOAD(a1, a2) # a1<- vCC
+ .if $chkzero
+ beqz a1, common_errDivideByZero # is second operand zero?
+ .endif
+ $preinstr # optional op
+ $instr # v0 = result
+ STORE(v0, rOBJ) # vAA <- v0
+#else
+ LOAD_F(fa0, a1) # fa0<- vBB
+ LOAD_F(fa1, a2) # fa1<- vCC
+ .if $chkzero
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+ $preinstr # optional op
+ $instr_f # fv0 = result
+ STORE_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ RETURN
diff --git a/vm/compiler/template/mips/fbinopWide.S b/vm/compiler/template/mips/fbinopWide.S
new file mode 100644
index 0000000..0e31b87
--- /dev/null
+++ b/vm/compiler/template/mips/fbinopWide.S
@@ -0,0 +1,45 @@
+%default {"preinstr":"", "chkzero":"0"}
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = op1 address
+ * a2 = op2 address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ move t0, a1 # save a1
+ move t1, a2 # save a2
+ LOAD64(rARG0, rARG1, t0) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3<- vCC/vCC+1
+ .if $chkzero
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ $preinstr # optional op
+ $instr # result<- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ LOAD64_F(fa0, fa0f, a1)
+ LOAD64_F(fa1, fa1f, a2)
+ .if $chkzero
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+ $preinstr # optional op
+ $instr_f
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ RETURN
diff --git a/vm/compiler/template/mips/footer.S b/vm/compiler/template/mips/footer.S
new file mode 100644
index 0000000..3b59dd9
--- /dev/null
+++ b/vm/compiler/template/mips/footer.S
@@ -0,0 +1,138 @@
+/*
+ * ===========================================================================
+ * Common subroutines and data
+ * ===========================================================================
+ */
+
+ .section .data.rel.ro
+ .align 4
+.LinvokeNative:
+ # Prep for the native call
+ # a1 = newFP, a0 = methodToCall
+ lw t9, offThread_jniLocal_topCookie(rSELF) # t9<- thread->localRef->...
+ sw zero, offThread_inJitCodeCache(rSELF) # not in jit code cache
+ sw a1, offThread_curFrame(rSELF) # self->curFrame = newFp
+ sw t9, (offStackSaveArea_localRefCookie - sizeofStackSaveArea)(a1)
+ # newFp->localRefCookie=top
+ lhu ra, offThread_subMode(rSELF)
+ SAVEAREA_FROM_FP(rBIX, a1) # rBIX<- new stack save area
+
+ move a2, a0 # a2<- methodToCall
+ move a0, a1 # a0<- newFp
+ add a1, rSELF, offThread_retval # a1<- &retval
+ move a3, rSELF # a3<- self
+ andi ra, kSubModeMethodTrace
+ beqz ra, 121f
+ # a2: methodToCall
+ # preserve a0-a3
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+ move rTEMP, a2 # preserve a2
+
+ move a0, rTEMP
+ move a1, rSELF
+ la t9, dvmFastMethodTraceEnter
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a3
+ SCRATCH_LOAD(a3, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+
+ lw t9, offMethod_nativeFunc(a2)
+ JALR(t9) # call methodToCall->nativeFunc
+ lw gp, STACK_OFFSET_GP(sp)
+
+ move a0, rTEMP
+ move a1, rSELF
+ la t9, dvmFastNativeMethodTraceExit
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+ b 212f
+
+121:
+ lw t9, offMethod_nativeFunc(a2)
+ JALR(t9) # call methodToCall->nativeFunc
+ lw gp, STACK_OFFSET_GP(sp)
+
+212:
+ # native return; rBIX=newSaveArea
+ # equivalent to dvmPopJniLocals
+ lw a2, offStackSaveArea_returnAddr(rBIX) # a2 = chaining cell ret addr
+ lw a0, offStackSaveArea_localRefCookie(rBIX) # a0<- saved->top
+ lw a1, offThread_exception(rSELF) # check for exception
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = fp
+ sw a0, offThread_jniLocal_topCookie(rSELF) # new top <- old top
+ lw a0, offStackSaveArea_savedPc(rBIX) # reload rPC
+
+ # a0 = dalvikCallsitePC
+ bnez a1, .LhandleException # handle exception if any
+
+ sw a2, offThread_inJitCodeCache(rSELF) # set the mode properly
+ beqz a2, 3f
+ jr a2 # go if return chaining cell still exist
+
+3:
+ # continue executing the next instruction through the interpreter
+ la a1, .LdvmJitToInterpTraceSelectNoChain # defined in footer.S
+ lw a1, (a1)
+ add rPC, a0, 3*2 # reconstruct new rPC
+
+#if defined(WITH_JIT_TUNING)
+ li a0, kCallsiteInterpreted
+#endif
+ jr a1
+
+
+/*
+ * On entry:
+ * a0 Faulting Dalvik PC
+ */
+.LhandleException:
+#if defined(WITH_SELF_VERIFICATION)
+ la t0, .LdeadFood
+ lw t0, (t0) # should not see this under self-verification mode
+ jr t0
+.LdeadFood:
+ .word 0xdeadf00d
+#endif
+ sw zero, offThread_inJitCodeCache(rSELF) # in interpreter land
+ la a1, .LdvmMterpCommonExceptionThrown # PIC way of getting &func
+ lw a1, (a1)
+ la rIBASE, .LdvmAsmInstructionStart # PIC way of getting &func
+ lw rIBASE, (rIBASE)
+ move rPC, a0 # reload the faulting Dalvid address
+ jr a1 # branch to dvmMterpCommonExeceptionThrown
+
+ .align 4
+.LdvmAsmInstructionStart:
+ .word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
+.LdvmJitToInterpTraceSelectNoChain:
+ .word dvmJitToInterpTraceSelectNoChain
+.LdvmJitToInterpNoChain:
+ .word dvmJitToInterpNoChain
+.LdvmMterpStdBail:
+ .word dvmMterpStdBail
+.LdvmMterpCommonExceptionThrown:
+ .word dvmMterpCommonExceptionThrown
+.LdvmLockObject:
+ .word dvmLockObject
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+ .word gDvmICHitCount
+#endif
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+ .word dvmSelfVerificationMemOpDecode
+#endif
+
+ .global dmvCompilerTemplateEnd
+dmvCompilerTemplateEnd:
+
+#endif /* WITH_JIT */
diff --git a/vm/compiler/template/mips/funop.S b/vm/compiler/template/mips/funop.S
new file mode 100644
index 0000000..0a984d7
--- /dev/null
+++ b/vm/compiler/template/mips/funop.S
@@ -0,0 +1,30 @@
+%default {"preinstr":""}
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: int-to-float, float-to-int
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = src dalvik register address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ *
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vBB
+ $preinstr # optional op
+ $instr # v0<- op, a0-a3 changed
+.L${opcode}_set_vreg:
+ STORE(v0, rOBJ) # vAA<- v0
+#else
+ LOAD_F(fa0, a1) # fa0<- vBB
+ $preinstr # optional op
+ $instr_f # fv0 = result
+.L${opcode}_set_vreg_f:
+ STORE_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ RETURN
diff --git a/vm/compiler/template/mips/funopNarrower.S b/vm/compiler/template/mips/funopNarrower.S
new file mode 100644
index 0000000..7fbaf7b
--- /dev/null
+++ b/vm/compiler/template/mips/funopNarrower.S
@@ -0,0 +1,33 @@
+%default {"preinstr":"", "load":"LOAD64_F(fa0, fa0f, a1)"}
+ /*
+ * Generic 64bit-to-32bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0/a1", where
+ * "result" is a 32-bit quantity in a0.
+ *
+ * For: long-to-float, double-to-int, double-to-float
+ * If hard floating point support is available, use fa0 as the parameter, except for
+ * long-to-float opcode.
+ * (This would work for long-to-int, but that instruction is actually
+ * an exact match for OP_MOVE.)
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = src dalvik register address
+ *
+ */
+ move rINST, a0 # save a0
+#ifdef SOFT_FLOAT
+ move t0, a1 # save a1
+ LOAD64(rARG0, rARG1, t0) # a0/a1<- vB/vB+1
+ $preinstr # optional op
+ $instr # v0<- op, a0-a3 changed
+.L${opcode}_set_vreg:
+ STORE(v0, rINST) # vA<- v0
+#else
+ $load
+ $preinstr # optional op
+ $instr_f # fv0 = result
+.L${opcode}_set_vreg_f:
+ STORE_F(fv0, rINST) # vA<- fv0
+#endif
+ RETURN
diff --git a/vm/compiler/template/mips/funopWider.S b/vm/compiler/template/mips/funopWider.S
new file mode 100644
index 0000000..887e171
--- /dev/null
+++ b/vm/compiler/template/mips/funopWider.S
@@ -0,0 +1,29 @@
+%default {"preinstr":"", "st_result":"STORE64_F(fv0, fv0f, rOBJ)"}
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vB
+ $preinstr # optional op
+ $instr # result<- op, a0-a3 changed
+
+.L${opcode}_set_vreg:
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vA/vA+1<- v0/v1
+#else
+ LOAD_F(fa0, a1) # fa0<- vB
+ $preinstr # optional op
+ $instr_f
+
+.L${opcode}_set_vreg:
+ $st_result # vA/vA+1<- fv0/fv0f
+#endif
+ RETURN
diff --git a/vm/compiler/template/mips/header.S b/vm/compiler/template/mips/header.S
new file mode 100644
index 0000000..de4a051
--- /dev/null
+++ b/vm/compiler/template/mips/header.S
@@ -0,0 +1,406 @@
+/*
+ * 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.
+ */
+
+#if defined(WITH_JIT)
+
+/*
+ * This is a #include, not a %include, because we want the C pre-processor
+ * to expand the macros into assembler assignment statements.
+ */
+#include "../../../mterp/common/asm-constants.h"
+#include "../../../mterp/common/mips-defines.h"
+#include "../../../mterp/common/jit-config.h"
+#include <asm/regdef.h>
+#include <asm/fpregdef.h>
+
+#ifdef __mips_hard_float
+#define HARD_FLOAT
+#else
+#define SOFT_FLOAT
+#endif
+
+/* MIPS definitions and declarations
+
+ reg nick purpose
+ s0 rPC interpreted program counter, used for fetching instructions
+ s1 rFP interpreted frame pointer, used for accessing locals and args
+ s2 rSELF pointer to thread
+ s3 rIBASE interpreted instruction base pointer, used for computed goto
+ s4 rINST first 16-bit code unit of current instruction
+*/
+
+/* register offsets */
+#define r_ZERO 0
+#define r_AT 1
+#define r_V0 2
+#define r_V1 3
+#define r_A0 4
+#define r_A1 5
+#define r_A2 6
+#define r_A3 7
+#define r_T0 8
+#define r_T1 9
+#define r_T2 10
+#define r_T3 11
+#define r_T4 12
+#define r_T5 13
+#define r_T6 14
+#define r_T7 15
+#define r_S0 16
+#define r_S1 17
+#define r_S2 18
+#define r_S3 19
+#define r_S4 20
+#define r_S5 21
+#define r_S6 22
+#define r_S7 23
+#define r_T8 24
+#define r_T9 25
+#define r_K0 26
+#define r_K1 27
+#define r_GP 28
+#define r_SP 29
+#define r_FP 30
+#define r_RA 31
+#define r_F0 32
+#define r_F1 33
+#define r_F2 34
+#define r_F3 35
+#define r_F4 36
+#define r_F5 37
+#define r_F6 38
+#define r_F7 39
+#define r_F8 40
+#define r_F9 41
+#define r_F10 42
+#define r_F11 43
+#define r_F12 44
+#define r_F13 45
+#define r_F14 46
+#define r_F15 47
+#define r_F16 48
+#define r_F17 49
+#define r_F18 50
+#define r_F19 51
+#define r_F20 52
+#define r_F21 53
+#define r_F22 54
+#define r_F23 55
+#define r_F24 56
+#define r_F25 57
+#define r_F26 58
+#define r_F27 59
+#define r_F28 60
+#define r_F29 61
+#define r_F30 62
+#define r_F31 63
+
+/* single-purpose registers, given names for clarity */
+#define rPC s0
+#define rFP s1
+#define rSELF s2
+#define rIBASE s3
+#define rINST s4
+#define rOBJ s5
+#define rBIX s6
+#define rTEMP s7
+
+/* The long arguments sent to function calls in Big-endian mode should be register
+swapped when sent to functions in little endian mode. In other words long variable
+sent as a0(MSW), a1(LSW) for a function call in LE mode should be sent as a1, a0 in
+Big Endian mode */
+
+#ifdef HAVE_LITTLE_ENDIAN
+#define rARG0 a0
+#define rARG1 a1
+#define rARG2 a2
+#define rARG3 a3
+#define rRESULT0 v0
+#define rRESULT1 v1
+#else
+#define rARG0 a1
+#define rARG1 a0
+#define rARG2 a3
+#define rARG3 a2
+#define rRESULT0 v1
+#define rRESULT1 v0
+#endif
+
+
+/* save/restore the PC and/or FP from the thread struct */
+#define LOAD_PC_FROM_SELF() lw rPC, offThread_pc(rSELF)
+#define SAVE_PC_TO_SELF() sw rPC, offThread_pc(rSELF)
+#define LOAD_FP_FROM_SELF() lw rFP, offThread_curFrame(rSELF)
+#define SAVE_FP_TO_SELF() sw rFP, offThread_curFrame(rSELF)
+
+#define EXPORT_PC() \
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+
+#define SAVEAREA_FROM_FP(rd, _fpreg) \
+ subu rd, _fpreg, sizeofStackSaveArea
+
+#define FETCH_INST() lhu rINST, (rPC)
+
+#define FETCH_ADVANCE_INST(_count) lhu rINST, (_count*2)(rPC); \
+ addu rPC, rPC, (_count * 2)
+
+#define FETCH_ADVANCE_INST_RB(rd) addu rPC, rPC, rd; \
+ lhu rINST, (rPC)
+
+#define FETCH(rd, _count) lhu rd, (_count * 2)(rPC)
+#define FETCH_S(rd, _count) lh rd, (_count * 2)(rPC)
+
+#ifdef HAVE_LITTLE_ENDIAN
+
+#define FETCH_B(rd, _count) lbu rd, (_count * 2)(rPC)
+#define FETCH_C(rd, _count) lbu rd, (_count * 2 + 1)(rPC)
+
+#else
+
+#define FETCH_B(rd, _count) lbu rd, (_count * 2 + 1)(rPC)
+#define FETCH_C(rd, _count) lbu rd, (_count * 2)(rPC)
+
+#endif
+
+#define GET_INST_OPCODE(rd) and rd, rINST, 0xFF
+
+#define GOTO_OPCODE(rd) sll rd, rd, ${handler_size_bits}; \
+ addu rd, rIBASE, rd; \
+ jr rd
+
+
+#define LOAD(rd, rbase) lw rd, 0(rbase)
+#define LOAD_F(rd, rbase) l.s rd, (rbase)
+#define STORE(rd, rbase) sw rd, 0(rbase)
+#define STORE_F(rd, rbase) s.s rd, (rbase)
+
+#define GET_VREG(rd, rix) LOAD_eas2(rd,rFP,rix)
+
+#define GET_VREG_F(rd, rix) EAS2(AT, rFP, rix); \
+ .set noat; l.s rd, (AT); .set at
+
+#define SET_VREG(rd, rix) STORE_eas2(rd, rFP, rix)
+
+#define SET_VREG_GOTO(rd, rix, dst) .set noreorder; \
+ sll dst, dst, ${handler_size_bits}; \
+ addu dst, rIBASE, dst; \
+ sll t8, rix, 2; \
+ addu t8, t8, rFP; \
+ jr dst; \
+ sw rd, 0(t8); \
+ .set reorder
+
+#define SET_VREG_F(rd, rix) EAS2(AT, rFP, rix); \
+ .set noat; s.s rd, (AT); .set at
+
+
+#define GET_OPA(rd) srl rd, rINST, 8
+#ifndef MIPS32R2
+#define GET_OPA4(rd) GET_OPA(rd); and rd, 0xf
+#else
+#define GET_OPA4(rd) ext rd, rd, 8, 4
+#endif
+#define GET_OPB(rd) srl rd, rINST, 12
+
+#define LOAD_rSELF_OFF(rd,off) lw rd, offThread_##off##(rSELF)
+
+#define LOAD_rSELF_method(rd) LOAD_rSELF_OFF(rd, method)
+#define LOAD_rSELF_methodClassDex(rd) LOAD_rSELF_OFF(rd, methodClassDex)
+#define LOAD_rSELF_interpStackEnd(rd) LOAD_rSELF_OFF(rd, interpStackEnd)
+#define LOAD_rSELF_retval(rd) LOAD_rSELF_OFF(rd, retval)
+#define LOAD_rSELF_pActiveProfilers(rd) LOAD_rSELF_OFF(rd, pActiveProfilers)
+#define LOAD_rSELF_bailPtr(rd) LOAD_rSELF_OFF(rd, bailPtr)
+
+#define GET_JIT_PROF_TABLE(rd) LOAD_rSELF_OFF(rd,pJitProfTable)
+#define GET_JIT_THRESHOLD(rd) LOAD_rSELF_OFF(rd,jitThreshold)
+
+/*
+ * Form an Effective Address rd = rbase + roff<<n;
+ * Uses reg AT
+ */
+#define EASN(rd,rbase,roff,rshift) .set noat; \
+ sll AT, roff, rshift; \
+ addu rd, rbase, AT; \
+ .set at
+
+#define EAS1(rd,rbase,roff) EASN(rd,rbase,roff,1)
+#define EAS2(rd,rbase,roff) EASN(rd,rbase,roff,2)
+#define EAS3(rd,rbase,roff) EASN(rd,rbase,roff,3)
+#define EAS4(rd,rbase,roff) EASN(rd,rbase,roff,4)
+
+/*
+ * Form an Effective Shift Right rd = rbase + roff>>n;
+ * Uses reg AT
+ */
+#define ESRN(rd,rbase,roff,rshift) .set noat; \
+ srl AT, roff, rshift; \
+ addu rd, rbase, AT; \
+ .set at
+
+#define LOAD_eas2(rd,rbase,roff) EAS2(AT, rbase, roff); \
+ .set noat; lw rd, 0(AT); .set at
+
+#define STORE_eas2(rd,rbase,roff) EAS2(AT, rbase, roff); \
+ .set noat; sw rd, 0(AT); .set at
+
+#define LOAD_RB_OFF(rd,rbase,off) lw rd, off(rbase)
+#define LOADu2_RB_OFF(rd,rbase,off) lhu rd, off(rbase)
+#define STORE_RB_OFF(rd,rbase,off) sw rd, off(rbase)
+
+#ifdef HAVE_LITTLE_ENDIAN
+
+#define STORE64_off(rlo,rhi,rbase,off) sw rlo, off(rbase); \
+ sw rhi, (off+4)(rbase)
+#define LOAD64_off(rlo,rhi,rbase,off) lw rlo, off(rbase); \
+ lw rhi, (off+4)(rbase)
+
+#define STORE64_off_F(rlo,rhi,rbase,off) s.s rlo, off(rbase); \
+ s.s rhi, (off+4)(rbase)
+#define LOAD64_off_F(rlo,rhi,rbase,off) l.s rlo, off(rbase); \
+ l.s rhi, (off+4)(rbase)
+#else
+
+#define STORE64_off(rlo,rhi,rbase,off) sw rlo, (off+4)(rbase); \
+ sw rhi, (off)(rbase)
+#define LOAD64_off(rlo,rhi,rbase,off) lw rlo, (off+4)(rbase); \
+ lw rhi, (off)(rbase)
+#define STORE64_off_F(rlo,rhi,rbase,off) s.s rlo, (off+4)(rbase); \
+ s.s rhi, (off)(rbase)
+#define LOAD64_off_F(rlo,rhi,rbase,off) l.s rlo, (off+4)(rbase); \
+ l.s rhi, (off)(rbase)
+#endif
+
+#define STORE64(rlo,rhi,rbase) STORE64_off(rlo,rhi,rbase,0)
+#define LOAD64(rlo,rhi,rbase) LOAD64_off(rlo,rhi,rbase,0)
+
+#define STORE64_F(rlo,rhi,rbase) STORE64_off_F(rlo,rhi,rbase,0)
+#define LOAD64_F(rlo,rhi,rbase) LOAD64_off_F(rlo,rhi,rbase,0)
+
+#define STORE64_lo(rd,rbase) sw rd, 0(rbase)
+#define STORE64_hi(rd,rbase) sw rd, 4(rbase)
+
+
+#define LOAD_offThread_exception(rd,rbase) LOAD_RB_OFF(rd,rbase,offThread_exception)
+#define LOAD_base_offArrayObject_length(rd,rbase) LOAD_RB_OFF(rd,rbase,offArrayObject_length)
+#define LOAD_base_offClassObject_accessFlags(rd,rbase) LOAD_RB_OFF(rd,rbase,offClassObject_accessFlags)
+#define LOAD_base_offClassObject_descriptor(rd,rbase) LOAD_RB_OFF(rd,rbase,offClassObject_descriptor)
+#define LOAD_base_offClassObject_super(rd,rbase) LOAD_RB_OFF(rd,rbase,offClassObject_super)
+
+#define LOAD_base_offClassObject_vtable(rd,rbase) LOAD_RB_OFF(rd,rbase,offClassObject_vtable)
+#define LOAD_base_offClassObject_vtableCount(rd,rbase) LOAD_RB_OFF(rd,rbase,offClassObject_vtableCount)
+#define LOAD_base_offDvmDex_pResClasses(rd,rbase) LOAD_RB_OFF(rd,rbase,offDvmDex_pResClasses)
+#define LOAD_base_offDvmDex_pResFields(rd,rbase) LOAD_RB_OFF(rd,rbase,offDvmDex_pResFields)
+
+#define LOAD_base_offDvmDex_pResMethods(rd,rbase) LOAD_RB_OFF(rd,rbase,offDvmDex_pResMethods)
+#define LOAD_base_offDvmDex_pResStrings(rd,rbase) LOAD_RB_OFF(rd,rbase,offDvmDex_pResStrings)
+#define LOAD_base_offInstField_byteOffset(rd,rbase) LOAD_RB_OFF(rd,rbase,offInstField_byteOffset)
+#define LOAD_base_offStaticField_value(rd,rbase) LOAD_RB_OFF(rd,rbase,offStaticField_value)
+#define LOAD_base_offMethod_clazz(rd,rbase) LOAD_RB_OFF(rd,rbase,offMethod_clazz)
+
+#define LOAD_base_offMethod_name(rd,rbase) LOAD_RB_OFF(rd,rbase,offMethod_name)
+#define LOAD_base_offObject_clazz(rd,rbase) LOAD_RB_OFF(rd,rbase,offObject_clazz)
+
+#define LOADu2_offMethod_methodIndex(rd,rbase) LOADu2_RB_OFF(rd,rbase,offMethod_methodIndex)
+
+
+#define STORE_offThread_exception(rd,rbase) STORE_RB_OFF(rd,rbase,offThread_exception)
+
+
+#define STACK_STORE(rd,off) sw rd, off(sp)
+#define STACK_LOAD(rd,off) lw rd, off(sp)
+#define CREATE_STACK(n) subu sp, sp, n
+#define DELETE_STACK(n) addu sp, sp, n
+
+#define SAVE_RA(offset) STACK_STORE(ra, offset)
+#define LOAD_RA(offset) STACK_LOAD(ra, offset)
+
+#define LOAD_ADDR(dest,addr) la dest, addr
+#define LOAD_IMM(dest, imm) li dest, imm
+#define MOVE_REG(dest,src) move dest, src
+#define RETURN jr ra
+#define STACK_SIZE 128
+
+#define STACK_OFFSET_ARG04 16
+#define STACK_OFFSET_GP 84
+#define STACK_OFFSET_rFP 112
+
+/* This directive will make sure all subsequent jal restore gp at a known offset */
+ .cprestore STACK_OFFSET_GP
+
+#define JAL(func) move rTEMP, ra; \
+ jal func; \
+ move ra, rTEMP
+
+#define JALR(reg) move rTEMP, ra; \
+ jalr ra, reg; \
+ move ra, rTEMP
+
+#define BAL(n) bal n
+
+#define STACK_STORE_RA() CREATE_STACK(STACK_SIZE); \
+ STACK_STORE(gp, STACK_OFFSET_GP); \
+ STACK_STORE(ra, 124)
+
+#define STACK_STORE_S0() STACK_STORE_RA(); \
+ STACK_STORE(s0, 116)
+
+#define STACK_STORE_S0S1() STACK_STORE_S0(); \
+ STACK_STORE(s1, STACK_OFFSET_rFP)
+
+#define STACK_LOAD_RA() STACK_LOAD(ra, 124); \
+ STACK_LOAD(gp, STACK_OFFSET_GP); \
+ DELETE_STACK(STACK_SIZE)
+
+#define STACK_LOAD_S0() STACK_LOAD(s0, 116); \
+ STACK_LOAD_RA()
+
+#define STACK_LOAD_S0S1() STACK_LOAD(s1, STACK_OFFSET_rFP); \
+ STACK_LOAD_S0()
+
+#define STACK_STORE_FULL() CREATE_STACK(STACK_SIZE); \
+ STACK_STORE(ra, 124); \
+ STACK_STORE(fp, 120); \
+ STACK_STORE(s0, 116); \
+ STACK_STORE(s1, STACK_OFFSET_rFP); \
+ STACK_STORE(s2, 108); \
+ STACK_STORE(s3, 104); \
+ STACK_STORE(s4, 100); \
+ STACK_STORE(s5, 96); \
+ STACK_STORE(s6, 92); \
+ STACK_STORE(s7, 88);
+
+#define STACK_LOAD_FULL() STACK_LOAD(gp, STACK_OFFSET_GP); \
+ STACK_LOAD(s7, 88); \
+ STACK_LOAD(s6, 92); \
+ STACK_LOAD(s5, 96); \
+ STACK_LOAD(s4, 100); \
+ STACK_LOAD(s3, 104); \
+ STACK_LOAD(s2, 108); \
+ STACK_LOAD(s1, STACK_OFFSET_rFP); \
+ STACK_LOAD(s0, 116); \
+ STACK_LOAD(fp, 120); \
+ STACK_LOAD(ra, 124); \
+ DELETE_STACK(STACK_SIZE)
+
+/*
+ * first 8 words are reserved for function calls
+ * Maximum offset is STACK_OFFSET_SCRMX-STACK_OFFSET_SCR
+ */
+#define STACK_OFFSET_SCR 32
+#define SCRATCH_STORE(r,off) \
+ STACK_STORE(r, STACK_OFFSET_SCR+off);
+#define SCRATCH_LOAD(r,off) \
+ STACK_LOAD(r, STACK_OFFSET_SCR+off);
diff --git a/vm/compiler/template/mips/platform.S b/vm/compiler/template/mips/platform.S
new file mode 100644
index 0000000..8b0d23e
--- /dev/null
+++ b/vm/compiler/template/mips/platform.S
@@ -0,0 +1,6 @@
+/*
+ * ===========================================================================
+ * CPU-version-specific defines and utility
+ * ===========================================================================
+ */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
index 331d902..27319e7 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
@@ -111,7 +111,7 @@
.global dvmCompilerTemplateStart
.type dvmCompilerTemplateStart, %function
- .text
+ .section .data.rel.ro
dvmCompilerTemplateStart:
@@ -170,8 +170,8 @@
stmfd sp!, {r0-r2,lr} @ preserve live registers
mov r0, r6
@ r0=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceExit
+ ldr ip, .LdvmFastMethodTraceExit
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore live registers
#endif
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
@@ -272,8 +272,8 @@
stmfd sp!, {r0-r3} @ preserve r0-r3
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -281,7 +281,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
- mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
+ bx r10 @ dvmJitToInterpTraceSelectNoChain
/* ------------------------------ */
.balign 4
@@ -330,8 +330,8 @@
stmfd sp!, {r0-r2,lr} @ preserve clobbered live registers
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore registers
#endif
@@ -453,8 +453,8 @@
mov r0, r2
mov r1, r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -463,8 +463,8 @@
#if defined(TEMPLATE_INLINE_PROFILING)
ldmfd sp!, {r0-r1} @ restore r2 and r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
#endif
@ native return; r10=newSaveArea
@ equivalent to dvmPopJniLocals
@@ -1508,8 +1508,8 @@
stmfd sp!, {r0-r2,lr} @ preserve live registers
mov r0, r6
@ r0=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceExit
+ ldr ip, .LdvmFastMethodTraceExit
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore live registers
#endif
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
@@ -1614,8 +1614,8 @@
stmfd sp!, {r0-r3} @ preserve r0-r3
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -1623,7 +1623,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
- mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
+ bx r10 @ dvmJitToInterpTraceSelectNoChain
#undef TEMPLATE_INLINE_PROFILING
@@ -1676,8 +1676,8 @@
stmfd sp!, {r0-r2,lr} @ preserve clobbered live registers
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore registers
#endif
@@ -1807,8 +1807,8 @@
mov r0, r2
mov r1, r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -1817,8 +1817,8 @@
#if defined(TEMPLATE_INLINE_PROFILING)
ldmfd sp!, {r0-r1} @ restore r2 and r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
#endif
@ native return; r10=newSaveArea
@ equivalent to dvmPopJniLocals
@@ -1855,7 +1855,7 @@
* ===========================================================================
*/
- .text
+ .section .data.rel.ro
.align 2
.LinvokeNative:
@ Prep for the native call
@@ -1880,20 +1880,20 @@
stmfd sp!, {r0-r3}
mov r0, r2
mov r1, r6
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3}
- mov lr, pc
- ldr pc, [r2, #offMethod_nativeFunc]
+ ldr ip, [r2, #offMethod_nativeFunc]
+ blx ip
ldmfd sp!, {r0-r1}
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
b 212f
121:
- mov lr, pc
- ldr pc, [r2, #offMethod_nativeFunc]
+ ldr ip, [r2, #offMethod_nativeFunc]
+ blx ip
212:
@ native return; r10=newSaveArea
@@ -1919,7 +1919,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
- mov pc, r1
+ bx r1
/*
* On entry:
@@ -1936,7 +1936,7 @@
ldr r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
ldr rIBASE, .LdvmAsmInstructionStart @ same as above
mov rPC, r0 @ reload the faulting Dalvik address
- mov pc, r1 @ branch to dvmMterpCommonExceptionThrown
+ bx r1 @ branch to dvmMterpCommonExceptionThrown
.align 2
.LdvmAsmInstructionStart:
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
index 044843e..68f6441 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
@@ -111,7 +111,7 @@
.global dvmCompilerTemplateStart
.type dvmCompilerTemplateStart, %function
- .text
+ .section .data.rel.ro
dvmCompilerTemplateStart:
@@ -170,8 +170,8 @@
stmfd sp!, {r0-r2,lr} @ preserve live registers
mov r0, r6
@ r0=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceExit
+ ldr ip, .LdvmFastMethodTraceExit
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore live registers
#endif
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
@@ -272,8 +272,8 @@
stmfd sp!, {r0-r3} @ preserve r0-r3
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -281,7 +281,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
- mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
+ bx r10 @ dvmJitToInterpTraceSelectNoChain
/* ------------------------------ */
.balign 4
@@ -330,8 +330,8 @@
stmfd sp!, {r0-r2,lr} @ preserve clobbered live registers
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore registers
#endif
@@ -453,8 +453,8 @@
mov r0, r2
mov r1, r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -463,8 +463,8 @@
#if defined(TEMPLATE_INLINE_PROFILING)
ldmfd sp!, {r0-r1} @ restore r2 and r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
#endif
@ native return; r10=newSaveArea
@ equivalent to dvmPopJniLocals
@@ -514,8 +514,8 @@
/* op vAA, vBB, vCC */
push {r0-r3} @ save operands
mov r11, lr @ save return address
- mov lr, pc
- ldr pc, .L__aeabi_cdcmple @ PIC way of "bl __aeabi_cdcmple"
+ ldr ip, .L__aeabi_cdcmple @ PIC way of "bl __aeabi_cdcmple"
+ blx ip
bhi .LTEMPLATE_CMPG_DOUBLE_gt_or_nan @ C set and Z clear, disambiguate
mvncc r0, #0 @ (less than) r1<- -1
moveq r0, #0 @ (equal) r1<- 0, trumps less than
@@ -528,8 +528,8 @@
.LTEMPLATE_CMPG_DOUBLE_gt_or_nan:
pop {r2-r3} @ restore operands in reverse order
pop {r0-r1} @ restore operands in reverse order
- mov lr, pc
- ldr pc, .L__aeabi_cdcmple @ r0<- Z set if eq, C clear if <
+ ldr ip, .L__aeabi_cdcmple @ r0<- Z set if eq, C clear if <
+ blx ip
movcc r0, #1 @ (greater than) r1<- 1
bxcc r11
mov r0, #1 @ r1<- 1 or -1 for NaN
@@ -558,8 +558,8 @@
/* op vAA, vBB, vCC */
push {r0-r3} @ save operands
mov r11, lr @ save return address
- mov lr, pc
- ldr pc, .L__aeabi_cdcmple @ PIC way of "bl __aeabi_cdcmple"
+ ldr ip, .L__aeabi_cdcmple @ PIC way of "bl __aeabi_cdcmple"
+ blx ip
bhi .LTEMPLATE_CMPL_DOUBLE_gt_or_nan @ C set and Z clear, disambiguate
mvncc r0, #0 @ (less than) r1<- -1
moveq r0, #0 @ (equal) r1<- 0, trumps less than
@@ -572,8 +572,8 @@
.LTEMPLATE_CMPL_DOUBLE_gt_or_nan:
pop {r2-r3} @ restore operands in reverse order
pop {r0-r1} @ restore operands in reverse order
- mov lr, pc
- ldr pc, .L__aeabi_cdcmple @ r0<- Z set if eq, C clear if <
+ ldr ip, .L__aeabi_cdcmple @ r0<- Z set if eq, C clear if <
+ blx ip
movcc r0, #1 @ (greater than) r1<- 1
bxcc r11
mvn r0, #0 @ r1<- 1 or -1 for NaN
@@ -622,8 +622,8 @@
mov r9, r0 @ Save copies - we may need to redo
mov r10, r1
mov r11, lr @ save return address
- mov lr, pc
- ldr pc, .L__aeabi_cfcmple @ cmp <=: C clear if <, Z set if eq
+ ldr ip, .L__aeabi_cfcmple @ cmp <=: C clear if <, Z set if eq
+ blx ip
bhi .LTEMPLATE_CMPG_FLOAT_gt_or_nan @ C set and Z clear, disambiguate
mvncc r0, #0 @ (less than) r0<- -1
moveq r0, #0 @ (equal) r0<- 0, trumps less than
@@ -634,8 +634,8 @@
.LTEMPLATE_CMPG_FLOAT_gt_or_nan:
mov r0, r10 @ restore in reverse order
mov r1, r9
- mov lr, pc
- ldr pc, .L__aeabi_cfcmple @ r0<- Z set if eq, C clear if <
+ ldr ip, .L__aeabi_cfcmple @ r0<- Z set if eq, C clear if <
+ blx ip
movcc r0, #1 @ (greater than) r1<- 1
bxcc r11
mov r0, #1 @ r1<- 1 or -1 for NaN
@@ -684,8 +684,8 @@
mov r9, r0 @ Save copies - we may need to redo
mov r10, r1
mov r11, lr @ save return address
- mov lr, pc
- ldr pc, .L__aeabi_cfcmple @ cmp <=: C clear if <, Z set if eq
+ ldr ip, .L__aeabi_cfcmple @ cmp <=: C clear if <, Z set if eq
+ blx ip
bhi .LTEMPLATE_CMPL_FLOAT_gt_or_nan @ C set and Z clear, disambiguate
mvncc r0, #0 @ (less than) r0<- -1
moveq r0, #0 @ (equal) r0<- 0, trumps less than
@@ -696,8 +696,8 @@
.LTEMPLATE_CMPL_FLOAT_gt_or_nan:
mov r0, r10 @ restore in reverse order
mov r1, r9
- mov lr, pc
- ldr pc, .L__aeabi_cfcmple @ r0<- Z set if eq, C clear if <
+ ldr ip, .L__aeabi_cfcmple @ r0<- Z set if eq, C clear if <
+ blx ip
movcc r0, #1 @ (greater than) r1<- 1
bxcc r11
mvn r0, #0 @ r1<- 1 or -1 for NaN
@@ -1239,8 +1239,8 @@
stmfd sp!, {r0-r2,lr} @ preserve live registers
mov r0, r6
@ r0=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceExit
+ ldr ip, .LdvmFastMethodTraceExit
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore live registers
#endif
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
@@ -1345,8 +1345,8 @@
stmfd sp!, {r0-r3} @ preserve r0-r3
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -1354,7 +1354,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
- mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
+ bx r10 @ dvmJitToInterpTraceSelectNoChain
#undef TEMPLATE_INLINE_PROFILING
@@ -1407,8 +1407,8 @@
stmfd sp!, {r0-r2,lr} @ preserve clobbered live registers
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore registers
#endif
@@ -1538,8 +1538,8 @@
mov r0, r2
mov r1, r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -1548,8 +1548,8 @@
#if defined(TEMPLATE_INLINE_PROFILING)
ldmfd sp!, {r0-r1} @ restore r2 and r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
#endif
@ native return; r10=newSaveArea
@ equivalent to dvmPopJniLocals
@@ -1586,7 +1586,7 @@
* ===========================================================================
*/
- .text
+ .section .data.rel.ro
.align 2
.LinvokeNative:
@ Prep for the native call
@@ -1611,20 +1611,20 @@
stmfd sp!, {r0-r3}
mov r0, r2
mov r1, r6
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3}
- mov lr, pc
- ldr pc, [r2, #offMethod_nativeFunc]
+ ldr ip, [r2, #offMethod_nativeFunc]
+ blx ip
ldmfd sp!, {r0-r1}
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
b 212f
121:
- mov lr, pc
- ldr pc, [r2, #offMethod_nativeFunc]
+ ldr ip, [r2, #offMethod_nativeFunc]
+ blx ip
212:
@ native return; r10=newSaveArea
@@ -1650,7 +1650,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
- mov pc, r1
+ bx r1
/*
* On entry:
@@ -1667,7 +1667,7 @@
ldr r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
ldr rIBASE, .LdvmAsmInstructionStart @ same as above
mov rPC, r0 @ reload the faulting Dalvik address
- mov pc, r1 @ branch to dvmMterpCommonExceptionThrown
+ bx r1 @ branch to dvmMterpCommonExceptionThrown
.align 2
.LdvmAsmInstructionStart:
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
index ba798e0..7573bd8 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
@@ -111,7 +111,7 @@
.global dvmCompilerTemplateStart
.type dvmCompilerTemplateStart, %function
- .text
+ .section .data.rel.ro
dvmCompilerTemplateStart:
@@ -170,8 +170,8 @@
stmfd sp!, {r0-r2,lr} @ preserve live registers
mov r0, r6
@ r0=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceExit
+ ldr ip, .LdvmFastMethodTraceExit
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore live registers
#endif
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
@@ -272,8 +272,8 @@
stmfd sp!, {r0-r3} @ preserve r0-r3
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -281,7 +281,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
- mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
+ bx r10 @ dvmJitToInterpTraceSelectNoChain
/* ------------------------------ */
.balign 4
@@ -330,8 +330,8 @@
stmfd sp!, {r0-r2,lr} @ preserve clobbered live registers
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore registers
#endif
@@ -453,8 +453,8 @@
mov r0, r2
mov r1, r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -463,8 +463,8 @@
#if defined(TEMPLATE_INLINE_PROFILING)
ldmfd sp!, {r0-r1} @ restore r2 and r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
#endif
@ native return; r10=newSaveArea
@ equivalent to dvmPopJniLocals
@@ -1508,8 +1508,8 @@
stmfd sp!, {r0-r2,lr} @ preserve live registers
mov r0, r6
@ r0=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceExit
+ ldr ip, .LdvmFastMethodTraceExit
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore live registers
#endif
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
@@ -1614,8 +1614,8 @@
stmfd sp!, {r0-r3} @ preserve r0-r3
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -1623,7 +1623,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
- mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
+ bx r10 @ dvmJitToInterpTraceSelectNoChain
#undef TEMPLATE_INLINE_PROFILING
@@ -1676,8 +1676,8 @@
stmfd sp!, {r0-r2,lr} @ preserve clobbered live registers
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore registers
#endif
@@ -1807,8 +1807,8 @@
mov r0, r2
mov r1, r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -1817,8 +1817,8 @@
#if defined(TEMPLATE_INLINE_PROFILING)
ldmfd sp!, {r0-r1} @ restore r2 and r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
#endif
@ native return; r10=newSaveArea
@ equivalent to dvmPopJniLocals
@@ -1855,7 +1855,7 @@
* ===========================================================================
*/
- .text
+ .section .data.rel.ro
.align 2
.LinvokeNative:
@ Prep for the native call
@@ -1880,20 +1880,20 @@
stmfd sp!, {r0-r3}
mov r0, r2
mov r1, r6
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3}
- mov lr, pc
- ldr pc, [r2, #offMethod_nativeFunc]
+ ldr ip, [r2, #offMethod_nativeFunc]
+ blx ip
ldmfd sp!, {r0-r1}
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
b 212f
121:
- mov lr, pc
- ldr pc, [r2, #offMethod_nativeFunc]
+ ldr ip, [r2, #offMethod_nativeFunc]
+ blx ip
212:
@ native return; r10=newSaveArea
@@ -1919,7 +1919,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
- mov pc, r1
+ bx r1
/*
* On entry:
@@ -1936,7 +1936,7 @@
ldr r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
ldr rIBASE, .LdvmAsmInstructionStart @ same as above
mov rPC, r0 @ reload the faulting Dalvik address
- mov pc, r1 @ branch to dvmMterpCommonExceptionThrown
+ bx r1 @ branch to dvmMterpCommonExceptionThrown
.align 2
.LdvmAsmInstructionStart:
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
index 825ac40..fd21a0e 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
@@ -111,7 +111,7 @@
.global dvmCompilerTemplateStart
.type dvmCompilerTemplateStart, %function
- .text
+ .section .data.rel.ro
dvmCompilerTemplateStart:
@@ -170,8 +170,8 @@
stmfd sp!, {r0-r2,lr} @ preserve live registers
mov r0, r6
@ r0=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceExit
+ ldr ip, .LdvmFastMethodTraceExit
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore live registers
#endif
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
@@ -272,8 +272,8 @@
stmfd sp!, {r0-r3} @ preserve r0-r3
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -281,7 +281,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
- mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
+ bx r10 @ dvmJitToInterpTraceSelectNoChain
/* ------------------------------ */
.balign 4
@@ -330,8 +330,8 @@
stmfd sp!, {r0-r2,lr} @ preserve clobbered live registers
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore registers
#endif
@@ -453,8 +453,8 @@
mov r0, r2
mov r1, r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -463,8 +463,8 @@
#if defined(TEMPLATE_INLINE_PROFILING)
ldmfd sp!, {r0-r1} @ restore r2 and r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
#endif
@ native return; r10=newSaveArea
@ equivalent to dvmPopJniLocals
@@ -1508,8 +1508,8 @@
stmfd sp!, {r0-r2,lr} @ preserve live registers
mov r0, r6
@ r0=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceExit
+ ldr ip, .LdvmFastMethodTraceExit
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore live registers
#endif
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
@@ -1614,8 +1614,8 @@
stmfd sp!, {r0-r3} @ preserve r0-r3
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -1623,7 +1623,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kInlineCacheMiss
#endif
- mov pc, r10 @ dvmJitToInterpTraceSelectNoChain
+ bx r10 @ dvmJitToInterpTraceSelectNoChain
#undef TEMPLATE_INLINE_PROFILING
@@ -1676,8 +1676,8 @@
stmfd sp!, {r0-r2,lr} @ preserve clobbered live registers
mov r1, r6
@ r0=methodToCall, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r2,lr} @ restore registers
#endif
@@ -1807,8 +1807,8 @@
mov r0, r2
mov r1, r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3} @ restore r0-r3
#endif
@@ -1817,8 +1817,8 @@
#if defined(TEMPLATE_INLINE_PROFILING)
ldmfd sp!, {r0-r1} @ restore r2 and r6
@ r0=JNIMethod, r1=rSELF
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
#endif
@ native return; r10=newSaveArea
@ equivalent to dvmPopJniLocals
@@ -1855,7 +1855,7 @@
* ===========================================================================
*/
- .text
+ .section .data.rel.ro
.align 2
.LinvokeNative:
@ Prep for the native call
@@ -1880,20 +1880,20 @@
stmfd sp!, {r0-r3}
mov r0, r2
mov r1, r6
- mov lr, pc
- ldr pc, .LdvmFastMethodTraceEnter
+ ldr ip, .LdvmFastMethodTraceEnter
+ blx ip
ldmfd sp!, {r0-r3}
- mov lr, pc
- ldr pc, [r2, #offMethod_nativeFunc]
+ ldr ip, [r2, #offMethod_nativeFunc]
+ blx ip
ldmfd sp!, {r0-r1}
- mov lr, pc
- ldr pc, .LdvmFastNativeMethodTraceExit
+ ldr ip, .LdvmFastNativeMethodTraceExit
+ blx ip
b 212f
121:
- mov lr, pc
- ldr pc, [r2, #offMethod_nativeFunc]
+ ldr ip, [r2, #offMethod_nativeFunc]
+ blx ip
212:
@ native return; r10=newSaveArea
@@ -1919,7 +1919,7 @@
#if defined(WITH_JIT_TUNING)
mov r0, #kCallsiteInterpreted
#endif
- mov pc, r1
+ bx r1
/*
* On entry:
@@ -1936,7 +1936,7 @@
ldr r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
ldr rIBASE, .LdvmAsmInstructionStart @ same as above
mov rPC, r0 @ reload the faulting Dalvik address
- mov pc, r1 @ branch to dvmMterpCommonExceptionThrown
+ bx r1 @ branch to dvmMterpCommonExceptionThrown
.align 2
.LdvmAsmInstructionStart:
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-ia32.S b/vm/compiler/template/out/CompilerTemplateAsm-ia32.S
index 4e86d09..eef9d65 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-ia32.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-ia32.S
@@ -47,7 +47,7 @@
.global dvmCompilerTemplateStart
.type dvmCompilerTemplateStart, %function
- .text
+ .section .data.rel.ro
dvmCompilerTemplateStart:
@@ -103,7 +103,7 @@
* ===========================================================================
*/
- .text
+ .section .data.rel.ro
.align 4
.global dmvCompilerTemplateEnd
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-mips.S b/vm/compiler/template/out/CompilerTemplateAsm-mips.S
new file mode 100644
index 0000000..401865d
--- /dev/null
+++ b/vm/compiler/template/out/CompilerTemplateAsm-mips.S
@@ -0,0 +1,3401 @@
+/*
+ * This file was generated automatically by gen-template.py for 'mips'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: mips/header.S */
+/*
+ * 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.
+ */
+
+#if defined(WITH_JIT)
+
+/*
+ * This is a #include, not a %include, because we want the C pre-processor
+ * to expand the macros into assembler assignment statements.
+ */
+#include "../../../mterp/common/asm-constants.h"
+#include "../../../mterp/common/mips-defines.h"
+#include "../../../mterp/common/jit-config.h"
+#include <asm/regdef.h>
+#include <asm/fpregdef.h>
+
+#ifdef __mips_hard_float
+#define HARD_FLOAT
+#else
+#define SOFT_FLOAT
+#endif
+
+/* MIPS definitions and declarations
+
+ reg nick purpose
+ s0 rPC interpreted program counter, used for fetching instructions
+ s1 rFP interpreted frame pointer, used for accessing locals and args
+ s2 rSELF pointer to thread
+ s3 rIBASE interpreted instruction base pointer, used for computed goto
+ s4 rINST first 16-bit code unit of current instruction
+*/
+
+/* register offsets */
+#define r_ZERO 0
+#define r_AT 1
+#define r_V0 2
+#define r_V1 3
+#define r_A0 4
+#define r_A1 5
+#define r_A2 6
+#define r_A3 7
+#define r_T0 8
+#define r_T1 9
+#define r_T2 10
+#define r_T3 11
+#define r_T4 12
+#define r_T5 13
+#define r_T6 14
+#define r_T7 15
+#define r_S0 16
+#define r_S1 17
+#define r_S2 18
+#define r_S3 19
+#define r_S4 20
+#define r_S5 21
+#define r_S6 22
+#define r_S7 23
+#define r_T8 24
+#define r_T9 25
+#define r_K0 26
+#define r_K1 27
+#define r_GP 28
+#define r_SP 29
+#define r_FP 30
+#define r_RA 31
+#define r_F0 32
+#define r_F1 33
+#define r_F2 34
+#define r_F3 35
+#define r_F4 36
+#define r_F5 37
+#define r_F6 38
+#define r_F7 39
+#define r_F8 40
+#define r_F9 41
+#define r_F10 42
+#define r_F11 43
+#define r_F12 44
+#define r_F13 45
+#define r_F14 46
+#define r_F15 47
+#define r_F16 48
+#define r_F17 49
+#define r_F18 50
+#define r_F19 51
+#define r_F20 52
+#define r_F21 53
+#define r_F22 54
+#define r_F23 55
+#define r_F24 56
+#define r_F25 57
+#define r_F26 58
+#define r_F27 59
+#define r_F28 60
+#define r_F29 61
+#define r_F30 62
+#define r_F31 63
+
+/* single-purpose registers, given names for clarity */
+#define rPC s0
+#define rFP s1
+#define rSELF s2
+#define rIBASE s3
+#define rINST s4
+#define rOBJ s5
+#define rBIX s6
+#define rTEMP s7
+
+/* The long arguments sent to function calls in Big-endian mode should be register
+swapped when sent to functions in little endian mode. In other words long variable
+sent as a0(MSW), a1(LSW) for a function call in LE mode should be sent as a1, a0 in
+Big Endian mode */
+
+#ifdef HAVE_LITTLE_ENDIAN
+#define rARG0 a0
+#define rARG1 a1
+#define rARG2 a2
+#define rARG3 a3
+#define rRESULT0 v0
+#define rRESULT1 v1
+#else
+#define rARG0 a1
+#define rARG1 a0
+#define rARG2 a3
+#define rARG3 a2
+#define rRESULT0 v1
+#define rRESULT1 v0
+#endif
+
+
+/* save/restore the PC and/or FP from the thread struct */
+#define LOAD_PC_FROM_SELF() lw rPC, offThread_pc(rSELF)
+#define SAVE_PC_TO_SELF() sw rPC, offThread_pc(rSELF)
+#define LOAD_FP_FROM_SELF() lw rFP, offThread_curFrame(rSELF)
+#define SAVE_FP_TO_SELF() sw rFP, offThread_curFrame(rSELF)
+
+#define EXPORT_PC() \
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+
+#define SAVEAREA_FROM_FP(rd, _fpreg) \
+ subu rd, _fpreg, sizeofStackSaveArea
+
+#define FETCH_INST() lhu rINST, (rPC)
+
+#define FETCH_ADVANCE_INST(_count) lhu rINST, (_count*2)(rPC); \
+ addu rPC, rPC, (_count * 2)
+
+#define FETCH_ADVANCE_INST_RB(rd) addu rPC, rPC, rd; \
+ lhu rINST, (rPC)
+
+#define FETCH(rd, _count) lhu rd, (_count * 2)(rPC)
+#define FETCH_S(rd, _count) lh rd, (_count * 2)(rPC)
+
+#ifdef HAVE_LITTLE_ENDIAN
+
+#define FETCH_B(rd, _count) lbu rd, (_count * 2)(rPC)
+#define FETCH_C(rd, _count) lbu rd, (_count * 2 + 1)(rPC)
+
+#else
+
+#define FETCH_B(rd, _count) lbu rd, (_count * 2 + 1)(rPC)
+#define FETCH_C(rd, _count) lbu rd, (_count * 2)(rPC)
+
+#endif
+
+#define GET_INST_OPCODE(rd) and rd, rINST, 0xFF
+
+#define GOTO_OPCODE(rd) sll rd, rd, -1000; \
+ addu rd, rIBASE, rd; \
+ jr rd
+
+
+#define LOAD(rd, rbase) lw rd, 0(rbase)
+#define LOAD_F(rd, rbase) l.s rd, (rbase)
+#define STORE(rd, rbase) sw rd, 0(rbase)
+#define STORE_F(rd, rbase) s.s rd, (rbase)
+
+#define GET_VREG(rd, rix) LOAD_eas2(rd,rFP,rix)
+
+#define GET_VREG_F(rd, rix) EAS2(AT, rFP, rix); \
+ .set noat; l.s rd, (AT); .set at
+
+#define SET_VREG(rd, rix) STORE_eas2(rd, rFP, rix)
+
+#define SET_VREG_GOTO(rd, rix, dst) .set noreorder; \
+ sll dst, dst, -1000; \
+ addu dst, rIBASE, dst; \
+ sll t8, rix, 2; \
+ addu t8, t8, rFP; \
+ jr dst; \
+ sw rd, 0(t8); \
+ .set reorder
+
+#define SET_VREG_F(rd, rix) EAS2(AT, rFP, rix); \
+ .set noat; s.s rd, (AT); .set at
+
+
+#define GET_OPA(rd) srl rd, rINST, 8
+#ifndef MIPS32R2
+#define GET_OPA4(rd) GET_OPA(rd); and rd, 0xf
+#else
+#define GET_OPA4(rd) ext rd, rd, 8, 4
+#endif
+#define GET_OPB(rd) srl rd, rINST, 12
+
+#define LOAD_rSELF_OFF(rd,off) lw rd, offThread_##off##(rSELF)
+
+#define LOAD_rSELF_method(rd) LOAD_rSELF_OFF(rd, method)
+#define LOAD_rSELF_methodClassDex(rd) LOAD_rSELF_OFF(rd, methodClassDex)
+#define LOAD_rSELF_interpStackEnd(rd) LOAD_rSELF_OFF(rd, interpStackEnd)
+#define LOAD_rSELF_retval(rd) LOAD_rSELF_OFF(rd, retval)
+#define LOAD_rSELF_pActiveProfilers(rd) LOAD_rSELF_OFF(rd, pActiveProfilers)
+#define LOAD_rSELF_bailPtr(rd) LOAD_rSELF_OFF(rd, bailPtr)
+
+#define GET_JIT_PROF_TABLE(rd) LOAD_rSELF_OFF(rd,pJitProfTable)
+#define GET_JIT_THRESHOLD(rd) LOAD_rSELF_OFF(rd,jitThreshold)
+
+/*
+ * Form an Effective Address rd = rbase + roff<<n;
+ * Uses reg AT
+ */
+#define EASN(rd,rbase,roff,rshift) .set noat; \
+ sll AT, roff, rshift; \
+ addu rd, rbase, AT; \
+ .set at
+
+#define EAS1(rd,rbase,roff) EASN(rd,rbase,roff,1)
+#define EAS2(rd,rbase,roff) EASN(rd,rbase,roff,2)
+#define EAS3(rd,rbase,roff) EASN(rd,rbase,roff,3)
+#define EAS4(rd,rbase,roff) EASN(rd,rbase,roff,4)
+
+/*
+ * Form an Effective Shift Right rd = rbase + roff>>n;
+ * Uses reg AT
+ */
+#define ESRN(rd,rbase,roff,rshift) .set noat; \
+ srl AT, roff, rshift; \
+ addu rd, rbase, AT; \
+ .set at
+
+#define LOAD_eas2(rd,rbase,roff) EAS2(AT, rbase, roff); \
+ .set noat; lw rd, 0(AT); .set at
+
+#define STORE_eas2(rd,rbase,roff) EAS2(AT, rbase, roff); \
+ .set noat; sw rd, 0(AT); .set at
+
+#define LOAD_RB_OFF(rd,rbase,off) lw rd, off(rbase)
+#define LOADu2_RB_OFF(rd,rbase,off) lhu rd, off(rbase)
+#define STORE_RB_OFF(rd,rbase,off) sw rd, off(rbase)
+
+#ifdef HAVE_LITTLE_ENDIAN
+
+#define STORE64_off(rlo,rhi,rbase,off) sw rlo, off(rbase); \
+ sw rhi, (off+4)(rbase)
+#define LOAD64_off(rlo,rhi,rbase,off) lw rlo, off(rbase); \
+ lw rhi, (off+4)(rbase)
+
+#define STORE64_off_F(rlo,rhi,rbase,off) s.s rlo, off(rbase); \
+ s.s rhi, (off+4)(rbase)
+#define LOAD64_off_F(rlo,rhi,rbase,off) l.s rlo, off(rbase); \
+ l.s rhi, (off+4)(rbase)
+#else
+
+#define STORE64_off(rlo,rhi,rbase,off) sw rlo, (off+4)(rbase); \
+ sw rhi, (off)(rbase)
+#define LOAD64_off(rlo,rhi,rbase,off) lw rlo, (off+4)(rbase); \
+ lw rhi, (off)(rbase)
+#define STORE64_off_F(rlo,rhi,rbase,off) s.s rlo, (off+4)(rbase); \
+ s.s rhi, (off)(rbase)
+#define LOAD64_off_F(rlo,rhi,rbase,off) l.s rlo, (off+4)(rbase); \
+ l.s rhi, (off)(rbase)
+#endif
+
+#define STORE64(rlo,rhi,rbase) STORE64_off(rlo,rhi,rbase,0)
+#define LOAD64(rlo,rhi,rbase) LOAD64_off(rlo,rhi,rbase,0)
+
+#define STORE64_F(rlo,rhi,rbase) STORE64_off_F(rlo,rhi,rbase,0)
+#define LOAD64_F(rlo,rhi,rbase) LOAD64_off_F(rlo,rhi,rbase,0)
+
+#define STORE64_lo(rd,rbase) sw rd, 0(rbase)
+#define STORE64_hi(rd,rbase) sw rd, 4(rbase)
+
+
+#define LOAD_offThread_exception(rd,rbase) LOAD_RB_OFF(rd,rbase,offThread_exception)
+#define LOAD_base_offArrayObject_length(rd,rbase) LOAD_RB_OFF(rd,rbase,offArrayObject_length)
+#define LOAD_base_offClassObject_accessFlags(rd,rbase) LOAD_RB_OFF(rd,rbase,offClassObject_accessFlags)
+#define LOAD_base_offClassObject_descriptor(rd,rbase) LOAD_RB_OFF(rd,rbase,offClassObject_descriptor)
+#define LOAD_base_offClassObject_super(rd,rbase) LOAD_RB_OFF(rd,rbase,offClassObject_super)
+
+#define LOAD_base_offClassObject_vtable(rd,rbase) LOAD_RB_OFF(rd,rbase,offClassObject_vtable)
+#define LOAD_base_offClassObject_vtableCount(rd,rbase) LOAD_RB_OFF(rd,rbase,offClassObject_vtableCount)
+#define LOAD_base_offDvmDex_pResClasses(rd,rbase) LOAD_RB_OFF(rd,rbase,offDvmDex_pResClasses)
+#define LOAD_base_offDvmDex_pResFields(rd,rbase) LOAD_RB_OFF(rd,rbase,offDvmDex_pResFields)
+
+#define LOAD_base_offDvmDex_pResMethods(rd,rbase) LOAD_RB_OFF(rd,rbase,offDvmDex_pResMethods)
+#define LOAD_base_offDvmDex_pResStrings(rd,rbase) LOAD_RB_OFF(rd,rbase,offDvmDex_pResStrings)
+#define LOAD_base_offInstField_byteOffset(rd,rbase) LOAD_RB_OFF(rd,rbase,offInstField_byteOffset)
+#define LOAD_base_offStaticField_value(rd,rbase) LOAD_RB_OFF(rd,rbase,offStaticField_value)
+#define LOAD_base_offMethod_clazz(rd,rbase) LOAD_RB_OFF(rd,rbase,offMethod_clazz)
+
+#define LOAD_base_offMethod_name(rd,rbase) LOAD_RB_OFF(rd,rbase,offMethod_name)
+#define LOAD_base_offObject_clazz(rd,rbase) LOAD_RB_OFF(rd,rbase,offObject_clazz)
+
+#define LOADu2_offMethod_methodIndex(rd,rbase) LOADu2_RB_OFF(rd,rbase,offMethod_methodIndex)
+
+
+#define STORE_offThread_exception(rd,rbase) STORE_RB_OFF(rd,rbase,offThread_exception)
+
+
+#define STACK_STORE(rd,off) sw rd, off(sp)
+#define STACK_LOAD(rd,off) lw rd, off(sp)
+#define CREATE_STACK(n) subu sp, sp, n
+#define DELETE_STACK(n) addu sp, sp, n
+
+#define SAVE_RA(offset) STACK_STORE(ra, offset)
+#define LOAD_RA(offset) STACK_LOAD(ra, offset)
+
+#define LOAD_ADDR(dest,addr) la dest, addr
+#define LOAD_IMM(dest, imm) li dest, imm
+#define MOVE_REG(dest,src) move dest, src
+#define RETURN jr ra
+#define STACK_SIZE 128
+
+#define STACK_OFFSET_ARG04 16
+#define STACK_OFFSET_GP 84
+#define STACK_OFFSET_rFP 112
+
+/* This directive will make sure all subsequent jal restore gp at a known offset */
+ .cprestore STACK_OFFSET_GP
+
+#define JAL(func) move rTEMP, ra; \
+ jal func; \
+ move ra, rTEMP
+
+#define JALR(reg) move rTEMP, ra; \
+ jalr ra, reg; \
+ move ra, rTEMP
+
+#define BAL(n) bal n
+
+#define STACK_STORE_RA() CREATE_STACK(STACK_SIZE); \
+ STACK_STORE(gp, STACK_OFFSET_GP); \
+ STACK_STORE(ra, 124)
+
+#define STACK_STORE_S0() STACK_STORE_RA(); \
+ STACK_STORE(s0, 116)
+
+#define STACK_STORE_S0S1() STACK_STORE_S0(); \
+ STACK_STORE(s1, STACK_OFFSET_rFP)
+
+#define STACK_LOAD_RA() STACK_LOAD(ra, 124); \
+ STACK_LOAD(gp, STACK_OFFSET_GP); \
+ DELETE_STACK(STACK_SIZE)
+
+#define STACK_LOAD_S0() STACK_LOAD(s0, 116); \
+ STACK_LOAD_RA()
+
+#define STACK_LOAD_S0S1() STACK_LOAD(s1, STACK_OFFSET_rFP); \
+ STACK_LOAD_S0()
+
+#define STACK_STORE_FULL() CREATE_STACK(STACK_SIZE); \
+ STACK_STORE(ra, 124); \
+ STACK_STORE(fp, 120); \
+ STACK_STORE(s0, 116); \
+ STACK_STORE(s1, STACK_OFFSET_rFP); \
+ STACK_STORE(s2, 108); \
+ STACK_STORE(s3, 104); \
+ STACK_STORE(s4, 100); \
+ STACK_STORE(s5, 96); \
+ STACK_STORE(s6, 92); \
+ STACK_STORE(s7, 88);
+
+#define STACK_LOAD_FULL() STACK_LOAD(gp, STACK_OFFSET_GP); \
+ STACK_LOAD(s7, 88); \
+ STACK_LOAD(s6, 92); \
+ STACK_LOAD(s5, 96); \
+ STACK_LOAD(s4, 100); \
+ STACK_LOAD(s3, 104); \
+ STACK_LOAD(s2, 108); \
+ STACK_LOAD(s1, STACK_OFFSET_rFP); \
+ STACK_LOAD(s0, 116); \
+ STACK_LOAD(fp, 120); \
+ STACK_LOAD(ra, 124); \
+ DELETE_STACK(STACK_SIZE)
+
+/*
+ * first 8 words are reserved for function calls
+ * Maximum offset is STACK_OFFSET_SCRMX-STACK_OFFSET_SCR
+ */
+#define STACK_OFFSET_SCR 32
+#define SCRATCH_STORE(r,off) \
+ STACK_STORE(r, STACK_OFFSET_SCR+off);
+#define SCRATCH_LOAD(r,off) \
+ STACK_LOAD(r, STACK_OFFSET_SCR+off);
+
+/* File: mips/platform.S */
+/*
+ * ===========================================================================
+ * CPU-version-specific defines and utility
+ * ===========================================================================
+ */
+
+
+
+ .global dvmCompilerTemplateStart
+ .type dvmCompilerTemplateStart, %function
+ .section .data.rel.ro
+
+dvmCompilerTemplateStart:
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMP_LONG
+dvmCompiler_TEMPLATE_CMP_LONG:
+/* File: mips/TEMPLATE_CMP_LONG.S */
+ /*
+ * Compare two 64-bit values
+ * x = y return 0
+ * x < y return -1
+ * x > y return 1
+ *
+ * I think I can improve on the ARM code by the following observation
+ * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
+ * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
+ * subu v0, t0, t1 # v0= -1:1:0 for [ < > = ]
+ *
+ * This code assumes the register pair ordering will depend on endianess (a1:a0 or a0:a1).
+ * a1:a0 => vBB
+ * a3:a2 => vCC
+ */
+ /* cmp-long vAA, vBB, vCC */
+ slt t0, rARG1, rARG3 # compare hi
+ sgt t1, rARG1, rARG3
+ subu v0, t1, t0 # v0<- (-1,1,0)
+ bnez v0, .LTEMPLATE_CMP_LONG_finish
+ # at this point x.hi==y.hi
+ sltu t0, rARG0, rARG2 # compare lo
+ sgtu t1, rARG0, rARG2
+ subu v0, t1, t0 # v0<- (-1,1,0) for [< > =]
+.LTEMPLATE_CMP_LONG_finish:
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_RETURN
+dvmCompiler_TEMPLATE_RETURN:
+/* File: mips/TEMPLATE_RETURN.S */
+ /*
+ * Unwind a frame from the Dalvik stack for compiled OP_RETURN_XXX.
+ * If the stored value in returnAddr
+ * is non-zero, the caller is compiled by the JIT thus return to the
+ * address in the code cache following the invoke instruction. Otherwise
+ * return to the special dvmJitToInterpNoChain entry point.
+ */
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # preserve a0-a2 and ra
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(ra, 12)
+
+ # a0=rSELF
+ move a0, rSELF
+ la t9, dvmFastMethodTraceExit
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a2 and ra
+ SCRATCH_LOAD(ra, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+#endif
+ SAVEAREA_FROM_FP(a0, rFP) # a0<- saveArea (old)
+ lw t0, offStackSaveArea_prevFrame(a0) # t0<- saveArea->prevFrame
+ lbu t1, offThread_breakFlags(rSELF) # t1<- breakFlags
+ lw rPC, offStackSaveArea_savedPc(a0) # rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+ lw t2, offStackSaveArea_returnAddr(a0) # t2<- chaining cell ret
+#else
+ move t2, zero # disable chaining
+#endif
+ lw a2, offStackSaveArea_method - sizeofStackSaveArea(t0)
+ # a2<- method we're returning to
+#if !defined(WITH_SELF_VERIFICATION)
+ beq a2, zero, 1f # bail to interpreter
+#else
+ bne a2, zero, 2f
+ JALR(ra) # punt to interpreter and compare state
+ # DOUG: assume this does not return ???
+2:
+#endif
+ la t4, .LdvmJitToInterpNoChainNoProfile # defined in footer.S
+ lw a1, (t4)
+ move rFP, t0 # publish new FP
+ beq a2, zero, 4f
+ lw t0, offMethod_clazz(a2) # t0<- method->clazz
+4:
+
+ sw a2, offThread_method(rSELF) # self->method = newSave->method
+ lw a0, offClassObject_pDvmDex(t0) # a0<- method->clazz->pDvmDex
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = fp
+ add rPC, rPC, 3*2 # publish new rPC
+ sw a0, offThread_methodClassDex(rSELF)
+ movn t2, zero, t1 # check the breadFlags and
+ # clear the chaining cell address
+ sw t2, offThread_inJitCodeCache(rSELF) # in code cache or not
+ beq t2, zero, 3f # chaining cell exists?
+ JALR(t2) # jump to the chaining cell
+ # DOUG: assume this does not return ???
+3:
+#if defined(WITH_JIT_TUNING)
+ li a0, kCallsiteInterpreted
+#endif
+ j a1 # callsite is interpreted
+1:
+ sw zero, offThread_inJitCodeCache(rSELF) # reset inJitCodeCache
+ SAVE_PC_TO_SELF() # SAVE_PC_FP_TO_SELF()
+ SAVE_FP_TO_SELF()
+ la t4, .LdvmMterpStdBail # defined in footer.S
+ lw a2, (t4)
+ move a0, rSELF # Expecting rSELF in a0
+ JALR(a2) # exit the interpreter
+ # DOUG: assume this does not return ???
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT:
+/* File: mips/TEMPLATE_INVOKE_METHOD_NO_OPT.S */
+ /*
+ * For polymorphic callsites - setup the Dalvik frame and load Dalvik PC
+ * into rPC then jump to dvmJitToInterpNoChain to dispatch the
+ * runtime-resolved callee.
+ */
+ # a0 = methodToCall, a1 = returnCell, rPC = dalvikCallsite
+ lh t7, offMethod_registersSize(a0) # t7<- methodToCall->regsSize
+ lh a2, offMethod_outsSize(a0) # a2<- methodToCall->outsSize
+ lw t9, offThread_interpStackEnd(rSELF) # t9<- interpStackEnd
+ lbu t8, offThread_breakFlags(rSELF) # t8<- breakFlags
+ move a3, a1 # a3<- returnCell
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- stack save area
+ sll t6, t7, 2 # multiply regsSize by 4 (4 bytes per reg)
+ sub a1, a1, t6 # a1<- newFp(old savearea-regsSize)
+ SAVEAREA_FROM_FP(t0, a1) # t0<- stack save area
+ sll t6, a2, 2 # multiply outsSize by 4 (4 bytes per reg)
+ sub t0, t0, t6 # t0<- bottom (newsave-outsSize)
+ bgeu t0, t9, 1f # bottom < interpStackEnd?
+ RETURN # return to raise stack overflow excep.
+
+1:
+ # a1 = newFP, a0 = methodToCall, a3 = returnCell, rPC = dalvikCallsite
+ lw t9, offMethod_clazz(a0) # t9<- methodToCall->clazz
+ lw t0, offMethod_accessFlags(a0) # t0<- methodToCall->accessFlags
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+ sw rPC, (offStackSaveArea_savedPc - sizeofStackSaveArea)(a1)
+ lw rPC, offMethod_insns(a0) # rPC<- methodToCall->insns
+
+ # set up newSaveArea
+ sw rFP, (offStackSaveArea_prevFrame - sizeofStackSaveArea)(a1)
+ sw a3, (offStackSaveArea_returnAddr - sizeofStackSaveArea)(a1)
+ sw a0, (offStackSaveArea_method - sizeofStackSaveArea)(a1)
+ beqz t8, 2f # breakFlags != 0
+ RETURN # bail to the interpreter
+
+2:
+ and t6, t0, ACC_NATIVE
+ beqz t6, 3f
+#if !defined(WITH_SELF_VERIFICATION)
+ j .LinvokeNative
+#else
+ RETURN # bail to the interpreter
+#endif
+
+3:
+ # continue executing the next instruction through the interpreter
+ la t0, .LdvmJitToInterpTraceSelectNoChain # defined in footer.S
+ lw rTEMP, (t0)
+ lw a3, offClassObject_pDvmDex(t9) # a3<- method->clazz->pDvmDex
+
+ # Update "thread" values for the new method
+ sw a0, offThread_method(rSELF) # self->method = methodToCall
+ sw a3, offThread_methodClassDex(rSELF) # self->methodClassDex = ...
+ move rFP, a1 # fp = newFp
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # preserve a0-a3
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+
+ # a0=methodToCall, a1=rSELF
+ move a1, rSELF
+ la t9, dvmFastMethodTraceEnter
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a3
+ SCRATCH_LOAD(a3, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+#endif
+
+ # Start executing the callee
+#if defined(WITH_JIT_TUNING)
+ li a0, kInlineCacheMiss
+#endif
+ jr rTEMP # dvmJitToInterpTraceSelectNoChain
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN
+dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
+/* File: mips/TEMPLATE_INVOKE_METHOD_CHAIN.S */
+ /*
+ * For monomorphic callsite, setup the Dalvik frame and return to the
+ * Thumb code through the link register to transfer control to the callee
+ * method through a dedicated chaining cell.
+ */
+ # a0 = methodToCall, a1 = returnCell, rPC = dalvikCallsite
+ # methodToCall is guaranteed to be non-native
+.LinvokeChain:
+ lh t7, offMethod_registersSize(a0) # t7<- methodToCall->regsSize
+ lh a2, offMethod_outsSize(a0) # a2<- methodToCall->outsSize
+ lw t9, offThread_interpStackEnd(rSELF) # t9<- interpStackEnd
+ lbu t8, offThread_breakFlags(rSELF) # t8<- breakFlags
+ move a3, a1 # a3<- returnCell
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- stack save area
+ sll t6, t7, 2 # multiply regsSize by 4 (4 bytes per reg)
+ sub a1, a1, t6 # a1<- newFp(old savearea-regsSize)
+ SAVEAREA_FROM_FP(t0, a1) # t0<- stack save area
+ add t2, ra, 8 # setup the punt-to-interp address
+ # 8 bytes skips branch and delay slot
+ sll t6, a2, 2 # multiply outsSize by 4 (4 bytes per reg)
+ sub t0, t0, t6 # t0<- bottom (newsave-outsSize)
+ bgeu t0, t9, 1f # bottom < interpStackEnd?
+ jr t2 # return to raise stack overflow excep.
+
+1:
+ # a1 = newFP, a0 = methodToCall, a3 = returnCell, rPC = dalvikCallsite
+ lw t9, offMethod_clazz(a0) # t9<- methodToCall->clazz
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+ sw rPC, (offStackSaveArea_savedPc - sizeofStackSaveArea)(a1)
+ lw rPC, offMethod_insns(a0) # rPC<- methodToCall->insns
+
+ # set up newSaveArea
+ sw rFP, (offStackSaveArea_prevFrame - sizeofStackSaveArea)(a1)
+ sw a3, (offStackSaveArea_returnAddr - sizeofStackSaveArea)(a1)
+ sw a0, (offStackSaveArea_method - sizeofStackSaveArea)(a1)
+ beqz t8, 2f # breakFlags != 0
+ jr t2 # bail to the interpreter
+
+2:
+ lw a3, offClassObject_pDvmDex(t9) # a3<- methodToCall->clazz->pDvmDex
+
+ # Update "thread" values for the new method
+ sw a0, offThread_method(rSELF) # self->method = methodToCall
+ sw a3, offThread_methodClassDex(rSELF) # self->methodClassDex = ...
+ move rFP, a1 # fp = newFp
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # preserve a0-a2 and ra
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(ra, 12)
+
+ move a1, rSELF
+ # a0=methodToCall, a1=rSELF
+ la t9, dvmFastMethodTraceEnter
+ jalr t9
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a2 and ra
+ SCRATCH_LOAD(ra, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+#endif
+ RETURN # return to the callee-chaining cell
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
+dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN:
+/* File: mips/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
+ /*
+ * For polymorphic callsite, check whether the cached class pointer matches
+ * the current one. If so setup the Dalvik frame and return to the
+ * Thumb code through the link register to transfer control to the callee
+ * method through a dedicated chaining cell.
+ *
+ * The predicted chaining cell is declared in ArmLIR.h with the
+ * following layout:
+ *
+ * typedef struct PredictedChainingCell {
+ * u4 branch;
+ * u4 delay_slot;
+ * const ClassObject *clazz;
+ * const Method *method;
+ * u4 counter;
+ * } PredictedChainingCell;
+ *
+ * Upon returning to the callsite:
+ * - lr : to branch to the chaining cell
+ * - lr+8 : to punt to the interpreter
+ * - lr+16: to fully resolve the callee and may rechain.
+ * a3 <- class
+ */
+ # a0 = this, a1 = returnCell, a2 = predictedChainCell, rPC = dalvikCallsite
+ lw a3, offObject_clazz(a0) # a3 <- this->class
+ lw rIBASE, 8(a2) # t0 <- predictedChainCell->clazz
+ lw a0, 12(a2) # a0 <- predictedChainCell->method
+ lw t1, offThread_icRechainCount(rSELF) # t1 <- shared rechainCount
+
+#if defined(WITH_JIT_TUNING)
+ la rINST, .LdvmICHitCount
+ #add t2, t2, 1
+ bne a3, rIBASE, 1f
+ nop
+ lw t2, 0(rINST)
+ add t2, t2, 1
+ sw t2, 0(rINST)
+1:
+ #add t2, t2, 1
+#endif
+ beq a3, rIBASE, .LinvokeChain # branch if predicted chain is valid
+ lw rINST, offClassObject_vtable(a3) # rINST <- this->class->vtable
+ beqz rIBASE, 2f # initialized class or not
+ sub a1, t1, 1 # count--
+ sw a1, offThread_icRechainCount(rSELF) # write back to InterpState
+ b 3f
+2:
+ move a1, zero
+3:
+ add ra, ra, 16 # return to fully-resolve landing pad
+ /*
+ * a1 <- count
+ * a2 <- &predictedChainCell
+ * a3 <- this->class
+ * rPC <- dPC
+ * rINST <- this->class->vtable
+ */
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
+/* File: mips/TEMPLATE_INVOKE_METHOD_NATIVE.S */
+ # a0 = methodToCall, a1 = returnCell, rPC = dalvikCallsite
+ lh t7, offMethod_registersSize(a0) # t7<- methodToCall->regsSize
+ lw t9, offThread_interpStackEnd(rSELF) # t9<- interpStackEnd
+ lbu t8, offThread_breakFlags(rSELF) # t8<- breakFlags
+ move a3, a1 # a3<- returnCell
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- stack save area
+ sll t6, t7, 2 # multiply regsSize by 4 (4 bytes per reg)
+ sub a1, a1, t6 # a1<- newFp(old savearea-regsSize)
+ SAVEAREA_FROM_FP(t0, a1) # t0<- stack save area
+ bgeu t0, t9, 1f # bottom < interpStackEnd?
+ RETURN # return to raise stack overflow excep.
+
+1:
+ # a1 = newFP, a0 = methodToCall, a3 = returnCell, rPC = dalvikCallsite
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+ sw rPC, (offStackSaveArea_savedPc - sizeofStackSaveArea)(a1)
+ lw rPC, offMethod_insns(a0) # rPC<- methodToCall->insns
+
+ # set up newSaveArea
+ sw rFP, (offStackSaveArea_prevFrame - sizeofStackSaveArea)(a1)
+ sw a3, (offStackSaveArea_returnAddr - sizeofStackSaveArea)(a1)
+ sw a0, (offStackSaveArea_method - sizeofStackSaveArea)(a1)
+ lw rTEMP, offMethod_nativeFunc(a0) # t9<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+ beqz t8, 2f # breakFlags != 0
+ RETURN # bail to the interpreter
+2:
+#else
+ RETURN # bail to the interpreter unconditionally
+#endif
+
+ # go ahead and transfer control to the native code
+ lw t6, offThread_jniLocal_topCookie(rSELF) # t6<- thread->localRef->...
+ sw a1, offThread_curFrame(rSELF) # self->curFrame = newFp
+ sw zero, offThread_inJitCodeCache(rSELF) # not in the jit code cache
+ sw t6, (offStackSaveArea_localRefCookie - sizeofStackSaveArea)(a1)
+ # newFp->localRefCookie=top
+ SAVEAREA_FROM_FP(rBIX, a1) # rBIX<- new stack save area
+ move a2, a0 # a2<- methodToCall
+ move a0, a1 # a0<- newFp
+ add a1, rSELF, offThread_retval # a1<- &retval
+ move a3, rSELF # a3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # a2: methodToCall
+ # preserve a0-a3
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+
+ move a0, a2
+ move a1, rSELF
+ # a0=JNIMethod, a1=rSELF
+ la t9, dvmFastMethodTraceEnter
+ JALR(t9) # off to the native code
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a3
+ SCRATCH_LOAD(a3, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+
+ move rOBJ, a2 # save a2
+#endif
+
+ JALR(rTEMP) # off to the native code
+ lw gp, STACK_OFFSET_GP(sp)
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+ move a0, rOBJ
+ move a1, rSELF
+ # a0=JNIMethod, a1=rSELF
+ la t9, dvmFastNativeMethodTraceExit
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+#endif
+
+ # native return; rBIX=newSaveArea
+ # equivalent to dvmPopJniLocals
+ lw a2, offStackSaveArea_returnAddr(rBIX) # a2 = chaining cell ret addr
+ lw a0, offStackSaveArea_localRefCookie(rBIX) # a0<- saved->top
+ lw a1, offThread_exception(rSELF) # check for exception
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = fp
+ sw a0, offThread_jniLocal_topCookie(rSELF) # new top <- old top
+ lw a0, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+
+ # a0 = dalvikCallsitePC
+ bnez a1, .LhandleException # handle exception if any
+
+ sw a2, offThread_inJitCodeCache(rSELF) # set the mode properly
+ beqz a2, 3f
+ jr a2 # go if return chaining cell still exist
+
+3:
+ # continue executing the next instruction through the interpreter
+ la a1, .LdvmJitToInterpTraceSelectNoChain # defined in footer.S
+ lw a1, (a1)
+ add rPC, a0, 3*2 # reconstruct new rPC (advance 3 dalvik instr)
+
+#if defined(WITH_JIT_TUNING)
+ li a0, kCallsiteInterpreted
+#endif
+ jr a1
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_MUL_LONG
+dvmCompiler_TEMPLATE_MUL_LONG:
+/* File: mips/TEMPLATE_MUL_LONG.S */
+ /*
+ * Signed 64-bit integer multiply.
+ *
+ * For JIT: op1 in a0/a1, op2 in a2/a3, return in v0/v1
+ *
+ * Consider WXxYZ (a1a0 x a3a2) with a long multiply:
+ *
+ * a1 a0
+ * x a3 a2
+ * -------------
+ * a2a1 a2a0
+ * a3a0
+ * a3a1 (<= unused)
+ * ---------------
+ * v1 v0
+ *
+ */
+ /* mul-long vAA, vBB, vCC */
+ mul rRESULT1,rARG3,rARG0 # v1= a3a0
+ multu rARG2,rARG0
+ mfhi t1
+ mflo rRESULT0 # v0= a2a0
+ mul t0,rARG2,rARG1 # t0= a2a1
+ addu rRESULT1,rRESULT1,t1 # v1= a3a0 + hi(a2a0)
+ addu rRESULT1,rRESULT1,t0 # v1= a3a0 + hi(a2a0) + a2a1;
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_SHL_LONG
+dvmCompiler_TEMPLATE_SHL_LONG:
+/* File: mips/TEMPLATE_SHL_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* shl-long vAA:vBB(rARG1:rARG0), vCC(a2) - result in (rRESULT1:rRESULT0) */
+ sll rRESULT0, rARG0, a2 # rlo<- alo << (shift&31)
+ not rRESULT1, a2 # rhi<- 31-shift (shift is 5b)
+ srl rARG0, 1
+ srl rARG0, rRESULT1 # alo<- alo >> (32-(shift&31))
+ sll rRESULT1, rARG1, a2 # rhi<- ahi << (shift&31)
+ or rRESULT1, rARG0 # rhi<- rhi | alo
+ andi a2, 0x20 # shift< shift & 0x20
+ movn rRESULT1, rRESULT0, a2 # rhi<- rlo (if shift&0x20)
+ movn rRESULT0, zero, a2 # rlo<- 0 (if shift&0x20)
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_SHR_LONG
+dvmCompiler_TEMPLATE_SHR_LONG:
+/* File: mips/TEMPLATE_SHR_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* shr-long vAA:vBB(rARG1:rARG0), vCC(a2) - result in (rRESULT1:rRESULT0) */
+ sra rRESULT1, rARG1, a2 # rhi<- ahi >> (shift&31)
+ srl rRESULT0, rARG0, a2 # rlo<- alo >> (shift&31)
+ sra a3, rARG1, 31 # a3<- sign(ah)
+ not rARG0, a2 # alo<- 31-shift (shift is 5b)
+ sll rARG1, 1
+ sll rARG1, rARG0 # ahi<- ahi << (32-(shift&31))
+ or rRESULT0, rARG1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn rRESULT0, rRESULT1, a2 # rlo<- rhi (if shift&0x20)
+ movn rRESULT1, a3, a2 # rhi<- sign(ahi) (if shift&0x20)
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_USHR_LONG
+dvmCompiler_TEMPLATE_USHR_LONG:
+/* File: mips/TEMPLATE_USHR_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* ushr-long vAA:vBB(rARG1:rARG0), vCC(a2) - result in (rRESULT1:rRESULT0) */
+ srl rRESULT1, rARG1, a2 # rhi<- ahi >> (shift&31)
+ srl rRESULT0, rARG0, a2 # rlo<- alo >> (shift&31)
+ not rARG0, a2 # alo<- 31-n (shift is 5b)
+ sll rARG1, 1
+ sll rARG1, rARG0 # ahi<- ahi << (32-(shift&31))
+ or rRESULT0, rARG1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn rRESULT0, rRESULT1, a2 # rlo<- rhi (if shift&0x20)
+ movn rRESULT1, zero, a2 # rhi<- 0 (if shift&0x20)
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
+dvmCompiler_TEMPLATE_ADD_FLOAT_VFP:
+/* File: mips/TEMPLATE_ADD_FLOAT_VFP.S */
+/* File: mips/fbinop.S */
+ /*
+ * Generic 32-bit binary float operation. a0 = a1 op a2.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = op1 address
+ * a2 = op2 address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ *
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vBB
+ LOAD(a1, a2) # a1<- vCC
+ .if 0
+ beqz a1, common_errDivideByZero # is second operand zero?
+ .endif
+ # optional op
+ JAL(__addsf3) # v0 = result
+ STORE(v0, rOBJ) # vAA <- v0
+#else
+ LOAD_F(fa0, a1) # fa0<- vBB
+ LOAD_F(fa1, a2) # fa1<- vCC
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+ # optional op
+ add.s fv0, fa0, fa1 # fv0 = result
+ STORE_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_SUB_FLOAT_VFP
+dvmCompiler_TEMPLATE_SUB_FLOAT_VFP:
+/* File: mips/TEMPLATE_SUB_FLOAT_VFP.S */
+/* File: mips/fbinop.S */
+ /*
+ * Generic 32-bit binary float operation. a0 = a1 op a2.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = op1 address
+ * a2 = op2 address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ *
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vBB
+ LOAD(a1, a2) # a1<- vCC
+ .if 0
+ beqz a1, common_errDivideByZero # is second operand zero?
+ .endif
+ # optional op
+ JAL(__subsf3) # v0 = result
+ STORE(v0, rOBJ) # vAA <- v0
+#else
+ LOAD_F(fa0, a1) # fa0<- vBB
+ LOAD_F(fa1, a2) # fa1<- vCC
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+ # optional op
+ sub.s fv0, fa0, fa1 # fv0 = result
+ STORE_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_MUL_FLOAT_VFP
+dvmCompiler_TEMPLATE_MUL_FLOAT_VFP:
+/* File: mips/TEMPLATE_MUL_FLOAT_VFP.S */
+/* File: mips/fbinop.S */
+ /*
+ * Generic 32-bit binary float operation. a0 = a1 op a2.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = op1 address
+ * a2 = op2 address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ *
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vBB
+ LOAD(a1, a2) # a1<- vCC
+ .if 0
+ beqz a1, common_errDivideByZero # is second operand zero?
+ .endif
+ # optional op
+ JAL(__mulsf3) # v0 = result
+ STORE(v0, rOBJ) # vAA <- v0
+#else
+ LOAD_F(fa0, a1) # fa0<- vBB
+ LOAD_F(fa1, a2) # fa1<- vCC
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+ # optional op
+ mul.s fv0, fa0, fa1 # fv0 = result
+ STORE_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_DIV_FLOAT_VFP
+dvmCompiler_TEMPLATE_DIV_FLOAT_VFP:
+/* File: mips/TEMPLATE_DIV_FLOAT_VFP.S */
+/* File: mips/fbinop.S */
+ /*
+ * Generic 32-bit binary float operation. a0 = a1 op a2.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = op1 address
+ * a2 = op2 address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ *
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vBB
+ LOAD(a1, a2) # a1<- vCC
+ .if 0
+ beqz a1, common_errDivideByZero # is second operand zero?
+ .endif
+ # optional op
+ JAL(__divsf3) # v0 = result
+ STORE(v0, rOBJ) # vAA <- v0
+#else
+ LOAD_F(fa0, a1) # fa0<- vBB
+ LOAD_F(fa1, a2) # fa1<- vCC
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+ # optional op
+ div.s fv0, fa0, fa1 # fv0 = result
+ STORE_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_ADD_DOUBLE_VFP
+dvmCompiler_TEMPLATE_ADD_DOUBLE_VFP:
+/* File: mips/TEMPLATE_ADD_DOUBLE_VFP.S */
+/* File: mips/fbinopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = op1 address
+ * a2 = op2 address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ move t0, a1 # save a1
+ move t1, a2 # save a2
+ LOAD64(rARG0, rARG1, t0) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3<- vCC/vCC+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ # optional op
+ JAL(__adddf3) # result<- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ LOAD64_F(fa0, fa0f, a1)
+ LOAD64_F(fa1, fa1f, a2)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+ # optional op
+ add.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_SUB_DOUBLE_VFP
+dvmCompiler_TEMPLATE_SUB_DOUBLE_VFP:
+/* File: mips/TEMPLATE_SUB_DOUBLE_VFP.S */
+/* File: mips/fbinopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = op1 address
+ * a2 = op2 address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ move t0, a1 # save a1
+ move t1, a2 # save a2
+ LOAD64(rARG0, rARG1, t0) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3<- vCC/vCC+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ # optional op
+ JAL(__subdf3) # result<- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ LOAD64_F(fa0, fa0f, a1)
+ LOAD64_F(fa1, fa1f, a2)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+ # optional op
+ sub.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_MUL_DOUBLE_VFP
+dvmCompiler_TEMPLATE_MUL_DOUBLE_VFP:
+/* File: mips/TEMPLATE_MUL_DOUBLE_VFP.S */
+/* File: mips/fbinopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = op1 address
+ * a2 = op2 address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ move t0, a1 # save a1
+ move t1, a2 # save a2
+ LOAD64(rARG0, rARG1, t0) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3<- vCC/vCC+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ # optional op
+ JAL(__muldf3) # result<- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ LOAD64_F(fa0, fa0f, a1)
+ LOAD64_F(fa1, fa1f, a2)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+ # optional op
+ mul.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_DIV_DOUBLE_VFP
+dvmCompiler_TEMPLATE_DIV_DOUBLE_VFP:
+/* File: mips/TEMPLATE_DIV_DOUBLE_VFP.S */
+/* File: mips/fbinopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = op1 address
+ * a2 = op2 address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ move t0, a1 # save a1
+ move t1, a2 # save a2
+ LOAD64(rARG0, rARG1, t0) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3<- vCC/vCC+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ # optional op
+ JAL(__divdf3) # result<- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ LOAD64_F(fa0, fa0f, a1)
+ LOAD64_F(fa1, fa1f, a2)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+ # optional op
+ div.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_DOUBLE_TO_FLOAT_VFP
+dvmCompiler_TEMPLATE_DOUBLE_TO_FLOAT_VFP:
+/* File: mips/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S */
+/* File: mips/funopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0/a1", where
+ * "result" is a 32-bit quantity in a0.
+ *
+ * For: long-to-float, double-to-int, double-to-float
+ * If hard floating point support is available, use fa0 as the parameter, except for
+ * long-to-float opcode.
+ * (This would work for long-to-int, but that instruction is actually
+ * an exact match for OP_MOVE.)
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = src dalvik register address
+ *
+ */
+ move rINST, a0 # save a0
+#ifdef SOFT_FLOAT
+ move t0, a1 # save a1
+ LOAD64(rARG0, rARG1, t0) # a0/a1<- vB/vB+1
+ # optional op
+ JAL(__truncdfsf2) # v0<- op, a0-a3 changed
+.LTEMPLATE_DOUBLE_TO_FLOAT_VFP_set_vreg:
+ STORE(v0, rINST) # vA<- v0
+#else
+ LOAD64_F(fa0, fa0f, a1)
+ # optional op
+ cvt.s.d fv0,fa0 # fv0 = result
+.LTEMPLATE_DOUBLE_TO_FLOAT_VFP_set_vreg_f:
+ STORE_F(fv0, rINST) # vA<- fv0
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_DOUBLE_TO_INT_VFP
+dvmCompiler_TEMPLATE_DOUBLE_TO_INT_VFP:
+/* File: mips/TEMPLATE_DOUBLE_TO_INT_VFP.S */
+/* File: mips/funopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0/a1", where
+ * "result" is a 32-bit quantity in a0.
+ *
+ * For: long-to-float, double-to-int, double-to-float
+ * If hard floating point support is available, use fa0 as the parameter, except for
+ * long-to-float opcode.
+ * (This would work for long-to-int, but that instruction is actually
+ * an exact match for OP_MOVE.)
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = src dalvik register address
+ *
+ */
+ move rINST, a0 # save a0
+#ifdef SOFT_FLOAT
+ move t0, a1 # save a1
+ LOAD64(rARG0, rARG1, t0) # a0/a1<- vB/vB+1
+ # optional op
+ b d2i_doconv # v0<- op, a0-a3 changed
+.LTEMPLATE_DOUBLE_TO_INT_VFP_set_vreg:
+ STORE(v0, rINST) # vA<- v0
+#else
+ LOAD64_F(fa0, fa0f, a1)
+ # optional op
+ b d2i_doconv # fv0 = result
+.LTEMPLATE_DOUBLE_TO_INT_VFP_set_vreg_f:
+ STORE_F(fv0, rINST) # vA<- fv0
+#endif
+ RETURN
+
+
+/*
+ * Convert the double in a0/a1 to an int in a0.
+ *
+ * We have to clip values to int min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ * Use rBIX / rOBJ as global to hold arguments (they are not bound to a global var)
+ */
+
+d2i_doconv:
+#ifdef SOFT_FLOAT
+ la t0, .LDOUBLE_TO_INT_max
+ LOAD64(rARG2, rARG3, t0)
+ move rBIX, rARG0 # save a0
+ move rOBJ, rARG1 # and a1
+ JAL(__gedf2) # is arg >= maxint?
+
+ move t0, v0
+ li v0, ~0x80000000 # return maxint (7fffffff)
+ bgez t0, .LTEMPLATE_DOUBLE_TO_INT_VFP_set_vreg # nonzero == yes
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rOBJ
+ la t0, .LDOUBLE_TO_INT_min
+ LOAD64(rARG2, rARG3, t0)
+ JAL(__ledf2) # is arg <= minint?
+
+ move t0, v0
+ li v0, 0x80000000 # return minint (80000000)
+ blez t0, .LTEMPLATE_DOUBLE_TO_INT_VFP_set_vreg # nonzero == yes
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rOBJ
+ move rARG2, rBIX # compare against self
+ move rARG3, rOBJ
+ JAL(__nedf2) # is arg == self?
+
+ move t0, v0 # zero == no
+ li v0, 0
+ bnez t0, .LTEMPLATE_DOUBLE_TO_INT_VFP_set_vreg # return zero for NaN
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rOBJ
+ JAL(__fixdfsi) # convert double to int
+ b .LTEMPLATE_DOUBLE_TO_INT_VFP_set_vreg
+#else
+ la t0, .LDOUBLE_TO_INT_max
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa1, fa0
+ l.s fv0, .LDOUBLE_TO_INT_maxret
+ bc1t .LTEMPLATE_DOUBLE_TO_INT_VFP_set_vreg_f
+
+ la t0, .LDOUBLE_TO_INT_min
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa0, fa1
+ l.s fv0, .LDOUBLE_TO_INT_minret
+ bc1t .LTEMPLATE_DOUBLE_TO_INT_VFP_set_vreg_f
+
+ mov.d fa1, fa0
+ c.un.d fcc0, fa0, fa1
+ li.s fv0, 0
+ bc1t .LTEMPLATE_DOUBLE_TO_INT_VFP_set_vreg_f
+
+ trunc.w.d fv0, fa0
+ b .LTEMPLATE_DOUBLE_TO_INT_VFP_set_vreg_f
+#endif
+
+
+.LDOUBLE_TO_INT_max:
+ .dword 0x41dfffffffc00000
+.LDOUBLE_TO_INT_min:
+ .dword 0xc1e0000000000000 # minint, as a double (high word)
+.LDOUBLE_TO_INT_maxret:
+ .word 0x7fffffff
+.LDOUBLE_TO_INT_minret:
+ .word 0x80000000
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_FLOAT_TO_DOUBLE_VFP
+dvmCompiler_TEMPLATE_FLOAT_TO_DOUBLE_VFP:
+/* File: mips/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S */
+/* File: mips/funopWider.S */
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vB
+ # optional op
+ JAL(__extendsfdf2) # result<- op, a0-a3 changed
+
+.LTEMPLATE_FLOAT_TO_DOUBLE_VFP_set_vreg:
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vA/vA+1<- v0/v1
+#else
+ LOAD_F(fa0, a1) # fa0<- vB
+ # optional op
+ cvt.d.s fv0, fa0
+
+.LTEMPLATE_FLOAT_TO_DOUBLE_VFP_set_vreg:
+ STORE64_F(fv0, fv0f, rOBJ) # vA/vA+1<- fv0/fv0f
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_FLOAT_TO_INT_VFP
+dvmCompiler_TEMPLATE_FLOAT_TO_INT_VFP:
+/* File: mips/TEMPLATE_FLOAT_TO_INT_VFP.S */
+/* File: mips/funop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: int-to-float, float-to-int
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = src dalvik register address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ *
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vBB
+ # optional op
+ b f2i_doconv # v0<- op, a0-a3 changed
+.LTEMPLATE_FLOAT_TO_INT_VFP_set_vreg:
+ STORE(v0, rOBJ) # vAA<- v0
+#else
+ LOAD_F(fa0, a1) # fa0<- vBB
+ # optional op
+ b f2i_doconv # fv0 = result
+.LTEMPLATE_FLOAT_TO_INT_VFP_set_vreg_f:
+ STORE_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ RETURN
+
+
+/*
+ * Not an entry point as it is used only once !!
+ */
+f2i_doconv:
+#ifdef SOFT_FLOAT
+ li a1, 0x4f000000 # (float)maxint
+ move rBIX, a0
+ JAL(__gesf2) # is arg >= maxint?
+ move t0, v0
+ li v0, ~0x80000000 # return maxint (7fffffff)
+ bgez t0, .LTEMPLATE_FLOAT_TO_INT_VFP_set_vreg
+
+ move a0, rBIX # recover arg
+ li a1, 0xcf000000 # (float)minint
+ JAL(__lesf2)
+
+ move t0, v0
+ li v0, 0x80000000 # return minint (80000000)
+ blez t0, .LTEMPLATE_FLOAT_TO_INT_VFP_set_vreg
+ move a0, rBIX
+ move a1, rBIX
+ JAL(__nesf2)
+
+ move t0, v0
+ li v0, 0 # return zero for NaN
+ bnez t0, .LTEMPLATE_FLOAT_TO_INT_VFP_set_vreg
+
+ move a0, rBIX
+ JAL(__fixsfsi)
+ b .LTEMPLATE_FLOAT_TO_INT_VFP_set_vreg
+#else
+ l.s fa1, .LFLOAT_TO_INT_max
+ c.ole.s fcc0, fa1, fa0
+ l.s fv0, .LFLOAT_TO_INT_ret_max
+ bc1t .LTEMPLATE_FLOAT_TO_INT_VFP_set_vreg_f
+
+ l.s fa1, .LFLOAT_TO_INT_min
+ c.ole.s fcc0, fa0, fa1
+ l.s fv0, .LFLOAT_TO_INT_ret_min
+ bc1t .LTEMPLATE_FLOAT_TO_INT_VFP_set_vreg_f
+
+ mov.s fa1, fa0
+ c.un.s fcc0, fa0, fa1
+ li.s fv0, 0
+ bc1t .LTEMPLATE_FLOAT_TO_INT_VFP_set_vreg_f
+
+ trunc.w.s fv0, fa0
+ b .LTEMPLATE_FLOAT_TO_INT_VFP_set_vreg_f
+#endif
+
+.LFLOAT_TO_INT_max:
+ .word 0x4f000000
+.LFLOAT_TO_INT_min:
+ .word 0xcf000000
+.LFLOAT_TO_INT_ret_max:
+ .word 0x7fffffff
+.LFLOAT_TO_INT_ret_min:
+ .word 0x80000000
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INT_TO_DOUBLE_VFP
+dvmCompiler_TEMPLATE_INT_TO_DOUBLE_VFP:
+/* File: mips/TEMPLATE_INT_TO_DOUBLE_VFP.S */
+/* File: mips/funopWider.S */
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vB
+ # optional op
+ JAL(__floatsidf) # result<- op, a0-a3 changed
+
+.LTEMPLATE_INT_TO_DOUBLE_VFP_set_vreg:
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vA/vA+1<- v0/v1
+#else
+ LOAD_F(fa0, a1) # fa0<- vB
+ # optional op
+ cvt.d.w fv0, fa0
+
+.LTEMPLATE_INT_TO_DOUBLE_VFP_set_vreg:
+ STORE64_F(fv0, fv0f, rOBJ) # vA/vA+1<- fv0/fv0f
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INT_TO_FLOAT_VFP
+dvmCompiler_TEMPLATE_INT_TO_FLOAT_VFP:
+/* File: mips/TEMPLATE_INT_TO_FLOAT_VFP.S */
+/* File: mips/funop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: int-to-float, float-to-int
+ *
+ * On entry:
+ * a0 = target dalvik register address
+ * a1 = src dalvik register address
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ *
+ */
+ move rOBJ, a0 # save a0
+#ifdef SOFT_FLOAT
+ LOAD(a0, a1) # a0<- vBB
+ # optional op
+ JAL(__floatsisf) # v0<- op, a0-a3 changed
+.LTEMPLATE_INT_TO_FLOAT_VFP_set_vreg:
+ STORE(v0, rOBJ) # vAA<- v0
+#else
+ LOAD_F(fa0, a1) # fa0<- vBB
+ # optional op
+ cvt.s.w fv0, fa0 # fv0 = result
+.LTEMPLATE_INT_TO_FLOAT_VFP_set_vreg_f:
+ STORE_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPG_DOUBLE_VFP
+dvmCompiler_TEMPLATE_CMPG_DOUBLE_VFP:
+/* File: mips/TEMPLATE_CMPG_DOUBLE_VFP.S */
+/* File: mips/TEMPLATE_CMPL_DOUBLE_VFP.S */
+ /*
+ * Compare two double precision floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * On entry:
+ * a0 = &op1 [vBB]
+ * a1 = &op2 [vCC]
+ *
+ * for: cmpl-double, cmpg-double
+ */
+ /* op vAA, vBB, vCC */
+
+ /* "clasic" form */
+#ifdef SOFT_FLOAT
+ move rOBJ, a0 # save a0
+ move rBIX, a1 # save a1
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3<- vCC/vCC+1
+ JAL(__eqdf2) # v0<- (vBB == vCC)
+ li rTEMP, 0 # vAA<- 0
+ beqz v0, TEMPLATE_CMPG_DOUBLE_VFP_finish
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3<- vCC/vCC+1
+ JAL(__ltdf2) # a0<- (vBB < vCC)
+ li rTEMP, -1 # vAA<- -1
+ bltz v0, TEMPLATE_CMPG_DOUBLE_VFP_finish
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3<- vCC/vCC+1
+ JAL(__gtdf2) # v0<- (vBB > vCC)
+ li rTEMP, 1 # vAA<- 1
+ bgtz v0, TEMPLATE_CMPG_DOUBLE_VFP_finish
+#else
+ LOAD64_F(fs0, fs0f, a0) # fs0<- vBB
+ LOAD64_F(fs1, fs1f, a1) # fs1<- vCC
+ c.olt.d fcc0, fs0, fs1 # Is fs0 < fs1
+ li rTEMP, -1
+ bc1t fcc0, TEMPLATE_CMPG_DOUBLE_VFP_finish
+ c.olt.d fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, TEMPLATE_CMPG_DOUBLE_VFP_finish
+ c.eq.d fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, TEMPLATE_CMPG_DOUBLE_VFP_finish
+#endif
+
+ li rTEMP, 1
+
+TEMPLATE_CMPG_DOUBLE_VFP_finish:
+ move v0, rTEMP # v0<- vAA
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
+dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP:
+/* File: mips/TEMPLATE_CMPL_DOUBLE_VFP.S */
+ /*
+ * Compare two double precision floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * On entry:
+ * a0 = &op1 [vBB]
+ * a1 = &op2 [vCC]
+ *
+ * for: cmpl-double, cmpg-double
+ */
+ /* op vAA, vBB, vCC */
+
+ /* "clasic" form */
+#ifdef SOFT_FLOAT
+ move rOBJ, a0 # save a0
+ move rBIX, a1 # save a1
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3<- vCC/vCC+1
+ JAL(__eqdf2) # v0<- (vBB == vCC)
+ li rTEMP, 0 # vAA<- 0
+ beqz v0, TEMPLATE_CMPL_DOUBLE_VFP_finish
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3<- vCC/vCC+1
+ JAL(__ltdf2) # a0<- (vBB < vCC)
+ li rTEMP, -1 # vAA<- -1
+ bltz v0, TEMPLATE_CMPL_DOUBLE_VFP_finish
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1<- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3<- vCC/vCC+1
+ JAL(__gtdf2) # v0<- (vBB > vCC)
+ li rTEMP, 1 # vAA<- 1
+ bgtz v0, TEMPLATE_CMPL_DOUBLE_VFP_finish
+#else
+ LOAD64_F(fs0, fs0f, a0) # fs0<- vBB
+ LOAD64_F(fs1, fs1f, a1) # fs1<- vCC
+ c.olt.d fcc0, fs0, fs1 # Is fs0 < fs1
+ li rTEMP, -1
+ bc1t fcc0, TEMPLATE_CMPL_DOUBLE_VFP_finish
+ c.olt.d fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, TEMPLATE_CMPL_DOUBLE_VFP_finish
+ c.eq.d fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, TEMPLATE_CMPL_DOUBLE_VFP_finish
+#endif
+
+ li rTEMP, -1
+
+TEMPLATE_CMPL_DOUBLE_VFP_finish:
+ move v0, rTEMP # v0<- vAA
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPG_FLOAT_VFP
+dvmCompiler_TEMPLATE_CMPG_FLOAT_VFP:
+/* File: mips/TEMPLATE_CMPG_FLOAT_VFP.S */
+/* File: mips/TEMPLATE_CMPL_FLOAT_VFP.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * On entry:
+ * a0 = &op1 [vBB]
+ * a1 = &op2 [vCC]
+ *
+ * for: cmpl-float, cmpg-float
+ */
+ /* op vAA, vBB, vCC */
+
+ /* "clasic" form */
+#ifdef SOFT_FLOAT
+ LOAD(rOBJ, a0) # rOBJ<- vBB
+ LOAD(rBIX, a1) # rBIX<- vCC
+ move a0, rOBJ # a0<- vBB
+ move a1, rBIX # a1<- vCC
+ JAL(__eqsf2) # v0<- (vBB == vCC)
+ li rTEMP, 0 # vAA<- 0
+ beqz v0, TEMPLATE_CMPG_FLOAT_VFP_finish
+ move a0, rOBJ # a0<- vBB
+ move a1, rBIX # a1<- vCC
+ JAL(__ltsf2) # a0<- (vBB < vCC)
+ li rTEMP, -1 # vAA<- -1
+ bltz v0, TEMPLATE_CMPG_FLOAT_VFP_finish
+ move a0, rOBJ # a0<- vBB
+ move a1, rBIX # a1<- vCC
+ JAL(__gtsf2) # v0<- (vBB > vCC)
+ li rTEMP, 1 # vAA<- 1
+ bgtz v0, TEMPLATE_CMPG_FLOAT_VFP_finish
+#else
+ LOAD_F(fs0, a0) # fs0<- vBB
+ LOAD_F(fs1, a1) # fs1<- vCC
+ c.olt.s fcc0, fs0, fs1 #Is fs0 < fs1
+ li rTEMP, -1
+ bc1t fcc0, TEMPLATE_CMPG_FLOAT_VFP_finish
+ c.olt.s fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, TEMPLATE_CMPG_FLOAT_VFP_finish
+ c.eq.s fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, TEMPLATE_CMPG_FLOAT_VFP_finish
+#endif
+
+ li rTEMP, 1
+
+TEMPLATE_CMPG_FLOAT_VFP_finish:
+ move v0, rTEMP # v0<- vAA
+ RETURN
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPL_FLOAT_VFP
+dvmCompiler_TEMPLATE_CMPL_FLOAT_VFP:
+/* File: mips/TEMPLATE_CMPL_FLOAT_VFP.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * On entry:
+ * a0 = &op1 [vBB]
+ * a1 = &op2 [vCC]
+ *
+ * for: cmpl-float, cmpg-float
+ */
+ /* op vAA, vBB, vCC */
+
+ /* "clasic" form */
+#ifdef SOFT_FLOAT
+ LOAD(rOBJ, a0) # rOBJ<- vBB
+ LOAD(rBIX, a1) # rBIX<- vCC
+ move a0, rOBJ # a0<- vBB
+ move a1, rBIX # a1<- vCC
+ JAL(__eqsf2) # v0<- (vBB == vCC)
+ li rTEMP, 0 # vAA<- 0
+ beqz v0, TEMPLATE_CMPL_FLOAT_VFP_finish
+ move a0, rOBJ # a0<- vBB
+ move a1, rBIX # a1<- vCC
+ JAL(__ltsf2) # a0<- (vBB < vCC)
+ li rTEMP, -1 # vAA<- -1
+ bltz v0, TEMPLATE_CMPL_FLOAT_VFP_finish
+ move a0, rOBJ # a0<- vBB
+ move a1, rBIX # a1<- vCC
+ JAL(__gtsf2) # v0<- (vBB > vCC)
+ li rTEMP, 1 # vAA<- 1
+ bgtz v0, TEMPLATE_CMPL_FLOAT_VFP_finish
+#else
+ LOAD_F(fs0, a0) # fs0<- vBB
+ LOAD_F(fs1, a1) # fs1<- vCC
+ c.olt.s fcc0, fs0, fs1 #Is fs0 < fs1
+ li rTEMP, -1
+ bc1t fcc0, TEMPLATE_CMPL_FLOAT_VFP_finish
+ c.olt.s fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, TEMPLATE_CMPL_FLOAT_VFP_finish
+ c.eq.s fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, TEMPLATE_CMPL_FLOAT_VFP_finish
+#endif
+
+ li rTEMP, -1
+
+TEMPLATE_CMPL_FLOAT_VFP_finish:
+ move v0, rTEMP # v0<- vAA
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP
+dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP:
+/* File: mips/TEMPLATE_SQRT_DOUBLE_VFP.S */
+
+ /*
+ * 64-bit floating point sqrt operation.
+ * If the result is a NaN, bail out to library code to do
+ * the right thing.
+ *
+ * On entry:
+ * a2 src addr of op1
+ * On exit:
+ * v0,v1/fv0 = res
+ */
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a2) # a0/a1<- vBB/vBB+1
+#else
+ LOAD64_F(fa0, fa0f, a2) # fa0/fa0f<- vBB/vBB+1
+ sqrt.d fv0, fa0
+ c.eq.d fv0, fv0
+ bc1t 1f
+#endif
+ JAL(sqrt)
+1:
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
+dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
+/* File: mips/TEMPLATE_THROW_EXCEPTION_COMMON.S */
+ /*
+ * Throw an exception from JIT'ed code.
+ * On entry:
+ * a0 Dalvik PC that raises the exception
+ */
+ j .LhandleException
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_MEM_OP_DECODE
+dvmCompiler_TEMPLATE_MEM_OP_DECODE:
+/* File: mips/TEMPLATE_MEM_OP_DECODE.S */
+#if defined(WITH_SELF_VERIFICATION)
+ /*
+ * This handler encapsulates heap memory ops for selfVerification mode.
+ *
+ * The call to the handler is inserted prior to a heap memory operation.
+ * This handler then calls a function to decode the memory op, and process
+ * it accordingly. Afterwards, the handler changes the return address to
+ * skip the memory op so it never gets executed.
+ */
+#ifdef HARD_FLOAT
+ /* push f0-f31 onto stack */
+ sw f0, fr0*-4(sp) # push f0
+ sw f1, fr1*-4(sp) # push f1
+ sw f2, fr2*-4(sp) # push f2
+ sw f3, fr3*-4(sp) # push f3
+ sw f4, fr4*-4(sp) # push f4
+ sw f5, fr5*-4(sp) # push f5
+ sw f6, fr6*-4(sp) # push f6
+ sw f7, fr7*-4(sp) # push f7
+ sw f8, fr8*-4(sp) # push f8
+ sw f9, fr9*-4(sp) # push f9
+ sw f10, fr10*-4(sp) # push f10
+ sw f11, fr11*-4(sp) # push f11
+ sw f12, fr12*-4(sp) # push f12
+ sw f13, fr13*-4(sp) # push f13
+ sw f14, fr14*-4(sp) # push f14
+ sw f15, fr15*-4(sp) # push f15
+ sw f16, fr16*-4(sp) # push f16
+ sw f17, fr17*-4(sp) # push f17
+ sw f18, fr18*-4(sp) # push f18
+ sw f19, fr19*-4(sp) # push f19
+ sw f20, fr20*-4(sp) # push f20
+ sw f21, fr21*-4(sp) # push f21
+ sw f22, fr22*-4(sp) # push f22
+ sw f23, fr23*-4(sp) # push f23
+ sw f24, fr24*-4(sp) # push f24
+ sw f25, fr25*-4(sp) # push f25
+ sw f26, fr26*-4(sp) # push f26
+ sw f27, fr27*-4(sp) # push f27
+ sw f28, fr28*-4(sp) # push f28
+ sw f29, fr29*-4(sp) # push f29
+ sw f30, fr30*-4(sp) # push f30
+ sw f31, fr31*-4(sp) # push f31
+
+ sub sp, (32-0)*4 # adjust stack pointer
+#endif
+
+ /* push gp registers (except zero, gp, sp, and fp) */
+ .set noat
+ sw AT, r_AT*-4(sp) # push at
+ .set at
+ sw v0, r_V0*-4(sp) # push v0
+ sw v1, r_V1*-4(sp) # push v1
+ sw a0, r_A0*-4(sp) # push a0
+ sw a1, r_A1*-4(sp) # push a1
+ sw a2, r_A2*-4(sp) # push a2
+ sw a3, r_A3*-4(sp) # push a3
+ sw t0, r_T0*-4(sp) # push t0
+ sw t1, r_T1*-4(sp) # push t1
+ sw t2, r_T2*-4(sp) # push t2
+ sw t3, r_T3*-4(sp) # push t3
+ sw t4, r_T4*-4(sp) # push t4
+ sw t5, r_T5*-4(sp) # push t5
+ sw t6, r_T6*-4(sp) # push t6
+ sw t7, r_T7*-4(sp) # push t7
+ sw s0, r_S0*-4(sp) # push s0
+ sw s1, r_S1*-4(sp) # push s1
+ sw s2, r_S2*-4(sp) # push s2
+ sw s3, r_S3*-4(sp) # push s3
+ sw s4, r_S4*-4(sp) # push s4
+ sw s5, r_S5*-4(sp) # push s5
+ sw s6, r_S6*-4(sp) # push s6
+ sw s7, r_S7*-4(sp) # push s7
+ sw t8, r_T8*-4(sp) # push t8
+ sw t9, r_T9*-4(sp) # push t9
+ sw k0, r_K0*-4(sp) # push k0
+ sw k1, r_K1*-4(sp) # push k1
+ sw ra, r_RA*-4(sp) # push RA
+
+ # Note: even if we don't save all 32 registers, we still need to
+ # adjust SP by 32 registers due to the way we are storing
+ # the registers on the stack.
+ sub sp, (32-0)*4 # adjust stack pointer
+
+ la a2, .LdvmSelfVerificationMemOpDecode # defined in footer.S
+ lw a2, (a2)
+ move a0, ra # a0<- link register
+ move a1, sp # a1<- stack pointer
+ JALR(a2)
+
+ /* pop gp registers (except zero, gp, sp, and fp) */
+ # Note: even if we don't save all 32 registers, we still need to
+ # adjust SP by 32 registers due to the way we are storing
+ # the registers on the stack.
+ add sp, (32-0)*4 # adjust stack pointer
+ .set noat
+ lw AT, r_AT*-4(sp) # pop at
+ .set at
+ lw v0, r_V0*-4(sp) # pop v0
+ lw v1, r_V1*-4(sp) # pop v1
+ lw a0, r_A0*-4(sp) # pop a0
+ lw a1, r_A1*-4(sp) # pop a1
+ lw a2, r_A2*-4(sp) # pop a2
+ lw a3, r_A3*-4(sp) # pop a3
+ lw t0, r_T0*-4(sp) # pop t0
+ lw t1, r_T1*-4(sp) # pop t1
+ lw t2, r_T2*-4(sp) # pop t2
+ lw t3, r_T3*-4(sp) # pop t3
+ lw t4, r_T4*-4(sp) # pop t4
+ lw t5, r_T5*-4(sp) # pop t5
+ lw t6, r_T6*-4(sp) # pop t6
+ lw t7, r_T7*-4(sp) # pop t7
+ lw s0, r_S0*-4(sp) # pop s0
+ lw s1, r_S1*-4(sp) # pop s1
+ lw s2, r_S2*-4(sp) # pop s2
+ lw s3, r_S3*-4(sp) # pop s3
+ lw s4, r_S4*-4(sp) # pop s4
+ lw s5, r_S5*-4(sp) # pop s5
+ lw s6, r_S6*-4(sp) # pop s6
+ lw s7, r_S7*-4(sp) # pop s7
+ lw t8, r_T8*-4(sp) # pop t8
+ lw t9, r_T9*-4(sp) # pop t9
+ lw k0, r_K0*-4(sp) # pop k0
+ lw k1, r_K1*-4(sp) # pop k1
+ lw ra, r_RA*-4(sp) # pop RA
+
+#ifdef HARD_FLOAT
+ /* pop f0-f31 from stack */
+ add sp, (32-0)*4 # adjust stack pointer
+ lw f0, fr0*-4(sp) # pop f0
+ lw f1, fr1*-4(sp) # pop f1
+ lw f2, fr2*-4(sp) # pop f2
+ lw f3, fr3*-4(sp) # pop f3
+ lw f4, fr4*-4(sp) # pop f4
+ lw f5, fr5*-4(sp) # pop f5
+ lw f6, fr6*-4(sp) # pop f6
+ lw f7, fr7*-4(sp) # pop f7
+ lw f8, fr8*-4(sp) # pop f8
+ lw f9, fr9*-4(sp) # pop f9
+ lw f10, fr10*-4(sp) # pop f10
+ lw f11, fr11*-4(sp) # pop f11
+ lw f12, fr12*-4(sp) # pop f12
+ lw f13, fr13*-4(sp) # pop f13
+ lw f14, fr14*-4(sp) # pop f14
+ lw f15, fr15*-4(sp) # pop f15
+ lw f16, fr16*-4(sp) # pop f16
+ lw f17, fr17*-4(sp) # pop f17
+ lw f18, fr18*-4(sp) # pop f18
+ lw f19, fr19*-4(sp) # pop f19
+ lw f20, fr20*-4(sp) # pop f20
+ lw f21, fr21*-4(sp) # pop f21
+ lw f22, fr22*-4(sp) # pop f22
+ lw f23, fr23*-4(sp) # pop f23
+ lw f24, fr24*-4(sp) # pop f24
+ lw f25, fr25*-4(sp) # pop f25
+ lw f26, fr26*-4(sp) # pop f26
+ lw f27, fr27*-4(sp) # pop f27
+ lw f28, fr28*-4(sp) # pop f28
+ lw f29, fr29*-4(sp) # pop f29
+ lw f30, fr30*-4(sp) # pop f30
+ lw f31, fr31*-4(sp) # pop f31
+#endif
+
+ RETURN
+#endif
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_STRING_COMPARETO
+dvmCompiler_TEMPLATE_STRING_COMPARETO:
+/* File: mips/TEMPLATE_STRING_COMPARETO.S */
+ /*
+ * String's compareTo.
+ *
+ * Requires a0/a1 to have been previously checked for null. Will
+ * return negative if this's string is < comp, 0 if they are the
+ * same and positive if >.
+ *
+ * IMPORTANT NOTE:
+ *
+ * This code relies on hard-coded offsets for string objects, and must be
+ * kept in sync with definitions in UtfString.h. See asm-constants.h
+ *
+ * On entry:
+ * a0: this object pointer
+ * a1: comp object pointer
+ *
+ */
+
+ subu v0, a0, a1 # Same?
+ bnez v0, 1f
+ RETURN
+1:
+ lw t0, STRING_FIELDOFF_OFFSET(a0)
+ lw t1, STRING_FIELDOFF_OFFSET(a1)
+ lw t2, STRING_FIELDOFF_COUNT(a0)
+ lw a2, STRING_FIELDOFF_COUNT(a1)
+ lw a0, STRING_FIELDOFF_VALUE(a0)
+ lw a1, STRING_FIELDOFF_VALUE(a1)
+
+ /*
+ * At this point, we have this/comp:
+ * offset: t0/t1
+ * count: t2/a2
+ * value: a0/a1
+ * We're going to compute
+ * a3 <- countDiff
+ * a2 <- minCount
+ */
+ subu a3, t2, a2 # a3<- countDiff
+ sleu t7, t2, a2
+ movn a2, t2, t7 # a2<- minCount
+
+ /*
+ * Note: data pointers point to first element.
+ */
+ addu a0, 16 # point to contents[0]
+ addu a1, 16 # point to contents[0]
+
+ /* Now, build pointers to the string data */
+ sll t7, t0, 1 # multiply offset by 2
+ addu a0, a0, t7
+ sll t7, t1, 1 # multiply offset by 2
+ addu a1, a1, t7
+
+ /*
+ * At this point we have:
+ * a0: *this string data
+ * a1: *comp string data
+ * a2: iteration count for comparison
+ * a3: value to return if the first part of the string is equal
+ * v0: reserved for result
+ * t0-t5 available for loading string data
+ */
+
+ subu a2, 2
+ bltz a2, do_remainder2
+
+ /*
+ * Unroll the first two checks so we can quickly catch early mismatch
+ * on long strings (but preserve incoming alignment)
+ */
+ lhu t0, 0(a0)
+ lhu t1, 0(a1)
+ subu v0, t0, t1
+ beqz v0, 1f
+ RETURN
+1:
+ lhu t2, 2(a0)
+ lhu t3, 2(a1)
+ subu v0, t2, t3
+ beqz v0, 2f
+ RETURN
+2:
+ addu a0, 4 # offset to contents[2]
+ addu a1, 4 # offset to contents[2]
+ li t7, 28
+ bgt a2, t7, do_memcmp16
+ subu a2, 3
+ bltz a2, do_remainder
+
+loopback_triple:
+ lhu t0, 0(a0)
+ lhu t1, 0(a1)
+ subu v0, t0, t1
+ beqz v0, 1f
+ RETURN
+1:
+ lhu t2, 2(a0)
+ lhu t3, 2(a1)
+ subu v0, t2, t3
+ beqz v0, 2f
+ RETURN
+2:
+ lhu t4, 4(a0)
+ lhu t5, 4(a1)
+ subu v0, t4, t5
+ beqz v0, 3f
+ RETURN
+3:
+ addu a0, 6 # offset to contents[i+3]
+ addu a1, 6 # offset to contents[i+3]
+ subu a2, 3
+ bgez a2, loopback_triple
+
+do_remainder:
+ addu a2, 3
+ beqz a2, returnDiff
+
+loopback_single:
+ lhu t0, 0(a0)
+ lhu t1, 0(a1)
+ subu v0, t0, t1
+ bnez v0, 1f
+ addu a0, 2 # offset to contents[i+1]
+ addu a1, 2 # offset to contents[i+1]
+ subu a2, 1
+ bnez a2, loopback_single
+
+returnDiff:
+ move v0, a3
+1:
+ RETURN
+
+do_remainder2:
+ addu a2, 2
+ bnez a2, loopback_single
+ move v0, a3
+ RETURN
+
+ /* Long string case */
+do_memcmp16:
+ move rOBJ, a3 # save return value if strings are equal
+ JAL(__memcmp16)
+ seq t0, v0, zero
+ movn v0, rOBJ, t0 # overwrite return value if strings are equal
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_STRING_INDEXOF
+dvmCompiler_TEMPLATE_STRING_INDEXOF:
+/* File: mips/TEMPLATE_STRING_INDEXOF.S */
+ /*
+ * String's indexOf.
+ *
+ * Requires a0 to have been previously checked for null. Will
+ * return index of match of a1 in v0.
+ *
+ * IMPORTANT NOTE:
+ *
+ * This code relies on hard-coded offsets for string objects, and must be
+ * kept in sync wth definitions in UtfString.h See asm-constants.h
+ *
+ * On entry:
+ * a0: string object pointer
+ * a1: char to match
+ * a2: Starting offset in string data
+ */
+
+ lw t0, STRING_FIELDOFF_OFFSET(a0)
+ lw t1, STRING_FIELDOFF_COUNT(a0)
+ lw v0, STRING_FIELDOFF_VALUE(a0)
+
+ /*
+ * At this point, we have:
+ * v0: object pointer
+ * a1: char to match
+ * a2: starting offset
+ * t0: offset
+ * t1: string length
+ */
+
+ /* Point to first element */
+ addu v0, 16 # point to contents[0]
+
+ /* Build pointer to start of string data */
+ sll t7, t0, 1 # multiply offset by 2
+ addu v0, v0, t7
+
+ /* Save a copy of starting data in v1 */
+ move v1, v0
+
+ /* Clamp start to [0..count] */
+ slt t7, a2, zero
+ movn a2, zero, t7
+ sgt t7, a2, t1
+ movn a2, t1, t7
+
+ /* Build pointer to start of data to compare */
+ sll t7, a2, 1 # multiply offset by 2
+ addu v0, v0, t7
+
+ /* Compute iteration count */
+ subu a3, t1, a2
+
+ /*
+ * At this point we have:
+ * v0: start of data to test
+ * a1: char to compare
+ * a3: iteration count
+ * v1: original start of string
+ * t0-t7 available for loading string data
+ */
+ subu a3, 4
+ bltz a3, indexof_remainder
+
+indexof_loop4:
+ lhu t0, 0(v0)
+ beq t0, a1, match_0
+ lhu t0, 2(v0)
+ beq t0, a1, match_1
+ lhu t0, 4(v0)
+ beq t0, a1, match_2
+ lhu t0, 6(v0)
+ beq t0, a1, match_3
+ addu v0, 8 # offset to contents[i+4]
+ subu a3, 4
+ bgez a3, indexof_loop4
+
+indexof_remainder:
+ addu a3, 4
+ beqz a3, indexof_nomatch
+
+indexof_loop1:
+ lhu t0, 0(v0)
+ beq t0, a1, match_0
+ addu v0, 2 # offset to contents[i+1]
+ subu a3, 1
+ bnez a3, indexof_loop1
+
+indexof_nomatch:
+ li v0, -1
+ RETURN
+
+match_0:
+ subu v0, v1
+ sra v0, v0, 1 # divide by 2
+ RETURN
+match_1:
+ addu v0, 2
+ subu v0, v1
+ sra v0, v0, 1 # divide by 2
+ RETURN
+match_2:
+ addu v0, 4
+ subu v0, v1
+ sra v0, v0, 1 # divide by 2
+ RETURN
+match_3:
+ addu v0, 6
+ subu v0, v1
+ sra v0, v0, 1 # divide by 2
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INTERPRET
+dvmCompiler_TEMPLATE_INTERPRET:
+/* File: mips/TEMPLATE_INTERPRET.S */
+ /*
+ * This handler transfers control to the interpeter without performing
+ * any lookups. It may be called either as part of a normal chaining
+ * operation, or from the transition code in header.S. We distinquish
+ * the two cases by looking at the link register. If called from a
+ * translation chain, it will point to the chaining Dalvik PC.
+ * On entry:
+ * ra - if NULL:
+ * a1 - the Dalvik PC to begin interpretation.
+ * else
+ * [ra] contains Dalvik PC to begin interpretation
+ * rSELF - pointer to thread
+ * rFP - Dalvik frame pointer
+ */
+ la t0, dvmJitToInterpPunt
+ move a0, a1
+ beq ra, zero, 1f
+ lw a0, 0(ra)
+1:
+ jr t0
+ # doesn't return
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_MONITOR_ENTER
+dvmCompiler_TEMPLATE_MONITOR_ENTER:
+/* File: mips/TEMPLATE_MONITOR_ENTER.S */
+ /*
+ * Call out to the runtime to lock an object. Because this thread
+ * may have been suspended in THREAD_MONITOR state and the Jit's
+ * translation cache subsequently cleared, we cannot return directly.
+ * Instead, unconditionally transition to the interpreter to resume.
+ *
+ * On entry:
+ * a0 - self pointer
+ * a1 - the object (which has already been null-checked by the caller
+ * rPC - the Dalvik PC of the following instruction.
+ */
+ la a2, .LdvmLockObject
+ lw t9, (a2)
+ sw zero, offThread_inJitCodeCache(a0) # record that we're not returning
+ JALR(t9) # dvmLockObject(self, obj)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ la a2, .LdvmJitToInterpNoChain
+ lw a2, (a2)
+
+ # Bail to interpreter - no chain [note - rPC still contains dPC]
+#if defined(WITH_JIT_TUNING)
+ li a0, kHeavyweightMonitor
+#endif
+ jr a2
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
+dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
+/* File: mips/TEMPLATE_MONITOR_ENTER_DEBUG.S */
+ /*
+ * To support deadlock prediction, this version of MONITOR_ENTER
+ * will always call the heavyweight dvmLockObject, check for an
+ * exception and then bail out to the interpreter.
+ *
+ * On entry:
+ * a0 - self pointer
+ * a1 - the object (which has already been null-checked by the caller
+ * rPC - the Dalvik PC of the following instruction.
+ *
+ */
+ la a2, .LdvmLockObject
+ lw t9, (a2)
+ sw zero, offThread_inJitCodeCache(a0) # record that we're not returning
+ JALR(t9) # dvmLockObject(self, obj)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # test for exception
+ lw a1, offThread_exception(rSELF)
+ beqz a1, 1f
+ sub a0, rPC, 2 # roll dPC back to this monitor instruction
+ j .LhandleException
+1:
+ # Bail to interpreter - no chain [note - rPC still contains dPC]
+#if defined(WITH_JIT_TUNING)
+ li a0, kHeavyweightMonitor
+#endif
+ la a2, .LdvmJitToInterpNoChain
+ lw a2, (a2)
+ jr a2
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_RESTORE_STATE
+dvmCompiler_TEMPLATE_RESTORE_STATE:
+/* File: mips/TEMPLATE_RESTORE_STATE.S */
+ /*
+ * This handler restores state following a selfVerification memory access.
+ * On entry:
+ * a0 - offset from rSELF to the 1st element of the coreRegs save array.
+ * Note: the following registers are not restored
+ * zero, AT, gp, sp, fp, ra
+ */
+
+ add a0, a0, rSELF # pointer to heapArgSpace.coreRegs[0]
+#if 0
+ lw zero, r_ZERO*4(a0) # restore zero
+#endif
+ .set noat
+ lw AT, r_AT*4(a0) # restore at
+ .set at
+ lw v0, r_V0*4(a0) # restore v0
+ lw v1, r_V1*4(a0) # restore v1
+
+ lw a1, r_A1*4(a0) # restore a1
+ lw a2, r_A2*4(a0) # restore a2
+ lw a3, r_A3*4(a0) # restore a3
+
+ lw t0, r_T0*4(a0) # restore t0
+ lw t1, r_T1*4(a0) # restore t1
+ lw t2, r_T2*4(a0) # restore t2
+ lw t3, r_T3*4(a0) # restore t3
+ lw t4, r_T4*4(a0) # restore t4
+ lw t5, r_T5*4(a0) # restore t5
+ lw t6, r_T6*4(a0) # restore t6
+ lw t7, r_T7*4(a0) # restore t7
+
+ lw s0, r_S0*4(a0) # restore s0
+ lw s1, r_S1*4(a0) # restore s1
+ lw s2, r_S2*4(a0) # restore s2
+ lw s3, r_S3*4(a0) # restore s3
+ lw s4, r_S4*4(a0) # restore s4
+ lw s5, r_S5*4(a0) # restore s5
+ lw s6, r_S6*4(a0) # restore s6
+ lw s7, r_S7*4(a0) # restore s7
+
+ lw t8, r_T8*4(a0) # restore t8
+ lw t9, r_T9*4(a0) # restore t9
+
+ lw k0, r_K0*4(a0) # restore k0
+ lw k1, r_K1*4(a0) # restore k1
+
+#if 0
+ lw gp, r_GP*4(a0) # restore gp
+ lw sp, r_SP*4(a0) # restore sp
+ lw fp, r_FP*4(a0) # restore fp
+ lw ra, r_RA*4(a0) # restore ra
+#endif
+
+/* #ifdef HARD_FLOAT */
+#if 0
+ lw f0, fr0*4(a0) # restore f0
+ lw f1, fr1*4(a0) # restore f1
+ lw f2, fr2*4(a0) # restore f2
+ lw f3, fr3*4(a0) # restore f3
+ lw f4, fr4*4(a0) # restore f4
+ lw f5, fr5*4(a0) # restore f5
+ lw f6, fr6*4(a0) # restore f6
+ lw f7, fr7*4(a0) # restore f7
+ lw f8, fr8*4(a0) # restore f8
+ lw f9, fr9*4(a0) # restore f9
+ lw f10, fr10*4(a0) # restore f10
+ lw f11, fr11*4(a0) # restore f11
+ lw f12, fr12*4(a0) # restore f12
+ lw f13, fr13*4(a0) # restore f13
+ lw f14, fr14*4(a0) # restore f14
+ lw f15, fr15*4(a0) # restore f15
+ lw f16, fr16*4(a0) # restore f16
+ lw f17, fr17*4(a0) # restore f17
+ lw f18, fr18*4(a0) # restore f18
+ lw f19, fr19*4(a0) # restore f19
+ lw f20, fr20*4(a0) # restore f20
+ lw f21, fr21*4(a0) # restore f21
+ lw f22, fr22*4(a0) # restore f22
+ lw f23, fr23*4(a0) # restore f23
+ lw f24, fr24*4(a0) # restore f24
+ lw f25, fr25*4(a0) # restore f25
+ lw f26, fr26*4(a0) # restore f26
+ lw f27, fr27*4(a0) # restore f27
+ lw f28, fr28*4(a0) # restore f28
+ lw f29, fr29*4(a0) # restore f29
+ lw f30, fr30*4(a0) # restore f30
+ lw f31, fr31*4(a0) # restore f31
+#endif
+
+ lw a0, r_A1*4(a0) # restore a0
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_SAVE_STATE
+dvmCompiler_TEMPLATE_SAVE_STATE:
+/* File: mips/TEMPLATE_SAVE_STATE.S */
+ /*
+ * This handler performs a register save for selfVerification mode.
+ * On entry:
+ * Top of stack + 4: a1 value to save
+ * Top of stack + 0: a0 value to save
+ * a0 - offset from rSELF to the beginning of the heapArgSpace record
+ * a1 - the value of regMap
+ *
+ * The handler must save regMap, r0-r31, f0-f31 if FPU, and then return with
+ * r0-r31 with their original values (note that this means a0 and a1 must take
+ * the values on the stack - not the ones in those registers on entry.
+ * Finally, the two registers previously pushed must be popped.
+ * Note: the following registers are not saved
+ * zero, AT, gp, sp, fp, ra
+ */
+ add a0, a0, rSELF # pointer to heapArgSpace
+ sw a1, 0(a0) # save regMap
+ add a0, a0, 4 # pointer to coreRegs
+#if 0
+ sw zero, r_ZERO*4(a0) # save zero
+#endif
+ .set noat
+ sw AT, r_AT*4(a0) # save at
+ .set at
+ sw v0, r_V0*4(a0) # save v0
+ sw v1, r_V1*4(a0) # save v1
+
+ lw a1, 0(sp) # recover a0 value
+ sw a1, r_A0*4(a0) # save a0
+ lw a1, 4(sp) # recover a1 value
+ sw a1, r_A1*4(a0) # save a1
+ sw a2, r_A2*4(a0) # save a2
+ sw a3, r_A3*4(a0) # save a3
+
+ sw t0, r_T0*4(a0) # save t0
+ sw t1, r_T1*4(a0) # save t1
+ sw t2, r_T2*4(a0) # save t2
+ sw t3, r_T3*4(a0) # save t3
+ sw t4, r_T4*4(a0) # save t4
+ sw t5, r_T5*4(a0) # save t5
+ sw t6, r_T6*4(a0) # save t6
+ sw t7, r_T7*4(a0) # save t7
+
+ sw s0, r_S0*4(a0) # save s0
+ sw s1, r_S1*4(a0) # save s1
+ sw s2, r_S2*4(a0) # save s2
+ sw s3, r_S3*4(a0) # save s3
+ sw s4, r_S4*4(a0) # save s4
+ sw s5, r_S5*4(a0) # save s5
+ sw s6, r_S6*4(a0) # save s6
+ sw s7, r_S7*4(a0) # save s7
+
+ sw t8, r_T8*4(a0) # save t8
+ sw t9, r_T9*4(a0) # save t9
+
+ sw k0, r_K0*4(a0) # save k0
+ sw k1, r_K1*4(a0) # save k1
+
+#if 0
+ sw gp, r_GP*4(a0) # save gp
+ sw sp, r_SP*4(a0) # save sp (need to adjust??? )
+ sw fp, r_FP*4(a0) # save fp
+ sw ra, r_RA*4(a0) # save ra
+#endif
+
+/* #ifdef HARD_FLOAT */
+#if 0
+ sw f0, fr0*4(a0) # save f0
+ sw f1, fr1*4(a0) # save f1
+ sw f2, fr2*4(a0) # save f2
+ sw f3, fr3*4(a0) # save f3
+ sw f4, fr4*4(a0) # save f4
+ sw f5, fr5*4(a0) # save f5
+ sw f6, fr6*4(a0) # save f6
+ sw f7, fr7*4(a0) # save f7
+ sw f8, fr8*4(a0) # save f8
+ sw f9, fr9*4(a0) # save f9
+ sw f10, fr10*4(a0) # save f10
+ sw f11, fr11*4(a0) # save f11
+ sw f12, fr12*4(a0) # save f12
+ sw f13, fr13*4(a0) # save f13
+ sw f14, fr14*4(a0) # save f14
+ sw f15, fr15*4(a0) # save f15
+ sw f16, fr16*4(a0) # save f16
+ sw f17, fr17*4(a0) # save f17
+ sw f18, fr18*4(a0) # save f18
+ sw f19, fr19*4(a0) # save f19
+ sw f20, fr20*4(a0) # save f20
+ sw f21, fr21*4(a0) # save f21
+ sw f22, fr22*4(a0) # save f22
+ sw f23, fr23*4(a0) # save f23
+ sw f24, fr24*4(a0) # save f24
+ sw f25, fr25*4(a0) # save f25
+ sw f26, fr26*4(a0) # save f26
+ sw f27, fr27*4(a0) # save f27
+ sw f28, fr28*4(a0) # save f28
+ sw f29, fr29*4(a0) # save f29
+ sw f30, fr30*4(a0) # save f30
+ sw f31, fr31*4(a0) # save f31
+#endif
+
+ lw a1, 0(sp) # recover a0 value
+ lw a1, 4(sp) # recover a1 value
+ sub sp, sp, 8 # adjust stack ptr
+ RETURN
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_PERIODIC_PROFILING
+dvmCompiler_TEMPLATE_PERIODIC_PROFILING:
+/* File: mips/TEMPLATE_PERIODIC_PROFILING.S */
+ /*
+ * Increment profile counter for this trace, and decrement
+ * sample counter. If sample counter goes below zero, turn
+ * off profiling.
+ *
+ * On entry
+ * (ra-16) is address of pointer to counter. Note: the counter
+ * actually exists 16 bytes before the return target for mips.
+ * - 4 bytes for prof count addr.
+ * - 4 bytes for chain cell offset (2bytes 32 bit aligned).
+ * - 4 bytes for call TEMPLATE_PERIODIC_PROFILING.
+ * - 4 bytes for call delay slot.
+ */
+ lw a0, -16(ra)
+ lw a1, offThread_pProfileCountdown(rSELF)
+ lw a2, 0(a0) # get counter
+ lw a3, 0(a1) # get countdown timer
+ addu a2, 1
+ sub a3, 1 # FIXME - bug in ARM code???
+ bltz a3, .LTEMPLATE_PERIODIC_PROFILING_disable_profiling
+ sw a2, 0(a0)
+ sw a3, 0(a1)
+ RETURN
+.LTEMPLATE_PERIODIC_PROFILING_disable_profiling:
+ move rTEMP, ra # preserve ra
+ la a0, dvmJitTraceProfilingOff
+ JALR(a0)
+ jr rTEMP
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_RETURN_PROF
+dvmCompiler_TEMPLATE_RETURN_PROF:
+/* File: mips/TEMPLATE_RETURN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: mips/TEMPLATE_RETURN.S */
+ /*
+ * Unwind a frame from the Dalvik stack for compiled OP_RETURN_XXX.
+ * If the stored value in returnAddr
+ * is non-zero, the caller is compiled by the JIT thus return to the
+ * address in the code cache following the invoke instruction. Otherwise
+ * return to the special dvmJitToInterpNoChain entry point.
+ */
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # preserve a0-a2 and ra
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(ra, 12)
+
+ # a0=rSELF
+ move a0, rSELF
+ la t9, dvmFastMethodTraceExit
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a2 and ra
+ SCRATCH_LOAD(ra, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+#endif
+ SAVEAREA_FROM_FP(a0, rFP) # a0<- saveArea (old)
+ lw t0, offStackSaveArea_prevFrame(a0) # t0<- saveArea->prevFrame
+ lbu t1, offThread_breakFlags(rSELF) # t1<- breakFlags
+ lw rPC, offStackSaveArea_savedPc(a0) # rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+ lw t2, offStackSaveArea_returnAddr(a0) # t2<- chaining cell ret
+#else
+ move t2, zero # disable chaining
+#endif
+ lw a2, offStackSaveArea_method - sizeofStackSaveArea(t0)
+ # a2<- method we're returning to
+#if !defined(WITH_SELF_VERIFICATION)
+ beq a2, zero, 1f # bail to interpreter
+#else
+ bne a2, zero, 2f
+ JALR(ra) # punt to interpreter and compare state
+ # DOUG: assume this does not return ???
+2:
+#endif
+ la t4, .LdvmJitToInterpNoChainNoProfile # defined in footer.S
+ lw a1, (t4)
+ move rFP, t0 # publish new FP
+ beq a2, zero, 4f
+ lw t0, offMethod_clazz(a2) # t0<- method->clazz
+4:
+
+ sw a2, offThread_method(rSELF) # self->method = newSave->method
+ lw a0, offClassObject_pDvmDex(t0) # a0<- method->clazz->pDvmDex
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = fp
+ add rPC, rPC, 3*2 # publish new rPC
+ sw a0, offThread_methodClassDex(rSELF)
+ movn t2, zero, t1 # check the breadFlags and
+ # clear the chaining cell address
+ sw t2, offThread_inJitCodeCache(rSELF) # in code cache or not
+ beq t2, zero, 3f # chaining cell exists?
+ JALR(t2) # jump to the chaining cell
+ # DOUG: assume this does not return ???
+3:
+#if defined(WITH_JIT_TUNING)
+ li a0, kCallsiteInterpreted
+#endif
+ j a1 # callsite is interpreted
+1:
+ sw zero, offThread_inJitCodeCache(rSELF) # reset inJitCodeCache
+ SAVE_PC_TO_SELF() # SAVE_PC_FP_TO_SELF()
+ SAVE_FP_TO_SELF()
+ la t4, .LdvmMterpStdBail # defined in footer.S
+ lw a2, (t4)
+ move a0, rSELF # Expecting rSELF in a0
+ JALR(a2) # exit the interpreter
+ # DOUG: assume this does not return ???
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF:
+/* File: mips/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: mips/TEMPLATE_INVOKE_METHOD_NO_OPT.S */
+ /*
+ * For polymorphic callsites - setup the Dalvik frame and load Dalvik PC
+ * into rPC then jump to dvmJitToInterpNoChain to dispatch the
+ * runtime-resolved callee.
+ */
+ # a0 = methodToCall, a1 = returnCell, rPC = dalvikCallsite
+ lh t7, offMethod_registersSize(a0) # t7<- methodToCall->regsSize
+ lh a2, offMethod_outsSize(a0) # a2<- methodToCall->outsSize
+ lw t9, offThread_interpStackEnd(rSELF) # t9<- interpStackEnd
+ lbu t8, offThread_breakFlags(rSELF) # t8<- breakFlags
+ move a3, a1 # a3<- returnCell
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- stack save area
+ sll t6, t7, 2 # multiply regsSize by 4 (4 bytes per reg)
+ sub a1, a1, t6 # a1<- newFp(old savearea-regsSize)
+ SAVEAREA_FROM_FP(t0, a1) # t0<- stack save area
+ sll t6, a2, 2 # multiply outsSize by 4 (4 bytes per reg)
+ sub t0, t0, t6 # t0<- bottom (newsave-outsSize)
+ bgeu t0, t9, 1f # bottom < interpStackEnd?
+ RETURN # return to raise stack overflow excep.
+
+1:
+ # a1 = newFP, a0 = methodToCall, a3 = returnCell, rPC = dalvikCallsite
+ lw t9, offMethod_clazz(a0) # t9<- methodToCall->clazz
+ lw t0, offMethod_accessFlags(a0) # t0<- methodToCall->accessFlags
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+ sw rPC, (offStackSaveArea_savedPc - sizeofStackSaveArea)(a1)
+ lw rPC, offMethod_insns(a0) # rPC<- methodToCall->insns
+
+ # set up newSaveArea
+ sw rFP, (offStackSaveArea_prevFrame - sizeofStackSaveArea)(a1)
+ sw a3, (offStackSaveArea_returnAddr - sizeofStackSaveArea)(a1)
+ sw a0, (offStackSaveArea_method - sizeofStackSaveArea)(a1)
+ beqz t8, 2f # breakFlags != 0
+ RETURN # bail to the interpreter
+
+2:
+ and t6, t0, ACC_NATIVE
+ beqz t6, 3f
+#if !defined(WITH_SELF_VERIFICATION)
+ j .LinvokeNative
+#else
+ RETURN # bail to the interpreter
+#endif
+
+3:
+ # continue executing the next instruction through the interpreter
+ la t0, .LdvmJitToInterpTraceSelectNoChain # defined in footer.S
+ lw rTEMP, (t0)
+ lw a3, offClassObject_pDvmDex(t9) # a3<- method->clazz->pDvmDex
+
+ # Update "thread" values for the new method
+ sw a0, offThread_method(rSELF) # self->method = methodToCall
+ sw a3, offThread_methodClassDex(rSELF) # self->methodClassDex = ...
+ move rFP, a1 # fp = newFp
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # preserve a0-a3
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+
+ # a0=methodToCall, a1=rSELF
+ move a1, rSELF
+ la t9, dvmFastMethodTraceEnter
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a3
+ SCRATCH_LOAD(a3, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+#endif
+
+ # Start executing the callee
+#if defined(WITH_JIT_TUNING)
+ li a0, kInlineCacheMiss
+#endif
+ jr rTEMP # dvmJitToInterpTraceSelectNoChain
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF:
+/* File: mips/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: mips/TEMPLATE_INVOKE_METHOD_CHAIN.S */
+ /*
+ * For monomorphic callsite, setup the Dalvik frame and return to the
+ * Thumb code through the link register to transfer control to the callee
+ * method through a dedicated chaining cell.
+ */
+ # a0 = methodToCall, a1 = returnCell, rPC = dalvikCallsite
+ # methodToCall is guaranteed to be non-native
+.LinvokeChainProf:
+ lh t7, offMethod_registersSize(a0) # t7<- methodToCall->regsSize
+ lh a2, offMethod_outsSize(a0) # a2<- methodToCall->outsSize
+ lw t9, offThread_interpStackEnd(rSELF) # t9<- interpStackEnd
+ lbu t8, offThread_breakFlags(rSELF) # t8<- breakFlags
+ move a3, a1 # a3<- returnCell
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- stack save area
+ sll t6, t7, 2 # multiply regsSize by 4 (4 bytes per reg)
+ sub a1, a1, t6 # a1<- newFp(old savearea-regsSize)
+ SAVEAREA_FROM_FP(t0, a1) # t0<- stack save area
+ add t2, ra, 8 # setup the punt-to-interp address
+ # 8 bytes skips branch and delay slot
+ sll t6, a2, 2 # multiply outsSize by 4 (4 bytes per reg)
+ sub t0, t0, t6 # t0<- bottom (newsave-outsSize)
+ bgeu t0, t9, 1f # bottom < interpStackEnd?
+ jr t2 # return to raise stack overflow excep.
+
+1:
+ # a1 = newFP, a0 = methodToCall, a3 = returnCell, rPC = dalvikCallsite
+ lw t9, offMethod_clazz(a0) # t9<- methodToCall->clazz
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+ sw rPC, (offStackSaveArea_savedPc - sizeofStackSaveArea)(a1)
+ lw rPC, offMethod_insns(a0) # rPC<- methodToCall->insns
+
+ # set up newSaveArea
+ sw rFP, (offStackSaveArea_prevFrame - sizeofStackSaveArea)(a1)
+ sw a3, (offStackSaveArea_returnAddr - sizeofStackSaveArea)(a1)
+ sw a0, (offStackSaveArea_method - sizeofStackSaveArea)(a1)
+ beqz t8, 2f # breakFlags != 0
+ jr t2 # bail to the interpreter
+
+2:
+ lw a3, offClassObject_pDvmDex(t9) # a3<- methodToCall->clazz->pDvmDex
+
+ # Update "thread" values for the new method
+ sw a0, offThread_method(rSELF) # self->method = methodToCall
+ sw a3, offThread_methodClassDex(rSELF) # self->methodClassDex = ...
+ move rFP, a1 # fp = newFp
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # preserve a0-a2 and ra
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(ra, 12)
+
+ move a1, rSELF
+ # a0=methodToCall, a1=rSELF
+ la t9, dvmFastMethodTraceEnter
+ jalr t9
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a2 and ra
+ SCRATCH_LOAD(ra, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+#endif
+ RETURN # return to the callee-chaining cell
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF:
+/* File: mips/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: mips/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
+ /*
+ * For polymorphic callsite, check whether the cached class pointer matches
+ * the current one. If so setup the Dalvik frame and return to the
+ * Thumb code through the link register to transfer control to the callee
+ * method through a dedicated chaining cell.
+ *
+ * The predicted chaining cell is declared in ArmLIR.h with the
+ * following layout:
+ *
+ * typedef struct PredictedChainingCell {
+ * u4 branch;
+ * u4 delay_slot;
+ * const ClassObject *clazz;
+ * const Method *method;
+ * u4 counter;
+ * } PredictedChainingCell;
+ *
+ * Upon returning to the callsite:
+ * - lr : to branch to the chaining cell
+ * - lr+8 : to punt to the interpreter
+ * - lr+16: to fully resolve the callee and may rechain.
+ * a3 <- class
+ */
+ # a0 = this, a1 = returnCell, a2 = predictedChainCell, rPC = dalvikCallsite
+ lw a3, offObject_clazz(a0) # a3 <- this->class
+ lw rIBASE, 8(a2) # t0 <- predictedChainCell->clazz
+ lw a0, 12(a2) # a0 <- predictedChainCell->method
+ lw t1, offThread_icRechainCount(rSELF) # t1 <- shared rechainCount
+
+#if defined(WITH_JIT_TUNING)
+ la rINST, .LdvmICHitCount
+ #add t2, t2, 1
+ bne a3, rIBASE, 1f
+ nop
+ lw t2, 0(rINST)
+ add t2, t2, 1
+ sw t2, 0(rINST)
+1:
+ #add t2, t2, 1
+#endif
+ beq a3, rIBASE, .LinvokeChainProf # branch if predicted chain is valid
+ lw rINST, offClassObject_vtable(a3) # rINST <- this->class->vtable
+ beqz rIBASE, 2f # initialized class or not
+ sub a1, t1, 1 # count--
+ sw a1, offThread_icRechainCount(rSELF) # write back to InterpState
+ b 3f
+2:
+ move a1, zero
+3:
+ add ra, ra, 16 # return to fully-resolve landing pad
+ /*
+ * a1 <- count
+ * a2 <- &predictedChainCell
+ * a3 <- this->class
+ * rPC <- dPC
+ * rINST <- this->class->vtable
+ */
+ RETURN
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF:
+/* File: mips/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: mips/TEMPLATE_INVOKE_METHOD_NATIVE.S */
+ # a0 = methodToCall, a1 = returnCell, rPC = dalvikCallsite
+ lh t7, offMethod_registersSize(a0) # t7<- methodToCall->regsSize
+ lw t9, offThread_interpStackEnd(rSELF) # t9<- interpStackEnd
+ lbu t8, offThread_breakFlags(rSELF) # t8<- breakFlags
+ move a3, a1 # a3<- returnCell
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- stack save area
+ sll t6, t7, 2 # multiply regsSize by 4 (4 bytes per reg)
+ sub a1, a1, t6 # a1<- newFp(old savearea-regsSize)
+ SAVEAREA_FROM_FP(t0, a1) # t0<- stack save area
+ bgeu t0, t9, 1f # bottom < interpStackEnd?
+ RETURN # return to raise stack overflow excep.
+
+1:
+ # a1 = newFP, a0 = methodToCall, a3 = returnCell, rPC = dalvikCallsite
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+ sw rPC, (offStackSaveArea_savedPc - sizeofStackSaveArea)(a1)
+ lw rPC, offMethod_insns(a0) # rPC<- methodToCall->insns
+
+ # set up newSaveArea
+ sw rFP, (offStackSaveArea_prevFrame - sizeofStackSaveArea)(a1)
+ sw a3, (offStackSaveArea_returnAddr - sizeofStackSaveArea)(a1)
+ sw a0, (offStackSaveArea_method - sizeofStackSaveArea)(a1)
+ lw rTEMP, offMethod_nativeFunc(a0) # t9<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+ beqz t8, 2f # breakFlags != 0
+ RETURN # bail to the interpreter
+2:
+#else
+ RETURN # bail to the interpreter unconditionally
+#endif
+
+ # go ahead and transfer control to the native code
+ lw t6, offThread_jniLocal_topCookie(rSELF) # t6<- thread->localRef->...
+ sw a1, offThread_curFrame(rSELF) # self->curFrame = newFp
+ sw zero, offThread_inJitCodeCache(rSELF) # not in the jit code cache
+ sw t6, (offStackSaveArea_localRefCookie - sizeofStackSaveArea)(a1)
+ # newFp->localRefCookie=top
+ SAVEAREA_FROM_FP(rBIX, a1) # rBIX<- new stack save area
+ move a2, a0 # a2<- methodToCall
+ move a0, a1 # a0<- newFp
+ add a1, rSELF, offThread_retval # a1<- &retval
+ move a3, rSELF # a3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+ # a2: methodToCall
+ # preserve a0-a3
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+
+ move a0, a2
+ move a1, rSELF
+ # a0=JNIMethod, a1=rSELF
+ la t9, dvmFastMethodTraceEnter
+ JALR(t9) # off to the native code
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a3
+ SCRATCH_LOAD(a3, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+
+ move rOBJ, a2 # save a2
+#endif
+
+ JALR(rTEMP) # off to the native code
+ lw gp, STACK_OFFSET_GP(sp)
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+ move a0, rOBJ
+ move a1, rSELF
+ # a0=JNIMethod, a1=rSELF
+ la t9, dvmFastNativeMethodTraceExit
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+#endif
+
+ # native return; rBIX=newSaveArea
+ # equivalent to dvmPopJniLocals
+ lw a2, offStackSaveArea_returnAddr(rBIX) # a2 = chaining cell ret addr
+ lw a0, offStackSaveArea_localRefCookie(rBIX) # a0<- saved->top
+ lw a1, offThread_exception(rSELF) # check for exception
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = fp
+ sw a0, offThread_jniLocal_topCookie(rSELF) # new top <- old top
+ lw a0, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+
+ # a0 = dalvikCallsitePC
+ bnez a1, .LhandleException # handle exception if any
+
+ sw a2, offThread_inJitCodeCache(rSELF) # set the mode properly
+ beqz a2, 3f
+ jr a2 # go if return chaining cell still exist
+
+3:
+ # continue executing the next instruction through the interpreter
+ la a1, .LdvmJitToInterpTraceSelectNoChain # defined in footer.S
+ lw a1, (a1)
+ add rPC, a0, 3*2 # reconstruct new rPC (advance 3 dalvik instr)
+
+#if defined(WITH_JIT_TUNING)
+ li a0, kCallsiteInterpreted
+#endif
+ jr a1
+
+#undef TEMPLATE_INLINE_PROFILING
+
+ .size dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
+/* File: mips/footer.S */
+/*
+ * ===========================================================================
+ * Common subroutines and data
+ * ===========================================================================
+ */
+
+ .section .data.rel.ro
+ .align 4
+.LinvokeNative:
+ # Prep for the native call
+ # a1 = newFP, a0 = methodToCall
+ lw t9, offThread_jniLocal_topCookie(rSELF) # t9<- thread->localRef->...
+ sw zero, offThread_inJitCodeCache(rSELF) # not in jit code cache
+ sw a1, offThread_curFrame(rSELF) # self->curFrame = newFp
+ sw t9, (offStackSaveArea_localRefCookie - sizeofStackSaveArea)(a1)
+ # newFp->localRefCookie=top
+ lhu ra, offThread_subMode(rSELF)
+ SAVEAREA_FROM_FP(rBIX, a1) # rBIX<- new stack save area
+
+ move a2, a0 # a2<- methodToCall
+ move a0, a1 # a0<- newFp
+ add a1, rSELF, offThread_retval # a1<- &retval
+ move a3, rSELF # a3<- self
+ andi ra, kSubModeMethodTrace
+ beqz ra, 121f
+ # a2: methodToCall
+ # preserve a0-a3
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+ move rTEMP, a2 # preserve a2
+
+ move a0, rTEMP
+ move a1, rSELF
+ la t9, dvmFastMethodTraceEnter
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # restore a0-a3
+ SCRATCH_LOAD(a3, 12)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+
+ lw t9, offMethod_nativeFunc(a2)
+ JALR(t9) # call methodToCall->nativeFunc
+ lw gp, STACK_OFFSET_GP(sp)
+
+ move a0, rTEMP
+ move a1, rSELF
+ la t9, dvmFastNativeMethodTraceExit
+ JALR(t9)
+ lw gp, STACK_OFFSET_GP(sp)
+ b 212f
+
+121:
+ lw t9, offMethod_nativeFunc(a2)
+ JALR(t9) # call methodToCall->nativeFunc
+ lw gp, STACK_OFFSET_GP(sp)
+
+212:
+ # native return; rBIX=newSaveArea
+ # equivalent to dvmPopJniLocals
+ lw a2, offStackSaveArea_returnAddr(rBIX) # a2 = chaining cell ret addr
+ lw a0, offStackSaveArea_localRefCookie(rBIX) # a0<- saved->top
+ lw a1, offThread_exception(rSELF) # check for exception
+ sw rFP, offThread_curFrame(rSELF) # self->curFrame = fp
+ sw a0, offThread_jniLocal_topCookie(rSELF) # new top <- old top
+ lw a0, offStackSaveArea_savedPc(rBIX) # reload rPC
+
+ # a0 = dalvikCallsitePC
+ bnez a1, .LhandleException # handle exception if any
+
+ sw a2, offThread_inJitCodeCache(rSELF) # set the mode properly
+ beqz a2, 3f
+ jr a2 # go if return chaining cell still exist
+
+3:
+ # continue executing the next instruction through the interpreter
+ la a1, .LdvmJitToInterpTraceSelectNoChain # defined in footer.S
+ lw a1, (a1)
+ add rPC, a0, 3*2 # reconstruct new rPC
+
+#if defined(WITH_JIT_TUNING)
+ li a0, kCallsiteInterpreted
+#endif
+ jr a1
+
+
+/*
+ * On entry:
+ * a0 Faulting Dalvik PC
+ */
+.LhandleException:
+#if defined(WITH_SELF_VERIFICATION)
+ la t0, .LdeadFood
+ lw t0, (t0) # should not see this under self-verification mode
+ jr t0
+.LdeadFood:
+ .word 0xdeadf00d
+#endif
+ sw zero, offThread_inJitCodeCache(rSELF) # in interpreter land
+ la a1, .LdvmMterpCommonExceptionThrown # PIC way of getting &func
+ lw a1, (a1)
+ la rIBASE, .LdvmAsmInstructionStart # PIC way of getting &func
+ lw rIBASE, (rIBASE)
+ move rPC, a0 # reload the faulting Dalvid address
+ jr a1 # branch to dvmMterpCommonExeceptionThrown
+
+ .align 4
+.LdvmAsmInstructionStart:
+ .word dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+ .word dvmJitToInterpNoChainNoProfile
+.LdvmJitToInterpTraceSelectNoChain:
+ .word dvmJitToInterpTraceSelectNoChain
+.LdvmJitToInterpNoChain:
+ .word dvmJitToInterpNoChain
+.LdvmMterpStdBail:
+ .word dvmMterpStdBail
+.LdvmMterpCommonExceptionThrown:
+ .word dvmMterpCommonExceptionThrown
+.LdvmLockObject:
+ .word dvmLockObject
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+ .word gDvmICHitCount
+#endif
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+ .word dvmSelfVerificationMemOpDecode
+#endif
+
+ .global dmvCompilerTemplateEnd
+dmvCompilerTemplateEnd:
+
+#endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/rebuild.sh b/vm/compiler/template/rebuild.sh
index f04d097..60f45be 100755
--- a/vm/compiler/template/rebuild.sh
+++ b/vm/compiler/template/rebuild.sh
@@ -19,4 +19,4 @@
# generated as part of the build.
#
set -e
-for arch in ia32 armv5te armv5te-vfp armv7-a armv7-a-neon; do TARGET_ARCH_EXT=$arch make -f Makefile-template; done
+for arch in ia32 armv5te armv5te-vfp armv7-a armv7-a-neon mips; do TARGET_ARCH_EXT=$arch make -f Makefile-template; done
diff --git a/vm/dalvik b/vm/dalvik
index 5569db9..cb46775 100644
--- a/vm/dalvik
+++ b/vm/dalvik
@@ -20,7 +20,7 @@
ANDROID_DATA=/tmp/android-data \
ANDROID_ROOT=$ANDROID_BUILD_TOP/out/host/linux-x86 \
LD_LIBRARY_PATH=$ANDROID_BUILD_TOP/out/host/linux-x86/lib \
-$ANDROID_BUILD_TOP/out/host/linux-x86/bin/dalvikvm \
+exec $ANDROID_BUILD_TOP/out/host/linux-x86/bin/dalvikvm \
-Xbootclasspath\
:$ANDROID_BUILD_TOP/out/host/linux-x86/framework/core-hostdex.jar\
:$ANDROID_BUILD_TOP/out/host/linux-x86/framework/bouncycastle-hostdex.jar\
diff --git a/vm/hprof/Hprof.cpp b/vm/hprof/Hprof.cpp
index 23fef82..d1dd499 100644
--- a/vm/hprof/Hprof.cpp
+++ b/vm/hprof/Hprof.cpp
@@ -246,6 +246,8 @@
if (ctx == NULL) {
return -1;
}
+ // first record
+ hprofStartNewRecord(ctx, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
dvmVisitRoots(hprofRootVisitor, ctx);
dvmHeapBitmapWalk(dvmHeapSourceGetLiveBits(), hprofBitmapCallback, ctx);
hprofFinishHeapDump(ctx);
diff --git a/vm/interp/Interp.cpp b/vm/interp/Interp.cpp
index 4109764..c168c7a 100644
--- a/vm/interp/Interp.cpp
+++ b/vm/interp/Interp.cpp
@@ -846,8 +846,8 @@
* terminates "with a thrown exception".
*/
u2 opcode = GET_OPCODE(*pc);
- if (opcode == OP_RETURN_VOID || opcode == OP_RETURN ||
- opcode == OP_RETURN_WIDE ||opcode == OP_RETURN_OBJECT)
+ if (opcode == OP_RETURN_VOID || opcode == OP_RETURN || opcode == OP_RETURN_VOID_BARRIER ||
+ opcode == OP_RETURN_OBJECT || opcode == OP_RETURN_WIDE)
{
eventFlags |= DBG_METHOD_EXIT;
}
@@ -991,24 +991,6 @@
*/
/*
- * Construct an s4 from two consecutive half-words of switch data.
- * This needs to check endianness because the DEX optimizer only swaps
- * half-words in instruction stream.
- *
- * "switchData" must be 32-bit aligned.
- */
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-static inline s4 s4FromSwitchData(const void* switchData) {
- return *(s4*) switchData;
-}
-#else
-static inline s4 s4FromSwitchData(const void* switchData) {
- u2* data = switchData;
- return data[0] | (((s4) data[1]) << 16);
-}
-#endif
-
-/*
* Find the matching case. Returns the offset to the handler instructions.
*
* Returns 3 if we don't find a match (it's the size of the packed-switch
@@ -1457,7 +1439,7 @@
case VERIFY_ERROR_NONE:
/* should never happen; use default exception */
assert(false);
- msg = strdup("weird - no error specified");
+ msg = "weird - no error specified";
break;
/* no default clause -- want warning if enum updated */
@@ -1483,8 +1465,10 @@
newValue.ctl.breakFlags |= kInterpSingleStep;
if (newValue.ctl.subMode & SAFEPOINT_BREAK_MASK)
newValue.ctl.breakFlags |= kInterpSafePoint;
+#ifndef DVM_NO_ASM_INTERP
newValue.ctl.curHandlerTable = (newValue.ctl.breakFlags) ?
thread->altHandlerTable : thread->mainHandlerTable;
+#endif
} while (dvmQuasiAtomicCas64(oldValue.all, newValue.all,
&thread->interpBreak.all) != 0);
}
@@ -1556,12 +1540,16 @@
Thread* thread;
uint8_t breakFlags;
uint8_t subMode;
+#ifndef DVM_NO_ASM_INTERP
void* handlerTable;
+#endif
dvmLockThreadList(self);
breakFlags = self->interpBreak.ctl.breakFlags;
subMode = self->interpBreak.ctl.subMode;
+#ifndef DVM_NO_ASM_INTERP
handlerTable = self->interpBreak.ctl.curHandlerTable;
+#endif
for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
if (subMode != thread->interpBreak.ctl.subMode) {
ALOGD("Warning: subMode mismatch - %#x:%#x, tid[%d]",
@@ -1571,11 +1559,13 @@
ALOGD("Warning: breakFlags mismatch - %#x:%#x, tid[%d]",
breakFlags,thread->interpBreak.ctl.breakFlags,thread->threadId);
}
+#ifndef DVM_NO_ASM_INTERP
if (handlerTable != thread->interpBreak.ctl.curHandlerTable) {
ALOGD("Warning: curHandlerTable mismatch - %#x:%#x, tid[%d]",
(int)handlerTable,(int)thread->interpBreak.ctl.curHandlerTable,
thread->threadId);
}
+#endif
#if defined(WITH_JIT)
if (thread->pJitProfTable != gDvmJit.pProfTable) {
ALOGD("Warning: pJitProfTable mismatch - %#x:%#x, tid[%d]",
@@ -1954,7 +1944,9 @@
if (gDvm.executionMode == kExecutionModeInterpFast)
stdInterp = dvmMterpStd;
#if defined(WITH_JIT)
- else if (gDvm.executionMode == kExecutionModeJit)
+ else if (gDvm.executionMode == kExecutionModeJit ||
+ gDvm.executionMode == kExecutionModeNcgO0 ||
+ gDvm.executionMode == kExecutionModeNcgO1)
stdInterp = dvmMterpStd;
#endif
else
diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h
index acec648..a053f6d 100644
--- a/vm/interp/InterpDefs.h
+++ b/vm/interp/InterpDefs.h
@@ -105,4 +105,22 @@
#endif
+/*
+ * Construct an s4 from two consecutive half-words of switch data.
+ * This needs to check endianness because the DEX optimizer only swaps
+ * half-words in instruction stream.
+ *
+ * "switchData" must be 32-bit aligned.
+ */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static inline s4 s4FromSwitchData(const void* switchData) {
+ return *(s4*) switchData;
+}
+#else
+static inline s4 s4FromSwitchData(const void* switchData) {
+ u2* data = switchData;
+ return data[0] | (((s4) data[1]) << 16);
+}
+#endif
+
#endif // DALVIK_INTERP_DEFS_H_
diff --git a/vm/interp/InterpState.h b/vm/interp/InterpState.h
index 37b7fdd..cc0a13f 100644
--- a/vm/interp/InterpState.h
+++ b/vm/interp/InterpState.h
@@ -25,6 +25,13 @@
#define DALVIK_INTERP_STATE_H_
/*
+ * For x86 JIT. In the lowered code sequences for bytecodes, at most 10
+ * temporary variables may be live at the same time. Therefore, at most
+ * 10 temporary variables can be spilled at the same time.
+*/
+#define MAX_SPILL_JIT_IA 10
+
+/*
* Execution mode, e.g. interpreter vs. JIT.
*/
enum ExecutionMode {
@@ -34,6 +41,10 @@
#if defined(WITH_JIT)
kExecutionModeJit,
#endif
+#if defined(WITH_JIT) /* IA only */
+ kExecutionModeNcgO0,
+ kExecutionModeNcgO1,
+#endif
};
/*
@@ -232,6 +243,15 @@
u4 unused:31;
};
+#if defined(ARCH_IA32)
+/*
+ * JIT code genarator optimization level
+ */
+enum JitOptLevel {
+ kJitOptLevelO0 = 0,
+ kJitOptLevelO1 = 1,
+};
+#endif // #if defined(ARCH_IA32)
#endif
#endif // DALVIK_INTERP_STATE_H_
diff --git a/vm/interp/Jit.cpp b/vm/interp/Jit.cpp
index 9f87705..6d53954 100644
--- a/vm/interp/Jit.cpp
+++ b/vm/interp/Jit.cpp
@@ -643,6 +643,8 @@
*/
android_atomic_release_store((int32_t)dPC,
(volatile int32_t *)(void *)&gDvmJit.pJitEntryTable[idx].dPC);
+ /* for simulator mode, we need to initialized codeAddress to null */
+ gDvmJit.pJitEntryTable[idx].codeAddress = NULL;
gDvmJit.pJitEntryTable[idx].dPC = dPC;
gDvmJit.jitTableEntriesUsed++;
} else {
@@ -796,7 +798,15 @@
if (lastPC == NULL) break;
/* Grow the trace around the last PC if jitState is kJitTSelect */
dexDecodeInstruction(lastPC, &decInsn);
-
+#if TRACE_OPCODE_FILTER
+ /* Only add JIT support opcode to trace. End the trace if
+ * this opcode is not supported.
+ */
+ if (!dvmIsOpcodeSupportedByJit(decInsn.opcode)) {
+ self->jitState = kJitTSelectEnd;
+ break;
+ }
+#endif
/*
* Treat {PACKED,SPARSE}_SWITCH as trace-ending instructions due
* to the amount of space it takes to generate the chaining
diff --git a/vm/interp/Stack.cpp b/vm/interp/Stack.cpp
index a1f8d71..9ef92c7 100644
--- a/vm/interp/Stack.cpp
+++ b/vm/interp/Stack.cpp
@@ -1401,6 +1401,8 @@
}
free_backtrace_symbols(backtrace_symbols, frames);
+ } else {
+ dvmPrintDebugMessage(target, " (native backtrace unavailable)\n");
}
#endif
}
diff --git a/vm/jdwp/JdwpHandler.cpp b/vm/jdwp/JdwpHandler.cpp
index b41139a..5ce432c 100644
--- a/vm/jdwp/JdwpHandler.cpp
+++ b/vm/jdwp/JdwpHandler.cpp
@@ -1067,8 +1067,9 @@
if (!dvmDbgGetThreadStatus(threadId, &threadStatus, &suspendStatus))
return ERR_INVALID_THREAD;
- ALOGV(" --> %s, %s", dvmJdwpThreadStatusStr(threadStatus),
- dvmJdwpSuspendStatusStr(suspendStatus));
+ ALOGV(" --> %s, %s",
+ dvmJdwpThreadStatusStr((JdwpThreadStatus) threadStatus),
+ dvmJdwpSuspendStatusStr((JdwpSuspendStatus) suspendStatus));
expandBufAdd4BE(pReply, threadStatus);
expandBufAdd4BE(pReply, suspendStatus);
diff --git a/vm/mterp/Mterp.cpp b/vm/mterp/Mterp.cpp
index b5cb9a5..bfeada2 100644
--- a/vm/mterp/Mterp.cpp
+++ b/vm/mterp/Mterp.cpp
@@ -52,7 +52,11 @@
* which one did, but if any one is too big the total size will
* overflow.
*/
+#if defined(__mips__)
+ const int width = 128;
+#else
const int width = 64;
+#endif
int interpSize = (uintptr_t) dvmAsmInstructionEnd -
(uintptr_t) dvmAsmInstructionStart;
if (interpSize != 0 && interpSize != kNumPackedOpcodes*width) {
diff --git a/vm/mterp/Mterp.h b/vm/mterp/Mterp.h
index b27e4f7..6762f67 100644
--- a/vm/mterp/Mterp.h
+++ b/vm/mterp/Mterp.h
@@ -35,15 +35,9 @@
/*
* Local entry and exit points. The platform-specific implementation must
* provide these two.
- *
- * dvmMterpStdRun() returns the "changeInterp" argument from dvmMterpStdBail(),
- * indicating whether we want to bail out of the interpreter or just switch
- * between "standard" and "debug" mode.
- *
- * The "mterp" interpreter is always "standard".
*/
-extern "C" bool dvmMterpStdRun(Thread* self);
-extern "C" void dvmMterpStdBail(Thread* self, bool changeInterp);
+extern "C" void dvmMterpStdRun(Thread* self);
+extern "C" void dvmMterpStdBail(Thread* self);
/*
* Helper for common_printMethod(), invoked from the assembly
diff --git a/vm/mterp/armv5te/OP_EXECUTE_INLINE.S b/vm/mterp/armv5te/OP_EXECUTE_INLINE.S
index 806eb98..ca71de1 100644
--- a/vm/mterp/armv5te/OP_EXECUTE_INLINE.S
+++ b/vm/mterp/armv5te/OP_EXECUTE_INLINE.S
@@ -60,6 +60,7 @@
ldr r0, [rFP, ip, lsl #2] @ r0<- vC
0:
ldr rINST, .L${opcode}_table @ table of InlineOperation
+5: add rINST, pc
ldr pc, [rINST, r10, lsl #4] @ sizeof=16, "func" is first entry
@ (not reached)
@@ -95,4 +96,4 @@
.L${opcode}_table:
- .word gDvmInlineOpsTable
+ .word PCREL_REF(gDvmInlineOpsTable,5b)
diff --git a/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S b/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S
index bb4b0e8..d9e35b8 100644
--- a/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S
+++ b/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S
@@ -52,6 +52,7 @@
GET_VREG(r0, ip) @ r0<- vBase[0]
0:
ldr r9, .L${opcode}_table @ table of InlineOperation
+5: add r9, pc
ldr pc, [r9, r10, lsl #4] @ sizeof=16, "func" is first entry
@ (not reached)
@@ -89,5 +90,5 @@
.L${opcode}_table:
- .word gDvmInlineOpsTable
+ .word PCREL_REF(gDvmInlineOpsTable,5b)
diff --git a/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
index f580d1c..de39958 100644
--- a/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
+++ b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
@@ -96,6 +96,7 @@
*/
.L${opcode}_notimpl:
ldr r0, .L_strFilledNewArrayNotImpl_${opcode}
+3: add r0, pc
bl dvmThrowInternalError
b common_exceptionThrown
@@ -105,4 +106,4 @@
*/
.L_strFilledNewArrayNotImpl_${opcode}:
- .word .LstrFilledNewArrayNotImpl
+ .word PCREL_REF(.LstrFilledNewArrayNotImpl,3b)
diff --git a/vm/mterp/armv5te/entry.S b/vm/mterp/armv5te/entry.S
index 19b6d4b..46b26a6 100644
--- a/vm/mterp/armv5te/entry.S
+++ b/vm/mterp/armv5te/entry.S
@@ -95,12 +95,15 @@
.Lbad_arg:
ldr r0, strBadEntryPoint
+0: add r0, pc
@ r1 holds value of entryPoint
bl printf
bl dvmAbort
.fnend
.size dvmMterpStdRun, .-dvmMterpStdRun
+strBadEntryPoint:
+ .word PCREL_REF(.LstrBadEntryPoint,0b)
.global dvmMterpStdBail
.type dvmMterpStdBail, %function
@@ -122,9 +125,3 @@
add sp, sp, #4 @ un-align 64
ldmfd sp!, {r4-r10,fp,pc} @ restore 9 regs and return
-
-/*
- * String references.
- */
-strBadEntryPoint:
- .word .LstrBadEntryPoint
diff --git a/vm/mterp/armv5te/footer.S b/vm/mterp/armv5te/footer.S
index d96e005..5d3e994 100644
--- a/vm/mterp/armv5te/footer.S
+++ b/vm/mterp/armv5te/footer.S
@@ -655,8 +655,8 @@
cmp lr, #0 @ any special SubModes active?
bne 11f @ go handle them if so
- mov lr, pc @ set return addr
- ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ blx ip
7:
@ native return; r10=newSaveArea
@@ -682,8 +682,8 @@
ldmfd sp, {r0-r3} @ refresh. NOTE: no sp autoincrement
@ Call the native method
- mov lr, pc @ set return addr
- ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ blx ip
@ Restore the pre-call arguments
ldmfd sp!, {r0-r3} @ r2<- methodToCall (others unneeded)
@@ -930,7 +930,9 @@
ldr r3, [r3, #offClassObject_descriptor]
@
ldr r2, strExceptionNotCaughtLocally
+0: add r2, pc
ldr r1, strLogTag
+1: add r1, pc
mov r0, #3 @ LOG_DEBUG
bl __android_log_print
#endif
@@ -940,6 +942,10 @@
bl dvmReleaseTrackedAlloc @ release the exception
b common_gotoBail @ bail out
+strExceptionNotCaughtLocally:
+ .word PCREL_REF(.LstrExceptionNotCaughtLocally,0b)
+strLogTag:
+ .word PCREL_REF(.LstrLogTag,1b)
/*
* Exception handling, calls through "glue code".
@@ -1007,9 +1013,13 @@
common_errDivideByZero:
EXPORT_PC()
ldr r0, strDivideByZero
+0: add r0, pc
bl dvmThrowArithmeticException
b common_exceptionThrown
+strDivideByZero:
+ .word PCREL_REF(.LstrDivideByZero,0b)
+
/*
* Attempt to allocate an array with a negative size.
* On entry: length in r1
@@ -1058,11 +1068,15 @@
.macro SQUEAK num
common_squeak\num:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
- ldr r0, strSqueak
+ ldr r0, strSqueak\num
+0: add r0, pc
mov r1, #\num
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+
+strSqueak\num:
+ .word PCREL_REF(.LstrSqueak,0b)
.endm
SQUEAK 0
@@ -1079,20 +1093,28 @@
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strSqueak
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strSqueak:
+ .word PCREL_REF(.LstrSqueak,0b)
+
/*
* Print a newline, preserving registers.
*/
common_printNewline:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
ldr r0, strNewline
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strNewline:
+ .word PCREL_REF(.LstrNewline,0b)
+
/*
* Print the 32-bit quantity in r0 as a hex value, preserving registers.
*/
@@ -1100,10 +1122,14 @@
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strPrintHex
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strPrintHex:
+ .word PCREL_REF(.LstrPrintHex,0b)
+
/*
* Print the 64-bit quantity in r0-r1, preserving registers.
*/
@@ -1112,10 +1138,14 @@
mov r3, r1
mov r2, r0
ldr r0, strPrintLong
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strPrintLong:
+ .word PCREL_REF(.LstrPrintLong,0b)
+
/*
* Print full method info. Pass the Method* in r0. Preserves regs.
*/
@@ -1170,25 +1200,6 @@
#endif
-/*
- * String references, must be close to the code that uses them.
- */
- .align 2
-strDivideByZero:
- .word .LstrDivideByZero
-strLogTag:
- .word .LstrLogTag
-strExceptionNotCaughtLocally:
- .word .LstrExceptionNotCaughtLocally
-
-strNewline:
- .word .LstrNewline
-strSqueak:
- .word .LstrSqueak
-strPrintHex:
- .word .LstrPrintHex
-strPrintLong:
- .word .LstrPrintLong
/*
* Zero-terminated ASCII string data.
diff --git a/vm/mterp/c/OP_APUT_OBJECT.cpp b/vm/mterp/c/OP_APUT_OBJECT.cpp
index 9318648..0730b72 100644
--- a/vm/mterp/c/OP_APUT_OBJECT.cpp
+++ b/vm/mterp/c/OP_APUT_OBJECT.cpp
@@ -24,7 +24,7 @@
if (!dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
obj->clazz->descriptor, obj,
- arrayObj->obj.clazz->descriptor, arrayObj);
+ arrayObj->clazz->descriptor, arrayObj);
dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
GOTO_exceptionThrown();
}
diff --git a/vm/mterp/c/OP_EXECUTE_INLINE.cpp b/vm/mterp/c/OP_EXECUTE_INLINE.cpp
index 8d20764..288ccc9 100644
--- a/vm/mterp/c/OP_EXECUTE_INLINE.cpp
+++ b/vm/mterp/c/OP_EXECUTE_INLINE.cpp
@@ -47,7 +47,7 @@
;
}
- if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+ if (self->interpBreak.ctl.subMode & kSubModeDebugProfile) {
if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
GOTO_exceptionThrown();
} else {
diff --git a/vm/mterp/c/OP_EXECUTE_INLINE_RANGE.cpp b/vm/mterp/c/OP_EXECUTE_INLINE_RANGE.cpp
index 664ada4..467f0e9 100644
--- a/vm/mterp/c/OP_EXECUTE_INLINE_RANGE.cpp
+++ b/vm/mterp/c/OP_EXECUTE_INLINE_RANGE.cpp
@@ -31,7 +31,7 @@
;
}
- if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+ if (self->interpBreak.ctl.subMode & kSubModeDebugProfile) {
if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
GOTO_exceptionThrown();
} else {
diff --git a/vm/mterp/c/OP_PACKED_SWITCH.cpp b/vm/mterp/c/OP_PACKED_SWITCH.cpp
index 3922e46..c820e80 100644
--- a/vm/mterp/c/OP_PACKED_SWITCH.cpp
+++ b/vm/mterp/c/OP_PACKED_SWITCH.cpp
@@ -6,7 +6,7 @@
vsrc1 = INST_AA(inst);
offset = FETCH(1) | (((s4) FETCH(2)) << 16);
- ILOGV("|packed-switch v%d +0x%04x", vsrc1, vsrc2);
+ ILOGV("|packed-switch v%d +0x%04x", vsrc1, offset);
switchData = pc + offset; // offset in 16-bit units
#ifndef NDEBUG
if (switchData < curMethod->insns ||
diff --git a/vm/mterp/c/OP_SPARSE_SWITCH.cpp b/vm/mterp/c/OP_SPARSE_SWITCH.cpp
index f48d06e..9ca16ad 100644
--- a/vm/mterp/c/OP_SPARSE_SWITCH.cpp
+++ b/vm/mterp/c/OP_SPARSE_SWITCH.cpp
@@ -6,7 +6,7 @@
vsrc1 = INST_AA(inst);
offset = FETCH(1) | (((s4) FETCH(2)) << 16);
- ILOGV("|sparse-switch v%d +0x%04x", vsrc1, vsrc2);
+ ILOGV("|sparse-switch v%d +0x%04x", vsrc1, offset);
switchData = pc + offset; // offset in 16-bit units
#ifndef NDEBUG
if (switchData < curMethod->insns ||
diff --git a/vm/mterp/c/gotoTargets.cpp b/vm/mterp/c/gotoTargets.cpp
index 2c05038..452bee8 100644
--- a/vm/mterp/c/gotoTargets.cpp
+++ b/vm/mterp/c/gotoTargets.cpp
@@ -917,7 +917,7 @@
DUMP_REGS(methodToCall, newFp, true); // show input args
if (self->interpBreak.ctl.subMode != 0) {
- dvmReportPreNativeInvoke(methodToCall, self, fp);
+ dvmReportPreNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
}
ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
@@ -931,12 +931,13 @@
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
if (self->interpBreak.ctl.subMode != 0) {
- dvmReportPostNativeInvoke(methodToCall, self, fp);
+ dvmReportPostNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
}
/* pop frame off */
dvmPopJniLocals(self, newSaveArea);
- self->interpSave.curFrame = fp;
+ self->interpSave.curFrame = newSaveArea->prevFrame;
+ fp = newSaveArea->prevFrame;
/*
* If the native code threw an exception, or interpreted code
diff --git a/vm/mterp/c/header.cpp b/vm/mterp/c/header.cpp
index d0e55f5..709e4c5 100644
--- a/vm/mterp/c/header.cpp
+++ b/vm/mterp/c/header.cpp
@@ -61,6 +61,14 @@
#if defined(__ARM_EABI__)
# define NO_UNALIGN_64__UNION
#endif
+/*
+ * MIPS ABI requires 64-bit alignment for access to 64-bit data types.
+ *
+ * Use memcpy() to do the transfer
+ */
+#if defined(__mips__)
+/* # define NO_UNALIGN_64__UNION */
+#endif
//#define LOG_INSTR /* verbose debugging */
diff --git a/vm/mterp/c/opcommon.cpp b/vm/mterp/c/opcommon.cpp
index 991df86..a49ed86 100644
--- a/vm/mterp/c/opcommon.cpp
+++ b/vm/mterp/c/opcommon.cpp
@@ -525,7 +525,7 @@
} \
SET_REGISTER##_regsize(vdst, \
dvmGetField##_ftype(obj, ifield->byteOffset)); \
- ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -569,7 +569,7 @@
} \
dvmSetField##_ftype(obj, ifield->byteOffset, \
GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -619,7 +619,7 @@
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -642,6 +642,6 @@
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
diff --git a/vm/mterp/common/asm-constants.h b/vm/mterp/common/asm-constants.h
index e1a4df6..80b36fc 100644
--- a/vm/mterp/common/asm-constants.h
+++ b/vm/mterp/common/asm-constants.h
@@ -40,7 +40,7 @@
* data structures. Some versions of gcc will hold small enumerated types
* in a char instead of an int.
*/
-#if defined(__ARM_EABI__)
+#if defined(__ARM_EABI__) || defined(__mips__)
# define MTERP_NO_UNALIGN_64
#endif
#if defined(HAVE_SHORT_ENUMS)
@@ -152,7 +152,11 @@
MTERP_OFFSET(offThread_methodClassDex, Thread, interpSave.methodClassDex, 12)
/* make sure all JValue union members are stored at the same offset */
MTERP_OFFSET(offThread_retval, Thread, interpSave.retval, 16)
+#ifdef HAVE_BIG_ENDIAN
+MTERP_OFFSET(offThread_retval_z, Thread, interpSave.retval.z, 19)
+#else
MTERP_OFFSET(offThread_retval_z, Thread, interpSave.retval.z, 16)
+#endif
MTERP_OFFSET(offThread_retval_i, Thread, interpSave.retval.i, 16)
MTERP_OFFSET(offThread_retval_j, Thread, interpSave.retval.j, 16)
MTERP_OFFSET(offThread_retval_l, Thread, interpSave.retval.l, 16)
@@ -316,3 +320,9 @@
MTERP_CONSTANT(DBG_METHOD_ENTRY, 0x04)
MTERP_CONSTANT(DBG_METHOD_EXIT, 0x08)
+
+#if defined(__thumb__)
+# define PCREL_REF(sym,label) sym-(label+4)
+#else
+# define PCREL_REF(sym,label) sym-(label+8)
+#endif
diff --git a/vm/mterp/common/mips-defines.h b/vm/mterp/common/mips-defines.h
new file mode 100644
index 0000000..1e11a30
--- /dev/null
+++ b/vm/mterp/common/mips-defines.h
@@ -0,0 +1,3 @@
+#define fcc0 $fcc0
+#define fcc1 $fcc1
+
diff --git a/vm/mterp/config-mips b/vm/mterp/config-mips
new file mode 100644
index 0000000..0dc80e8
--- /dev/null
+++ b/vm/mterp/config-mips
@@ -0,0 +1,65 @@
+# 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.
+
+#
+# Configuration for MIPS architecture targets.
+#
+
+handler-style computed-goto
+handler-size 128
+# Need to specify split-ops to generate alt-ops at the end after
+# importing other files.
+split-ops
+
+# source for the instruction table stub
+asm-stub mips/stub.S
+
+# source for alternate entry stub
+asm-alt-stub mips/alt_stub.S
+
+# file header and basic definitions
+import c/header.cpp
+import mips/header.S
+
+# C pre-processor defines for stub C instructions
+import cstubs/stubdefs.cpp
+
+# highly-platform-specific defs
+import mips/platform.S
+
+# common defs for the C helpers; include this before the instruction handlers
+import c/opcommon.cpp
+
+# arch-specific entry point to interpreter
+import mips/entry.S
+
+# opcode list; argument to op-start is default directory
+op-start mips
+
+# OP_BREAKPOINT needs explicit testing
+ op OP_BREAKPOINT c
+
+op-end
+
+# "helper" code for C; include if you use any of the C stubs (this generates
+# object code, so it's normally excluded)
+import c/gotoTargets.cpp
+
+# end of defs; include this when cstubs/stubdefs.cpp is included
+import cstubs/enddefs.cpp
+
+# common subroutines for asm
+import mips/footer.S
+import mips/debug.cpp
+alt-ops
diff --git a/vm/mterp/config-x86-atom b/vm/mterp/config-x86-atom
deleted file mode 100644
index 8cf427c..0000000
--- a/vm/mterp/config-x86-atom
+++ /dev/null
@@ -1,306 +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.
-
-# Specifies the size of the assembly region in bytes
-handler-style computed-goto
-handler-size 64
-
-# source for the instruction table stub
-asm-stub x86-atom/stub.S
-
-# file header, macros and definitions
-import c/header.cpp
-import x86-atom/header.S
-
-# common defs for the C helper; include this before the instruction handlers
-import cstubs/stubdefs.cpp
-import c/opcommon.cpp
-
-# start of opcode list; command gives default directory location of instruction files
-op-start x86-atom
-
-#op OP_ADD_DOUBLE_2ADDR c
-#op OP_ADD_DOUBLE c
-#op OP_ADD_FLOAT_2ADDR c
-#op OP_ADD_FLOAT c
-#op OP_ADD_INT_2ADDR c
-#op OP_ADD_INT_LIT16 c
-#op OP_ADD_INT_LIT8 c
-#op OP_ADD_INT c
-#op OP_ADD_LONG_2ADDR c
-#op OP_ADD_LONG c
-#op OP_AGET_BOOLEAN c
-#op OP_AGET_BYTE c
-#op OP_AGET_CHAR c
-#op OP_AGET_OBJECT c
-#op OP_AGET c
-#op OP_AGET_SHORT c
-#op OP_AGET_WIDE c
-#op OP_AND_INT_2ADDR c
-#op OP_AND_INT_LIT16 c
-#op OP_AND_INT_LIT8 c
-#op OP_AND_INT c
-#op OP_AND_LONG_2ADDR c
-#op OP_AND_LONG c
-#op OP_APUT_BOOLEAN c
-#op OP_APUT_BYTE c
-#op OP_APUT_CHAR c
-#op OP_APUT_OBJECT c
-#op OP_APUT c
-#op OP_APUT_SHORT c
-#op OP_APUT_WIDE c
-#op OP_ARRAY_LENGTH c
-#op OP_CHECK_CAST c
-#op OP_CMPG_DOUBLE c
-#op OP_CMPG_FLOAT c
-#op OP_CMPL_DOUBLE c
-#op OP_CMPL_FLOAT c
-#op OP_CMP_LONG c
-#op OP_CONST_16 c
-#op OP_CONST_4 c
-#op OP_CONST_CLASS c
-#op OP_CONST_HIGH16 c
-#op OP_CONST c
-#op OP_CONST_STRING_JUMBO c
-#op OP_CONST_STRING c
-#op OP_CONST_WIDE_16 c
-#op OP_CONST_WIDE_32 c
-#op OP_CONST_WIDE_HIGH16 c
-#op OP_CONST_WIDE c
-#op OP_DIV_DOUBLE_2ADDR c
-#op OP_DIV_DOUBLE c
-#op OP_DIV_FLOAT_2ADDR c
-#op OP_DIV_FLOAT c
-#op OP_DIV_INT_2ADDR c
-#op OP_DIV_INT_LIT16 c
-#op OP_DIV_INT_LIT8 c
-#op OP_DIV_INT c
-#op OP_DIV_LONG_2ADDR c
-#op OP_DIV_LONG c
-#op OP_DOUBLE_TO_FLOAT c
-#op OP_DOUBLE_TO_INT c
-#op OP_DOUBLE_TO_LONG c
-#op OP_EXECUTE_INLINE c
-#op OP_FILL_ARRAY_DATA c
-#op OP_FILLED_NEW_ARRAY_RANGE c
-#op OP_FILLED_NEW_ARRAY c
-#op OP_FLOAT_TO_DOUBLE c
-#op OP_FLOAT_TO_INT c
-#op OP_FLOAT_TO_LONG c
-#op OP_GOTO_16 c
-#op OP_GOTO_32 c
-#op OP_GOTO c
-#op OP_IF_EQ c
-#op OP_IF_EQZ c
-#op OP_IF_GE c
-#op OP_IF_GEZ c
-#op OP_IF_GT c
-#op OP_IF_GTZ c
-#op OP_IF_LE c
-#op OP_IF_LEZ c
-#op OP_IF_LT c
-#op OP_IF_LTZ c
-#op OP_IF_NE c
-#op OP_IF_NEZ c
-#op OP_IGET_BOOLEAN c
-#op OP_IGET_BYTE c
-#op OP_IGET_CHAR c
-#op OP_IGET_OBJECT_QUICK c
-#op OP_IGET_OBJECT c
-#op OP_IGET_QUICK c
-#op OP_IGET c
-#op OP_IGET_SHORT c
-#op OP_IGET_WIDE_QUICK c
-#op OP_IGET_WIDE c
-#op OP_INSTANCE_OF c
-#op OP_INT_TO_BYTE c
-#op OP_INT_TO_CHAR c
-#op OP_INT_TO_DOUBLE c
-#op OP_INT_TO_FLOAT c
-#op OP_INT_TO_LONG c
-#op OP_INT_TO_SHORT c
-#op OP_INVOKE_DIRECT_EMPTY c
-#op OP_INVOKE_DIRECT_RANGE c
-#op OP_INVOKE_DIRECT c
-#op OP_INVOKE_INTERFACE_RANGE c
-#op OP_INVOKE_INTERFACE c
-#op OP_INVOKE_STATIC_RANGE c
-#op OP_INVOKE_STATIC c
-#op OP_INVOKE_SUPER_QUICK_RANGE c
-#op OP_INVOKE_SUPER_QUICK c
-#op OP_INVOKE_SUPER_RANGE c
-#op OP_INVOKE_SUPER c
-#op OP_INVOKE_VIRTUAL_QUICK_RANGE c
-#op OP_INVOKE_VIRTUAL_QUICK c
-#op OP_INVOKE_VIRTUAL_RANGE c
-#op OP_INVOKE_VIRTUAL c
-#op OP_IPUT_BOOLEAN c
-#op OP_IPUT_BYTE c
-#op OP_IPUT_CHAR c
-#op OP_IPUT_OBJECT_QUICK c
-#op OP_IPUT_OBJECT c
-#op OP_IPUT_QUICK c
-#op OP_IPUT c
-#op OP_IPUT_SHORT c
-#op OP_IPUT_WIDE_QUICK c
-#op OP_IPUT_WIDE c
-#op OP_LONG_TO_DOUBLE c
-#op OP_LONG_TO_FLOAT c
-#op OP_LONG_TO_INT c
-#op OP_MONITOR_ENTER c
-#op OP_MONITOR_EXIT c
-#op OP_MOVE_16 c
-#op OP_MOVE_EXCEPTION c
-#op OP_MOVE_FROM16 c
-#op OP_MOVE_OBJECT_16 c
-#op OP_MOVE_OBJECT_FROM16 c
-#op OP_MOVE_OBJECT c
-#op OP_MOVE_RESULT_OBJECT c
-#op OP_MOVE_RESULT c
-#op OP_MOVE_RESULT_WIDE c
-#op OP_MOVE c
-#op OP_MOVE_WIDE_16 c
-#op OP_MOVE_WIDE_FROM16 c
-#op OP_MOVE_WIDE c
-#op OP_MUL_DOUBLE_2ADDR c
-#op OP_MUL_DOUBLE c
-#op OP_MUL_FLOAT_2ADDR c
-#op OP_MUL_FLOAT c
-#op OP_MUL_INT_2ADDR c
-#op OP_MUL_INT_LIT16 c
-#op OP_MUL_INT_LIT8 c
-#op OP_MUL_INT c
-#op OP_MUL_LONG_2ADDR c
-#op OP_MUL_LONG c
-#op OP_NEG_DOUBLE c
-#op OP_NEG_FLOAT c
-#op OP_NEG_INT c
-#op OP_NEG_LONG c
-#op OP_NEW_ARRAY c
-#op OP_NEW_INSTANCE c
-#op OP_NOP c
-#op OP_NOT_INT c
-#op OP_NOT_LONG c
-#op OP_OR_INT_2ADDR c
-#op OP_OR_INT_LIT16 c
-#op OP_OR_INT_LIT8 c
-#op OP_OR_INT c
-#op OP_OR_LONG_2ADDR c
-#op OP_OR_LONG c
-#op OP_PACKED_SWITCH c
-#op OP_REM_DOUBLE_2ADDR c
-#op OP_REM_DOUBLE c
-#op OP_REM_FLOAT_2ADDR c
-#op OP_REM_FLOAT c
-#op OP_REM_INT_2ADDR c
-#op OP_REM_INT_LIT16 c
-#op OP_REM_INT_LIT8 c
-#op OP_REM_INT c
-#op OP_REM_LONG_2ADDR c
-#op OP_REM_LONG c
-#op OP_RETURN_OBJECT c
-#op OP_RETURN c
-#op OP_RETURN_VOID c
-#op OP_RETURN_WIDE c
-#op OP_RSUB_INT_LIT8 c
-#op OP_RSUB_INT c
-#op OP_SGET_BOOLEAN c
-#op OP_SGET_BYTE c
-#op OP_SGET_CHAR c
-#op OP_SGET_OBJECT c
-#op OP_SGET c
-#op OP_SGET_SHORT c
-#op OP_SGET_WIDE c
-#op OP_SHL_INT_2ADDR c
-#op OP_SHL_INT_LIT8 c
-#op OP_SHL_INT c
-#op OP_SHL_LONG_2ADDR c
-#op OP_SHL_LONG c
-#op OP_SHR_INT_2ADDR c
-#op OP_SHR_INT_LIT8 c
-#op OP_SHR_INT c
-#op OP_SHR_LONG_2ADDR c
-#op OP_SHR_LONG c
-#op OP_SPARSE_SWITCH c
-#op OP_SPUT_BOOLEAN c
-#op OP_SPUT_BYTE c
-#op OP_SPUT_CHAR c
-#op OP_SPUT_OBJECT c
-#op OP_SPUT c
-#op OP_SPUT_SHORT c
-#op OP_SPUT_WIDE c
-#op OP_SUB_DOUBLE_2ADDR c
-#op OP_SUB_DOUBLE c
-#op OP_SUB_FLOAT_2ADDR c
-#op OP_SUB_FLOAT c
-#op OP_SUB_INT_2ADDR c
-#op OP_SUB_INT c
-#op OP_SUB_LONG_2ADDR c
-#op OP_SUB_LONG c
-#op OP_THROW c
-#op OP_UNUSED_3E c
-#op OP_UNUSED_3F c
-#op OP_UNUSED_40 c
-#op OP_UNUSED_41 c
-#op OP_UNUSED_42 c
-#op OP_UNUSED_43 c
-#op OP_UNUSED_73 c
-#op OP_UNUSED_79 c
-#op OP_UNUSED_7A c
-#op OP_UNUSED_F1 c
-#op OP_UNUSED_FC c
-#op OP_UNUSED_FD c
-#op OP_UNUSED_FE c
-#op OP_UNUSED_FF c
-#op OP_USHR_INT_2ADDR c
-#op OP_USHR_INT_LIT8 c
-#op OP_USHR_INT c
-#op OP_USHR_LONG_2ADDR c
-#op OP_USHR_LONG c
-#op OP_XOR_INT_2ADDR c
-#op OP_XOR_INT_LIT16 c
-#op OP_XOR_INT_LIT8 c
-#op OP_XOR_INT c
-#op OP_XOR_LONG_2ADDR c
-#op OP_XOR_LONG c
-
-# TODO: provide native implementations
-op OP_BREAKPOINT c
-op OP_EXECUTE_INLINE_RANGE c
-op OP_IGET_VOLATILE c
-op OP_IPUT_VOLATILE c
-op OP_SGET_VOLATILE c
-op OP_SPUT_VOLATILE c
-op OP_IGET_OBJECT_VOLATILE c
-op OP_IPUT_OBJECT_VOLATILE c
-op OP_SGET_OBJECT_VOLATILE c
-op OP_SPUT_OBJECT_VOLATILE c
-op OP_IGET_WIDE_VOLATILE c
-op OP_IPUT_WIDE_VOLATILE c
-op OP_SGET_WIDE_VOLATILE c
-op OP_SPUT_WIDE_VOLATILE c
-op OP_RETURN_VOID_BARRIER c
-op OP_INVOKE_OBJECT_INIT_RANGE c
-
-op-end
-
-# arch-specific entry point to interpreter
-import x86-atom/entry.S
-
-# "helper" code for C; include this after the instruction handlers
-import c/gotoTargets.cpp
-import cstubs/enddefs.cpp
-
-# common subroutines for asm
-import x86-atom/footer.S
diff --git a/vm/mterp/cstubs/entry.cpp b/vm/mterp/cstubs/entry.cpp
index 350bd86..90b6cea 100644
--- a/vm/mterp/cstubs/entry.cpp
+++ b/vm/mterp/cstubs/entry.cpp
@@ -2,7 +2,7 @@
* Handler function table, one entry per opcode.
*/
#undef H
-#define H(_op) dvmMterp_##_op
+#define H(_op) (const void*) dvmMterp_##_op
DEFINE_GOTO_TABLE(gDvmMterpHandlers)
#undef H
@@ -21,12 +21,12 @@
{
jmp_buf jmpBuf;
- self->bailPtr = &jmpBuf;
+ self->interpSave.bailPtr = &jmpBuf;
/* We exit via a longjmp */
if (setjmp(jmpBuf)) {
LOGVV("mterp threadid=%d returning", dvmThreadSelf()->threadId);
- return
+ return;
}
/* run until somebody longjmp()s out */
@@ -40,8 +40,8 @@
* FINISH code. For allstubs, we must do an explicit check
* in the interpretation loop.
*/
- if (self-interpBreak.ctl.subMode) {
- dvmCheckBefore(pc, fp, self, curMethod);
+ if (self->interpBreak.ctl.subMode) {
+ dvmCheckBefore(pc, fp, self);
}
Handler handler = (Handler) gDvmMterpHandlers[inst & 0xff];
(void) gDvmMterpHandlerNames; /* avoid gcc "defined but not used" */
@@ -56,6 +56,6 @@
*/
void dvmMterpStdBail(Thread* self)
{
- jmp_buf* pJmpBuf = self->bailPtr;
+ jmp_buf* pJmpBuf = (jmp_buf*) self->interpSave.bailPtr;
longjmp(*pJmpBuf, 1);
}
diff --git a/vm/mterp/cstubs/stubdefs.cpp b/vm/mterp/cstubs/stubdefs.cpp
index ed0e4da..58b4559 100644
--- a/vm/mterp/cstubs/stubdefs.cpp
+++ b/vm/mterp/cstubs/stubdefs.cpp
@@ -82,6 +82,8 @@
}
#endif
+#define FINISH_BKPT(_opcode) /* FIXME? */
+#define DISPATCH_EXTENDED(_opcode) /* FIXME? */
/*
* The "goto label" statements turn into function calls followed by
@@ -118,7 +120,7 @@
* As a special case, "goto bail" turns into a longjmp.
*/
#define GOTO_bail() \
- dvmMterpStdBail(self, false);
+ dvmMterpStdBail(self)
/*
* Periodically check for thread suspension.
diff --git a/vm/mterp/gen-mterp.py b/vm/mterp/gen-mterp.py
index 47c3647..f60d8c6 100755
--- a/vm/mterp/gen-mterp.py
+++ b/vm/mterp/gen-mterp.py
@@ -25,6 +25,7 @@
interp_defs_file = "../../libdex/DexOpcodes.h" # need opcode list
kNumPackedOpcodes = 256 # TODO: Derive this from DexOpcodes.h.
+splitops = False
verbose = False
handler_size_bits = -1000
handler_size_bytes = -1000
@@ -217,7 +218,18 @@
in_op_start = 2
loadAndEmitOpcodes()
+ if splitops == False:
+ if generate_alt_table:
+ loadAndEmitAltOpcodes()
+ if style == "jump-table":
+ emitJmpTable("dvmAsmInstructionStart", label_prefix);
+ emitJmpTable("dvmAsmAltInstructionStart", alt_label_prefix);
+def genaltop(tokens):
+ if in_op_start != 2:
+ raise DataParseError("alt-op can be specified only after op-end")
+ if len(tokens) != 1:
+ raise DataParseError("opEnd takes no arguments")
if generate_alt_table:
loadAndEmitAltOpcodes()
if style == "jump-table":
@@ -307,7 +319,6 @@
asm_fp.write(" .balign 4\n")
asm_fp.write("dvmAsmSisterStart:\n")
asm_fp.writelines(sister_list)
-
asm_fp.write("\n .size dvmAsmSisterStart, .-dvmAsmSisterStart\n")
asm_fp.write(" .global dvmAsmSisterEnd\n")
asm_fp.write("dvmAsmSisterEnd:\n\n")
@@ -593,6 +604,10 @@
opEntry(tokens)
elif tokens[0] == "handler-style":
setHandlerStyle(tokens)
+ elif tokens[0] == "alt-ops":
+ genaltop(tokens)
+ elif tokens[0] == "split-ops":
+ splitops = True
else:
raise DataParseError, "unrecognized command '%s'" % tokens[0]
if style == None:
diff --git a/vm/mterp/mips/ALT_OP_DISPATCH_FF.S b/vm/mterp/mips/ALT_OP_DISPATCH_FF.S
new file mode 100644
index 0000000..0c542a0
--- /dev/null
+++ b/vm/mterp/mips/ALT_OP_DISPATCH_FF.S
@@ -0,0 +1,10 @@
+%verify "executed"
+/*
+ * Unlike other alt stubs, we don't want to call dvmCheckBefore() here.
+ * Instead, just treat this as a trampoline to reach the real alt
+ * handler (which will do the dvmCheckBefore() call.
+ */
+ mov ip, rINST, lsr #8 @ ip<- extended opcode
+ add ip, ip, #256 @ add offset for extended opcodes
+ GOTO_OPCODE(ip) @ go to proper extended handler
+
diff --git a/vm/mterp/mips/OP_ADD_DOUBLE.S b/vm/mterp/mips/OP_ADD_DOUBLE.S
new file mode 100644
index 0000000..1d5cebc
--- /dev/null
+++ b/vm/mterp/mips/OP_ADD_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflopWide.S" {"instr":"JAL(__adddf3)", "instr_f":"add.d fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_ADD_DOUBLE_2ADDR.S b/vm/mterp/mips/OP_ADD_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..499961f
--- /dev/null
+++ b/vm/mterp/mips/OP_ADD_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflopWide2addr.S" {"instr":"JAL(__adddf3)", "instr_f":"add.d fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_ADD_FLOAT.S b/vm/mterp/mips/OP_ADD_FLOAT.S
new file mode 100644
index 0000000..18c94f4
--- /dev/null
+++ b/vm/mterp/mips/OP_ADD_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflop.S" {"instr":"JAL(__addsf3)", "instr_f":"add.s fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_ADD_FLOAT_2ADDR.S b/vm/mterp/mips/OP_ADD_FLOAT_2ADDR.S
new file mode 100644
index 0000000..0a39770
--- /dev/null
+++ b/vm/mterp/mips/OP_ADD_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflop2addr.S" {"instr":"JAL(__addsf3)", "instr_f":"add.s fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_ADD_INT.S b/vm/mterp/mips/OP_ADD_INT.S
new file mode 100644
index 0000000..dcbbb7e
--- /dev/null
+++ b/vm/mterp/mips/OP_ADD_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"instr":"addu a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_ADD_INT_2ADDR.S b/vm/mterp/mips/OP_ADD_INT_2ADDR.S
new file mode 100644
index 0000000..8bb3b0c
--- /dev/null
+++ b/vm/mterp/mips/OP_ADD_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"instr":"addu a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_ADD_INT_LIT16.S b/vm/mterp/mips/OP_ADD_INT_LIT16.S
new file mode 100644
index 0000000..de45f81
--- /dev/null
+++ b/vm/mterp/mips/OP_ADD_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit16.S" {"instr":"addu a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_ADD_INT_LIT8.S b/vm/mterp/mips/OP_ADD_INT_LIT8.S
new file mode 100644
index 0000000..feaaaa2
--- /dev/null
+++ b/vm/mterp/mips/OP_ADD_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"instr":"addu a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_ADD_LONG.S b/vm/mterp/mips/OP_ADD_LONG.S
new file mode 100644
index 0000000..d57e1cf
--- /dev/null
+++ b/vm/mterp/mips/OP_ADD_LONG.S
@@ -0,0 +1,10 @@
+%verify "executed"
+/*
+ * The compiler generates the following sequence for
+ * [v1 v0] = [a1 a0] + [a3 a2];
+ * addu v0,a2,a0
+ * addu a1,a3,a1
+ * sltu v1,v0,a2
+ * addu v1,v1,a1
+ */
+%include "mips/binopWide.S" { "result0":"v0", "result1":"v1", "preinstr":"addu v0, a2, a0", "instr":"addu a1, a3, a1; sltu v1, v0, a2; addu v1, v1, a1" }
diff --git a/vm/mterp/mips/OP_ADD_LONG_2ADDR.S b/vm/mterp/mips/OP_ADD_LONG_2ADDR.S
new file mode 100644
index 0000000..6a87119
--- /dev/null
+++ b/vm/mterp/mips/OP_ADD_LONG_2ADDR.S
@@ -0,0 +1,5 @@
+%verify "executed"
+/*
+ *See OP_ADD_LONG.S for details
+ */
+%include "mips/binopWide2addr.S" { "result0":"v0", "result1":"v1", "preinstr":"addu v0, a2, a0", "instr":"addu a1, a3, a1; sltu v1, v0, a2; addu v1, v1, a1" }
diff --git a/vm/mterp/mips/OP_AGET.S b/vm/mterp/mips/OP_AGET.S
new file mode 100644
index 0000000..e1b182a
--- /dev/null
+++ b/vm/mterp/mips/OP_AGET.S
@@ -0,0 +1,31 @@
+%default { "load":"lw", "shift":"2" }
+%verify "executed"
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if $shift
+ EASN(a0, a0, a1, $shift) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ # a1 >= a3; compare unsigned index
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ $load a2, offArrayObject_contents(a0) # a2 <- vBB[vCC]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, rOBJ, t0) # vAA <- a2
+
diff --git a/vm/mterp/mips/OP_AGET_BOOLEAN.S b/vm/mterp/mips/OP_AGET_BOOLEAN.S
new file mode 100644
index 0000000..d38c466
--- /dev/null
+++ b/vm/mterp/mips/OP_AGET_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_AGET.S" { "load":"lbu", "shift":"0" }
diff --git a/vm/mterp/mips/OP_AGET_BYTE.S b/vm/mterp/mips/OP_AGET_BYTE.S
new file mode 100644
index 0000000..2c0b0be
--- /dev/null
+++ b/vm/mterp/mips/OP_AGET_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_AGET.S" { "load":"lb", "shift":"0" }
diff --git a/vm/mterp/mips/OP_AGET_CHAR.S b/vm/mterp/mips/OP_AGET_CHAR.S
new file mode 100644
index 0000000..9146b97
--- /dev/null
+++ b/vm/mterp/mips/OP_AGET_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_AGET.S" { "load":"lhu", "shift":"1" }
diff --git a/vm/mterp/mips/OP_AGET_OBJECT.S b/vm/mterp/mips/OP_AGET_OBJECT.S
new file mode 100644
index 0000000..16d500d
--- /dev/null
+++ b/vm/mterp/mips/OP_AGET_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_AGET.S"
diff --git a/vm/mterp/mips/OP_AGET_SHORT.S b/vm/mterp/mips/OP_AGET_SHORT.S
new file mode 100644
index 0000000..ba4c939
--- /dev/null
+++ b/vm/mterp/mips/OP_AGET_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_AGET.S" { "load":"lh", "shift":"1" }
diff --git a/vm/mterp/mips/OP_AGET_WIDE.S b/vm/mterp/mips/OP_AGET_WIDE.S
new file mode 100644
index 0000000..896ea4f
--- /dev/null
+++ b/vm/mterp/mips/OP_AGET_WIDE.S
@@ -0,0 +1,27 @@
+%verify "executed"
+ /*
+ * Array get, 64 bits. vAA <- vBB[vCC].
+ *
+ * Arrays of long/double are 64-bit aligned.
+ */
+ /* aget-wide vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ EAS3(a0, a0, a1) # a0 <- arrayObj + index*width
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+
+.L${opcode}_finish:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ LOAD64_off(a2, a3, a0, offArrayObject_contents)
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a2, a3, rOBJ) # vAA/vAA+1 <- a2/a3
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_AND_INT.S b/vm/mterp/mips/OP_AND_INT.S
new file mode 100644
index 0000000..721129b
--- /dev/null
+++ b/vm/mterp/mips/OP_AND_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"instr":"and a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_AND_INT_2ADDR.S b/vm/mterp/mips/OP_AND_INT_2ADDR.S
new file mode 100644
index 0000000..4563705
--- /dev/null
+++ b/vm/mterp/mips/OP_AND_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"instr":"and a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_AND_INT_LIT16.S b/vm/mterp/mips/OP_AND_INT_LIT16.S
new file mode 100644
index 0000000..81c0a04
--- /dev/null
+++ b/vm/mterp/mips/OP_AND_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit16.S" {"instr":"and a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_AND_INT_LIT8.S b/vm/mterp/mips/OP_AND_INT_LIT8.S
new file mode 100644
index 0000000..61c1c9d
--- /dev/null
+++ b/vm/mterp/mips/OP_AND_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"instr":"and a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_AND_LONG.S b/vm/mterp/mips/OP_AND_LONG.S
new file mode 100644
index 0000000..8249617
--- /dev/null
+++ b/vm/mterp/mips/OP_AND_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopWide.S" {"preinstr":"and a0, a0, a2", "instr":"and a1, a1, a3"}
diff --git a/vm/mterp/mips/OP_AND_LONG_2ADDR.S b/vm/mterp/mips/OP_AND_LONG_2ADDR.S
new file mode 100644
index 0000000..f9bf88f
--- /dev/null
+++ b/vm/mterp/mips/OP_AND_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopWide2addr.S" {"preinstr":"and a0, a0, a2", "instr":"and a1, a1, a3"}
diff --git a/vm/mterp/mips/OP_APUT.S b/vm/mterp/mips/OP_APUT.S
new file mode 100644
index 0000000..7839b69
--- /dev/null
+++ b/vm/mterp/mips/OP_APUT.S
@@ -0,0 +1,27 @@
+%default { "store":"sw", "shift":"2" }
+%verify "executed"
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if $shift
+ EASN(a0, a0, a1, $shift) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a2, rOBJ) # a2 <- vAA
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ $store a2, offArrayObject_contents(a0) # vBB[vCC] <- a2
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_APUT_BOOLEAN.S b/vm/mterp/mips/OP_APUT_BOOLEAN.S
new file mode 100644
index 0000000..eeb9747
--- /dev/null
+++ b/vm/mterp/mips/OP_APUT_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_APUT.S" { "store":"sb", "shift":"0" }
diff --git a/vm/mterp/mips/OP_APUT_BYTE.S b/vm/mterp/mips/OP_APUT_BYTE.S
new file mode 100644
index 0000000..eeb9747
--- /dev/null
+++ b/vm/mterp/mips/OP_APUT_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_APUT.S" { "store":"sb", "shift":"0" }
diff --git a/vm/mterp/mips/OP_APUT_CHAR.S b/vm/mterp/mips/OP_APUT_CHAR.S
new file mode 100644
index 0000000..4c57fb1
--- /dev/null
+++ b/vm/mterp/mips/OP_APUT_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_APUT.S" { "store":"sh", "shift":"1" }
diff --git a/vm/mterp/mips/OP_APUT_OBJECT.S b/vm/mterp/mips/OP_APUT_OBJECT.S
new file mode 100644
index 0000000..1d5b06e
--- /dev/null
+++ b/vm/mterp/mips/OP_APUT_OBJECT.S
@@ -0,0 +1,50 @@
+%verify "executed"
+ /*
+ * Store an object into an array. vBB[vCC] <- vAA.
+ *
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(t1) # t1 <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ GET_VREG(rINST, a2) # rINST <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ GET_VREG(rBIX, t1) # rBIX <- vAA
+ # null array object?
+ beqz rINST, common_errNullObject # yes, bail
+
+ LOAD_base_offArrayObject_length(a3, rINST) # a3 <- arrayObj->length
+ EAS2(rOBJ, rINST, a1) # rOBJ <- arrayObj + index*width
+ # compare unsigned index, length
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ /*
+ * On entry:
+ * rINST = vBB (arrayObj)
+ * rBIX = vAA (obj)
+ * rOBJ = offset into array (vBB + vCC * width)
+ */
+ bnez rBIX, .L${opcode}_checks # yes, skip type checks
+.L${opcode}_finish:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ sw rBIX, offArrayObject_contents(rOBJ) # vBB[vCC] <- vAA
+ GOTO_OPCODE(t0) # jump to next instruction
+
+%break
+.L${opcode}_checks:
+ LOAD_base_offObject_clazz(a0, rBIX) # a0 <- obj->clazz
+ LOAD_base_offObject_clazz(a1, rINST) # a1 <- arrayObj->clazz
+ JAL(dvmCanPutArrayElement) # test object type vs. array type
+ beqz v0, .L${opcode}_throw # okay ?
+ lw a2, offThread_cardTable(rSELF)
+ srl t1, rINST, GC_CARD_SHIFT
+ addu t2, a2, t1
+ sb a2, (t2)
+ b .L${opcode}_finish # yes, skip type checks
+.L${opcode}_throw:
+ LOAD_base_offObject_clazz(a0, rBIX) # a0 <- obj->clazz
+ LOAD_base_offObject_clazz(a1, rINST) # a1 <- arrayObj->clazz
+ EXPORT_PC()
+ JAL(dvmThrowArrayStoreExceptionIncompatibleElement)
+ b common_exceptionThrown
diff --git a/vm/mterp/mips/OP_APUT_SHORT.S b/vm/mterp/mips/OP_APUT_SHORT.S
new file mode 100644
index 0000000..4c57fb1
--- /dev/null
+++ b/vm/mterp/mips/OP_APUT_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_APUT.S" { "store":"sh", "shift":"1" }
diff --git a/vm/mterp/mips/OP_APUT_WIDE.S b/vm/mterp/mips/OP_APUT_WIDE.S
new file mode 100644
index 0000000..0046cd5
--- /dev/null
+++ b/vm/mterp/mips/OP_APUT_WIDE.S
@@ -0,0 +1,27 @@
+%verify "executed"
+ /*
+ * Array put, 64 bits. vBB[vCC] <- vAA.
+ *
+ * Arrays of long/double are 64-bit aligned, so it's okay to use STRD.
+ */
+ /* aput-wide vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(t0) # t0 <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ EAS3(a0, a0, a1) # a0 <- arrayObj + index*width
+ EAS2(rOBJ, rFP, t0) # rOBJ <- &fp[AA]
+ # compare unsigned index, length
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ LOAD64(a2, a3, rOBJ) # a2/a3 <- vAA/vAA+1
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64_off(a2, a3, a0, offArrayObject_contents) # a2/a3 <- vBB[vCC]
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_ARRAY_LENGTH.S b/vm/mterp/mips/OP_ARRAY_LENGTH.S
new file mode 100644
index 0000000..9416011
--- /dev/null
+++ b/vm/mterp/mips/OP_ARRAY_LENGTH.S
@@ -0,0 +1,14 @@
+%verify "executed"
+ /*
+ * Return the length of an array.
+ */
+ GET_OPB(a1) # a1 <- B
+ GET_OPA4(a2) # a2 <- A+
+ GET_VREG(a0, a1) # a0 <- vB (object ref)
+ # is object null?
+ beqz a0, common_errNullObject # yup, fail
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- array length
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a3, a2, t0) # vA <- length
+
diff --git a/vm/mterp/mips/OP_BREAKPOINT.S b/vm/mterp/mips/OP_BREAKPOINT.S
new file mode 100644
index 0000000..3624810
--- /dev/null
+++ b/vm/mterp/mips/OP_BREAKPOINT.S
@@ -0,0 +1,15 @@
+%verify "executed"
+ /*
+ * Breakpoint handler.
+ *
+ * Restart this instruction with the original opcode. By
+ * the time we get here, the breakpoint will have already been
+ * handled.
+ */
+ move a0, rPC
+ JAL(dvmGetOriginalOpcode) # (rPC)
+ FETCH(rINST, 0) # reload OP_BREAKPOINT + rest of inst
+ lw a1, offThread_mainHandlerTable(rSELF)
+ and rINST, 0xff00
+ or rINST, rINST, a0
+ GOTO_OPCODE_BASE(a1, a0)
diff --git a/vm/mterp/mips/OP_CHECK_CAST.S b/vm/mterp/mips/OP_CHECK_CAST.S
new file mode 100644
index 0000000..f29a51f
--- /dev/null
+++ b/vm/mterp/mips/OP_CHECK_CAST.S
@@ -0,0 +1,71 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+ /*
+ * Check to see if a cast from one class to another is allowed.
+ */
+ # check-cast vAA, class /* BBBB */
+ GET_OPA(a3) # a3 <- AA
+ FETCH(a2, 1) # a2 <- BBBB
+ GET_VREG(rOBJ, a3) # rOBJ <- object
+ LOAD_rSELF_methodClassDex(a0) # a0 <- pDvmDex
+ LOAD_base_offDvmDex_pResClasses(a0, a0) # a0 <- pDvmDex->pResClasses
+ # is object null?
+ beqz rOBJ, .L${opcode}_okay # null obj, cast always succeeds
+ LOAD_eas2(a1, a0, a2) # a1 <- resolved class
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- obj->clazz
+ # have we resolved this before?
+ beqz a1, .L${opcode}_resolve # not resolved, do it now
+.L${opcode}_resolved:
+ # same class (trivial success)?
+ bne a0, a1, .L${opcode}_fullcheck # no, do full check
+.L${opcode}_okay:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * a0 holds obj->clazz
+ * a1 holds class resolved from BBBB
+ * rOBJ holds object
+ */
+.L${opcode}_fullcheck:
+ move rBIX,a1 # avoid ClassObject getting clobbered
+ JAL(dvmInstanceofNonTrivial) # v0 <- boolean result
+ # failed?
+ bnez v0, .L${opcode}_okay # no, success
+ b .L${opcode}_castfailure
+%break
+
+.L${opcode}_castfailure:
+ # A cast has failed. We need to throw a ClassCastException with the
+ # class of the object that failed to be cast.
+ EXPORT_PC() # about to throw
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- obj->clazz
+ move a1,rBIX # r1<- desired class
+ JAL(dvmThrowClassCastException)
+ b common_exceptionThrown
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * a2 holds BBBB
+ * rOBJ holds object
+ */
+.L${opcode}_resolve:
+ EXPORT_PC() # resolve() could throw
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ move a1, a2 # a1 <- BBBB
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- resolved ClassObject ptr
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ move a1, v0 # a1 <- class resolved from BBB
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- obj->clazz
+ b .L${opcode}_resolved # pick up where we left off
diff --git a/vm/mterp/mips/OP_CHECK_CAST_JUMBO.S b/vm/mterp/mips/OP_CHECK_CAST_JUMBO.S
new file mode 100644
index 0000000..966ffab
--- /dev/null
+++ b/vm/mterp/mips/OP_CHECK_CAST_JUMBO.S
@@ -0,0 +1,84 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+ /*
+ * Check to see if a cast from one class to another is allowed.
+ */
+ /* check-cast/ jumbo vBBBB, class #AAAAAAAA */
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ FETCH(a2, 2) # a2<- AAAA (hi)
+ FETCH(a3, 3) # a3<- BBBB
+ sll a2,a2,16
+ or a2, a0, a2 # a2<- AAAAaaaa
+
+ GET_VREG(rOBJ, a3) # rOBJ<- object
+ LOAD_rSELF_methodClassDex(a0) # a0<- pDvmDex
+ LOAD_base_offDvmDex_pResClasses(a0, a0) # a0<- pDvmDex->pResClasses
+ # is object null?
+ beqz rOBJ, .L${opcode}_okay # null obj, cast always succeeds
+ LOAD_eas2(a1, a0, a2) # a1<- resolved class
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0<- obj->clazz
+ # have we resolved this before?
+ beqz a1, .L${opcode}_resolve # not resolved, do it now
+.L${opcode}_resolved:
+ # same class (trivial success)?
+ bne a0, a1, .L${opcode}_fullcheck # no, do full check
+ b .L${opcode}_okay # yes, finish up
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * a0 holds obj->clazz
+ * a1 holds class resolved from BBBB
+ * rOBJ holds object
+ */
+.L${opcode}_fullcheck:
+ move rBIX,a1 # avoid ClassObject getting clobbered
+ JAL(dvmInstanceofNonTrivial) # v0<- boolean result
+ # failed?
+ bnez v0, .L${opcode}_okay # no, success
+ b .L${opcode}_castfailure
+
+%break
+
+
+.L${opcode}_castfailure:
+ # A cast has failed. We need to throw a ClassCastException with the
+ # class of the object that failed to be cast.
+ EXPORT_PC() # about to throw
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0<- obj->clazz
+ move a1,rBIX # r1<- desired class
+ JAL(dvmThrowClassCastException)
+ b common_exceptionThrown
+
+ /*
+ * Advance PC and get next opcode
+ *
+ */
+.L${opcode}_okay:
+ FETCH_ADVANCE_INST(4) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * a2 holds AAAAAAAA
+ * rOBJ holds object
+ */
+.L${opcode}_resolve:
+ EXPORT_PC() # resolve() could throw
+ LOAD_rSELF_method(a3) # a3<- self->method
+ move a1, a2 # a1<- AAAAAAAA
+ li a2, 0 # a2<- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0<- method->clazz
+ JAL(dvmResolveClass) # v0<- resolved ClassObject ptr
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ move a1, v0 # a1<- class resolved from AAAAAAAA
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0<- obj->clazz
+ b .L${opcode}_resolved # pick up where we left off
+
+
diff --git a/vm/mterp/mips/OP_CMPG_DOUBLE.S b/vm/mterp/mips/OP_CMPG_DOUBLE.S
new file mode 100644
index 0000000..8e740e3
--- /dev/null
+++ b/vm/mterp/mips/OP_CMPG_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_CMPL_DOUBLE.S" { "naninst":"li rTEMP, 1" }
diff --git a/vm/mterp/mips/OP_CMPG_FLOAT.S b/vm/mterp/mips/OP_CMPG_FLOAT.S
new file mode 100644
index 0000000..2c4e97b
--- /dev/null
+++ b/vm/mterp/mips/OP_CMPG_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_CMPL_FLOAT.S" { "naninst":"li rTEMP, 1" }
diff --git a/vm/mterp/mips/OP_CMPL_DOUBLE.S b/vm/mterp/mips/OP_CMPL_DOUBLE.S
new file mode 100644
index 0000000..63bb005
--- /dev/null
+++ b/vm/mterp/mips/OP_CMPL_DOUBLE.S
@@ -0,0 +1,70 @@
+%default { "naninst":"li rTEMP, -1" }
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * See OP_CMPL_FLOAT for an explanation.
+ *
+ * For: cmpl-double, cmpg-double
+ */
+ /* op vAA, vBB, vCC */
+
+ FETCH(a0, 1) # a0 <- CCBB
+ and rOBJ, a0, 255 # s0 <- BB
+ srl rBIX, a0, 8 # t0 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # s0 <- &fp[BB]
+ EAS2(rBIX, rFP, rBIX) # t0 <- &fp[CC]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3 <- vCC/vCC+1
+ JAL(__eqdf2) # cmp <=: C clear if <, Z set if eq
+ li rTEMP, 0
+ beqz v0, ${opcode}_finish
+
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3 <- vCC/vCC+1
+ JAL(__ltdf2)
+ li rTEMP, -1
+ bltz v0, ${opcode}_finish
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vBB/vBB+1
+ b ${opcode}_continue
+#else
+ LOAD64_F(fs0, fs0f, rOBJ)
+ LOAD64_F(fs1, fs1f, rBIX)
+ c.olt.d fcc0, fs0, fs1
+ li rTEMP, -1
+ bc1t fcc0, ${opcode}_finish
+ c.olt.d fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, ${opcode}_finish
+ c.eq.d fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, ${opcode}_finish
+ b ${opcode}_nan
+#endif
+%break
+
+${opcode}_nan:
+ $naninst
+ b ${opcode}_finish
+
+#ifdef SOFT_FLOAT
+${opcode}_continue:
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3 <- vCC/vCC+1
+ JAL(__gtdf2) # fallthru
+ li rTEMP, 1 # rTEMP = 1 if v0 != 0
+ blez v0, ${opcode}_nan # fall thru for finish
+#endif
+
+${opcode}_finish:
+ GET_OPA(rOBJ)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(rTEMP, rOBJ, t0) # vAA <- rTEMP
diff --git a/vm/mterp/mips/OP_CMPL_FLOAT.S b/vm/mterp/mips/OP_CMPL_FLOAT.S
new file mode 100644
index 0000000..6e07084
--- /dev/null
+++ b/vm/mterp/mips/OP_CMPL_FLOAT.S
@@ -0,0 +1,82 @@
+%default { "naninst":"li rTEMP, -1" }
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * for: cmpl-float, cmpg-float
+ */
+ /* op vAA, vBB, vCC */
+
+ /* "clasic" form */
+ FETCH(a0, 1) # a0 <- CCBB
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8
+#ifdef SOFT_FLOAT
+ GET_VREG(rOBJ, a2) # rOBJ <- vBB
+ GET_VREG(rBIX, a3) # rBIX <- vCC
+ move a0, rOBJ # a0 <- vBB
+ move a1, rBIX # a1 <- vCC
+ JAL(__eqsf2) # a0 <- (vBB == vCC)
+ li rTEMP, 0 # set rTEMP to 0
+ beqz v0, ${opcode}_finish
+ move a0, rOBJ # a0 <- vBB
+ move a1, rBIX # a1 <- vCC
+ JAL(__ltsf2) # a0 <- (vBB < vCC)
+ li rTEMP, -1
+ bltz v0, ${opcode}_finish
+ move a0, rOBJ # a0 <- vBB
+ move a1, rBIX # a1 <- vCC
+ b ${opcode}_continue
+#else
+ GET_VREG_F(fs0, a2)
+ GET_VREG_F(fs1, a3)
+ c.olt.s fcc0, fs0, fs1 # Is fs0 < fs1
+ li rTEMP, -1
+ bc1t fcc0, ${opcode}_finish
+ c.olt.s fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, ${opcode}_finish
+ c.eq.s fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, ${opcode}_finish
+ b ${opcode}_nan
+
+#endif
+
+%break
+
+${opcode}_nan:
+ $naninst
+ b ${opcode}_finish
+
+#ifdef SOFT_FLOAT
+${opcode}_continue:
+ JAL(__gtsf2) # v0 <- (vBB > vCC)
+ li rTEMP, 1 # rTEMP = 1 if v0 != 0
+ bgtz v0, ${opcode}_finish
+ b ${opcode}_nan
+#endif
+
+${opcode}_finish:
+ GET_OPA(t0)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ SET_VREG(rTEMP, t0) # vAA <- rTEMP
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0)
diff --git a/vm/mterp/mips/OP_CMP_LONG.S b/vm/mterp/mips/OP_CMP_LONG.S
new file mode 100644
index 0000000..fcdfce7
--- /dev/null
+++ b/vm/mterp/mips/OP_CMP_LONG.S
@@ -0,0 +1,40 @@
+%verify "executed"
+%verify "basic lt, gt, eq"
+%verify "hi equal, lo <=>"
+%verify "lo equal, hi <=>"
+ /*
+ * Compare two 64-bit values
+ * x = y return 0
+ * x < y return -1
+ * x > y return 1
+ *
+ * I think I can improve on the ARM code by the following observation
+ * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
+ * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
+ * subu v0, t0, t1 # v0= -1:1:0 for [ < > = ]
+ */
+ /* cmp-long vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(a3, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a0, a1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a2, a3, a3) # a2/a3 <- vCC/vCC+1
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ slt t0, a1, a3 # compare hi
+ sgt t1, a1, a3
+ subu v0, t1, t0 # v0 <- (-1, 1, 0)
+ bnez v0, .L${opcode}_finish
+ # at this point x.hi==y.hi
+ sltu t0, a0, a2 # compare lo
+ sgtu t1, a0, a2
+ subu v0, t1, t0 # v0 <- (-1, 1, 0) for [< > =]
+
+.L${opcode}_finish:
+ SET_VREG(v0, rOBJ) # vAA <- v0
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_CONST.S b/vm/mterp/mips/OP_CONST.S
new file mode 100644
index 0000000..309b52a
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST.S
@@ -0,0 +1,11 @@
+%verify "executed"
+ # const vAA, /* +BBBBbbbb */
+ GET_OPA(a3) # a3 <- AA
+ FETCH(a0, 1) # a0 <- bbbb (low)
+ FETCH(a1, 2) # a1 <- BBBB (high)
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ sll a1, a1, 16
+ or a0, a1, a0 # a0 <- BBBBbbbb
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, a3, t0) # vAA <- a0
+
diff --git a/vm/mterp/mips/OP_CONST_16.S b/vm/mterp/mips/OP_CONST_16.S
new file mode 100644
index 0000000..69732f4
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_16.S
@@ -0,0 +1,8 @@
+%verify "executed"
+ # const/16 vAA, /* +BBBB */
+ FETCH_S(a0, 1) # a0 <- ssssBBBB (sign-extended)
+ GET_OPA(a3) # a3 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, a3, t0) # vAA <- a0
+
diff --git a/vm/mterp/mips/OP_CONST_4.S b/vm/mterp/mips/OP_CONST_4.S
new file mode 100644
index 0000000..833e373
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_4.S
@@ -0,0 +1,10 @@
+%verify "executed"
+ # const/4 vA, /* +B */
+ sll a1, rINST, 16 # a1 <- Bxxx0000
+ GET_OPA(a0) # a0 <- A+
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ sra a1, a1, 28 # a1 <- sssssssB (sign-extended)
+ and a0, a0, 15
+ GET_INST_OPCODE(t0) # ip <- opcode from rINST
+ SET_VREG_GOTO(a1, a0, t0) # fp[A] <- a1
+
diff --git a/vm/mterp/mips/OP_CONST_CLASS.S b/vm/mterp/mips/OP_CONST_CLASS.S
new file mode 100644
index 0000000..f63d7c3
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_CLASS.S
@@ -0,0 +1,31 @@
+%verify "executed"
+%verify "Class already resolved"
+%verify "Class not yet resolved"
+%verify "Class cannot be resolved"
+ # const/class vAA, Class /* BBBB */
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_rSELF_methodClassDex(a2) # a2 <- self->methodClassDex
+ GET_OPA(rOBJ) # rOBJ <- AA
+ LOAD_base_offDvmDex_pResClasses(a2, a2) # a2 <- dvmDex->pResClasses
+ LOAD_eas2(v0, a2, a1) # v0 <- pResClasses[BBBB]
+
+ bnez v0, .L${opcode}_resolve # v0!=0 => resolved-ok
+ /*
+ * Continuation if the Class has not yet been resolved.
+ * a1: BBBB (Class ref)
+ * rOBJ: target register
+ */
+ EXPORT_PC()
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ li a2, 1 # a2 <- true
+ LOAD_base_offMethod_clazz(a0, a0) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- Class reference
+ # failed==0?
+ beqz v0, common_exceptionThrown # yup, handle the exception
+
+.L${opcode}_resolve:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(v0, rOBJ, t0) # vAA <- v0
+
+
diff --git a/vm/mterp/mips/OP_CONST_CLASS_JUMBO.S b/vm/mterp/mips/OP_CONST_CLASS_JUMBO.S
new file mode 100644
index 0000000..05604b9
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_CLASS_JUMBO.S
@@ -0,0 +1,34 @@
+%verify "executed"
+%verify "Class already resolved"
+%verify "Class not yet resolved"
+%verify "Class cannot be resolved"
+ /* const-class/jumbo vBBBB, Class@AAAAAAAA */
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ LOAD_rSELF_methodClassDex(a2) # a2 <- self->methodClassDex
+ FETCH(a1, 2) # a1<- AAAA (hi)
+ LOAD_base_offDvmDex_pResClasses(a2, a2) # a2 <- dvmDex->pResClasses
+ sll a1,a1,16
+ or a1, a0, a1 # a1<- AAAAaaaa
+ FETCH(rOBJ, 3) # rOBJ<- BBBB
+ LOAD_eas2(v0, a2, a1) # v0 <- pResClasses[BBBB]
+
+ bnez v0, .L${opcode}_resolve # v0!=0 => resolved-ok
+ /*
+ * Continuation if the Class has not yet been resolved.
+ * a1: AAAAAAAA (Class ref)
+ * rOBJ: target register
+ */
+ EXPORT_PC()
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ li a2, 1 # a2 <- true
+ LOAD_base_offMethod_clazz(a0, a0) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- Class reference
+ # failed==0?
+ beqz v0, common_exceptionThrown # yup, handle the exception
+
+.L${opcode}_resolve:
+ FETCH_ADVANCE_INST(4) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(v0, rOBJ, t0) # vBBBB <- v0
+
+
diff --git a/vm/mterp/mips/OP_CONST_HIGH16.S b/vm/mterp/mips/OP_CONST_HIGH16.S
new file mode 100644
index 0000000..04c6d5d
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_HIGH16.S
@@ -0,0 +1,9 @@
+%verify "executed"
+ # const/high16 vAA, /* +BBBB0000 */
+ FETCH(a0, 1) # a0 <- 0000BBBB (zero-extended)
+ GET_OPA(a3) # a3 <- AA
+ sll a0, a0, 16 # a0 <- BBBB0000
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, a3, t0) # vAA <- a0
+
diff --git a/vm/mterp/mips/OP_CONST_STRING.S b/vm/mterp/mips/OP_CONST_STRING.S
new file mode 100644
index 0000000..f59b1d6
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_STRING.S
@@ -0,0 +1,33 @@
+%verify "executed"
+%verify "String already resolved"
+%verify "String not yet resolved"
+%verify "String cannot be resolved"
+ # const/string vAA, String /* BBBB */
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_rSELF_methodClassDex(a2) # a2 <- self->methodClassDex
+ GET_OPA(rOBJ) # rOBJ <- AA
+ LOAD_base_offDvmDex_pResStrings(a2, a2) # a2 <- dvmDex->pResStrings
+ LOAD_eas2(v0, a2, a1) # v0 <- pResStrings[BBBB]
+ # not yet resolved?
+ bnez v0, .L${opcode}_resolve
+ /*
+ * Continuation if the String has not yet been resolved.
+ * a1: BBBB (String ref)
+ * rOBJ: target register
+ */
+ EXPORT_PC()
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ LOAD_base_offMethod_clazz(a0, a0) # a0 <- method->clazz
+ JAL(dvmResolveString) # v0 <- String reference
+ # failed?
+ beqz v0, common_exceptionThrown # yup, handle the exception
+
+.L${opcode}_resolve:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(v0, rOBJ, t0) # vAA <- v0
+
+
+
+
+
diff --git a/vm/mterp/mips/OP_CONST_STRING_JUMBO.S b/vm/mterp/mips/OP_CONST_STRING_JUMBO.S
new file mode 100644
index 0000000..0c3d0bd
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_STRING_JUMBO.S
@@ -0,0 +1,32 @@
+%verify "executed"
+%verify "String already resolved"
+%verify "String not yet resolved"
+%verify "String cannot be resolved"
+ # const/string vAA, String /* BBBBBBBB */
+ FETCH(a0, 1) # a0 <- bbbb (low)
+ FETCH(a1, 2) # a1 <- BBBB (high)
+ LOAD_rSELF_methodClassDex(a2) # a2 <- self->methodClassDex
+ GET_OPA(rOBJ) # rOBJ <- AA
+ LOAD_base_offDvmDex_pResStrings(a2, a2) # a2 <- dvmDex->pResStrings
+ sll a1, a1, 16
+ or a1, a1, a0 # a1 <- BBBBbbbb
+ LOAD_eas2(v0, a2, a1) # v0 <- pResStrings[BBBB]
+ bnez v0, .L${opcode}_resolve
+
+ /*
+ * Continuation if the String has not yet been resolved.
+ * a1: BBBBBBBB (String ref)
+ * rOBJ: target register
+ */
+ EXPORT_PC()
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ LOAD_base_offMethod_clazz(a0, a0) # a0 <- method->clazz
+ JAL(dvmResolveString) # v0 <- String reference
+ # failed?
+ beqz v0, common_exceptionThrown # yup, handle the exception
+
+.L${opcode}_resolve:
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ SET_VREG_GOTO(v0, rOBJ, t1) # vAA <- v0
+
diff --git a/vm/mterp/mips/OP_CONST_WIDE.S b/vm/mterp/mips/OP_CONST_WIDE.S
new file mode 100644
index 0000000..ba1c462
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_WIDE.S
@@ -0,0 +1,17 @@
+%verify "executed"
+ # const-wide vAA, /* +HHHHhhhhBBBBbbbb */
+ FETCH(a0, 1) # a0 <- bbbb (low)
+ FETCH(a1, 2) # a1 <- BBBB (low middle)
+ FETCH(a2, 3) # a2 <- hhhh (high middle)
+ sll a1, 16 #
+ or a0, a1 # a0 <- BBBBbbbb (low word)
+ FETCH(a3, 4) # a3 <- HHHH (high)
+ GET_OPA(t1) # t1 <- AA
+ sll a3, 16
+ or a1, a3, a2 # a1 <- HHHHhhhh (high word)
+ FETCH_ADVANCE_INST(5) # advance rPC, load rINST
+ EAS2(t1, rFP, t1) # t1 <- &fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, t1) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_CONST_WIDE_16.S b/vm/mterp/mips/OP_CONST_WIDE_16.S
new file mode 100644
index 0000000..d431529
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_WIDE_16.S
@@ -0,0 +1,11 @@
+%verify "executed"
+ # const-wide/16 vAA, /* +BBBB */
+ FETCH_S(a0, 1) # a0 <- ssssBBBB (sign-extended)
+ GET_OPA(a3) # a3 <- AA
+ sra a1, a0, 31 # a1 <- ssssssss
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a3, rFP, a3) # a3 <- &fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_CONST_WIDE_32.S b/vm/mterp/mips/OP_CONST_WIDE_32.S
new file mode 100644
index 0000000..9cb9a3f
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_WIDE_32.S
@@ -0,0 +1,14 @@
+%verify "executed"
+ # const-wide/32 vAA, /* +BBBBbbbb */
+ FETCH(a0, 1) # a0 <- 0000bbbb (low)
+ GET_OPA(a3) # a3 <- AA
+ FETCH_S(a2, 2) # a2 <- ssssBBBB (high)
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ sll a2, a2, 16
+ or a0, a0, a2 # a0 <- BBBBbbbb
+ EAS2(a3, rFP, a3) # a3 <- &fp[AA]
+ sra a1, a0, 31 # a1 <- ssssssss
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_CONST_WIDE_HIGH16.S b/vm/mterp/mips/OP_CONST_WIDE_HIGH16.S
new file mode 100644
index 0000000..c56cd26
--- /dev/null
+++ b/vm/mterp/mips/OP_CONST_WIDE_HIGH16.S
@@ -0,0 +1,12 @@
+%verify "executed"
+ # const-wide/high16 vAA, /* +BBBB000000000000 */
+ FETCH(a1, 1) # a1 <- 0000BBBB (zero-extended)
+ GET_OPA(a3) # a3 <- AA
+ li a0, 0 # a0 <- 00000000
+ sll a1, 16 # a1 <- BBBB0000
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a3, rFP, a3) # a3 <- &fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_DISPATCH_FF.S b/vm/mterp/mips/OP_DISPATCH_FF.S
new file mode 100644
index 0000000..0503c33
--- /dev/null
+++ b/vm/mterp/mips/OP_DISPATCH_FF.S
@@ -0,0 +1,4 @@
+%verify "executed"
+ srl t0, rINST, 8 # t0<- extended opcode
+ addu t0, t0, 256 # add offset for extended opcodes
+ GOTO_OPCODE(t0) # go to proper extended handler
diff --git a/vm/mterp/mips/OP_DIV_DOUBLE.S b/vm/mterp/mips/OP_DIV_DOUBLE.S
new file mode 100644
index 0000000..a7e0302
--- /dev/null
+++ b/vm/mterp/mips/OP_DIV_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflopWide.S" {"instr":"JAL(__divdf3)", "instr_f":"div.d fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_DIV_DOUBLE_2ADDR.S b/vm/mterp/mips/OP_DIV_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..18e28d7
--- /dev/null
+++ b/vm/mterp/mips/OP_DIV_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflopWide2addr.S" {"instr":"JAL(__divdf3)", "instr_f":"div.d fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_DIV_FLOAT.S b/vm/mterp/mips/OP_DIV_FLOAT.S
new file mode 100644
index 0000000..59bb8d6
--- /dev/null
+++ b/vm/mterp/mips/OP_DIV_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflop.S" {"instr":"JAL(__divsf3)", "instr_f":"div.s fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_DIV_FLOAT_2ADDR.S b/vm/mterp/mips/OP_DIV_FLOAT_2ADDR.S
new file mode 100644
index 0000000..a0a546f
--- /dev/null
+++ b/vm/mterp/mips/OP_DIV_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflop2addr.S" {"instr":"JAL(__divsf3)", "instr_f":"div.s fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_DIV_INT.S b/vm/mterp/mips/OP_DIV_INT.S
new file mode 100644
index 0000000..b845475
--- /dev/null
+++ b/vm/mterp/mips/OP_DIV_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"instr":"div zero, a0, a1; mflo a0", "chkzero":"1"}
diff --git a/vm/mterp/mips/OP_DIV_INT_2ADDR.S b/vm/mterp/mips/OP_DIV_INT_2ADDR.S
new file mode 100644
index 0000000..1f13ad8
--- /dev/null
+++ b/vm/mterp/mips/OP_DIV_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"instr":"div zero, a0, a1; mflo a0", "chkzero":"1"}
diff --git a/vm/mterp/mips/OP_DIV_INT_LIT16.S b/vm/mterp/mips/OP_DIV_INT_LIT16.S
new file mode 100644
index 0000000..d75d210
--- /dev/null
+++ b/vm/mterp/mips/OP_DIV_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit16.S" {"instr":"div zero, a0, a1; mflo a0", "chkzero":"1"}
diff --git a/vm/mterp/mips/OP_DIV_INT_LIT8.S b/vm/mterp/mips/OP_DIV_INT_LIT8.S
new file mode 100644
index 0000000..384eb0d
--- /dev/null
+++ b/vm/mterp/mips/OP_DIV_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"instr":"div zero, a0, a1; mflo a0", "chkzero":"1"}
diff --git a/vm/mterp/mips/OP_DIV_LONG.S b/vm/mterp/mips/OP_DIV_LONG.S
new file mode 100644
index 0000000..bb39d2a
--- /dev/null
+++ b/vm/mterp/mips/OP_DIV_LONG.S
@@ -0,0 +1,6 @@
+%verify "executed"
+#ifdef HAVE_LITTLE_ENDIAN
+%include "mips/binopWide.S" {"result0":"v0", "result1":"v1", "instr":"JAL(__divdi3)", "chkzero":"1"}
+#else
+%include "mips/binopWide.S" { "arg0":"a1", "arg1":"a0", "arg2":"a3", "arg3":"a2", "result0":"v1", "result1":"v0", "instr":"JAL(__divdi3)", "chkzero":"1"}
+#endif
diff --git a/vm/mterp/mips/OP_DIV_LONG_2ADDR.S b/vm/mterp/mips/OP_DIV_LONG_2ADDR.S
new file mode 100644
index 0000000..8e751b6
--- /dev/null
+++ b/vm/mterp/mips/OP_DIV_LONG_2ADDR.S
@@ -0,0 +1,6 @@
+%verify "executed"
+#ifdef HAVE_LITTLE_ENDIAN
+%include "mips/binopWide2addr.S" {"result0":"v0", "result1":"v1", "instr":"JAL(__divdi3)", "chkzero":"1"}
+#else
+%include "mips/binopWide2addr.S" {"arg0":"a1", "arg1":"a0", "arg2":"a3", "arg3":"a2", "result0":"v1", "result1":"v0", "instr":"JAL(__divdi3)", "chkzero":"1"}
+#endif
diff --git a/vm/mterp/mips/OP_DOUBLE_TO_FLOAT.S b/vm/mterp/mips/OP_DOUBLE_TO_FLOAT.S
new file mode 100644
index 0000000..f1e04ea
--- /dev/null
+++ b/vm/mterp/mips/OP_DOUBLE_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unopNarrower.S" {"instr":"JAL(__truncdfsf2)", "instr_f":"cvt.s.d fv0, fa0"}
diff --git a/vm/mterp/mips/OP_DOUBLE_TO_INT.S b/vm/mterp/mips/OP_DOUBLE_TO_INT.S
new file mode 100644
index 0000000..33199c4
--- /dev/null
+++ b/vm/mterp/mips/OP_DOUBLE_TO_INT.S
@@ -0,0 +1,80 @@
+%verify "executed"
+%include "mips/unopNarrower.S" {"instr":"b d2i_doconv", "instr_f":"b d2i_doconv"}
+/*
+ * Convert the double in a0/a1 to an int in a0.
+ *
+ * We have to clip values to int min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ * Use rBIX / rTEMP as global to hold arguments (they are not bound to a global var)
+ */
+%break
+
+
+d2i_doconv:
+#ifdef SOFT_FLOAT
+ la t0, .LDOUBLE_TO_INT_max
+ LOAD64(rARG2, rARG3, t0)
+ move rBIX, rARG0 # save a0
+ move rTEMP, rARG1 # and a1
+ JAL(__gedf2) # is arg >= maxint?
+
+ move t0, v0
+ li v0, ~0x80000000 # return maxint (7fffffff)
+ bgez t0, .L${opcode}_set_vreg # nonzero == yes
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rTEMP
+ la t0, .LDOUBLE_TO_INT_min
+ LOAD64(rARG2, rARG3, t0)
+ JAL(__ledf2) # is arg <= minint?
+
+ move t0, v0
+ li v0, 0x80000000 # return minint (80000000)
+ blez t0, .L${opcode}_set_vreg # nonzero == yes
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rTEMP
+ move rARG2, rBIX # compare against self
+ move rARG3, rTEMP
+ JAL(__nedf2) # is arg == self?
+
+ move t0, v0 # zero == no
+ li v0, 0
+ bnez t0, .L${opcode}_set_vreg # return zero for NaN
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rTEMP
+ JAL(__fixdfsi) # convert double to int
+ b .L${opcode}_set_vreg
+#else
+ la t0, .LDOUBLE_TO_INT_max
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa1, fa0
+ l.s fv0, .LDOUBLE_TO_INT_maxret
+ bc1t .L${opcode}_set_vreg_f
+
+ la t0, .LDOUBLE_TO_INT_min
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa0, fa1
+ l.s fv0, .LDOUBLE_TO_INT_minret
+ bc1t .L${opcode}_set_vreg_f
+
+ mov.d fa1, fa0
+ c.un.d fcc0, fa0, fa1
+ li.s fv0, 0
+ bc1t .L${opcode}_set_vreg_f
+
+ trunc.w.d fv0, fa0
+ b .L${opcode}_set_vreg_f
+#endif
+
+
+.LDOUBLE_TO_INT_max:
+ .dword 0x41dfffffffc00000
+.LDOUBLE_TO_INT_min:
+ .dword 0xc1e0000000000000 # minint, as a double (high word)
+.LDOUBLE_TO_INT_maxret:
+ .word 0x7fffffff
+.LDOUBLE_TO_INT_minret:
+ .word 0x80000000
diff --git a/vm/mterp/mips/OP_DOUBLE_TO_LONG.S b/vm/mterp/mips/OP_DOUBLE_TO_LONG.S
new file mode 100644
index 0000000..153d557
--- /dev/null
+++ b/vm/mterp/mips/OP_DOUBLE_TO_LONG.S
@@ -0,0 +1,76 @@
+%verify "executed"
+%include "mips/unflopWide.S" {"instr":"b d2l_doconv", "st_result":"STORE64(rRESULT0, rRESULT1, rOBJ)"}
+%break
+
+d2l_doconv:
+#ifdef SOFT_FLOAT
+ la t0, .LDOUBLE_TO_LONG_max
+ LOAD64(rARG2, rARG3, t0)
+ move rBIX, rARG0 # save a0
+ move rTEMP, rARG1 # and a1
+ JAL(__gedf2)
+
+ move t1, v0
+ la t0, .LDOUBLE_TO_LONG_ret_max
+ LOAD64(rRESULT0, rRESULT1, t0)
+ bgez t1, .L${opcode}_set_vreg
+
+ move rARG0, rBIX
+ move rARG1, rTEMP
+ la t0, .LDOUBLE_TO_LONG_min
+ LOAD64(rARG2, rARG3, t0)
+ JAL(__ledf2)
+
+ move t1, v0
+ la t0, .LDOUBLE_TO_LONG_ret_min
+ LOAD64(rRESULT0, rRESULT1, t0)
+ blez t1, .L${opcode}_set_vreg
+
+ move rARG0, rBIX
+ move rARG1, rTEMP
+ move rARG2, rBIX
+ move rARG3, rTEMP
+ JAL(__nedf2)
+
+ move t0, v0
+ li rRESULT0, 0
+ li rRESULT1, 0
+ bnez t0, .L${opcode}_set_vreg
+
+ move rARG0, rBIX
+ move rARG1, rTEMP
+ JAL(__fixdfdi)
+
+#else
+ la t0, .LDOUBLE_TO_LONG_max
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa1, fa0
+ la t0, .LDOUBLE_TO_LONG_ret_max
+ LOAD64(rRESULT0, rRESULT1, t0)
+ bc1t .L${opcode}_set_vreg
+
+ la t0, .LDOUBLE_TO_LONG_min
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa0, fa1
+ la t0, .LDOUBLE_TO_LONG_ret_min
+ LOAD64(rRESULT0, rRESULT1, t0)
+ bc1t .L${opcode}_set_vreg
+
+ mov.d fa1, fa0
+ c.un.d fcc0, fa0, fa1
+ li rRESULT0, 0
+ li rRESULT1, 0
+ bc1t .L${opcode}_set_vreg
+ JAL(__fixdfdi)
+#endif
+ b .L${opcode}_set_vreg
+
+
+.LDOUBLE_TO_LONG_max:
+ .dword 0x43e0000000000000 # maxlong, as a double (high word)
+.LDOUBLE_TO_LONG_min:
+ .dword 0xc3e0000000000000 # minlong, as a double (high word)
+.LDOUBLE_TO_LONG_ret_max:
+ .dword 0x7fffffffffffffff
+.LDOUBLE_TO_LONG_ret_min:
+ .dword 0x8000000000000000
diff --git a/vm/mterp/mips/OP_EXECUTE_INLINE.S b/vm/mterp/mips/OP_EXECUTE_INLINE.S
new file mode 100644
index 0000000..cbc8917
--- /dev/null
+++ b/vm/mterp/mips/OP_EXECUTE_INLINE.S
@@ -0,0 +1,104 @@
+%verify "executed"
+%verify "exception handled"
+ /*
+ * Execute a "native inline" instruction.
+ *
+ * We need to call an InlineOp4Func:
+ * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+ *
+ * The first four args are in a0-a3, pointer to return value storage
+ * is on the stack. The function's return value is a flag that tells
+ * us if an exception was thrown.
+ *
+ * TUNING: could maintain two tables, pointer in Thread and
+ * swap if profiler/debuggger active.
+ */
+ /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+ lhu a2, offThread_subMode(rSELF)
+ FETCH(rBIX, 1) # rBIX <- BBBB
+ EXPORT_PC() # can throw
+ and a2, kSubModeDebugProfile # Any going on?
+ bnez a2, .L${opcode}_debugmode # yes - take slow path
+.L${opcode}_resume:
+ addu a1, rSELF, offThread_retval # a1 <- &self->retval
+ GET_OPB(a0) # a0 <- B
+ # Stack should have 16/20 available
+ sw a1, STACK_OFFSET_ARG04(sp) # push &self->retval
+ BAL(.L${opcode}_continue) # make call; will return after
+ lw gp, STACK_OFFSET_GP(sp) # restore gp
+ # test boolean result of inline
+ beqz v0, common_exceptionThrown # returned false, handle exception
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+%break
+
+ /*
+ * Extract args, call function.
+ * a0 = #of args (0-4)
+ * rBIX = call index
+ *
+ * Other ideas:
+ * - Use a jump table from the main piece to jump directly into the
+ * AND/LW pairs. Costs a data load, saves a branch.
+ * - Have five separate pieces that do the loading, so we can work the
+ * interleave a little better. Increases code size.
+ */
+.L${opcode}_continue:
+ FETCH(rINST, 2) # rINST <- FEDC
+ beq a0, 0, 0f
+ beq a0, 1, 1f
+ beq a0, 2, 2f
+ beq a0, 3, 3f
+ beq a0, 4, 4f
+ JAL(common_abort) # too many arguments
+
+4:
+ and t0, rINST, 0xf000 # isolate F
+ ESRN(t1, rFP, t0, 10)
+ lw a3, 0(t1) # a3 <- vF (shift right 12, left 2)
+3:
+ and t0, rINST, 0x0f00 # isolate E
+ ESRN(t1, rFP, t0, 6)
+ lw a2, 0(t1) # a2 <- vE
+2:
+ and t0, rINST, 0x00f0 # isolate D
+ ESRN(t1, rFP, t0, 2)
+ lw a1, 0(t1) # a1 <- vD
+1:
+ and t0, rINST, 0x000f # isolate C
+ EASN(t1, rFP, t0, 2)
+ lw a0, 0(t1) # a0 <- vC
+0:
+ la rINST, gDvmInlineOpsTable # table of InlineOperation
+ EAS4(t1, rINST, rBIX) # t1 <- rINST + rBIX<<4
+ lw t9, 0(t1)
+ jr t9 # sizeof=16, "func" is first entry
+ # (not reached)
+
+ /*
+ * We're debugging or profiling.
+ * rBIX: opIndex
+ */
+.L${opcode}_debugmode:
+ move a0, rBIX
+ JAL(dvmResolveInlineNative)
+ beqz v0, .L${opcode}_resume # did it resolve? no, just move on
+ move rOBJ, v0 # remember method
+ move a0, v0
+ move a1, rSELF
+ JAL(dvmFastMethodTraceEnter) # (method, self)
+ addu a1, rSELF, offThread_retval # a1<- &self->retval
+ GET_OPB(a0) # a0 <- B
+ # Stack should have 16/20 available
+ sw a1, 16(sp) # push &self->retval
+ BAL(.L${opcode}_continue) # make call; will return after
+ lw gp, STACK_OFFSET_GP(sp) # restore gp
+ move rINST, v0 # save result of inline
+ move a0, rOBJ # a0<- method
+ move a1, rSELF # a1<- self
+ JAL(dvmFastMethodTraceExit) # (method, self)
+ beqz v0, common_exceptionThrown # returned false, handle exception
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_EXECUTE_INLINE_RANGE.S b/vm/mterp/mips/OP_EXECUTE_INLINE_RANGE.S
new file mode 100644
index 0000000..3c95a8c
--- /dev/null
+++ b/vm/mterp/mips/OP_EXECUTE_INLINE_RANGE.S
@@ -0,0 +1,92 @@
+%verify "executed"
+%verify "exception handled"
+ /*
+ * Execute a "native inline" instruction, using "/range" semantics.
+ * Same idea as execute-inline, but we get the args differently.
+ *
+ * We need to call an InlineOp4Func:
+ * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+ *
+ * The first four args are in a0-a3, pointer to return value storage
+ * is on the stack. The function's return value is a flag that tells
+ * us if an exception was thrown.
+ */
+ /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */
+ lhu a2, offThread_subMode(rSELF)
+ FETCH(rBIX, 1) # rBIX<- BBBB
+ EXPORT_PC() # can throw
+ and a2, kSubModeDebugProfile # Any going on?
+ bnez a2, .L${opcode}_debugmode # yes - take slow path
+.L${opcode}_resume:
+ addu a1, rSELF, offThread_retval # a1<- &self->retval
+ GET_OPA(a0)
+ sw a1, STACK_OFFSET_ARG04(sp) # push &self->retval
+ BAL(.L${opcode}_continue) # make call; will return after
+ lw gp, STACK_OFFSET_GP(sp) # restore gp
+ beqz v0, common_exceptionThrown # returned false, handle exception
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+%break
+
+ /*
+ * Extract args, call function.
+ * a0 = #of args (0-4)
+ * rBIX = call index
+ * ra = return addr, above [DO NOT JAL out of here w/o preserving ra]
+ */
+.L${opcode}_continue:
+ FETCH(rOBJ, 2) # rOBJ <- CCCC
+ beq a0, 0, 0f
+ beq a0, 1, 1f
+ beq a0, 2, 2f
+ beq a0, 3, 3f
+ beq a0, 4, 4f
+ JAL(common_abort) # too many arguments
+
+4:
+ add t0, rOBJ, 3
+ GET_VREG(a3, t0)
+3:
+ add t0, rOBJ, 2
+ GET_VREG(a2, t0)
+2:
+ add t0, rOBJ, 1
+ GET_VREG(a1, t0)
+1:
+ GET_VREG(a0, rOBJ)
+0:
+ la rOBJ, gDvmInlineOpsTable # table of InlineOperation
+ EAS4(t1, rOBJ, rBIX) # t1 <- rINST + rBIX<<4
+ lw t9, 0(t1)
+ jr t9 # sizeof=16, "func" is first entry
+ # not reached
+
+ /*
+ * We're debugging or profiling.
+ * rBIX: opIndex
+ */
+.L${opcode}_debugmode:
+ move a0, rBIX
+ JAL(dvmResolveInlineNative)
+ beqz v0, .L${opcode}_resume # did it resolve? no, just move on
+ move rOBJ, v0 # remember method
+ move a0, v0
+ move a1, rSELF
+ JAL(dvmFastMethodTraceEnter) # (method, self)
+ addu a1, rSELF, offThread_retval # a1<- &self->retval
+ GET_OPA(a0) # a0 <- A
+ # Stack should have 16/20 available
+ sw a1, 16(sp) # push &self->retval
+ move rINST, rOBJ # rINST<- method
+ BAL(.L${opcode}_continue) # make call; will return after
+ lw gp, STACK_OFFSET_GP(sp) # restore gp
+ move rOBJ, v0 # save result of inline
+ move a0, rINST # a0<- method
+ move a1, rSELF # a1<- self
+ JAL(dvmFastNativeMethodTraceExit) # (method, self)
+ beqz rOBJ, common_exceptionThrown # returned false, handle exception
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_FILLED_NEW_ARRAY.S b/vm/mterp/mips/OP_FILLED_NEW_ARRAY.S
new file mode 100644
index 0000000..2cb225d
--- /dev/null
+++ b/vm/mterp/mips/OP_FILLED_NEW_ARRAY.S
@@ -0,0 +1,120 @@
+%default { "isrange":"0" }
+%verify "executed"
+%verify "unimplemented array type"
+ /*
+ * Create a new array with elements filled from registers.
+ *
+ * for: filled-new-array, filled-new-array/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op {vCCCC..v(CCCC+AA-1)}, type /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResClasses(a3, a3) # a3 <- pDvmDex->pResClasses
+ EXPORT_PC() # need for resolve and alloc
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved class
+ GET_OPA(rOBJ) # rOBJ <- AA or BA
+ # already resolved?
+ bnez a0, .L${opcode}_continue # yes, continue on
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- call(clazz, ref)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b .L${opcode}_continue
+%break
+
+ /*
+ * On entry:
+ * a0 holds array class
+ * rOBJ holds AA or BA
+ */
+.L${opcode}_continue:
+ LOAD_base_offClassObject_descriptor(a3, a0) # a3 <- arrayClass->descriptor
+ li a2, ALLOC_DONT_TRACK # a2 <- alloc flags
+ lbu rINST, 1(a3) # rINST <- descriptor[1]
+ .if $isrange
+ move a1, rOBJ # a1 <- AA (length)
+ .else
+ srl a1, rOBJ, 4 # rOBJ <- B (length)
+ .endif
+ seq t0, rINST, 'I' # array of ints?
+ seq t1, rINST, 'L' # array of objects?
+ or t0, t1
+ seq t1, rINST, '[' # array of arrays?
+ or t0, t1
+ move rBIX, a1 # save length in rBIX
+ beqz t0, .L${opcode}_notimpl # no, not handled yet
+ JAL(dvmAllocArrayByClass) # v0 <- call(arClass, length, flags)
+ # null return?
+ beqz v0, common_exceptionThrown # alloc failed, handle exception
+
+ FETCH(a1, 2) # a1 <- FEDC or CCCC
+ sw v0, offThread_retval(rSELF) # retval.l <- new array
+ sw rINST, (offThread_retval+4)(rSELF) # retval.h <- type
+ addu a0, v0, offArrayObject_contents # a0 <- newArray->contents
+ subu rBIX, rBIX, 1 # length--, check for neg
+ FETCH_ADVANCE_INST(3) # advance to next instr, load rINST
+ bltz rBIX, 2f # was zero, bail
+
+ # copy values from registers into the array
+ # a0=array, a1=CCCC/FEDC, t0=length (from AA or B), rOBJ=AA/BA
+ move t0, rBIX
+ .if $isrange
+ EAS2(a2, rFP, a1) # a2 <- &fp[CCCC]
+1:
+ lw a3, 0(a2) # a3 <- *a2++
+ addu a2, 4
+ subu t0, t0, 1 # count--
+ sw a3, (a0) # *contents++ = vX
+ addu a0, 4
+ bgez t0, 1b
+
+ # continue at 2
+ .else
+ slt t1, t0, 4 # length was initially 5?
+ and a2, rOBJ, 15 # a2 <- A
+ bnez t1, 1f # <= 4 args, branch
+ GET_VREG(a3, a2) # a3 <- vA
+ subu t0, t0, 1 # count--
+ sw a3, 16(a0) # contents[4] = vA
+1:
+ and a2, a1, 15 # a2 <- F/E/D/C
+ GET_VREG(a3, a2) # a3 <- vF/vE/vD/vC
+ srl a1, a1, 4 # a1 <- next reg in low 4
+ subu t0, t0, 1 # count--
+ sw a3, 0(a0) # *contents++ = vX
+ addu a0, a0, 4
+ bgez t0, 1b
+ # continue at 2
+ .endif
+
+2:
+ lw a0, offThread_retval(rSELF) # a0 <- object
+ lw a1, (offThread_retval+4)(rSELF) # a1 <- type
+ seq t1, a1, 'I' # Is int array?
+ bnez t1, 3f
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ srl t3, a0, GC_CARD_SHIFT
+ addu t2, a2, t3
+ sb a2, (t2)
+3:
+ GET_INST_OPCODE(t0) # ip <- opcode from rINST
+ GOTO_OPCODE(t0) # execute it
+
+
+ /*
+ * Throw an exception indicating that we have not implemented this
+ * mode of filled-new-array.
+ */
+.L${opcode}_notimpl:
+ la a0, .LstrFilledNewArrayNotImpl
+ JAL(dvmThrowInternalError)
+ b common_exceptionThrown
+
+ /*
+ * Ideally we'd only define this once, but depending on layout we can
+ * exceed the range of the load above.
+ */
diff --git a/vm/mterp/mips/OP_FILLED_NEW_ARRAY_JUMBO.S b/vm/mterp/mips/OP_FILLED_NEW_ARRAY_JUMBO.S
new file mode 100644
index 0000000..a546db2
--- /dev/null
+++ b/vm/mterp/mips/OP_FILLED_NEW_ARRAY_JUMBO.S
@@ -0,0 +1,95 @@
+%default { "isrange":"0" }
+%verify "executed"
+%verify "unimplemented array type"
+ /*
+ * Create a new array with elements filled from registers.
+ *
+ * TODO: convert most of this into a common subroutine, shared with
+ * OP_FILLED_NEW_ARRAY.S.
+ */
+ /* filled-new-array/jumbo {vCCCC..v(CCCC+BBBB-1)}, type@AAAAAAAA */
+
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a0, 1) # r0<- aaaa (lo)
+ FETCH(a1, 2) # r1<- AAAA (hi)
+ LOAD_base_offDvmDex_pResClasses(a3, a3) # a3 <- pDvmDex->pResClasses
+ sll a1,a1,16
+ or a1, a0, a1 # a1<- AAAAaaaa
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved class
+ GET_OPA(rOBJ) # rOBJ <- AA or BA
+ EXPORT_PC() # need for resolve and alloc
+ # already resolved?
+ bnez a0, .L${opcode}_continue # yes, continue on
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- call(clazz, ref)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b .L${opcode}_continue
+%break
+
+ /*
+ * On entry:
+ * a0 holds array class
+ * rOBJ holds AA or BA
+ */
+.L${opcode}_continue:
+ LOAD_base_offClassObject_descriptor(a3, a0) # a3 <- arrayClass->descriptor
+ li a2, ALLOC_DONT_TRACK # a2 <- alloc flags
+ lbu rINST, 1(a3) # rINST <- descriptor[1]
+ FETCH(a1, 3) # a1<- BBBB (length)
+ seq t0, rINST, 'I' # array of ints?
+ seq t1, rINST, 'L' # array of objects?
+ or t0, t1
+ seq t1, rINST, '[' # array of arrays?
+ or t0, t1
+ move rBIX, a1 # save length in rBIX
+ beqz t0, .L${opcode}_notimpl # no, not handled yet
+ JAL(dvmAllocArrayByClass) # v0 <- call(arClass, length, flags)
+ # null return?
+ beqz v0, common_exceptionThrown # alloc failed, handle exception
+
+ FETCH(a1, 4) # a1 CCCC
+ sw v0, offThread_retval(rSELF) # retval.l <- new array
+ sw rINST, (offThread_retval+4)(rSELF) # retval.h <- type
+ addu a0, v0, offArrayObject_contents # a0 <- newArray->contents
+ subu rBIX, rBIX, 1 # length--, check for neg
+ FETCH_ADVANCE_INST(5) # advance to next instr, load rINST
+ bltz rBIX, 2f # was zero, bail
+
+ # copy values from registers into the array
+ # a0=array, a1=CCCC, t0=BBBB(length)
+ move t0, rBIX
+ EAS2(a2, rFP, a1) # a2 <- &fp[CCCC]
+1:
+ lw a3, 0(a2) # a3 <- *a2++
+ addu a2, 4
+ subu t0, t0, 1 # count--
+ sw a3, (a0) # *contents++ = vX
+ addu a0, 4
+ bgez t0, 1b
+
+2:
+ lw a0, offThread_retval(rSELF) # a0 <- object
+ lw a1, (offThread_retval+4)(rSELF) # a1 <- type
+ seq t1, a1, 'I' # Is int array?
+ bnez t1, 3f
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ srl t3, a0, GC_CARD_SHIFT
+ addu t2, a2, t3
+ sb a2, (t2)
+3:
+ GET_INST_OPCODE(t0) # ip <- opcode from rINST
+ GOTO_OPCODE(t0) # execute it
+
+
+ /*
+ * Throw an exception indicating that we have not implemented this
+ * mode of filled-new-array.
+ */
+.L${opcode}_notimpl:
+ la a0, .LstrFilledNewArrayNotImpl
+ JAL(dvmThrowInternalError)
+ b common_exceptionThrown
diff --git a/vm/mterp/mips/OP_FILLED_NEW_ARRAY_RANGE.S b/vm/mterp/mips/OP_FILLED_NEW_ARRAY_RANGE.S
new file mode 100644
index 0000000..9611796
--- /dev/null
+++ b/vm/mterp/mips/OP_FILLED_NEW_ARRAY_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_FILLED_NEW_ARRAY.S" { "isrange":"1" }
diff --git a/vm/mterp/mips/OP_FILL_ARRAY_DATA.S b/vm/mterp/mips/OP_FILL_ARRAY_DATA.S
new file mode 100644
index 0000000..7a97799
--- /dev/null
+++ b/vm/mterp/mips/OP_FILL_ARRAY_DATA.S
@@ -0,0 +1,16 @@
+%verify "executed"
+ /* fill-array-data vAA, +BBBBBBBB */
+ FETCH(a0, 1) # a0 <- bbbb (lo)
+ FETCH(a1, 2) # a1 <- BBBB (hi)
+ GET_OPA(a3) # a3 <- AA
+ sll a1, a1, 16 # a1 <- BBBBbbbb
+ or a1, a0, a1 # a1 <- BBBBbbbb
+ GET_VREG(a0, a3) # a0 <- vAA (array object)
+ EAS1(a1, rPC, a1) # a1 <- PC + BBBBbbbb*2 (array data off.)
+ EXPORT_PC()
+ JAL(dvmInterpHandleFillArrayData) # fill the array with predefined data
+ # 0 means an exception is thrown
+ beqz v0, common_exceptionThrown # has exception
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_FLOAT_TO_DOUBLE.S b/vm/mterp/mips/OP_FLOAT_TO_DOUBLE.S
new file mode 100644
index 0000000..1e2120d
--- /dev/null
+++ b/vm/mterp/mips/OP_FLOAT_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unflopWider.S" {"instr":"JAL(__extendsfdf2)", "instr_f":"cvt.d.s fv0, fa0"}
diff --git a/vm/mterp/mips/OP_FLOAT_TO_INT.S b/vm/mterp/mips/OP_FLOAT_TO_INT.S
new file mode 100644
index 0000000..166d685
--- /dev/null
+++ b/vm/mterp/mips/OP_FLOAT_TO_INT.S
@@ -0,0 +1,63 @@
+%verify "executed"
+%include "mips/unflop.S" {"instr":"b f2i_doconv", "instr_f":"b f2i_doconv"}
+%break
+
+/*
+ * Not an entry point as it is used only once !!
+ */
+f2i_doconv:
+#ifdef SOFT_FLOAT
+ li a1, 0x4f000000 # (float)maxint
+ move rBIX, a0
+ JAL(__gesf2) # is arg >= maxint?
+ move t0, v0
+ li v0, ~0x80000000 # return maxint (7fffffff)
+ bgez t0, .L${opcode}_set_vreg
+
+ move a0, rBIX # recover arg
+ li a1, 0xcf000000 # (float)minint
+ JAL(__lesf2)
+
+ move t0, v0
+ li v0, 0x80000000 # return minint (80000000)
+ blez t0, .L${opcode}_set_vreg
+ move a0, rBIX
+ move a1, rBIX
+ JAL(__nesf2)
+
+ move t0, v0
+ li v0, 0 # return zero for NaN
+ bnez t0, .L${opcode}_set_vreg
+
+ move a0, rBIX
+ JAL(__fixsfsi)
+ b .L${opcode}_set_vreg
+#else
+ l.s fa1, .LFLOAT_TO_INT_max
+ c.ole.s fcc0, fa1, fa0
+ l.s fv0, .LFLOAT_TO_INT_ret_max
+ bc1t .L${opcode}_set_vreg_f
+
+ l.s fa1, .LFLOAT_TO_INT_min
+ c.ole.s fcc0, fa0, fa1
+ l.s fv0, .LFLOAT_TO_INT_ret_min
+ bc1t .L${opcode}_set_vreg_f
+
+ mov.s fa1, fa0
+ c.un.s fcc0, fa0, fa1
+ li.s fv0, 0
+ bc1t .L${opcode}_set_vreg_f
+
+ trunc.w.s fv0, fa0
+ b .L${opcode}_set_vreg_f
+#endif
+
+.LFLOAT_TO_INT_max:
+ .word 0x4f000000
+.LFLOAT_TO_INT_min:
+ .word 0xcf000000
+.LFLOAT_TO_INT_ret_max:
+ .word 0x7fffffff
+.LFLOAT_TO_INT_ret_min:
+ .word 0x80000000
+
diff --git a/vm/mterp/mips/OP_FLOAT_TO_LONG.S b/vm/mterp/mips/OP_FLOAT_TO_LONG.S
new file mode 100644
index 0000000..3e76027
--- /dev/null
+++ b/vm/mterp/mips/OP_FLOAT_TO_LONG.S
@@ -0,0 +1,65 @@
+%verify "executed"
+%include "mips/unflopWider.S" {"instr":"b f2l_doconv", "instr_f":"b f2l_doconv", "st_result":"STORE64(rRESULT0, rRESULT1, rOBJ)"}
+%break
+
+f2l_doconv:
+#ifdef SOFT_FLOAT
+ li a1, 0x5f000000
+ move rBIX, a0
+ JAL(__gesf2)
+
+ move t0, v0
+ li rRESULT0, ~0
+ li rRESULT1, ~0x80000000
+ bgez t0, .L${opcode}_set_vreg
+
+ move a0, rBIX
+ li a1, 0xdf000000
+ JAL(__lesf2)
+
+ move t0, v0
+ li rRESULT0, 0
+ li rRESULT1, 0x80000000
+ blez t0, .L${opcode}_set_vreg
+
+ move a0, rBIX
+ move a1, rBIX
+ JAL(__nesf2)
+
+ move t0, v0
+ li rRESULT0, 0
+ li rRESULT1, 0
+ bnez t0, .L${opcode}_set_vreg
+
+ move a0, rBIX
+ JAL(__fixsfdi)
+
+#else
+ l.s fa1, .LLONG_TO_max
+ c.ole.s fcc0, fa1, fa0
+ li rRESULT0, ~0
+ li rRESULT1, ~0x80000000
+ bc1t .L${opcode}_set_vreg
+
+ l.s fa1, .LLONG_TO_min
+ c.ole.s fcc0, fa0, fa1
+ li rRESULT0, 0
+ li rRESULT1, 0x80000000
+ bc1t .L${opcode}_set_vreg
+
+ mov.s fa1, fa0
+ c.un.s fcc0, fa0, fa1
+ li rRESULT0, 0
+ li rRESULT1, 0
+ bc1t .L${opcode}_set_vreg
+
+ JAL(__fixsfdi)
+#endif
+
+ b .L${opcode}_set_vreg
+
+.LLONG_TO_max:
+ .word 0x5f000000
+
+.LLONG_TO_min:
+ .word 0xdf000000
diff --git a/vm/mterp/mips/OP_GOTO.S b/vm/mterp/mips/OP_GOTO.S
new file mode 100644
index 0000000..27c20e3
--- /dev/null
+++ b/vm/mterp/mips/OP_GOTO.S
@@ -0,0 +1,23 @@
+%verify "executed"
+%verify "forward and backward"
+ /*
+ * Unconditional branch, 8-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ */
+ /* goto +AA */
+ sll a0, rINST, 16 # a0 <- AAxx0000
+ sra a1, a0, 24 # a1 <- ssssssAA (sign-extended)
+ addu a2, a1, a1 # a2 <- byte offset
+ /* If backwards branch refresh rBASE */
+ bgez a1, 1f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+1:
+ FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bltz a1, common_testUpdateProfile # (a0) check for trace hotness
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_GOTO_16.S b/vm/mterp/mips/OP_GOTO_16.S
new file mode 100644
index 0000000..22c29da
--- /dev/null
+++ b/vm/mterp/mips/OP_GOTO_16.S
@@ -0,0 +1,21 @@
+%verify "executed"
+%verify "forward and backward"
+ /*
+ * Unconditional branch, 16-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ */
+ /* goto/16 +AAAA */
+ FETCH_S(a0, 1) # a0 <- ssssAAAA (sign-extended)
+ addu a1, a0, a0 # a1 <- byte offset, flags set
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+ bgez a1, 1f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+1:
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bltz a1, common_testUpdateProfile # (a0) hot trace head?
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_GOTO_32.S b/vm/mterp/mips/OP_GOTO_32.S
new file mode 100644
index 0000000..84598c2
--- /dev/null
+++ b/vm/mterp/mips/OP_GOTO_32.S
@@ -0,0 +1,32 @@
+%verify "executed"
+%verify "forward, backward, self"
+ /*
+ * Unconditional branch, 32-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ *
+ * Unlike most opcodes, this one is allowed to branch to itself, so
+ * our "backward branch" test must be "<=0" instead of "<0".
+ */
+ /* goto/32 +AAAAAAAA */
+ FETCH(a0, 1) # a0 <- aaaa (lo)
+ FETCH(a1, 2) # a1 <- AAAA (hi)
+ sll a1, a1, 16
+ or a0, a0, a1 # a0 <- AAAAaaaa
+ addu a1, a0, a0 # a1 <- byte offset
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgtz a1, 1f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+1:
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+ blez a1, common_testUpdateProfile # (a0) hot trace head?
+#else
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+ bgtz a0, 2f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+2:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_IF_EQ.S b/vm/mterp/mips/OP_IF_EQ.S
new file mode 100644
index 0000000..183ec1b
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_EQ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/bincmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/mips/OP_IF_EQZ.S b/vm/mterp/mips/OP_IF_EQZ.S
new file mode 100644
index 0000000..5587291
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_EQZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/zcmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/mips/OP_IF_GE.S b/vm/mterp/mips/OP_IF_GE.S
new file mode 100644
index 0000000..19bc86f
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_GE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/bincmp.S" { "revcmp":"lt" }
diff --git a/vm/mterp/mips/OP_IF_GEZ.S b/vm/mterp/mips/OP_IF_GEZ.S
new file mode 100644
index 0000000..5d4fa0f
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_GEZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/zcmp.S" { "revcmp":"lt" }
diff --git a/vm/mterp/mips/OP_IF_GT.S b/vm/mterp/mips/OP_IF_GT.S
new file mode 100644
index 0000000..8335bd3
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_GT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/bincmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/mips/OP_IF_GTZ.S b/vm/mterp/mips/OP_IF_GTZ.S
new file mode 100644
index 0000000..3c70c35
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_GTZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/zcmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/mips/OP_IF_LE.S b/vm/mterp/mips/OP_IF_LE.S
new file mode 100644
index 0000000..c1524f9
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_LE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/bincmp.S" { "revcmp":"gt" }
diff --git a/vm/mterp/mips/OP_IF_LEZ.S b/vm/mterp/mips/OP_IF_LEZ.S
new file mode 100644
index 0000000..fa930aa
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_LEZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/zcmp.S" { "revcmp":"gt" }
diff --git a/vm/mterp/mips/OP_IF_LT.S b/vm/mterp/mips/OP_IF_LT.S
new file mode 100644
index 0000000..fbda8bc
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_LT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/bincmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/mips/OP_IF_LTZ.S b/vm/mterp/mips/OP_IF_LTZ.S
new file mode 100644
index 0000000..e93dd62
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_LTZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/zcmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/mips/OP_IF_NE.S b/vm/mterp/mips/OP_IF_NE.S
new file mode 100644
index 0000000..c484ede
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_NE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/bincmp.S" { "revcmp":"eq" }
diff --git a/vm/mterp/mips/OP_IF_NEZ.S b/vm/mterp/mips/OP_IF_NEZ.S
new file mode 100644
index 0000000..24cbb6b
--- /dev/null
+++ b/vm/mterp/mips/OP_IF_NEZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/zcmp.S" { "revcmp":"eq" }
diff --git a/vm/mterp/mips/OP_IGET.S b/vm/mterp/mips/OP_IGET.S
new file mode 100644
index 0000000..ba4fada
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET.S
@@ -0,0 +1,49 @@
+%default { "load":"lw", "barrier":" # noop", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test results
+ move a0, v0
+ bnez v0, .L${opcode}_finish
+ b common_exceptionThrown
+%break
+
+ /*
+ * Currently:
+ * v0 holds resolved field
+ * rOBJ holds object (caller saved)
+ */
+.L${opcode}_finish:
+ #BAL(common_squeak${sqnum})
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ addu a3, a3, rOBJ # form address
+ $load a0, (a3) # a0 <- obj.field (8/16/32 bits)
+ $barrier # acquiring load
+ GET_OPA4(a2) # a2 <- A+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IGET_BOOLEAN.S b/vm/mterp/mips/OP_IGET_BOOLEAN.S
new file mode 100644
index 0000000..4f32dbf
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET.S"
diff --git a/vm/mterp/mips/OP_IGET_BOOLEAN_JUMBO.S b/vm/mterp/mips/OP_IGET_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..1bb6233
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_BOOLEAN_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET_JUMBO.S"
diff --git a/vm/mterp/mips/OP_IGET_BYTE.S b/vm/mterp/mips/OP_IGET_BYTE.S
new file mode 100644
index 0000000..f699e87
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_BYTE.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "mips/OP_IGET.S"
diff --git a/vm/mterp/mips/OP_IGET_BYTE_JUMBO.S b/vm/mterp/mips/OP_IGET_BYTE_JUMBO.S
new file mode 100644
index 0000000..a59ee92
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_BYTE_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "mips/OP_IGET_JUMBO.S"
diff --git a/vm/mterp/mips/OP_IGET_CHAR.S b/vm/mterp/mips/OP_IGET_CHAR.S
new file mode 100644
index 0000000..cb3a03b
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_CHAR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "large values are not sign-extended"
+%include "mips/OP_IGET.S"
diff --git a/vm/mterp/mips/OP_IGET_CHAR_JUMBO.S b/vm/mterp/mips/OP_IGET_CHAR_JUMBO.S
new file mode 100644
index 0000000..408daca
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_CHAR_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "large values are not sign-extended"
+%include "mips/OP_IGET_JUMBO.S"
diff --git a/vm/mterp/mips/OP_IGET_JUMBO.S b/vm/mterp/mips/OP_IGET_JUMBO.S
new file mode 100644
index 0000000..49920b9
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_JUMBO.S
@@ -0,0 +1,55 @@
+%default { "load":"lw", "barrier":" # noop", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Jumbo 32-bit instance field get.
+ *
+ * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+ * iget-char/jumbo, iget-short/jumbo
+ */
+ /* exop vBBBB, vCCCC, field@AAAAAAAA */
+ FETCH(a1, 1) # a1<- aaaa (lo)
+ FETCH(a2, 2) # a2<- AAAA (hi)
+ FETCH(a0, 4) # a0<- CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ sll a2,a2,16
+ or a1, a1, a2 # a1<- AAAAaaaa
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ b .L${opcode}_resolved # resolved, continue
+
+%break
+
+.L${opcode}_resolved:
+ # test results
+ move a0, v0
+ beqz a0,common_exceptionThrown
+ /*
+ * Currently:
+ * v0 holds resolved field
+ * rOBJ holds object (caller saved)
+ */
+.L${opcode}_finish:
+ #BAL(common_squeak${sqnum})
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ addu a3, a3, rOBJ # form address
+ $load a0, (a3) # a0 <- obj.field (8/16/32 bits)
+ $barrier # acquiring load
+ FETCH(a2, 3) # a2<- BBBB
+ FETCH_ADVANCE_INST(5) # advance rPC, load rINST
+ SET_VREG(a0, a2) # fp[BBBB]<- a0
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IGET_OBJECT.S b/vm/mterp/mips/OP_IGET_OBJECT.S
new file mode 100644
index 0000000..4f32dbf
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET.S"
diff --git a/vm/mterp/mips/OP_IGET_OBJECT_JUMBO.S b/vm/mterp/mips/OP_IGET_OBJECT_JUMBO.S
new file mode 100644
index 0000000..1bb6233
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_OBJECT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET_JUMBO.S"
diff --git a/vm/mterp/mips/OP_IGET_OBJECT_QUICK.S b/vm/mterp/mips/OP_IGET_OBJECT_QUICK.S
new file mode 100644
index 0000000..e4f7d00
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_OBJECT_QUICK.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET_QUICK.S"
diff --git a/vm/mterp/mips/OP_IGET_OBJECT_VOLATILE.S b/vm/mterp/mips/OP_IGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..30c6774
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_IGET_OBJECT_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_IGET_OBJECT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..00bab92
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_OBJECT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET_OBJECT_JUMBO.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_IGET_QUICK.S b/vm/mterp/mips/OP_IGET_QUICK.S
new file mode 100644
index 0000000..4490796
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_QUICK.S
@@ -0,0 +1,17 @@
+%verify "executed"
+%verify "null object"
+ /* For: iget-quick, iget-object-quick */
+ # op vA, vB, offset /* CCCC */
+ GET_OPB(a2) # a2 <- B
+ GET_VREG(a3, a2) # a3 <- object we're operating on
+ FETCH(a1, 1) # a1 <- field byte offset
+ GET_OPA4(a2) # a2 <- A(+)
+ # check object for null
+ beqz a3, common_errNullObject # object was null
+ addu t0, a3, a1 #
+ lw a0, 0(t0) # a0 <- obj.field (always 32 bits)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IGET_SHORT.S b/vm/mterp/mips/OP_IGET_SHORT.S
new file mode 100644
index 0000000..f699e87
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_SHORT.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "mips/OP_IGET.S"
diff --git a/vm/mterp/mips/OP_IGET_SHORT_JUMBO.S b/vm/mterp/mips/OP_IGET_SHORT_JUMBO.S
new file mode 100644
index 0000000..a59ee92
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_SHORT_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "mips/OP_IGET_JUMBO.S"
diff --git a/vm/mterp/mips/OP_IGET_VOLATILE.S b/vm/mterp/mips/OP_IGET_VOLATILE.S
new file mode 100644
index 0000000..30c6774
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_IGET_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_IGET_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..ed06737
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET_JUMBO.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_IGET_WIDE.S b/vm/mterp/mips/OP_IGET_WIDE.S
new file mode 100644
index 0000000..2cdf80c
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_WIDE.S
@@ -0,0 +1,49 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Wide 32-bit instance field get.
+ */
+ # iget-wide vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test return code
+ move a0, v0
+ bnez v0, .L${opcode}_finish
+ b common_exceptionThrown
+%break
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.L${opcode}_finish:
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ beqz rOBJ, common_errNullObject # object was null
+ GET_OPA4(a2) # a2 <- A+
+ addu rOBJ, rOBJ, a3 # form address
+ .if $volatile
+ vLOAD64(a0, a1, rOBJ) # a0/a1 <- obj.field (64-bit align ok)
+ .else
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- obj.field (64-bit align ok)
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a3, rFP, a2) # a3 <- &fp[A]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # fp[A] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IGET_WIDE_JUMBO.S b/vm/mterp/mips/OP_IGET_WIDE_JUMBO.S
new file mode 100644
index 0000000..97819a7
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_WIDE_JUMBO.S
@@ -0,0 +1,57 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Jumbo 64-bit instance field get.
+ */
+ /* iget-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+ FETCH(a1, 1) # a1<- aaaa (lo)
+ FETCH(a2, 2) # a2<- AAAA (hi)
+ FETCH(a0, 4) # a0<- CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ sll a2,a2,16
+ or a1, a1, a2 # a1<- AAAAaaaa
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[CCCC], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ b .L${opcode}_resolved # resolved, continue
+
+%break
+
+.L${opcode}_resolved:
+ # test return code
+ move a0, v0
+ bnez v0, .L${opcode}_finish
+ b common_exceptionThrown
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.L${opcode}_finish:
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ beqz rOBJ, common_errNullObject # object was null
+ GET_OPA4(a2) # a2 <- A+
+ addu rOBJ, rOBJ, a3 # form address
+ .if $volatile
+ vLOAD64(a0, a1, rOBJ) # a0/a1 <- obj.field (64-bit align ok)
+ .else
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- obj.field (64-bit align ok)
+ .endif
+ FETCH(a2, 3) # r2<- BBBB
+ FETCH_ADVANCE_INST(5) # advance rPC, load rINST
+ EAS2(a3, rFP, a2) # a3 <- &fp[BBBB]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # fp[BBBB] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IGET_WIDE_QUICK.S b/vm/mterp/mips/OP_IGET_WIDE_QUICK.S
new file mode 100644
index 0000000..f4d8fdb
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_WIDE_QUICK.S
@@ -0,0 +1,17 @@
+%verify "executed"
+%verify "null object"
+ # iget-wide-quick vA, vB, offset /* CCCC */
+ GET_OPB(a2) # a2 <- B
+ GET_VREG(a3, a2) # a3 <- object we're operating on
+ FETCH(a1, 1) # a1 <- field byte offset
+ GET_OPA4(a2) # a2 <- A(+)
+ # check object for null
+ beqz a3, common_errNullObject # object was null
+ addu t0, a3, a1 # t0 <- a3 + a1
+ LOAD64(a0, a1, t0) # a0 <- obj.field (64 bits, aligned)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a3, rFP, a2)
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # fp[A] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IGET_WIDE_VOLATILE.S b/vm/mterp/mips/OP_IGET_WIDE_VOLATILE.S
new file mode 100644
index 0000000..1804fb1
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/mips/OP_IGET_WIDE_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_IGET_WIDE_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..801aa84
--- /dev/null
+++ b/vm/mterp/mips/OP_IGET_WIDE_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IGET_WIDE_JUMBO.S" {"volatile":"1"}
diff --git a/vm/mterp/mips/OP_INSTANCE_OF.S b/vm/mterp/mips/OP_INSTANCE_OF.S
new file mode 100644
index 0000000..f296d44
--- /dev/null
+++ b/vm/mterp/mips/OP_INSTANCE_OF.S
@@ -0,0 +1,82 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+ /*
+ * Check to see if an object reference is an instance of a class.
+ *
+ * Most common situation is a non-null object, being compared against
+ * an already-resolved class.
+ */
+ # instance-of vA, vB, class /* CCCC */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a3) # a0 <- vB (object)
+ LOAD_rSELF_methodClassDex(a2) # a2 <- pDvmDex
+ # is object null?
+ beqz a0, .L${opcode}_store # null obj, not an instance, store a0
+ FETCH(a3, 1) # a3 <- CCCC
+ LOAD_base_offDvmDex_pResClasses(a2, a2) # a2 <- pDvmDex->pResClasses
+ LOAD_eas2(a1, a2, a3) # a1 <- resolved class
+ LOAD_base_offObject_clazz(a0, a0) # a0 <- obj->clazz
+ # have we resolved this before?
+ beqz a1, .L${opcode}_resolve # not resolved, do it now
+.L${opcode}_resolved: # a0=obj->clazz, a1=resolved class
+ # same class (trivial success)?
+ beq a0, a1, .L${opcode}_trivial # yes, trivial finish
+ b .L${opcode}_fullcheck # no, do full check
+
+ /*
+ * Trivial test succeeded, save and bail.
+ * rOBJ holds A
+ */
+.L${opcode}_trivial:
+ li a0, 1 # indicate success
+ # fall thru
+ /*
+ * a0 holds boolean result
+ * rOBJ holds A
+ */
+.L${opcode}_store:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ SET_VREG(a0, rOBJ) # vA <- a0
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+%break
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * a0 holds obj->clazz
+ * a1 holds class resolved from BBBB
+ * rOBJ holds A
+ */
+.L${opcode}_fullcheck:
+ JAL(dvmInstanceofNonTrivial) # v0 <- boolean result
+ move a0, v0 # fall through to ${opcode}_store
+ b .L${opcode}_store
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * a3 holds BBBB
+ * rOBJ holds A
+ */
+.L${opcode}_resolve:
+ EXPORT_PC() # resolve() could throw
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ move a1, a3 # a1 <- BBBB
+ li a2, 1 # a2 <- true
+ LOAD_base_offMethod_clazz(a0, a0) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- resolved ClassObject ptr
+ # got null?
+ move a1, v0 # a1 <- class resolved from BBB
+ beqz v0, common_exceptionThrown # yes, handle exception
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, a3) # a0 <- vB (object)
+ LOAD_base_offObject_clazz(a0, a0) # a0 <- obj->clazz
+ b .L${opcode}_resolved # pick up where we left off
+
diff --git a/vm/mterp/mips/OP_INSTANCE_OF_JUMBO.S b/vm/mterp/mips/OP_INSTANCE_OF_JUMBO.S
new file mode 100644
index 0000000..c55a30c
--- /dev/null
+++ b/vm/mterp/mips/OP_INSTANCE_OF_JUMBO.S
@@ -0,0 +1,96 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+ /*
+ * Check to see if an object reference is an instance of a class.
+ *
+ * Most common situation is a non-null object, being compared against
+ * an already-resolved class.
+ *
+ * TODO: convert most of this into a common subroutine, shared with
+ * OP_INSTANCE_OF.S.
+ */
+ /* instance-of/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+ FETCH(a3, 4) # a3<- vCCCC
+ FETCH(rOBJ, 3) # rOBJ<- vBBBB
+ GET_VREG(a0, a3) # a0 <- vCCCC (object)
+ LOAD_rSELF_methodClassDex(a2) # a2 <- pDvmDex
+ # is object null?
+ beqz a0, .L${opcode}_store # null obj, not an instance, store a0
+ FETCH(a1, 1) # r1<- aaaa (lo)
+ FETCH(a3, 2) # r3<- AAAA (hi)
+ LOAD_base_offDvmDex_pResClasses(a2, a2) # a2 <- pDvmDex->pResClasses
+ sll a3,a3,16
+ or a3, a1, a3 # a3<- AAAAaaaa
+
+ LOAD_eas2(a1, a2, a3) # a1 <- resolved class
+ LOAD_base_offObject_clazz(a0, a0) # a0 <- obj->clazz
+ # have we resolved this before?
+ beqz a1, .L${opcode}_resolve # not resolved, do it now
+ b .L${opcode}_resolved # resolved, continue
+
+%break
+
+ /*
+ * Class resolved, determine type of check necessary. This is common.
+ * r0 holds obj->clazz
+ * r1 holds class resolved from AAAAAAAA
+ * r9 holds BBBB
+ */
+
+.L${opcode}_resolved: # a0=obj->clazz, a1=resolved class
+ # same class (trivial success)?
+ beq a0, a1, .L${opcode}_trivial # yes, trivial finish
+ # fall through to ${opcode}_fullcheck
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * a0 holds obj->clazz
+ * a1 holds class resolved from AAAAAAAA
+ * rOBJ holds BBBB
+ */
+.L${opcode}_fullcheck:
+ JAL(dvmInstanceofNonTrivial) # v0 <- boolean result
+ move a0, v0
+ b .L${opcode}_store # go to ${opcode}_store
+
+.L${opcode}_trivial:
+ li a0, 1 # indicate success
+ # fall thru
+ /*
+ * a0 holds boolean result
+ * rOBJ holds BBBB
+ */
+.L${opcode}_store:
+ FETCH_ADVANCE_INST(5) # advance rPC, load rINST
+ SET_VREG(a0, rOBJ) # vBBBB <- a0
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * a3 holds AAAAAAAA
+ * rOBJ holds BBBB
+ */
+.L${opcode}_resolve:
+ EXPORT_PC() # resolve() could throw
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ move a1, a3 # a1 <- AAAAAAAA
+ li a2, 1 # a2 <- true
+ LOAD_base_offMethod_clazz(a0, a0) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- resolved ClassObject ptr
+ # got null?
+ move a1, v0 # a1 <- class resolved from BBB
+ beqz v0, common_exceptionThrown # yes, handle exception
+ FETCH(ra, 4) # a3<- vCCCC
+ move a1, a0 # a1<- class resolved from AAAAAAAA
+
+ GET_VREG(a0, a3) # a0 <- vCCCC (object)
+ LOAD_base_offObject_clazz(a0, a0) # a0 <- obj->clazz
+ b .L${opcode}_resolved # pick up where we left off
+
diff --git a/vm/mterp/mips/OP_INT_TO_BYTE.S b/vm/mterp/mips/OP_INT_TO_BYTE.S
new file mode 100644
index 0000000..e9edb97
--- /dev/null
+++ b/vm/mterp/mips/OP_INT_TO_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unop.S" {"preinstr":"sll a0, a0, 24", "instr":"sra a0, a0, 24"}
diff --git a/vm/mterp/mips/OP_INT_TO_CHAR.S b/vm/mterp/mips/OP_INT_TO_CHAR.S
new file mode 100644
index 0000000..5da74da
--- /dev/null
+++ b/vm/mterp/mips/OP_INT_TO_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unop.S" {"preinstr":"", "instr":"and a0, 0xffff"}
diff --git a/vm/mterp/mips/OP_INT_TO_DOUBLE.S b/vm/mterp/mips/OP_INT_TO_DOUBLE.S
new file mode 100644
index 0000000..5ee4813
--- /dev/null
+++ b/vm/mterp/mips/OP_INT_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unflopWider.S" {"instr":"JAL(__floatsidf)", "instr_f":"cvt.d.w fv0, fa0"}
diff --git a/vm/mterp/mips/OP_INT_TO_FLOAT.S b/vm/mterp/mips/OP_INT_TO_FLOAT.S
new file mode 100644
index 0000000..9cf7c48
--- /dev/null
+++ b/vm/mterp/mips/OP_INT_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unflop.S" {"instr":"JAL(__floatsisf)", "instr_f":"cvt.s.w fv0, fa0"}
diff --git a/vm/mterp/mips/OP_INT_TO_LONG.S b/vm/mterp/mips/OP_INT_TO_LONG.S
new file mode 100644
index 0000000..5691ea5
--- /dev/null
+++ b/vm/mterp/mips/OP_INT_TO_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unopWider.S" {"instr":"sra a1, a0, 31"}
diff --git a/vm/mterp/mips/OP_INT_TO_SHORT.S b/vm/mterp/mips/OP_INT_TO_SHORT.S
new file mode 100644
index 0000000..d1fc349
--- /dev/null
+++ b/vm/mterp/mips/OP_INT_TO_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unop.S" {"preinstr":"sll a0, 16", "instr":"sra a0, 16"}
diff --git a/vm/mterp/mips/OP_INVOKE_DIRECT.S b/vm/mterp/mips/OP_INVOKE_DIRECT.S
new file mode 100644
index 0000000..9bbf334
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_DIRECT.S
@@ -0,0 +1,42 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+ /*
+ * Handle a direct method call.
+ *
+ * (We could defer the "is 'this' pointer null" test to the common
+ * method invocation code, and use a flag to indicate that static
+ * calls don't count. If we do this as part of copying the arguments
+ * out we could avoiding loading the first arg twice.)
+ *
+ * for: invoke-direct, invoke-direct/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ FETCH(rBIX, 2) # rBIX <- GFED or CCCC
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved methodToCall
+ .if (!$isrange)
+ and rBIX, rBIX, 15 # rBIX <- D (or stays CCCC)
+ .endif
+ EXPORT_PC() # must export for invoke
+ GET_VREG(rOBJ, rBIX) # rOBJ <- "this" ptr
+ # already resolved?
+ bnez a0, 1f # resolved, call the function
+
+ lw a3, offThread_method(rSELF) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_DIRECT # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+
+1:
+ bnez rOBJ, common_invokeMethod${routine} # a0=method, rOBJ="this"
+ b common_errNullObject # yes, throw exception
+
+
+
diff --git a/vm/mterp/mips/OP_INVOKE_DIRECT_JUMBO.S b/vm/mterp/mips/OP_INVOKE_DIRECT_JUMBO.S
new file mode 100644
index 0000000..afe70b7
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_DIRECT_JUMBO.S
@@ -0,0 +1,43 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+ /*
+ * Handle a direct method call.
+ *
+ * (We could defer the "is 'this' pointer null" test to the common
+ * method invocation code, and use a flag to indicate that static
+ * calls don't count. If we do this as part of copying the arguments
+ * out we could avoiding loading the first arg twice.)
+ *
+ */
+ /* invoke-direct/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ FETCH(a1, 2) # a1<- AAAA (hi)
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ sll a1,a1,16
+ or a1, a0, a1 # a1<- AAAAaaaa
+ FETCH(rBIX, 4) # rBIX <- GFED or CCCC
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved methodToCall
+ .if (!$isrange)
+ and rBIX, rBIX, 15 # rBIX <- D (or stays CCCC)
+ .endif
+ EXPORT_PC() # must export for invoke
+ GET_VREG(rOBJ, rBIX) # rOBJ <- "this" ptr
+ # already resolved?
+ bnez a0, 1f # resolved, call the function
+
+ lw a3, offThread_method(rSELF) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_DIRECT # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+
+1:
+ bnez rOBJ, common_invokeMethodJumbo # a0=method, rOBJ="this"
+ b common_errNullObject # yes, throw exception
+
+
+
diff --git a/vm/mterp/mips/OP_INVOKE_DIRECT_RANGE.S b/vm/mterp/mips/OP_INVOKE_DIRECT_RANGE.S
new file mode 100644
index 0000000..ef88011
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_DIRECT_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_INVOKE_DIRECT.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/mips/OP_INVOKE_INTERFACE.S b/vm/mterp/mips/OP_INVOKE_INTERFACE.S
new file mode 100644
index 0000000..0924093
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_INTERFACE.S
@@ -0,0 +1,28 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+ /*
+ * Handle an interface method call.
+ *
+ * for: invoke-interface, invoke-interface/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(a2, 2) # a2 <- FEDC or CCCC
+ FETCH(a1, 1) # a1 <- BBBB
+ .if (!$isrange)
+ and a2, 15 # a2 <- C (or stays CCCC)
+ .endif
+ EXPORT_PC() # must export for invoke
+ GET_VREG(rOBJ, a2) # rOBJ <- first arg ("this")
+ LOAD_rSELF_methodClassDex(a3) # a3 <- methodClassDex
+ LOAD_rSELF_method(a2) # a2 <- method
+ # null obj?
+ beqz rOBJ, common_errNullObject # yes, fail
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- thisPtr->clazz
+ JAL(dvmFindInterfaceMethodInCache) # v0 <- call(class, ref, method, dex)
+ move a0, v0
+ # failed?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b common_invokeMethod${routine} # (a0=method, rOBJ="this")
diff --git a/vm/mterp/mips/OP_INVOKE_INTERFACE_JUMBO.S b/vm/mterp/mips/OP_INVOKE_INTERFACE_JUMBO.S
new file mode 100644
index 0000000..b055d69
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_INTERFACE_JUMBO.S
@@ -0,0 +1,25 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+ /*
+ * Handle an interface method call.
+ */
+ /* invoke-interface/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+ FETCH(a2, 4) # a2<- CCCC
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ FETCH(a1, 2) # a1<- AAAA (hi)
+ EXPORT_PC() # must export for invoke
+ sll a1,a1,16
+ or a1, a0, a1 # a1<- AAAAaaaa
+ GET_VREG(rOBJ, a2) # rOBJ <- first arg ("this")
+ LOAD_rSELF_methodClassDex(a3) # a3 <- methodClassDex
+ LOAD_rSELF_method(a2) # a2 <- method
+ # null obj?
+ beqz rOBJ, common_errNullObject # yes, fail
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- thisPtr->clazz
+ JAL(dvmFindInterfaceMethodInCache) # v0 <- call(class, ref, method, dex)
+ move a0, v0
+ # failed?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b common_invokeMethodJumbo # (a0=method, rOBJ="this")
diff --git a/vm/mterp/mips/OP_INVOKE_INTERFACE_RANGE.S b/vm/mterp/mips/OP_INVOKE_INTERFACE_RANGE.S
new file mode 100644
index 0000000..6257c8a
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_INTERFACE_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_INVOKE_INTERFACE.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/mips/OP_INVOKE_OBJECT_INIT_JUMBO.S b/vm/mterp/mips/OP_INVOKE_OBJECT_INIT_JUMBO.S
new file mode 100644
index 0000000..bd7c46d
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_OBJECT_INIT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_INVOKE_OBJECT_INIT_RANGE.S" {"jumbo":"1", "cccc":"4"}
diff --git a/vm/mterp/mips/OP_INVOKE_OBJECT_INIT_RANGE.S b/vm/mterp/mips/OP_INVOKE_OBJECT_INIT_RANGE.S
new file mode 100644
index 0000000..df0d6c9
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_OBJECT_INIT_RANGE.S
@@ -0,0 +1,48 @@
+%default { "jumbo":"0", "cccc":"2" }
+%verify "executed"
+%verify "finalizable class"
+ /*
+ * Invoke Object.<init> on an object. In practice we know that
+ * Object's nullary constructor doesn't do anything, so we just
+ * skip it unless a debugger is active.
+ */
+ FETCH(a1, ${cccc}) # a1<- CCCC
+ GET_VREG(a0, a1) # a0<- "this" ptr
+ # check for NULL
+ beqz a0, common_errNullObject # export PC and throw NPE
+ LOAD_base_offObject_clazz(a1, a0) # a1<- obj->clazz
+ LOAD_base_offClassObject_accessFlags(a2, a1) # a2<- clazz->accessFlags
+ and a2, CLASS_ISFINALIZABLE # is this class finalizable?
+ beqz a2, .L${opcode}_finish # no, go
+
+.L${opcode}_setFinal:
+ EXPORT_PC() # can throw
+ JAL(dvmSetFinalizable) # call dvmSetFinalizable(obj)
+ LOAD_offThread_exception(a0, rSELF) # a0<- self->exception
+ # exception pending?
+ bnez a0, common_exceptionThrown # yes, handle it
+
+.L${opcode}_finish:
+ lhu a1, offThread_subMode(rSELF)
+ and a1, kSubModeDebuggerActive # debugger active?
+ bnez a1, .L${opcode}_debugger # Yes - skip optimization
+ FETCH_ADVANCE_INST(${cccc}+1) # advance to next instr, load rINST
+ GET_INST_OPCODE(t0) # t0<- opcode from rINST
+ GOTO_OPCODE(t0) # execute it
+
+%break
+ /*
+ * A debugger is attached, so we need to go ahead and do
+ * this. For simplicity, we'll just jump directly to the
+ * corresponding handler. Note that we can't use
+ * rIBASE here because it may be in single-step mode.
+ * Load the primary table base directly.
+ */
+.L${opcode}_debugger:
+ lw a1, offThread_mainHandlerTable(rSELF)
+ .if $jumbo
+ li t0, OP_INVOKE_DIRECT_JUMBO
+ .else
+ li t0, OP_INVOKE_DIRECT_RANGE
+ .endif
+ GOTO_OPCODE_BASE(a1, t0) # execute it
diff --git a/vm/mterp/mips/OP_INVOKE_STATIC.S b/vm/mterp/mips/OP_INVOKE_STATIC.S
new file mode 100644
index 0000000..ba2d7cc
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_STATIC.S
@@ -0,0 +1,54 @@
+%default { "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+ /*
+ * Handle a static method call.
+ *
+ * for: invoke-static, invoke-static/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ li rOBJ, 0 # null "this" in delay slot
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved methodToCall
+#if defined(WITH_JIT)
+ EAS2(rBIX, a3, a1) # rBIX<- &resolved_metherToCall
+#endif
+ EXPORT_PC() # must export for invoke
+ # already resolved?
+ bnez a0, common_invokeMethod${routine} # yes, continue on
+ b .L${opcode}_resolve
+%break
+
+.L${opcode}_resolve:
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_STATIC # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+#if defined(WITH_JIT)
+ /*
+ * Check to see if we're actively building a trace. If so,
+ * we need to keep this instruction out of it.
+ * rBIX: &resolved_methodToCall
+ */
+ lhu a2, offThread_subMode(rSELF)
+ beqz v0, common_exceptionThrown # null, handle exception
+ and a2, kSubModeJitTraceBuild # trace under construction?
+ beqz a2, common_invokeMethod${routine} # no, (a0=method, rOBJ="this")
+ lw a1, 0(rBIX) # reload resolved method
+ # finished resloving?
+ bnez a1, common_invokeMethod${routine} # yes, (a0=method, rOBJ="this")
+ move rBIX, a0 # preserve method
+ move a0, rSELF
+ move a1, rPC
+ JAL(dvmJitEndTraceSelect) # (self, pc)
+ move a0, rBIX
+ b common_invokeMethod${routine} # whew, finally!
+#else
+ # got null?
+ bnez v0, common_invokeMethod${routine} # (a0=method, rOBJ="this")
+ b common_exceptionThrown # yes, handle exception
+#endif
diff --git a/vm/mterp/mips/OP_INVOKE_STATIC_JUMBO.S b/vm/mterp/mips/OP_INVOKE_STATIC_JUMBO.S
new file mode 100644
index 0000000..80576a2
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_STATIC_JUMBO.S
@@ -0,0 +1,53 @@
+%verify "executed"
+%verify "unknown method"
+ /*
+ * Handle a static method call.
+ */
+ /* invoke-static/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ FETCH(a1, 2) # a1<- AAAA (hi)
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ sll a1,a1,16
+ or a1, a0, a1 # r1<- AAAAaaaa
+ li rOBJ, 0 # null "this" in delay slot
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved methodToCall
+#if defined(WITH_JIT)
+ EAS2(rBIX, a3, a1) # rBIX<- &resolved_metherToCall
+#endif
+ EXPORT_PC() # must export for invoke
+ # already resolved?
+ bnez a0, common_invokeMethodJumboNoThis # (a0 = method)
+ b .L${opcode}_resolve
+%break
+
+.L${opcode}_resolve:
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_STATIC # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+#if defined(WITH_JIT)
+ /*
+ * Check to see if we're actively building a trace. If so,
+ * we need to keep this instruction out of it.
+ * rBIX: &resolved_methodToCall
+ */
+ lhu a2, offThread_subMode(rSELF)
+ beqz v0, common_exceptionThrown # null, handle exception
+ and a2, kSubModeJitTraceBuild # trace under construction?
+ beqz a2, common_invokeMethodJumboNoThis # no, (a0=method, rOBJ="this")
+ lw a1, 0(rBIX) # reload resolved method
+ # finished resloving?
+ bnez a1, common_invokeMethodJumboNoThis # yes, (a0=method, rOBJ="this")
+ move rBIX, a0 # preserve method
+ move a0, rSELF
+ move a1, rPC
+ JAL(dvmJitEndTraceSelect) # (self, pc)
+ move a0, rBIX
+ b common_invokeMethodJumboNoThis # whew, finally!
+#else
+ # got null?
+ bnez v0, common_invokeMethodJumboNoThis # (a0=method, rOBJ="this")
+ b common_exceptionThrown # yes, handle exception
+#endif
diff --git a/vm/mterp/mips/OP_INVOKE_STATIC_RANGE.S b/vm/mterp/mips/OP_INVOKE_STATIC_RANGE.S
new file mode 100644
index 0000000..9b45216
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_STATIC_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_INVOKE_STATIC.S" { "routine":"Range" }
diff --git a/vm/mterp/mips/OP_INVOKE_SUPER.S b/vm/mterp/mips/OP_INVOKE_SUPER.S
new file mode 100644
index 0000000..6b44380
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_SUPER.S
@@ -0,0 +1,60 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+ /*
+ * Handle a "super" method call.
+ *
+ * for: invoke-super, invoke-super/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ FETCH(t0, 2) # t0 <- GFED or CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ .if (!$isrange)
+ and t0, t0, 15 # t0 <- D (or stays CCCC)
+ .endif
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ GET_VREG(rOBJ, t0) # rOBJ <- "this" ptr
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved baseMethod
+ # null "this"?
+ LOAD_rSELF_method(t1) # t1 <- current method
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ # cmp a0, 0; already resolved?
+ LOAD_base_offMethod_clazz(rBIX, t1) # rBIX <- method->clazz
+ EXPORT_PC() # must export for invoke
+ bnez a0, .L${opcode}_continue # resolved, continue on
+
+ move a0, rBIX # a0 <- method->clazz
+ li a2, METHOD_VIRTUAL # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b .L${opcode}_continue
+%break
+
+ /*
+ * At this point:
+ * a0 = resolved base method
+ * rBIX = method->clazz
+ */
+.L${opcode}_continue:
+ LOAD_base_offClassObject_super(a1, rBIX) # a1 <- method->clazz->super
+ LOADu2_offMethod_methodIndex(a2, a0) # a2 <- baseMethod->methodIndex
+ LOAD_base_offClassObject_vtableCount(a3, a1) # a3 <- super->vtableCount
+ EXPORT_PC() # must export for invoke
+ # compare (methodIndex, vtableCount)
+ bgeu a2, a3, .L${opcode}_nsm # method not present in superclass
+ LOAD_base_offClassObject_vtable(a1, a1) # a1 <- ...clazz->super->vtable
+ LOAD_eas2(a0, a1, a2) # a0 <- vtable[methodIndex]
+ b common_invokeMethod${routine} # continue on
+
+ /*
+ * Throw a NoSuchMethodError with the method name as the message.
+ * a0 = resolved base method
+ */
+.L${opcode}_nsm:
+ LOAD_base_offMethod_name(a1, a0) # a1 <- method name
+ b common_errNoSuchMethod
+
diff --git a/vm/mterp/mips/OP_INVOKE_SUPER_JUMBO.S b/vm/mterp/mips/OP_INVOKE_SUPER_JUMBO.S
new file mode 100644
index 0000000..5794cb1
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_SUPER_JUMBO.S
@@ -0,0 +1,56 @@
+%verify "executed"
+%verify "unknown method"
+ /*
+ * Handle a "super" method call.
+ */
+ /* invoke-super/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+ FETCH(t0, 4) # t0<- CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ FETCH(a1, 2) # a1<- AAAA (hi)
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ sll a1,a1,16
+ or a1, a0, a1 # a1<- AAAAaaaa
+ GET_VREG(rOBJ, t0) # rOBJ <- "this" ptr
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved baseMethod
+ # null "this"?
+ LOAD_rSELF_method(t1) # t1 <- current method
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ # cmp a0, 0; already resolved?
+ LOAD_base_offMethod_clazz(rBIX, t1) # rBIX <- method->clazz
+ EXPORT_PC() # must export for invoke
+ bnez a0, .L${opcode}_continue # resolved, continue on
+
+ move a0, rBIX # a0 <- method->clazz
+ li a2, METHOD_VIRTUAL # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b .L${opcode}_continue
+%break
+
+ /*
+ * At this point:
+ * a0 = resolved base method
+ * rBIX = method->clazz
+ */
+.L${opcode}_continue:
+ LOAD_base_offClassObject_super(a1, rBIX) # a1 <- method->clazz->super
+ LOADu2_offMethod_methodIndex(a2, a0) # a2 <- baseMethod->methodIndex
+ LOAD_base_offClassObject_vtableCount(a3, a1) # a3 <- super->vtableCount
+ EXPORT_PC() # must export for invoke
+ # compare (methodIndex, vtableCount)
+ bgeu a2, a3, .L${opcode}_nsm # method not present in superclass
+ LOAD_base_offClassObject_vtable(a1, a1) # a1 <- ...clazz->super->vtable
+ LOAD_eas2(a0, a1, a2) # a0 <- vtable[methodIndex]
+ b common_invokeMethodJumbo # a0=method rOBJ="this"
+
+ /*
+ * Throw a NoSuchMethodError with the method name as the message.
+ * a0 = resolved base method
+ */
+.L${opcode}_nsm:
+ LOAD_base_offMethod_name(a1, a0) # a1 <- method name
+ b common_errNoSuchMethod
+
diff --git a/vm/mterp/mips/OP_INVOKE_SUPER_QUICK.S b/vm/mterp/mips/OP_INVOKE_SUPER_QUICK.S
new file mode 100644
index 0000000..eb5465a
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_SUPER_QUICK.S
@@ -0,0 +1,26 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+ /*
+ * Handle an optimized "super" method call.
+ *
+ * for: [opt] invoke-super-quick, invoke-super-quick/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ FETCH(t0, 2) # t0 <- GFED or CCCC
+ LOAD_rSELF_method(a2) # a2 <- current method
+ .if (!$isrange)
+ and t0, t0, 15 # t0 <- D (or stays CCCC)
+ .endif
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offMethod_clazz(a2, a2) # a2 <- method->clazz
+ EXPORT_PC() # must export for invoke
+ LOAD_base_offClassObject_super(a2, a2) # a2 <- method->clazz->super
+ GET_VREG(rOBJ, t0) # rOBJ <- "this"
+ LOAD_base_offClassObject_vtable(a2, a2) # a2 <- ...clazz->super->vtable
+ # is "this" null ?
+ LOAD_eas2(a0, a2, a1) # a0 <- super->vtable[BBBB]
+ beqz rOBJ, common_errNullObject # "this" is null, throw exception
+ b common_invokeMethod${routine} # (a0=method, rOBJ="this")
+
diff --git a/vm/mterp/mips/OP_INVOKE_SUPER_QUICK_RANGE.S b/vm/mterp/mips/OP_INVOKE_SUPER_QUICK_RANGE.S
new file mode 100644
index 0000000..ade7bba
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_SUPER_QUICK_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_INVOKE_SUPER_QUICK.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/mips/OP_INVOKE_SUPER_RANGE.S b/vm/mterp/mips/OP_INVOKE_SUPER_RANGE.S
new file mode 100644
index 0000000..7821d31
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_SUPER_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_INVOKE_SUPER.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/mips/OP_INVOKE_VIRTUAL.S b/vm/mterp/mips/OP_INVOKE_VIRTUAL.S
new file mode 100644
index 0000000..9f6d2c3
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_VIRTUAL.S
@@ -0,0 +1,48 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+ /*
+ * Handle a virtual method call.
+ *
+ * for: invoke-virtual, invoke-virtual/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ FETCH(rBIX, 2) # rBIX <- GFED or CCCC
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved baseMethod
+ .if (!$isrange)
+ and rBIX, rBIX, 15 # rBIX <- D (or stays CCCC)
+ .endif
+ EXPORT_PC() # must export for invoke
+ # already resolved?
+ bnez a0, .L${opcode}_continue # yes, continue on
+
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_VIRTUAL # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ bnez v0, .L${opcode}_continue # no, continue
+ b common_exceptionThrown # yes, handle exception
+%break
+
+ /*
+ * At this point:
+ * a0 = resolved base method
+ * rBIX= C or CCCC (index of first arg, which is the "this" ptr)
+ */
+.L${opcode}_continue:
+ GET_VREG(rOBJ, rBIX) # rOBJ <- "this" ptr
+ LOADu2_offMethod_methodIndex(a2, a0) # a2 <- baseMethod->methodIndex
+ # is "this" null?
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ LOAD_base_offObject_clazz(a3, rOBJ) # a3 <- thisPtr->clazz
+ LOAD_base_offClassObject_vtable(a3, a3) # a3 <- thisPtr->clazz->vtable
+ LOAD_eas2(a0, a3, a2) # a0 <- vtable[methodIndex]
+ b common_invokeMethod${routine} # (a0=method, rOBJ="this")
+
diff --git a/vm/mterp/mips/OP_INVOKE_VIRTUAL_JUMBO.S b/vm/mterp/mips/OP_INVOKE_VIRTUAL_JUMBO.S
new file mode 100644
index 0000000..6bcde34
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_VIRTUAL_JUMBO.S
@@ -0,0 +1,44 @@
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+ /*
+ * Handle a virtual method call.
+ */
+ /* invoke-virtual/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ FETCH(a1, 2) # a1<- AAAA (hi)
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ sll a1,a1,16
+ or a1, a0, a1 # a1<- AAAAaaaa
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved baseMethod
+ EXPORT_PC() # must export for invoke
+ # already resolved?
+ bnez a0, .L${opcode}_continue # yes, continue on
+
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_VIRTUAL # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ bnez v0, .L${opcode}_continue # no, continue
+ b common_exceptionThrown # yes, handle exception
+%break
+
+ /*
+ * At this point:
+ * a0 = resolved base method
+ * rBIX= C or CCCC (index of first arg, which is the "this" ptr)
+ */
+.L${opcode}_continue:
+ FETCH(rBIX,4) # rBIX <- CCCC
+ GET_VREG(rOBJ, rBIX) # rOBJ <- "this" ptr
+ LOADu2_offMethod_methodIndex(a2, a0) # a2 <- baseMethod->methodIndex
+ # is "this" null?
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ LOAD_base_offObject_clazz(a3, rOBJ) # a3 <- thisPtr->clazz
+ LOAD_base_offClassObject_vtable(a3, a3) # a3 <- thisPtr->clazz->vtable
+ LOAD_eas2(a0, a3, a2) # a0 <- vtable[methodIndex]
+ b common_invokeMethodJumbo # (a0=method, rOBJ="this")
+
diff --git a/vm/mterp/mips/OP_INVOKE_VIRTUAL_QUICK.S b/vm/mterp/mips/OP_INVOKE_VIRTUAL_QUICK.S
new file mode 100644
index 0000000..1952b70
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_VIRTUAL_QUICK.S
@@ -0,0 +1,23 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "null object"
+ /*
+ * Handle an optimized virtual method call.
+ *
+ * for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ FETCH(a3, 2) # a3 <- FEDC or CCCC
+ FETCH(a1, 1) # a1 <- BBBB
+ .if (!$isrange)
+ and a3, a3, 15 # a3 <- C (or stays CCCC)
+ .endif
+ GET_VREG(rOBJ, a3) # rOBJ <- vC ("this" ptr)
+ # is "this" null?
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ LOAD_base_offObject_clazz(a2, rOBJ) # a2 <- thisPtr->clazz
+ LOAD_base_offClassObject_vtable(a2, a2) # a2 <- thisPtr->clazz->vtable
+ EXPORT_PC() # invoke must export
+ LOAD_eas2(a0, a2, a1) # a0 <- vtable[BBBB]
+ b common_invokeMethod${routine} # (a0=method, r9="this")
diff --git a/vm/mterp/mips/OP_INVOKE_VIRTUAL_QUICK_RANGE.S b/vm/mterp/mips/OP_INVOKE_VIRTUAL_QUICK_RANGE.S
new file mode 100644
index 0000000..8048895
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_VIRTUAL_QUICK_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_INVOKE_VIRTUAL_QUICK.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/mips/OP_INVOKE_VIRTUAL_RANGE.S b/vm/mterp/mips/OP_INVOKE_VIRTUAL_RANGE.S
new file mode 100644
index 0000000..5f86b4b
--- /dev/null
+++ b/vm/mterp/mips/OP_INVOKE_VIRTUAL_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_INVOKE_VIRTUAL.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/mips/OP_IPUT.S b/vm/mterp/mips/OP_IPUT.S
new file mode 100644
index 0000000..626cc92
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT.S
@@ -0,0 +1,50 @@
+%default { "store":"sw","postbarrier":" # noop", "prebarrier":" # noop", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .L${opcode}_finish # yes, finish up
+ b common_exceptionThrown
+%break
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.L${opcode}_finish:
+ #BAL(common_squeak${sqnum})
+ GET_OPA4(a1) # a1 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ GET_VREG(a0, a1) # a0 <- fp[A]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu rOBJ, rOBJ, a3 # form address
+ $prebarrier # releasing store
+ $store a0, (rOBJ) # obj.field (8/16/32 bits) <- a0
+ $postbarrier
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IPUT_BOOLEAN.S b/vm/mterp/mips/OP_IPUT_BOOLEAN.S
new file mode 100644
index 0000000..4f09dab
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT.S"
diff --git a/vm/mterp/mips/OP_IPUT_BOOLEAN_JUMBO.S b/vm/mterp/mips/OP_IPUT_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..8457c29
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_BOOLEAN_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT_JUMBO.S"
diff --git a/vm/mterp/mips/OP_IPUT_BYTE.S b/vm/mterp/mips/OP_IPUT_BYTE.S
new file mode 100644
index 0000000..4f09dab
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT.S"
diff --git a/vm/mterp/mips/OP_IPUT_BYTE_JUMBO.S b/vm/mterp/mips/OP_IPUT_BYTE_JUMBO.S
new file mode 100644
index 0000000..8457c29
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_BYTE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT_JUMBO.S"
diff --git a/vm/mterp/mips/OP_IPUT_CHAR.S b/vm/mterp/mips/OP_IPUT_CHAR.S
new file mode 100644
index 0000000..4f09dab
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT.S"
diff --git a/vm/mterp/mips/OP_IPUT_CHAR_JUMBO.S b/vm/mterp/mips/OP_IPUT_CHAR_JUMBO.S
new file mode 100644
index 0000000..8457c29
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_CHAR_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT_JUMBO.S"
diff --git a/vm/mterp/mips/OP_IPUT_JUMBO.S b/vm/mterp/mips/OP_IPUT_JUMBO.S
new file mode 100644
index 0000000..2d05984
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_JUMBO.S
@@ -0,0 +1,58 @@
+%default { "store":"sw","postbarrier":"# noop ", "prebarrier":" # noop", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Jumbo 32-bit instance field put.
+ *
+ * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+ * iput-short/jumbo
+ */
+ /* exop vBBBB, vCCCC, field@AAAAAAAA */
+ FETCH(a1, 1) # a1<- aaaa (lo)
+ FETCH(a2, 2) # a2<- AAAA (hi)
+ FETCH(a0, 4) # a0<- CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ sll a2,a2,16
+ or a1, a1, a2 # a1<- AAAAaaaa
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ b .L${opcode}_resolved # resolved, continue
+
+%break
+
+.L${opcode}_resolved:
+ move a0, v0
+ beqz a0, common_exceptionThrown
+ # fall through to ${opcode}_finish
+
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.L${opcode}_finish:
+ #BAL(common_squeak${sqnum})
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ FETCH(a1, 3) # a1<- BBBB
+ GET_VREG(a0, a1) # a0 <- fp[BBBB]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(5) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu rOBJ, rOBJ, a3 # form address
+ $prebarrier # releasing store
+ $store a0, (rOBJ) # obj.field (8/16/32 bits) <- a0
+ $postbarrier
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IPUT_OBJECT.S b/vm/mterp/mips/OP_IPUT_OBJECT.S
new file mode 100644
index 0000000..0382fa8
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_OBJECT.S
@@ -0,0 +1,56 @@
+%default { "store":"sw", "postbarrier":" # noop", "prebarrier":" # noop", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * 32-bit instance field put.
+ *
+ * for: iput-object, iput-object-volatile
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .L${opcode}_finish # yes, finish up
+ b common_exceptionThrown
+%break
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.L${opcode}_finish:
+ #BAL(common_squeak${sqnum})
+ GET_OPA4(a1) # a1 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ GET_VREG(a0, a1) # a0 <- fp[A]
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu t2, rOBJ, a3 # form address
+ $prebarrier # releasing store
+ $store a0, (t2) # obj.field (32 bits) <- a0
+ $postbarrier
+ beqz a0, 1f # stored a null reference?
+ srl t1, rOBJ, GC_CARD_SHIFT
+ addu t2, a2, t1
+ sb a2, (t2) # mark card if not
+1:
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IPUT_OBJECT_JUMBO.S b/vm/mterp/mips/OP_IPUT_OBJECT_JUMBO.S
new file mode 100644
index 0000000..ce82ff8
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_OBJECT_JUMBO.S
@@ -0,0 +1,60 @@
+%default { "store":"sw", "postbarrier":" # noop", "prebarrier":" # noop", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Jumbo 32-bit instance field put.
+ */
+ /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+ FETCH(a1, 1) # a1<- aaaa (lo)
+ FETCH(a2, 2) # a2<- AAAA (hi)
+ FETCH(a0, 4) # a0<- CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ sll a1,a1,16
+ or a1, a1, a2 # a1<- AAAAaaaa
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ b .L${opcode}_resolved
+
+%break
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.L${opcode}_resolved:
+ move a0, v0
+ beqz a0, common_exceptionThrown
+ # fall through to ${opcode}_finish
+
+.L${opcode}_finish:
+ #BAL(common_squeak${sqnum})
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ FETCH(a1, 3) # a1<- BBBB
+ GET_VREG(a0, a1) # a0 <- fp[BBBB]
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(5) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu t2, rOBJ, a3 # form address
+ $prebarrier # releasing store
+ $store a0, (t2) # obj.field (32 bits) <- a0
+ $postbarrier
+ beqz a0, 1f # stored a null reference?
+ srl t1, rOBJ, GC_CARD_SHIFT
+ addu t2, a2, t1
+ sb a2, (t2) # mark card if not
+1:
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IPUT_OBJECT_QUICK.S b/vm/mterp/mips/OP_IPUT_OBJECT_QUICK.S
new file mode 100644
index 0000000..eb0afb4
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_OBJECT_QUICK.S
@@ -0,0 +1,21 @@
+%verify "executed"
+%verify "null object"
+ /* For: iput-object-quick */
+ # op vA, vB, offset /* CCCC */
+ GET_OPB(a2) # a2 <- B
+ GET_VREG(a3, a2) # a3 <- fp[B], the object pointer
+ FETCH(a1, 1) # a1 <- field byte offset
+ GET_OPA4(a2) # a2 <- A(+)
+ beqz a3, common_errNullObject # object was null
+ GET_VREG(a0, a2) # a0 <- fp[A]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ addu t0, a3, a1
+ sw a0, 0(t0) # obj.field (always 32 bits) <- a0
+ beqz a0, 1f
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ srl t1, a3, GC_CARD_SHIFT
+ addu t2, a2, t1
+ sb a2, 0(t2)
+1:
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_IPUT_OBJECT_VOLATILE.S b/vm/mterp/mips/OP_IPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..8320a7d
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT_OBJECT.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_IPUT_OBJECT_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_IPUT_OBJECT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..48cdb6c
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_OBJECT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT_OBJECT_JUMBO.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_IPUT_QUICK.S b/vm/mterp/mips/OP_IPUT_QUICK.S
new file mode 100644
index 0000000..8976265
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_QUICK.S
@@ -0,0 +1,16 @@
+%verify "executed"
+%verify "null object"
+ /* For: iput-quick, iput-object-quick */
+ # op vA, vB, offset /* CCCC */
+ GET_OPB(a2) # a2 <- B
+ GET_VREG(a3, a2) # a3 <- fp[B], the object pointer
+ FETCH(a1, 1) # a1 <- field byte offset
+ GET_OPA4(a2) # a2 <- A(+)
+ beqz a3, common_errNullObject # object was null
+ GET_VREG(a0, a2) # a0 <- fp[A]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ addu t0, a3, a1
+ sw a0, 0(t0) # obj.field (always 32 bits) <- a0
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IPUT_SHORT.S b/vm/mterp/mips/OP_IPUT_SHORT.S
new file mode 100644
index 0000000..4f09dab
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT.S"
diff --git a/vm/mterp/mips/OP_IPUT_SHORT_JUMBO.S b/vm/mterp/mips/OP_IPUT_SHORT_JUMBO.S
new file mode 100644
index 0000000..8457c29
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_SHORT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT_JUMBO.S"
diff --git a/vm/mterp/mips/OP_IPUT_VOLATILE.S b/vm/mterp/mips/OP_IPUT_VOLATILE.S
new file mode 100644
index 0000000..4cb365f
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_IPUT_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_IPUT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..aaf70b7
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT_JUMBO.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_IPUT_WIDE.S b/vm/mterp/mips/OP_IPUT_WIDE.S
new file mode 100644
index 0000000..b8d9690
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_WIDE.S
@@ -0,0 +1,48 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ # iput-wide vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .L${opcode}_finish # yes, finish up
+ b common_exceptionThrown
+%break
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.L${opcode}_finish:
+ GET_OPA4(a2) # a2 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ EAS2(a2, rFP, a2) # a2 <- &fp[A]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ LOAD64(a0, a1, a2) # a0/a1 <- fp[A]
+ GET_INST_OPCODE(rBIX) # extract opcode from rINST
+ addu a2, rOBJ, a3 # form address
+ .if $volatile
+ JAL(dvmQuasiAtomicSwap64Sync) # stores r0/r1 into addr r2
+# STORE64(a0, a1, a2) # obj.field (64 bits, aligned) <- a0 a1
+ .else
+ STORE64(a0, a1, a2) # obj.field (64 bits, aligned) <- a0 a1
+ .endif
+ GOTO_OPCODE(rBIX) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IPUT_WIDE_JUMBO.S b/vm/mterp/mips/OP_IPUT_WIDE_JUMBO.S
new file mode 100644
index 0000000..8edc142
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_WIDE_JUMBO.S
@@ -0,0 +1,55 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+ FETCH(a1, 1) # a1<- aaaa (lo)
+ FETCH(a2, 2) # a2<- AAAA (hi)
+ FETCH(a0, 4) # a0<- CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ sll a2,a2,16
+ or a1, a1, a2 # a1<- AAAAaaaa
+
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ b .L${opcode}_resolved # resolved, continue
+
+%break
+
+.L${opcode}_resolved:
+ move a0, v0
+ beqz a0, common_exceptionThrown
+ # fall through to ${opcode}_finish
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.L${opcode}_finish:
+ FETCH(a2, 3) # a1<- BBBB
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ EAS2(a2, rFP, a2) # a2 <- &fp[BBBB]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(5) # advance rPC, load rINST
+ LOAD64(a0, a1, a2) # a0/a1 <- fp[BBBB]
+ GET_INST_OPCODE(rBIX) # extract opcode from rINST
+ addu a2, rOBJ, a3 # form address
+ .if $volatile
+ JAL(dvmQuasiAtomicSwap64Sync) # stores r0/r1 into addr r2
+# STORE64(a0, a1, a2) # obj.field (64 bits, aligned) <- a0 a1
+ .else
+ STORE64(a0, a1, a2) # obj.field (64 bits, aligned) <- a0 a1
+ .endif
+ GOTO_OPCODE(rBIX) # jump to next instruction
+
+
diff --git a/vm/mterp/mips/OP_IPUT_WIDE_QUICK.S b/vm/mterp/mips/OP_IPUT_WIDE_QUICK.S
new file mode 100644
index 0000000..f86c403
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_WIDE_QUICK.S
@@ -0,0 +1,17 @@
+%verify "executed"
+%verify "null object"
+ # iput-wide-quick vA, vB, offset /* CCCC */
+ GET_OPA4(a0) # a0 <- A(+)
+ GET_OPB(a1) # a1 <- B
+ GET_VREG(a2, a1) # a2 <- fp[B], the object pointer
+ EAS2(a3, rFP, a0) # a3 <- &fp[A]
+ LOAD64(a0, a1, a3) # a0/a1 <- fp[A]
+ # check object for null
+ beqz a2, common_errNullObject # object was null
+ FETCH(a3, 1) # a3 <- field byte offset
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ addu a2, a2, a3 # obj.field (64 bits, aligned) <- a0/a1
+ STORE64(a0, a1, a2) # obj.field (64 bits, aligned) <- a0/a1
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_IPUT_WIDE_VOLATILE.S b/vm/mterp/mips/OP_IPUT_WIDE_VOLATILE.S
new file mode 100644
index 0000000..784be66
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/mips/OP_IPUT_WIDE_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_IPUT_WIDE_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..72436fa
--- /dev/null
+++ b/vm/mterp/mips/OP_IPUT_WIDE_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_IPUT_WIDE_JUMBO.S" {"volatile":"1"}
diff --git a/vm/mterp/mips/OP_LONG_TO_DOUBLE.S b/vm/mterp/mips/OP_LONG_TO_DOUBLE.S
new file mode 100644
index 0000000..fad9ec0
--- /dev/null
+++ b/vm/mterp/mips/OP_LONG_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unflopWide.S" {"instr":"JAL(__floatdidf)", "ld_arg":"LOAD64(rARG0, rARG1, a3)"}
diff --git a/vm/mterp/mips/OP_LONG_TO_FLOAT.S b/vm/mterp/mips/OP_LONG_TO_FLOAT.S
new file mode 100644
index 0000000..86a143a
--- /dev/null
+++ b/vm/mterp/mips/OP_LONG_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unopNarrower.S" {"instr":"JAL(__floatdisf)", "instr_f":"JAL(__floatdisf)", "load":"LOAD64(rARG0, rARG1, a3)"}
diff --git a/vm/mterp/mips/OP_LONG_TO_INT.S b/vm/mterp/mips/OP_LONG_TO_INT.S
new file mode 100644
index 0000000..fe8f865
--- /dev/null
+++ b/vm/mterp/mips/OP_LONG_TO_INT.S
@@ -0,0 +1,10 @@
+%verify "executed"
+ GET_OPB(a1) # a1 <- B from 15:12
+ GET_OPA4(a0) # a0 <- A from 11:8
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+#ifdef HAVE_BIG_ENDIAN
+ addu a1, a1, 1
+#endif
+ GET_VREG(a2, a1) # a2 <- fp[B]
+ GET_INST_OPCODE(t0) # t0 <- opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[A] <- a2
diff --git a/vm/mterp/mips/OP_MONITOR_ENTER.S b/vm/mterp/mips/OP_MONITOR_ENTER.S
new file mode 100644
index 0000000..1f5541e
--- /dev/null
+++ b/vm/mterp/mips/OP_MONITOR_ENTER.S
@@ -0,0 +1,17 @@
+%verify "executed"
+%verify "exception for null object"
+ /*
+ * Synchronize on an object.
+ */
+ /* monitor-enter vAA */
+ GET_OPA(a2) # a2 <- AA
+ GET_VREG(a1, a2) # a1 <- vAA (object)
+ move a0, rSELF # a0 <- self
+ EXPORT_PC() # export PC so we can grab stack trace
+ # null object?
+ beqz a1, common_errNullObject # null object, throw an exception
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ JAL(dvmLockObject) # call(self, obj)
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_MONITOR_EXIT.S b/vm/mterp/mips/OP_MONITOR_EXIT.S
new file mode 100644
index 0000000..fc671cb
--- /dev/null
+++ b/vm/mterp/mips/OP_MONITOR_EXIT.S
@@ -0,0 +1,26 @@
+%verify "executed"
+%verify "exception for null object (impossible in javac)"
+%verify "dvmUnlockObject fails"
+ /*
+ * Unlock an object.
+ *
+ * Exceptions that occur when unlocking a monitor need to appear as
+ * if they happened at the following instruction. See the Dalvik
+ * instruction spec.
+ */
+ /* monitor-exit vAA */
+ GET_OPA(a2) # a2 <- AA
+ EXPORT_PC() # before fetch: export the PC
+ GET_VREG(a1, a2) # a1 <- vAA (object)
+ # null object?
+ beqz a1, 1f
+ move a0, rSELF # a0 <- self
+ JAL(dvmUnlockObject) # v0 <- success for unlock(self, obj)
+ # failed?
+ FETCH_ADVANCE_INST(1) # before throw: advance rPC, load rINST
+ beqz v0, common_exceptionThrown # yes, exception is pending
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+1:
+ FETCH_ADVANCE_INST(1) # before throw: advance rPC, load rINST
+ b common_errNullObject
diff --git a/vm/mterp/mips/OP_MOVE.S b/vm/mterp/mips/OP_MOVE.S
new file mode 100644
index 0000000..dbf7ea4
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE.S
@@ -0,0 +1,10 @@
+%verify "executed"
+ /* for move, move-object, long-to-int */
+ /* op vA, vB */
+ GET_OPB(a1) # a1 <- B from 15:12
+ GET_OPA4(a0) # a0 <- A from 11:8
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ GET_VREG(a2, a1) # a2 <- fp[B]
+ GET_INST_OPCODE(t0) # t0 <- opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[A] <- a2
+
diff --git a/vm/mterp/mips/OP_MOVE_16.S b/vm/mterp/mips/OP_MOVE_16.S
new file mode 100644
index 0000000..8410b93
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_16.S
@@ -0,0 +1,10 @@
+%verify "executed"
+ /* for: move/16, move-object/16 */
+ /* op vAAAA, vBBBB */
+ FETCH(a1, 2) # a1 <- BBBB
+ FETCH(a0, 1) # a0 <- AAAA
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_VREG(a2, a1) # a2 <- fp[BBBB]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[AAAA] <- a2 and jump
+
diff --git a/vm/mterp/mips/OP_MOVE_EXCEPTION.S b/vm/mterp/mips/OP_MOVE_EXCEPTION.S
new file mode 100644
index 0000000..1040155
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_EXCEPTION.S
@@ -0,0 +1,11 @@
+%verify "executed"
+ /* move-exception vAA */
+ GET_OPA(a2) # a2 <- AA
+ LOAD_offThread_exception(a3, rSELF) # a3 <- dvmGetException bypass
+ li a1, 0 # a1 <- 0
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ SET_VREG(a3, a2) # fp[AA] <- exception obj
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE_offThread_exception(a1, rSELF) # dvmClearException bypass
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_MOVE_FROM16.S b/vm/mterp/mips/OP_MOVE_FROM16.S
new file mode 100644
index 0000000..d018140
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_FROM16.S
@@ -0,0 +1,10 @@
+%verify "executed"
+ /* for: move/from16, move-object/from16 */
+ /* op vAA, vBBBB */
+ FETCH(a1, 1) # a1 <- BBBB
+ GET_OPA(a0) # a0 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a2, a1) # a2 <- fp[BBBB]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[AA] <- a2
+
diff --git a/vm/mterp/mips/OP_MOVE_OBJECT.S b/vm/mterp/mips/OP_MOVE_OBJECT.S
new file mode 100644
index 0000000..7150ed5
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_MOVE.S"
diff --git a/vm/mterp/mips/OP_MOVE_OBJECT_16.S b/vm/mterp/mips/OP_MOVE_OBJECT_16.S
new file mode 100644
index 0000000..c3dfae0
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_OBJECT_16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_MOVE_16.S"
diff --git a/vm/mterp/mips/OP_MOVE_OBJECT_FROM16.S b/vm/mterp/mips/OP_MOVE_OBJECT_FROM16.S
new file mode 100644
index 0000000..1ec1ae9
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_OBJECT_FROM16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_MOVE_FROM16.S"
diff --git a/vm/mterp/mips/OP_MOVE_RESULT.S b/vm/mterp/mips/OP_MOVE_RESULT.S
new file mode 100644
index 0000000..05f40fa
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_RESULT.S
@@ -0,0 +1,9 @@
+%verify "executed"
+ /* for: move-result, move-result-object */
+ /* op vAA */
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ LOAD_rSELF_retval(a0) # a0 <- self->retval.i
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, a2, t0) # fp[AA] <- a0
+
diff --git a/vm/mterp/mips/OP_MOVE_RESULT_OBJECT.S b/vm/mterp/mips/OP_MOVE_RESULT_OBJECT.S
new file mode 100644
index 0000000..74aa091
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_RESULT_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_MOVE_RESULT.S"
diff --git a/vm/mterp/mips/OP_MOVE_RESULT_WIDE.S b/vm/mterp/mips/OP_MOVE_RESULT_WIDE.S
new file mode 100644
index 0000000..8a548d1
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_RESULT_WIDE.S
@@ -0,0 +1,11 @@
+%verify "executed"
+ /* move-result-wide vAA */
+ GET_OPA(a2) # a2 <- AA
+ addu a3, rSELF, offThread_retval # a3 <- &self->retval
+ EAS2(a2, rFP, a2) # a2 <- &fp[AA]
+ LOAD64(a0, a1, a3) # a0/a1 <- retval.j
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a2) # fp[AA] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_MOVE_WIDE.S b/vm/mterp/mips/OP_MOVE_WIDE.S
new file mode 100644
index 0000000..7470061
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_WIDE.S
@@ -0,0 +1,13 @@
+%verify "executed"
+ /* move-wide vA, vB */
+ /* NOTE: regs can overlap, e.g. "move v6, v7" or "move v7, v6" */
+ GET_OPA4(a2) # a2 <- A(+)
+ GET_OPB(a3) # a3 <- B
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+ EAS2(a2, rFP, a2) # a2 <- &fp[A]
+ LOAD64(a0, a1, a3) # a0/a1 <- fp[B]
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a2) # fp[A] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_MOVE_WIDE_16.S b/vm/mterp/mips/OP_MOVE_WIDE_16.S
new file mode 100644
index 0000000..bdd9f26
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_WIDE_16.S
@@ -0,0 +1,13 @@
+%verify "executed"
+ /* move-wide/16 vAAAA, vBBBB */
+ /* NOTE: regs can overlap, e.g. "move v6, v7" or "move v7, v6" */
+ FETCH(a3, 2) # a3 <- BBBB
+ FETCH(a2, 1) # a2 <- AAAA
+ EAS2(a3, rFP, a3) # a3 <- &fp[BBBB]
+ EAS2(a2, rFP, a2) # a2 <- &fp[AAAA]
+ LOAD64(a0, a1, a3) # a0/a1 <- fp[BBBB]
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a2) # fp[AAAA] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_MOVE_WIDE_FROM16.S b/vm/mterp/mips/OP_MOVE_WIDE_FROM16.S
new file mode 100644
index 0000000..44251f4
--- /dev/null
+++ b/vm/mterp/mips/OP_MOVE_WIDE_FROM16.S
@@ -0,0 +1,13 @@
+%verify "executed"
+ /* move-wide/from16 vAA, vBBBB */
+ /* NOTE: regs can overlap, e.g. "move v6, v7" or "move v7, v6" */
+ FETCH(a3, 1) # a3 <- BBBB
+ GET_OPA(a2) # a2 <- AA
+ EAS2(a3, rFP, a3) # a3 <- &fp[BBBB]
+ EAS2(a2, rFP, a2) # a2 <- &fp[AA]
+ LOAD64(a0, a1, a3) # a0/a1 <- fp[BBBB]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a2) # fp[AA] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_MUL_DOUBLE.S b/vm/mterp/mips/OP_MUL_DOUBLE.S
new file mode 100644
index 0000000..565ca57
--- /dev/null
+++ b/vm/mterp/mips/OP_MUL_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflopWide.S" {"instr":"JAL(__muldf3)", "instr_f":"mul.d fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_MUL_DOUBLE_2ADDR.S b/vm/mterp/mips/OP_MUL_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..8d1dac1
--- /dev/null
+++ b/vm/mterp/mips/OP_MUL_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflopWide2addr.S" {"instr":"JAL(__muldf3)", "instr_f":"mul.d fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_MUL_FLOAT.S b/vm/mterp/mips/OP_MUL_FLOAT.S
new file mode 100644
index 0000000..af9bb3b
--- /dev/null
+++ b/vm/mterp/mips/OP_MUL_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflop.S" {"instr":"JAL(__mulsf3)", "instr_f":"mul.s fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_MUL_FLOAT_2ADDR.S b/vm/mterp/mips/OP_MUL_FLOAT_2ADDR.S
new file mode 100644
index 0000000..726e8a4
--- /dev/null
+++ b/vm/mterp/mips/OP_MUL_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflop2addr.S" {"instr":"JAL(__mulsf3)", "instr_f":"mul.s fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_MUL_INT.S b/vm/mterp/mips/OP_MUL_INT.S
new file mode 100644
index 0000000..d9d6d2a
--- /dev/null
+++ b/vm/mterp/mips/OP_MUL_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"instr":"mul a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_MUL_INT_2ADDR.S b/vm/mterp/mips/OP_MUL_INT_2ADDR.S
new file mode 100644
index 0000000..bbf4d77
--- /dev/null
+++ b/vm/mterp/mips/OP_MUL_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"instr":"mul a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_MUL_INT_LIT16.S b/vm/mterp/mips/OP_MUL_INT_LIT16.S
new file mode 100644
index 0000000..654e76d
--- /dev/null
+++ b/vm/mterp/mips/OP_MUL_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit16.S" {"instr":"mul a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_MUL_INT_LIT8.S b/vm/mterp/mips/OP_MUL_INT_LIT8.S
new file mode 100644
index 0000000..c0278ae
--- /dev/null
+++ b/vm/mterp/mips/OP_MUL_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"instr":"mul a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_MUL_LONG.S b/vm/mterp/mips/OP_MUL_LONG.S
new file mode 100644
index 0000000..c16a230
--- /dev/null
+++ b/vm/mterp/mips/OP_MUL_LONG.S
@@ -0,0 +1,41 @@
+%verify "executed"
+ /*
+ * Signed 64-bit integer multiply.
+ * a1 a0
+ * x a3 a2
+ * -------------
+ * a2a1 a2a0
+ * a3a0
+ * a3a1 (<= unused)
+ * ---------------
+ * v1 v0
+ */
+ /* mul-long vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ and t0, a0, 255 # a2 <- BB
+ srl t1, a0, 8 # a3 <- CC
+ EAS2(t0, rFP, t0) # t0 <- &fp[BB]
+ LOAD64(a0, a1, t0) # a0/a1 <- vBB/vBB+1
+
+ EAS2(t1, rFP, t1) # t0 <- &fp[CC]
+ LOAD64(a2, a3, t1) # a2/a3 <- vCC/vCC+1
+
+ mul v1, a3, a0 # v1= a3a0
+ multu a2, a0
+ mfhi t1
+ mflo v0 # v0= a2a0
+ mul t0, a2, a1 # t0= a2a1
+ addu v1, v1, t1 # v1+= hi(a2a0)
+ addu v1, v1, t0 # v1= a3a0 + a2a1;
+
+ GET_OPA(a0) # a0 <- AA
+ EAS2(a0, rFP, a0) # a0 <- &fp[A]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ b .L${opcode}_finish
+%break
+
+.L${opcode}_finish:
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, a0) # vAA::vAA+1 <- v0(low) :: v1(high)
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_MUL_LONG_2ADDR.S b/vm/mterp/mips/OP_MUL_LONG_2ADDR.S
new file mode 100644
index 0000000..85de7be
--- /dev/null
+++ b/vm/mterp/mips/OP_MUL_LONG_2ADDR.S
@@ -0,0 +1,28 @@
+%verify "executed"
+ /*
+ * See comments in OP_MUL_LONG.S
+ */
+ /* mul-long/2addr vA, vB */
+ GET_OPA4(t0) # t0 <- A+
+
+ EAS2(t0, rFP, t0) # t0 <- &fp[A]
+ LOAD64(a0, a1, t0) # vAA.low / high
+
+ GET_OPB(t1) # t1 <- B
+ EAS2(t1, rFP, t1) # t1 <- &fp[B]
+ LOAD64(a2, a3, t1) # vBB.low / high
+
+ mul v1, a3, a0 # v1= a3a0
+ multu a2, a0
+ mfhi t1
+ mflo v0 # v0= a2a0
+ mul t2, a2, a1 # t2= a2a1
+ addu v1, v1, t1 # v1= a3a0 + hi(a2a0)
+ addu v1, v1, t2 # v1= v1 + a2a1;
+
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ # vAA <- v0 (low)
+ STORE64(v0, v1, t0) # vAA+1 <- v1 (high)
+ GOTO_OPCODE(t1) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_NEG_DOUBLE.S b/vm/mterp/mips/OP_NEG_DOUBLE.S
new file mode 100644
index 0000000..5707c65
--- /dev/null
+++ b/vm/mterp/mips/OP_NEG_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unopWide.S" {"instr":"addu a1, a1, 0x80000000"}
diff --git a/vm/mterp/mips/OP_NEG_FLOAT.S b/vm/mterp/mips/OP_NEG_FLOAT.S
new file mode 100644
index 0000000..7e25e55
--- /dev/null
+++ b/vm/mterp/mips/OP_NEG_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unop.S" {"instr":"addu a0, a0, 0x80000000"}
diff --git a/vm/mterp/mips/OP_NEG_INT.S b/vm/mterp/mips/OP_NEG_INT.S
new file mode 100644
index 0000000..da87a6a
--- /dev/null
+++ b/vm/mterp/mips/OP_NEG_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unop.S" {"instr":"negu a0, a0"}
diff --git a/vm/mterp/mips/OP_NEG_LONG.S b/vm/mterp/mips/OP_NEG_LONG.S
new file mode 100644
index 0000000..a562987
--- /dev/null
+++ b/vm/mterp/mips/OP_NEG_LONG.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%include "mips/unopWide.S" {"result0":"v0", "result1":"v1", "preinstr":"negu v0, a0", "instr":"negu v1, a1; sltu a0, zero, v0; subu v1, v1, a0"}
+
diff --git a/vm/mterp/mips/OP_NEW_ARRAY.S b/vm/mterp/mips/OP_NEW_ARRAY.S
new file mode 100644
index 0000000..5d01794
--- /dev/null
+++ b/vm/mterp/mips/OP_NEW_ARRAY.S
@@ -0,0 +1,61 @@
+%verify "executed"
+%verify "negative array length"
+%verify "allocation fails"
+ /*
+ * Allocate an array of objects, specified with the array class
+ * and a count.
+ *
+ * The verifier guarantees that this is an array class, so we don't
+ * check for it here.
+ */
+ /* new-array vA, vB, class@CCCC */
+ GET_OPB(a0) # a0 <- B
+ FETCH(a2, 1) # a2 <- CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ GET_VREG(a1, a0) # a1 <- vB (array length)
+ LOAD_base_offDvmDex_pResClasses(a3, a3) # a3 <- pDvmDex->pResClasses
+ LOAD_eas2(a0, a3, a2) # a0 <- resolved class
+ # check length
+ bltz a1, common_errNegativeArraySize # negative length, bail - len in a1
+ EXPORT_PC() # req'd for resolve, alloc
+ # already resolved?
+ beqz a0, .L${opcode}_resolve
+
+ /*
+ * Finish allocation.
+ *
+ * a0 holds class
+ * a1 holds array length
+ */
+.L${opcode}_finish:
+ li a2, ALLOC_DONT_TRACK # don't track in local refs table
+ JAL(dvmAllocArrayByClass) # v0 <- call(clazz, length, flags)
+ GET_OPA4(a2) # a2 <- A+
+ # failed?
+ beqz v0, common_exceptionThrown # yes, handle the exception
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(v0, a2) # vA <- v0
+ GOTO_OPCODE(t0) # jump to next instruction
+%break
+
+ /*
+ * Resolve class. (This is an uncommon case.)
+ *
+ * a1 holds array length
+ * a2 holds class ref CCCC
+ */
+.L${opcode}_resolve:
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ move rOBJ, a1 # rOBJ <- length (save)
+ move a1, a2 # a1 <- CCCC
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- call(clazz, ref)
+ move a1, rOBJ # a1 <- length (restore)
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ move a0, v0
+ b .L${opcode}_finish # continue with ${opcode}_finish
+
+
diff --git a/vm/mterp/mips/OP_NEW_ARRAY_JUMBO.S b/vm/mterp/mips/OP_NEW_ARRAY_JUMBO.S
new file mode 100644
index 0000000..6761505
--- /dev/null
+++ b/vm/mterp/mips/OP_NEW_ARRAY_JUMBO.S
@@ -0,0 +1,69 @@
+%verify "executed"
+%verify "negative array length"
+%verify "allocation fails"
+ /*
+ * Allocate an array of objects, specified with the array class
+ * and a count.
+ *
+ * The verifier guarantees that this is an array class, so we don't
+ * check for it here.
+ */
+ /* new-array/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+ FETCH(a2, 1) # a2<- aaaa (lo)
+ FETCH(a3, 2) # a3<- AAAA (hi)
+ FETCH(a0, 4) # a0<- vCCCC
+ sll a3,a3,16 #
+ or a2, a2, a3 # a2<- AAAAaaaa
+
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ GET_VREG(a1, a0) # a1 <- vCCCC (array length)
+ LOAD_base_offDvmDex_pResClasses(a3, a3) # a3 <- pDvmDex->pResClasses
+ LOAD_eas2(a0, a3, a2) # a0 <- resolved class
+ # check length
+ bltz a1, common_errNegativeArraySize # negative length, bail - len in a1
+ EXPORT_PC() # req'd for resolve, alloc
+ # already resolved?
+ beqz a0, .L${opcode}_resolve # not resolved,
+ b .L${opcode}_finish
+%break
+
+ /*
+ * Finish allocation.
+ *
+ * a0 holds class
+ * a1 holds array length
+ */
+.L${opcode}_finish:
+ li a2, ALLOC_DONT_TRACK # don't track in local refs table
+ JAL(dvmAllocArrayByClass) # v0 <- call(clazz, length, flags)
+ FETCH(a2, 3) # r2<- vBBBB
+ # failed?
+ beqz v0, common_exceptionThrown # yes, handle the exception
+ FETCH_ADVANCE_INST(5) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(v0, a2) # vBBBB <- v0
+ GOTO_OPCODE(t0) # jump to next instruction
+#%break
+
+
+
+ /*
+ * Resolve class. (This is an uncommon case.)
+ *
+ * a1 holds array length
+ * a2 holds class ref AAAAAAAA
+ */
+.L${opcode}_resolve:
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ move rOBJ, a1 # rOBJ <- length (save)
+ move a1, a2 # a1 <- AAAAAAAA
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- call(clazz, ref)
+ move a1, rOBJ # a1 <- length (restore)
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ move a0, v0
+ b .L${opcode}_finish # continue with to ${opcode}_finish
+
+
diff --git a/vm/mterp/mips/OP_NEW_INSTANCE.S b/vm/mterp/mips/OP_NEW_INSTANCE.S
new file mode 100644
index 0000000..ca946ad
--- /dev/null
+++ b/vm/mterp/mips/OP_NEW_INSTANCE.S
@@ -0,0 +1,106 @@
+%verify "executed"
+%verify "class not resolved"
+%verify "class cannot be resolved"
+%verify "class not initialized"
+%verify "class fails to initialize"
+%verify "class already resolved/initialized"
+%verify "class is abstract or interface"
+%verify "allocation fails"
+ /*
+ * Create a new instance of a class.
+ */
+ # new-instance vAA, class /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResClasses(a3, a3) # a3 <- pDvmDex->pResClasses
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved class
+#if defined(WITH_JIT)
+ EAS2(rBIX, a3, a1) # rBIX <- &resolved_class
+#endif
+ EXPORT_PC() # req'd for init, resolve, alloc
+ # already resolved?
+ beqz a0, .L${opcode}_resolve # no, resolve it now
+.L${opcode}_resolved: # a0=class
+ lbu a1, offClassObject_status(a0) # a1 <- ClassStatus enum
+ # has class been initialized?
+ li t0, CLASS_INITIALIZED
+ move rOBJ, a0 # save a0
+ bne a1, t0, .L${opcode}_needinit # no, init class now
+
+.L${opcode}_initialized: # a0=class
+ LOAD_base_offClassObject_accessFlags(a3, a0) # a3 <- clazz->accessFlags
+ li a1, ALLOC_DONT_TRACK # flags for alloc call
+ # a0=class
+ JAL(dvmAllocObject) # v0 <- new object
+ GET_OPA(a3) # a3 <- AA
+#if defined(WITH_JIT)
+ /*
+ * The JIT needs the class to be fully resolved before it can
+ * include this instruction in a trace.
+ */
+ lhu a1, offThread_subMode(rSELF)
+ beqz v0, common_exceptionThrown # yes, handle the exception
+ and a1, kSubModeJitTraceBuild # under construction?
+ bnez a1, .L${opcode}_jitCheck
+#else
+ # failed?
+ beqz v0, common_exceptionThrown # yes, handle the exception
+#endif
+ b .L${opcode}_continue
+
+%break
+
+.L${opcode}_continue:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(v0, a3) # vAA <- v0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+#if defined(WITH_JIT)
+ /*
+ * Check to see if we need to stop the trace building early.
+ * v0: new object
+ * a3: vAA
+ */
+.L${opcode}_jitCheck:
+ lw a1, 0(rBIX) # reload resolved class
+ # okay?
+ bnez a1, .L${opcode}_continue # yes, finish
+ move rOBJ, v0 # preserve new object
+ move rBIX, a3 # preserve vAA
+ move a0, rSELF
+ move a1, rPC
+ JAL(dvmJitEndTraceSelect) # (self, pc)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(rOBJ, rBIX) # vAA <- new object
+ GOTO_OPCODE(t0) # jump to next instruction
+#endif
+
+ /*
+ * Class initialization required.
+ *
+ * a0 holds class object
+ */
+.L${opcode}_needinit:
+ JAL(dvmInitClass) # initialize class
+ move a0, rOBJ # restore a0
+ # check boolean result
+ bnez v0, .L${opcode}_initialized # success, continue
+ b common_exceptionThrown # failed, deal with init exception
+
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * a1 holds BBBB
+ */
+.L${opcode}_resolve:
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- resolved ClassObject ptr
+ move a0, v0
+ # got null?
+ bnez v0, .L${opcode}_resolved # no, continue
+ b common_exceptionThrown # yes, handle exception
diff --git a/vm/mterp/mips/OP_NEW_INSTANCE_JUMBO.S b/vm/mterp/mips/OP_NEW_INSTANCE_JUMBO.S
new file mode 100644
index 0000000..a00991e
--- /dev/null
+++ b/vm/mterp/mips/OP_NEW_INSTANCE_JUMBO.S
@@ -0,0 +1,108 @@
+%verify "executed"
+%verify "class not resolved"
+%verify "class cannot be resolved"
+%verify "class not initialized"
+%verify "class fails to initialize"
+%verify "class already resolved/initialized"
+%verify "class is abstract or interface"
+%verify "allocation fails"
+ /*
+ * Create a new instance of a class.
+ */
+ /* new-instance/jumbo vBBBB, class@AAAAAAAA */
+ FETCH(a0, 1) # a0<- aaaa (lo)DvmDex
+ FETCH(a1, 2) # a1<- AAAA (hi)BBB
+ LOAD_base_offDvmDex_pResClasses(a3, a3) # a3 <- pDvmDex->pResClasses
+ sll a1,a1,16
+ or a1, a0, a1 # a1<- AAAAaaaa
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved class
+#if defined(WITH_JIT)
+ EAS2(rBIX, a3, a1) # rBIX <- &resolved_class
+#endif
+ EXPORT_PC() # req'd for init, resolve, alloc
+ # already resolved?
+ beqz a0, .L${opcode}_resolve # no, resolve it now
+.L${opcode}_resolved: # a0=class
+ lbu a1, offClassObject_status(a0) # a1 <- ClassStatus enum
+ # has class been initialized?
+ li t0, CLASS_INITIALIZED
+ move rOBJ, a0 # save a0
+ bne a1, t0, .L${opcode}_needinit # no, init class now
+
+.L${opcode}_initialized: # a0=class
+ LOAD_base_offClassObject_accessFlags(a3, a0) # a3 <- clazz->accessFlags
+ li a1, ALLOC_DONT_TRACK # flags for alloc call
+ # a0=class
+ JAL(dvmAllocObject) # v0 <- new object
+ FETCH(a3, 3) # a3<- BBBB
+#if defined(WITH_JIT)
+ /*
+ * The JIT needs the class to be fully resolved before it can
+ * include this instruction in a trace.
+ */
+ lhu a1, offThread_subMode(rSELF)
+ beqz v0, common_exceptionThrown # yes, handle the exception
+ and a1, kSubModeJitTraceBuild # under construction?
+ bnez a1, .L${opcode}_jitCheck
+#else
+ # failed?
+ beqz v0, common_exceptionThrown # yes, handle the exception
+#endif
+ b .L${opcode}_continue
+
+%break
+
+.L${opcode}_continue:
+ FETCH_ADVANCE_INST(4) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(v0, a3) # vBBBB <- v0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+#if defined(WITH_JIT)
+ /*
+ * Check to see if we need to stop the trace building early.
+ * v0: new object
+ * a3: vAA
+ */
+.L${opcode}_jitCheck:
+ lw a1, 0(rBIX) # reload resolved class
+ # okay?
+ bnez a1, .L${opcode}_continue # yes, finish
+ move rOBJ, v0 # preserve new object
+ move rBIX, a3 # preserve vAA
+ move a0, rSELF
+ move a1, rPC
+ JAL(dvmJitEndTraceSelect) # (self, pc)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(rOBJ, rBIX) # vAA <- new object
+ GOTO_OPCODE(t0) # jump to next instruction
+#endif
+
+ /*
+ * Class initialization required.
+ *
+ * a0 holds class object
+ */
+.L${opcode}_needinit:
+ JAL(dvmInitClass) # initialize class
+ move a0, rOBJ # restore a0
+ # check boolean result
+ bnez v0, .L${opcode}_initialized # success, continue
+ b common_exceptionThrown # failed, deal with init exception
+
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * a1 holds AAAAAAAA
+ */
+.L${opcode}_resolve:
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- resolved ClassObject ptr
+ move a0, v0
+ # got null?
+ bnez v0, .L${opcode}_resolved # no, continue
+ b common_exceptionThrown # yes, handle exception
diff --git a/vm/mterp/mips/OP_NOP.S b/vm/mterp/mips/OP_NOP.S
new file mode 100644
index 0000000..38a5eb4
--- /dev/null
+++ b/vm/mterp/mips/OP_NOP.S
@@ -0,0 +1,13 @@
+%verify "executed"
+ FETCH_ADVANCE_INST(1) # advance to next instr, load rINST
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0) # execute it
+
+#ifdef ASSIST_DEBUGGER
+ /* insert fake function header to help gdb find the stack frame */
+ .type dalvik_inst, @function
+dalvik_inst:
+ .ent dalvik_inst
+ .end dalvik_inst
+#endif
+
diff --git a/vm/mterp/mips/OP_NOT_INT.S b/vm/mterp/mips/OP_NOT_INT.S
new file mode 100644
index 0000000..3402d19
--- /dev/null
+++ b/vm/mterp/mips/OP_NOT_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unop.S" {"instr":"not a0, a0"}
diff --git a/vm/mterp/mips/OP_NOT_LONG.S b/vm/mterp/mips/OP_NOT_LONG.S
new file mode 100644
index 0000000..8947c4e
--- /dev/null
+++ b/vm/mterp/mips/OP_NOT_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/unopWide.S" {"preinstr":"not a0, a0", "instr":"not a1, a1"}
diff --git a/vm/mterp/mips/OP_OR_INT.S b/vm/mterp/mips/OP_OR_INT.S
new file mode 100644
index 0000000..683242f
--- /dev/null
+++ b/vm/mterp/mips/OP_OR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"instr":"or a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_OR_INT_2ADDR.S b/vm/mterp/mips/OP_OR_INT_2ADDR.S
new file mode 100644
index 0000000..e63835b
--- /dev/null
+++ b/vm/mterp/mips/OP_OR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"instr":"or a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_OR_INT_LIT16.S b/vm/mterp/mips/OP_OR_INT_LIT16.S
new file mode 100644
index 0000000..c12495d
--- /dev/null
+++ b/vm/mterp/mips/OP_OR_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit16.S" {"instr":"or a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_OR_INT_LIT8.S b/vm/mterp/mips/OP_OR_INT_LIT8.S
new file mode 100644
index 0000000..f2ac2d0
--- /dev/null
+++ b/vm/mterp/mips/OP_OR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"instr":"or a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_OR_LONG.S b/vm/mterp/mips/OP_OR_LONG.S
new file mode 100644
index 0000000..8b080f6
--- /dev/null
+++ b/vm/mterp/mips/OP_OR_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopWide.S" {"preinstr":"or a0, a0, a2", "instr":"or a1, a1, a3"}
diff --git a/vm/mterp/mips/OP_OR_LONG_2ADDR.S b/vm/mterp/mips/OP_OR_LONG_2ADDR.S
new file mode 100644
index 0000000..ef37dbf
--- /dev/null
+++ b/vm/mterp/mips/OP_OR_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopWide2addr.S" {"preinstr":"or a0, a0, a2", "instr":"or a1, a1, a3"}
diff --git a/vm/mterp/mips/OP_PACKED_SWITCH.S b/vm/mterp/mips/OP_PACKED_SWITCH.S
new file mode 100644
index 0000000..add1dac
--- /dev/null
+++ b/vm/mterp/mips/OP_PACKED_SWITCH.S
@@ -0,0 +1,34 @@
+%default { "func":"dvmInterpHandlePackedSwitch" }
+%verify executed
+ /*
+ * Handle a packed-switch or sparse-switch instruction. In both cases
+ * we decode it and hand it off to a helper function.
+ *
+ * We don't really expect backward branches in a switch statement, but
+ * they're perfectly legal, so we check for them here.
+ *
+ * When the JIT is present, all targets are considered treated as
+ * a potential trace heads regardless of branch direction.
+ *
+ * for: packed-switch, sparse-switch
+ */
+ /* op vAA, +BBBB */
+ FETCH(a0, 1) # a0 <- bbbb (lo)
+ FETCH(a1, 2) # a1 <- BBBB (hi)
+ GET_OPA(a3) # a3 <- AA
+ sll t0, a1, 16
+ or a0, a0, t0 # a0 <- BBBBbbbb
+ GET_VREG(a1, a3) # a1 <- vAA
+ EAS1(a0, rPC, a0) # a0 <- PC + BBBBbbbb*2
+ JAL($func) # a0 <- code-unit branch offset
+ addu a1, v0, v0 # a1 <- byte offset
+ bgtz a1, 1f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+1:
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bnez a0, common_updateProfile
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_REM_DOUBLE.S b/vm/mterp/mips/OP_REM_DOUBLE.S
new file mode 100644
index 0000000..4329ed3
--- /dev/null
+++ b/vm/mterp/mips/OP_REM_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflopWide.S" {"instr":"JAL(fmod)", "instr_f":"JAL(fmod)"}
diff --git a/vm/mterp/mips/OP_REM_DOUBLE_2ADDR.S b/vm/mterp/mips/OP_REM_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..97cd893
--- /dev/null
+++ b/vm/mterp/mips/OP_REM_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflopWide2addr.S" {"instr":"JAL(fmod)", "instr_f":"JAL(fmod)"}
diff --git a/vm/mterp/mips/OP_REM_FLOAT.S b/vm/mterp/mips/OP_REM_FLOAT.S
new file mode 100644
index 0000000..e68cfb5
--- /dev/null
+++ b/vm/mterp/mips/OP_REM_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflop.S" {"instr":"JAL(fmodf)", "instr_f":"JAL(fmodf)"}
diff --git a/vm/mterp/mips/OP_REM_FLOAT_2ADDR.S b/vm/mterp/mips/OP_REM_FLOAT_2ADDR.S
new file mode 100644
index 0000000..f78cbb3
--- /dev/null
+++ b/vm/mterp/mips/OP_REM_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflop2addr.S" {"instr":"JAL(fmodf)", "instr_f":"JAL(fmodf)"}
diff --git a/vm/mterp/mips/OP_REM_INT.S b/vm/mterp/mips/OP_REM_INT.S
new file mode 100644
index 0000000..f1dcf37
--- /dev/null
+++ b/vm/mterp/mips/OP_REM_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"instr":"div zero, a0, a1; mfhi a0", "chkzero":"1"}
diff --git a/vm/mterp/mips/OP_REM_INT_2ADDR.S b/vm/mterp/mips/OP_REM_INT_2ADDR.S
new file mode 100644
index 0000000..85d616b
--- /dev/null
+++ b/vm/mterp/mips/OP_REM_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"instr":"div zero, a0, a1; mfhi a0", "chkzero":"1"}
diff --git a/vm/mterp/mips/OP_REM_INT_LIT16.S b/vm/mterp/mips/OP_REM_INT_LIT16.S
new file mode 100644
index 0000000..1f31442
--- /dev/null
+++ b/vm/mterp/mips/OP_REM_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit16.S" {"instr":"div zero, a0, a1; mfhi a0", "chkzero":"1"}
diff --git a/vm/mterp/mips/OP_REM_INT_LIT8.S b/vm/mterp/mips/OP_REM_INT_LIT8.S
new file mode 100644
index 0000000..4b5bb82
--- /dev/null
+++ b/vm/mterp/mips/OP_REM_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"instr":"div zero, a0, a1; mfhi a0", "chkzero":"1"}
diff --git a/vm/mterp/mips/OP_REM_LONG.S b/vm/mterp/mips/OP_REM_LONG.S
new file mode 100644
index 0000000..d76221a
--- /dev/null
+++ b/vm/mterp/mips/OP_REM_LONG.S
@@ -0,0 +1,7 @@
+%verify "executed"
+/* ldivmod returns quotient in a0/a1 and remainder in a2/a3 */
+#ifdef HAVE_LITTLE_ENDIAN
+%include "mips/binopWide.S" { "result0":"v0", "result1":"v1", "instr":"JAL(__moddi3)", "chkzero":"1"}
+#else
+%include "mips/binopWide.S" { "arg0":"a1", "arg1":"a0", "arg2":"a3", "arg3":"a2", "result0":"v1", "result1":"v0", "instr":"JAL(__moddi3)", "chkzero":"1"}
+#endif
diff --git a/vm/mterp/mips/OP_REM_LONG_2ADDR.S b/vm/mterp/mips/OP_REM_LONG_2ADDR.S
new file mode 100644
index 0000000..be194a5
--- /dev/null
+++ b/vm/mterp/mips/OP_REM_LONG_2ADDR.S
@@ -0,0 +1,6 @@
+%verify "executed"
+#ifdef HAVE_LITTLE_ENDIAN
+%include "mips/binopWide2addr.S" { "result0":"v0", "result1":"v1", "instr":"JAL(__moddi3)", "chkzero":"1"}
+#else
+%include "mips/binopWide2addr.S" {"arg0":"a1", "arg1":"a0", "arg2":"a3", "arg3":"a2", "result0":"v1", "result1":"v0", "instr":"JAL(__moddi3)", "chkzero":"1"}
+#endif
diff --git a/vm/mterp/mips/OP_RETURN.S b/vm/mterp/mips/OP_RETURN.S
new file mode 100644
index 0000000..acc01cf
--- /dev/null
+++ b/vm/mterp/mips/OP_RETURN.S
@@ -0,0 +1,13 @@
+%verify "executed"
+ /*
+ * Return a 32-bit value. Copies the return value into the "thread"
+ * structure, then jumps to the return handler.
+ *
+ * for: return, return-object
+ */
+ /* op vAA */
+ GET_OPA(a2) # a2 <- AA
+ GET_VREG(a0, a2) # a0 <- vAA
+ sw a0, offThread_retval(rSELF) # retval.i <- vAA
+ b common_returnFromMethod
+
diff --git a/vm/mterp/mips/OP_RETURN_OBJECT.S b/vm/mterp/mips/OP_RETURN_OBJECT.S
new file mode 100644
index 0000000..4459668
--- /dev/null
+++ b/vm/mterp/mips/OP_RETURN_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_RETURN.S"
diff --git a/vm/mterp/mips/OP_RETURN_VOID.S b/vm/mterp/mips/OP_RETURN_VOID.S
new file mode 100644
index 0000000..781f835
--- /dev/null
+++ b/vm/mterp/mips/OP_RETURN_VOID.S
@@ -0,0 +1,3 @@
+%verify "executed"
+ b common_returnFromMethod
+
diff --git a/vm/mterp/mips/OP_RETURN_VOID_BARRIER.S b/vm/mterp/mips/OP_RETURN_VOID_BARRIER.S
new file mode 100644
index 0000000..4cb5b9b
--- /dev/null
+++ b/vm/mterp/mips/OP_RETURN_VOID_BARRIER.S
@@ -0,0 +1,3 @@
+%verify "executed"
+ SMP_DMB
+ b common_returnFromMethod
diff --git a/vm/mterp/mips/OP_RETURN_WIDE.S b/vm/mterp/mips/OP_RETURN_WIDE.S
new file mode 100644
index 0000000..bd93d6a
--- /dev/null
+++ b/vm/mterp/mips/OP_RETURN_WIDE.S
@@ -0,0 +1,13 @@
+%verify "executed"
+ /*
+ * Return a 64-bit value. Copies the return value into the "thread"
+ * structure, then jumps to the return handler.
+ */
+ /* return-wide vAA */
+ GET_OPA(a2) # a2 <- AA
+ EAS2(a2, rFP, a2) # a2 <- &fp[AA]
+ addu a3, rSELF, offThread_retval # a3 <- &self->retval
+ LOAD64(a0, a1, a2) # a0/a1 <- vAA/vAA+1
+ STORE64(a0, a1, a3) # retval <- a0/a1
+ b common_returnFromMethod
+
diff --git a/vm/mterp/mips/OP_RSUB_INT.S b/vm/mterp/mips/OP_RSUB_INT.S
new file mode 100644
index 0000000..03918ea
--- /dev/null
+++ b/vm/mterp/mips/OP_RSUB_INT.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */
+%include "mips/binopLit16.S" {"instr":"subu a0, a1, a0"}
diff --git a/vm/mterp/mips/OP_RSUB_INT_LIT8.S b/vm/mterp/mips/OP_RSUB_INT_LIT8.S
new file mode 100644
index 0000000..75d3d40
--- /dev/null
+++ b/vm/mterp/mips/OP_RSUB_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"instr":"subu a0, a1, a0"}
diff --git a/vm/mterp/mips/OP_SGET.S b/vm/mterp/mips/OP_SGET.S
new file mode 100644
index 0000000..80e1913
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET.S
@@ -0,0 +1,50 @@
+%default { "barrier":" # no-op " }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry !null?
+ bnez a0, .L${opcode}_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .L${opcode}_finish # resume
+%break
+
+.L${opcode}_finish:
+ LOAD_base_offStaticField_value(a1, a0) # a1 <- field value
+ $barrier # acquiring load
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a1, a2, t0) # fp[AA] <- a1
diff --git a/vm/mterp/mips/OP_SGET_BOOLEAN.S b/vm/mterp/mips/OP_SGET_BOOLEAN.S
new file mode 100644
index 0000000..86024ec
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET.S"
diff --git a/vm/mterp/mips/OP_SGET_BOOLEAN_JUMBO.S b/vm/mterp/mips/OP_SGET_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..2a787a2
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_BOOLEAN_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/mips/OP_SGET_BYTE.S b/vm/mterp/mips/OP_SGET_BYTE.S
new file mode 100644
index 0000000..86024ec
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET.S"
diff --git a/vm/mterp/mips/OP_SGET_BYTE_JUMBO.S b/vm/mterp/mips/OP_SGET_BYTE_JUMBO.S
new file mode 100644
index 0000000..2a787a2
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_BYTE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/mips/OP_SGET_CHAR.S b/vm/mterp/mips/OP_SGET_CHAR.S
new file mode 100644
index 0000000..86024ec
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET.S"
diff --git a/vm/mterp/mips/OP_SGET_CHAR_JUMBO.S b/vm/mterp/mips/OP_SGET_CHAR_JUMBO.S
new file mode 100644
index 0000000..2a787a2
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_CHAR_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/mips/OP_SGET_JUMBO.S b/vm/mterp/mips/OP_SGET_JUMBO.S
new file mode 100644
index 0000000..93e7586
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_JUMBO.S
@@ -0,0 +1,54 @@
+%default { "barrier":" # no-op " }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Jumbo 32-bit SGET handler.
+ *
+ * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+ * sget-char/jumbo, sget-short/jumbo
+ */
+ /* exop vBBBB, field@AAAAAAAA */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ FETCH(a1, 2) # a1<- AAAA (hi)
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ sll a1,a1,16
+ or a1, a0, a1 # a1<- AAAAaaaa
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry !null?
+ bnez a0, .L${opcode}_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: AAAAAAAA field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .L${opcode}_finish # resume
+%break
+
+.L${opcode}_finish:
+ LOAD_base_offStaticField_value(a1, a0) # a1 <- field value
+ $barrier # acquiring load
+ FETCH(a2, 3) # r2<- BBBB
+ FETCH_ADVANCE_INST(4) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a1, a2, t0) # fp[BBBB] <- a1
diff --git a/vm/mterp/mips/OP_SGET_OBJECT.S b/vm/mterp/mips/OP_SGET_OBJECT.S
new file mode 100644
index 0000000..86024ec
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET.S"
diff --git a/vm/mterp/mips/OP_SGET_OBJECT_JUMBO.S b/vm/mterp/mips/OP_SGET_OBJECT_JUMBO.S
new file mode 100644
index 0000000..2a787a2
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_OBJECT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/mips/OP_SGET_OBJECT_VOLATILE.S b/vm/mterp/mips/OP_SGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..d880f97
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_SGET_OBJECT_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_SGET_OBJECT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..c9975c8
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_OBJECT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET_OBJECT_JUMBO.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_SGET_SHORT.S b/vm/mterp/mips/OP_SGET_SHORT.S
new file mode 100644
index 0000000..86024ec
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET.S"
diff --git a/vm/mterp/mips/OP_SGET_SHORT_JUMBO.S b/vm/mterp/mips/OP_SGET_SHORT_JUMBO.S
new file mode 100644
index 0000000..2a787a2
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_SHORT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/mips/OP_SGET_VOLATILE.S b/vm/mterp/mips/OP_SGET_VOLATILE.S
new file mode 100644
index 0000000..d880f97
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_SGET_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_SGET_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..93a5f41
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET_JUMBO.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_SGET_WIDE.S b/vm/mterp/mips/OP_SGET_WIDE.S
new file mode 100644
index 0000000..0e72992
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_WIDE.S
@@ -0,0 +1,58 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * 64-bit SGET handler.
+ */
+ # sget-wide vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ *
+ * Returns StaticField pointer in v0.
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+
+ b .L${opcode}_finish # resume
+%break
+
+.L${opcode}_finish:
+ GET_OPA(a1) # a1 <- AA
+ .if $volatile
+ vLOAD64_off(a2, a3, a0, offStaticField_value) # a2/a3 <- field value (aligned)
+ .else
+ LOAD64_off(a2, a3, a0, offStaticField_value) # a2/a3 <- field value (aligned)
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a1, rFP, a1) # a1 <- &fp[AA]
+ STORE64(a2, a3, a1) # vAA/vAA+1 <- a2/a3
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
diff --git a/vm/mterp/mips/OP_SGET_WIDE_JUMBO.S b/vm/mterp/mips/OP_SGET_WIDE_JUMBO.S
new file mode 100644
index 0000000..7a52889
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_WIDE_JUMBO.S
@@ -0,0 +1,47 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Jumbo 64-bit SGET handler.
+ */
+ /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ FETCH(a1, 2) # a1<- AAAA (hi)
+ LOAD_base_offDvmDex_pResFields(a2, a2) # a2 <- dvmDex->pResFields
+ sll a1,a1,16
+ or a1, a0, a1 # a1<- AAAAaaaa
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry null?
+ bnez a0, .L${opcode}_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: AAAAAAAA field ref
+ *
+ * Returns StaticField pointer in v0.
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # a0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+ b .L${opcode}_finish # resume
+%break
+
+.L${opcode}_finish:
+ FETCH(a1, 3) # a1<- BBBB
+ .if $volatile
+ vLOAD64_off(a2, a3, a0, offStaticField_value) # a2/a3 <- field value (aligned)
+ .else
+ LOAD64_off(a2, a3, a0, offStaticField_value) # a2/a3 <- field value (aligned)
+ .endif
+ FETCH_ADVANCE_INST(4) # advance rPC, load rINST
+ EAS2(a1, rFP, a1) # a1 <- &fp[BBBB]
+ STORE64(a2, a3, a1) # vBBBB/vBBBB+1 <- a2/a3
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_SGET_WIDE_VOLATILE.S b/vm/mterp/mips/OP_SGET_WIDE_VOLATILE.S
new file mode 100644
index 0000000..ca2fce4
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/mips/OP_SGET_WIDE_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_SGET_WIDE_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..c6039c3
--- /dev/null
+++ b/vm/mterp/mips/OP_SGET_WIDE_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SGET_WIDE_JUMBO.S" {"volatile":"1"}
diff --git a/vm/mterp/mips/OP_SHL_INT.S b/vm/mterp/mips/OP_SHL_INT.S
new file mode 100644
index 0000000..9981dec
--- /dev/null
+++ b/vm/mterp/mips/OP_SHL_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"preinstr":"and a1, a1, 31", "instr":"sll a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_SHL_INT_2ADDR.S b/vm/mterp/mips/OP_SHL_INT_2ADDR.S
new file mode 100644
index 0000000..0ac0a8f
--- /dev/null
+++ b/vm/mterp/mips/OP_SHL_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"preinstr":"and a1, a1, 31", "instr":"sll a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_SHL_INT_LIT8.S b/vm/mterp/mips/OP_SHL_INT_LIT8.S
new file mode 100644
index 0000000..1110037
--- /dev/null
+++ b/vm/mterp/mips/OP_SHL_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"preinstr":"and a1, a1, 31", "instr":"sll a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_SHL_LONG.S b/vm/mterp/mips/OP_SHL_LONG.S
new file mode 100644
index 0000000..817ac2f
--- /dev/null
+++ b/vm/mterp/mips/OP_SHL_LONG.S
@@ -0,0 +1,33 @@
+%verify "executed"
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* shl-long vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(t2) # t2 <- AA
+ and a3, a0, 255 # a3 <- BB
+ srl a0, a0, 8 # a0 <- CC
+ EAS2(a3, rFP, a3) # a3 <- &fp[BB]
+ GET_VREG(a2, a0) # a2 <- vCC
+ LOAD64(a0, a1, a3) # a0/a1 <- vBB/vBB+1
+
+ EAS2(t2, rFP, t2) # t2 <- &fp[AA]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ sll v0, a0, a2 # rlo<- alo << (shift&31)
+ not v1, a2 # rhi<- 31-shift (shift is 5b)
+ srl a0, 1
+ srl a0, v1 # alo<- alo >> (32-(shift&31))
+ sll v1, a1, a2 # rhi<- ahi << (shift&31)
+ or v1, a0 # rhi<- rhi | alo
+ andi a2, 0x20 # shift< shift & 0x20
+ movn v1, v0, a2 # rhi<- rlo (if shift&0x20)
+ movn v0, zero, a2 # rlo<- 0 (if shift&0x20)
+
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, t2) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_SHL_LONG_2ADDR.S b/vm/mterp/mips/OP_SHL_LONG_2ADDR.S
new file mode 100644
index 0000000..1191427
--- /dev/null
+++ b/vm/mterp/mips/OP_SHL_LONG_2ADDR.S
@@ -0,0 +1,28 @@
+%verify "executed"
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* shl-long/2addr vA, vB */
+ GET_OPA4(t2) # t2 <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a2, a3) # a2 <- vB
+ EAS2(rOBJ, rFP, t2) # rOBJ <- &fp[A]
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ sll v0, a0, a2 # rlo<- alo << (shift&31)
+ not v1, a2 # rhi<- 31-shift (shift is 5b)
+ srl a0, 1
+ srl a0, v1 # alo<- alo >> (32-(shift&31))
+ sll v1, a1, a2 # rhi<- ahi << (shift&31)
+ or v1, a0 # rhi<- rhi | alo
+ andi a2, 0x20 # shift< shift & 0x20
+ movn v1, v0, a2 # rhi<- rlo (if shift&0x20)
+ movn v0, zero, a2 # rlo<- 0 (if shift&0x20)
+
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_SHR_INT.S b/vm/mterp/mips/OP_SHR_INT.S
new file mode 100644
index 0000000..c5911e7
--- /dev/null
+++ b/vm/mterp/mips/OP_SHR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"preinstr":"and a1, a1, 31", "instr":"sra a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_SHR_INT_2ADDR.S b/vm/mterp/mips/OP_SHR_INT_2ADDR.S
new file mode 100644
index 0000000..b979e9f
--- /dev/null
+++ b/vm/mterp/mips/OP_SHR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"preinstr":"and a1, a1, 31", "instr":"sra a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_SHR_INT_LIT8.S b/vm/mterp/mips/OP_SHR_INT_LIT8.S
new file mode 100644
index 0000000..6124619
--- /dev/null
+++ b/vm/mterp/mips/OP_SHR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"preinstr":"and a1, a1, 31", "instr":"sra a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_SHR_LONG.S b/vm/mterp/mips/OP_SHR_LONG.S
new file mode 100644
index 0000000..6906978
--- /dev/null
+++ b/vm/mterp/mips/OP_SHR_LONG.S
@@ -0,0 +1,33 @@
+%verify "executed"
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* shr-long vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(t3) # t3 <- AA
+ and a3, a0, 255 # a3 <- BB
+ srl a0, a0, 8 # a0 <- CC
+ EAS2(a3, rFP, a3) # a3 <- &fp[BB]
+ GET_VREG(a2, a0) # a2 <- vCC
+ LOAD64(a0, a1, a3) # a0/a1 <- vBB/vBB+1
+ EAS2(t3, rFP, t3) # t3 <- &fp[AA]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ sra v1, a1, a2 # rhi<- ahi >> (shift&31)
+ srl v0, a0, a2 # rlo<- alo >> (shift&31)
+ sra a3, a1, 31 # a3<- sign(ah)
+ not a0, a2 # alo<- 31-shift (shift is 5b)
+ sll a1, 1
+ sll a1, a0 # ahi<- ahi << (32-(shift&31))
+ or v0, a1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn v0, v1, a2 # rlo<- rhi (if shift&0x20)
+ movn v1, a3, a2 # rhi<- sign(ahi) (if shift&0x20)
+
+ STORE64(v0, v1, t3) # vAA/VAA+1 <- v0/v0
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_SHR_LONG_2ADDR.S b/vm/mterp/mips/OP_SHR_LONG_2ADDR.S
new file mode 100644
index 0000000..439923e
--- /dev/null
+++ b/vm/mterp/mips/OP_SHR_LONG_2ADDR.S
@@ -0,0 +1,28 @@
+%verify "executed"
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* shr-long/2addr vA, vB */
+ GET_OPA4(t2) # t2 <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a2, a3) # a2 <- vB
+ EAS2(t2, rFP, t2) # t2 <- &fp[A]
+ LOAD64(a0, a1, t2) # a0/a1 <- vAA/vAA+1
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ sra v1, a1, a2 # rhi<- ahi >> (shift&31)
+ srl v0, a0, a2 # rlo<- alo >> (shift&31)
+ sra a3, a1, 31 # a3<- sign(ah)
+ not a0, a2 # alo<- 31-shift (shift is 5b)
+ sll a1, 1
+ sll a1, a0 # ahi<- ahi << (32-(shift&31))
+ or v0, a1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn v0, v1, a2 # rlo<- rhi (if shift&0x20)
+ movn v1, a3, a2 # rhi<- sign(ahi) (if shift&0x20)
+
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, t2) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_SPARSE_SWITCH.S b/vm/mterp/mips/OP_SPARSE_SWITCH.S
new file mode 100644
index 0000000..32067de
--- /dev/null
+++ b/vm/mterp/mips/OP_SPARSE_SWITCH.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_PACKED_SWITCH.S" { "func":"dvmInterpHandleSparseSwitch" }
diff --git a/vm/mterp/mips/OP_SPUT.S b/vm/mterp/mips/OP_SPUT.S
new file mode 100644
index 0000000..722a12f
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT.S
@@ -0,0 +1,50 @@
+%default { "postbarrier":"# no-op", "prebarrier":"# no-op" }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .L${opcode}_finish # is resolved entry null?
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .L${opcode}_finish # resume
+%break
+
+.L${opcode}_finish:
+ # field ptr in a0
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ $prebarrier # releasing store
+ sw a1, offStaticField_value(a0) # field <- vAA
+ $postbarrier
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_SPUT_BOOLEAN.S b/vm/mterp/mips/OP_SPUT_BOOLEAN.S
new file mode 100644
index 0000000..96434b7
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT.S"
diff --git a/vm/mterp/mips/OP_SPUT_BOOLEAN_JUMBO.S b/vm/mterp/mips/OP_SPUT_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..e183701
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_BOOLEAN_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/mips/OP_SPUT_BYTE.S b/vm/mterp/mips/OP_SPUT_BYTE.S
new file mode 100644
index 0000000..96434b7
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT.S"
diff --git a/vm/mterp/mips/OP_SPUT_BYTE_JUMBO.S b/vm/mterp/mips/OP_SPUT_BYTE_JUMBO.S
new file mode 100644
index 0000000..e183701
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_BYTE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/mips/OP_SPUT_CHAR.S b/vm/mterp/mips/OP_SPUT_CHAR.S
new file mode 100644
index 0000000..96434b7
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT.S"
diff --git a/vm/mterp/mips/OP_SPUT_CHAR_JUMBO.S b/vm/mterp/mips/OP_SPUT_CHAR_JUMBO.S
new file mode 100644
index 0000000..e183701
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_CHAR_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/mips/OP_SPUT_JUMBO.S b/vm/mterp/mips/OP_SPUT_JUMBO.S
new file mode 100644
index 0000000..5a4f824
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_JUMBO.S
@@ -0,0 +1,55 @@
+%default { "postbarrier":" # no-op ", "prebarrier":" # no-op " }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Jumbo 32-bit SPUT handler.
+ *
+ * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+ * sput-short/jumbo
+ */
+ /* exop vBBBB, field@AAAAAAAA */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ FETCH(a1, 2) # a1<- AAAA (hi)
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ sll a1,a1,16
+ or a1, a0, a1 # a1<- AAAAaaaa
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .L${opcode}_finish # is resolved entry null?
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: AAAAAAAA field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .L${opcode}_finish # resume
+%break
+
+.L${opcode}_finish:
+ # field ptr in a0
+ FETCH(a2, 3) # a2<- BBBB
+ FETCH_ADVANCE_INST(4) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[BBBB]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ $prebarrier # releasing store
+ sw a1, offStaticField_value(a0) # field <- vBBBB
+ $postbarrier
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_SPUT_OBJECT.S b/vm/mterp/mips/OP_SPUT_OBJECT.S
new file mode 100644
index 0000000..0fd3db3
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_OBJECT.S
@@ -0,0 +1,56 @@
+%default { "postbarrier":"# no-op", "prebarrier":"# no-op" }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput-object, sput-object-volatile
+ */
+ /* op vAA, field@BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .L${opcode}_finish # is resolved entry null?
+
+ /* Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .L${opcode}_finish # resume
+
+%break
+.L${opcode}_finish: # field ptr in a0
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[AA]
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ lw t1, offField_clazz(a0) # t1 <- field->clazz
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ $prebarrier # releasing store
+ sw a1, offStaticField_value(a0) # field <- vAA
+ $postbarrier
+ beqz a1, 1f
+ srl t2, t1, GC_CARD_SHIFT
+ addu t3, a2, t2
+ sb a2, (t3)
+1:
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_SPUT_OBJECT_JUMBO.S b/vm/mterp/mips/OP_SPUT_OBJECT_JUMBO.S
new file mode 100644
index 0000000..22fa450
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_OBJECT_JUMBO.S
@@ -0,0 +1,58 @@
+%default { "postbarrier":" # no-op ", "prebarrier":" # no-op " }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Jumbo 32-bit SPUT handler for objects
+ */
+ /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a0, 1) # a0<- aaaa (lo)
+ FETCH(a1, 2) # a1<- AAAA (hi)
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ sll a1,a1,16
+ or a1,a0,a1 # a1<- AAAAaaaa
+
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .L${opcode}_finish # is resolved entry null?
+
+ /* Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .L${opcode}_finish # resume
+
+%break
+.L${opcode}_finish: # field ptr in a0
+ FETCH(a2, 3) # a2<- BBBB
+ FETCH_ADVANCE_INST(4) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[BBBB]
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ lw t1, offField_clazz(a0) # t1 <- field->clazz
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ $prebarrier # releasing store
+ sw a1, offStaticField_value(a0) # field <- vBBBB
+ $postbarrier
+ beqz a1, 1f
+ srl t2, t1, GC_CARD_SHIFT
+ addu t3, a2, t2
+ sb a2, (t3)
+ 1:
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/OP_SPUT_OBJECT_VOLATILE.S b/vm/mterp/mips/OP_SPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..8b6dc14
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT_OBJECT.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_SPUT_OBJECT_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_SPUT_OBJECT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..fd22e6e
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_OBJECT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT_OBJECT_JUMBO.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_SPUT_SHORT.S b/vm/mterp/mips/OP_SPUT_SHORT.S
new file mode 100644
index 0000000..96434b7
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT.S"
diff --git a/vm/mterp/mips/OP_SPUT_SHORT_JUMBO.S b/vm/mterp/mips/OP_SPUT_SHORT_JUMBO.S
new file mode 100644
index 0000000..e183701
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_SHORT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/mips/OP_SPUT_VOLATILE.S b/vm/mterp/mips/OP_SPUT_VOLATILE.S
new file mode 100644
index 0000000..9e1f1a5
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_SPUT_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_SPUT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..7c8e2f4
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT_JUMBO.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/mips/OP_SPUT_WIDE.S b/vm/mterp/mips/OP_SPUT_WIDE.S
new file mode 100644
index 0000000..3e1d042
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_WIDE.S
@@ -0,0 +1,58 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * 64-bit SPUT handler.
+ */
+ # sput-wide vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ GET_OPA(t0) # t0 <- AA
+ LOAD_eas2(a2, rBIX, a1) # a2 <- resolved StaticField ptr
+ EAS2(rOBJ, rFP, t0) # rOBJ<- &fp[AA]
+ # is resolved entry null?
+ beqz a2, .L${opcode}_resolve # yes, do resolve
+.L${opcode}_finish: # field ptr in a2, AA in rOBJ
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+ GET_INST_OPCODE(rBIX) # extract opcode from rINST
+ .if $volatile
+ addu a2, offStaticField_value # a2<- pointer to data
+ JAL(dvmQuasiAtomicSwap64Sync) # stores a0/a1 into addr a2
+ .else
+ STORE64_off(a0, a1, a2, offStaticField_value) # field <- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(rBIX) # jump to next instruction
+%break
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rOBJ: &fp[AA]
+ * rBIX: dvmDex->pResFields
+ *
+ * Returns StaticField pointer in a2.
+ */
+.L${opcode}_resolve:
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ # success ?
+ move a0, v0
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ move a2, v0
+ b .L${opcode}_finish # resume
diff --git a/vm/mterp/mips/OP_SPUT_WIDE_JUMBO.S b/vm/mterp/mips/OP_SPUT_WIDE_JUMBO.S
new file mode 100644
index 0000000..b12ac62
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_WIDE_JUMBO.S
@@ -0,0 +1,60 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * Jumbo 64-bit SPUT handler.
+ */
+ /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1<- aaaa (lo)
+ FETCH(a2, 2) # a2<- AAAA (hi)
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ sll a2,a2,16
+ or a1, a1, a2 # a1<- AAAAaaaa
+ FETCH(rOBJ, 3) # rOBJ<- BBBB solved StaticField ptr
+ EAS2(rOBJ, rFP, t0) # rOBJ<- &fp[BBBB]
+ # is resolved entry null?
+ beqz a2, .L${opcode}_resolve # yes, do resolve
+.L${opcode}_finish: # field ptr in a2, BBBB in rOBJ
+ FETCH_ADVANCE_INST(4) # advance rPC, load rINST
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vBBBB/vBBBB+1
+ GET_INST_OPCODE(rBIX) # extract opcode from rINST
+ .if $volatile
+ addu a2, offStaticField_value # a2<- pointer to data
+ JAL(dvmQuasiAtomicSwap64Sync) # stores a0/a1 into addr a2
+ .else
+ STORE64_off(a0, a1, a2, offStaticField_value) # field <- vBBBB/vBBBB+1
+ .endif
+ GOTO_OPCODE(rBIX) # jump to next instruction
+%break
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: AAAAAAAA field ref
+ * rOBJ: &fp[BBBB]
+ * rBIX: dvmDex->pResFields
+ *
+ * Returns StaticField pointer in a2.
+ */
+.L${opcode}_resolve:
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ # success ?
+ move a0, v0
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ move a2, v0
+ b .L${opcode}_finish # resume
diff --git a/vm/mterp/mips/OP_SPUT_WIDE_VOLATILE.S b/vm/mterp/mips/OP_SPUT_WIDE_VOLATILE.S
new file mode 100644
index 0000000..359b37f
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/mips/OP_SPUT_WIDE_VOLATILE_JUMBO.S b/vm/mterp/mips/OP_SPUT_WIDE_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..6dc59e5
--- /dev/null
+++ b/vm/mterp/mips/OP_SPUT_WIDE_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/OP_SPUT_WIDE_JUMBO.S" {"volatile":"1"}
diff --git a/vm/mterp/mips/OP_SUB_DOUBLE.S b/vm/mterp/mips/OP_SUB_DOUBLE.S
new file mode 100644
index 0000000..3b6fa6d
--- /dev/null
+++ b/vm/mterp/mips/OP_SUB_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflopWide.S" {"instr":"JAL(__subdf3)", "instr_f":"sub.d fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_SUB_DOUBLE_2ADDR.S b/vm/mterp/mips/OP_SUB_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..cdd973e
--- /dev/null
+++ b/vm/mterp/mips/OP_SUB_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflopWide2addr.S" {"instr":"JAL(__subdf3)", "instr_f":"sub.d fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_SUB_FLOAT.S b/vm/mterp/mips/OP_SUB_FLOAT.S
new file mode 100644
index 0000000..9096267
--- /dev/null
+++ b/vm/mterp/mips/OP_SUB_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflop.S" {"instr":"JAL(__subsf3)", "instr_f":"sub.s fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_SUB_FLOAT_2ADDR.S b/vm/mterp/mips/OP_SUB_FLOAT_2ADDR.S
new file mode 100644
index 0000000..143b7e6
--- /dev/null
+++ b/vm/mterp/mips/OP_SUB_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binflop2addr.S" {"instr":"JAL(__subsf3)", "instr_f":"sub.s fv0, fa0, fa1"}
diff --git a/vm/mterp/mips/OP_SUB_INT.S b/vm/mterp/mips/OP_SUB_INT.S
new file mode 100644
index 0000000..aaa6a7b
--- /dev/null
+++ b/vm/mterp/mips/OP_SUB_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"instr":"subu a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_SUB_INT_2ADDR.S b/vm/mterp/mips/OP_SUB_INT_2ADDR.S
new file mode 100644
index 0000000..0032229
--- /dev/null
+++ b/vm/mterp/mips/OP_SUB_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"instr":"subu a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_SUB_LONG.S b/vm/mterp/mips/OP_SUB_LONG.S
new file mode 100644
index 0000000..700d4ea
--- /dev/null
+++ b/vm/mterp/mips/OP_SUB_LONG.S
@@ -0,0 +1,10 @@
+%verify "executed"
+/*
+ * For little endian the code sequence looks as follows:
+ * subu v0,a0,a2
+ * subu v1,a1,a3
+ * sltu a0,a0,v0
+ * subu v1,v1,a0
+ */
+%include "mips/binopWide.S" { "result0":"v0", "result1":"v1", "preinstr":"subu v0, a0, a2", "instr":"subu v1, a1, a3; sltu a0, a0, v0; subu v1, v1, a0" }
+
diff --git a/vm/mterp/mips/OP_SUB_LONG_2ADDR.S b/vm/mterp/mips/OP_SUB_LONG_2ADDR.S
new file mode 100644
index 0000000..9b12d69
--- /dev/null
+++ b/vm/mterp/mips/OP_SUB_LONG_2ADDR.S
@@ -0,0 +1,5 @@
+%verify "executed"
+/*
+ * See comments in OP_SUB_LONG.S
+ */
+%include "mips/binopWide2addr.S" { "result0":"v0", "result1":"v1", "preinstr":"subu v0, a0, a2", "instr":"subu v1, a1, a3; sltu a0, a0, v0; subu v1, v1, a0" }
diff --git a/vm/mterp/mips/OP_THROW.S b/vm/mterp/mips/OP_THROW.S
new file mode 100644
index 0000000..b879b29
--- /dev/null
+++ b/vm/mterp/mips/OP_THROW.S
@@ -0,0 +1,15 @@
+%verify "executed"
+%verify "exception for null object"
+ /*
+ * Throw an exception object in the current thread.
+ */
+ /* throw vAA */
+ GET_OPA(a2) # a2 <- AA
+ GET_VREG(a1, a2) # a1 <- vAA (exception object)
+ EXPORT_PC() # exception handler can throw
+ # null object?
+ beqz a1, common_errNullObject # yes, throw an NPE instead
+ # bypass dvmSetException, just store it
+ STORE_offThread_exception(a1, rSELF) # thread->exception <- obj
+ b common_exceptionThrown
+
diff --git a/vm/mterp/mips/OP_THROW_VERIFICATION_ERROR.S b/vm/mterp/mips/OP_THROW_VERIFICATION_ERROR.S
new file mode 100644
index 0000000..a68b256
--- /dev/null
+++ b/vm/mterp/mips/OP_THROW_VERIFICATION_ERROR.S
@@ -0,0 +1,15 @@
+%verify executed
+ /*
+ * Handle a throw-verification-error instruction. This throws an
+ * exception for an error discovered during verification. The
+ * exception is indicated by AA, with some detail provided by BBBB.
+ */
+ /* op AA, ref@BBBB */
+
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ FETCH(a2, 1) # a2 <- BBBB
+ EXPORT_PC() # export the PC
+ GET_OPA(a1) # a1 <- AA
+ JAL(dvmThrowVerificationError) # always throws
+ b common_exceptionThrown # handle exception
+
diff --git a/vm/mterp/mips/OP_THROW_VERIFICATION_ERROR_JUMBO.S b/vm/mterp/mips/OP_THROW_VERIFICATION_ERROR_JUMBO.S
new file mode 100644
index 0000000..dbddc42
--- /dev/null
+++ b/vm/mterp/mips/OP_THROW_VERIFICATION_ERROR_JUMBO.S
@@ -0,0 +1,17 @@
+%verify executed
+ /*
+ * Handle a jumbo throw-verification-error instruction. This throws an
+ * exception for an error discovered during verification. The
+ * exception is indicated by BBBB, with some detail provided by AAAAAAAA.
+ */
+ /* exop BBBB, Class@AAAAAAAA */
+ FETCH(a1, 1) # a1<- aaaa (lo)
+ FETCH(a2, 2) # a2<- AAAA (hi)
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ sll a2,a2,16
+ or a2, a1, a2 # a2<- AAAAaaaa
+ EXPORT_PC() # export the PC
+ FETCH(a1, 3) # a1<- BBBB
+ JAL(dvmThrowVerificationError) # always throws
+ b common_exceptionThrown # handle exception
+
diff --git a/vm/mterp/mips/OP_UNUSED_27FF.S b/vm/mterp/mips/OP_UNUSED_27FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_27FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_28FF.S b/vm/mterp/mips/OP_UNUSED_28FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_28FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_29FF.S b/vm/mterp/mips/OP_UNUSED_29FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_29FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_2AFF.S b/vm/mterp/mips/OP_UNUSED_2AFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_2AFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_2BFF.S b/vm/mterp/mips/OP_UNUSED_2BFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_2BFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_2CFF.S b/vm/mterp/mips/OP_UNUSED_2CFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_2CFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_2DFF.S b/vm/mterp/mips/OP_UNUSED_2DFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_2DFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_2EFF.S b/vm/mterp/mips/OP_UNUSED_2EFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_2EFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_2FFF.S b/vm/mterp/mips/OP_UNUSED_2FFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_2FFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_30FF.S b/vm/mterp/mips/OP_UNUSED_30FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_30FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_31FF.S b/vm/mterp/mips/OP_UNUSED_31FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_31FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_32FF.S b/vm/mterp/mips/OP_UNUSED_32FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_32FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_33FF.S b/vm/mterp/mips/OP_UNUSED_33FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_33FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_34FF.S b/vm/mterp/mips/OP_UNUSED_34FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_34FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_35FF.S b/vm/mterp/mips/OP_UNUSED_35FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_35FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_36FF.S b/vm/mterp/mips/OP_UNUSED_36FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_36FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_37FF.S b/vm/mterp/mips/OP_UNUSED_37FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_37FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_38FF.S b/vm/mterp/mips/OP_UNUSED_38FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_38FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_39FF.S b/vm/mterp/mips/OP_UNUSED_39FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_39FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_3AFF.S b/vm/mterp/mips/OP_UNUSED_3AFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_3AFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_3BFF.S b/vm/mterp/mips/OP_UNUSED_3BFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_3BFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_3CFF.S b/vm/mterp/mips/OP_UNUSED_3CFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_3CFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_3DFF.S b/vm/mterp/mips/OP_UNUSED_3DFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_3DFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_3E.S b/vm/mterp/mips/OP_UNUSED_3E.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_3E.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_3EFF.S b/vm/mterp/mips/OP_UNUSED_3EFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_3EFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_3F.S b/vm/mterp/mips/OP_UNUSED_3F.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_3F.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_3FFF.S b/vm/mterp/mips/OP_UNUSED_3FFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_3FFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_40.S b/vm/mterp/mips/OP_UNUSED_40.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_40.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_40FF.S b/vm/mterp/mips/OP_UNUSED_40FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_40FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_41.S b/vm/mterp/mips/OP_UNUSED_41.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_41.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_41FF.S b/vm/mterp/mips/OP_UNUSED_41FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_41FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_42.S b/vm/mterp/mips/OP_UNUSED_42.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_42.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_42FF.S b/vm/mterp/mips/OP_UNUSED_42FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_42FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_43.S b/vm/mterp/mips/OP_UNUSED_43.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_43.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_43FF.S b/vm/mterp/mips/OP_UNUSED_43FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_43FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_44FF.S b/vm/mterp/mips/OP_UNUSED_44FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_44FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_45FF.S b/vm/mterp/mips/OP_UNUSED_45FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_45FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_46FF.S b/vm/mterp/mips/OP_UNUSED_46FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_46FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_47FF.S b/vm/mterp/mips/OP_UNUSED_47FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_47FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_48FF.S b/vm/mterp/mips/OP_UNUSED_48FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_48FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_49FF.S b/vm/mterp/mips/OP_UNUSED_49FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_49FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_4AFF.S b/vm/mterp/mips/OP_UNUSED_4AFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_4AFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_4BFF.S b/vm/mterp/mips/OP_UNUSED_4BFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_4BFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_4CFF.S b/vm/mterp/mips/OP_UNUSED_4CFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_4CFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_4DFF.S b/vm/mterp/mips/OP_UNUSED_4DFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_4DFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_4EFF.S b/vm/mterp/mips/OP_UNUSED_4EFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_4EFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_4FFF.S b/vm/mterp/mips/OP_UNUSED_4FFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_4FFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_50FF.S b/vm/mterp/mips/OP_UNUSED_50FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_50FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_51FF.S b/vm/mterp/mips/OP_UNUSED_51FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_51FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_52FF.S b/vm/mterp/mips/OP_UNUSED_52FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_52FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_53FF.S b/vm/mterp/mips/OP_UNUSED_53FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_53FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_54FF.S b/vm/mterp/mips/OP_UNUSED_54FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_54FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_55FF.S b/vm/mterp/mips/OP_UNUSED_55FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_55FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_56FF.S b/vm/mterp/mips/OP_UNUSED_56FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_56FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_57FF.S b/vm/mterp/mips/OP_UNUSED_57FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_57FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_58FF.S b/vm/mterp/mips/OP_UNUSED_58FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_58FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_59FF.S b/vm/mterp/mips/OP_UNUSED_59FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_59FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_5AFF.S b/vm/mterp/mips/OP_UNUSED_5AFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_5AFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_5BFF.S b/vm/mterp/mips/OP_UNUSED_5BFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_5BFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_5CFF.S b/vm/mterp/mips/OP_UNUSED_5CFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_5CFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_5DFF.S b/vm/mterp/mips/OP_UNUSED_5DFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_5DFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_5EFF.S b/vm/mterp/mips/OP_UNUSED_5EFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_5EFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_5FFF.S b/vm/mterp/mips/OP_UNUSED_5FFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_5FFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_60FF.S b/vm/mterp/mips/OP_UNUSED_60FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_60FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_61FF.S b/vm/mterp/mips/OP_UNUSED_61FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_61FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_62FF.S b/vm/mterp/mips/OP_UNUSED_62FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_62FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_63FF.S b/vm/mterp/mips/OP_UNUSED_63FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_63FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_64FF.S b/vm/mterp/mips/OP_UNUSED_64FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_64FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_65FF.S b/vm/mterp/mips/OP_UNUSED_65FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_65FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_66FF.S b/vm/mterp/mips/OP_UNUSED_66FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_66FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_67FF.S b/vm/mterp/mips/OP_UNUSED_67FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_67FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_68FF.S b/vm/mterp/mips/OP_UNUSED_68FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_68FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_69FF.S b/vm/mterp/mips/OP_UNUSED_69FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_69FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_6AFF.S b/vm/mterp/mips/OP_UNUSED_6AFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_6AFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_6BFF.S b/vm/mterp/mips/OP_UNUSED_6BFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_6BFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_6CFF.S b/vm/mterp/mips/OP_UNUSED_6CFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_6CFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_6DFF.S b/vm/mterp/mips/OP_UNUSED_6DFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_6DFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_6EFF.S b/vm/mterp/mips/OP_UNUSED_6EFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_6EFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_6FFF.S b/vm/mterp/mips/OP_UNUSED_6FFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_6FFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_70FF.S b/vm/mterp/mips/OP_UNUSED_70FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_70FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_71FF.S b/vm/mterp/mips/OP_UNUSED_71FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_71FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_72FF.S b/vm/mterp/mips/OP_UNUSED_72FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_72FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_73.S b/vm/mterp/mips/OP_UNUSED_73.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_73.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_73FF.S b/vm/mterp/mips/OP_UNUSED_73FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_73FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_74FF.S b/vm/mterp/mips/OP_UNUSED_74FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_74FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_75FF.S b/vm/mterp/mips/OP_UNUSED_75FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_75FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_76FF.S b/vm/mterp/mips/OP_UNUSED_76FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_76FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_77FF.S b/vm/mterp/mips/OP_UNUSED_77FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_77FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_78FF.S b/vm/mterp/mips/OP_UNUSED_78FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_78FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_79.S b/vm/mterp/mips/OP_UNUSED_79.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_79.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_79FF.S b/vm/mterp/mips/OP_UNUSED_79FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_79FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_7A.S b/vm/mterp/mips/OP_UNUSED_7A.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_7A.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_7AFF.S b/vm/mterp/mips/OP_UNUSED_7AFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_7AFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_7BFF.S b/vm/mterp/mips/OP_UNUSED_7BFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_7BFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_7CFF.S b/vm/mterp/mips/OP_UNUSED_7CFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_7CFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_7DFF.S b/vm/mterp/mips/OP_UNUSED_7DFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_7DFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_7EFF.S b/vm/mterp/mips/OP_UNUSED_7EFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_7EFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_7FFF.S b/vm/mterp/mips/OP_UNUSED_7FFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_7FFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_80FF.S b/vm/mterp/mips/OP_UNUSED_80FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_80FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_81FF.S b/vm/mterp/mips/OP_UNUSED_81FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_81FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_82FF.S b/vm/mterp/mips/OP_UNUSED_82FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_82FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_83FF.S b/vm/mterp/mips/OP_UNUSED_83FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_83FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_84FF.S b/vm/mterp/mips/OP_UNUSED_84FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_84FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_85FF.S b/vm/mterp/mips/OP_UNUSED_85FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_85FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_86FF.S b/vm/mterp/mips/OP_UNUSED_86FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_86FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_87FF.S b/vm/mterp/mips/OP_UNUSED_87FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_87FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_88FF.S b/vm/mterp/mips/OP_UNUSED_88FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_88FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_89FF.S b/vm/mterp/mips/OP_UNUSED_89FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_89FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_8AFF.S b/vm/mterp/mips/OP_UNUSED_8AFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_8AFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_8BFF.S b/vm/mterp/mips/OP_UNUSED_8BFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_8BFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_8CFF.S b/vm/mterp/mips/OP_UNUSED_8CFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_8CFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_8DFF.S b/vm/mterp/mips/OP_UNUSED_8DFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_8DFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_8EFF.S b/vm/mterp/mips/OP_UNUSED_8EFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_8EFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_8FFF.S b/vm/mterp/mips/OP_UNUSED_8FFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_8FFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_90FF.S b/vm/mterp/mips/OP_UNUSED_90FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_90FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_91FF.S b/vm/mterp/mips/OP_UNUSED_91FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_91FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_92FF.S b/vm/mterp/mips/OP_UNUSED_92FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_92FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_93FF.S b/vm/mterp/mips/OP_UNUSED_93FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_93FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_94FF.S b/vm/mterp/mips/OP_UNUSED_94FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_94FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_95FF.S b/vm/mterp/mips/OP_UNUSED_95FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_95FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_96FF.S b/vm/mterp/mips/OP_UNUSED_96FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_96FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_97FF.S b/vm/mterp/mips/OP_UNUSED_97FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_97FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_98FF.S b/vm/mterp/mips/OP_UNUSED_98FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_98FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_99FF.S b/vm/mterp/mips/OP_UNUSED_99FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_99FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_9AFF.S b/vm/mterp/mips/OP_UNUSED_9AFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_9AFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_9BFF.S b/vm/mterp/mips/OP_UNUSED_9BFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_9BFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_9CFF.S b/vm/mterp/mips/OP_UNUSED_9CFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_9CFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_9DFF.S b/vm/mterp/mips/OP_UNUSED_9DFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_9DFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_9EFF.S b/vm/mterp/mips/OP_UNUSED_9EFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_9EFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_9FFF.S b/vm/mterp/mips/OP_UNUSED_9FFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_9FFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_A0FF.S b/vm/mterp/mips/OP_UNUSED_A0FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_A0FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_A1FF.S b/vm/mterp/mips/OP_UNUSED_A1FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_A1FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_A2FF.S b/vm/mterp/mips/OP_UNUSED_A2FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_A2FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_A3FF.S b/vm/mterp/mips/OP_UNUSED_A3FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_A3FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_A4FF.S b/vm/mterp/mips/OP_UNUSED_A4FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_A4FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_A5FF.S b/vm/mterp/mips/OP_UNUSED_A5FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_A5FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_A6FF.S b/vm/mterp/mips/OP_UNUSED_A6FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_A6FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_A7FF.S b/vm/mterp/mips/OP_UNUSED_A7FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_A7FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_A8FF.S b/vm/mterp/mips/OP_UNUSED_A8FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_A8FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_A9FF.S b/vm/mterp/mips/OP_UNUSED_A9FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_A9FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_AAFF.S b/vm/mterp/mips/OP_UNUSED_AAFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_AAFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_ABFF.S b/vm/mterp/mips/OP_UNUSED_ABFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_ABFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_ACFF.S b/vm/mterp/mips/OP_UNUSED_ACFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_ACFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_ADFF.S b/vm/mterp/mips/OP_UNUSED_ADFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_ADFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_AEFF.S b/vm/mterp/mips/OP_UNUSED_AEFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_AEFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_AFFF.S b/vm/mterp/mips/OP_UNUSED_AFFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_AFFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_B0FF.S b/vm/mterp/mips/OP_UNUSED_B0FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_B0FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_B1FF.S b/vm/mterp/mips/OP_UNUSED_B1FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_B1FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_B2FF.S b/vm/mterp/mips/OP_UNUSED_B2FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_B2FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_B3FF.S b/vm/mterp/mips/OP_UNUSED_B3FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_B3FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_B4FF.S b/vm/mterp/mips/OP_UNUSED_B4FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_B4FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_B5FF.S b/vm/mterp/mips/OP_UNUSED_B5FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_B5FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_B6FF.S b/vm/mterp/mips/OP_UNUSED_B6FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_B6FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_B7FF.S b/vm/mterp/mips/OP_UNUSED_B7FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_B7FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_B8FF.S b/vm/mterp/mips/OP_UNUSED_B8FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_B8FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_B9FF.S b/vm/mterp/mips/OP_UNUSED_B9FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_B9FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_BAFF.S b/vm/mterp/mips/OP_UNUSED_BAFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_BAFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_BBFF.S b/vm/mterp/mips/OP_UNUSED_BBFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_BBFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_BCFF.S b/vm/mterp/mips/OP_UNUSED_BCFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_BCFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_BDFF.S b/vm/mterp/mips/OP_UNUSED_BDFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_BDFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_BEFF.S b/vm/mterp/mips/OP_UNUSED_BEFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_BEFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_BFFF.S b/vm/mterp/mips/OP_UNUSED_BFFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_BFFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_C0FF.S b/vm/mterp/mips/OP_UNUSED_C0FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_C0FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_C1FF.S b/vm/mterp/mips/OP_UNUSED_C1FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_C1FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_C2FF.S b/vm/mterp/mips/OP_UNUSED_C2FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_C2FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_C3FF.S b/vm/mterp/mips/OP_UNUSED_C3FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_C3FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_C4FF.S b/vm/mterp/mips/OP_UNUSED_C4FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_C4FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_C5FF.S b/vm/mterp/mips/OP_UNUSED_C5FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_C5FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_C6FF.S b/vm/mterp/mips/OP_UNUSED_C6FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_C6FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_C7FF.S b/vm/mterp/mips/OP_UNUSED_C7FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_C7FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_C8FF.S b/vm/mterp/mips/OP_UNUSED_C8FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_C8FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_C9FF.S b/vm/mterp/mips/OP_UNUSED_C9FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_C9FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_CAFF.S b/vm/mterp/mips/OP_UNUSED_CAFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_CAFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_CBFF.S b/vm/mterp/mips/OP_UNUSED_CBFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_CBFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_CCFF.S b/vm/mterp/mips/OP_UNUSED_CCFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_CCFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_CDFF.S b/vm/mterp/mips/OP_UNUSED_CDFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_CDFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_CEFF.S b/vm/mterp/mips/OP_UNUSED_CEFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_CEFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_CFFF.S b/vm/mterp/mips/OP_UNUSED_CFFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_CFFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_D0FF.S b/vm/mterp/mips/OP_UNUSED_D0FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_D0FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_D1FF.S b/vm/mterp/mips/OP_UNUSED_D1FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_D1FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_D2FF.S b/vm/mterp/mips/OP_UNUSED_D2FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_D2FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_D3FF.S b/vm/mterp/mips/OP_UNUSED_D3FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_D3FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_D4FF.S b/vm/mterp/mips/OP_UNUSED_D4FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_D4FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_D5FF.S b/vm/mterp/mips/OP_UNUSED_D5FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_D5FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_D6FF.S b/vm/mterp/mips/OP_UNUSED_D6FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_D6FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_D7FF.S b/vm/mterp/mips/OP_UNUSED_D7FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_D7FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_D8FF.S b/vm/mterp/mips/OP_UNUSED_D8FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_D8FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_D9FF.S b/vm/mterp/mips/OP_UNUSED_D9FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_D9FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_DAFF.S b/vm/mterp/mips/OP_UNUSED_DAFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_DAFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_DBFF.S b/vm/mterp/mips/OP_UNUSED_DBFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_DBFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_DCFF.S b/vm/mterp/mips/OP_UNUSED_DCFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_DCFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_DDFF.S b/vm/mterp/mips/OP_UNUSED_DDFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_DDFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_DEFF.S b/vm/mterp/mips/OP_UNUSED_DEFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_DEFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_DFFF.S b/vm/mterp/mips/OP_UNUSED_DFFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_DFFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E0FF.S b/vm/mterp/mips/OP_UNUSED_E0FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E0FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E1FF.S b/vm/mterp/mips/OP_UNUSED_E1FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E1FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E2FF.S b/vm/mterp/mips/OP_UNUSED_E2FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E2FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E3.S b/vm/mterp/mips/OP_UNUSED_E3.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E3.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E3FF.S b/vm/mterp/mips/OP_UNUSED_E3FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E3FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E4.S b/vm/mterp/mips/OP_UNUSED_E4.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E4.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E4FF.S b/vm/mterp/mips/OP_UNUSED_E4FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E4FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E5.S b/vm/mterp/mips/OP_UNUSED_E5.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E5.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E5FF.S b/vm/mterp/mips/OP_UNUSED_E5FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E5FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E6.S b/vm/mterp/mips/OP_UNUSED_E6.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E6.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E6FF.S b/vm/mterp/mips/OP_UNUSED_E6FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E6FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E7.S b/vm/mterp/mips/OP_UNUSED_E7.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E7.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E7FF.S b/vm/mterp/mips/OP_UNUSED_E7FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E7FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E8.S b/vm/mterp/mips/OP_UNUSED_E8.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E8.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E8FF.S b/vm/mterp/mips/OP_UNUSED_E8FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E8FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E9.S b/vm/mterp/mips/OP_UNUSED_E9.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E9.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_E9FF.S b/vm/mterp/mips/OP_UNUSED_E9FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_E9FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_EA.S b/vm/mterp/mips/OP_UNUSED_EA.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_EA.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_EAFF.S b/vm/mterp/mips/OP_UNUSED_EAFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_EAFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_EB.S b/vm/mterp/mips/OP_UNUSED_EB.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_EB.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_EBFF.S b/vm/mterp/mips/OP_UNUSED_EBFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_EBFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_EC.S b/vm/mterp/mips/OP_UNUSED_EC.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_EC.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_ECFF.S b/vm/mterp/mips/OP_UNUSED_ECFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_ECFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_ED.S b/vm/mterp/mips/OP_UNUSED_ED.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_ED.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_EDFF.S b/vm/mterp/mips/OP_UNUSED_EDFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_EDFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_EEFF.S b/vm/mterp/mips/OP_UNUSED_EEFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_EEFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_EF.S b/vm/mterp/mips/OP_UNUSED_EF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_EF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_EFFF.S b/vm/mterp/mips/OP_UNUSED_EFFF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_EFFF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_F0FF.S b/vm/mterp/mips/OP_UNUSED_F0FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_F0FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_F1.S b/vm/mterp/mips/OP_UNUSED_F1.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_F1.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_F1FF.S b/vm/mterp/mips/OP_UNUSED_F1FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_F1FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_FC.S b/vm/mterp/mips/OP_UNUSED_FC.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_FC.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_FD.S b/vm/mterp/mips/OP_UNUSED_FD.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_FD.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_FE.S b/vm/mterp/mips/OP_UNUSED_FE.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_FE.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_UNUSED_FF.S b/vm/mterp/mips/OP_UNUSED_FF.S
new file mode 100644
index 0000000..99ef3cf
--- /dev/null
+++ b/vm/mterp/mips/OP_UNUSED_FF.S
@@ -0,0 +1 @@
+%include "mips/unused.S"
diff --git a/vm/mterp/mips/OP_USHR_INT.S b/vm/mterp/mips/OP_USHR_INT.S
new file mode 100644
index 0000000..7b474b6
--- /dev/null
+++ b/vm/mterp/mips/OP_USHR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"preinstr":"and a1, a1, 31", "instr":"srl a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_USHR_INT_2ADDR.S b/vm/mterp/mips/OP_USHR_INT_2ADDR.S
new file mode 100644
index 0000000..71b5e36
--- /dev/null
+++ b/vm/mterp/mips/OP_USHR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"preinstr":"and a1, a1, 31", "instr":"srl a0, a0, a1 "}
diff --git a/vm/mterp/mips/OP_USHR_INT_LIT8.S b/vm/mterp/mips/OP_USHR_INT_LIT8.S
new file mode 100644
index 0000000..7dbe863
--- /dev/null
+++ b/vm/mterp/mips/OP_USHR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"preinstr":"and a1, a1, 31", "instr":"srl a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_USHR_LONG.S b/vm/mterp/mips/OP_USHR_LONG.S
new file mode 100644
index 0000000..acd9d15
--- /dev/null
+++ b/vm/mterp/mips/OP_USHR_LONG.S
@@ -0,0 +1,32 @@
+%verify "executed"
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* ushr-long vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(t0) # t3 <- AA
+ and a3, a0, 255 # a3 <- BB
+ srl a0, a0, 8 # a0 <- CC
+ EAS2(a3, rFP, a3) # a3 <- &fp[BB]
+ GET_VREG(a2, a0) # a2 <- vCC
+ LOAD64(a0, a1, a3) # a0/a1 <- vBB/vBB+1
+ EAS2(rOBJ, rFP, t0) # rOBJ <- &fp[AA]
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ srl v1, a1, a2 # rhi<- ahi >> (shift&31)
+ srl v0, a0, a2 # rlo<- alo >> (shift&31)
+ not a0, a2 # alo<- 31-n (shift is 5b)
+ sll a1, 1
+ sll a1, a0 # ahi<- ahi << (32-(shift&31))
+ or v0, a1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn v0, v1, a2 # rlo<- rhi (if shift&0x20)
+ movn v1, zero, a2 # rhi<- 0 (if shift&0x20)
+
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- v0/v1
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_USHR_LONG_2ADDR.S b/vm/mterp/mips/OP_USHR_LONG_2ADDR.S
new file mode 100644
index 0000000..103cc98
--- /dev/null
+++ b/vm/mterp/mips/OP_USHR_LONG_2ADDR.S
@@ -0,0 +1,27 @@
+%verify "executed"
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* ushr-long/2addr vA, vB */
+ GET_OPA4(t3) # t3 <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a2, a3) # a2 <- vB
+ EAS2(t3, rFP, t3) # t3 <- &fp[A]
+ LOAD64(a0, a1, t3) # a0/a1 <- vAA/vAA+1
+
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ srl v1, a1, a2 # rhi<- ahi >> (shift&31)
+ srl v0, a0, a2 # rlo<- alo >> (shift&31)
+ not a0, a2 # alo<- 31-n (shift is 5b)
+ sll a1, 1
+ sll a1, a0 # ahi<- ahi << (32-(shift&31))
+ or v0, a1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn v0, v1, a2 # rlo<- rhi (if shift&0x20)
+ movn v1, zero, a2 # rhi<- 0 (if shift&0x20)
+
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, t3) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
diff --git a/vm/mterp/mips/OP_XOR_INT.S b/vm/mterp/mips/OP_XOR_INT.S
new file mode 100644
index 0000000..6551e75
--- /dev/null
+++ b/vm/mterp/mips/OP_XOR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop.S" {"instr":"xor a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_XOR_INT_2ADDR.S b/vm/mterp/mips/OP_XOR_INT_2ADDR.S
new file mode 100644
index 0000000..f93b782
--- /dev/null
+++ b/vm/mterp/mips/OP_XOR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binop2addr.S" {"instr":"xor a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_XOR_INT_LIT16.S b/vm/mterp/mips/OP_XOR_INT_LIT16.S
new file mode 100644
index 0000000..add8ef2
--- /dev/null
+++ b/vm/mterp/mips/OP_XOR_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit16.S" {"instr":"xor a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_XOR_INT_LIT8.S b/vm/mterp/mips/OP_XOR_INT_LIT8.S
new file mode 100644
index 0000000..31fa360
--- /dev/null
+++ b/vm/mterp/mips/OP_XOR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopLit8.S" {"instr":"xor a0, a0, a1"}
diff --git a/vm/mterp/mips/OP_XOR_LONG.S b/vm/mterp/mips/OP_XOR_LONG.S
new file mode 100644
index 0000000..1f07c84
--- /dev/null
+++ b/vm/mterp/mips/OP_XOR_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopWide.S" {"preinstr":"xor a0, a0, a2", "instr":"xor a1, a1, a3"}
diff --git a/vm/mterp/mips/OP_XOR_LONG_2ADDR.S b/vm/mterp/mips/OP_XOR_LONG_2ADDR.S
new file mode 100644
index 0000000..dade7a9
--- /dev/null
+++ b/vm/mterp/mips/OP_XOR_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "mips/binopWide2addr.S" {"preinstr":"xor a0, a0, a2", "instr":"xor a1, a1, a3"}
diff --git a/vm/mterp/mips/alt_stub.S b/vm/mterp/mips/alt_stub.S
new file mode 100644
index 0000000..edf71a7
--- /dev/null
+++ b/vm/mterp/mips/alt_stub.S
@@ -0,0 +1,20 @@
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (${opnum} * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
diff --git a/vm/mterp/mips/bincmp.S b/vm/mterp/mips/bincmp.S
new file mode 100644
index 0000000..e2398d0
--- /dev/null
+++ b/vm/mterp/mips/bincmp.S
@@ -0,0 +1,35 @@
+%verify "branch taken"
+%verify "branch not taken"
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ GET_OPA4(a0) # a0 <- A+
+ GET_OPB(a1) # a1 <- B
+ GET_VREG(a3, a1) # a3 <- vB
+ GET_VREG(a2, a0) # a2 <- vA
+ b${revcmp} a2, a3, 1f # branch to 1 if comparison failed
+ FETCH_S(a1, 1) # a1<- branch offset, in code units
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a2, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a2, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+3:
+ bnez a0, common_updateProfile
+#else
+ bgez a2, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/mips/binflop.S b/vm/mterp/mips/binflop.S
new file mode 100644
index 0000000..6b02707
--- /dev/null
+++ b/vm/mterp/mips/binflop.S
@@ -0,0 +1,44 @@
+%default {"preinstr":"", "chkzero":"0"}
+ /*
+ * Generic 32-bit binary float operation.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ */
+
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+#ifdef SOFT_FLOAT
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if $chkzero
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa1, a3) # a1 <- vCC
+ GET_VREG_F(fa0, a2) # a0 <- vBB
+
+ .if $chkzero
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ $preinstr # optional op
+#ifdef SOFT_FLOAT
+ $instr # v0 = result
+ SET_VREG(v0, rOBJ) # vAA <- v0
+#else
+ $instr_f # f0 = result
+ SET_VREG_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 11-14 instructions */
+
diff --git a/vm/mterp/mips/binflop2addr.S b/vm/mterp/mips/binflop2addr.S
new file mode 100644
index 0000000..c20a1c6
--- /dev/null
+++ b/vm/mterp/mips/binflop2addr.S
@@ -0,0 +1,45 @@
+%default {"preinstr":"", "chkzero":"0"}
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" and
+ * "instr_f" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr,
+ * div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if $chkzero
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa0, rOBJ)
+ GET_VREG_F(fa1, a3)
+ .if $chkzero
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ $preinstr # optional op
+#ifdef SOFT_FLOAT
+ $instr # result <- op, a0-a3 changed
+ SET_VREG(v0, rOBJ) # vAA <- result
+#else
+ $instr_f
+ SET_VREG_F(fv0, rOBJ) # vAA <- result
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-13 instructions */
+
diff --git a/vm/mterp/mips/binflopWide.S b/vm/mterp/mips/binflopWide.S
new file mode 100644
index 0000000..ad61680
--- /dev/null
+++ b/vm/mterp/mips/binflopWide.S
@@ -0,0 +1,52 @@
+%default {"preinstr":"", "chkzero":"0"}
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # s5 <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3 <- vCC/vCC+1
+ .if $chkzero
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, a2)
+ LOAD64_F(fa1, fa1f, t1)
+ .if $chkzero
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ $preinstr # optional op
+#ifdef SOFT_FLOAT
+ $instr # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ $instr_f
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
diff --git a/vm/mterp/mips/binflopWide2addr.S b/vm/mterp/mips/binflopWide2addr.S
new file mode 100644
index 0000000..aacd482
--- /dev/null
+++ b/vm/mterp/mips/binflopWide2addr.S
@@ -0,0 +1,46 @@
+%default {"preinstr":"", "chkzero":"0"}
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr, rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG2, rARG3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if $chkzero
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, rOBJ)
+ LOAD64_F(fa1, fa1f, a1)
+ .if $chkzero
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ $preinstr # optional op
+#ifdef SOFT_FLOAT
+ $instr # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ $instr_f
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
diff --git a/vm/mterp/mips/binop.S b/vm/mterp/mips/binop.S
new file mode 100644
index 0000000..8bbe0fb
--- /dev/null
+++ b/vm/mterp/mips/binop.S
@@ -0,0 +1,34 @@
+%default {"preinstr":"", "result":"a0", "chkzero":"0"}
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if $chkzero
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ $preinstr # optional op
+ $instr # $result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO($result, rOBJ, t0) # vAA <- $result
+ /* 11-14 instructions */
+
diff --git a/vm/mterp/mips/binop2addr.S b/vm/mterp/mips/binop2addr.S
new file mode 100644
index 0000000..acca20d
--- /dev/null
+++ b/vm/mterp/mips/binop2addr.S
@@ -0,0 +1,30 @@
+%default {"preinstr":"", "result":"a0", "chkzero":"0"}
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if $chkzero
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ $preinstr # optional op
+ $instr # $result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO($result, rOBJ, t0) # vAA <- $result
+ /* 10-13 instructions */
+
diff --git a/vm/mterp/mips/binopLit16.S b/vm/mterp/mips/binopLit16.S
new file mode 100644
index 0000000..74b4533
--- /dev/null
+++ b/vm/mterp/mips/binopLit16.S
@@ -0,0 +1,30 @@
+%default {"result":"a0", "chkzero":"0"}
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ # binop/lit16 vA, vB, /* +CCCC */
+ FETCH_S(a1, 1) # a1 <- ssssCCCC (sign-extended)
+ GET_OPB(a2) # a2 <- B
+ GET_OPA(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a2) # a0 <- vB
+ and rOBJ, rOBJ, 15
+ .if $chkzero
+ # cmp a1, 0; is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ $instr # $result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO($result, rOBJ, t0) # vAA <- $result
+ /* 10-13 instructions */
+
diff --git a/vm/mterp/mips/binopLit8.S b/vm/mterp/mips/binopLit8.S
new file mode 100644
index 0000000..c3d7464
--- /dev/null
+++ b/vm/mterp/mips/binopLit8.S
@@ -0,0 +1,32 @@
+%default {"preinstr":"", "result":"a0", "chkzero":"0"}
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if $chkzero
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ $preinstr # optional op
+ $instr # $result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO($result, rOBJ, t0) # vAA <- $result
+ /* 10-12 instructions */
+
diff --git a/vm/mterp/mips/binopWide.S b/vm/mterp/mips/binopWide.S
new file mode 100644
index 0000000..3e47ab9
--- /dev/null
+++ b/vm/mterp/mips/binopWide.S
@@ -0,0 +1,38 @@
+%default {"preinstr":"", "result0":"a0", "result1":"a1", "chkzero":"0", "arg0":"a0", "arg1":"a1", "arg2":"a2", "arg3":"a3"}
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+ LOAD64($arg0, $arg1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64($arg2, $arg3, t1) # a2/a3 <- vCC/vCC+1
+ .if $chkzero
+ or t0, $arg2, $arg3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ $preinstr # optional op
+ $instr # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64($result0, $result1, rOBJ) # vAA/vAA+1 <- $result0/$result1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
diff --git a/vm/mterp/mips/binopWide2addr.S b/vm/mterp/mips/binopWide2addr.S
new file mode 100644
index 0000000..7494604
--- /dev/null
+++ b/vm/mterp/mips/binopWide2addr.S
@@ -0,0 +1,34 @@
+%default {"preinstr":"", "result0":"a0", "result1":"a1", "chkzero":"0", "arg0":"a0", "arg1":"a1", "arg2":"a2", "arg3":"a3"}
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ LOAD64($arg2, $arg3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64($arg0, $arg1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if $chkzero
+ or t0, $arg2, $arg3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ $preinstr # optional op
+ $instr # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64($result0, $result1, rOBJ) # vAA/vAA+1 <- $result0/$result1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
diff --git a/vm/mterp/mips/debug.cpp b/vm/mterp/mips/debug.cpp
new file mode 100644
index 0000000..0de6b67
--- /dev/null
+++ b/vm/mterp/mips/debug.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+
+/*
+ * Dump the fixed-purpose MIPS registers, along with some other info.
+ *
+ */
+void dvmMterpDumpMipsRegs(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3)
+{
+ register uint32_t rPC asm("s0");
+ register uint32_t rFP asm("s1");
+ register uint32_t rSELF asm("s2");
+ register uint32_t rIBASE asm("s3");
+ register uint32_t rINST asm("s4");
+ register uint32_t rOBJ asm("s5");
+ register uint32_t rBIX asm("s6");
+ register uint32_t rTEMP asm("s7");
+
+ //extern char dvmAsmInstructionStart[];
+
+ printf("REGS: a0=%08x a1=%08x a2=%08x a3=%08x\n", a0, a1, a2, a3);
+ printf(" : rPC=%08x rFP=%08x rSELF=%08x rIBASE=%08x\n",
+ rPC, rFP, rSELF, rIBASE);
+ printf(" : rINST=%08x rOBJ=%08x rBIX=%08x rTEMP=%08x \n", rINST, rOBJ, rBIX, rTEMP);
+
+ //Thread* self = (Thread*) rSELF;
+ //const Method* method = self->method;
+ printf(" + self is %p\n", dvmThreadSelf());
+ //printf(" + currently in %s.%s %s\n",
+ // method->clazz->descriptor, method->name, method->signature);
+ //printf(" + dvmAsmInstructionStart = %p\n", dvmAsmInstructionStart);
+ //printf(" + next handler for 0x%02x = %p\n",
+ // rINST & 0xff, dvmAsmInstructionStart + (rINST & 0xff) * 64);
+}
+
+/*
+ * Dump the StackSaveArea for the specified frame pointer.
+ */
+void dvmDumpFp(void* fp, StackSaveArea* otherSaveArea)
+{
+ StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
+ printf("StackSaveArea for fp %p [%p/%p]:\n", fp, saveArea, otherSaveArea);
+#ifdef EASY_GDB
+ printf(" prevSave=%p, prevFrame=%p savedPc=%p meth=%p curPc=%p\n",
+ saveArea->prevSave, saveArea->prevFrame, saveArea->savedPc,
+ saveArea->method, saveArea->xtra.currentPc);
+#else
+ printf(" prevFrame=%p savedPc=%p meth=%p curPc=%p fp[0]=0x%08x\n",
+ saveArea->prevFrame, saveArea->savedPc,
+ saveArea->method, saveArea->xtra.currentPc,
+ *(u4*)fp);
+#endif
+}
+
+/*
+ * Does the bulk of the work for common_printMethod().
+ */
+void dvmMterpPrintMethod(Method* method)
+{
+ /*
+ * It is a direct (non-virtual) method if it is static, private,
+ * or a constructor.
+ */
+ bool isDirect =
+ ((method->accessFlags & (ACC_STATIC|ACC_PRIVATE)) != 0) ||
+ (method->name[0] == '<');
+
+ char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+
+ printf("<%c:%s.%s %s> ",
+ isDirect ? 'D' : 'V',
+ method->clazz->descriptor,
+ method->name,
+ desc);
+
+ free(desc);
+}
diff --git a/vm/mterp/mips/entry.S b/vm/mterp/mips/entry.S
new file mode 100644
index 0000000..8a1b61a
--- /dev/null
+++ b/vm/mterp/mips/entry.S
@@ -0,0 +1,107 @@
+
+/*
+ * 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.
+ */
+/*
+ * Interpreter entry point.
+ */
+
+#define ASSIST_DEBUGGER 1
+
+ .text
+ .align 2
+ .global dvmMterpStdRun
+ .ent dvmMterpStdRun
+ .frame sp, STACK_SIZE, ra
+/*
+ * On entry:
+ * r0 Thread* self
+ *
+ * The return comes via a call to dvmMterpStdBail().
+ */
+
+dvmMterpStdRun:
+ .set noreorder
+ .cpload t9
+ .set reorder
+/* Save to the stack. Frame size = STACK_SIZE */
+ STACK_STORE_FULL()
+/* This directive will make sure all subsequent jal restore gp at a known offset */
+ .cprestore STACK_OFFSET_GP
+
+ addu fp, sp, STACK_SIZE # Move Frame Pointer to the base of frame
+ /* save stack pointer, add magic word for debuggerd */
+ sw sp, offThread_bailPtr(a0) # Save SP
+
+ /* set up "named" registers, figure out entry point */
+ move rSELF, a0 # set rSELF
+ LOAD_PC_FROM_SELF()
+ LOAD_FP_FROM_SELF()
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+
+#if defined(WITH_JIT)
+.LentryInstr:
+ /* Entry is always a possible trace start */
+ lw a0, offThread_pJitProfTable(rSELF)
+ FETCH_INST() # load rINST from rPC
+ sw zero, offThread_inJitCodeCache(rSELF)
+#if !defined(WITH_SELF_VERIFICATION)
+ bnez a0, common_updateProfile # profiling is enabled
+#else
+ lw a2, offThread_shadowSpace(rSELF) # to find out the jit exit state
+ beqz a0, 1f # profiling is disabled
+ lw a3, offShadowSpace_jitExitState(a2) # jit exit state
+ li t0, kSVSTraceSelect
+ bne a3, t0, 2f
+ li a2, kJitTSelectRequestHot # ask for trace selection
+ b common_selectTrace # go build the trace
+2:
+ li a4, kSVSNoProfile
+ beq a3, a4, 1f # don't profile the next instruction?
+ b common_updateProfile # collect profiles
+#endif
+1:
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+#else
+ /* start executing the instruction at rPC */
+ FETCH_INST() # load rINST from rPC
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+#endif
+
+.Lbad_arg:
+ la a0, .LstrBadEntryPoint
+ #a1 holds value of entryPoint
+ JAL(printf)
+ JAL(dvmAbort)
+
+ .end dvmMterpStdRun
+
+ .global dvmMterpStdBail
+ .ent dvmMterpStdBail
+
+/* Restore the stack pointer and all the registers stored at sp from the save
+ * point established on entry. Return to whoever called dvmMterpStdRun.
+ *
+ * On entry:
+ * a0 Thread* self
+ */
+dvmMterpStdBail:
+ lw sp, offThread_bailPtr(a0) # Restore sp
+ STACK_LOAD_FULL()
+ jr ra
+
+ .end dvmMterpStdBail
diff --git a/vm/mterp/mips/footer.S b/vm/mterp/mips/footer.S
new file mode 100644
index 0000000..b5b53b7
--- /dev/null
+++ b/vm/mterp/mips/footer.S
@@ -0,0 +1,1205 @@
+/*
+ * ===========================================================================
+ * Common subroutines and data
+ * ===========================================================================
+ */
+
+ .text
+ .align 2
+
+#if defined(WITH_JIT)
+#if defined(WITH_SELF_VERIFICATION)
+
+/*
+ * "longjmp" to a translation after single-stepping. Before returning
+ * to translation, must save state for self-verification.
+ */
+ .global dvmJitResumeTranslation # (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+ move rSELF, a0 # restore self
+ move rPC, a1 # restore Dalvik pc
+ move rFP, a2 # restore Dalvik fp
+ lw rBIX, offThread_jitResumeNPC(rSELF)
+ sw zero, offThread_jitResumeNPC(rSELF) # reset resume address
+ lw sp, offThread_jitResumeNSP(rSELF) # cut back native stack
+ b jitSVShadowRunStart # resume as if cache hit
+ # expects resume addr in rBIX
+
+ .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+ li a2, kSVSPunt # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+ move rPC, a0 # set up dalvik pc
+ EXPORT_PC()
+ sw ra, offThread_jitResumeNPC(rSELF)
+ sw a1, offThread_jitResumeDPC(rSELF)
+ li a2, kSVSSingleStep # a2 <- interpreter entry point
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ move a0, rPC # pass our target PC
+ li a2, kSVSNoProfile # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+ move a0, rPC # pass our target PC
+ li a2, kSVSTraceSelect # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+ lw a0, 0(ra) # pass our target PC
+ li a2, kSVSTraceSelect # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpBackwardBranch
+dvmJitToInterpBackwardBranch:
+ lw a0, 0(ra) # pass our target PC
+ li a2, kSVSBackwardBranch # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+ lw a0, 0(ra) # pass our target PC
+ li a2, kSVSNormal # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+ move a0, rPC # pass our target PC
+ li a2, kSVSNoChain # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+#else /* WITH_SELF_VERIFICATION */
+
+
+/*
+ * "longjmp" to a translation after single-stepping.
+ */
+ .global dvmJitResumeTranslation # (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+ move rSELF, a0 # restore self
+ move rPC, a1 # restore Dalvik pc
+ move rFP, a2 # restore Dalvik fp
+ lw a0, offThread_jitResumeNPC(rSELF)
+ sw zero, offThread_jitResumeNPC(rSELF) # reset resume address
+ lw sp, offThread_jitResumeNSP(rSELF) # cut back native stack
+ jr a0 # resume translation
+
+
+/*
+ * Return from the translation cache to the interpreter when the compiler is
+ * having issues translating/executing a Dalvik instruction. We have to skip
+ * the code cache lookup otherwise it is possible to indefinitely bouce
+ * between the interpreter and the code cache if the instruction that fails
+ * to be compiled happens to be at a trace start.
+ */
+ .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+ lw gp, STACK_OFFSET_GP(sp)
+ move rPC, a0
+#if defined(WITH_JIT_TUNING)
+ move a0, ra
+ JAL(dvmBumpPunt)
+#endif
+ EXPORT_PC()
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * On entry:
+ * rPC <= Dalvik PC of instrucion to interpret
+ * a1 <= Dalvik PC of resume instruction
+ * ra <= resume point in translation
+ */
+
+ .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+ lw gp, STACK_OFFSET_GP(sp)
+ move rPC, a0 # set up dalvik pc
+ EXPORT_PC()
+ sw ra, offThread_jitResumeNPC(rSELF)
+ sw sp, offThread_jitResumeNSP(rSELF)
+ sw a1, offThread_jitResumeDPC(rSELF)
+ li a1, 1
+ sw a1, offThread_singleStepCount(rSELF) # just step once
+ move a0, rSELF
+ li a1, kSubModeCountedStep
+ JAL(dvmEnableSubMode) # (self, subMode)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target. Commonly used for callees.
+ */
+ .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+ lw gp, STACK_OFFSET_GP(sp)
+#if defined(WITH_JIT_TUNING)
+ JAL(dvmBumpNoChain)
+#endif
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # (pc, self)
+ move a0, v0
+ sw a0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+ beqz a0, 2f # 0 means translation does not exist
+ jr a0
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target. Commonly used following
+ * invokes.
+ */
+ .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+ lw gp, STACK_OFFSET_GP(sp)
+ lw rPC, (ra) # get our target PC
+ subu rINST, ra, 8 # save start of chain branch
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # @ (pc, self)
+ sw v0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ beqz v0, 2f
+ move a0, v0
+ move a1, rINST
+ JAL(dvmJitChain) # v0 <- dvmJitChain(codeAddr, chainAddr)
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+ move a0, v0
+ beqz a0, toInterpreter # didn't chain - resume with interpreter
+
+ jr a0 # continue native execution
+
+/* No translation, so request one if profiling isn't disabled */
+2:
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ lw a0, offThread_pJitProfTable(rSELF)
+ FETCH_INST()
+ li t0, kJitTSelectRequestHot
+ movn a2, t0, a0 # ask for trace selection
+ bnez a0, common_selectTrace
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+
+/*
+ * Return from the translation cache to the interpreter.
+ * The return was done with a BLX from thumb mode, and
+ * the following 32-bit word contains the target rPC value.
+ * Note that lr (r14) will have its low-order bit set to denote
+ * its thumb-mode origin.
+ *
+ * We'll need to stash our lr origin away, recover the new
+ * target and then check to see if there is a translation available
+ * for our new target. If so, we do a translation chain and
+ * go back to native execution. Otherwise, it's back to the
+ * interpreter (after treating this entry as a potential
+ * trace start).
+ */
+ .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+ lw gp, STACK_OFFSET_GP(sp)
+ lw rPC, (ra) # get our target PC
+ subu rINST, ra, 8 # save start of chain branch
+#if defined(WITH_JIT_TUNING)
+ JAL(dvmBumpNormal)
+#endif
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # @ (pc, self)
+ move a0, v0
+ sw a0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ beqz a0, toInterpreter # go if not, otherwise do chain
+ move a1, rINST
+ JAL(dvmJitChain) # v0 <- dvmJitChain(codeAddr, chainAddr)
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+ move a0, v0
+ beqz a0, toInterpreter # didn't chain - resume with interpreter
+
+ jr a0 # continue native execution
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ JAL(dvmBumpNoChain)
+#endif
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # (pc, self)
+ move a0, v0
+ sw a0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+ beqz a0, footer235
+
+ jr a0 # continue native execution if so
+footer235:
+ EXPORT_PC()
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
+
+ .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+ lw gp, STACK_OFFSET_GP(sp)
+#if defined(WITH_JIT_TUNING)
+ JAL(dvmBumpNoChain)
+#endif
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # (pc, self)
+ move a0, v0
+ sw a0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+ beqz a0, 1f
+ jr a0 # continue native execution if so
+1:
+#endif /* WITH_SELF_VERIFICATION */
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rSELF & rFP were preserved in the translated code, and rPC has
+ * already been restored by the time we get here. We'll need to set
+ * up rIBASE & rINST, and load the address of the JitTable into r0.
+ */
+
+toInterpreter:
+ EXPORT_PC()
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ lw a0, offThread_pJitProfTable(rSELF)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ # NOTE: intended fallthrough
+
+/*
+ * Similar to common_updateProfile, but tests for null pJitProfTable
+ * r0 holds pJifProfTAble, rINST is loaded, rPC is current and
+ * rIBASE has been recently refreshed.
+ */
+
+common_testUpdateProfile:
+
+ beqz a0, 4f
+
+/*
+ * Common code to update potential trace start counter, and initiate
+ * a trace-build if appropriate.
+ * On entry here:
+ * r0 <= pJitProfTable (verified non-NULL)
+ * rPC <= Dalvik PC
+ * rINST <= next instruction
+ */
+common_updateProfile:
+ srl a3, rPC, 12 # cheap, but fast hash function
+ xor a3, a3, rPC
+ andi a3, a3, JIT_PROF_SIZE-1 # eliminate excess bits
+ addu t1, a0, a3
+ lbu a1, (t1) # get counter
+ GET_INST_OPCODE(t0)
+ subu a1, a1, 1 # decrement counter
+ sb a1, (t1) # and store it
+ beqz a1, 1f
+ GOTO_OPCODE(t0) # if not threshold, fallthrough otherwise
+1:
+ /* Looks good, reset the counter */
+ lw a1, offThread_jitThreshold(rSELF)
+ sb a1, (t1)
+ EXPORT_PC()
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # (pc, self)
+ move a0, v0
+ sw v0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+
+#if !defined(WITH_SELF_VERIFICATION)
+ li t0, kJitTSelectRequest # ask for trace selection
+ movz a2, t0, a0
+ beqz a0, common_selectTrace
+ jr a0 # jump to the translation
+#else
+
+ bne a0, zero, skip_ask_for_trace_selection
+ li a2, kJitTSelectRequest # ask for trace selection
+ j common_selectTrace
+
+skip_ask_for_trace_selection:
+ /*
+ * At this point, we have a target translation. However, if
+ * that translation is actually the interpret-only pseudo-translation
+ * we want to treat it the same as no translation.
+ */
+ move rBIX, a0 # save target
+ jal dvmCompilerGetInterpretTemplate
+ # special case?
+ bne v0, rBIX, jitSVShadowRunStart # set up self verification shadow space
+ # Need to clear the inJitCodeCache flag
+ sw zero, offThread_inJitCodeCache(rSELF) # back to the interp land
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+ /* no return */
+#endif
+
+/*
+ * On entry:
+ * r2 is jit state.
+ */
+
+common_selectTrace:
+ lhu a0, offThread_subMode(rSELF)
+ andi a0, (kSubModeJitTraceBuild | kSubModeJitSV)
+ bnez a0, 3f # already doing JIT work, continue
+ sw a2, offThread_jitState(rSELF)
+ move a0, rSELF
+
+/*
+ * Call out to validate trace-building request. If successful,
+ * rIBASE will be swapped to to send us into single-stepping trace
+ * building mode, so we need to refresh before we continue.
+ */
+
+ EXPORT_PC()
+ SAVE_PC_TO_SELF()
+ SAVE_FP_TO_SELF()
+ JAL(dvmJitCheckTraceRequest)
+3:
+ FETCH_INST()
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+4:
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0)
+ /* no return */
+#endif
+
+#if defined(WITH_SELF_VERIFICATION)
+
+/*
+ * Save PC and registers to shadow memory for self verification mode
+ * before jumping to native translation.
+ * On entry:
+ * rPC, rFP, rSELF: the values that they should contain
+ * r10: the address of the target translation.
+ */
+jitSVShadowRunStart:
+ move a0, rPC # r0 <- program counter
+ move a1, rFP # r1 <- frame pointer
+ move a2, rSELF # r2 <- InterpState pointer
+ move a3, rBIX # r3 <- target translation
+ jal dvmSelfVerificationSaveState # save registers to shadow space
+ lw rFP, offShadowSpace_shadowFP(v0) # rFP <- fp in shadow space
+ jr rBIX # jump to the translation
+
+/*
+ * Restore PC, registers, and interpState to original values
+ * before jumping back to the interpreter.
+ */
+jitSVShadowRunEnd:
+ move a1, rFP # pass ending fp
+ move a3, rSELF # pass self ptr for convenience
+ jal dvmSelfVerificationRestoreState # restore pc and fp values
+ LOAD_PC_FP_FROM_SELF() # restore pc, fp
+ lw a1, offShadowSpace_svState(a0) # get self verification state
+ beq a1, zero, 1f # check for punt condition
+
+ # Setup SV single-stepping
+ move a0, rSELF
+ li a1, kSubModeJitSV
+ JAL(dvmEnableSubMode) # (self, subMode)
+ li a2, kJitSelfVerification # ask for self verification
+ sw a2, offThread_jitState(rSELF)
+ # Intentional fallthrough
+
+1:
+ # exit to interpreter without check
+ EXPORT_PC()
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+#endif
+
+/*
+ * The equivalent of "goto bail", this calls through the "bail handler".
+ * It will end this interpreter activation, and return to the caller
+ * of dvmMterpStdRun.
+ *
+ * State registers will be saved to the "thread" area before bailing
+ * debugging purposes
+ */
+ .ent common_gotoBail
+common_gotoBail:
+ SAVE_PC_FP_TO_SELF() # export state to "thread"
+ move a0, rSELF # a0 <- self ptr
+ b dvmMterpStdBail # call(self, changeInterp)
+ .end common_gotoBail
+
+/*
+ * The JIT's invoke method needs to remember the callsite class and
+ * target pair. Save them here so that they are available to
+ * dvmCheckJit following the interpretation of this invoke.
+ */
+#if defined(WITH_JIT)
+save_callsiteinfo:
+ beqz rOBJ, 1f
+ lw rOBJ, offObject_clazz(rOBJ)
+1:
+ sw a0, offThread_methodToCall(rSELF)
+ sw rOBJ, offThread_callsiteClass(rSELF)
+ jr ra
+#endif
+
+/*
+ * Common code for jumbo method invocation.
+ * NOTE: this adjusts rPC to account for the difference in instruction width.
+ * As a result, the savedPc in the stack frame will not be wholly accurate. So
+ * long as that is only used for source file line number calculations, we're
+ * okay.
+ */
+common_invokeMethodJumboNoThis:
+#if defined(WITH_JIT)
+ /* On entry: a0 is "Method* methodToCall */
+ li rOBJ, 0 # clear "this"
+#endif
+common_invokeMethodJumbo:
+ /* On entry: a0 is "Method* methodToCall, rOBJ is "this" */
+.LinvokeNewJumbo:
+#if defined(WITH_JIT)
+ lhu a1, offThread_subMode(rSELF)
+ andi a1, kSubModeJitTraceBuild
+ beqz a1, 1f
+ JAL(save_callsiteinfo)
+#endif
+/* prepare to copy args to "outs" area of current frame */
+1:
+ add rPC, rPC, 4 # adjust pc to make return consistent
+ FETCH(a2, 1)
+ SAVEAREA_FROM_FP(rBIX, rFP) # rBIX <- stack save area
+ beqz a2, .LinvokeArgsDone # if no args, skip the rest
+ FETCH(a1, 2) # a1 <- CCCC
+ b .LinvokeRangeArgs # handle args like invoke range
+
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ * a0 is "Method* methodToCall", the method we're trying to call
+ */
+common_invokeMethodRange:
+.LinvokeNewRange:
+#if defined(WITH_JIT)
+ lhu a1, offThread_subMode(rSELF)
+ andi a1, kSubModeJitTraceBuild
+ beqz a1, 1f
+ JAL(save_callsiteinfo)
+#endif
+ # prepare to copy args to "outs" area of current frame
+1:
+ GET_OPA(a2)
+ SAVEAREA_FROM_FP(rBIX, rFP) # rBIX <- stack save area
+ beqz a2, .LinvokeArgsDone
+ FETCH(a1, 2) # a1 <- CCCC
+.LinvokeRangeArgs:
+ # a0=methodToCall, a1=CCCC, a2=count, rBIX=outs
+ # (very few methods have > 10 args; could unroll for common cases)
+ EAS2(a3, rFP, a1)
+ sll t0, a2, 2
+ subu rBIX, rBIX, t0
+
+1:
+ lw a1, 0(a3)
+ addu a3, a3, 4
+ subu a2, a2, 1
+ sw a1, 0(rBIX)
+ addu rBIX, 4
+ bnez a2, 1b
+ b .LinvokeArgsDone
+
+/*
+ * Common code for method invocation without range.
+ *
+ * On entry:
+ * a0 is "Method* methodToCall", "rOBJ is this"
+ */
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+#if defined(WITH_JIT)
+ lhu a1, offThread_subMode(rSELF)
+ andi a1, kSubModeJitTraceBuild
+ beqz a1, 1f
+ JAL(save_callsiteinfo)
+#endif
+
+ # prepare to copy args to "outs" area of current frame
+1:
+ GET_OPB(a2)
+ SAVEAREA_FROM_FP(rBIX, rFP)
+ beqz a2, .LinvokeArgsDone
+ FETCH(a1, 2)
+
+ # a0=methodToCall, a1=GFED, a2=count,
+.LinvokeNonRange:
+ beq a2, 0, 0f
+ beq a2, 1, 1f
+ beq a2, 2, 2f
+ beq a2, 3, 3f
+ beq a2, 4, 4f
+ beq a2, 5, 5f
+
+5:
+ and t0, rINST, 0x0f00
+ ESRN(t2, rFP, t0, 6)
+ lw a3, (t2)
+ subu rBIX, 4
+ sw a3, 0(rBIX)
+
+4:
+ and t0, a1, 0xf000
+ ESRN(t2, rFP, t0, 10)
+ lw a3, (t2)
+ subu rBIX, 4
+ sw a3, 0(rBIX)
+
+3:
+ and t0, a1, 0x0f00
+ ESRN(t2, rFP, t0, 6)
+ lw a3, (t2)
+ subu rBIX, 4
+ sw a3, 0(rBIX)
+
+2:
+ and t0, a1, 0x00f0
+ ESRN(t2, rFP, t0, 2)
+ lw a3, (t2)
+ subu rBIX, 4
+ sw a3, 0(rBIX)
+
+1:
+ and t0, a1, 0x000f
+ EASN(t2, rFP, t0, 2)
+ lw a3, (t2)
+ subu rBIX, 4
+ sw a3, 0(rBIX)
+
+0:
+ #fall through .LinvokeArgsDone
+
+
+.LinvokeArgsDone: # a0=methodToCall
+ lhu rOBJ, offMethod_registersSize(a0)
+ lhu a3, offMethod_outsSize(a0)
+ lw a2, offMethod_insns(a0)
+ lw rINST, offMethod_clazz(a0)
+ # find space for the new stack frame, check for overflow
+ SAVEAREA_FROM_FP(a1, rFP) # a1 <- stack save area
+ sll t0, rOBJ, 2 # a1 <- newFp (old savearea - regsSize)
+ subu a1, a1, t0
+ SAVEAREA_FROM_FP(rBIX, a1)
+ lw rOBJ, offThread_interpStackEnd(rSELF) # t3 <- interpStackEnd
+ sll t2, a3, 2
+ subu t0, rBIX, t2
+ lhu ra, offThread_subMode(rSELF)
+ lw a3, offMethod_accessFlags(a0) # a3 <- methodToCall->accessFlags
+ bltu t0, rOBJ, .LstackOverflow # yes, this frame will overflow stack
+
+
+ # set up newSaveArea
+#ifdef EASY_GDB
+ SAVEAREA_FROM_FP(t0, rFP)
+ sw t0, offStackSaveArea_prevSave(rBIX)
+#endif
+ sw rFP, (offStackSaveArea_prevFrame)(rBIX)
+ sw rPC, (offStackSaveArea_savedPc)(rBIX)
+#if defined(WITH_JIT)
+ sw zero, (offStackSaveArea_returnAddr)(rBIX)
+#endif
+ sw a0, (offStackSaveArea_method)(rBIX)
+ # Profiling?
+ bnez ra, 2f
+1:
+ and t2, a3, ACC_NATIVE
+ bnez t2, .LinvokeNative
+ lhu rOBJ, (a2) # rOBJ -< load Inst from New PC
+ lw a3, offClassObject_pDvmDex(rINST)
+ move rPC, a2 # Publish new rPC
+ # Update state values for the new method
+ # a0=methodToCall, a1=newFp, a3=newMethodClass, rOBJ=newINST
+ sw a0, offThread_method(rSELF)
+ sw a3, offThread_methodClassDex(rSELF)
+ li a2, 1
+ sw a2, offThread_debugIsMethodEntry(rSELF)
+
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ move rFP, a1 # fp = newFp
+ GET_PREFETCHED_OPCODE(t0, rOBJ) # extract prefetched opcode from rOBJ
+ move rINST, rOBJ # publish new rINST
+ sw a1, offThread_curFrame(rSELF)
+ bnez a0, common_updateProfile
+ GOTO_OPCODE(t0)
+#else
+ move rFP, a1
+ GET_PREFETCHED_OPCODE(t0, rOBJ)
+ move rINST, rOBJ
+ sw a1, offThread_curFrame(rSELF)
+ GOTO_OPCODE(t0)
+#endif
+
+2:
+ # Profiling - record method entry. a0: methodToCall
+ STACK_STORE(a0, 0)
+ STACK_STORE(a1, 4)
+ STACK_STORE(a2, 8)
+ STACK_STORE(a3, 12)
+ sw rPC, offThread_pc(rSELF) # update interpSave.pc
+ move a1, a0
+ move a0, rSELF
+ JAL(dvmReportInvoke)
+ STACK_LOAD(a3, 12) # restore a0-a3
+ STACK_LOAD(a2, 8)
+ STACK_LOAD(a1, 4)
+ STACK_LOAD(a0, 0)
+ b 1b
+.LinvokeNative:
+ # Prep for the native call
+ # a0=methodToCall, a1=newFp, rBIX=newSaveArea
+ lhu ra, offThread_subMode(rSELF)
+ lw t3, offThread_jniLocal_topCookie(rSELF)
+ sw a1, offThread_curFrame(rSELF)
+ sw t3, offStackSaveArea_localRefCookie(rBIX) # newFp->localRefCookie=top
+ move a2, a0
+ move a0, a1
+ addu a1, rSELF, offThread_retval
+ move a3, rSELF
+#ifdef ASSIST_DEBUGGER
+ /* insert fake function header to help gdb find the stack frame */
+ b .Lskip
+ .ent dalvik_mterp
+dalvik_mterp:
+ STACK_STORE_FULL()
+.Lskip:
+#endif
+ bnez ra, 11f # Any special SubModes active?
+ lw t9, offMethod_nativeFunc(a2)
+ jalr t9
+ lw gp, STACK_OFFSET_GP(sp)
+7:
+ # native return; rBIX=newSaveArea
+ # equivalent to dvmPopJniLocals
+ lw a0, offStackSaveArea_localRefCookie(rBIX)
+ lw a1, offThread_exception(rSELF)
+ sw rFP, offThread_curFrame(rSELF)
+ sw a0, offThread_jniLocal_topCookie(rSELF) # new top <- old top
+ bnez a1, common_exceptionThrown
+
+ FETCH_ADVANCE_INST(3)
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+11:
+ # a0=newFp, a1=&retval, a2=methodToCall, a3=self, ra=subModes
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+ move a0, a2 # a0 <- methodToCall
+ move a1, rSELF
+ move a2, rFP
+ JAL(dvmReportPreNativeInvoke) # (methodToCall, self, fp)
+ SCRATCH_LOAD(a3, 12) # restore a0-a3
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+
+ # Call the native method
+ lw t9, offMethod_nativeFunc(a2) # t9<-methodToCall->nativeFunc
+ jalr t9
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # Restore the pre-call arguments
+ SCRATCH_LOAD(a3, 12) # restore a0-a3
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+
+ # Finish up any post-invoke subMode requirements
+ move a0, a2
+ move a1, rSELF
+ move a2, rFP
+ JAL(dvmReportPostNativeInvoke) # (methodToCall, self, fp)
+ b 7b
+
+
+.LstackOverflow: # a0=methodToCall
+ move a1, a0 # a1 <- methodToCall
+ move a0, rSELF # a0 <- self
+ JAL(dvmHandleStackOverflow) # dvmHandleStackOverflow(self, methodToCall)
+ b common_exceptionThrown
+#ifdef ASSIST_DEBUGGER
+ .end dalvik_mterp
+#endif
+
+ /*
+ * Common code for method invocation, calling through "glue code".
+ *
+ * TODO: now that we have range and non-range invoke handlers, this
+ * needs to be split into two. Maybe just create entry points
+ * that set r9 and jump here?
+ *
+ * On entry:
+ * r0 is "Method* methodToCall", the method we're trying to call
+ * r9 is "bool methodCallRange", indicating if this is a /range variant
+ */
+
+/*
+ * Common code for handling a return instruction.
+ *
+ * This does not return.
+ */
+common_returnFromMethod:
+.LreturnNew:
+ lhu t0, offThread_subMode(rSELF)
+ SAVEAREA_FROM_FP(a0, rFP)
+ lw rOBJ, offStackSaveArea_savedPc(a0) # rOBJ = saveArea->savedPc
+ bnez t0, 19f
+14:
+ lw rFP, offStackSaveArea_prevFrame(a0) # fp = saveArea->prevFrame
+ lw a2, (offStackSaveArea_method - sizeofStackSaveArea)(rFP)
+ # a2<- method we're returning to
+ # is this a break frame?
+ beqz a2, common_gotoBail # break frame, bail out completely
+
+ lw rBIX, offMethod_clazz(a2) # rBIX<- method->clazz
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+ PREFETCH_ADVANCE_INST(rINST, rOBJ, 3) # advance rOBJ, update new rINST
+ sw a2, offThread_method(rSELF) # self->method = newSave->method
+ lw a1, offClassObject_pDvmDex(rBIX) # r1<- method->clazz->pDvmDex
+ sw rFP, offThread_curFrame(rSELF) # curFrame = fp
+#if defined(WITH_JIT)
+ lw rBIX, offStackSaveArea_returnAddr(a0)
+ move rPC, rOBJ # publish new rPC
+ sw a1, offThread_methodClassDex(rSELF)
+ sw rBIX, offThread_inJitCodeCache(rSELF) # may return to JIT'ed land
+ beqz rBIX, 15f # caller is compiled code
+ move t9, rBIX
+ jalr t9
+ lw gp, STACK_OFFSET_GP(sp)
+15:
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+#else
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ move rPC, rOBJ # publish new rPC
+ sw a1, offThread_methodClassDex(rSELF)
+ GOTO_OPCODE(t0)
+#endif
+
+19:
+ # Handle special actions
+ # On entry, a0: StackSaveArea
+ lw a1, offStackSaveArea_prevFrame(a0) # a1<- prevFP
+ sw rPC, offThread_pc(rSELF) # update interpSave.pc
+ sw a1, offThread_curFrame(rSELF) # update interpSave.curFrame
+ move a0, rSELF
+ JAL(dvmReportReturn)
+ SAVEAREA_FROM_FP(a0, rFP) # restore StackSaveArea
+ b 14b
+
+ .if 0
+ /*
+ * Return handling, calls through "glue code".
+ */
+.LreturnOld:
+ SAVE_PC_FP_TO_SELF() # export state
+ move a0, rSELF # arg to function
+ JAL(dvmMterp_returnFromMethod)
+ b common_resumeAfterGlueCall
+ .endif
+
+/*
+ * Somebody has thrown an exception. Handle it.
+ *
+ * If the exception processing code returns to us (instead of falling
+ * out of the interpreter), continue with whatever the next instruction
+ * now happens to be.
+ *
+ * This does not return.
+ */
+ .global dvmMterpCommonExceptionThrown
+dvmMterpCommonExceptionThrown:
+common_exceptionThrown:
+.LexceptionNew:
+
+ EXPORT_PC()
+ move a0, rSELF
+ JAL(dvmCheckSuspendPending)
+ lw rOBJ, offThread_exception(rSELF)
+ move a1, rSELF
+ move a0, rOBJ
+ JAL(dvmAddTrackedAlloc)
+ lhu a2, offThread_subMode(rSELF)
+ sw zero, offThread_exception(rSELF)
+
+ # Special subMode?
+ bnez a2, 7f # any special subMode handling needed?
+8:
+ /* set up args and a local for "&fp" */
+ sw rFP, 20(sp) # store rFP => tmp
+ addu t0, sp, 20 # compute &tmp
+ sw t0, STACK_OFFSET_ARG04(sp) # save it in arg4 as per ABI
+ li a3, 0 # a3 <- false
+ lw a1, offThread_method(rSELF)
+ move a0, rSELF
+ lw a1, offMethod_insns(a1)
+ lhu ra, offThread_subMode(rSELF)
+ move a2, rOBJ
+ subu a1, rPC, a1
+ sra a1, a1, 1
+
+ /* call, r0 gets catchRelPc (a code-unit offset) */
+ JAL(dvmFindCatchBlock) # call(self, relPc, exc, scan?, &fp)
+ lw rFP, 20(sp) # retrieve the updated rFP
+
+ /* update frame pointer and check result from dvmFindCatchBlock */
+ move a0, v0
+ bltz v0, .LnotCaughtLocally
+
+ /* fix earlier stack overflow if necessary; Preserve a0 */
+ lbu a1, offThread_stackOverflowed(rSELF)
+ beqz a1, 1f
+ move rBIX, a0
+ move a0, rSELF
+ move a1, rOBJ
+ JAL(dvmCleanupStackOverflow)
+ move a0, rBIX
+
+1:
+
+/* adjust locals to match self->interpSave.curFrame and updated PC */
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- new save area
+ lw a1, offStackSaveArea_method(a1)
+ sw a1, offThread_method(rSELF)
+ lw a2, offMethod_clazz(a1)
+ lw a3, offMethod_insns(a1)
+ lw a2, offClassObject_pDvmDex(a2)
+ EAS1(rPC, a3, a0)
+ sw a2, offThread_methodClassDex(rSELF)
+
+ /* release the tracked alloc on the exception */
+ move a0, rOBJ
+ move a1, rSELF
+ JAL(dvmReleaseTrackedAlloc)
+
+ /* restore the exception if the handler wants it */
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ GET_INST_OPCODE(t0)
+ bne t0, OP_MOVE_EXCEPTION, 2f
+ sw rOBJ, offThread_exception(rSELF)
+2:
+ GOTO_OPCODE(t0)
+
+ # Manage debugger bookkeeping
+7:
+ sw rPC, offThread_pc(rSELF)
+ sw rFP, offThread_curFrame(rSELF)
+ move a0, rSELF
+ move a1, rOBJ
+ JAL(dvmReportExceptionThrow)
+ b 8b
+
+.LnotCaughtLocally: # rOBJ = exception
+ /* fix stack overflow if necessary */
+ lbu a1, offThread_stackOverflowed(rSELF)
+ beqz a1, 3f
+ move a0, rSELF
+ move a1, rOBJ
+ JAL(dvmCleanupStackOverflow) # dvmCleanupStackOverflow(self, exception)
+
+3:
+ # may want to show "not caught locally" debug messages here
+#if DVM_SHOW_EXCEPTION >= 2
+ /* call __android_log_print(prio, tag, format, ...) */
+ /* "Exception %s from %s:%d not caught locally" */
+ lw a0, offThread_method(rSELF)
+ lw a1, offMethod_insns(a0)
+ subu a1, rPC, a1
+ sra a1, a1, 1
+ JAL(dvmLineNumFromPC)
+ sw v0, 20(sp)
+ # dvmGetMethodSourceFile(method)
+ lw a0, offThread_method(rSELF)
+ JAL(dvmGetMethodSourceFile)
+ sw v0, 16(sp)
+ # exception->clazz->descriptor
+ lw a3, offObject_clazz(rOBJ)
+ lw a3, offClassObject_descriptor(a3)
+ la a2, .LstrExceptionNotCaughtLocally
+ la a1, .LstrLogTag
+ li a0, 3
+ JAL(__android_log_print)
+#endif
+ sw rOBJ, offThread_exception(rSELF)
+ move a0, rOBJ
+ move a1, rSELF
+ JAL(dvmReleaseTrackedAlloc)
+ b common_gotoBail
+
+ /*
+ * Exception handling, calls through "glue code".
+ */
+ .if 0
+.LexceptionOld:
+ SAVE_PC_TO_SELF() # export state
+ SAVE_FP_TO_SELF()
+ move a0, rSELF # arg to function
+ JAL(dvmMterp_exceptionThrown)
+ b common_resumeAfterGlueCall
+ .endif
+
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including the current
+ * instruction.
+ *
+ * On entry:
+ * rBIX: &dvmDex->pResFields[field]
+ * a0: field pointer (must preserve)
+ */
+common_verifyField:
+ lhu a3, offThread_subMode(rSELF)
+ andi a3, kSubModeJitTraceBuild
+ bnez a3, 1f # Not building trace, continue
+ jr ra
+1:
+ lw a1, (rBIX)
+ beqz a1, 2f # resolution complete ?
+ jr ra
+2:
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+ SCRATCH_STORE(ra, 16)
+ move a0, rSELF
+ move a1, rPC
+ JAL(dvmJitEndTraceSelect) #(self,pc) end trace before this inst)
+ SCRATCH_LOAD(a0, 0)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a3, 12)
+ SCRATCH_LOAD(ra, 16)
+ jr ra # return
+#endif
+
+/*
+ * After returning from a "glued" function, pull out the updated
+ * values and start executing at the next instruction.
+ */
+common_resumeAfterGlueCall:
+ LOAD_PC_FP_FROM_SELF() # pull rPC and rFP out of thread
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh
+ FETCH_INST() # load rINST from rPC
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/*
+ * Invalid array index. Note that our calling convention is strange; we use a1
+ * and a3 because those just happen to be the registers all our callers are
+ * using. We move a3 before calling the C function, but a1 happens to match.
+ * a1: index
+ * a3: size
+ */
+common_errArrayIndex:
+ EXPORT_PC()
+ move a0, a3
+ JAL(dvmThrowArrayIndexOutOfBoundsException)
+ b common_exceptionThrown
+
+/*
+ * Integer divide or mod by zero.
+ */
+common_errDivideByZero:
+ EXPORT_PC()
+ la a0, .LstrDivideByZero
+ JAL(dvmThrowArithmeticException)
+ b common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry: length in a1
+ */
+common_errNegativeArraySize:
+ EXPORT_PC()
+ move a0, a1 # arg0 <- len
+ JAL(dvmThrowNegativeArraySizeException) # (len)
+ b common_exceptionThrown
+
+/*
+ * Invocation of a non-existent method.
+ * On entry: method name in a1
+ */
+common_errNoSuchMethod:
+ EXPORT_PC()
+ move a0, a1
+ JAL(dvmThrowNoSuchMethodError)
+ b common_exceptionThrown
+
+/*
+ * We encountered a null object when we weren't expecting one. We
+ * export the PC, throw a NullPointerException, and goto the exception
+ * processing code.
+ */
+common_errNullObject:
+ EXPORT_PC()
+ li a0, 0
+ JAL(dvmThrowNullPointerException)
+ b common_exceptionThrown
+
+/*
+ * For debugging, cause an immediate fault. The source address will be in ra. Use a jal to jump here.
+ */
+common_abort:
+ lw zero,-4(zero) # generate SIGSEGV
+
+/*
+ * Spit out a "we were here", preserving all registers.
+ */
+ .macro SQUEAK num
+common_squeak\num:
+ STACK_STORE_RA();
+ la a0, .LstrSqueak
+ LOAD_IMM(a1, \num);
+ JAL(printf);
+ STACK_LOAD_RA();
+ RETURN;
+ .endm
+
+ SQUEAK 0
+ SQUEAK 1
+ SQUEAK 2
+ SQUEAK 3
+ SQUEAK 4
+ SQUEAK 5
+
+/*
+ * Spit out the number in a0, preserving registers.
+ */
+common_printNum:
+ STACK_STORE_RA()
+ MOVE_REG(a1, a0)
+ la a0, .LstrSqueak
+ JAL(printf)
+ STACK_LOAD_RA()
+ RETURN
+
+/*
+ * Print a newline, preserving registers.
+ */
+common_printNewline:
+ STACK_STORE_RA()
+ la a0, .LstrNewline
+ JAL(printf)
+ STACK_LOAD_RA()
+ RETURN
+
+ /*
+ * Print the 32-bit quantity in a0 as a hex value, preserving registers.
+ */
+common_printHex:
+ STACK_STORE_RA()
+ MOVE_REG(a1, a0)
+ la a0, .LstrPrintHex
+ JAL(printf)
+ STACK_LOAD_RA()
+RETURN;
+
+/*
+ * Print the 64-bit quantity in a0-a1, preserving registers.
+ */
+common_printLong:
+ STACK_STORE_RA()
+ MOVE_REG(a3, a1)
+ MOVE_REG(a2, a0)
+ la a0, .LstrPrintLong
+ JAL(printf)
+ STACK_LOAD_RA()
+ RETURN;
+
+/*
+ * Print full method info. Pass the Method* in a0. Preserves regs.
+ */
+common_printMethod:
+ STACK_STORE_RA()
+ JAL(dvmMterpPrintMethod)
+ STACK_LOAD_RA()
+ RETURN
+
+/*
+ * Call a C helper function that dumps regs and possibly some
+ * additional info. Requires the C function to be compiled in.
+ */
+ .if 0
+common_dumpRegs:
+ STACK_STORE_RA()
+ JAL(dvmMterpDumpMipsRegs)
+ STACK_LOAD_RA()
+ RETURN
+ .endif
+
+/*
+ * Zero-terminated ASCII string data.
+ */
+ .data
+
+.LstrBadEntryPoint:
+ .asciiz "Bad entry point %d\n"
+.LstrDivideByZero:
+ .asciiz "divide by zero"
+.LstrFilledNewArrayNotImpl:
+ .asciiz "filled-new-array only implemented for 'int'"
+.LstrLogTag:
+ .asciiz "mterp"
+.LstrExceptionNotCaughtLocally:
+ .asciiz "Exception %s from %s:%d not caught locally\n"
+
+.LstrNewline:
+ .asciiz "\n"
+.LstrSqueak:
+ .asciiz "<%d>"
+.LstrPrintHex:
+ .asciiz "<0x%x>"
+.LstrPrintLong:
+ .asciiz "<%lld>"
diff --git a/vm/mterp/mips/header.S b/vm/mterp/mips/header.S
new file mode 100644
index 0000000..0f03599
--- /dev/null
+++ b/vm/mterp/mips/header.S
@@ -0,0 +1,345 @@
+#include "../common/asm-constants.h"
+#include "../common/mips-defines.h"
+#include <asm/regdef.h>
+#include <asm/fpregdef.h>
+
+#ifdef __mips_hard_float
+#define HARD_FLOAT
+#else
+#define SOFT_FLOAT
+#endif
+
+#if (__mips==32) && (__mips_isa_rev>=2)
+#define MIPS32R2
+#endif
+
+/* MIPS definitions and declarations
+
+ reg nick purpose
+ s0 rPC interpreted program counter, used for fetching instructions
+ s1 rFP interpreted frame pointer, used for accessing locals and args
+ s2 rSELF self (Thread) pointer
+ s3 rIBASE interpreted instruction base pointer, used for computed goto
+ s4 rINST first 16-bit code unit of current instruction
+*/
+
+
+/* single-purpose registers, given names for clarity */
+#define rPC s0
+#define rFP s1
+#define rSELF s2
+#define rIBASE s3
+#define rINST s4
+#define rOBJ s5
+#define rBIX s6
+#define rTEMP s7
+
+/* The long arguments sent to function calls in Big-endian mode should be register
+swapped when sent to functions in little endian mode. In other words long variable
+sent as a0(MSW), a1(LSW) for a function call in LE mode should be sent as a1, a0 in
+Big Endian mode */
+
+#ifdef HAVE_LITTLE_ENDIAN
+#define rARG0 a0
+#define rARG1 a1
+#define rARG2 a2
+#define rARG3 a3
+#define rRESULT0 v0
+#define rRESULT1 v1
+#else
+#define rARG0 a1
+#define rARG1 a0
+#define rARG2 a3
+#define rARG3 a2
+#define rRESULT0 v1
+#define rRESULT1 v0
+#endif
+
+
+/* save/restore the PC and/or FP from the glue struct */
+#define LOAD_PC_FROM_SELF() lw rPC, offThread_pc(rSELF)
+#define SAVE_PC_TO_SELF() sw rPC, offThread_pc(rSELF)
+#define LOAD_FP_FROM_SELF() lw rFP, offThread_curFrame(rSELF)
+#define SAVE_FP_TO_SELF() sw rFP, offThread_curFrame(rSELF)
+#define LOAD_PC_FP_FROM_SELF() \
+ LOAD_PC_FROM_SELF(); \
+ LOAD_FP_FROM_SELF()
+#define SAVE_PC_FP_TO_SELF() \
+ SAVE_PC_TO_SELF(); \
+ SAVE_FP_TO_SELF()
+
+#define EXPORT_PC() \
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+
+#define SAVEAREA_FROM_FP(rd, _fpreg) \
+ subu rd, _fpreg, sizeofStackSaveArea
+
+#define FETCH_INST() lhu rINST, (rPC)
+
+#define FETCH_ADVANCE_INST(_count) lhu rINST, ((_count)*2)(rPC); \
+ addu rPC, rPC, ((_count) * 2)
+
+#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
+ lhu _dreg, ((_count)*2)(_sreg) ; \
+ addu _sreg, _sreg, (_count)*2
+
+#define FETCH_ADVANCE_INST_RB(rd) addu rPC, rPC, rd; \
+ lhu rINST, (rPC)
+
+#define FETCH(rd, _count) lhu rd, ((_count) * 2)(rPC)
+#define FETCH_S(rd, _count) lh rd, ((_count) * 2)(rPC)
+
+#ifdef HAVE_LITTLE_ENDIAN
+
+#define FETCH_B(rd, _count) lbu rd, ((_count) * 2)(rPC)
+#define FETCH_C(rd, _count) lbu rd, ((_count) * 2 + 1)(rPC)
+
+#else
+
+#define FETCH_B(rd, _count) lbu rd, ((_count) * 2 + 1)(rPC)
+#define FETCH_C(rd, _count) lbu rd, ((_count) * 2)(rPC)
+
+#endif
+
+#define GET_INST_OPCODE(rd) and rd, rINST, 0xFF
+
+/*
+ * Put the prefetched instruction's opcode field into the specified register.
+ */
+
+#define GET_PREFETCHED_OPCODE(dreg, sreg) andi dreg, sreg, 255
+
+#define GOTO_OPCODE(rd) sll rd, rd, ${handler_size_bits}; \
+ addu rd, rIBASE, rd; \
+ jr rd
+
+#define GOTO_OPCODE_BASE(_base, rd) sll rd, rd, ${handler_size_bits}; \
+ addu rd, _base, rd; \
+ jr rd
+
+#define GET_VREG(rd, rix) LOAD_eas2(rd, rFP, rix)
+
+#define GET_VREG_F(rd, rix) EAS2(AT, rFP, rix); \
+ .set noat; l.s rd, (AT); .set at
+
+#define SET_VREG(rd, rix) STORE_eas2(rd, rFP, rix)
+
+#define SET_VREG_GOTO(rd, rix, dst) .set noreorder; \
+ sll dst, dst, ${handler_size_bits}; \
+ addu dst, rIBASE, dst; \
+ sll t8, rix, 2; \
+ addu t8, t8, rFP; \
+ jr dst; \
+ sw rd, 0(t8); \
+ .set reorder
+
+#define SET_VREG_F(rd, rix) EAS2(AT, rFP, rix); \
+ .set noat; s.s rd, (AT); .set at
+
+
+#define GET_OPA(rd) srl rd, rINST, 8
+#ifndef MIPS32R2
+#define GET_OPA4(rd) GET_OPA(rd); and rd, 0xf
+#else
+#define GET_OPA4(rd) ext rd, rINST, 8, 4
+#endif
+#define GET_OPB(rd) srl rd, rINST, 12
+
+#define LOAD_rSELF_OFF(rd, off) lw rd, offThread_##off## (rSELF)
+
+#define LOAD_rSELF_method(rd) LOAD_rSELF_OFF(rd, method)
+#define LOAD_rSELF_methodClassDex(rd) LOAD_rSELF_OFF(rd, methodClassDex)
+#define LOAD_rSELF_interpStackEnd(rd) LOAD_rSELF_OFF(rd, interpStackEnd)
+#define LOAD_rSELF_retval(rd) LOAD_rSELF_OFF(rd, retval)
+#define LOAD_rSELF_pActiveProfilers(rd) LOAD_rSELF_OFF(rd, pActiveProfilers)
+#define LOAD_rSELF_bailPtr(rd) LOAD_rSELF_OFF(rd, bailPtr)
+#define LOAD_rSELF_SelfSuspendCount(rd) LOAD_rSELF_OFF(rd, SelfSuspendCount)
+
+
+/*
+ * Form an Effective Address rd = rbase + roff<<n;
+ * Uses reg AT
+ */
+#define EASN(rd, rbase, roff, rshift) .set noat; \
+ sll AT, roff, rshift; \
+ addu rd, rbase, AT; \
+ .set at
+
+#define EAS1(rd, rbase, roff) EASN(rd, rbase, roff, 1)
+#define EAS2(rd, rbase, roff) EASN(rd, rbase, roff, 2)
+#define EAS3(rd, rbase, roff) EASN(rd, rbase, roff, 3)
+#define EAS4(rd, rbase, roff) EASN(rd, rbase, roff, 4)
+
+/*
+ * Form an Effective Shift Right rd = rbase + roff>>n;
+ * Uses reg AT
+ */
+#define ESRN(rd, rbase, roff, rshift) .set noat; \
+ srl AT, roff, rshift; \
+ addu rd, rbase, AT; \
+ .set at
+
+#define LOAD_eas2(rd, rbase, roff) EAS2(AT, rbase, roff); \
+ .set noat; lw rd, 0(AT); .set at
+
+#define STORE_eas2(rd, rbase, roff) EAS2(AT, rbase, roff); \
+ .set noat; sw rd, 0(AT); .set at
+
+#define LOAD_RB_OFF(rd, rbase, off) lw rd, off(rbase)
+#define LOADu2_RB_OFF(rd, rbase, off) lhu rd, off(rbase)
+#define STORE_RB_OFF(rd, rbase, off) sw rd, off(rbase)
+
+#ifdef HAVE_LITTLE_ENDIAN
+
+#define STORE64_off(rlo, rhi, rbase, off) sw rlo, off(rbase); \
+ sw rhi, (off+4)(rbase)
+#define LOAD64_off(rlo, rhi, rbase, off) lw rlo, off(rbase); \
+ lw rhi, (off+4)(rbase)
+
+#define vSTORE64_off(rlo, rhi, rbase, off) sw rlo, off(rbase); \
+ sw rhi, (off+4)(rbase)
+#define vLOAD64_off(rlo, rhi, rbase, off) lw rlo, off(rbase); \
+ lw rhi, (off+4)(rbase)
+
+#define STORE64_off_F(rlo, rhi, rbase, off) s.s rlo, off(rbase); \
+ s.s rhi, (off+4)(rbase)
+#define LOAD64_off_F(rlo, rhi, rbase, off) l.s rlo, off(rbase); \
+ l.s rhi, (off+4)(rbase)
+#else
+
+#define STORE64_off(rlo, rhi, rbase, off) sw rlo, (off+4)(rbase); \
+ sw rhi, (off)(rbase)
+#define LOAD64_off(rlo, rhi, rbase, off) lw rlo, (off+4)(rbase); \
+ lw rhi, (off)(rbase)
+#define vSTORE64_off(rlo, rhi, rbase, off) sw rlo, (off+4)(rbase); \
+ sw rhi, (off)(rbase)
+#define vLOAD64_off(rlo, rhi, rbase, off) lw rlo, (off+4)(rbase); \
+ lw rhi, (off)(rbase)
+#define STORE64_off_F(rlo, rhi, rbase, off) s.s rlo, (off+4)(rbase); \
+ s.s rhi, (off)(rbase)
+#define LOAD64_off_F(rlo, rhi, rbase, off) l.s rlo, (off+4)(rbase); \
+ l.s rhi, (off)(rbase)
+#endif
+
+#define STORE64(rlo, rhi, rbase) STORE64_off(rlo, rhi, rbase, 0)
+#define LOAD64(rlo, rhi, rbase) LOAD64_off(rlo, rhi, rbase, 0)
+
+#define vSTORE64(rlo, rhi, rbase) vSTORE64_off(rlo, rhi, rbase, 0)
+#define vLOAD64(rlo, rhi, rbase) vLOAD64_off(rlo, rhi, rbase, 0)
+
+#define STORE64_F(rlo, rhi, rbase) STORE64_off_F(rlo, rhi, rbase, 0)
+#define LOAD64_F(rlo, rhi, rbase) LOAD64_off_F(rlo, rhi, rbase, 0)
+
+#define STORE64_lo(rd, rbase) sw rd, 0(rbase)
+#define STORE64_hi(rd, rbase) sw rd, 4(rbase)
+
+
+#define LOAD_offThread_exception(rd, rbase) LOAD_RB_OFF(rd, rbase, offThread_exception)
+#define LOAD_base_offArrayObject_length(rd, rbase) LOAD_RB_OFF(rd, rbase, offArrayObject_length)
+#define LOAD_base_offClassObject_accessFlags(rd, rbase) LOAD_RB_OFF(rd, rbase, offClassObject_accessFlags)
+#define LOAD_base_offClassObject_descriptor(rd, rbase) LOAD_RB_OFF(rd, rbase, offClassObject_descriptor)
+#define LOAD_base_offClassObject_super(rd, rbase) LOAD_RB_OFF(rd, rbase, offClassObject_super)
+
+#define LOAD_base_offClassObject_vtable(rd, rbase) LOAD_RB_OFF(rd, rbase, offClassObject_vtable)
+#define LOAD_base_offClassObject_vtableCount(rd, rbase) LOAD_RB_OFF(rd, rbase, offClassObject_vtableCount)
+#define LOAD_base_offDvmDex_pResClasses(rd, rbase) LOAD_RB_OFF(rd, rbase, offDvmDex_pResClasses)
+#define LOAD_base_offDvmDex_pResFields(rd, rbase) LOAD_RB_OFF(rd, rbase, offDvmDex_pResFields)
+
+#define LOAD_base_offDvmDex_pResMethods(rd, rbase) LOAD_RB_OFF(rd, rbase, offDvmDex_pResMethods)
+#define LOAD_base_offDvmDex_pResStrings(rd, rbase) LOAD_RB_OFF(rd, rbase, offDvmDex_pResStrings)
+#define LOAD_base_offInstField_byteOffset(rd, rbase) LOAD_RB_OFF(rd, rbase, offInstField_byteOffset)
+#define LOAD_base_offStaticField_value(rd, rbase) LOAD_RB_OFF(rd, rbase, offStaticField_value)
+#define LOAD_base_offMethod_clazz(rd, rbase) LOAD_RB_OFF(rd, rbase, offMethod_clazz)
+
+#define LOAD_base_offMethod_name(rd, rbase) LOAD_RB_OFF(rd, rbase, offMethod_name)
+#define LOAD_base_offObject_clazz(rd, rbase) LOAD_RB_OFF(rd, rbase, offObject_clazz)
+
+#define LOADu2_offMethod_methodIndex(rd, rbase) LOADu2_RB_OFF(rd, rbase, offMethod_methodIndex)
+
+
+#define STORE_offThread_exception(rd, rbase) STORE_RB_OFF(rd, rbase, offThread_exception)
+
+
+#define STACK_STORE(rd, off) sw rd, off(sp)
+#define STACK_LOAD(rd, off) lw rd, off(sp)
+#define CREATE_STACK(n) subu sp, sp, n
+#define DELETE_STACK(n) addu sp, sp, n
+
+#define SAVE_RA(offset) STACK_STORE(ra, offset)
+#define LOAD_RA(offset) STACK_LOAD(ra, offset)
+
+#define LOAD_ADDR(dest, addr) la dest, addr
+#define LOAD_IMM(dest, imm) li dest, imm
+#define MOVE_REG(dest, src) move dest, src
+#define RETURN jr ra
+#define STACK_SIZE 128
+
+#define STACK_OFFSET_ARG04 16
+#define STACK_OFFSET_ARG05 20
+#define STACK_OFFSET_ARG06 24
+#define STACK_OFFSET_ARG07 28
+#define STACK_OFFSET_SCR 32
+#define STACK_OFFSET_SCRMX 80
+#define STACK_OFFSET_GP 84
+#define STACK_OFFSET_rFP 112
+
+#define JAL(n) jal n
+#define BAL(n) bal n
+
+#define STACK_STORE_RA() CREATE_STACK(STACK_SIZE); \
+ STACK_STORE(gp, STACK_OFFSET_GP); \
+ STACK_STORE(ra, 124)
+
+#define STACK_STORE_S0() STACK_STORE_RA(); \
+ STACK_STORE(s0, 116)
+
+#define STACK_STORE_S0S1() STACK_STORE_S0(); \
+ STACK_STORE(s1, STACK_OFFSET_rFP)
+
+#define STACK_LOAD_RA() STACK_LOAD(ra, 124); \
+ STACK_LOAD(gp, STACK_OFFSET_GP); \
+ DELETE_STACK(STACK_SIZE)
+
+#define STACK_LOAD_S0() STACK_LOAD(s0, 116); \
+ STACK_LOAD_RA()
+
+#define STACK_LOAD_S0S1() STACK_LOAD(s1, STACK_OFFSET_rFP); \
+ STACK_LOAD_S0()
+
+#define STACK_STORE_FULL() CREATE_STACK(STACK_SIZE); \
+ STACK_STORE(ra, 124); \
+ STACK_STORE(fp, 120); \
+ STACK_STORE(s0, 116); \
+ STACK_STORE(s1, STACK_OFFSET_rFP); \
+ STACK_STORE(s2, 108); \
+ STACK_STORE(s3, 104); \
+ STACK_STORE(s4, 100); \
+ STACK_STORE(s5, 96); \
+ STACK_STORE(s6, 92); \
+ STACK_STORE(s7, 88);
+
+#define STACK_LOAD_FULL() STACK_LOAD(gp, STACK_OFFSET_GP); \
+ STACK_LOAD(s7, 88); \
+ STACK_LOAD(s6, 92); \
+ STACK_LOAD(s5, 96); \
+ STACK_LOAD(s4, 100); \
+ STACK_LOAD(s3, 104); \
+ STACK_LOAD(s2, 108); \
+ STACK_LOAD(s1, STACK_OFFSET_rFP); \
+ STACK_LOAD(s0, 116); \
+ STACK_LOAD(fp, 120); \
+ STACK_LOAD(ra, 124); \
+ DELETE_STACK(STACK_SIZE)
+
+/*
+ * first 8 words are reserved for function calls
+ * Maximum offset is STACK_OFFSET_SCRMX-STACK_OFFSET_SCR
+ */
+#define SCRATCH_STORE(r,off) \
+ STACK_STORE(r, STACK_OFFSET_SCR+off);
+#define SCRATCH_LOAD(r,off) \
+ STACK_LOAD(r, STACK_OFFSET_SCR+off);
+
+#if defined(WITH_JIT)
+#include "../common/jit-config.h"
+#endif
diff --git a/vm/mterp/mips/platform.S b/vm/mterp/mips/platform.S
new file mode 100644
index 0000000..ec1e3ee
--- /dev/null
+++ b/vm/mterp/mips/platform.S
@@ -0,0 +1,32 @@
+/*
+ * ===========================================================================
+ * CPU-version-specific defines
+ * ===========================================================================
+ */
+
+#if !defined(ANDROID_SMP)
+# error "Must define ANDROID_SMP"
+#endif
+
+/*
+ * Macro for data memory barrier.
+ */
+.macro SMP_DMB
+#if ANDROID_SMP != 0
+ sync
+#else
+ /* not SMP */
+#endif
+.endm
+
+/*
+ * Macro for data memory barrier (store/store variant).
+ */
+.macro SMP_DMB_ST
+#if ANDROID_SMP != 0
+ // FIXME: Is this really needed?
+ sync
+#else
+ /* not SMP */
+#endif
+.endm
diff --git a/vm/mterp/mips/stub.S b/vm/mterp/mips/stub.S
new file mode 100644
index 0000000..fad2238
--- /dev/null
+++ b/vm/mterp/mips/stub.S
@@ -0,0 +1,10 @@
+ /* (stub) */
+ SAVE_PC_TO_SELF() # only need to export PC and FP
+ SAVE_FP_TO_SELF()
+ move a0, rSELF # self is first arg to function
+ JAL(dvmMterp_${opcode}) # call
+ LOAD_PC_FROM_SELF() # retrieve updated values
+ LOAD_FP_FROM_SELF()
+ FETCH_INST() # load next instruction from rPC
+ GET_INST_OPCODE(t0) # ...trim down to just the opcode
+ GOTO_OPCODE(t0) # ...and jump to the handler
diff --git a/vm/mterp/mips/unflop.S b/vm/mterp/mips/unflop.S
new file mode 100644
index 0000000..9018bc9
--- /dev/null
+++ b/vm/mterp/mips/unflop.S
@@ -0,0 +1,32 @@
+%default {"preinstr":""}
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: int-to-float, float-to-int
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(rOBJ) # t0 <- A+
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, a3) # a0 <- vB
+#else
+ GET_VREG_F(fa0, a3)
+#endif
+ $preinstr # optional op
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+#ifdef SOFT_FLOAT
+ $instr # a0 <- op, a0-a3 changed
+
+.L${opcode}_set_vreg:
+ SET_VREG(v0, rOBJ) # vAA <- result0
+#else
+ $instr_f
+
+.L${opcode}_set_vreg_f:
+ SET_VREG_F(fv0, rOBJ)
+#endif
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ GOTO_OPCODE(t1) # jump to next instruction
+ /* 9-10 instructions */
diff --git a/vm/mterp/mips/unflopWide.S b/vm/mterp/mips/unflopWide.S
new file mode 100644
index 0000000..3411c2e
--- /dev/null
+++ b/vm/mterp/mips/unflopWide.S
@@ -0,0 +1,32 @@
+%default {"preinstr":"", "ld_arg":"LOAD64_F(fa0, fa0f, a3)", "st_result":"STORE64_F(fv0, fv0f, rOBJ)"}
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0/a1".
+ * This could be a MIPS instruction or a function call.
+ *
+ * long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ GET_OPA4(rOBJ) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # t1 <- &fp[A]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a3) # a0/a1 <- vAA
+#else
+ $ld_arg
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ $preinstr # optional op
+ $instr # a0/a1 <- op, a2-a3 changed
+
+.L${opcode}_set_vreg:
+#ifdef SOFT_FLOAT
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vAA <- a0/a1
+#else
+ $st_result # vAA <- a0/a1
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-13 instructions */
+
diff --git a/vm/mterp/mips/unflopWider.S b/vm/mterp/mips/unflopWider.S
new file mode 100644
index 0000000..f6d5718
--- /dev/null
+++ b/vm/mterp/mips/unflopWider.S
@@ -0,0 +1,33 @@
+%default {"preinstr":"", "st_result":"STORE64_F(fv0, fv0f, rOBJ)"}
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0", where
+ * "result" is a 64-bit quantity in a0/a1.
+ *
+ * For: int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, a3) # a0 <- vB
+#else
+ GET_VREG_F(fa0, a3)
+#endif
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ $preinstr # optional op
+#ifdef SOFT_FLOAT
+ $instr # result <- op, a0-a3 changed
+
+.L${opcode}_set_vreg:
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vA/vA+1 <- a0/a1
+#else
+ $instr_f
+
+.L${opcode}_set_vreg:
+ $st_result # vA/vA+1 <- a0/a1
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-11 instructions */
diff --git a/vm/mterp/mips/unop.S b/vm/mterp/mips/unop.S
new file mode 100644
index 0000000..52a8f0a
--- /dev/null
+++ b/vm/mterp/mips/unop.S
@@ -0,0 +1,19 @@
+%default {"preinstr":"", "result0":"a0"}
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(t0) # t0 <- A+
+ GET_VREG(a0, a3) # a0 <- vB
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ $preinstr # optional op
+ $instr # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ SET_VREG_GOTO($result0, t0, t1) # vAA <- result0
+ /* 9-10 instructions */
diff --git a/vm/mterp/mips/unopNarrower.S b/vm/mterp/mips/unopNarrower.S
new file mode 100644
index 0000000..85a94b7
--- /dev/null
+++ b/vm/mterp/mips/unopNarrower.S
@@ -0,0 +1,37 @@
+%default {"preinstr":"", "load":"LOAD64_F(fa0, fa0f, a3)"}
+ /*
+ * Generic 64bit-to-32bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0/a1", where
+ * "result" is a 32-bit quantity in a0.
+ *
+ * For: long-to-float, double-to-int, double-to-float
+ * If hard floating point support is available, use fa0 as the parameter, except for
+ * long-to-float opcode.
+ * (This would work for long-to-int, but that instruction is actually
+ * an exact match for OP_MOVE.)
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(rOBJ) # t1 <- A+
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a3) # a0/a1 <- vB/vB+1
+#else
+ $load
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ $preinstr # optional op
+#ifdef SOFT_FLOAT
+ $instr # a0 <- op, a0-a3 changed
+
+.L${opcode}_set_vreg:
+ SET_VREG(v0, rOBJ) # vA <- result0
+#else
+ $instr_f
+
+.L${opcode}_set_vreg_f:
+ SET_VREG_F(fv0, rOBJ) # vA <- result0
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-11 instructions */
diff --git a/vm/mterp/mips/unopWide.S b/vm/mterp/mips/unopWide.S
new file mode 100644
index 0000000..00e4e17
--- /dev/null
+++ b/vm/mterp/mips/unopWide.S
@@ -0,0 +1,22 @@
+%default {"preinstr":"", "result0":"a0", "result1":"a1"}
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0/a1".
+ * This could be MIPS instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ GET_OPA4(t1) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+ EAS2(rOBJ, rFP, t1) # rOBJ <- &fp[A]
+ LOAD64(a0, a1, a3) # a0/a1 <- vAA
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ $preinstr # optional op
+ $instr # a0/a1 <- op, a2-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64($result0, $result1, rOBJ) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-13 instructions */
+
diff --git a/vm/mterp/mips/unopWider.S b/vm/mterp/mips/unopWider.S
new file mode 100644
index 0000000..f601c11
--- /dev/null
+++ b/vm/mterp/mips/unopWider.S
@@ -0,0 +1,20 @@
+%default {"preinstr":"", "result0":"a0", "result1":"a1"}
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0", where
+ * "result" is a 64-bit quantity in a0/a1.
+ *
+ * For: int-to-long, int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ GET_OPA4(t1) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, a3) # a0 <- vB
+ EAS2(rOBJ, rFP, t1) # rOBJ <- &fp[A]
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ $preinstr # optional op
+ $instr # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64($result0, $result1, rOBJ) # vA/vA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-11 instructions */
diff --git a/vm/mterp/mips/unused.S b/vm/mterp/mips/unused.S
new file mode 100644
index 0000000..d91dafb
--- /dev/null
+++ b/vm/mterp/mips/unused.S
@@ -0,0 +1,2 @@
+ BAL(common_abort)
+
diff --git a/vm/mterp/mips/zcmp.S b/vm/mterp/mips/zcmp.S
new file mode 100644
index 0000000..aaac52d
--- /dev/null
+++ b/vm/mterp/mips/zcmp.S
@@ -0,0 +1,33 @@
+%verify "branch taken"
+%verify "branch not taken"
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ GET_OPA(a0) # a0 <- AA
+ GET_VREG(a2, a0) # a2 <- vAA
+ FETCH_S(a1, 1) # a1 <- branch offset, in code units
+ b${revcmp} a2, zero, 1f # branch to 1 if comparison failed
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a1, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a1, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh table base
+3:
+ bnez a0, common_updateProfile # test for JIT off at target
+#else
+ bgez a1, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rtable base
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
index 84b47a2..a7eeb50 100644
--- a/vm/mterp/out/InterpAsm-armv5te-vfp.S
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -319,12 +319,15 @@
.Lbad_arg:
ldr r0, strBadEntryPoint
+0: add r0, pc
@ r1 holds value of entryPoint
bl printf
bl dvmAbort
.fnend
.size dvmMterpStdRun, .-dvmMterpStdRun
+strBadEntryPoint:
+ .word PCREL_REF(.LstrBadEntryPoint,0b)
.global dvmMterpStdBail
.type dvmMterpStdBail, %function
@@ -347,12 +350,6 @@
ldmfd sp!, {r4-r10,fp,pc} @ restore 9 regs and return
-/*
- * String references.
- */
-strBadEntryPoint:
- .word .LstrBadEntryPoint
-
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
@@ -8059,6 +8056,7 @@
*/
.LOP_FILLED_NEW_ARRAY_notimpl:
ldr r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY
+3: add r0, pc
bl dvmThrowInternalError
b common_exceptionThrown
@@ -8068,7 +8066,7 @@
*/
.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY:
- .word .LstrFilledNewArrayNotImpl
+ .word PCREL_REF(.LstrFilledNewArrayNotImpl,3b)
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
@@ -8143,6 +8141,7 @@
*/
.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
ldr r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE
+3: add r0, pc
bl dvmThrowInternalError
b common_exceptionThrown
@@ -8152,7 +8151,7 @@
*/
.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE:
- .word .LstrFilledNewArrayNotImpl
+ .word PCREL_REF(.LstrFilledNewArrayNotImpl,3b)
/* continuation for OP_CMPL_FLOAT */
.LOP_CMPL_FLOAT_finish:
@@ -9531,6 +9530,7 @@
ldr r0, [rFP, ip, lsl #2] @ r0<- vC
0:
ldr rINST, .LOP_EXECUTE_INLINE_table @ table of InlineOperation
+5: add rINST, pc
ldr pc, [rINST, r10, lsl #4] @ sizeof=16, "func" is first entry
@ (not reached)
@@ -9566,7 +9566,7 @@
.LOP_EXECUTE_INLINE_table:
- .word gDvmInlineOpsTable
+ .word PCREL_REF(gDvmInlineOpsTable,5b)
/* continuation for OP_EXECUTE_INLINE_RANGE */
@@ -9591,6 +9591,7 @@
GET_VREG(r0, ip) @ r0<- vBase[0]
0:
ldr r9, .LOP_EXECUTE_INLINE_RANGE_table @ table of InlineOperation
+5: add r9, pc
ldr pc, [r9, r10, lsl #4] @ sizeof=16, "func" is first entry
@ (not reached)
@@ -9628,7 +9629,7 @@
.LOP_EXECUTE_INLINE_RANGE_table:
- .word gDvmInlineOpsTable
+ .word PCREL_REF(gDvmInlineOpsTable,5b)
/* continuation for OP_INVOKE_OBJECT_INIT_RANGE */
@@ -16298,8 +16299,8 @@
cmp lr, #0 @ any special SubModes active?
bne 11f @ go handle them if so
- mov lr, pc @ set return addr
- ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ blx ip
7:
@ native return; r10=newSaveArea
@@ -16325,8 +16326,8 @@
ldmfd sp, {r0-r3} @ refresh. NOTE: no sp autoincrement
@ Call the native method
- mov lr, pc @ set return addr
- ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ blx ip
@ Restore the pre-call arguments
ldmfd sp!, {r0-r3} @ r2<- methodToCall (others unneeded)
@@ -16573,7 +16574,9 @@
ldr r3, [r3, #offClassObject_descriptor]
@
ldr r2, strExceptionNotCaughtLocally
+0: add r2, pc
ldr r1, strLogTag
+1: add r1, pc
mov r0, #3 @ LOG_DEBUG
bl __android_log_print
#endif
@@ -16583,6 +16586,10 @@
bl dvmReleaseTrackedAlloc @ release the exception
b common_gotoBail @ bail out
+strExceptionNotCaughtLocally:
+ .word PCREL_REF(.LstrExceptionNotCaughtLocally,0b)
+strLogTag:
+ .word PCREL_REF(.LstrLogTag,1b)
/*
* Exception handling, calls through "glue code".
@@ -16650,9 +16657,13 @@
common_errDivideByZero:
EXPORT_PC()
ldr r0, strDivideByZero
+0: add r0, pc
bl dvmThrowArithmeticException
b common_exceptionThrown
+strDivideByZero:
+ .word PCREL_REF(.LstrDivideByZero,0b)
+
/*
* Attempt to allocate an array with a negative size.
* On entry: length in r1
@@ -16701,11 +16712,15 @@
.macro SQUEAK num
common_squeak\num:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
- ldr r0, strSqueak
+ ldr r0, strSqueak\num
+0: add r0, pc
mov r1, #\num
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+
+strSqueak\num:
+ .word PCREL_REF(.LstrSqueak,0b)
.endm
SQUEAK 0
@@ -16722,20 +16737,28 @@
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strSqueak
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strSqueak:
+ .word PCREL_REF(.LstrSqueak,0b)
+
/*
* Print a newline, preserving registers.
*/
common_printNewline:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
ldr r0, strNewline
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strNewline:
+ .word PCREL_REF(.LstrNewline,0b)
+
/*
* Print the 32-bit quantity in r0 as a hex value, preserving registers.
*/
@@ -16743,10 +16766,14 @@
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strPrintHex
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strPrintHex:
+ .word PCREL_REF(.LstrPrintHex,0b)
+
/*
* Print the 64-bit quantity in r0-r1, preserving registers.
*/
@@ -16755,10 +16782,14 @@
mov r3, r1
mov r2, r0
ldr r0, strPrintLong
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strPrintLong:
+ .word PCREL_REF(.LstrPrintLong,0b)
+
/*
* Print full method info. Pass the Method* in r0. Preserves regs.
*/
@@ -16813,25 +16844,6 @@
#endif
-/*
- * String references, must be close to the code that uses them.
- */
- .align 2
-strDivideByZero:
- .word .LstrDivideByZero
-strLogTag:
- .word .LstrLogTag
-strExceptionNotCaughtLocally:
- .word .LstrExceptionNotCaughtLocally
-
-strNewline:
- .word .LstrNewline
-strSqueak:
- .word .LstrSqueak
-strPrintHex:
- .word .LstrPrintHex
-strPrintLong:
- .word .LstrPrintLong
/*
* Zero-terminated ASCII string data.
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index 89c8133..c0f27b3 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -319,12 +319,15 @@
.Lbad_arg:
ldr r0, strBadEntryPoint
+0: add r0, pc
@ r1 holds value of entryPoint
bl printf
bl dvmAbort
.fnend
.size dvmMterpStdRun, .-dvmMterpStdRun
+strBadEntryPoint:
+ .word PCREL_REF(.LstrBadEntryPoint,0b)
.global dvmMterpStdBail
.type dvmMterpStdBail, %function
@@ -347,12 +350,6 @@
ldmfd sp!, {r4-r10,fp,pc} @ restore 9 regs and return
-/*
- * String references.
- */
-strBadEntryPoint:
- .word .LstrBadEntryPoint
-
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
@@ -8381,6 +8378,7 @@
*/
.LOP_FILLED_NEW_ARRAY_notimpl:
ldr r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY
+3: add r0, pc
bl dvmThrowInternalError
b common_exceptionThrown
@@ -8390,7 +8388,7 @@
*/
.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY:
- .word .LstrFilledNewArrayNotImpl
+ .word PCREL_REF(.LstrFilledNewArrayNotImpl,3b)
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
@@ -8465,6 +8463,7 @@
*/
.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
ldr r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE
+3: add r0, pc
bl dvmThrowInternalError
b common_exceptionThrown
@@ -8474,7 +8473,7 @@
*/
.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE:
- .word .LstrFilledNewArrayNotImpl
+ .word PCREL_REF(.LstrFilledNewArrayNotImpl,3b)
/* continuation for OP_CMPL_FLOAT */
@@ -9989,6 +9988,7 @@
ldr r0, [rFP, ip, lsl #2] @ r0<- vC
0:
ldr rINST, .LOP_EXECUTE_INLINE_table @ table of InlineOperation
+5: add rINST, pc
ldr pc, [rINST, r10, lsl #4] @ sizeof=16, "func" is first entry
@ (not reached)
@@ -10024,7 +10024,7 @@
.LOP_EXECUTE_INLINE_table:
- .word gDvmInlineOpsTable
+ .word PCREL_REF(gDvmInlineOpsTable,5b)
/* continuation for OP_EXECUTE_INLINE_RANGE */
@@ -10049,6 +10049,7 @@
GET_VREG(r0, ip) @ r0<- vBase[0]
0:
ldr r9, .LOP_EXECUTE_INLINE_RANGE_table @ table of InlineOperation
+5: add r9, pc
ldr pc, [r9, r10, lsl #4] @ sizeof=16, "func" is first entry
@ (not reached)
@@ -10086,7 +10087,7 @@
.LOP_EXECUTE_INLINE_RANGE_table:
- .word gDvmInlineOpsTable
+ .word PCREL_REF(gDvmInlineOpsTable,5b)
/* continuation for OP_INVOKE_OBJECT_INIT_RANGE */
@@ -16756,8 +16757,8 @@
cmp lr, #0 @ any special SubModes active?
bne 11f @ go handle them if so
- mov lr, pc @ set return addr
- ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ blx ip
7:
@ native return; r10=newSaveArea
@@ -16783,8 +16784,8 @@
ldmfd sp, {r0-r3} @ refresh. NOTE: no sp autoincrement
@ Call the native method
- mov lr, pc @ set return addr
- ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ blx ip
@ Restore the pre-call arguments
ldmfd sp!, {r0-r3} @ r2<- methodToCall (others unneeded)
@@ -17031,7 +17032,9 @@
ldr r3, [r3, #offClassObject_descriptor]
@
ldr r2, strExceptionNotCaughtLocally
+0: add r2, pc
ldr r1, strLogTag
+1: add r1, pc
mov r0, #3 @ LOG_DEBUG
bl __android_log_print
#endif
@@ -17041,6 +17044,10 @@
bl dvmReleaseTrackedAlloc @ release the exception
b common_gotoBail @ bail out
+strExceptionNotCaughtLocally:
+ .word PCREL_REF(.LstrExceptionNotCaughtLocally,0b)
+strLogTag:
+ .word PCREL_REF(.LstrLogTag,1b)
/*
* Exception handling, calls through "glue code".
@@ -17108,9 +17115,13 @@
common_errDivideByZero:
EXPORT_PC()
ldr r0, strDivideByZero
+0: add r0, pc
bl dvmThrowArithmeticException
b common_exceptionThrown
+strDivideByZero:
+ .word PCREL_REF(.LstrDivideByZero,0b)
+
/*
* Attempt to allocate an array with a negative size.
* On entry: length in r1
@@ -17159,11 +17170,15 @@
.macro SQUEAK num
common_squeak\num:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
- ldr r0, strSqueak
+ ldr r0, strSqueak\num
+0: add r0, pc
mov r1, #\num
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+
+strSqueak\num:
+ .word PCREL_REF(.LstrSqueak,0b)
.endm
SQUEAK 0
@@ -17180,20 +17195,28 @@
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strSqueak
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strSqueak:
+ .word PCREL_REF(.LstrSqueak,0b)
+
/*
* Print a newline, preserving registers.
*/
common_printNewline:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
ldr r0, strNewline
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strNewline:
+ .word PCREL_REF(.LstrNewline,0b)
+
/*
* Print the 32-bit quantity in r0 as a hex value, preserving registers.
*/
@@ -17201,10 +17224,14 @@
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strPrintHex
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strPrintHex:
+ .word PCREL_REF(.LstrPrintHex,0b)
+
/*
* Print the 64-bit quantity in r0-r1, preserving registers.
*/
@@ -17213,10 +17240,14 @@
mov r3, r1
mov r2, r0
ldr r0, strPrintLong
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strPrintLong:
+ .word PCREL_REF(.LstrPrintLong,0b)
+
/*
* Print full method info. Pass the Method* in r0. Preserves regs.
*/
@@ -17271,25 +17302,6 @@
#endif
-/*
- * String references, must be close to the code that uses them.
- */
- .align 2
-strDivideByZero:
- .word .LstrDivideByZero
-strLogTag:
- .word .LstrLogTag
-strExceptionNotCaughtLocally:
- .word .LstrExceptionNotCaughtLocally
-
-strNewline:
- .word .LstrNewline
-strSqueak:
- .word .LstrSqueak
-strPrintHex:
- .word .LstrPrintHex
-strPrintLong:
- .word .LstrPrintLong
/*
* Zero-terminated ASCII string data.
diff --git a/vm/mterp/out/InterpAsm-armv7-a-neon.S b/vm/mterp/out/InterpAsm-armv7-a-neon.S
index 2bed3ef..afa47db 100644
--- a/vm/mterp/out/InterpAsm-armv7-a-neon.S
+++ b/vm/mterp/out/InterpAsm-armv7-a-neon.S
@@ -333,12 +333,15 @@
.Lbad_arg:
ldr r0, strBadEntryPoint
+0: add r0, pc
@ r1 holds value of entryPoint
bl printf
bl dvmAbort
.fnend
.size dvmMterpStdRun, .-dvmMterpStdRun
+strBadEntryPoint:
+ .word PCREL_REF(.LstrBadEntryPoint,0b)
.global dvmMterpStdBail
.type dvmMterpStdBail, %function
@@ -361,12 +364,6 @@
ldmfd sp!, {r4-r10,fp,pc} @ restore 9 regs and return
-/*
- * String references.
- */
-strBadEntryPoint:
- .word .LstrBadEntryPoint
-
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
@@ -8013,6 +8010,7 @@
*/
.LOP_FILLED_NEW_ARRAY_notimpl:
ldr r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY
+3: add r0, pc
bl dvmThrowInternalError
b common_exceptionThrown
@@ -8022,7 +8020,7 @@
*/
.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY:
- .word .LstrFilledNewArrayNotImpl
+ .word PCREL_REF(.LstrFilledNewArrayNotImpl,3b)
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
@@ -8097,6 +8095,7 @@
*/
.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
ldr r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE
+3: add r0, pc
bl dvmThrowInternalError
b common_exceptionThrown
@@ -8106,7 +8105,7 @@
*/
.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE:
- .word .LstrFilledNewArrayNotImpl
+ .word PCREL_REF(.LstrFilledNewArrayNotImpl,3b)
/* continuation for OP_CMPL_FLOAT */
.LOP_CMPL_FLOAT_finish:
@@ -9468,6 +9467,7 @@
ldr r0, [rFP, ip, lsl #2] @ r0<- vC
0:
ldr rINST, .LOP_EXECUTE_INLINE_table @ table of InlineOperation
+5: add rINST, pc
ldr pc, [rINST, r10, lsl #4] @ sizeof=16, "func" is first entry
@ (not reached)
@@ -9503,7 +9503,7 @@
.LOP_EXECUTE_INLINE_table:
- .word gDvmInlineOpsTable
+ .word PCREL_REF(gDvmInlineOpsTable,5b)
/* continuation for OP_EXECUTE_INLINE_RANGE */
@@ -9528,6 +9528,7 @@
GET_VREG(r0, ip) @ r0<- vBase[0]
0:
ldr r9, .LOP_EXECUTE_INLINE_RANGE_table @ table of InlineOperation
+5: add r9, pc
ldr pc, [r9, r10, lsl #4] @ sizeof=16, "func" is first entry
@ (not reached)
@@ -9565,7 +9566,7 @@
.LOP_EXECUTE_INLINE_RANGE_table:
- .word gDvmInlineOpsTable
+ .word PCREL_REF(gDvmInlineOpsTable,5b)
/* continuation for OP_INVOKE_OBJECT_INIT_RANGE */
@@ -16235,8 +16236,8 @@
cmp lr, #0 @ any special SubModes active?
bne 11f @ go handle them if so
- mov lr, pc @ set return addr
- ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ blx ip
7:
@ native return; r10=newSaveArea
@@ -16262,8 +16263,8 @@
ldmfd sp, {r0-r3} @ refresh. NOTE: no sp autoincrement
@ Call the native method
- mov lr, pc @ set return addr
- ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ blx ip
@ Restore the pre-call arguments
ldmfd sp!, {r0-r3} @ r2<- methodToCall (others unneeded)
@@ -16510,7 +16511,9 @@
ldr r3, [r3, #offClassObject_descriptor]
@
ldr r2, strExceptionNotCaughtLocally
+0: add r2, pc
ldr r1, strLogTag
+1: add r1, pc
mov r0, #3 @ LOG_DEBUG
bl __android_log_print
#endif
@@ -16520,6 +16523,10 @@
bl dvmReleaseTrackedAlloc @ release the exception
b common_gotoBail @ bail out
+strExceptionNotCaughtLocally:
+ .word PCREL_REF(.LstrExceptionNotCaughtLocally,0b)
+strLogTag:
+ .word PCREL_REF(.LstrLogTag,1b)
/*
* Exception handling, calls through "glue code".
@@ -16587,9 +16594,13 @@
common_errDivideByZero:
EXPORT_PC()
ldr r0, strDivideByZero
+0: add r0, pc
bl dvmThrowArithmeticException
b common_exceptionThrown
+strDivideByZero:
+ .word PCREL_REF(.LstrDivideByZero,0b)
+
/*
* Attempt to allocate an array with a negative size.
* On entry: length in r1
@@ -16638,11 +16649,15 @@
.macro SQUEAK num
common_squeak\num:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
- ldr r0, strSqueak
+ ldr r0, strSqueak\num
+0: add r0, pc
mov r1, #\num
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+
+strSqueak\num:
+ .word PCREL_REF(.LstrSqueak,0b)
.endm
SQUEAK 0
@@ -16659,20 +16674,28 @@
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strSqueak
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strSqueak:
+ .word PCREL_REF(.LstrSqueak,0b)
+
/*
* Print a newline, preserving registers.
*/
common_printNewline:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
ldr r0, strNewline
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strNewline:
+ .word PCREL_REF(.LstrNewline,0b)
+
/*
* Print the 32-bit quantity in r0 as a hex value, preserving registers.
*/
@@ -16680,10 +16703,14 @@
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strPrintHex
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strPrintHex:
+ .word PCREL_REF(.LstrPrintHex,0b)
+
/*
* Print the 64-bit quantity in r0-r1, preserving registers.
*/
@@ -16692,10 +16719,14 @@
mov r3, r1
mov r2, r0
ldr r0, strPrintLong
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strPrintLong:
+ .word PCREL_REF(.LstrPrintLong,0b)
+
/*
* Print full method info. Pass the Method* in r0. Preserves regs.
*/
@@ -16750,25 +16781,6 @@
#endif
-/*
- * String references, must be close to the code that uses them.
- */
- .align 2
-strDivideByZero:
- .word .LstrDivideByZero
-strLogTag:
- .word .LstrLogTag
-strExceptionNotCaughtLocally:
- .word .LstrExceptionNotCaughtLocally
-
-strNewline:
- .word .LstrNewline
-strSqueak:
- .word .LstrSqueak
-strPrintHex:
- .word .LstrPrintHex
-strPrintLong:
- .word .LstrPrintLong
/*
* Zero-terminated ASCII string data.
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
index c9ebb1d..9ce376e 100644
--- a/vm/mterp/out/InterpAsm-armv7-a.S
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -333,12 +333,15 @@
.Lbad_arg:
ldr r0, strBadEntryPoint
+0: add r0, pc
@ r1 holds value of entryPoint
bl printf
bl dvmAbort
.fnend
.size dvmMterpStdRun, .-dvmMterpStdRun
+strBadEntryPoint:
+ .word PCREL_REF(.LstrBadEntryPoint,0b)
.global dvmMterpStdBail
.type dvmMterpStdBail, %function
@@ -361,12 +364,6 @@
ldmfd sp!, {r4-r10,fp,pc} @ restore 9 regs and return
-/*
- * String references.
- */
-strBadEntryPoint:
- .word .LstrBadEntryPoint
-
.global dvmAsmInstructionStart
.type dvmAsmInstructionStart, %function
@@ -8013,6 +8010,7 @@
*/
.LOP_FILLED_NEW_ARRAY_notimpl:
ldr r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY
+3: add r0, pc
bl dvmThrowInternalError
b common_exceptionThrown
@@ -8022,7 +8020,7 @@
*/
.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY:
- .word .LstrFilledNewArrayNotImpl
+ .word PCREL_REF(.LstrFilledNewArrayNotImpl,3b)
/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
@@ -8097,6 +8095,7 @@
*/
.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
ldr r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE
+3: add r0, pc
bl dvmThrowInternalError
b common_exceptionThrown
@@ -8106,7 +8105,7 @@
*/
.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE:
- .word .LstrFilledNewArrayNotImpl
+ .word PCREL_REF(.LstrFilledNewArrayNotImpl,3b)
/* continuation for OP_CMPL_FLOAT */
.LOP_CMPL_FLOAT_finish:
@@ -9468,6 +9467,7 @@
ldr r0, [rFP, ip, lsl #2] @ r0<- vC
0:
ldr rINST, .LOP_EXECUTE_INLINE_table @ table of InlineOperation
+5: add rINST, pc
ldr pc, [rINST, r10, lsl #4] @ sizeof=16, "func" is first entry
@ (not reached)
@@ -9503,7 +9503,7 @@
.LOP_EXECUTE_INLINE_table:
- .word gDvmInlineOpsTable
+ .word PCREL_REF(gDvmInlineOpsTable,5b)
/* continuation for OP_EXECUTE_INLINE_RANGE */
@@ -9528,6 +9528,7 @@
GET_VREG(r0, ip) @ r0<- vBase[0]
0:
ldr r9, .LOP_EXECUTE_INLINE_RANGE_table @ table of InlineOperation
+5: add r9, pc
ldr pc, [r9, r10, lsl #4] @ sizeof=16, "func" is first entry
@ (not reached)
@@ -9565,7 +9566,7 @@
.LOP_EXECUTE_INLINE_RANGE_table:
- .word gDvmInlineOpsTable
+ .word PCREL_REF(gDvmInlineOpsTable,5b)
/* continuation for OP_INVOKE_OBJECT_INIT_RANGE */
@@ -16235,8 +16236,8 @@
cmp lr, #0 @ any special SubModes active?
bne 11f @ go handle them if so
- mov lr, pc @ set return addr
- ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ blx ip
7:
@ native return; r10=newSaveArea
@@ -16262,8 +16263,8 @@
ldmfd sp, {r0-r3} @ refresh. NOTE: no sp autoincrement
@ Call the native method
- mov lr, pc @ set return addr
- ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ blx ip
@ Restore the pre-call arguments
ldmfd sp!, {r0-r3} @ r2<- methodToCall (others unneeded)
@@ -16510,7 +16511,9 @@
ldr r3, [r3, #offClassObject_descriptor]
@
ldr r2, strExceptionNotCaughtLocally
+0: add r2, pc
ldr r1, strLogTag
+1: add r1, pc
mov r0, #3 @ LOG_DEBUG
bl __android_log_print
#endif
@@ -16520,6 +16523,10 @@
bl dvmReleaseTrackedAlloc @ release the exception
b common_gotoBail @ bail out
+strExceptionNotCaughtLocally:
+ .word PCREL_REF(.LstrExceptionNotCaughtLocally,0b)
+strLogTag:
+ .word PCREL_REF(.LstrLogTag,1b)
/*
* Exception handling, calls through "glue code".
@@ -16587,9 +16594,13 @@
common_errDivideByZero:
EXPORT_PC()
ldr r0, strDivideByZero
+0: add r0, pc
bl dvmThrowArithmeticException
b common_exceptionThrown
+strDivideByZero:
+ .word PCREL_REF(.LstrDivideByZero,0b)
+
/*
* Attempt to allocate an array with a negative size.
* On entry: length in r1
@@ -16638,11 +16649,15 @@
.macro SQUEAK num
common_squeak\num:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
- ldr r0, strSqueak
+ ldr r0, strSqueak\num
+0: add r0, pc
mov r1, #\num
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+
+strSqueak\num:
+ .word PCREL_REF(.LstrSqueak,0b)
.endm
SQUEAK 0
@@ -16659,20 +16674,28 @@
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strSqueak
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strSqueak:
+ .word PCREL_REF(.LstrSqueak,0b)
+
/*
* Print a newline, preserving registers.
*/
common_printNewline:
stmfd sp!, {r0, r1, r2, r3, ip, lr}
ldr r0, strNewline
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strNewline:
+ .word PCREL_REF(.LstrNewline,0b)
+
/*
* Print the 32-bit quantity in r0 as a hex value, preserving registers.
*/
@@ -16680,10 +16703,14 @@
stmfd sp!, {r0, r1, r2, r3, ip, lr}
mov r1, r0
ldr r0, strPrintHex
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strPrintHex:
+ .word PCREL_REF(.LstrPrintHex,0b)
+
/*
* Print the 64-bit quantity in r0-r1, preserving registers.
*/
@@ -16692,10 +16719,14 @@
mov r3, r1
mov r2, r0
ldr r0, strPrintLong
+0: add r0, pc
bl printf
ldmfd sp!, {r0, r1, r2, r3, ip, lr}
bx lr
+strPrintLong:
+ .word PCREL_REF(.LstrPrintLong,0b)
+
/*
* Print full method info. Pass the Method* in r0. Preserves regs.
*/
@@ -16750,25 +16781,6 @@
#endif
-/*
- * String references, must be close to the code that uses them.
- */
- .align 2
-strDivideByZero:
- .word .LstrDivideByZero
-strLogTag:
- .word .LstrLogTag
-strExceptionNotCaughtLocally:
- .word .LstrExceptionNotCaughtLocally
-
-strNewline:
- .word .LstrNewline
-strSqueak:
- .word .LstrSqueak
-strPrintHex:
- .word .LstrPrintHex
-strPrintLong:
- .word .LstrPrintLong
/*
* Zero-terminated ASCII string data.
diff --git a/vm/mterp/out/InterpAsm-mips.S b/vm/mterp/out/InterpAsm-mips.S
new file mode 100644
index 0000000..98837fd
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-mips.S
@@ -0,0 +1,18622 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'mips'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: mips/header.S */
+#include "../common/asm-constants.h"
+#include "../common/mips-defines.h"
+#include <asm/regdef.h>
+#include <asm/fpregdef.h>
+
+#ifdef __mips_hard_float
+#define HARD_FLOAT
+#else
+#define SOFT_FLOAT
+#endif
+
+#if (__mips==32) && (__mips_isa_rev>=2)
+#define MIPS32R2
+#endif
+
+/* MIPS definitions and declarations
+
+ reg nick purpose
+ s0 rPC interpreted program counter, used for fetching instructions
+ s1 rFP interpreted frame pointer, used for accessing locals and args
+ s2 rSELF self (Thread) pointer
+ s3 rIBASE interpreted instruction base pointer, used for computed goto
+ s4 rINST first 16-bit code unit of current instruction
+*/
+
+
+/* single-purpose registers, given names for clarity */
+#define rPC s0
+#define rFP s1
+#define rSELF s2
+#define rIBASE s3
+#define rINST s4
+#define rOBJ s5
+#define rBIX s6
+#define rTEMP s7
+
+/* The long arguments sent to function calls in Big-endian mode should be register
+swapped when sent to functions in little endian mode. In other words long variable
+sent as a0(MSW), a1(LSW) for a function call in LE mode should be sent as a1, a0 in
+Big Endian mode */
+
+#ifdef HAVE_LITTLE_ENDIAN
+#define rARG0 a0
+#define rARG1 a1
+#define rARG2 a2
+#define rARG3 a3
+#define rRESULT0 v0
+#define rRESULT1 v1
+#else
+#define rARG0 a1
+#define rARG1 a0
+#define rARG2 a3
+#define rARG3 a2
+#define rRESULT0 v1
+#define rRESULT1 v0
+#endif
+
+
+/* save/restore the PC and/or FP from the glue struct */
+#define LOAD_PC_FROM_SELF() lw rPC, offThread_pc(rSELF)
+#define SAVE_PC_TO_SELF() sw rPC, offThread_pc(rSELF)
+#define LOAD_FP_FROM_SELF() lw rFP, offThread_curFrame(rSELF)
+#define SAVE_FP_TO_SELF() sw rFP, offThread_curFrame(rSELF)
+#define LOAD_PC_FP_FROM_SELF() \
+ LOAD_PC_FROM_SELF(); \
+ LOAD_FP_FROM_SELF()
+#define SAVE_PC_FP_TO_SELF() \
+ SAVE_PC_TO_SELF(); \
+ SAVE_FP_TO_SELF()
+
+#define EXPORT_PC() \
+ sw rPC, (offStackSaveArea_currentPc - sizeofStackSaveArea)(rFP)
+
+#define SAVEAREA_FROM_FP(rd, _fpreg) \
+ subu rd, _fpreg, sizeofStackSaveArea
+
+#define FETCH_INST() lhu rINST, (rPC)
+
+#define FETCH_ADVANCE_INST(_count) lhu rINST, ((_count)*2)(rPC); \
+ addu rPC, rPC, ((_count) * 2)
+
+#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
+ lhu _dreg, ((_count)*2)(_sreg) ; \
+ addu _sreg, _sreg, (_count)*2
+
+#define FETCH_ADVANCE_INST_RB(rd) addu rPC, rPC, rd; \
+ lhu rINST, (rPC)
+
+#define FETCH(rd, _count) lhu rd, ((_count) * 2)(rPC)
+#define FETCH_S(rd, _count) lh rd, ((_count) * 2)(rPC)
+
+#ifdef HAVE_LITTLE_ENDIAN
+
+#define FETCH_B(rd, _count) lbu rd, ((_count) * 2)(rPC)
+#define FETCH_C(rd, _count) lbu rd, ((_count) * 2 + 1)(rPC)
+
+#else
+
+#define FETCH_B(rd, _count) lbu rd, ((_count) * 2 + 1)(rPC)
+#define FETCH_C(rd, _count) lbu rd, ((_count) * 2)(rPC)
+
+#endif
+
+#define GET_INST_OPCODE(rd) and rd, rINST, 0xFF
+
+/*
+ * Put the prefetched instruction's opcode field into the specified register.
+ */
+
+#define GET_PREFETCHED_OPCODE(dreg, sreg) andi dreg, sreg, 255
+
+#define GOTO_OPCODE(rd) sll rd, rd, 7; \
+ addu rd, rIBASE, rd; \
+ jr rd
+
+#define GOTO_OPCODE_BASE(_base, rd) sll rd, rd, 7; \
+ addu rd, _base, rd; \
+ jr rd
+
+#define GET_VREG(rd, rix) LOAD_eas2(rd, rFP, rix)
+
+#define GET_VREG_F(rd, rix) EAS2(AT, rFP, rix); \
+ .set noat; l.s rd, (AT); .set at
+
+#define SET_VREG(rd, rix) STORE_eas2(rd, rFP, rix)
+
+#define SET_VREG_GOTO(rd, rix, dst) .set noreorder; \
+ sll dst, dst, 7; \
+ addu dst, rIBASE, dst; \
+ sll t8, rix, 2; \
+ addu t8, t8, rFP; \
+ jr dst; \
+ sw rd, 0(t8); \
+ .set reorder
+
+#define SET_VREG_F(rd, rix) EAS2(AT, rFP, rix); \
+ .set noat; s.s rd, (AT); .set at
+
+
+#define GET_OPA(rd) srl rd, rINST, 8
+#ifndef MIPS32R2
+#define GET_OPA4(rd) GET_OPA(rd); and rd, 0xf
+#else
+#define GET_OPA4(rd) ext rd, rINST, 8, 4
+#endif
+#define GET_OPB(rd) srl rd, rINST, 12
+
+#define LOAD_rSELF_OFF(rd, off) lw rd, offThread_##off## (rSELF)
+
+#define LOAD_rSELF_method(rd) LOAD_rSELF_OFF(rd, method)
+#define LOAD_rSELF_methodClassDex(rd) LOAD_rSELF_OFF(rd, methodClassDex)
+#define LOAD_rSELF_interpStackEnd(rd) LOAD_rSELF_OFF(rd, interpStackEnd)
+#define LOAD_rSELF_retval(rd) LOAD_rSELF_OFF(rd, retval)
+#define LOAD_rSELF_pActiveProfilers(rd) LOAD_rSELF_OFF(rd, pActiveProfilers)
+#define LOAD_rSELF_bailPtr(rd) LOAD_rSELF_OFF(rd, bailPtr)
+#define LOAD_rSELF_SelfSuspendCount(rd) LOAD_rSELF_OFF(rd, SelfSuspendCount)
+
+
+/*
+ * Form an Effective Address rd = rbase + roff<<n;
+ * Uses reg AT
+ */
+#define EASN(rd, rbase, roff, rshift) .set noat; \
+ sll AT, roff, rshift; \
+ addu rd, rbase, AT; \
+ .set at
+
+#define EAS1(rd, rbase, roff) EASN(rd, rbase, roff, 1)
+#define EAS2(rd, rbase, roff) EASN(rd, rbase, roff, 2)
+#define EAS3(rd, rbase, roff) EASN(rd, rbase, roff, 3)
+#define EAS4(rd, rbase, roff) EASN(rd, rbase, roff, 4)
+
+/*
+ * Form an Effective Shift Right rd = rbase + roff>>n;
+ * Uses reg AT
+ */
+#define ESRN(rd, rbase, roff, rshift) .set noat; \
+ srl AT, roff, rshift; \
+ addu rd, rbase, AT; \
+ .set at
+
+#define LOAD_eas2(rd, rbase, roff) EAS2(AT, rbase, roff); \
+ .set noat; lw rd, 0(AT); .set at
+
+#define STORE_eas2(rd, rbase, roff) EAS2(AT, rbase, roff); \
+ .set noat; sw rd, 0(AT); .set at
+
+#define LOAD_RB_OFF(rd, rbase, off) lw rd, off(rbase)
+#define LOADu2_RB_OFF(rd, rbase, off) lhu rd, off(rbase)
+#define STORE_RB_OFF(rd, rbase, off) sw rd, off(rbase)
+
+#ifdef HAVE_LITTLE_ENDIAN
+
+#define STORE64_off(rlo, rhi, rbase, off) sw rlo, off(rbase); \
+ sw rhi, (off+4)(rbase)
+#define LOAD64_off(rlo, rhi, rbase, off) lw rlo, off(rbase); \
+ lw rhi, (off+4)(rbase)
+
+#define vSTORE64_off(rlo, rhi, rbase, off) sw rlo, off(rbase); \
+ sw rhi, (off+4)(rbase)
+#define vLOAD64_off(rlo, rhi, rbase, off) lw rlo, off(rbase); \
+ lw rhi, (off+4)(rbase)
+
+#define STORE64_off_F(rlo, rhi, rbase, off) s.s rlo, off(rbase); \
+ s.s rhi, (off+4)(rbase)
+#define LOAD64_off_F(rlo, rhi, rbase, off) l.s rlo, off(rbase); \
+ l.s rhi, (off+4)(rbase)
+#else
+
+#define STORE64_off(rlo, rhi, rbase, off) sw rlo, (off+4)(rbase); \
+ sw rhi, (off)(rbase)
+#define LOAD64_off(rlo, rhi, rbase, off) lw rlo, (off+4)(rbase); \
+ lw rhi, (off)(rbase)
+#define vSTORE64_off(rlo, rhi, rbase, off) sw rlo, (off+4)(rbase); \
+ sw rhi, (off)(rbase)
+#define vLOAD64_off(rlo, rhi, rbase, off) lw rlo, (off+4)(rbase); \
+ lw rhi, (off)(rbase)
+#define STORE64_off_F(rlo, rhi, rbase, off) s.s rlo, (off+4)(rbase); \
+ s.s rhi, (off)(rbase)
+#define LOAD64_off_F(rlo, rhi, rbase, off) l.s rlo, (off+4)(rbase); \
+ l.s rhi, (off)(rbase)
+#endif
+
+#define STORE64(rlo, rhi, rbase) STORE64_off(rlo, rhi, rbase, 0)
+#define LOAD64(rlo, rhi, rbase) LOAD64_off(rlo, rhi, rbase, 0)
+
+#define vSTORE64(rlo, rhi, rbase) vSTORE64_off(rlo, rhi, rbase, 0)
+#define vLOAD64(rlo, rhi, rbase) vLOAD64_off(rlo, rhi, rbase, 0)
+
+#define STORE64_F(rlo, rhi, rbase) STORE64_off_F(rlo, rhi, rbase, 0)
+#define LOAD64_F(rlo, rhi, rbase) LOAD64_off_F(rlo, rhi, rbase, 0)
+
+#define STORE64_lo(rd, rbase) sw rd, 0(rbase)
+#define STORE64_hi(rd, rbase) sw rd, 4(rbase)
+
+
+#define LOAD_offThread_exception(rd, rbase) LOAD_RB_OFF(rd, rbase, offThread_exception)
+#define LOAD_base_offArrayObject_length(rd, rbase) LOAD_RB_OFF(rd, rbase, offArrayObject_length)
+#define LOAD_base_offClassObject_accessFlags(rd, rbase) LOAD_RB_OFF(rd, rbase, offClassObject_accessFlags)
+#define LOAD_base_offClassObject_descriptor(rd, rbase) LOAD_RB_OFF(rd, rbase, offClassObject_descriptor)
+#define LOAD_base_offClassObject_super(rd, rbase) LOAD_RB_OFF(rd, rbase, offClassObject_super)
+
+#define LOAD_base_offClassObject_vtable(rd, rbase) LOAD_RB_OFF(rd, rbase, offClassObject_vtable)
+#define LOAD_base_offClassObject_vtableCount(rd, rbase) LOAD_RB_OFF(rd, rbase, offClassObject_vtableCount)
+#define LOAD_base_offDvmDex_pResClasses(rd, rbase) LOAD_RB_OFF(rd, rbase, offDvmDex_pResClasses)
+#define LOAD_base_offDvmDex_pResFields(rd, rbase) LOAD_RB_OFF(rd, rbase, offDvmDex_pResFields)
+
+#define LOAD_base_offDvmDex_pResMethods(rd, rbase) LOAD_RB_OFF(rd, rbase, offDvmDex_pResMethods)
+#define LOAD_base_offDvmDex_pResStrings(rd, rbase) LOAD_RB_OFF(rd, rbase, offDvmDex_pResStrings)
+#define LOAD_base_offInstField_byteOffset(rd, rbase) LOAD_RB_OFF(rd, rbase, offInstField_byteOffset)
+#define LOAD_base_offStaticField_value(rd, rbase) LOAD_RB_OFF(rd, rbase, offStaticField_value)
+#define LOAD_base_offMethod_clazz(rd, rbase) LOAD_RB_OFF(rd, rbase, offMethod_clazz)
+
+#define LOAD_base_offMethod_name(rd, rbase) LOAD_RB_OFF(rd, rbase, offMethod_name)
+#define LOAD_base_offObject_clazz(rd, rbase) LOAD_RB_OFF(rd, rbase, offObject_clazz)
+
+#define LOADu2_offMethod_methodIndex(rd, rbase) LOADu2_RB_OFF(rd, rbase, offMethod_methodIndex)
+
+
+#define STORE_offThread_exception(rd, rbase) STORE_RB_OFF(rd, rbase, offThread_exception)
+
+
+#define STACK_STORE(rd, off) sw rd, off(sp)
+#define STACK_LOAD(rd, off) lw rd, off(sp)
+#define CREATE_STACK(n) subu sp, sp, n
+#define DELETE_STACK(n) addu sp, sp, n
+
+#define SAVE_RA(offset) STACK_STORE(ra, offset)
+#define LOAD_RA(offset) STACK_LOAD(ra, offset)
+
+#define LOAD_ADDR(dest, addr) la dest, addr
+#define LOAD_IMM(dest, imm) li dest, imm
+#define MOVE_REG(dest, src) move dest, src
+#define RETURN jr ra
+#define STACK_SIZE 128
+
+#define STACK_OFFSET_ARG04 16
+#define STACK_OFFSET_ARG05 20
+#define STACK_OFFSET_ARG06 24
+#define STACK_OFFSET_ARG07 28
+#define STACK_OFFSET_SCR 32
+#define STACK_OFFSET_SCRMX 80
+#define STACK_OFFSET_GP 84
+#define STACK_OFFSET_rFP 112
+
+#define JAL(n) jal n
+#define BAL(n) bal n
+
+#define STACK_STORE_RA() CREATE_STACK(STACK_SIZE); \
+ STACK_STORE(gp, STACK_OFFSET_GP); \
+ STACK_STORE(ra, 124)
+
+#define STACK_STORE_S0() STACK_STORE_RA(); \
+ STACK_STORE(s0, 116)
+
+#define STACK_STORE_S0S1() STACK_STORE_S0(); \
+ STACK_STORE(s1, STACK_OFFSET_rFP)
+
+#define STACK_LOAD_RA() STACK_LOAD(ra, 124); \
+ STACK_LOAD(gp, STACK_OFFSET_GP); \
+ DELETE_STACK(STACK_SIZE)
+
+#define STACK_LOAD_S0() STACK_LOAD(s0, 116); \
+ STACK_LOAD_RA()
+
+#define STACK_LOAD_S0S1() STACK_LOAD(s1, STACK_OFFSET_rFP); \
+ STACK_LOAD_S0()
+
+#define STACK_STORE_FULL() CREATE_STACK(STACK_SIZE); \
+ STACK_STORE(ra, 124); \
+ STACK_STORE(fp, 120); \
+ STACK_STORE(s0, 116); \
+ STACK_STORE(s1, STACK_OFFSET_rFP); \
+ STACK_STORE(s2, 108); \
+ STACK_STORE(s3, 104); \
+ STACK_STORE(s4, 100); \
+ STACK_STORE(s5, 96); \
+ STACK_STORE(s6, 92); \
+ STACK_STORE(s7, 88);
+
+#define STACK_LOAD_FULL() STACK_LOAD(gp, STACK_OFFSET_GP); \
+ STACK_LOAD(s7, 88); \
+ STACK_LOAD(s6, 92); \
+ STACK_LOAD(s5, 96); \
+ STACK_LOAD(s4, 100); \
+ STACK_LOAD(s3, 104); \
+ STACK_LOAD(s2, 108); \
+ STACK_LOAD(s1, STACK_OFFSET_rFP); \
+ STACK_LOAD(s0, 116); \
+ STACK_LOAD(fp, 120); \
+ STACK_LOAD(ra, 124); \
+ DELETE_STACK(STACK_SIZE)
+
+/*
+ * first 8 words are reserved for function calls
+ * Maximum offset is STACK_OFFSET_SCRMX-STACK_OFFSET_SCR
+ */
+#define SCRATCH_STORE(r,off) \
+ STACK_STORE(r, STACK_OFFSET_SCR+off);
+#define SCRATCH_LOAD(r,off) \
+ STACK_LOAD(r, STACK_OFFSET_SCR+off);
+
+#if defined(WITH_JIT)
+#include "../common/jit-config.h"
+#endif
+
+/* File: mips/platform.S */
+/*
+ * ===========================================================================
+ * CPU-version-specific defines
+ * ===========================================================================
+ */
+
+#if !defined(ANDROID_SMP)
+# error "Must define ANDROID_SMP"
+#endif
+
+/*
+ * Macro for data memory barrier.
+ */
+.macro SMP_DMB
+#if ANDROID_SMP != 0
+ sync
+#else
+ /* not SMP */
+#endif
+.endm
+
+/*
+ * Macro for data memory barrier (store/store variant).
+ */
+.macro SMP_DMB_ST
+#if ANDROID_SMP != 0
+ // FIXME: Is this really needed?
+ sync
+#else
+ /* not SMP */
+#endif
+.endm
+
+/* File: mips/entry.S */
+
+/*
+ * 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.
+ */
+/*
+ * Interpreter entry point.
+ */
+
+#define ASSIST_DEBUGGER 1
+
+ .text
+ .align 2
+ .global dvmMterpStdRun
+ .ent dvmMterpStdRun
+ .frame sp, STACK_SIZE, ra
+/*
+ * On entry:
+ * r0 Thread* self
+ *
+ * The return comes via a call to dvmMterpStdBail().
+ */
+
+dvmMterpStdRun:
+ .set noreorder
+ .cpload t9
+ .set reorder
+/* Save to the stack. Frame size = STACK_SIZE */
+ STACK_STORE_FULL()
+/* This directive will make sure all subsequent jal restore gp at a known offset */
+ .cprestore STACK_OFFSET_GP
+
+ addu fp, sp, STACK_SIZE # Move Frame Pointer to the base of frame
+ /* save stack pointer, add magic word for debuggerd */
+ sw sp, offThread_bailPtr(a0) # Save SP
+
+ /* set up "named" registers, figure out entry point */
+ move rSELF, a0 # set rSELF
+ LOAD_PC_FROM_SELF()
+ LOAD_FP_FROM_SELF()
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+
+#if defined(WITH_JIT)
+.LentryInstr:
+ /* Entry is always a possible trace start */
+ lw a0, offThread_pJitProfTable(rSELF)
+ FETCH_INST() # load rINST from rPC
+ sw zero, offThread_inJitCodeCache(rSELF)
+#if !defined(WITH_SELF_VERIFICATION)
+ bnez a0, common_updateProfile # profiling is enabled
+#else
+ lw a2, offThread_shadowSpace(rSELF) # to find out the jit exit state
+ beqz a0, 1f # profiling is disabled
+ lw a3, offShadowSpace_jitExitState(a2) # jit exit state
+ li t0, kSVSTraceSelect
+ bne a3, t0, 2f
+ li a2, kJitTSelectRequestHot # ask for trace selection
+ b common_selectTrace # go build the trace
+2:
+ li a4, kSVSNoProfile
+ beq a3, a4, 1f # don't profile the next instruction?
+ b common_updateProfile # collect profiles
+#endif
+1:
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+#else
+ /* start executing the instruction at rPC */
+ FETCH_INST() # load rINST from rPC
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+#endif
+
+.Lbad_arg:
+ la a0, .LstrBadEntryPoint
+ #a1 holds value of entryPoint
+ JAL(printf)
+ JAL(dvmAbort)
+
+ .end dvmMterpStdRun
+
+ .global dvmMterpStdBail
+ .ent dvmMterpStdBail
+
+/* Restore the stack pointer and all the registers stored at sp from the save
+ * point established on entry. Return to whoever called dvmMterpStdRun.
+ *
+ * On entry:
+ * a0 Thread* self
+ */
+dvmMterpStdBail:
+ lw sp, offThread_bailPtr(a0) # Restore sp
+ STACK_LOAD_FULL()
+ jr ra
+
+ .end dvmMterpStdBail
+
+
+ .global dvmAsmInstructionStart
+ .type dvmAsmInstructionStart, %function
+dvmAsmInstructionStart = .L_OP_NOP
+ .text
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_NOP: /* 0x00 */
+/* File: mips/OP_NOP.S */
+ FETCH_ADVANCE_INST(1) # advance to next instr, load rINST
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0) # execute it
+
+#ifdef ASSIST_DEBUGGER
+ /* insert fake function header to help gdb find the stack frame */
+ .type dalvik_inst, @function
+dalvik_inst:
+ .ent dalvik_inst
+ .end dalvik_inst
+#endif
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE: /* 0x01 */
+/* File: mips/OP_MOVE.S */
+ /* for move, move-object, long-to-int */
+ /* op vA, vB */
+ GET_OPB(a1) # a1 <- B from 15:12
+ GET_OPA4(a0) # a0 <- A from 11:8
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ GET_VREG(a2, a1) # a2 <- fp[B]
+ GET_INST_OPCODE(t0) # t0 <- opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[A] <- a2
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_FROM16: /* 0x02 */
+/* File: mips/OP_MOVE_FROM16.S */
+ /* for: move/from16, move-object/from16 */
+ /* op vAA, vBBBB */
+ FETCH(a1, 1) # a1 <- BBBB
+ GET_OPA(a0) # a0 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a2, a1) # a2 <- fp[BBBB]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[AA] <- a2
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_16: /* 0x03 */
+/* File: mips/OP_MOVE_16.S */
+ /* for: move/16, move-object/16 */
+ /* op vAAAA, vBBBB */
+ FETCH(a1, 2) # a1 <- BBBB
+ FETCH(a0, 1) # a0 <- AAAA
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_VREG(a2, a1) # a2 <- fp[BBBB]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[AAAA] <- a2 and jump
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_WIDE: /* 0x04 */
+/* File: mips/OP_MOVE_WIDE.S */
+ /* move-wide vA, vB */
+ /* NOTE: regs can overlap, e.g. "move v6, v7" or "move v7, v6" */
+ GET_OPA4(a2) # a2 <- A(+)
+ GET_OPB(a3) # a3 <- B
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+ EAS2(a2, rFP, a2) # a2 <- &fp[A]
+ LOAD64(a0, a1, a3) # a0/a1 <- fp[B]
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a2) # fp[A] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: mips/OP_MOVE_WIDE_FROM16.S */
+ /* move-wide/from16 vAA, vBBBB */
+ /* NOTE: regs can overlap, e.g. "move v6, v7" or "move v7, v6" */
+ FETCH(a3, 1) # a3 <- BBBB
+ GET_OPA(a2) # a2 <- AA
+ EAS2(a3, rFP, a3) # a3 <- &fp[BBBB]
+ EAS2(a2, rFP, a2) # a2 <- &fp[AA]
+ LOAD64(a0, a1, a3) # a0/a1 <- fp[BBBB]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a2) # fp[AA] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: mips/OP_MOVE_WIDE_16.S */
+ /* move-wide/16 vAAAA, vBBBB */
+ /* NOTE: regs can overlap, e.g. "move v6, v7" or "move v7, v6" */
+ FETCH(a3, 2) # a3 <- BBBB
+ FETCH(a2, 1) # a2 <- AAAA
+ EAS2(a3, rFP, a3) # a3 <- &fp[BBBB]
+ EAS2(a2, rFP, a2) # a2 <- &fp[AAAA]
+ LOAD64(a0, a1, a3) # a0/a1 <- fp[BBBB]
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a2) # fp[AAAA] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_OBJECT: /* 0x07 */
+/* File: mips/OP_MOVE_OBJECT.S */
+/* File: mips/OP_MOVE.S */
+ /* for move, move-object, long-to-int */
+ /* op vA, vB */
+ GET_OPB(a1) # a1 <- B from 15:12
+ GET_OPA4(a0) # a0 <- A from 11:8
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ GET_VREG(a2, a1) # a2 <- fp[B]
+ GET_INST_OPCODE(t0) # t0 <- opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[A] <- a2
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: mips/OP_MOVE_OBJECT_FROM16.S */
+/* File: mips/OP_MOVE_FROM16.S */
+ /* for: move/from16, move-object/from16 */
+ /* op vAA, vBBBB */
+ FETCH(a1, 1) # a1 <- BBBB
+ GET_OPA(a0) # a0 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a2, a1) # a2 <- fp[BBBB]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[AA] <- a2
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: mips/OP_MOVE_OBJECT_16.S */
+/* File: mips/OP_MOVE_16.S */
+ /* for: move/16, move-object/16 */
+ /* op vAAAA, vBBBB */
+ FETCH(a1, 2) # a1 <- BBBB
+ FETCH(a0, 1) # a0 <- AAAA
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_VREG(a2, a1) # a2 <- fp[BBBB]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[AAAA] <- a2 and jump
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_RESULT: /* 0x0a */
+/* File: mips/OP_MOVE_RESULT.S */
+ /* for: move-result, move-result-object */
+ /* op vAA */
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ LOAD_rSELF_retval(a0) # a0 <- self->retval.i
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, a2, t0) # fp[AA] <- a0
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: mips/OP_MOVE_RESULT_WIDE.S */
+ /* move-result-wide vAA */
+ GET_OPA(a2) # a2 <- AA
+ addu a3, rSELF, offThread_retval # a3 <- &self->retval
+ EAS2(a2, rFP, a2) # a2 <- &fp[AA]
+ LOAD64(a0, a1, a3) # a0/a1 <- retval.j
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a2) # fp[AA] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: mips/OP_MOVE_RESULT_OBJECT.S */
+/* File: mips/OP_MOVE_RESULT.S */
+ /* for: move-result, move-result-object */
+ /* op vAA */
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ LOAD_rSELF_retval(a0) # a0 <- self->retval.i
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, a2, t0) # fp[AA] <- a0
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: mips/OP_MOVE_EXCEPTION.S */
+ /* move-exception vAA */
+ GET_OPA(a2) # a2 <- AA
+ LOAD_offThread_exception(a3, rSELF) # a3 <- dvmGetException bypass
+ li a1, 0 # a1 <- 0
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ SET_VREG(a3, a2) # fp[AA] <- exception obj
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE_offThread_exception(a1, rSELF) # dvmClearException bypass
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_RETURN_VOID: /* 0x0e */
+/* File: mips/OP_RETURN_VOID.S */
+ b common_returnFromMethod
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_RETURN: /* 0x0f */
+/* File: mips/OP_RETURN.S */
+ /*
+ * Return a 32-bit value. Copies the return value into the "thread"
+ * structure, then jumps to the return handler.
+ *
+ * for: return, return-object
+ */
+ /* op vAA */
+ GET_OPA(a2) # a2 <- AA
+ GET_VREG(a0, a2) # a0 <- vAA
+ sw a0, offThread_retval(rSELF) # retval.i <- vAA
+ b common_returnFromMethod
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_RETURN_WIDE: /* 0x10 */
+/* File: mips/OP_RETURN_WIDE.S */
+ /*
+ * Return a 64-bit value. Copies the return value into the "thread"
+ * structure, then jumps to the return handler.
+ */
+ /* return-wide vAA */
+ GET_OPA(a2) # a2 <- AA
+ EAS2(a2, rFP, a2) # a2 <- &fp[AA]
+ addu a3, rSELF, offThread_retval # a3 <- &self->retval
+ LOAD64(a0, a1, a2) # a0/a1 <- vAA/vAA+1
+ STORE64(a0, a1, a3) # retval <- a0/a1
+ b common_returnFromMethod
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_RETURN_OBJECT: /* 0x11 */
+/* File: mips/OP_RETURN_OBJECT.S */
+/* File: mips/OP_RETURN.S */
+ /*
+ * Return a 32-bit value. Copies the return value into the "thread"
+ * structure, then jumps to the return handler.
+ *
+ * for: return, return-object
+ */
+ /* op vAA */
+ GET_OPA(a2) # a2 <- AA
+ GET_VREG(a0, a2) # a0 <- vAA
+ sw a0, offThread_retval(rSELF) # retval.i <- vAA
+ b common_returnFromMethod
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST_4: /* 0x12 */
+/* File: mips/OP_CONST_4.S */
+ # const/4 vA, /* +B */
+ sll a1, rINST, 16 # a1 <- Bxxx0000
+ GET_OPA(a0) # a0 <- A+
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ sra a1, a1, 28 # a1 <- sssssssB (sign-extended)
+ and a0, a0, 15
+ GET_INST_OPCODE(t0) # ip <- opcode from rINST
+ SET_VREG_GOTO(a1, a0, t0) # fp[A] <- a1
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST_16: /* 0x13 */
+/* File: mips/OP_CONST_16.S */
+ # const/16 vAA, /* +BBBB */
+ FETCH_S(a0, 1) # a0 <- ssssBBBB (sign-extended)
+ GET_OPA(a3) # a3 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, a3, t0) # vAA <- a0
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST: /* 0x14 */
+/* File: mips/OP_CONST.S */
+ # const vAA, /* +BBBBbbbb */
+ GET_OPA(a3) # a3 <- AA
+ FETCH(a0, 1) # a0 <- bbbb (low)
+ FETCH(a1, 2) # a1 <- BBBB (high)
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ sll a1, a1, 16
+ or a0, a1, a0 # a0 <- BBBBbbbb
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, a3, t0) # vAA <- a0
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST_HIGH16: /* 0x15 */
+/* File: mips/OP_CONST_HIGH16.S */
+ # const/high16 vAA, /* +BBBB0000 */
+ FETCH(a0, 1) # a0 <- 0000BBBB (zero-extended)
+ GET_OPA(a3) # a3 <- AA
+ sll a0, a0, 16 # a0 <- BBBB0000
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, a3, t0) # vAA <- a0
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST_WIDE_16: /* 0x16 */
+/* File: mips/OP_CONST_WIDE_16.S */
+ # const-wide/16 vAA, /* +BBBB */
+ FETCH_S(a0, 1) # a0 <- ssssBBBB (sign-extended)
+ GET_OPA(a3) # a3 <- AA
+ sra a1, a0, 31 # a1 <- ssssssss
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a3, rFP, a3) # a3 <- &fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST_WIDE_32: /* 0x17 */
+/* File: mips/OP_CONST_WIDE_32.S */
+ # const-wide/32 vAA, /* +BBBBbbbb */
+ FETCH(a0, 1) # a0 <- 0000bbbb (low)
+ GET_OPA(a3) # a3 <- AA
+ FETCH_S(a2, 2) # a2 <- ssssBBBB (high)
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ sll a2, a2, 16
+ or a0, a0, a2 # a0 <- BBBBbbbb
+ EAS2(a3, rFP, a3) # a3 <- &fp[AA]
+ sra a1, a0, 31 # a1 <- ssssssss
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST_WIDE: /* 0x18 */
+/* File: mips/OP_CONST_WIDE.S */
+ # const-wide vAA, /* +HHHHhhhhBBBBbbbb */
+ FETCH(a0, 1) # a0 <- bbbb (low)
+ FETCH(a1, 2) # a1 <- BBBB (low middle)
+ FETCH(a2, 3) # a2 <- hhhh (high middle)
+ sll a1, 16 #
+ or a0, a1 # a0 <- BBBBbbbb (low word)
+ FETCH(a3, 4) # a3 <- HHHH (high)
+ GET_OPA(t1) # t1 <- AA
+ sll a3, 16
+ or a1, a3, a2 # a1 <- HHHHhhhh (high word)
+ FETCH_ADVANCE_INST(5) # advance rPC, load rINST
+ EAS2(t1, rFP, t1) # t1 <- &fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, t1) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: mips/OP_CONST_WIDE_HIGH16.S */
+ # const-wide/high16 vAA, /* +BBBB000000000000 */
+ FETCH(a1, 1) # a1 <- 0000BBBB (zero-extended)
+ GET_OPA(a3) # a3 <- AA
+ li a0, 0 # a0 <- 00000000
+ sll a1, 16 # a1 <- BBBB0000
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a3, rFP, a3) # a3 <- &fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST_STRING: /* 0x1a */
+/* File: mips/OP_CONST_STRING.S */
+ # const/string vAA, String /* BBBB */
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_rSELF_methodClassDex(a2) # a2 <- self->methodClassDex
+ GET_OPA(rOBJ) # rOBJ <- AA
+ LOAD_base_offDvmDex_pResStrings(a2, a2) # a2 <- dvmDex->pResStrings
+ LOAD_eas2(v0, a2, a1) # v0 <- pResStrings[BBBB]
+ # not yet resolved?
+ bnez v0, .LOP_CONST_STRING_resolve
+ /*
+ * Continuation if the String has not yet been resolved.
+ * a1: BBBB (String ref)
+ * rOBJ: target register
+ */
+ EXPORT_PC()
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ LOAD_base_offMethod_clazz(a0, a0) # a0 <- method->clazz
+ JAL(dvmResolveString) # v0 <- String reference
+ # failed?
+ beqz v0, common_exceptionThrown # yup, handle the exception
+
+.LOP_CONST_STRING_resolve:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(v0, rOBJ, t0) # vAA <- v0
+
+
+
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: mips/OP_CONST_STRING_JUMBO.S */
+ # const/string vAA, String /* BBBBBBBB */
+ FETCH(a0, 1) # a0 <- bbbb (low)
+ FETCH(a1, 2) # a1 <- BBBB (high)
+ LOAD_rSELF_methodClassDex(a2) # a2 <- self->methodClassDex
+ GET_OPA(rOBJ) # rOBJ <- AA
+ LOAD_base_offDvmDex_pResStrings(a2, a2) # a2 <- dvmDex->pResStrings
+ sll a1, a1, 16
+ or a1, a1, a0 # a1 <- BBBBbbbb
+ LOAD_eas2(v0, a2, a1) # v0 <- pResStrings[BBBB]
+ bnez v0, .LOP_CONST_STRING_JUMBO_resolve
+
+ /*
+ * Continuation if the String has not yet been resolved.
+ * a1: BBBBBBBB (String ref)
+ * rOBJ: target register
+ */
+ EXPORT_PC()
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ LOAD_base_offMethod_clazz(a0, a0) # a0 <- method->clazz
+ JAL(dvmResolveString) # v0 <- String reference
+ # failed?
+ beqz v0, common_exceptionThrown # yup, handle the exception
+
+.LOP_CONST_STRING_JUMBO_resolve:
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ SET_VREG_GOTO(v0, rOBJ, t1) # vAA <- v0
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CONST_CLASS: /* 0x1c */
+/* File: mips/OP_CONST_CLASS.S */
+ # const/class vAA, Class /* BBBB */
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_rSELF_methodClassDex(a2) # a2 <- self->methodClassDex
+ GET_OPA(rOBJ) # rOBJ <- AA
+ LOAD_base_offDvmDex_pResClasses(a2, a2) # a2 <- dvmDex->pResClasses
+ LOAD_eas2(v0, a2, a1) # v0 <- pResClasses[BBBB]
+
+ bnez v0, .LOP_CONST_CLASS_resolve # v0!=0 => resolved-ok
+ /*
+ * Continuation if the Class has not yet been resolved.
+ * a1: BBBB (Class ref)
+ * rOBJ: target register
+ */
+ EXPORT_PC()
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ li a2, 1 # a2 <- true
+ LOAD_base_offMethod_clazz(a0, a0) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- Class reference
+ # failed==0?
+ beqz v0, common_exceptionThrown # yup, handle the exception
+
+.LOP_CONST_CLASS_resolve:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(v0, rOBJ, t0) # vAA <- v0
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MONITOR_ENTER: /* 0x1d */
+/* File: mips/OP_MONITOR_ENTER.S */
+ /*
+ * Synchronize on an object.
+ */
+ /* monitor-enter vAA */
+ GET_OPA(a2) # a2 <- AA
+ GET_VREG(a1, a2) # a1 <- vAA (object)
+ move a0, rSELF # a0 <- self
+ EXPORT_PC() # export PC so we can grab stack trace
+ # null object?
+ beqz a1, common_errNullObject # null object, throw an exception
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ JAL(dvmLockObject) # call(self, obj)
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MONITOR_EXIT: /* 0x1e */
+/* File: mips/OP_MONITOR_EXIT.S */
+ /*
+ * Unlock an object.
+ *
+ * Exceptions that occur when unlocking a monitor need to appear as
+ * if they happened at the following instruction. See the Dalvik
+ * instruction spec.
+ */
+ /* monitor-exit vAA */
+ GET_OPA(a2) # a2 <- AA
+ EXPORT_PC() # before fetch: export the PC
+ GET_VREG(a1, a2) # a1 <- vAA (object)
+ # null object?
+ beqz a1, 1f
+ move a0, rSELF # a0 <- self
+ JAL(dvmUnlockObject) # v0 <- success for unlock(self, obj)
+ # failed?
+ FETCH_ADVANCE_INST(1) # before throw: advance rPC, load rINST
+ beqz v0, common_exceptionThrown # yes, exception is pending
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+1:
+ FETCH_ADVANCE_INST(1) # before throw: advance rPC, load rINST
+ b common_errNullObject
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CHECK_CAST: /* 0x1f */
+/* File: mips/OP_CHECK_CAST.S */
+ /*
+ * Check to see if a cast from one class to another is allowed.
+ */
+ # check-cast vAA, class /* BBBB */
+ GET_OPA(a3) # a3 <- AA
+ FETCH(a2, 1) # a2 <- BBBB
+ GET_VREG(rOBJ, a3) # rOBJ <- object
+ LOAD_rSELF_methodClassDex(a0) # a0 <- pDvmDex
+ LOAD_base_offDvmDex_pResClasses(a0, a0) # a0 <- pDvmDex->pResClasses
+ # is object null?
+ beqz rOBJ, .LOP_CHECK_CAST_okay # null obj, cast always succeeds
+ LOAD_eas2(a1, a0, a2) # a1 <- resolved class
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- obj->clazz
+ # have we resolved this before?
+ beqz a1, .LOP_CHECK_CAST_resolve # not resolved, do it now
+.LOP_CHECK_CAST_resolved:
+ # same class (trivial success)?
+ bne a0, a1, .LOP_CHECK_CAST_fullcheck # no, do full check
+.LOP_CHECK_CAST_okay:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * a0 holds obj->clazz
+ * a1 holds class resolved from BBBB
+ * rOBJ holds object
+ */
+.LOP_CHECK_CAST_fullcheck:
+ move rBIX,a1 # avoid ClassObject getting clobbered
+ JAL(dvmInstanceofNonTrivial) # v0 <- boolean result
+ # failed?
+ bnez v0, .LOP_CHECK_CAST_okay # no, success
+ b .LOP_CHECK_CAST_castfailure
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INSTANCE_OF: /* 0x20 */
+/* File: mips/OP_INSTANCE_OF.S */
+ /*
+ * Check to see if an object reference is an instance of a class.
+ *
+ * Most common situation is a non-null object, being compared against
+ * an already-resolved class.
+ */
+ # instance-of vA, vB, class /* CCCC */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a3) # a0 <- vB (object)
+ LOAD_rSELF_methodClassDex(a2) # a2 <- pDvmDex
+ # is object null?
+ beqz a0, .LOP_INSTANCE_OF_store # null obj, not an instance, store a0
+ FETCH(a3, 1) # a3 <- CCCC
+ LOAD_base_offDvmDex_pResClasses(a2, a2) # a2 <- pDvmDex->pResClasses
+ LOAD_eas2(a1, a2, a3) # a1 <- resolved class
+ LOAD_base_offObject_clazz(a0, a0) # a0 <- obj->clazz
+ # have we resolved this before?
+ beqz a1, .LOP_INSTANCE_OF_resolve # not resolved, do it now
+.LOP_INSTANCE_OF_resolved: # a0=obj->clazz, a1=resolved class
+ # same class (trivial success)?
+ beq a0, a1, .LOP_INSTANCE_OF_trivial # yes, trivial finish
+ b .LOP_INSTANCE_OF_fullcheck # no, do full check
+
+ /*
+ * Trivial test succeeded, save and bail.
+ * rOBJ holds A
+ */
+.LOP_INSTANCE_OF_trivial:
+ li a0, 1 # indicate success
+ # fall thru
+ /*
+ * a0 holds boolean result
+ * rOBJ holds A
+ */
+.LOP_INSTANCE_OF_store:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ SET_VREG(a0, rOBJ) # vA <- a0
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: mips/OP_ARRAY_LENGTH.S */
+ /*
+ * Return the length of an array.
+ */
+ GET_OPB(a1) # a1 <- B
+ GET_OPA4(a2) # a2 <- A+
+ GET_VREG(a0, a1) # a0 <- vB (object ref)
+ # is object null?
+ beqz a0, common_errNullObject # yup, fail
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- array length
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a3, a2, t0) # vA <- length
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_NEW_INSTANCE: /* 0x22 */
+/* File: mips/OP_NEW_INSTANCE.S */
+ /*
+ * Create a new instance of a class.
+ */
+ # new-instance vAA, class /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResClasses(a3, a3) # a3 <- pDvmDex->pResClasses
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved class
+#if defined(WITH_JIT)
+ EAS2(rBIX, a3, a1) # rBIX <- &resolved_class
+#endif
+ EXPORT_PC() # req'd for init, resolve, alloc
+ # already resolved?
+ beqz a0, .LOP_NEW_INSTANCE_resolve # no, resolve it now
+.LOP_NEW_INSTANCE_resolved: # a0=class
+ lbu a1, offClassObject_status(a0) # a1 <- ClassStatus enum
+ # has class been initialized?
+ li t0, CLASS_INITIALIZED
+ move rOBJ, a0 # save a0
+ bne a1, t0, .LOP_NEW_INSTANCE_needinit # no, init class now
+
+.LOP_NEW_INSTANCE_initialized: # a0=class
+ LOAD_base_offClassObject_accessFlags(a3, a0) # a3 <- clazz->accessFlags
+ li a1, ALLOC_DONT_TRACK # flags for alloc call
+ # a0=class
+ JAL(dvmAllocObject) # v0 <- new object
+ GET_OPA(a3) # a3 <- AA
+#if defined(WITH_JIT)
+ /*
+ * The JIT needs the class to be fully resolved before it can
+ * include this instruction in a trace.
+ */
+ lhu a1, offThread_subMode(rSELF)
+ beqz v0, common_exceptionThrown # yes, handle the exception
+ and a1, kSubModeJitTraceBuild # under construction?
+ bnez a1, .LOP_NEW_INSTANCE_jitCheck
+#else
+ # failed?
+ beqz v0, common_exceptionThrown # yes, handle the exception
+#endif
+ b .LOP_NEW_INSTANCE_continue
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_NEW_ARRAY: /* 0x23 */
+/* File: mips/OP_NEW_ARRAY.S */
+ /*
+ * Allocate an array of objects, specified with the array class
+ * and a count.
+ *
+ * The verifier guarantees that this is an array class, so we don't
+ * check for it here.
+ */
+ /* new-array vA, vB, class@CCCC */
+ GET_OPB(a0) # a0 <- B
+ FETCH(a2, 1) # a2 <- CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ GET_VREG(a1, a0) # a1 <- vB (array length)
+ LOAD_base_offDvmDex_pResClasses(a3, a3) # a3 <- pDvmDex->pResClasses
+ LOAD_eas2(a0, a3, a2) # a0 <- resolved class
+ # check length
+ bltz a1, common_errNegativeArraySize # negative length, bail - len in a1
+ EXPORT_PC() # req'd for resolve, alloc
+ # already resolved?
+ beqz a0, .LOP_NEW_ARRAY_resolve
+
+ /*
+ * Finish allocation.
+ *
+ * a0 holds class
+ * a1 holds array length
+ */
+.LOP_NEW_ARRAY_finish:
+ li a2, ALLOC_DONT_TRACK # don't track in local refs table
+ JAL(dvmAllocArrayByClass) # v0 <- call(clazz, length, flags)
+ GET_OPA4(a2) # a2 <- A+
+ # failed?
+ beqz v0, common_exceptionThrown # yes, handle the exception
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(v0, a2) # vA <- v0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: mips/OP_FILLED_NEW_ARRAY.S */
+ /*
+ * Create a new array with elements filled from registers.
+ *
+ * for: filled-new-array, filled-new-array/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op {vCCCC..v(CCCC+AA-1)}, type /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResClasses(a3, a3) # a3 <- pDvmDex->pResClasses
+ EXPORT_PC() # need for resolve and alloc
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved class
+ GET_OPA(rOBJ) # rOBJ <- AA or BA
+ # already resolved?
+ bnez a0, .LOP_FILLED_NEW_ARRAY_continue # yes, continue on
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- call(clazz, ref)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b .LOP_FILLED_NEW_ARRAY_continue
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: mips/OP_FILLED_NEW_ARRAY_RANGE.S */
+/* File: mips/OP_FILLED_NEW_ARRAY.S */
+ /*
+ * Create a new array with elements filled from registers.
+ *
+ * for: filled-new-array, filled-new-array/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op {vCCCC..v(CCCC+AA-1)}, type /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResClasses(a3, a3) # a3 <- pDvmDex->pResClasses
+ EXPORT_PC() # need for resolve and alloc
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved class
+ GET_OPA(rOBJ) # rOBJ <- AA or BA
+ # already resolved?
+ bnez a0, .LOP_FILLED_NEW_ARRAY_RANGE_continue # yes, continue on
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- call(clazz, ref)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b .LOP_FILLED_NEW_ARRAY_RANGE_continue
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: mips/OP_FILL_ARRAY_DATA.S */
+ /* fill-array-data vAA, +BBBBBBBB */
+ FETCH(a0, 1) # a0 <- bbbb (lo)
+ FETCH(a1, 2) # a1 <- BBBB (hi)
+ GET_OPA(a3) # a3 <- AA
+ sll a1, a1, 16 # a1 <- BBBBbbbb
+ or a1, a0, a1 # a1 <- BBBBbbbb
+ GET_VREG(a0, a3) # a0 <- vAA (array object)
+ EAS1(a1, rPC, a1) # a1 <- PC + BBBBbbbb*2 (array data off.)
+ EXPORT_PC()
+ JAL(dvmInterpHandleFillArrayData) # fill the array with predefined data
+ # 0 means an exception is thrown
+ beqz v0, common_exceptionThrown # has exception
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_THROW: /* 0x27 */
+/* File: mips/OP_THROW.S */
+ /*
+ * Throw an exception object in the current thread.
+ */
+ /* throw vAA */
+ GET_OPA(a2) # a2 <- AA
+ GET_VREG(a1, a2) # a1 <- vAA (exception object)
+ EXPORT_PC() # exception handler can throw
+ # null object?
+ beqz a1, common_errNullObject # yes, throw an NPE instead
+ # bypass dvmSetException, just store it
+ STORE_offThread_exception(a1, rSELF) # thread->exception <- obj
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_GOTO: /* 0x28 */
+/* File: mips/OP_GOTO.S */
+ /*
+ * Unconditional branch, 8-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ */
+ /* goto +AA */
+ sll a0, rINST, 16 # a0 <- AAxx0000
+ sra a1, a0, 24 # a1 <- ssssssAA (sign-extended)
+ addu a2, a1, a1 # a2 <- byte offset
+ /* If backwards branch refresh rBASE */
+ bgez a1, 1f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+1:
+ FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bltz a1, common_testUpdateProfile # (a0) check for trace hotness
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_GOTO_16: /* 0x29 */
+/* File: mips/OP_GOTO_16.S */
+ /*
+ * Unconditional branch, 16-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ */
+ /* goto/16 +AAAA */
+ FETCH_S(a0, 1) # a0 <- ssssAAAA (sign-extended)
+ addu a1, a0, a0 # a1 <- byte offset, flags set
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+ bgez a1, 1f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+1:
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bltz a1, common_testUpdateProfile # (a0) hot trace head?
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_GOTO_32: /* 0x2a */
+/* File: mips/OP_GOTO_32.S */
+ /*
+ * Unconditional branch, 32-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ *
+ * Unlike most opcodes, this one is allowed to branch to itself, so
+ * our "backward branch" test must be "<=0" instead of "<0".
+ */
+ /* goto/32 +AAAAAAAA */
+ FETCH(a0, 1) # a0 <- aaaa (lo)
+ FETCH(a1, 2) # a1 <- AAAA (hi)
+ sll a1, a1, 16
+ or a0, a0, a1 # a0 <- AAAAaaaa
+ addu a1, a0, a0 # a1 <- byte offset
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgtz a1, 1f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+1:
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+ blez a1, common_testUpdateProfile # (a0) hot trace head?
+#else
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+ bgtz a0, 2f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+2:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_PACKED_SWITCH: /* 0x2b */
+/* File: mips/OP_PACKED_SWITCH.S */
+ /*
+ * Handle a packed-switch or sparse-switch instruction. In both cases
+ * we decode it and hand it off to a helper function.
+ *
+ * We don't really expect backward branches in a switch statement, but
+ * they're perfectly legal, so we check for them here.
+ *
+ * When the JIT is present, all targets are considered treated as
+ * a potential trace heads regardless of branch direction.
+ *
+ * for: packed-switch, sparse-switch
+ */
+ /* op vAA, +BBBB */
+ FETCH(a0, 1) # a0 <- bbbb (lo)
+ FETCH(a1, 2) # a1 <- BBBB (hi)
+ GET_OPA(a3) # a3 <- AA
+ sll t0, a1, 16
+ or a0, a0, t0 # a0 <- BBBBbbbb
+ GET_VREG(a1, a3) # a1 <- vAA
+ EAS1(a0, rPC, a0) # a0 <- PC + BBBBbbbb*2
+ JAL(dvmInterpHandlePackedSwitch) # a0 <- code-unit branch offset
+ addu a1, v0, v0 # a1 <- byte offset
+ bgtz a1, 1f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+1:
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bnez a0, common_updateProfile
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: mips/OP_SPARSE_SWITCH.S */
+/* File: mips/OP_PACKED_SWITCH.S */
+ /*
+ * Handle a packed-switch or sparse-switch instruction. In both cases
+ * we decode it and hand it off to a helper function.
+ *
+ * We don't really expect backward branches in a switch statement, but
+ * they're perfectly legal, so we check for them here.
+ *
+ * When the JIT is present, all targets are considered treated as
+ * a potential trace heads regardless of branch direction.
+ *
+ * for: packed-switch, sparse-switch
+ */
+ /* op vAA, +BBBB */
+ FETCH(a0, 1) # a0 <- bbbb (lo)
+ FETCH(a1, 2) # a1 <- BBBB (hi)
+ GET_OPA(a3) # a3 <- AA
+ sll t0, a1, 16
+ or a0, a0, t0 # a0 <- BBBBbbbb
+ GET_VREG(a1, a3) # a1 <- vAA
+ EAS1(a0, rPC, a0) # a0 <- PC + BBBBbbbb*2
+ JAL(dvmInterpHandleSparseSwitch) # a0 <- code-unit branch offset
+ addu a1, v0, v0 # a1 <- byte offset
+ bgtz a1, 1f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh handler base
+1:
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bnez a0, common_updateProfile
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CMPL_FLOAT: /* 0x2d */
+/* File: mips/OP_CMPL_FLOAT.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * for: cmpl-float, cmpg-float
+ */
+ /* op vAA, vBB, vCC */
+
+ /* "clasic" form */
+ FETCH(a0, 1) # a0 <- CCBB
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8
+#ifdef SOFT_FLOAT
+ GET_VREG(rOBJ, a2) # rOBJ <- vBB
+ GET_VREG(rBIX, a3) # rBIX <- vCC
+ move a0, rOBJ # a0 <- vBB
+ move a1, rBIX # a1 <- vCC
+ JAL(__eqsf2) # a0 <- (vBB == vCC)
+ li rTEMP, 0 # set rTEMP to 0
+ beqz v0, OP_CMPL_FLOAT_finish
+ move a0, rOBJ # a0 <- vBB
+ move a1, rBIX # a1 <- vCC
+ JAL(__ltsf2) # a0 <- (vBB < vCC)
+ li rTEMP, -1
+ bltz v0, OP_CMPL_FLOAT_finish
+ move a0, rOBJ # a0 <- vBB
+ move a1, rBIX # a1 <- vCC
+ b OP_CMPL_FLOAT_continue
+#else
+ GET_VREG_F(fs0, a2)
+ GET_VREG_F(fs1, a3)
+ c.olt.s fcc0, fs0, fs1 # Is fs0 < fs1
+ li rTEMP, -1
+ bc1t fcc0, OP_CMPL_FLOAT_finish
+ c.olt.s fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, OP_CMPL_FLOAT_finish
+ c.eq.s fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, OP_CMPL_FLOAT_finish
+ b OP_CMPL_FLOAT_nan
+
+#endif
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CMPG_FLOAT: /* 0x2e */
+/* File: mips/OP_CMPG_FLOAT.S */
+/* File: mips/OP_CMPL_FLOAT.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * for: cmpl-float, cmpg-float
+ */
+ /* op vAA, vBB, vCC */
+
+ /* "clasic" form */
+ FETCH(a0, 1) # a0 <- CCBB
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8
+#ifdef SOFT_FLOAT
+ GET_VREG(rOBJ, a2) # rOBJ <- vBB
+ GET_VREG(rBIX, a3) # rBIX <- vCC
+ move a0, rOBJ # a0 <- vBB
+ move a1, rBIX # a1 <- vCC
+ JAL(__eqsf2) # a0 <- (vBB == vCC)
+ li rTEMP, 0 # set rTEMP to 0
+ beqz v0, OP_CMPG_FLOAT_finish
+ move a0, rOBJ # a0 <- vBB
+ move a1, rBIX # a1 <- vCC
+ JAL(__ltsf2) # a0 <- (vBB < vCC)
+ li rTEMP, -1
+ bltz v0, OP_CMPG_FLOAT_finish
+ move a0, rOBJ # a0 <- vBB
+ move a1, rBIX # a1 <- vCC
+ b OP_CMPG_FLOAT_continue
+#else
+ GET_VREG_F(fs0, a2)
+ GET_VREG_F(fs1, a3)
+ c.olt.s fcc0, fs0, fs1 # Is fs0 < fs1
+ li rTEMP, -1
+ bc1t fcc0, OP_CMPG_FLOAT_finish
+ c.olt.s fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, OP_CMPG_FLOAT_finish
+ c.eq.s fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, OP_CMPG_FLOAT_finish
+ b OP_CMPG_FLOAT_nan
+
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: mips/OP_CMPL_DOUBLE.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * See OP_CMPL_FLOAT for an explanation.
+ *
+ * For: cmpl-double, cmpg-double
+ */
+ /* op vAA, vBB, vCC */
+
+ FETCH(a0, 1) # a0 <- CCBB
+ and rOBJ, a0, 255 # s0 <- BB
+ srl rBIX, a0, 8 # t0 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # s0 <- &fp[BB]
+ EAS2(rBIX, rFP, rBIX) # t0 <- &fp[CC]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3 <- vCC/vCC+1
+ JAL(__eqdf2) # cmp <=: C clear if <, Z set if eq
+ li rTEMP, 0
+ beqz v0, OP_CMPL_DOUBLE_finish
+
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3 <- vCC/vCC+1
+ JAL(__ltdf2)
+ li rTEMP, -1
+ bltz v0, OP_CMPL_DOUBLE_finish
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vBB/vBB+1
+ b OP_CMPL_DOUBLE_continue
+#else
+ LOAD64_F(fs0, fs0f, rOBJ)
+ LOAD64_F(fs1, fs1f, rBIX)
+ c.olt.d fcc0, fs0, fs1
+ li rTEMP, -1
+ bc1t fcc0, OP_CMPL_DOUBLE_finish
+ c.olt.d fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, OP_CMPL_DOUBLE_finish
+ c.eq.d fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, OP_CMPL_DOUBLE_finish
+ b OP_CMPL_DOUBLE_nan
+#endif
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: mips/OP_CMPG_DOUBLE.S */
+/* File: mips/OP_CMPL_DOUBLE.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into a1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * See OP_CMPL_FLOAT for an explanation.
+ *
+ * For: cmpl-double, cmpg-double
+ */
+ /* op vAA, vBB, vCC */
+
+ FETCH(a0, 1) # a0 <- CCBB
+ and rOBJ, a0, 255 # s0 <- BB
+ srl rBIX, a0, 8 # t0 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # s0 <- &fp[BB]
+ EAS2(rBIX, rFP, rBIX) # t0 <- &fp[CC]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3 <- vCC/vCC+1
+ JAL(__eqdf2) # cmp <=: C clear if <, Z set if eq
+ li rTEMP, 0
+ beqz v0, OP_CMPG_DOUBLE_finish
+
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3 <- vCC/vCC+1
+ JAL(__ltdf2)
+ li rTEMP, -1
+ bltz v0, OP_CMPG_DOUBLE_finish
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vBB/vBB+1
+ b OP_CMPG_DOUBLE_continue
+#else
+ LOAD64_F(fs0, fs0f, rOBJ)
+ LOAD64_F(fs1, fs1f, rBIX)
+ c.olt.d fcc0, fs0, fs1
+ li rTEMP, -1
+ bc1t fcc0, OP_CMPG_DOUBLE_finish
+ c.olt.d fcc0, fs1, fs0
+ li rTEMP, 1
+ bc1t fcc0, OP_CMPG_DOUBLE_finish
+ c.eq.d fcc0, fs0, fs1
+ li rTEMP, 0
+ bc1t fcc0, OP_CMPG_DOUBLE_finish
+ b OP_CMPG_DOUBLE_nan
+#endif
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_CMP_LONG: /* 0x31 */
+/* File: mips/OP_CMP_LONG.S */
+ /*
+ * Compare two 64-bit values
+ * x = y return 0
+ * x < y return -1
+ * x > y return 1
+ *
+ * I think I can improve on the ARM code by the following observation
+ * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
+ * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
+ * subu v0, t0, t1 # v0= -1:1:0 for [ < > = ]
+ */
+ /* cmp-long vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(a3, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a0, a1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a2, a3, a3) # a2/a3 <- vCC/vCC+1
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ slt t0, a1, a3 # compare hi
+ sgt t1, a1, a3
+ subu v0, t1, t0 # v0 <- (-1, 1, 0)
+ bnez v0, .LOP_CMP_LONG_finish
+ # at this point x.hi==y.hi
+ sltu t0, a0, a2 # compare lo
+ sgtu t1, a0, a2
+ subu v0, t1, t0 # v0 <- (-1, 1, 0) for [< > =]
+
+.LOP_CMP_LONG_finish:
+ SET_VREG(v0, rOBJ) # vAA <- v0
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_EQ: /* 0x32 */
+/* File: mips/OP_IF_EQ.S */
+/* File: mips/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ GET_OPA4(a0) # a0 <- A+
+ GET_OPB(a1) # a1 <- B
+ GET_VREG(a3, a1) # a3 <- vB
+ GET_VREG(a2, a0) # a2 <- vA
+ bne a2, a3, 1f # branch to 1 if comparison failed
+ FETCH_S(a1, 1) # a1<- branch offset, in code units
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a2, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a2, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+3:
+ bnez a0, common_updateProfile
+#else
+ bgez a2, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_NE: /* 0x33 */
+/* File: mips/OP_IF_NE.S */
+/* File: mips/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ GET_OPA4(a0) # a0 <- A+
+ GET_OPB(a1) # a1 <- B
+ GET_VREG(a3, a1) # a3 <- vB
+ GET_VREG(a2, a0) # a2 <- vA
+ beq a2, a3, 1f # branch to 1 if comparison failed
+ FETCH_S(a1, 1) # a1<- branch offset, in code units
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a2, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a2, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+3:
+ bnez a0, common_updateProfile
+#else
+ bgez a2, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_LT: /* 0x34 */
+/* File: mips/OP_IF_LT.S */
+/* File: mips/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ GET_OPA4(a0) # a0 <- A+
+ GET_OPB(a1) # a1 <- B
+ GET_VREG(a3, a1) # a3 <- vB
+ GET_VREG(a2, a0) # a2 <- vA
+ bge a2, a3, 1f # branch to 1 if comparison failed
+ FETCH_S(a1, 1) # a1<- branch offset, in code units
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a2, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a2, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+3:
+ bnez a0, common_updateProfile
+#else
+ bgez a2, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_GE: /* 0x35 */
+/* File: mips/OP_IF_GE.S */
+/* File: mips/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ GET_OPA4(a0) # a0 <- A+
+ GET_OPB(a1) # a1 <- B
+ GET_VREG(a3, a1) # a3 <- vB
+ GET_VREG(a2, a0) # a2 <- vA
+ blt a2, a3, 1f # branch to 1 if comparison failed
+ FETCH_S(a1, 1) # a1<- branch offset, in code units
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a2, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a2, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+3:
+ bnez a0, common_updateProfile
+#else
+ bgez a2, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_GT: /* 0x36 */
+/* File: mips/OP_IF_GT.S */
+/* File: mips/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ GET_OPA4(a0) # a0 <- A+
+ GET_OPB(a1) # a1 <- B
+ GET_VREG(a3, a1) # a3 <- vB
+ GET_VREG(a2, a0) # a2 <- vA
+ ble a2, a3, 1f # branch to 1 if comparison failed
+ FETCH_S(a1, 1) # a1<- branch offset, in code units
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a2, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a2, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+3:
+ bnez a0, common_updateProfile
+#else
+ bgez a2, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_LE: /* 0x37 */
+/* File: mips/OP_IF_LE.S */
+/* File: mips/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ GET_OPA4(a0) # a0 <- A+
+ GET_OPB(a1) # a1 <- B
+ GET_VREG(a3, a1) # a3 <- vB
+ GET_VREG(a2, a0) # a2 <- vA
+ bgt a2, a3, 1f # branch to 1 if comparison failed
+ FETCH_S(a1, 1) # a1<- branch offset, in code units
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a2, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a2, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+3:
+ bnez a0, common_updateProfile
+#else
+ bgez a2, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_EQZ: /* 0x38 */
+/* File: mips/OP_IF_EQZ.S */
+/* File: mips/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ GET_OPA(a0) # a0 <- AA
+ GET_VREG(a2, a0) # a2 <- vAA
+ FETCH_S(a1, 1) # a1 <- branch offset, in code units
+ bne a2, zero, 1f # branch to 1 if comparison failed
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a1, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a1, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh table base
+3:
+ bnez a0, common_updateProfile # test for JIT off at target
+#else
+ bgez a1, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rtable base
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_NEZ: /* 0x39 */
+/* File: mips/OP_IF_NEZ.S */
+/* File: mips/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ GET_OPA(a0) # a0 <- AA
+ GET_VREG(a2, a0) # a2 <- vAA
+ FETCH_S(a1, 1) # a1 <- branch offset, in code units
+ beq a2, zero, 1f # branch to 1 if comparison failed
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a1, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a1, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh table base
+3:
+ bnez a0, common_updateProfile # test for JIT off at target
+#else
+ bgez a1, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rtable base
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_LTZ: /* 0x3a */
+/* File: mips/OP_IF_LTZ.S */
+/* File: mips/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ GET_OPA(a0) # a0 <- AA
+ GET_VREG(a2, a0) # a2 <- vAA
+ FETCH_S(a1, 1) # a1 <- branch offset, in code units
+ bge a2, zero, 1f # branch to 1 if comparison failed
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a1, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a1, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh table base
+3:
+ bnez a0, common_updateProfile # test for JIT off at target
+#else
+ bgez a1, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rtable base
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_GEZ: /* 0x3b */
+/* File: mips/OP_IF_GEZ.S */
+/* File: mips/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ GET_OPA(a0) # a0 <- AA
+ GET_VREG(a2, a0) # a2 <- vAA
+ FETCH_S(a1, 1) # a1 <- branch offset, in code units
+ blt a2, zero, 1f # branch to 1 if comparison failed
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a1, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a1, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh table base
+3:
+ bnez a0, common_updateProfile # test for JIT off at target
+#else
+ bgez a1, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rtable base
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_GTZ: /* 0x3c */
+/* File: mips/OP_IF_GTZ.S */
+/* File: mips/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ GET_OPA(a0) # a0 <- AA
+ GET_VREG(a2, a0) # a2 <- vAA
+ FETCH_S(a1, 1) # a1 <- branch offset, in code units
+ ble a2, zero, 1f # branch to 1 if comparison failed
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a1, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a1, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh table base
+3:
+ bnez a0, common_updateProfile # test for JIT off at target
+#else
+ bgez a1, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rtable base
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IF_LEZ: /* 0x3d */
+/* File: mips/OP_IF_LEZ.S */
+/* File: mips/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ GET_OPA(a0) # a0 <- AA
+ GET_VREG(a2, a0) # a2 <- vAA
+ FETCH_S(a1, 1) # a1 <- branch offset, in code units
+ bgt a2, zero, 1f # branch to 1 if comparison failed
+ b 2f
+1:
+ li a1, 2 # a1- BYTE branch dist for not-taken
+2:
+ addu a1, a1, a1 # convert to bytes
+ FETCH_ADVANCE_INST_RB(a1) # update rPC, load rINST
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ bgez a1, 3f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh table base
+3:
+ bnez a0, common_updateProfile # test for JIT off at target
+#else
+ bgez a1, 4f
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rtable base
+4:
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_UNUSED_3E: /* 0x3e */
+/* File: mips/OP_UNUSED_3E.S */
+/* File: mips/unused.S */
+ BAL(common_abort)
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_UNUSED_3F: /* 0x3f */
+/* File: mips/OP_UNUSED_3F.S */
+/* File: mips/unused.S */
+ BAL(common_abort)
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_UNUSED_40: /* 0x40 */
+/* File: mips/OP_UNUSED_40.S */
+/* File: mips/unused.S */
+ BAL(common_abort)
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_UNUSED_41: /* 0x41 */
+/* File: mips/OP_UNUSED_41.S */
+/* File: mips/unused.S */
+ BAL(common_abort)
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_UNUSED_42: /* 0x42 */
+/* File: mips/OP_UNUSED_42.S */
+/* File: mips/unused.S */
+ BAL(common_abort)
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_UNUSED_43: /* 0x43 */
+/* File: mips/OP_UNUSED_43.S */
+/* File: mips/unused.S */
+ BAL(common_abort)
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AGET: /* 0x44 */
+/* File: mips/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 2
+ EASN(a0, a0, a1, 2) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ # a1 >= a3; compare unsigned index
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ lw a2, offArrayObject_contents(a0) # a2 <- vBB[vCC]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, rOBJ, t0) # vAA <- a2
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AGET_WIDE: /* 0x45 */
+/* File: mips/OP_AGET_WIDE.S */
+ /*
+ * Array get, 64 bits. vAA <- vBB[vCC].
+ *
+ * Arrays of long/double are 64-bit aligned.
+ */
+ /* aget-wide vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ EAS3(a0, a0, a1) # a0 <- arrayObj + index*width
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+
+.LOP_AGET_WIDE_finish:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ LOAD64_off(a2, a3, a0, offArrayObject_contents)
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a2, a3, rOBJ) # vAA/vAA+1 <- a2/a3
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AGET_OBJECT: /* 0x46 */
+/* File: mips/OP_AGET_OBJECT.S */
+/* File: mips/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 2
+ EASN(a0, a0, a1, 2) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ # a1 >= a3; compare unsigned index
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ lw a2, offArrayObject_contents(a0) # a2 <- vBB[vCC]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, rOBJ, t0) # vAA <- a2
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: mips/OP_AGET_BOOLEAN.S */
+/* File: mips/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 0
+ EASN(a0, a0, a1, 0) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ # a1 >= a3; compare unsigned index
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ lbu a2, offArrayObject_contents(a0) # a2 <- vBB[vCC]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, rOBJ, t0) # vAA <- a2
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AGET_BYTE: /* 0x48 */
+/* File: mips/OP_AGET_BYTE.S */
+/* File: mips/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 0
+ EASN(a0, a0, a1, 0) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ # a1 >= a3; compare unsigned index
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ lb a2, offArrayObject_contents(a0) # a2 <- vBB[vCC]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, rOBJ, t0) # vAA <- a2
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AGET_CHAR: /* 0x49 */
+/* File: mips/OP_AGET_CHAR.S */
+/* File: mips/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 1
+ EASN(a0, a0, a1, 1) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ # a1 >= a3; compare unsigned index
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ lhu a2, offArrayObject_contents(a0) # a2 <- vBB[vCC]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, rOBJ, t0) # vAA <- a2
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AGET_SHORT: /* 0x4a */
+/* File: mips/OP_AGET_SHORT.S */
+/* File: mips/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 1
+ EASN(a0, a0, a1, 1) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ # a1 >= a3; compare unsigned index
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ lh a2, offArrayObject_contents(a0) # a2 <- vBB[vCC]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a2, rOBJ, t0) # vAA <- a2
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_APUT: /* 0x4b */
+/* File: mips/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 2
+ EASN(a0, a0, a1, 2) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a2, rOBJ) # a2 <- vAA
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ sw a2, offArrayObject_contents(a0) # vBB[vCC] <- a2
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_APUT_WIDE: /* 0x4c */
+/* File: mips/OP_APUT_WIDE.S */
+ /*
+ * Array put, 64 bits. vBB[vCC] <- vAA.
+ *
+ * Arrays of long/double are 64-bit aligned, so it's okay to use STRD.
+ */
+ /* aput-wide vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(t0) # t0 <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ EAS3(a0, a0, a1) # a0 <- arrayObj + index*width
+ EAS2(rOBJ, rFP, t0) # rOBJ <- &fp[AA]
+ # compare unsigned index, length
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ LOAD64(a2, a3, rOBJ) # a2/a3 <- vAA/vAA+1
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64_off(a2, a3, a0, offArrayObject_contents) # a2/a3 <- vBB[vCC]
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_APUT_OBJECT: /* 0x4d */
+/* File: mips/OP_APUT_OBJECT.S */
+ /*
+ * Store an object into an array. vBB[vCC] <- vAA.
+ *
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(t1) # t1 <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ GET_VREG(rINST, a2) # rINST <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ GET_VREG(rBIX, t1) # rBIX <- vAA
+ # null array object?
+ beqz rINST, common_errNullObject # yes, bail
+
+ LOAD_base_offArrayObject_length(a3, rINST) # a3 <- arrayObj->length
+ EAS2(rOBJ, rINST, a1) # rOBJ <- arrayObj + index*width
+ # compare unsigned index, length
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ /*
+ * On entry:
+ * rINST = vBB (arrayObj)
+ * rBIX = vAA (obj)
+ * rOBJ = offset into array (vBB + vCC * width)
+ */
+ bnez rBIX, .LOP_APUT_OBJECT_checks # yes, skip type checks
+.LOP_APUT_OBJECT_finish:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ sw rBIX, offArrayObject_contents(rOBJ) # vBB[vCC] <- vAA
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: mips/OP_APUT_BOOLEAN.S */
+/* File: mips/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 0
+ EASN(a0, a0, a1, 0) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a2, rOBJ) # a2 <- vAA
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ sb a2, offArrayObject_contents(a0) # vBB[vCC] <- a2
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_APUT_BYTE: /* 0x4f */
+/* File: mips/OP_APUT_BYTE.S */
+/* File: mips/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 0
+ EASN(a0, a0, a1, 0) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a2, rOBJ) # a2 <- vAA
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ sb a2, offArrayObject_contents(a0) # vBB[vCC] <- a2
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_APUT_CHAR: /* 0x50 */
+/* File: mips/OP_APUT_CHAR.S */
+/* File: mips/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 1
+ EASN(a0, a0, a1, 1) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a2, rOBJ) # a2 <- vAA
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ sh a2, offArrayObject_contents(a0) # vBB[vCC] <- a2
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_APUT_SHORT: /* 0x51 */
+/* File: mips/OP_APUT_SHORT.S */
+/* File: mips/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(a2, 1) # a2 <- BB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ FETCH_C(a3, 1) # a3 <- CC
+ GET_VREG(a0, a2) # a0 <- vBB (array object)
+ GET_VREG(a1, a3) # a1 <- vCC (requested index)
+ # null array object?
+ beqz a0, common_errNullObject # yes, bail
+ LOAD_base_offArrayObject_length(a3, a0) # a3 <- arrayObj->length
+ .if 1
+ EASN(a0, a0, a1, 1) # a0 <- arrayObj + index*width
+ .else
+ addu a0, a0, a1
+ .endif
+ bgeu a1, a3, common_errArrayIndex # index >= length, bail
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a2, rOBJ) # a2 <- vAA
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ sh a2, offArrayObject_contents(a0) # vBB[vCC] <- a2
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET: /* 0x52 */
+/* File: mips/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IGET_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test results
+ move a0, v0
+ bnez v0, .LOP_IGET_finish
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_WIDE: /* 0x53 */
+/* File: mips/OP_IGET_WIDE.S */
+ /*
+ * Wide 32-bit instance field get.
+ */
+ # iget-wide vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IGET_WIDE_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test return code
+ move a0, v0
+ bnez v0, .LOP_IGET_WIDE_finish
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_OBJECT: /* 0x54 */
+/* File: mips/OP_IGET_OBJECT.S */
+/* File: mips/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IGET_OBJECT_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test results
+ move a0, v0
+ bnez v0, .LOP_IGET_OBJECT_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: mips/OP_IGET_BOOLEAN.S */
+/* File: mips/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IGET_BOOLEAN_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test results
+ move a0, v0
+ bnez v0, .LOP_IGET_BOOLEAN_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_BYTE: /* 0x56 */
+/* File: mips/OP_IGET_BYTE.S */
+/* File: mips/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IGET_BYTE_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test results
+ move a0, v0
+ bnez v0, .LOP_IGET_BYTE_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_CHAR: /* 0x57 */
+/* File: mips/OP_IGET_CHAR.S */
+/* File: mips/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IGET_CHAR_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test results
+ move a0, v0
+ bnez v0, .LOP_IGET_CHAR_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_SHORT: /* 0x58 */
+/* File: mips/OP_IGET_SHORT.S */
+/* File: mips/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IGET_SHORT_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test results
+ move a0, v0
+ bnez v0, .LOP_IGET_SHORT_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT: /* 0x59 */
+/* File: mips/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IPUT_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .LOP_IPUT_finish # yes, finish up
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_WIDE: /* 0x5a */
+/* File: mips/OP_IPUT_WIDE.S */
+ # iput-wide vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IPUT_WIDE_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .LOP_IPUT_WIDE_finish # yes, finish up
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_OBJECT: /* 0x5b */
+/* File: mips/OP_IPUT_OBJECT.S */
+ /*
+ * 32-bit instance field put.
+ *
+ * for: iput-object, iput-object-volatile
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IPUT_OBJECT_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .LOP_IPUT_OBJECT_finish # yes, finish up
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: mips/OP_IPUT_BOOLEAN.S */
+/* File: mips/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IPUT_BOOLEAN_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .LOP_IPUT_BOOLEAN_finish # yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_BYTE: /* 0x5d */
+/* File: mips/OP_IPUT_BYTE.S */
+/* File: mips/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IPUT_BYTE_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .LOP_IPUT_BYTE_finish # yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_CHAR: /* 0x5e */
+/* File: mips/OP_IPUT_CHAR.S */
+/* File: mips/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IPUT_CHAR_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .LOP_IPUT_CHAR_finish # yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_SHORT: /* 0x5f */
+/* File: mips/OP_IPUT_SHORT.S */
+/* File: mips/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IPUT_SHORT_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .LOP_IPUT_SHORT_finish # yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SGET: /* 0x60 */
+/* File: mips/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry !null?
+ bnez a0, .LOP_SGET_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SGET_finish # resume
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SGET_WIDE: /* 0x61 */
+/* File: mips/OP_SGET_WIDE.S */
+ /*
+ * 64-bit SGET handler.
+ */
+ # sget-wide vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_SGET_WIDE_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ *
+ * Returns StaticField pointer in v0.
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+
+ b .LOP_SGET_WIDE_finish # resume
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SGET_OBJECT: /* 0x62 */
+/* File: mips/OP_SGET_OBJECT.S */
+/* File: mips/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry !null?
+ bnez a0, .LOP_SGET_OBJECT_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SGET_OBJECT_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SGET_BOOLEAN: /* 0x63 */
+/* File: mips/OP_SGET_BOOLEAN.S */
+/* File: mips/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry !null?
+ bnez a0, .LOP_SGET_BOOLEAN_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SGET_BOOLEAN_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SGET_BYTE: /* 0x64 */
+/* File: mips/OP_SGET_BYTE.S */
+/* File: mips/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry !null?
+ bnez a0, .LOP_SGET_BYTE_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SGET_BYTE_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SGET_CHAR: /* 0x65 */
+/* File: mips/OP_SGET_CHAR.S */
+/* File: mips/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry !null?
+ bnez a0, .LOP_SGET_CHAR_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SGET_CHAR_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SGET_SHORT: /* 0x66 */
+/* File: mips/OP_SGET_SHORT.S */
+/* File: mips/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry !null?
+ bnez a0, .LOP_SGET_SHORT_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SGET_SHORT_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPUT: /* 0x67 */
+/* File: mips/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .LOP_SPUT_finish # is resolved entry null?
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SPUT_finish # resume
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPUT_WIDE: /* 0x68 */
+/* File: mips/OP_SPUT_WIDE.S */
+ /*
+ * 64-bit SPUT handler.
+ */
+ # sput-wide vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ GET_OPA(t0) # t0 <- AA
+ LOAD_eas2(a2, rBIX, a1) # a2 <- resolved StaticField ptr
+ EAS2(rOBJ, rFP, t0) # rOBJ<- &fp[AA]
+ # is resolved entry null?
+ beqz a2, .LOP_SPUT_WIDE_resolve # yes, do resolve
+.LOP_SPUT_WIDE_finish: # field ptr in a2, AA in rOBJ
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+ GET_INST_OPCODE(rBIX) # extract opcode from rINST
+ .if 0
+ addu a2, offStaticField_value # a2<- pointer to data
+ JAL(dvmQuasiAtomicSwap64Sync) # stores a0/a1 into addr a2
+ .else
+ STORE64_off(a0, a1, a2, offStaticField_value) # field <- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(rBIX) # jump to next instruction
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPUT_OBJECT: /* 0x69 */
+/* File: mips/OP_SPUT_OBJECT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput-object, sput-object-volatile
+ */
+ /* op vAA, field@BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .LOP_SPUT_OBJECT_finish # is resolved entry null?
+
+ /* Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SPUT_OBJECT_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: mips/OP_SPUT_BOOLEAN.S */
+/* File: mips/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .LOP_SPUT_BOOLEAN_finish # is resolved entry null?
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SPUT_BOOLEAN_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPUT_BYTE: /* 0x6b */
+/* File: mips/OP_SPUT_BYTE.S */
+/* File: mips/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .LOP_SPUT_BYTE_finish # is resolved entry null?
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SPUT_BYTE_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPUT_CHAR: /* 0x6c */
+/* File: mips/OP_SPUT_CHAR.S */
+/* File: mips/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .LOP_SPUT_CHAR_finish # is resolved entry null?
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SPUT_CHAR_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPUT_SHORT: /* 0x6d */
+/* File: mips/OP_SPUT_SHORT.S */
+/* File: mips/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .LOP_SPUT_SHORT_finish # is resolved entry null?
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SPUT_SHORT_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: mips/OP_INVOKE_VIRTUAL.S */
+ /*
+ * Handle a virtual method call.
+ *
+ * for: invoke-virtual, invoke-virtual/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ FETCH(rBIX, 2) # rBIX <- GFED or CCCC
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved baseMethod
+ .if (!0)
+ and rBIX, rBIX, 15 # rBIX <- D (or stays CCCC)
+ .endif
+ EXPORT_PC() # must export for invoke
+ # already resolved?
+ bnez a0, .LOP_INVOKE_VIRTUAL_continue # yes, continue on
+
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_VIRTUAL # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ bnez v0, .LOP_INVOKE_VIRTUAL_continue # no, continue
+ b common_exceptionThrown # yes, handle exception
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_SUPER: /* 0x6f */
+/* File: mips/OP_INVOKE_SUPER.S */
+ /*
+ * Handle a "super" method call.
+ *
+ * for: invoke-super, invoke-super/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ FETCH(t0, 2) # t0 <- GFED or CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ .if (!0)
+ and t0, t0, 15 # t0 <- D (or stays CCCC)
+ .endif
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ GET_VREG(rOBJ, t0) # rOBJ <- "this" ptr
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved baseMethod
+ # null "this"?
+ LOAD_rSELF_method(t1) # t1 <- current method
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ # cmp a0, 0; already resolved?
+ LOAD_base_offMethod_clazz(rBIX, t1) # rBIX <- method->clazz
+ EXPORT_PC() # must export for invoke
+ bnez a0, .LOP_INVOKE_SUPER_continue # resolved, continue on
+
+ move a0, rBIX # a0 <- method->clazz
+ li a2, METHOD_VIRTUAL # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b .LOP_INVOKE_SUPER_continue
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: mips/OP_INVOKE_DIRECT.S */
+ /*
+ * Handle a direct method call.
+ *
+ * (We could defer the "is 'this' pointer null" test to the common
+ * method invocation code, and use a flag to indicate that static
+ * calls don't count. If we do this as part of copying the arguments
+ * out we could avoiding loading the first arg twice.)
+ *
+ * for: invoke-direct, invoke-direct/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ FETCH(rBIX, 2) # rBIX <- GFED or CCCC
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved methodToCall
+ .if (!0)
+ and rBIX, rBIX, 15 # rBIX <- D (or stays CCCC)
+ .endif
+ EXPORT_PC() # must export for invoke
+ GET_VREG(rOBJ, rBIX) # rOBJ <- "this" ptr
+ # already resolved?
+ bnez a0, 1f # resolved, call the function
+
+ lw a3, offThread_method(rSELF) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_DIRECT # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+
+1:
+ bnez rOBJ, common_invokeMethodNoRange # a0=method, rOBJ="this"
+ b common_errNullObject # yes, throw exception
+
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_STATIC: /* 0x71 */
+/* File: mips/OP_INVOKE_STATIC.S */
+ /*
+ * Handle a static method call.
+ *
+ * for: invoke-static, invoke-static/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ li rOBJ, 0 # null "this" in delay slot
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved methodToCall
+#if defined(WITH_JIT)
+ EAS2(rBIX, a3, a1) # rBIX<- &resolved_metherToCall
+#endif
+ EXPORT_PC() # must export for invoke
+ # already resolved?
+ bnez a0, common_invokeMethodNoRange # yes, continue on
+ b .LOP_INVOKE_STATIC_resolve
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: mips/OP_INVOKE_INTERFACE.S */
+ /*
+ * Handle an interface method call.
+ *
+ * for: invoke-interface, invoke-interface/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(a2, 2) # a2 <- FEDC or CCCC
+ FETCH(a1, 1) # a1 <- BBBB
+ .if (!0)
+ and a2, 15 # a2 <- C (or stays CCCC)
+ .endif
+ EXPORT_PC() # must export for invoke
+ GET_VREG(rOBJ, a2) # rOBJ <- first arg ("this")
+ LOAD_rSELF_methodClassDex(a3) # a3 <- methodClassDex
+ LOAD_rSELF_method(a2) # a2 <- method
+ # null obj?
+ beqz rOBJ, common_errNullObject # yes, fail
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- thisPtr->clazz
+ JAL(dvmFindInterfaceMethodInCache) # v0 <- call(class, ref, method, dex)
+ move a0, v0
+ # failed?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b common_invokeMethodNoRange # (a0=method, rOBJ="this")
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_UNUSED_73: /* 0x73 */
+/* File: mips/OP_UNUSED_73.S */
+/* File: mips/unused.S */
+ BAL(common_abort)
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: mips/OP_INVOKE_VIRTUAL_RANGE.S */
+/* File: mips/OP_INVOKE_VIRTUAL.S */
+ /*
+ * Handle a virtual method call.
+ *
+ * for: invoke-virtual, invoke-virtual/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ FETCH(rBIX, 2) # rBIX <- GFED or CCCC
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved baseMethod
+ .if (!1)
+ and rBIX, rBIX, 15 # rBIX <- D (or stays CCCC)
+ .endif
+ EXPORT_PC() # must export for invoke
+ # already resolved?
+ bnez a0, .LOP_INVOKE_VIRTUAL_RANGE_continue # yes, continue on
+
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_VIRTUAL # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ bnez v0, .LOP_INVOKE_VIRTUAL_RANGE_continue # no, continue
+ b common_exceptionThrown # yes, handle exception
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: mips/OP_INVOKE_SUPER_RANGE.S */
+/* File: mips/OP_INVOKE_SUPER.S */
+ /*
+ * Handle a "super" method call.
+ *
+ * for: invoke-super, invoke-super/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ FETCH(t0, 2) # t0 <- GFED or CCCC
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ .if (!1)
+ and t0, t0, 15 # t0 <- D (or stays CCCC)
+ .endif
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ GET_VREG(rOBJ, t0) # rOBJ <- "this" ptr
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved baseMethod
+ # null "this"?
+ LOAD_rSELF_method(t1) # t1 <- current method
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ # cmp a0, 0; already resolved?
+ LOAD_base_offMethod_clazz(rBIX, t1) # rBIX <- method->clazz
+ EXPORT_PC() # must export for invoke
+ bnez a0, .LOP_INVOKE_SUPER_RANGE_continue # resolved, continue on
+
+ move a0, rBIX # a0 <- method->clazz
+ li a2, METHOD_VIRTUAL # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b .LOP_INVOKE_SUPER_RANGE_continue
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: mips/OP_INVOKE_DIRECT_RANGE.S */
+/* File: mips/OP_INVOKE_DIRECT.S */
+ /*
+ * Handle a direct method call.
+ *
+ * (We could defer the "is 'this' pointer null" test to the common
+ * method invocation code, and use a flag to indicate that static
+ * calls don't count. If we do this as part of copying the arguments
+ * out we could avoiding loading the first arg twice.)
+ *
+ * for: invoke-direct, invoke-direct/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ FETCH(rBIX, 2) # rBIX <- GFED or CCCC
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved methodToCall
+ .if (!1)
+ and rBIX, rBIX, 15 # rBIX <- D (or stays CCCC)
+ .endif
+ EXPORT_PC() # must export for invoke
+ GET_VREG(rOBJ, rBIX) # rOBJ <- "this" ptr
+ # already resolved?
+ bnez a0, 1f # resolved, call the function
+
+ lw a3, offThread_method(rSELF) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_DIRECT # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+
+1:
+ bnez rOBJ, common_invokeMethodRange # a0=method, rOBJ="this"
+ b common_errNullObject # yes, throw exception
+
+
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: mips/OP_INVOKE_STATIC_RANGE.S */
+/* File: mips/OP_INVOKE_STATIC.S */
+ /*
+ * Handle a static method call.
+ *
+ * for: invoke-static, invoke-static/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ LOAD_rSELF_methodClassDex(a3) # a3 <- pDvmDex
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offDvmDex_pResMethods(a3, a3) # a3 <- pDvmDex->pResMethods
+ li rOBJ, 0 # null "this" in delay slot
+ LOAD_eas2(a0, a3, a1) # a0 <- resolved methodToCall
+#if defined(WITH_JIT)
+ EAS2(rBIX, a3, a1) # rBIX<- &resolved_metherToCall
+#endif
+ EXPORT_PC() # must export for invoke
+ # already resolved?
+ bnez a0, common_invokeMethodRange # yes, continue on
+ b .LOP_INVOKE_STATIC_RANGE_resolve
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: mips/OP_INVOKE_INTERFACE_RANGE.S */
+/* File: mips/OP_INVOKE_INTERFACE.S */
+ /*
+ * Handle an interface method call.
+ *
+ * for: invoke-interface, invoke-interface/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(a2, 2) # a2 <- FEDC or CCCC
+ FETCH(a1, 1) # a1 <- BBBB
+ .if (!1)
+ and a2, 15 # a2 <- C (or stays CCCC)
+ .endif
+ EXPORT_PC() # must export for invoke
+ GET_VREG(rOBJ, a2) # rOBJ <- first arg ("this")
+ LOAD_rSELF_methodClassDex(a3) # a3 <- methodClassDex
+ LOAD_rSELF_method(a2) # a2 <- method
+ # null obj?
+ beqz rOBJ, common_errNullObject # yes, fail
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- thisPtr->clazz
+ JAL(dvmFindInterfaceMethodInCache) # v0 <- call(class, ref, method, dex)
+ move a0, v0
+ # failed?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ b common_invokeMethodRange # (a0=method, rOBJ="this")
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_UNUSED_79: /* 0x79 */
+/* File: mips/OP_UNUSED_79.S */
+/* File: mips/unused.S */
+ BAL(common_abort)
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_UNUSED_7A: /* 0x7a */
+/* File: mips/OP_UNUSED_7A.S */
+/* File: mips/unused.S */
+ BAL(common_abort)
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_NEG_INT: /* 0x7b */
+/* File: mips/OP_NEG_INT.S */
+/* File: mips/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(t0) # t0 <- A+
+ GET_VREG(a0, a3) # a0 <- vB
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+ negu a0, a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ SET_VREG_GOTO(a0, t0, t1) # vAA <- result0
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_NOT_INT: /* 0x7c */
+/* File: mips/OP_NOT_INT.S */
+/* File: mips/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(t0) # t0 <- A+
+ GET_VREG(a0, a3) # a0 <- vB
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+ not a0, a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ SET_VREG_GOTO(a0, t0, t1) # vAA <- result0
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_NEG_LONG: /* 0x7d */
+/* File: mips/OP_NEG_LONG.S */
+/* File: mips/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0/a1".
+ * This could be MIPS instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ GET_OPA4(t1) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+ EAS2(rOBJ, rFP, t1) # rOBJ <- &fp[A]
+ LOAD64(a0, a1, a3) # a0/a1 <- vAA
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ negu v0, a0 # optional op
+ negu v1, a1; sltu a0, zero, v0; subu v1, v1, a0 # a0/a1 <- op, a2-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-13 instructions */
+
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_NOT_LONG: /* 0x7e */
+/* File: mips/OP_NOT_LONG.S */
+/* File: mips/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0/a1".
+ * This could be MIPS instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ GET_OPA4(t1) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+ EAS2(rOBJ, rFP, t1) # rOBJ <- &fp[A]
+ LOAD64(a0, a1, a3) # a0/a1 <- vAA
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ not a0, a0 # optional op
+ not a1, a1 # a0/a1 <- op, a2-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, rOBJ) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_NEG_FLOAT: /* 0x7f */
+/* File: mips/OP_NEG_FLOAT.S */
+/* File: mips/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(t0) # t0 <- A+
+ GET_VREG(a0, a3) # a0 <- vB
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+ addu a0, a0, 0x80000000 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ SET_VREG_GOTO(a0, t0, t1) # vAA <- result0
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_NEG_DOUBLE: /* 0x80 */
+/* File: mips/OP_NEG_DOUBLE.S */
+/* File: mips/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0/a1".
+ * This could be MIPS instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ GET_OPA4(t1) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+ EAS2(rOBJ, rFP, t1) # rOBJ <- &fp[A]
+ LOAD64(a0, a1, a3) # a0/a1 <- vAA
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+ addu a1, a1, 0x80000000 # a0/a1 <- op, a2-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, rOBJ) # vAA <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INT_TO_LONG: /* 0x81 */
+/* File: mips/OP_INT_TO_LONG.S */
+/* File: mips/unopWider.S */
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0", where
+ * "result" is a 64-bit quantity in a0/a1.
+ *
+ * For: int-to-long, int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ GET_OPA4(t1) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, a3) # a0 <- vB
+ EAS2(rOBJ, rFP, t1) # rOBJ <- &fp[A]
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+ sra a1, a0, 31 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, rOBJ) # vA/vA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-11 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: mips/OP_INT_TO_FLOAT.S */
+/* File: mips/unflop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: int-to-float, float-to-int
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(rOBJ) # t0 <- A+
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, a3) # a0 <- vB
+#else
+ GET_VREG_F(fa0, a3)
+#endif
+ # optional op
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+#ifdef SOFT_FLOAT
+ JAL(__floatsisf) # a0 <- op, a0-a3 changed
+
+.LOP_INT_TO_FLOAT_set_vreg:
+ SET_VREG(v0, rOBJ) # vAA <- result0
+#else
+ cvt.s.w fv0, fa0
+
+.LOP_INT_TO_FLOAT_set_vreg_f:
+ SET_VREG_F(fv0, rOBJ)
+#endif
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ GOTO_OPCODE(t1) # jump to next instruction
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: mips/OP_INT_TO_DOUBLE.S */
+/* File: mips/unflopWider.S */
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0", where
+ * "result" is a 64-bit quantity in a0/a1.
+ *
+ * For: int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, a3) # a0 <- vB
+#else
+ GET_VREG_F(fa0, a3)
+#endif
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__floatsidf) # result <- op, a0-a3 changed
+
+.LOP_INT_TO_DOUBLE_set_vreg:
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vA/vA+1 <- a0/a1
+#else
+ cvt.d.w fv0, fa0
+
+.LOP_INT_TO_DOUBLE_set_vreg:
+ STORE64_F(fv0, fv0f, rOBJ) # vA/vA+1 <- a0/a1
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-11 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_LONG_TO_INT: /* 0x84 */
+/* File: mips/OP_LONG_TO_INT.S */
+ GET_OPB(a1) # a1 <- B from 15:12
+ GET_OPA4(a0) # a0 <- A from 11:8
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+#ifdef HAVE_BIG_ENDIAN
+ addu a1, a1, 1
+#endif
+ GET_VREG(a2, a1) # a2 <- fp[B]
+ GET_INST_OPCODE(t0) # t0 <- opcode from rINST
+ SET_VREG_GOTO(a2, a0, t0) # fp[A] <- a2
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: mips/OP_LONG_TO_FLOAT.S */
+/* File: mips/unopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0/a1", where
+ * "result" is a 32-bit quantity in a0.
+ *
+ * For: long-to-float, double-to-int, double-to-float
+ * If hard floating point support is available, use fa0 as the parameter, except for
+ * long-to-float opcode.
+ * (This would work for long-to-int, but that instruction is actually
+ * an exact match for OP_MOVE.)
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(rOBJ) # t1 <- A+
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a3) # a0/a1 <- vB/vB+1
+#else
+ LOAD64(rARG0, rARG1, a3)
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__floatdisf) # a0 <- op, a0-a3 changed
+
+.LOP_LONG_TO_FLOAT_set_vreg:
+ SET_VREG(v0, rOBJ) # vA <- result0
+#else
+ JAL(__floatdisf)
+
+.LOP_LONG_TO_FLOAT_set_vreg_f:
+ SET_VREG_F(fv0, rOBJ) # vA <- result0
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-11 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: mips/OP_LONG_TO_DOUBLE.S */
+/* File: mips/unflopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0/a1".
+ * This could be a MIPS instruction or a function call.
+ *
+ * long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ GET_OPA4(rOBJ) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # t1 <- &fp[A]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a3) # a0/a1 <- vAA
+#else
+ LOAD64(rARG0, rARG1, a3)
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+ JAL(__floatdidf) # a0/a1 <- op, a2-a3 changed
+
+.LOP_LONG_TO_DOUBLE_set_vreg:
+#ifdef SOFT_FLOAT
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vAA <- a0/a1
+#else
+ STORE64_F(fv0, fv0f, rOBJ) # vAA <- a0/a1
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: mips/OP_FLOAT_TO_INT.S */
+/* File: mips/unflop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: int-to-float, float-to-int
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(rOBJ) # t0 <- A+
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, a3) # a0 <- vB
+#else
+ GET_VREG_F(fa0, a3)
+#endif
+ # optional op
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+#ifdef SOFT_FLOAT
+ b f2i_doconv # a0 <- op, a0-a3 changed
+
+.LOP_FLOAT_TO_INT_set_vreg:
+ SET_VREG(v0, rOBJ) # vAA <- result0
+#else
+ b f2i_doconv
+
+.LOP_FLOAT_TO_INT_set_vreg_f:
+ SET_VREG_F(fv0, rOBJ)
+#endif
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ GOTO_OPCODE(t1) # jump to next instruction
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: mips/OP_FLOAT_TO_LONG.S */
+/* File: mips/unflopWider.S */
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0", where
+ * "result" is a 64-bit quantity in a0/a1.
+ *
+ * For: int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, a3) # a0 <- vB
+#else
+ GET_VREG_F(fa0, a3)
+#endif
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ b f2l_doconv # result <- op, a0-a3 changed
+
+.LOP_FLOAT_TO_LONG_set_vreg:
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vA/vA+1 <- a0/a1
+#else
+ b f2l_doconv
+
+.LOP_FLOAT_TO_LONG_set_vreg:
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vA/vA+1 <- a0/a1
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-11 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: mips/OP_FLOAT_TO_DOUBLE.S */
+/* File: mips/unflopWider.S */
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0", where
+ * "result" is a 64-bit quantity in a0/a1.
+ *
+ * For: int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, a3) # a0 <- vB
+#else
+ GET_VREG_F(fa0, a3)
+#endif
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__extendsfdf2) # result <- op, a0-a3 changed
+
+.LOP_FLOAT_TO_DOUBLE_set_vreg:
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vA/vA+1 <- a0/a1
+#else
+ cvt.d.s fv0, fa0
+
+.LOP_FLOAT_TO_DOUBLE_set_vreg:
+ STORE64_F(fv0, fv0f, rOBJ) # vA/vA+1 <- a0/a1
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-11 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: mips/OP_DOUBLE_TO_INT.S */
+/* File: mips/unopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0/a1", where
+ * "result" is a 32-bit quantity in a0.
+ *
+ * For: long-to-float, double-to-int, double-to-float
+ * If hard floating point support is available, use fa0 as the parameter, except for
+ * long-to-float opcode.
+ * (This would work for long-to-int, but that instruction is actually
+ * an exact match for OP_MOVE.)
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(rOBJ) # t1 <- A+
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a3) # a0/a1 <- vB/vB+1
+#else
+ LOAD64_F(fa0, fa0f, a3)
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ b d2i_doconv # a0 <- op, a0-a3 changed
+
+.LOP_DOUBLE_TO_INT_set_vreg:
+ SET_VREG(v0, rOBJ) # vA <- result0
+#else
+ b d2i_doconv
+
+.LOP_DOUBLE_TO_INT_set_vreg_f:
+ SET_VREG_F(fv0, rOBJ) # vA <- result0
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-11 instructions */
+
+/*
+ * Convert the double in a0/a1 to an int in a0.
+ *
+ * We have to clip values to int min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ * Use rBIX / rTEMP as global to hold arguments (they are not bound to a global var)
+ */
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: mips/OP_DOUBLE_TO_LONG.S */
+/* File: mips/unflopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0/a1".
+ * This could be a MIPS instruction or a function call.
+ *
+ * long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ GET_OPA4(rOBJ) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # t1 <- &fp[A]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a3) # a0/a1 <- vAA
+#else
+ LOAD64_F(fa0, fa0f, a3)
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+ b d2l_doconv # a0/a1 <- op, a2-a3 changed
+
+.LOP_DOUBLE_TO_LONG_set_vreg:
+#ifdef SOFT_FLOAT
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vAA <- a0/a1
+#else
+ STORE64(rRESULT0, rRESULT1, rOBJ) # vAA <- a0/a1
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: mips/OP_DOUBLE_TO_FLOAT.S */
+/* File: mips/unopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op a0/a1", where
+ * "result" is a 32-bit quantity in a0.
+ *
+ * For: long-to-float, double-to-int, double-to-float
+ * If hard floating point support is available, use fa0 as the parameter, except for
+ * long-to-float opcode.
+ * (This would work for long-to-int, but that instruction is actually
+ * an exact match for OP_MOVE.)
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(rOBJ) # t1 <- A+
+ EAS2(a3, rFP, a3) # a3 <- &fp[B]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a3) # a0/a1 <- vB/vB+1
+#else
+ LOAD64_F(fa0, fa0f, a3)
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__truncdfsf2) # a0 <- op, a0-a3 changed
+
+.LOP_DOUBLE_TO_FLOAT_set_vreg:
+ SET_VREG(v0, rOBJ) # vA <- result0
+#else
+ cvt.s.d fv0, fa0
+
+.LOP_DOUBLE_TO_FLOAT_set_vreg_f:
+ SET_VREG_F(fv0, rOBJ) # vA <- result0
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-11 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INT_TO_BYTE: /* 0x8d */
+/* File: mips/OP_INT_TO_BYTE.S */
+/* File: mips/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(t0) # t0 <- A+
+ GET_VREG(a0, a3) # a0 <- vB
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ sll a0, a0, 24 # optional op
+ sra a0, a0, 24 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ SET_VREG_GOTO(a0, t0, t1) # vAA <- result0
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INT_TO_CHAR: /* 0x8e */
+/* File: mips/OP_INT_TO_CHAR.S */
+/* File: mips/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(t0) # t0 <- A+
+ GET_VREG(a0, a3) # a0 <- vB
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+ and a0, 0xffff # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ SET_VREG_GOTO(a0, t0, t1) # vAA <- result0
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INT_TO_SHORT: /* 0x8f */
+/* File: mips/OP_INT_TO_SHORT.S */
+/* File: mips/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op a0".
+ * This could be a MIPS instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ GET_OPB(a3) # a3 <- B
+ GET_OPA4(t0) # t0 <- A+
+ GET_VREG(a0, a3) # a0 <- vB
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ sll a0, 16 # optional op
+ sra a0, 16 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ SET_VREG_GOTO(a0, t0, t1) # vAA <- result0
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ADD_INT: /* 0x90 */
+/* File: mips/OP_ADD_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+ addu a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SUB_INT: /* 0x91 */
+/* File: mips/OP_SUB_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+ subu a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MUL_INT: /* 0x92 */
+/* File: mips/OP_MUL_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+ mul a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DIV_INT: /* 0x93 */
+/* File: mips/OP_DIV_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 1
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+ div zero, a0, a1; mflo a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_REM_INT: /* 0x94 */
+/* File: mips/OP_REM_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 1
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+ div zero, a0, a1; mfhi a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AND_INT: /* 0x95 */
+/* File: mips/OP_AND_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+ and a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_OR_INT: /* 0x96 */
+/* File: mips/OP_OR_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+ or a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_XOR_INT: /* 0x97 */
+/* File: mips/OP_XOR_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+ xor a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SHL_INT: /* 0x98 */
+/* File: mips/OP_SHL_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ and a1, a1, 31 # optional op
+ sll a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SHR_INT: /* 0x99 */
+/* File: mips/OP_SHR_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ and a1, a1, 31 # optional op
+ sra a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_USHR_INT: /* 0x9a */
+/* File: mips/OP_USHR_INT.S */
+/* File: mips/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0 op a1".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ and a1, a1, 31 # optional op
+ srl a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ADD_LONG: /* 0x9b */
+/* File: mips/OP_ADD_LONG.S */
+/*
+ * The compiler generates the following sequence for
+ * [v1 v0] = [a1 a0] + [a3 a2];
+ * addu v0,a2,a0
+ * addu a1,a3,a1
+ * sltu v1,v0,a2
+ * addu v1,v1,a1
+ */
+/* File: mips/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a0, a1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a2, a3, t1) # a2/a3 <- vCC/vCC+1
+ .if 0
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ addu v0, a2, a0 # optional op
+ addu a1, a3, a1; sltu v1, v0, a2; addu v1, v1, a1 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- v0/v1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SUB_LONG: /* 0x9c */
+/* File: mips/OP_SUB_LONG.S */
+/*
+ * For little endian the code sequence looks as follows:
+ * subu v0,a0,a2
+ * subu v1,a1,a3
+ * sltu a0,a0,v0
+ * subu v1,v1,a0
+ */
+/* File: mips/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a0, a1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a2, a3, t1) # a2/a3 <- vCC/vCC+1
+ .if 0
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ subu v0, a0, a2 # optional op
+ subu v1, a1, a3; sltu a0, a0, v0; subu v1, v1, a0 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- v0/v1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MUL_LONG: /* 0x9d */
+/* File: mips/OP_MUL_LONG.S */
+ /*
+ * Signed 64-bit integer multiply.
+ * a1 a0
+ * x a3 a2
+ * -------------
+ * a2a1 a2a0
+ * a3a0
+ * a3a1 (<= unused)
+ * ---------------
+ * v1 v0
+ */
+ /* mul-long vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ and t0, a0, 255 # a2 <- BB
+ srl t1, a0, 8 # a3 <- CC
+ EAS2(t0, rFP, t0) # t0 <- &fp[BB]
+ LOAD64(a0, a1, t0) # a0/a1 <- vBB/vBB+1
+
+ EAS2(t1, rFP, t1) # t0 <- &fp[CC]
+ LOAD64(a2, a3, t1) # a2/a3 <- vCC/vCC+1
+
+ mul v1, a3, a0 # v1= a3a0
+ multu a2, a0
+ mfhi t1
+ mflo v0 # v0= a2a0
+ mul t0, a2, a1 # t0= a2a1
+ addu v1, v1, t1 # v1+= hi(a2a0)
+ addu v1, v1, t0 # v1= a3a0 + a2a1;
+
+ GET_OPA(a0) # a0 <- AA
+ EAS2(a0, rFP, a0) # a0 <- &fp[A]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ b .LOP_MUL_LONG_finish
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DIV_LONG: /* 0x9e */
+/* File: mips/OP_DIV_LONG.S */
+#ifdef HAVE_LITTLE_ENDIAN
+/* File: mips/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a0, a1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a2, a3, t1) # a2/a3 <- vCC/vCC+1
+ .if 1
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ JAL(__divdi3) # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- v0/v1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+#else
+/* File: mips/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a1, a0, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a3, a2, t1) # a2/a3 <- vCC/vCC+1
+ .if 1
+ or t0, a3, a2 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ JAL(__divdi3) # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v1, v0, rOBJ) # vAA/vAA+1 <- v1/v0
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+#endif
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_REM_LONG: /* 0x9f */
+/* File: mips/OP_REM_LONG.S */
+/* ldivmod returns quotient in a0/a1 and remainder in a2/a3 */
+#ifdef HAVE_LITTLE_ENDIAN
+/* File: mips/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a0, a1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a2, a3, t1) # a2/a3 <- vCC/vCC+1
+ .if 1
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ JAL(__moddi3) # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- v0/v1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+#else
+/* File: mips/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a1, a0, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a3, a2, t1) # a2/a3 <- vCC/vCC+1
+ .if 1
+ or t0, a3, a2 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ JAL(__moddi3) # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v1, v0, rOBJ) # vAA/vAA+1 <- v1/v0
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+#endif
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AND_LONG: /* 0xa0 */
+/* File: mips/OP_AND_LONG.S */
+/* File: mips/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a0, a1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a2, a3, t1) # a2/a3 <- vCC/vCC+1
+ .if 0
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ and a0, a0, a2 # optional op
+ and a1, a1, a3 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, rOBJ) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_OR_LONG: /* 0xa1 */
+/* File: mips/OP_OR_LONG.S */
+/* File: mips/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a0, a1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a2, a3, t1) # a2/a3 <- vCC/vCC+1
+ .if 0
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ or a0, a0, a2 # optional op
+ or a1, a1, a3 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, rOBJ) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_XOR_LONG: /* 0xa2 */
+/* File: mips/OP_XOR_LONG.S */
+/* File: mips/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+ LOAD64(a0, a1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(a2, a3, t1) # a2/a3 <- vCC/vCC+1
+ .if 0
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ xor a0, a0, a2 # optional op
+ xor a1, a1, a3 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, rOBJ) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SHL_LONG: /* 0xa3 */
+/* File: mips/OP_SHL_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* shl-long vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(t2) # t2 <- AA
+ and a3, a0, 255 # a3 <- BB
+ srl a0, a0, 8 # a0 <- CC
+ EAS2(a3, rFP, a3) # a3 <- &fp[BB]
+ GET_VREG(a2, a0) # a2 <- vCC
+ LOAD64(a0, a1, a3) # a0/a1 <- vBB/vBB+1
+
+ EAS2(t2, rFP, t2) # t2 <- &fp[AA]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ sll v0, a0, a2 # rlo<- alo << (shift&31)
+ not v1, a2 # rhi<- 31-shift (shift is 5b)
+ srl a0, 1
+ srl a0, v1 # alo<- alo >> (32-(shift&31))
+ sll v1, a1, a2 # rhi<- ahi << (shift&31)
+ or v1, a0 # rhi<- rhi | alo
+ andi a2, 0x20 # shift< shift & 0x20
+ movn v1, v0, a2 # rhi<- rlo (if shift&0x20)
+ movn v0, zero, a2 # rlo<- 0 (if shift&0x20)
+
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, t2) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SHR_LONG: /* 0xa4 */
+/* File: mips/OP_SHR_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* shr-long vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(t3) # t3 <- AA
+ and a3, a0, 255 # a3 <- BB
+ srl a0, a0, 8 # a0 <- CC
+ EAS2(a3, rFP, a3) # a3 <- &fp[BB]
+ GET_VREG(a2, a0) # a2 <- vCC
+ LOAD64(a0, a1, a3) # a0/a1 <- vBB/vBB+1
+ EAS2(t3, rFP, t3) # t3 <- &fp[AA]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ sra v1, a1, a2 # rhi<- ahi >> (shift&31)
+ srl v0, a0, a2 # rlo<- alo >> (shift&31)
+ sra a3, a1, 31 # a3<- sign(ah)
+ not a0, a2 # alo<- 31-shift (shift is 5b)
+ sll a1, 1
+ sll a1, a0 # ahi<- ahi << (32-(shift&31))
+ or v0, a1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn v0, v1, a2 # rlo<- rhi (if shift&0x20)
+ movn v1, a3, a2 # rhi<- sign(ahi) (if shift&0x20)
+
+ STORE64(v0, v1, t3) # vAA/VAA+1 <- v0/v0
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_USHR_LONG: /* 0xa5 */
+/* File: mips/OP_USHR_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* ushr-long vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(t0) # t3 <- AA
+ and a3, a0, 255 # a3 <- BB
+ srl a0, a0, 8 # a0 <- CC
+ EAS2(a3, rFP, a3) # a3 <- &fp[BB]
+ GET_VREG(a2, a0) # a2 <- vCC
+ LOAD64(a0, a1, a3) # a0/a1 <- vBB/vBB+1
+ EAS2(rOBJ, rFP, t0) # rOBJ <- &fp[AA]
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ srl v1, a1, a2 # rhi<- ahi >> (shift&31)
+ srl v0, a0, a2 # rlo<- alo >> (shift&31)
+ not a0, a2 # alo<- 31-n (shift is 5b)
+ sll a1, 1
+ sll a1, a0 # ahi<- ahi << (32-(shift&31))
+ or v0, a1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn v0, v1, a2 # rlo<- rhi (if shift&0x20)
+ movn v1, zero, a2 # rhi<- 0 (if shift&0x20)
+
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- v0/v1
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ADD_FLOAT: /* 0xa6 */
+/* File: mips/OP_ADD_FLOAT.S */
+/* File: mips/binflop.S */
+ /*
+ * Generic 32-bit binary float operation.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ */
+
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+#ifdef SOFT_FLOAT
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa1, a3) # a1 <- vCC
+ GET_VREG_F(fa0, a2) # a0 <- vBB
+
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__addsf3) # v0 = result
+ SET_VREG(v0, rOBJ) # vAA <- v0
+#else
+ add.s fv0, fa0, fa1 # f0 = result
+ SET_VREG_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SUB_FLOAT: /* 0xa7 */
+/* File: mips/OP_SUB_FLOAT.S */
+/* File: mips/binflop.S */
+ /*
+ * Generic 32-bit binary float operation.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ */
+
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+#ifdef SOFT_FLOAT
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa1, a3) # a1 <- vCC
+ GET_VREG_F(fa0, a2) # a0 <- vBB
+
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__subsf3) # v0 = result
+ SET_VREG(v0, rOBJ) # vAA <- v0
+#else
+ sub.s fv0, fa0, fa1 # f0 = result
+ SET_VREG_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MUL_FLOAT: /* 0xa8 */
+/* File: mips/OP_MUL_FLOAT.S */
+/* File: mips/binflop.S */
+ /*
+ * Generic 32-bit binary float operation.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ */
+
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+#ifdef SOFT_FLOAT
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa1, a3) # a1 <- vCC
+ GET_VREG_F(fa0, a2) # a0 <- vBB
+
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__mulsf3) # v0 = result
+ SET_VREG(v0, rOBJ) # vAA <- v0
+#else
+ mul.s fv0, fa0, fa1 # f0 = result
+ SET_VREG_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DIV_FLOAT: /* 0xa9 */
+/* File: mips/OP_DIV_FLOAT.S */
+/* File: mips/binflop.S */
+ /*
+ * Generic 32-bit binary float operation.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ */
+
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+#ifdef SOFT_FLOAT
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa1, a3) # a1 <- vCC
+ GET_VREG_F(fa0, a2) # a0 <- vBB
+
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__divsf3) # v0 = result
+ SET_VREG(v0, rOBJ) # vAA <- v0
+#else
+ div.s fv0, fa0, fa1 # f0 = result
+ SET_VREG_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_REM_FLOAT: /* 0xaa */
+/* File: mips/OP_REM_FLOAT.S */
+/* File: mips/binflop.S */
+ /*
+ * Generic 32-bit binary float operation.
+ *
+ * For: add-fp, sub-fp, mul-fp, div-fp
+ */
+
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ srl a3, a0, 8 # a3 <- CC
+ and a2, a0, 255 # a2 <- BB
+#ifdef SOFT_FLOAT
+ GET_VREG(a1, a3) # a1 <- vCC
+ GET_VREG(a0, a2) # a0 <- vBB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa1, a3) # a1 <- vCC
+ GET_VREG_F(fa0, a2) # a0 <- vBB
+
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1 # condition bit and comparision with 0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(fmodf) # v0 = result
+ SET_VREG(v0, rOBJ) # vAA <- v0
+#else
+ JAL(fmodf) # f0 = result
+ SET_VREG_F(fv0, rOBJ) # vAA <- fv0
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ADD_DOUBLE: /* 0xab */
+/* File: mips/OP_ADD_DOUBLE.S */
+/* File: mips/binflopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # s5 <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3 <- vCC/vCC+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, a2)
+ LOAD64_F(fa1, fa1f, t1)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__adddf3) # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ add.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SUB_DOUBLE: /* 0xac */
+/* File: mips/OP_SUB_DOUBLE.S */
+/* File: mips/binflopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # s5 <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3 <- vCC/vCC+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, a2)
+ LOAD64_F(fa1, fa1f, t1)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__subdf3) # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ sub.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MUL_DOUBLE: /* 0xad */
+/* File: mips/OP_MUL_DOUBLE.S */
+/* File: mips/binflopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # s5 <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3 <- vCC/vCC+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, a2)
+ LOAD64_F(fa1, fa1f, t1)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__muldf3) # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ mul.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DIV_DOUBLE: /* 0xae */
+/* File: mips/OP_DIV_DOUBLE.S */
+/* File: mips/binflopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # s5 <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3 <- vCC/vCC+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, a2)
+ LOAD64_F(fa1, fa1f, t1)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__divdf3) # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ div.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_REM_DOUBLE: /* 0xaf */
+/* File: mips/OP_REM_DOUBLE.S */
+/* File: mips/binflopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(a0, 1) # a0 <- CCBB
+ GET_OPA(rOBJ) # s5 <- AA
+ and a2, a0, 255 # a2 <- BB
+ srl a3, a0, 8 # a3 <- CC
+ EAS2(rOBJ, rFP, rOBJ) # s5 <- &fp[AA]
+ EAS2(a2, rFP, a2) # a2 <- &fp[BB]
+ EAS2(t1, rFP, a3) # a3 <- &fp[CC]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG0, rARG1, a2) # a0/a1 <- vBB/vBB+1
+ LOAD64(rARG2, rARG3, t1) # a2/a3 <- vCC/vCC+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, a2)
+ LOAD64_F(fa1, fa1f, t1)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(fmod) # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ JAL(fmod)
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: mips/OP_ADD_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ addu a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: mips/OP_SUB_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ subu a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: mips/OP_MUL_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ mul a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: mips/OP_DIV_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 1
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ div zero, a0, a1; mflo a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: mips/OP_REM_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 1
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ div zero, a0, a1; mfhi a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: mips/OP_AND_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ and a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: mips/OP_OR_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ or a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: mips/OP_XOR_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ xor a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: mips/OP_SHL_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ and a1, a1, 31 # optional op
+ sll a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: mips/OP_SHR_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ and a1, a1, 31 # optional op
+ sra a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: mips/OP_USHR_INT_2ADDR.S */
+/* File: mips/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ and a1, a1, 31 # optional op
+ srl a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: mips/OP_ADD_LONG_2ADDR.S */
+/*
+ *See OP_ADD_LONG.S for details
+ */
+/* File: mips/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ LOAD64(a2, a3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 0
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ addu v0, a2, a0 # optional op
+ addu a1, a3, a1; sltu v1, v0, a2; addu v1, v1, a1 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- v0/v1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: mips/OP_SUB_LONG_2ADDR.S */
+/*
+ * See comments in OP_SUB_LONG.S
+ */
+/* File: mips/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ LOAD64(a2, a3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 0
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ subu v0, a0, a2 # optional op
+ subu v1, a1, a3; sltu a0, a0, v0; subu v1, v1, a0 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- v0/v1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: mips/OP_MUL_LONG_2ADDR.S */
+ /*
+ * See comments in OP_MUL_LONG.S
+ */
+ /* mul-long/2addr vA, vB */
+ GET_OPA4(t0) # t0 <- A+
+
+ EAS2(t0, rFP, t0) # t0 <- &fp[A]
+ LOAD64(a0, a1, t0) # vAA.low / high
+
+ GET_OPB(t1) # t1 <- B
+ EAS2(t1, rFP, t1) # t1 <- &fp[B]
+ LOAD64(a2, a3, t1) # vBB.low / high
+
+ mul v1, a3, a0 # v1= a3a0
+ multu a2, a0
+ mfhi t1
+ mflo v0 # v0= a2a0
+ mul t2, a2, a1 # t2= a2a1
+ addu v1, v1, t1 # v1= a3a0 + hi(a2a0)
+ addu v1, v1, t2 # v1= v1 + a2a1;
+
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ GET_INST_OPCODE(t1) # extract opcode from rINST
+ # vAA <- v0 (low)
+ STORE64(v0, v1, t0) # vAA+1 <- v1 (high)
+ GOTO_OPCODE(t1) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: mips/OP_DIV_LONG_2ADDR.S */
+#ifdef HAVE_LITTLE_ENDIAN
+/* File: mips/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ LOAD64(a2, a3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 1
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ JAL(__divdi3) # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- v0/v1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+#else
+/* File: mips/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ LOAD64(a3, a2, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(a1, a0, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 1
+ or t0, a3, a2 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ JAL(__divdi3) # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v1, v0, rOBJ) # vAA/vAA+1 <- v1/v0
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+#endif
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: mips/OP_REM_LONG_2ADDR.S */
+#ifdef HAVE_LITTLE_ENDIAN
+/* File: mips/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ LOAD64(a2, a3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 1
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ JAL(__moddi3) # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- v0/v1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+#else
+/* File: mips/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ LOAD64(a3, a2, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(a1, a0, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 1
+ or t0, a3, a2 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ # optional op
+ JAL(__moddi3) # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v1, v0, rOBJ) # vAA/vAA+1 <- v1/v0
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+#endif
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: mips/OP_AND_LONG_2ADDR.S */
+/* File: mips/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ LOAD64(a2, a3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 0
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ and a0, a0, a2 # optional op
+ and a1, a1, a3 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, rOBJ) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: mips/OP_OR_LONG_2ADDR.S */
+/* File: mips/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ LOAD64(a2, a3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 0
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ or a0, a0, a2 # optional op
+ or a1, a1, a3 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, rOBJ) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: mips/OP_XOR_LONG_2ADDR.S */
+/* File: mips/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be a MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+ LOAD64(a2, a3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 0
+ or t0, a2, a3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ xor a0, a0, a2 # optional op
+ xor a1, a1, a3 # result <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, rOBJ) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: mips/OP_SHL_LONG_2ADDR.S */
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* shl-long/2addr vA, vB */
+ GET_OPA4(t2) # t2 <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a2, a3) # a2 <- vB
+ EAS2(rOBJ, rFP, t2) # rOBJ <- &fp[A]
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ sll v0, a0, a2 # rlo<- alo << (shift&31)
+ not v1, a2 # rhi<- 31-shift (shift is 5b)
+ srl a0, 1
+ srl a0, v1 # alo<- alo >> (32-(shift&31))
+ sll v1, a1, a2 # rhi<- ahi << (shift&31)
+ or v1, a0 # rhi<- rhi | alo
+ andi a2, 0x20 # shift< shift & 0x20
+ movn v1, v0, a2 # rhi<- rlo (if shift&0x20)
+ movn v0, zero, a2 # rlo<- 0 (if shift&0x20)
+
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, rOBJ) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: mips/OP_SHR_LONG_2ADDR.S */
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* shr-long/2addr vA, vB */
+ GET_OPA4(t2) # t2 <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a2, a3) # a2 <- vB
+ EAS2(t2, rFP, t2) # t2 <- &fp[A]
+ LOAD64(a0, a1, t2) # a0/a1 <- vAA/vAA+1
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+
+ sra v1, a1, a2 # rhi<- ahi >> (shift&31)
+ srl v0, a0, a2 # rlo<- alo >> (shift&31)
+ sra a3, a1, 31 # a3<- sign(ah)
+ not a0, a2 # alo<- 31-shift (shift is 5b)
+ sll a1, 1
+ sll a1, a0 # ahi<- ahi << (32-(shift&31))
+ or v0, a1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn v0, v1, a2 # rlo<- rhi (if shift&0x20)
+ movn v1, a3, a2 # rhi<- sign(ahi) (if shift&0x20)
+
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, t2) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: mips/OP_USHR_LONG_2ADDR.S */
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* ushr-long/2addr vA, vB */
+ GET_OPA4(t3) # t3 <- A+
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a2, a3) # a2 <- vB
+ EAS2(t3, rFP, t3) # t3 <- &fp[A]
+ LOAD64(a0, a1, t3) # a0/a1 <- vAA/vAA+1
+
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ srl v1, a1, a2 # rhi<- ahi >> (shift&31)
+ srl v0, a0, a2 # rlo<- alo >> (shift&31)
+ not a0, a2 # alo<- 31-n (shift is 5b)
+ sll a1, 1
+ sll a1, a0 # ahi<- ahi << (32-(shift&31))
+ or v0, a1 # rlo<- rlo | ahi
+ andi a2, 0x20 # shift & 0x20
+ movn v0, v1, a2 # rlo<- rhi (if shift&0x20)
+ movn v1, zero, a2 # rhi<- 0 (if shift&0x20)
+
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, t3) # vAA/vAA+1 <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: mips/OP_ADD_FLOAT_2ADDR.S */
+/* File: mips/binflop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" and
+ * "instr_f" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr,
+ * div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa0, rOBJ)
+ GET_VREG_F(fa1, a3)
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__addsf3) # result <- op, a0-a3 changed
+ SET_VREG(v0, rOBJ) # vAA <- result
+#else
+ add.s fv0, fa0, fa1
+ SET_VREG_F(fv0, rOBJ) # vAA <- result
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: mips/OP_SUB_FLOAT_2ADDR.S */
+/* File: mips/binflop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" and
+ * "instr_f" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr,
+ * div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa0, rOBJ)
+ GET_VREG_F(fa1, a3)
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__subsf3) # result <- op, a0-a3 changed
+ SET_VREG(v0, rOBJ) # vAA <- result
+#else
+ sub.s fv0, fa0, fa1
+ SET_VREG_F(fv0, rOBJ) # vAA <- result
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: mips/OP_MUL_FLOAT_2ADDR.S */
+/* File: mips/binflop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" and
+ * "instr_f" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr,
+ * div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa0, rOBJ)
+ GET_VREG_F(fa1, a3)
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__mulsf3) # result <- op, a0-a3 changed
+ SET_VREG(v0, rOBJ) # vAA <- result
+#else
+ mul.s fv0, fa0, fa1
+ SET_VREG_F(fv0, rOBJ) # vAA <- result
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: mips/OP_DIV_FLOAT_2ADDR.S */
+/* File: mips/binflop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" and
+ * "instr_f" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr,
+ * div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa0, rOBJ)
+ GET_VREG_F(fa1, a3)
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__divsf3) # result <- op, a0-a3 changed
+ SET_VREG(v0, rOBJ) # vAA <- result
+#else
+ div.s fv0, fa0, fa1
+ SET_VREG_F(fv0, rOBJ) # vAA <- result
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: mips/OP_REM_FLOAT_2ADDR.S */
+/* File: mips/binflop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" and
+ * "instr_f" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr,
+ * div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # t1 <- A+
+ GET_OPB(a3) # a3 <- B
+#ifdef SOFT_FLOAT
+ GET_VREG(a0, rOBJ) # a0 <- vA
+ GET_VREG(a1, a3) # a1 <- vB
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+#else
+ GET_VREG_F(fa0, rOBJ)
+ GET_VREG_F(fa1, a3)
+ .if 0
+ # is second operand zero?
+ li.s ft0, 0
+ c.eq.s fcc0, ft0, fa1
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(fmodf) # result <- op, a0-a3 changed
+ SET_VREG(v0, rOBJ) # vAA <- result
+#else
+ JAL(fmodf)
+ SET_VREG_F(fv0, rOBJ) # vAA <- result
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: mips/OP_ADD_DOUBLE_2ADDR.S */
+/* File: mips/binflopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr, rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG2, rARG3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, rOBJ)
+ LOAD64_F(fa1, fa1f, a1)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__adddf3) # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ add.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: mips/OP_SUB_DOUBLE_2ADDR.S */
+/* File: mips/binflopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr, rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG2, rARG3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, rOBJ)
+ LOAD64_F(fa1, fa1f, a1)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__subdf3) # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ sub.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: mips/OP_MUL_DOUBLE_2ADDR.S */
+/* File: mips/binflopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr, rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG2, rARG3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, rOBJ)
+ LOAD64_F(fa1, fa1f, a1)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__muldf3) # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ mul.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: mips/OP_DIV_DOUBLE_2ADDR.S */
+/* File: mips/binflopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr, rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG2, rARG3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, rOBJ)
+ LOAD64_F(fa1, fa1f, a1)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(__divdf3) # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ div.d fv0, fa0, fa1
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: mips/OP_REM_DOUBLE_2ADDR.S */
+/* File: mips/binflopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0-a1 op a2-a3".
+ * This could be an MIPS instruction or a function call.
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr, rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ GET_OPA4(rOBJ) # rOBJ <- A+
+ GET_OPB(a1) # a1 <- B
+ EAS2(a1, rFP, a1) # a1 <- &fp[B]
+ EAS2(rOBJ, rFP, rOBJ) # rOBJ <- &fp[A]
+#ifdef SOFT_FLOAT
+ LOAD64(rARG2, rARG3, a1) # a2/a3 <- vBB/vBB+1
+ LOAD64(rARG0, rARG1, rOBJ) # a0/a1 <- vAA/vAA+1
+ .if 0
+ or t0, rARG2, rARG3 # second arg (a2-a3) is zero?
+ beqz t0, common_errDivideByZero
+ .endif
+#else
+ LOAD64_F(fa0, fa0f, rOBJ)
+ LOAD64_F(fa1, fa1f, a1)
+ .if 0
+ li.d ft0, 0
+ c.eq.d fcc0, fa1, ft0
+ bc1t fcc0, common_errDivideByZero
+ .endif
+#endif
+1:
+ FETCH_ADVANCE_INST(1) # advance rPC, load rINST
+ # optional op
+#ifdef SOFT_FLOAT
+ JAL(fmod) # result <- op, a0-a3 changed
+ STORE64(rRESULT0, rRESULT1, rOBJ)
+#else
+ JAL(fmod)
+ STORE64_F(fv0, fv0f, rOBJ)
+#endif
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: mips/OP_ADD_INT_LIT16.S */
+/* File: mips/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ # binop/lit16 vA, vB, /* +CCCC */
+ FETCH_S(a1, 1) # a1 <- ssssCCCC (sign-extended)
+ GET_OPB(a2) # a2 <- B
+ GET_OPA(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a2) # a0 <- vB
+ and rOBJ, rOBJ, 15
+ .if 0
+ # cmp a1, 0; is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ addu a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_RSUB_INT: /* 0xd1 */
+/* File: mips/OP_RSUB_INT.S */
+/* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */
+/* File: mips/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ # binop/lit16 vA, vB, /* +CCCC */
+ FETCH_S(a1, 1) # a1 <- ssssCCCC (sign-extended)
+ GET_OPB(a2) # a2 <- B
+ GET_OPA(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a2) # a0 <- vB
+ and rOBJ, rOBJ, 15
+ .if 0
+ # cmp a1, 0; is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ subu a0, a1, a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: mips/OP_MUL_INT_LIT16.S */
+/* File: mips/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ # binop/lit16 vA, vB, /* +CCCC */
+ FETCH_S(a1, 1) # a1 <- ssssCCCC (sign-extended)
+ GET_OPB(a2) # a2 <- B
+ GET_OPA(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a2) # a0 <- vB
+ and rOBJ, rOBJ, 15
+ .if 0
+ # cmp a1, 0; is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ mul a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: mips/OP_DIV_INT_LIT16.S */
+/* File: mips/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ # binop/lit16 vA, vB, /* +CCCC */
+ FETCH_S(a1, 1) # a1 <- ssssCCCC (sign-extended)
+ GET_OPB(a2) # a2 <- B
+ GET_OPA(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a2) # a0 <- vB
+ and rOBJ, rOBJ, 15
+ .if 1
+ # cmp a1, 0; is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ div zero, a0, a1; mflo a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: mips/OP_REM_INT_LIT16.S */
+/* File: mips/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ # binop/lit16 vA, vB, /* +CCCC */
+ FETCH_S(a1, 1) # a1 <- ssssCCCC (sign-extended)
+ GET_OPB(a2) # a2 <- B
+ GET_OPA(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a2) # a0 <- vB
+ and rOBJ, rOBJ, 15
+ .if 1
+ # cmp a1, 0; is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ div zero, a0, a1; mfhi a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: mips/OP_AND_INT_LIT16.S */
+/* File: mips/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ # binop/lit16 vA, vB, /* +CCCC */
+ FETCH_S(a1, 1) # a1 <- ssssCCCC (sign-extended)
+ GET_OPB(a2) # a2 <- B
+ GET_OPA(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a2) # a0 <- vB
+ and rOBJ, rOBJ, 15
+ .if 0
+ # cmp a1, 0; is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ and a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: mips/OP_OR_INT_LIT16.S */
+/* File: mips/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ # binop/lit16 vA, vB, /* +CCCC */
+ FETCH_S(a1, 1) # a1 <- ssssCCCC (sign-extended)
+ GET_OPB(a2) # a2 <- B
+ GET_OPA(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a2) # a0 <- vB
+ and rOBJ, rOBJ, 15
+ .if 0
+ # cmp a1, 0; is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ or a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: mips/OP_XOR_INT_LIT16.S */
+/* File: mips/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ # binop/lit16 vA, vB, /* +CCCC */
+ FETCH_S(a1, 1) # a1 <- ssssCCCC (sign-extended)
+ GET_OPB(a2) # a2 <- B
+ GET_OPA(rOBJ) # rOBJ <- A+
+ GET_VREG(a0, a2) # a0 <- vB
+ and rOBJ, rOBJ, 15
+ .if 0
+ # cmp a1, 0; is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ xor a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: mips/OP_ADD_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ addu a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: mips/OP_RSUB_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ subu a0, a1, a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_MUL_INT_LIT8: /* 0xda */
+/* File: mips/OP_MUL_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ mul a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: mips/OP_DIV_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 1
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ div zero, a0, a1; mflo a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_REM_INT_LIT8: /* 0xdc */
+/* File: mips/OP_REM_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 1
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ div zero, a0, a1; mfhi a0 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_AND_INT_LIT8: /* 0xdd */
+/* File: mips/OP_AND_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ and a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_OR_INT_LIT8: /* 0xde */
+/* File: mips/OP_OR_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ or a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: mips/OP_XOR_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ # optional op
+ xor a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: mips/OP_SHL_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ and a1, a1, 31 # optional op
+ sll a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: mips/OP_SHR_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ and a1, a1, 31 # optional op
+ sra a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: mips/OP_USHR_INT_LIT8.S */
+/* File: mips/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = a0 op a1".
+ * This could be an MIPS instruction or a function call. (If the result
+ * comes back in a register other than a0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (a1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ # binop/lit8 vAA, vBB, /* +CC */
+ FETCH_S(a3, 1) # a3 <- ssssCCBB (sign-extended for CC)
+ GET_OPA(rOBJ) # rOBJ <- AA
+ and a2, a3, 255 # a2 <- BB
+ GET_VREG(a0, a2) # a0 <- vBB
+ sra a1, a3, 8 # a1 <- ssssssCC (sign extended)
+ .if 0
+ # is second operand zero?
+ beqz a1, common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+
+ and a1, a1, 31 # optional op
+ srl a0, a0, a1 # a0 <- op, a0-a3 changed
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a0, rOBJ, t0) # vAA <- a0
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: mips/OP_IGET_VOLATILE.S */
+/* File: mips/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IGET_VOLATILE_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test results
+ move a0, v0
+ bnez v0, .LOP_IGET_VOLATILE_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: mips/OP_IPUT_VOLATILE.S */
+/* File: mips/OP_IPUT.S */
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IPUT_VOLATILE_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .LOP_IPUT_VOLATILE_finish # yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: mips/OP_SGET_VOLATILE.S */
+/* File: mips/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry !null?
+ bnez a0, .LOP_SGET_VOLATILE_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SGET_VOLATILE_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: mips/OP_SPUT_VOLATILE.S */
+/* File: mips/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .LOP_SPUT_VOLATILE_finish # is resolved entry null?
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SPUT_VOLATILE_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: mips/OP_IGET_OBJECT_VOLATILE.S */
+/* File: mips/OP_IGET.S */
+ /*
+ * General 32-bit instance field get.
+ *
+ * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IGET_OBJECT_VOLATILE_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test results
+ move a0, v0
+ bnez v0, .LOP_IGET_OBJECT_VOLATILE_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: mips/OP_IGET_WIDE_VOLATILE.S */
+/* File: mips/OP_IGET_WIDE.S */
+ /*
+ * Wide 32-bit instance field get.
+ */
+ # iget-wide vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IGET_WIDE_VOLATILE_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # test return code
+ move a0, v0
+ bnez v0, .LOP_IGET_WIDE_VOLATILE_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: mips/OP_IPUT_WIDE_VOLATILE.S */
+/* File: mips/OP_IPUT_WIDE.S */
+ # iput-wide vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IPUT_WIDE_VOLATILE_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .LOP_IPUT_WIDE_VOLATILE_finish # yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: mips/OP_SGET_WIDE_VOLATILE.S */
+/* File: mips/OP_SGET_WIDE.S */
+ /*
+ * 64-bit SGET handler.
+ */
+ # sget-wide vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_SGET_WIDE_VOLATILE_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ *
+ * Returns StaticField pointer in v0.
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+
+ b .LOP_SGET_WIDE_VOLATILE_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: mips/OP_SPUT_WIDE_VOLATILE.S */
+/* File: mips/OP_SPUT_WIDE.S */
+ /*
+ * 64-bit SPUT handler.
+ */
+ # sput-wide vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ GET_OPA(t0) # t0 <- AA
+ LOAD_eas2(a2, rBIX, a1) # a2 <- resolved StaticField ptr
+ EAS2(rOBJ, rFP, t0) # rOBJ<- &fp[AA]
+ # is resolved entry null?
+ beqz a2, .LOP_SPUT_WIDE_VOLATILE_resolve # yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_finish: # field ptr in a2, AA in rOBJ
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- vAA/vAA+1
+ GET_INST_OPCODE(rBIX) # extract opcode from rINST
+ .if 1
+ addu a2, offStaticField_value # a2<- pointer to data
+ JAL(dvmQuasiAtomicSwap64Sync) # stores a0/a1 into addr a2
+ .else
+ STORE64_off(a0, a1, a2, offStaticField_value) # field <- vAA/vAA+1
+ .endif
+ GOTO_OPCODE(rBIX) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_BREAKPOINT: /* 0xec */
+ /* (stub) */
+ SAVE_PC_TO_SELF() # only need to export PC and FP
+ SAVE_FP_TO_SELF()
+ move a0, rSELF # self is first arg to function
+ JAL(dvmMterp_OP_BREAKPOINT) # call
+ LOAD_PC_FROM_SELF() # retrieve updated values
+ LOAD_FP_FROM_SELF()
+ FETCH_INST() # load next instruction from rPC
+ GET_INST_OPCODE(t0) # ...trim down to just the opcode
+ GOTO_OPCODE(t0) # ...and jump to the handler
+/* ------------------------------ */
+ .balign 128
+.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: mips/OP_THROW_VERIFICATION_ERROR.S */
+ /*
+ * Handle a throw-verification-error instruction. This throws an
+ * exception for an error discovered during verification. The
+ * exception is indicated by AA, with some detail provided by BBBB.
+ */
+ /* op AA, ref@BBBB */
+
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ FETCH(a2, 1) # a2 <- BBBB
+ EXPORT_PC() # export the PC
+ GET_OPA(a1) # a1 <- AA
+ JAL(dvmThrowVerificationError) # always throws
+ b common_exceptionThrown # handle exception
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_EXECUTE_INLINE: /* 0xee */
+/* File: mips/OP_EXECUTE_INLINE.S */
+ /*
+ * Execute a "native inline" instruction.
+ *
+ * We need to call an InlineOp4Func:
+ * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+ *
+ * The first four args are in a0-a3, pointer to return value storage
+ * is on the stack. The function's return value is a flag that tells
+ * us if an exception was thrown.
+ *
+ * TUNING: could maintain two tables, pointer in Thread and
+ * swap if profiler/debuggger active.
+ */
+ /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+ lhu a2, offThread_subMode(rSELF)
+ FETCH(rBIX, 1) # rBIX <- BBBB
+ EXPORT_PC() # can throw
+ and a2, kSubModeDebugProfile # Any going on?
+ bnez a2, .LOP_EXECUTE_INLINE_debugmode # yes - take slow path
+.LOP_EXECUTE_INLINE_resume:
+ addu a1, rSELF, offThread_retval # a1 <- &self->retval
+ GET_OPB(a0) # a0 <- B
+ # Stack should have 16/20 available
+ sw a1, STACK_OFFSET_ARG04(sp) # push &self->retval
+ BAL(.LOP_EXECUTE_INLINE_continue) # make call; will return after
+ lw gp, STACK_OFFSET_GP(sp) # restore gp
+ # test boolean result of inline
+ beqz v0, common_exceptionThrown # returned false, handle exception
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: mips/OP_EXECUTE_INLINE_RANGE.S */
+ /*
+ * Execute a "native inline" instruction, using "/range" semantics.
+ * Same idea as execute-inline, but we get the args differently.
+ *
+ * We need to call an InlineOp4Func:
+ * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+ *
+ * The first four args are in a0-a3, pointer to return value storage
+ * is on the stack. The function's return value is a flag that tells
+ * us if an exception was thrown.
+ */
+ /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */
+ lhu a2, offThread_subMode(rSELF)
+ FETCH(rBIX, 1) # rBIX<- BBBB
+ EXPORT_PC() # can throw
+ and a2, kSubModeDebugProfile # Any going on?
+ bnez a2, .LOP_EXECUTE_INLINE_RANGE_debugmode # yes - take slow path
+.LOP_EXECUTE_INLINE_RANGE_resume:
+ addu a1, rSELF, offThread_retval # a1<- &self->retval
+ GET_OPA(a0)
+ sw a1, STACK_OFFSET_ARG04(sp) # push &self->retval
+ BAL(.LOP_EXECUTE_INLINE_RANGE_continue) # make call; will return after
+ lw gp, STACK_OFFSET_GP(sp) # restore gp
+ beqz v0, common_exceptionThrown # returned false, handle exception
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: mips/OP_INVOKE_OBJECT_INIT_RANGE.S */
+ /*
+ * Invoke Object.<init> on an object. In practice we know that
+ * Object's nullary constructor doesn't do anything, so we just
+ * skip it unless a debugger is active.
+ */
+ FETCH(a1, 2) # a1<- CCCC
+ GET_VREG(a0, a1) # a0<- "this" ptr
+ # check for NULL
+ beqz a0, common_errNullObject # export PC and throw NPE
+ LOAD_base_offObject_clazz(a1, a0) # a1<- obj->clazz
+ LOAD_base_offClassObject_accessFlags(a2, a1) # a2<- clazz->accessFlags
+ and a2, CLASS_ISFINALIZABLE # is this class finalizable?
+ beqz a2, .LOP_INVOKE_OBJECT_INIT_RANGE_finish # no, go
+
+.LOP_INVOKE_OBJECT_INIT_RANGE_setFinal:
+ EXPORT_PC() # can throw
+ JAL(dvmSetFinalizable) # call dvmSetFinalizable(obj)
+ LOAD_offThread_exception(a0, rSELF) # a0<- self->exception
+ # exception pending?
+ bnez a0, common_exceptionThrown # yes, handle it
+
+.LOP_INVOKE_OBJECT_INIT_RANGE_finish:
+ lhu a1, offThread_subMode(rSELF)
+ and a1, kSubModeDebuggerActive # debugger active?
+ bnez a1, .LOP_INVOKE_OBJECT_INIT_RANGE_debugger # Yes - skip optimization
+ FETCH_ADVANCE_INST(2+1) # advance to next instr, load rINST
+ GET_INST_OPCODE(t0) # t0<- opcode from rINST
+ GOTO_OPCODE(t0) # execute it
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: mips/OP_RETURN_VOID_BARRIER.S */
+ SMP_DMB
+ b common_returnFromMethod
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_QUICK: /* 0xf2 */
+/* File: mips/OP_IGET_QUICK.S */
+ /* For: iget-quick, iget-object-quick */
+ # op vA, vB, offset /* CCCC */
+ GET_OPB(a2) # a2 <- B
+ GET_VREG(a3, a2) # a3 <- object we're operating on
+ FETCH(a1, 1) # a1 <- field byte offset
+ GET_OPA4(a2) # a2 <- A(+)
+ # check object for null
+ beqz a3, common_errNullObject # object was null
+ addu t0, a3, a1 #
+ lw a0, 0(t0) # a0 <- obj.field (always 32 bits)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: mips/OP_IGET_WIDE_QUICK.S */
+ # iget-wide-quick vA, vB, offset /* CCCC */
+ GET_OPB(a2) # a2 <- B
+ GET_VREG(a3, a2) # a3 <- object we're operating on
+ FETCH(a1, 1) # a1 <- field byte offset
+ GET_OPA4(a2) # a2 <- A(+)
+ # check object for null
+ beqz a3, common_errNullObject # object was null
+ addu t0, a3, a1 # t0 <- a3 + a1
+ LOAD64(a0, a1, t0) # a0 <- obj.field (64 bits, aligned)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a3, rFP, a2)
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # fp[A] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* File: mips/OP_IGET_OBJECT_QUICK.S */
+/* File: mips/OP_IGET_QUICK.S */
+ /* For: iget-quick, iget-object-quick */
+ # op vA, vB, offset /* CCCC */
+ GET_OPB(a2) # a2 <- B
+ GET_VREG(a3, a2) # a3 <- object we're operating on
+ FETCH(a1, 1) # a1 <- field byte offset
+ GET_OPA4(a2) # a2 <- A(+)
+ # check object for null
+ beqz a3, common_errNullObject # object was null
+ addu t0, a3, a1 #
+ lw a0, 0(t0) # a0 <- obj.field (always 32 bits)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_QUICK: /* 0xf5 */
+/* File: mips/OP_IPUT_QUICK.S */
+ /* For: iput-quick, iput-object-quick */
+ # op vA, vB, offset /* CCCC */
+ GET_OPB(a2) # a2 <- B
+ GET_VREG(a3, a2) # a3 <- fp[B], the object pointer
+ FETCH(a1, 1) # a1 <- field byte offset
+ GET_OPA4(a2) # a2 <- A(+)
+ beqz a3, common_errNullObject # object was null
+ GET_VREG(a0, a2) # a0 <- fp[A]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ addu t0, a3, a1
+ sw a0, 0(t0) # obj.field (always 32 bits) <- a0
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: mips/OP_IPUT_WIDE_QUICK.S */
+ # iput-wide-quick vA, vB, offset /* CCCC */
+ GET_OPA4(a0) # a0 <- A(+)
+ GET_OPB(a1) # a1 <- B
+ GET_VREG(a2, a1) # a2 <- fp[B], the object pointer
+ EAS2(a3, rFP, a0) # a3 <- &fp[A]
+ LOAD64(a0, a1, a3) # a0/a1 <- fp[A]
+ # check object for null
+ beqz a2, common_errNullObject # object was null
+ FETCH(a3, 1) # a3 <- field byte offset
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ addu a2, a2, a3 # obj.field (64 bits, aligned) <- a0/a1
+ STORE64(a0, a1, a2) # obj.field (64 bits, aligned) <- a0/a1
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
+/* File: mips/OP_IPUT_OBJECT_QUICK.S */
+ /* For: iput-object-quick */
+ # op vA, vB, offset /* CCCC */
+ GET_OPB(a2) # a2 <- B
+ GET_VREG(a3, a2) # a3 <- fp[B], the object pointer
+ FETCH(a1, 1) # a1 <- field byte offset
+ GET_OPA4(a2) # a2 <- A(+)
+ beqz a3, common_errNullObject # object was null
+ GET_VREG(a0, a2) # a0 <- fp[A]
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ addu t0, a3, a1
+ sw a0, 0(t0) # obj.field (always 32 bits) <- a0
+ beqz a0, 1f
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ srl t1, a3, GC_CARD_SHIFT
+ addu t2, a2, t1
+ sb a2, 0(t2)
+1:
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: mips/OP_INVOKE_VIRTUAL_QUICK.S */
+ /*
+ * Handle an optimized virtual method call.
+ *
+ * for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ FETCH(a3, 2) # a3 <- FEDC or CCCC
+ FETCH(a1, 1) # a1 <- BBBB
+ .if (!0)
+ and a3, a3, 15 # a3 <- C (or stays CCCC)
+ .endif
+ GET_VREG(rOBJ, a3) # rOBJ <- vC ("this" ptr)
+ # is "this" null?
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ LOAD_base_offObject_clazz(a2, rOBJ) # a2 <- thisPtr->clazz
+ LOAD_base_offClassObject_vtable(a2, a2) # a2 <- thisPtr->clazz->vtable
+ EXPORT_PC() # invoke must export
+ LOAD_eas2(a0, a2, a1) # a0 <- vtable[BBBB]
+ b common_invokeMethodNoRange # (a0=method, r9="this")
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: mips/OP_INVOKE_VIRTUAL_QUICK_RANGE.S */
+/* File: mips/OP_INVOKE_VIRTUAL_QUICK.S */
+ /*
+ * Handle an optimized virtual method call.
+ *
+ * for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ FETCH(a3, 2) # a3 <- FEDC or CCCC
+ FETCH(a1, 1) # a1 <- BBBB
+ .if (!1)
+ and a3, a3, 15 # a3 <- C (or stays CCCC)
+ .endif
+ GET_VREG(rOBJ, a3) # rOBJ <- vC ("this" ptr)
+ # is "this" null?
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ LOAD_base_offObject_clazz(a2, rOBJ) # a2 <- thisPtr->clazz
+ LOAD_base_offClassObject_vtable(a2, a2) # a2 <- thisPtr->clazz->vtable
+ EXPORT_PC() # invoke must export
+ LOAD_eas2(a0, a2, a1) # a0 <- vtable[BBBB]
+ b common_invokeMethodRange # (a0=method, r9="this")
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: mips/OP_INVOKE_SUPER_QUICK.S */
+ /*
+ * Handle an optimized "super" method call.
+ *
+ * for: [opt] invoke-super-quick, invoke-super-quick/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ FETCH(t0, 2) # t0 <- GFED or CCCC
+ LOAD_rSELF_method(a2) # a2 <- current method
+ .if (!0)
+ and t0, t0, 15 # t0 <- D (or stays CCCC)
+ .endif
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offMethod_clazz(a2, a2) # a2 <- method->clazz
+ EXPORT_PC() # must export for invoke
+ LOAD_base_offClassObject_super(a2, a2) # a2 <- method->clazz->super
+ GET_VREG(rOBJ, t0) # rOBJ <- "this"
+ LOAD_base_offClassObject_vtable(a2, a2) # a2 <- ...clazz->super->vtable
+ # is "this" null ?
+ LOAD_eas2(a0, a2, a1) # a0 <- super->vtable[BBBB]
+ beqz rOBJ, common_errNullObject # "this" is null, throw exception
+ b common_invokeMethodNoRange # (a0=method, rOBJ="this")
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: mips/OP_INVOKE_SUPER_QUICK_RANGE.S */
+/* File: mips/OP_INVOKE_SUPER_QUICK.S */
+ /*
+ * Handle an optimized "super" method call.
+ *
+ * for: [opt] invoke-super-quick, invoke-super-quick/range
+ */
+ # op vB, {vD, vE, vF, vG, vA}, class /* CCCC */
+ # op vAA, {vCCCC..v(CCCC+AA-1)}, meth /* BBBB */
+ FETCH(t0, 2) # t0 <- GFED or CCCC
+ LOAD_rSELF_method(a2) # a2 <- current method
+ .if (!1)
+ and t0, t0, 15 # t0 <- D (or stays CCCC)
+ .endif
+ FETCH(a1, 1) # a1 <- BBBB
+ LOAD_base_offMethod_clazz(a2, a2) # a2 <- method->clazz
+ EXPORT_PC() # must export for invoke
+ LOAD_base_offClassObject_super(a2, a2) # a2 <- method->clazz->super
+ GET_VREG(rOBJ, t0) # rOBJ <- "this"
+ LOAD_base_offClassObject_vtable(a2, a2) # a2 <- ...clazz->super->vtable
+ # is "this" null ?
+ LOAD_eas2(a0, a2, a1) # a0 <- super->vtable[BBBB]
+ beqz rOBJ, common_errNullObject # "this" is null, throw exception
+ b common_invokeMethodRange # (a0=method, rOBJ="this")
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: mips/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: mips/OP_IPUT_OBJECT.S */
+ /*
+ * 32-bit instance field put.
+ *
+ * for: iput-object, iput-object-volatile
+ */
+ # op vA, vB, field /* CCCC */
+ GET_OPB(a0) # a0 <- B
+ LOAD_rSELF_methodClassDex(a3) # a3 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref CCCC
+ LOAD_base_offDvmDex_pResFields(a2, a3) # a2 <- pDvmDex->pResFields
+ GET_VREG(rOBJ, a0) # rOBJ <- fp[B], the object pointer
+ LOAD_eas2(a0, a2, a1) # a0 <- resolved InstField ptr
+ # is resolved entry null?
+ bnez a0, .LOP_IPUT_OBJECT_VOLATILE_finish # no, already resolved
+ LOAD_rSELF_method(a2) # a2 <- current method
+ EXPORT_PC() # resolve() could throw
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveInstField) # v0 <- resolved InstField ptr
+ # success?
+ move a0, v0
+ bnez v0, .LOP_IPUT_OBJECT_VOLATILE_finish # yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: mips/OP_SGET_OBJECT_VOLATILE.S */
+/* File: mips/OP_SGET.S */
+ /*
+ * General 32-bit SGET handler.
+ *
+ * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+ */
+ # op vAA, field /* BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ # is resolved entry !null?
+ bnez a0, .LOP_SGET_OBJECT_VOLATILE_finish
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ # success?
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SGET_OBJECT_VOLATILE_finish # resume
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: mips/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: mips/OP_SPUT_OBJECT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput-object, sput-object-volatile
+ */
+ /* op vAA, field@BBBB */
+ LOAD_rSELF_methodClassDex(a2) # a2 <- DvmDex
+ FETCH(a1, 1) # a1 <- field ref BBBB
+ LOAD_base_offDvmDex_pResFields(rBIX, a2) # rBIX <- dvmDex->pResFields
+ LOAD_eas2(a0, rBIX, a1) # a0 <- resolved StaticField ptr
+ bnez a0, .LOP_SPUT_OBJECT_VOLATILE_finish # is resolved entry null?
+
+ /* Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rBIX: dvmDex->pResFields
+ */
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() may throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ move a0, v0
+ beqz v0, common_exceptionThrown # success? no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ b .LOP_SPUT_OBJECT_VOLATILE_finish # resume
+
+
+
+/* ------------------------------ */
+ .balign 128
+.L_OP_UNUSED_FF: /* 0xff */
+/* File: mips/OP_UNUSED_FF.S */
+/* File: mips/unused.S */
+ BAL(common_abort)
+
+
+
+ .balign 128
+ .size dvmAsmInstructionStart, .-dvmAsmInstructionStart
+ .global dvmAsmInstructionEnd
+dvmAsmInstructionEnd:
+
+/*
+ * ===========================================================================
+ * Sister implementations
+ * ===========================================================================
+ */
+ .global dvmAsmSisterStart
+ .type dvmAsmSisterStart, %function
+ .text
+ .balign 4
+dvmAsmSisterStart:
+
+/* continuation for OP_CHECK_CAST */
+
+.LOP_CHECK_CAST_castfailure:
+ # A cast has failed. We need to throw a ClassCastException with the
+ # class of the object that failed to be cast.
+ EXPORT_PC() # about to throw
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- obj->clazz
+ move a1,rBIX # r1<- desired class
+ JAL(dvmThrowClassCastException)
+ b common_exceptionThrown
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * a2 holds BBBB
+ * rOBJ holds object
+ */
+.LOP_CHECK_CAST_resolve:
+ EXPORT_PC() # resolve() could throw
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ move a1, a2 # a1 <- BBBB
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- resolved ClassObject ptr
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ move a1, v0 # a1 <- class resolved from BBB
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- obj->clazz
+ b .LOP_CHECK_CAST_resolved # pick up where we left off
+
+/* continuation for OP_INSTANCE_OF */
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * a0 holds obj->clazz
+ * a1 holds class resolved from BBBB
+ * rOBJ holds A
+ */
+.LOP_INSTANCE_OF_fullcheck:
+ JAL(dvmInstanceofNonTrivial) # v0 <- boolean result
+ move a0, v0 # fall through to OP_INSTANCE_OF_store
+ b .LOP_INSTANCE_OF_store
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * a3 holds BBBB
+ * rOBJ holds A
+ */
+.LOP_INSTANCE_OF_resolve:
+ EXPORT_PC() # resolve() could throw
+ LOAD_rSELF_method(a0) # a0 <- self->method
+ move a1, a3 # a1 <- BBBB
+ li a2, 1 # a2 <- true
+ LOAD_base_offMethod_clazz(a0, a0) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- resolved ClassObject ptr
+ # got null?
+ move a1, v0 # a1 <- class resolved from BBB
+ beqz v0, common_exceptionThrown # yes, handle exception
+ GET_OPB(a3) # a3 <- B
+ GET_VREG(a0, a3) # a0 <- vB (object)
+ LOAD_base_offObject_clazz(a0, a0) # a0 <- obj->clazz
+ b .LOP_INSTANCE_OF_resolved # pick up where we left off
+
+
+/* continuation for OP_NEW_INSTANCE */
+
+.LOP_NEW_INSTANCE_continue:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(v0, a3) # vAA <- v0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+#if defined(WITH_JIT)
+ /*
+ * Check to see if we need to stop the trace building early.
+ * v0: new object
+ * a3: vAA
+ */
+.LOP_NEW_INSTANCE_jitCheck:
+ lw a1, 0(rBIX) # reload resolved class
+ # okay?
+ bnez a1, .LOP_NEW_INSTANCE_continue # yes, finish
+ move rOBJ, v0 # preserve new object
+ move rBIX, a3 # preserve vAA
+ move a0, rSELF
+ move a1, rPC
+ JAL(dvmJitEndTraceSelect) # (self, pc)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(rOBJ, rBIX) # vAA <- new object
+ GOTO_OPCODE(t0) # jump to next instruction
+#endif
+
+ /*
+ * Class initialization required.
+ *
+ * a0 holds class object
+ */
+.LOP_NEW_INSTANCE_needinit:
+ JAL(dvmInitClass) # initialize class
+ move a0, rOBJ # restore a0
+ # check boolean result
+ bnez v0, .LOP_NEW_INSTANCE_initialized # success, continue
+ b common_exceptionThrown # failed, deal with init exception
+
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * a1 holds BBBB
+ */
+.LOP_NEW_INSTANCE_resolve:
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- resolved ClassObject ptr
+ move a0, v0
+ # got null?
+ bnez v0, .LOP_NEW_INSTANCE_resolved # no, continue
+ b common_exceptionThrown # yes, handle exception
+
+/* continuation for OP_NEW_ARRAY */
+
+ /*
+ * Resolve class. (This is an uncommon case.)
+ *
+ * a1 holds array length
+ * a2 holds class ref CCCC
+ */
+.LOP_NEW_ARRAY_resolve:
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ move rOBJ, a1 # rOBJ <- length (save)
+ move a1, a2 # a1 <- CCCC
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- call(clazz, ref)
+ move a1, rOBJ # a1 <- length (restore)
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ move a0, v0
+ b .LOP_NEW_ARRAY_finish # continue with OP_NEW_ARRAY_finish
+
+
+
+/* continuation for OP_FILLED_NEW_ARRAY */
+
+ /*
+ * On entry:
+ * a0 holds array class
+ * rOBJ holds AA or BA
+ */
+.LOP_FILLED_NEW_ARRAY_continue:
+ LOAD_base_offClassObject_descriptor(a3, a0) # a3 <- arrayClass->descriptor
+ li a2, ALLOC_DONT_TRACK # a2 <- alloc flags
+ lbu rINST, 1(a3) # rINST <- descriptor[1]
+ .if 0
+ move a1, rOBJ # a1 <- AA (length)
+ .else
+ srl a1, rOBJ, 4 # rOBJ <- B (length)
+ .endif
+ seq t0, rINST, 'I' # array of ints?
+ seq t1, rINST, 'L' # array of objects?
+ or t0, t1
+ seq t1, rINST, '[' # array of arrays?
+ or t0, t1
+ move rBIX, a1 # save length in rBIX
+ beqz t0, .LOP_FILLED_NEW_ARRAY_notimpl # no, not handled yet
+ JAL(dvmAllocArrayByClass) # v0 <- call(arClass, length, flags)
+ # null return?
+ beqz v0, common_exceptionThrown # alloc failed, handle exception
+
+ FETCH(a1, 2) # a1 <- FEDC or CCCC
+ sw v0, offThread_retval(rSELF) # retval.l <- new array
+ sw rINST, (offThread_retval+4)(rSELF) # retval.h <- type
+ addu a0, v0, offArrayObject_contents # a0 <- newArray->contents
+ subu rBIX, rBIX, 1 # length--, check for neg
+ FETCH_ADVANCE_INST(3) # advance to next instr, load rINST
+ bltz rBIX, 2f # was zero, bail
+
+ # copy values from registers into the array
+ # a0=array, a1=CCCC/FEDC, t0=length (from AA or B), rOBJ=AA/BA
+ move t0, rBIX
+ .if 0
+ EAS2(a2, rFP, a1) # a2 <- &fp[CCCC]
+1:
+ lw a3, 0(a2) # a3 <- *a2++
+ addu a2, 4
+ subu t0, t0, 1 # count--
+ sw a3, (a0) # *contents++ = vX
+ addu a0, 4
+ bgez t0, 1b
+
+ # continue at 2
+ .else
+ slt t1, t0, 4 # length was initially 5?
+ and a2, rOBJ, 15 # a2 <- A
+ bnez t1, 1f # <= 4 args, branch
+ GET_VREG(a3, a2) # a3 <- vA
+ subu t0, t0, 1 # count--
+ sw a3, 16(a0) # contents[4] = vA
+1:
+ and a2, a1, 15 # a2 <- F/E/D/C
+ GET_VREG(a3, a2) # a3 <- vF/vE/vD/vC
+ srl a1, a1, 4 # a1 <- next reg in low 4
+ subu t0, t0, 1 # count--
+ sw a3, 0(a0) # *contents++ = vX
+ addu a0, a0, 4
+ bgez t0, 1b
+ # continue at 2
+ .endif
+
+2:
+ lw a0, offThread_retval(rSELF) # a0 <- object
+ lw a1, (offThread_retval+4)(rSELF) # a1 <- type
+ seq t1, a1, 'I' # Is int array?
+ bnez t1, 3f
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ srl t3, a0, GC_CARD_SHIFT
+ addu t2, a2, t3
+ sb a2, (t2)
+3:
+ GET_INST_OPCODE(t0) # ip <- opcode from rINST
+ GOTO_OPCODE(t0) # execute it
+
+
+ /*
+ * Throw an exception indicating that we have not implemented this
+ * mode of filled-new-array.
+ */
+.LOP_FILLED_NEW_ARRAY_notimpl:
+ la a0, .LstrFilledNewArrayNotImpl
+ JAL(dvmThrowInternalError)
+ b common_exceptionThrown
+
+ /*
+ * Ideally we'd only define this once, but depending on layout we can
+ * exceed the range of the load above.
+ */
+
+/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
+
+ /*
+ * On entry:
+ * a0 holds array class
+ * rOBJ holds AA or BA
+ */
+.LOP_FILLED_NEW_ARRAY_RANGE_continue:
+ LOAD_base_offClassObject_descriptor(a3, a0) # a3 <- arrayClass->descriptor
+ li a2, ALLOC_DONT_TRACK # a2 <- alloc flags
+ lbu rINST, 1(a3) # rINST <- descriptor[1]
+ .if 1
+ move a1, rOBJ # a1 <- AA (length)
+ .else
+ srl a1, rOBJ, 4 # rOBJ <- B (length)
+ .endif
+ seq t0, rINST, 'I' # array of ints?
+ seq t1, rINST, 'L' # array of objects?
+ or t0, t1
+ seq t1, rINST, '[' # array of arrays?
+ or t0, t1
+ move rBIX, a1 # save length in rBIX
+ beqz t0, .LOP_FILLED_NEW_ARRAY_RANGE_notimpl # no, not handled yet
+ JAL(dvmAllocArrayByClass) # v0 <- call(arClass, length, flags)
+ # null return?
+ beqz v0, common_exceptionThrown # alloc failed, handle exception
+
+ FETCH(a1, 2) # a1 <- FEDC or CCCC
+ sw v0, offThread_retval(rSELF) # retval.l <- new array
+ sw rINST, (offThread_retval+4)(rSELF) # retval.h <- type
+ addu a0, v0, offArrayObject_contents # a0 <- newArray->contents
+ subu rBIX, rBIX, 1 # length--, check for neg
+ FETCH_ADVANCE_INST(3) # advance to next instr, load rINST
+ bltz rBIX, 2f # was zero, bail
+
+ # copy values from registers into the array
+ # a0=array, a1=CCCC/FEDC, t0=length (from AA or B), rOBJ=AA/BA
+ move t0, rBIX
+ .if 1
+ EAS2(a2, rFP, a1) # a2 <- &fp[CCCC]
+1:
+ lw a3, 0(a2) # a3 <- *a2++
+ addu a2, 4
+ subu t0, t0, 1 # count--
+ sw a3, (a0) # *contents++ = vX
+ addu a0, 4
+ bgez t0, 1b
+
+ # continue at 2
+ .else
+ slt t1, t0, 4 # length was initially 5?
+ and a2, rOBJ, 15 # a2 <- A
+ bnez t1, 1f # <= 4 args, branch
+ GET_VREG(a3, a2) # a3 <- vA
+ subu t0, t0, 1 # count--
+ sw a3, 16(a0) # contents[4] = vA
+1:
+ and a2, a1, 15 # a2 <- F/E/D/C
+ GET_VREG(a3, a2) # a3 <- vF/vE/vD/vC
+ srl a1, a1, 4 # a1 <- next reg in low 4
+ subu t0, t0, 1 # count--
+ sw a3, 0(a0) # *contents++ = vX
+ addu a0, a0, 4
+ bgez t0, 1b
+ # continue at 2
+ .endif
+
+2:
+ lw a0, offThread_retval(rSELF) # a0 <- object
+ lw a1, (offThread_retval+4)(rSELF) # a1 <- type
+ seq t1, a1, 'I' # Is int array?
+ bnez t1, 3f
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ srl t3, a0, GC_CARD_SHIFT
+ addu t2, a2, t3
+ sb a2, (t2)
+3:
+ GET_INST_OPCODE(t0) # ip <- opcode from rINST
+ GOTO_OPCODE(t0) # execute it
+
+
+ /*
+ * Throw an exception indicating that we have not implemented this
+ * mode of filled-new-array.
+ */
+.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
+ la a0, .LstrFilledNewArrayNotImpl
+ JAL(dvmThrowInternalError)
+ b common_exceptionThrown
+
+ /*
+ * Ideally we'd only define this once, but depending on layout we can
+ * exceed the range of the load above.
+ */
+
+/* continuation for OP_CMPL_FLOAT */
+
+OP_CMPL_FLOAT_nan:
+ li rTEMP, -1
+ b OP_CMPL_FLOAT_finish
+
+#ifdef SOFT_FLOAT
+OP_CMPL_FLOAT_continue:
+ JAL(__gtsf2) # v0 <- (vBB > vCC)
+ li rTEMP, 1 # rTEMP = 1 if v0 != 0
+ bgtz v0, OP_CMPL_FLOAT_finish
+ b OP_CMPL_FLOAT_nan
+#endif
+
+OP_CMPL_FLOAT_finish:
+ GET_OPA(t0)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ SET_VREG(rTEMP, t0) # vAA <- rTEMP
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0)
+
+/* continuation for OP_CMPG_FLOAT */
+
+OP_CMPG_FLOAT_nan:
+ li rTEMP, 1
+ b OP_CMPG_FLOAT_finish
+
+#ifdef SOFT_FLOAT
+OP_CMPG_FLOAT_continue:
+ JAL(__gtsf2) # v0 <- (vBB > vCC)
+ li rTEMP, 1 # rTEMP = 1 if v0 != 0
+ bgtz v0, OP_CMPG_FLOAT_finish
+ b OP_CMPG_FLOAT_nan
+#endif
+
+OP_CMPG_FLOAT_finish:
+ GET_OPA(t0)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ SET_VREG(rTEMP, t0) # vAA <- rTEMP
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0)
+
+/* continuation for OP_CMPL_DOUBLE */
+
+OP_CMPL_DOUBLE_nan:
+ li rTEMP, -1
+ b OP_CMPL_DOUBLE_finish
+
+#ifdef SOFT_FLOAT
+OP_CMPL_DOUBLE_continue:
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3 <- vCC/vCC+1
+ JAL(__gtdf2) # fallthru
+ li rTEMP, 1 # rTEMP = 1 if v0 != 0
+ blez v0, OP_CMPL_DOUBLE_nan # fall thru for finish
+#endif
+
+OP_CMPL_DOUBLE_finish:
+ GET_OPA(rOBJ)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(rTEMP, rOBJ, t0) # vAA <- rTEMP
+
+/* continuation for OP_CMPG_DOUBLE */
+
+OP_CMPG_DOUBLE_nan:
+ li rTEMP, 1
+ b OP_CMPG_DOUBLE_finish
+
+#ifdef SOFT_FLOAT
+OP_CMPG_DOUBLE_continue:
+ LOAD64(rARG2, rARG3, rBIX) # a2/a3 <- vCC/vCC+1
+ JAL(__gtdf2) # fallthru
+ li rTEMP, 1 # rTEMP = 1 if v0 != 0
+ blez v0, OP_CMPG_DOUBLE_nan # fall thru for finish
+#endif
+
+OP_CMPG_DOUBLE_finish:
+ GET_OPA(rOBJ)
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(rTEMP, rOBJ, t0) # vAA <- rTEMP
+
+/* continuation for OP_APUT_OBJECT */
+.LOP_APUT_OBJECT_checks:
+ LOAD_base_offObject_clazz(a0, rBIX) # a0 <- obj->clazz
+ LOAD_base_offObject_clazz(a1, rINST) # a1 <- arrayObj->clazz
+ JAL(dvmCanPutArrayElement) # test object type vs. array type
+ beqz v0, .LOP_APUT_OBJECT_throw # okay ?
+ lw a2, offThread_cardTable(rSELF)
+ srl t1, rINST, GC_CARD_SHIFT
+ addu t2, a2, t1
+ sb a2, (t2)
+ b .LOP_APUT_OBJECT_finish # yes, skip type checks
+.LOP_APUT_OBJECT_throw:
+ LOAD_base_offObject_clazz(a0, rBIX) # a0 <- obj->clazz
+ LOAD_base_offObject_clazz(a1, rINST) # a1 <- arrayObj->clazz
+ EXPORT_PC()
+ JAL(dvmThrowArrayStoreExceptionIncompatibleElement)
+ b common_exceptionThrown
+
+/* continuation for OP_IGET */
+
+ /*
+ * Currently:
+ * v0 holds resolved field
+ * rOBJ holds object (caller saved)
+ */
+.LOP_IGET_finish:
+ #BAL(common_squeak0)
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ addu a3, a3, rOBJ # form address
+ lw a0, (a3) # a0 <- obj.field (8/16/32 bits)
+ # noop # acquiring load
+ GET_OPA4(a2) # a2 <- A+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IGET_WIDE */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IGET_WIDE_finish:
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ beqz rOBJ, common_errNullObject # object was null
+ GET_OPA4(a2) # a2 <- A+
+ addu rOBJ, rOBJ, a3 # form address
+ .if 0
+ vLOAD64(a0, a1, rOBJ) # a0/a1 <- obj.field (64-bit align ok)
+ .else
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- obj.field (64-bit align ok)
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a3, rFP, a2) # a3 <- &fp[A]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # fp[A] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IGET_OBJECT */
+
+ /*
+ * Currently:
+ * v0 holds resolved field
+ * rOBJ holds object (caller saved)
+ */
+.LOP_IGET_OBJECT_finish:
+ #BAL(common_squeak0)
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ addu a3, a3, rOBJ # form address
+ lw a0, (a3) # a0 <- obj.field (8/16/32 bits)
+ # noop # acquiring load
+ GET_OPA4(a2) # a2 <- A+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IGET_BOOLEAN */
+
+ /*
+ * Currently:
+ * v0 holds resolved field
+ * rOBJ holds object (caller saved)
+ */
+.LOP_IGET_BOOLEAN_finish:
+ #BAL(common_squeak0)
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ addu a3, a3, rOBJ # form address
+ lw a0, (a3) # a0 <- obj.field (8/16/32 bits)
+ # noop # acquiring load
+ GET_OPA4(a2) # a2 <- A+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IGET_BYTE */
+
+ /*
+ * Currently:
+ * v0 holds resolved field
+ * rOBJ holds object (caller saved)
+ */
+.LOP_IGET_BYTE_finish:
+ #BAL(common_squeak0)
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ addu a3, a3, rOBJ # form address
+ lw a0, (a3) # a0 <- obj.field (8/16/32 bits)
+ # noop # acquiring load
+ GET_OPA4(a2) # a2 <- A+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IGET_CHAR */
+
+ /*
+ * Currently:
+ * v0 holds resolved field
+ * rOBJ holds object (caller saved)
+ */
+.LOP_IGET_CHAR_finish:
+ #BAL(common_squeak0)
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ addu a3, a3, rOBJ # form address
+ lw a0, (a3) # a0 <- obj.field (8/16/32 bits)
+ # noop # acquiring load
+ GET_OPA4(a2) # a2 <- A+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IGET_SHORT */
+
+ /*
+ * Currently:
+ * v0 holds resolved field
+ * rOBJ holds object (caller saved)
+ */
+.LOP_IGET_SHORT_finish:
+ #BAL(common_squeak0)
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ addu a3, a3, rOBJ # form address
+ lw a0, (a3) # a0 <- obj.field (8/16/32 bits)
+ # noop # acquiring load
+ GET_OPA4(a2) # a2 <- A+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IPUT */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IPUT_finish:
+ #BAL(common_squeak0)
+ GET_OPA4(a1) # a1 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ GET_VREG(a0, a1) # a0 <- fp[A]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu rOBJ, rOBJ, a3 # form address
+ # noop # releasing store
+ sw a0, (rOBJ) # obj.field (8/16/32 bits) <- a0
+ # noop
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IPUT_WIDE */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IPUT_WIDE_finish:
+ GET_OPA4(a2) # a2 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ EAS2(a2, rFP, a2) # a2 <- &fp[A]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ LOAD64(a0, a1, a2) # a0/a1 <- fp[A]
+ GET_INST_OPCODE(rBIX) # extract opcode from rINST
+ addu a2, rOBJ, a3 # form address
+ .if 0
+ JAL(dvmQuasiAtomicSwap64Sync) # stores r0/r1 into addr r2
+# STORE64(a0, a1, a2) # obj.field (64 bits, aligned) <- a0 a1
+ .else
+ STORE64(a0, a1, a2) # obj.field (64 bits, aligned) <- a0 a1
+ .endif
+ GOTO_OPCODE(rBIX) # jump to next instruction
+
+
+/* continuation for OP_IPUT_OBJECT */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IPUT_OBJECT_finish:
+ #BAL(common_squeak0)
+ GET_OPA4(a1) # a1 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ GET_VREG(a0, a1) # a0 <- fp[A]
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu t2, rOBJ, a3 # form address
+ # noop # releasing store
+ sw a0, (t2) # obj.field (32 bits) <- a0
+ # noop
+ beqz a0, 1f # stored a null reference?
+ srl t1, rOBJ, GC_CARD_SHIFT
+ addu t2, a2, t1
+ sb a2, (t2) # mark card if not
+1:
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IPUT_BOOLEAN */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IPUT_BOOLEAN_finish:
+ #BAL(common_squeak0)
+ GET_OPA4(a1) # a1 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ GET_VREG(a0, a1) # a0 <- fp[A]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu rOBJ, rOBJ, a3 # form address
+ # noop # releasing store
+ sw a0, (rOBJ) # obj.field (8/16/32 bits) <- a0
+ # noop
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IPUT_BYTE */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IPUT_BYTE_finish:
+ #BAL(common_squeak0)
+ GET_OPA4(a1) # a1 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ GET_VREG(a0, a1) # a0 <- fp[A]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu rOBJ, rOBJ, a3 # form address
+ # noop # releasing store
+ sw a0, (rOBJ) # obj.field (8/16/32 bits) <- a0
+ # noop
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IPUT_CHAR */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IPUT_CHAR_finish:
+ #BAL(common_squeak0)
+ GET_OPA4(a1) # a1 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ GET_VREG(a0, a1) # a0 <- fp[A]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu rOBJ, rOBJ, a3 # form address
+ # noop # releasing store
+ sw a0, (rOBJ) # obj.field (8/16/32 bits) <- a0
+ # noop
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IPUT_SHORT */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IPUT_SHORT_finish:
+ #BAL(common_squeak0)
+ GET_OPA4(a1) # a1 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ GET_VREG(a0, a1) # a0 <- fp[A]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu rOBJ, rOBJ, a3 # form address
+ # noop # releasing store
+ sw a0, (rOBJ) # obj.field (8/16/32 bits) <- a0
+ # noop
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_SGET */
+
+.LOP_SGET_finish:
+ LOAD_base_offStaticField_value(a1, a0) # a1 <- field value
+ # no-op # acquiring load
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a1, a2, t0) # fp[AA] <- a1
+
+/* continuation for OP_SGET_WIDE */
+
+.LOP_SGET_WIDE_finish:
+ GET_OPA(a1) # a1 <- AA
+ .if 0
+ vLOAD64_off(a2, a3, a0, offStaticField_value) # a2/a3 <- field value (aligned)
+ .else
+ LOAD64_off(a2, a3, a0, offStaticField_value) # a2/a3 <- field value (aligned)
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a1, rFP, a1) # a1 <- &fp[AA]
+ STORE64(a2, a3, a1) # vAA/vAA+1 <- a2/a3
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+
+/* continuation for OP_SGET_OBJECT */
+
+.LOP_SGET_OBJECT_finish:
+ LOAD_base_offStaticField_value(a1, a0) # a1 <- field value
+ # no-op # acquiring load
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a1, a2, t0) # fp[AA] <- a1
+
+/* continuation for OP_SGET_BOOLEAN */
+
+.LOP_SGET_BOOLEAN_finish:
+ LOAD_base_offStaticField_value(a1, a0) # a1 <- field value
+ # no-op # acquiring load
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a1, a2, t0) # fp[AA] <- a1
+
+/* continuation for OP_SGET_BYTE */
+
+.LOP_SGET_BYTE_finish:
+ LOAD_base_offStaticField_value(a1, a0) # a1 <- field value
+ # no-op # acquiring load
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a1, a2, t0) # fp[AA] <- a1
+
+/* continuation for OP_SGET_CHAR */
+
+.LOP_SGET_CHAR_finish:
+ LOAD_base_offStaticField_value(a1, a0) # a1 <- field value
+ # no-op # acquiring load
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a1, a2, t0) # fp[AA] <- a1
+
+/* continuation for OP_SGET_SHORT */
+
+.LOP_SGET_SHORT_finish:
+ LOAD_base_offStaticField_value(a1, a0) # a1 <- field value
+ # no-op # acquiring load
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a1, a2, t0) # fp[AA] <- a1
+
+/* continuation for OP_SPUT */
+
+.LOP_SPUT_finish:
+ # field ptr in a0
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ # no-op # releasing store
+ sw a1, offStaticField_value(a0) # field <- vAA
+ # no-op
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* continuation for OP_SPUT_WIDE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rOBJ: &fp[AA]
+ * rBIX: dvmDex->pResFields
+ *
+ * Returns StaticField pointer in a2.
+ */
+.LOP_SPUT_WIDE_resolve:
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ # success ?
+ move a0, v0
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ move a2, v0
+ b .LOP_SPUT_WIDE_finish # resume
+
+/* continuation for OP_SPUT_OBJECT */
+.LOP_SPUT_OBJECT_finish: # field ptr in a0
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[AA]
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ lw t1, offField_clazz(a0) # t1 <- field->clazz
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ # no-op # releasing store
+ sw a1, offStaticField_value(a0) # field <- vAA
+ # no-op
+ beqz a1, 1f
+ srl t2, t1, GC_CARD_SHIFT
+ addu t3, a2, t2
+ sb a2, (t3)
+1:
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* continuation for OP_SPUT_BOOLEAN */
+
+.LOP_SPUT_BOOLEAN_finish:
+ # field ptr in a0
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ # no-op # releasing store
+ sw a1, offStaticField_value(a0) # field <- vAA
+ # no-op
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* continuation for OP_SPUT_BYTE */
+
+.LOP_SPUT_BYTE_finish:
+ # field ptr in a0
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ # no-op # releasing store
+ sw a1, offStaticField_value(a0) # field <- vAA
+ # no-op
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* continuation for OP_SPUT_CHAR */
+
+.LOP_SPUT_CHAR_finish:
+ # field ptr in a0
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ # no-op # releasing store
+ sw a1, offStaticField_value(a0) # field <- vAA
+ # no-op
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* continuation for OP_SPUT_SHORT */
+
+.LOP_SPUT_SHORT_finish:
+ # field ptr in a0
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ # no-op # releasing store
+ sw a1, offStaticField_value(a0) # field <- vAA
+ # no-op
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* continuation for OP_INVOKE_VIRTUAL */
+
+ /*
+ * At this point:
+ * a0 = resolved base method
+ * rBIX= C or CCCC (index of first arg, which is the "this" ptr)
+ */
+.LOP_INVOKE_VIRTUAL_continue:
+ GET_VREG(rOBJ, rBIX) # rOBJ <- "this" ptr
+ LOADu2_offMethod_methodIndex(a2, a0) # a2 <- baseMethod->methodIndex
+ # is "this" null?
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ LOAD_base_offObject_clazz(a3, rOBJ) # a3 <- thisPtr->clazz
+ LOAD_base_offClassObject_vtable(a3, a3) # a3 <- thisPtr->clazz->vtable
+ LOAD_eas2(a0, a3, a2) # a0 <- vtable[methodIndex]
+ b common_invokeMethodNoRange # (a0=method, rOBJ="this")
+
+
+/* continuation for OP_INVOKE_SUPER */
+
+ /*
+ * At this point:
+ * a0 = resolved base method
+ * rBIX = method->clazz
+ */
+.LOP_INVOKE_SUPER_continue:
+ LOAD_base_offClassObject_super(a1, rBIX) # a1 <- method->clazz->super
+ LOADu2_offMethod_methodIndex(a2, a0) # a2 <- baseMethod->methodIndex
+ LOAD_base_offClassObject_vtableCount(a3, a1) # a3 <- super->vtableCount
+ EXPORT_PC() # must export for invoke
+ # compare (methodIndex, vtableCount)
+ bgeu a2, a3, .LOP_INVOKE_SUPER_nsm # method not present in superclass
+ LOAD_base_offClassObject_vtable(a1, a1) # a1 <- ...clazz->super->vtable
+ LOAD_eas2(a0, a1, a2) # a0 <- vtable[methodIndex]
+ b common_invokeMethodNoRange # continue on
+
+ /*
+ * Throw a NoSuchMethodError with the method name as the message.
+ * a0 = resolved base method
+ */
+.LOP_INVOKE_SUPER_nsm:
+ LOAD_base_offMethod_name(a1, a0) # a1 <- method name
+ b common_errNoSuchMethod
+
+
+/* continuation for OP_INVOKE_STATIC */
+
+.LOP_INVOKE_STATIC_resolve:
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_STATIC # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+#if defined(WITH_JIT)
+ /*
+ * Check to see if we're actively building a trace. If so,
+ * we need to keep this instruction out of it.
+ * rBIX: &resolved_methodToCall
+ */
+ lhu a2, offThread_subMode(rSELF)
+ beqz v0, common_exceptionThrown # null, handle exception
+ and a2, kSubModeJitTraceBuild # trace under construction?
+ beqz a2, common_invokeMethodNoRange # no, (a0=method, rOBJ="this")
+ lw a1, 0(rBIX) # reload resolved method
+ # finished resloving?
+ bnez a1, common_invokeMethodNoRange # yes, (a0=method, rOBJ="this")
+ move rBIX, a0 # preserve method
+ move a0, rSELF
+ move a1, rPC
+ JAL(dvmJitEndTraceSelect) # (self, pc)
+ move a0, rBIX
+ b common_invokeMethodNoRange # whew, finally!
+#else
+ # got null?
+ bnez v0, common_invokeMethodNoRange # (a0=method, rOBJ="this")
+ b common_exceptionThrown # yes, handle exception
+#endif
+
+/* continuation for OP_INVOKE_VIRTUAL_RANGE */
+
+ /*
+ * At this point:
+ * a0 = resolved base method
+ * rBIX= C or CCCC (index of first arg, which is the "this" ptr)
+ */
+.LOP_INVOKE_VIRTUAL_RANGE_continue:
+ GET_VREG(rOBJ, rBIX) # rOBJ <- "this" ptr
+ LOADu2_offMethod_methodIndex(a2, a0) # a2 <- baseMethod->methodIndex
+ # is "this" null?
+ beqz rOBJ, common_errNullObject # null "this", throw exception
+ LOAD_base_offObject_clazz(a3, rOBJ) # a3 <- thisPtr->clazz
+ LOAD_base_offClassObject_vtable(a3, a3) # a3 <- thisPtr->clazz->vtable
+ LOAD_eas2(a0, a3, a2) # a0 <- vtable[methodIndex]
+ b common_invokeMethodRange # (a0=method, rOBJ="this")
+
+
+/* continuation for OP_INVOKE_SUPER_RANGE */
+
+ /*
+ * At this point:
+ * a0 = resolved base method
+ * rBIX = method->clazz
+ */
+.LOP_INVOKE_SUPER_RANGE_continue:
+ LOAD_base_offClassObject_super(a1, rBIX) # a1 <- method->clazz->super
+ LOADu2_offMethod_methodIndex(a2, a0) # a2 <- baseMethod->methodIndex
+ LOAD_base_offClassObject_vtableCount(a3, a1) # a3 <- super->vtableCount
+ EXPORT_PC() # must export for invoke
+ # compare (methodIndex, vtableCount)
+ bgeu a2, a3, .LOP_INVOKE_SUPER_RANGE_nsm # method not present in superclass
+ LOAD_base_offClassObject_vtable(a1, a1) # a1 <- ...clazz->super->vtable
+ LOAD_eas2(a0, a1, a2) # a0 <- vtable[methodIndex]
+ b common_invokeMethodRange # continue on
+
+ /*
+ * Throw a NoSuchMethodError with the method name as the message.
+ * a0 = resolved base method
+ */
+.LOP_INVOKE_SUPER_RANGE_nsm:
+ LOAD_base_offMethod_name(a1, a0) # a1 <- method name
+ b common_errNoSuchMethod
+
+
+/* continuation for OP_INVOKE_STATIC_RANGE */
+
+.LOP_INVOKE_STATIC_RANGE_resolve:
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ li a2, METHOD_STATIC # resolver method type
+ JAL(dvmResolveMethod) # v0 <- call(clazz, ref, flags)
+ move a0, v0
+#if defined(WITH_JIT)
+ /*
+ * Check to see if we're actively building a trace. If so,
+ * we need to keep this instruction out of it.
+ * rBIX: &resolved_methodToCall
+ */
+ lhu a2, offThread_subMode(rSELF)
+ beqz v0, common_exceptionThrown # null, handle exception
+ and a2, kSubModeJitTraceBuild # trace under construction?
+ beqz a2, common_invokeMethodRange # no, (a0=method, rOBJ="this")
+ lw a1, 0(rBIX) # reload resolved method
+ # finished resloving?
+ bnez a1, common_invokeMethodRange # yes, (a0=method, rOBJ="this")
+ move rBIX, a0 # preserve method
+ move a0, rSELF
+ move a1, rPC
+ JAL(dvmJitEndTraceSelect) # (self, pc)
+ move a0, rBIX
+ b common_invokeMethodRange # whew, finally!
+#else
+ # got null?
+ bnez v0, common_invokeMethodRange # (a0=method, rOBJ="this")
+ b common_exceptionThrown # yes, handle exception
+#endif
+
+/* continuation for OP_FLOAT_TO_INT */
+
+/*
+ * Not an entry point as it is used only once !!
+ */
+f2i_doconv:
+#ifdef SOFT_FLOAT
+ li a1, 0x4f000000 # (float)maxint
+ move rBIX, a0
+ JAL(__gesf2) # is arg >= maxint?
+ move t0, v0
+ li v0, ~0x80000000 # return maxint (7fffffff)
+ bgez t0, .LOP_FLOAT_TO_INT_set_vreg
+
+ move a0, rBIX # recover arg
+ li a1, 0xcf000000 # (float)minint
+ JAL(__lesf2)
+
+ move t0, v0
+ li v0, 0x80000000 # return minint (80000000)
+ blez t0, .LOP_FLOAT_TO_INT_set_vreg
+ move a0, rBIX
+ move a1, rBIX
+ JAL(__nesf2)
+
+ move t0, v0
+ li v0, 0 # return zero for NaN
+ bnez t0, .LOP_FLOAT_TO_INT_set_vreg
+
+ move a0, rBIX
+ JAL(__fixsfsi)
+ b .LOP_FLOAT_TO_INT_set_vreg
+#else
+ l.s fa1, .LFLOAT_TO_INT_max
+ c.ole.s fcc0, fa1, fa0
+ l.s fv0, .LFLOAT_TO_INT_ret_max
+ bc1t .LOP_FLOAT_TO_INT_set_vreg_f
+
+ l.s fa1, .LFLOAT_TO_INT_min
+ c.ole.s fcc0, fa0, fa1
+ l.s fv0, .LFLOAT_TO_INT_ret_min
+ bc1t .LOP_FLOAT_TO_INT_set_vreg_f
+
+ mov.s fa1, fa0
+ c.un.s fcc0, fa0, fa1
+ li.s fv0, 0
+ bc1t .LOP_FLOAT_TO_INT_set_vreg_f
+
+ trunc.w.s fv0, fa0
+ b .LOP_FLOAT_TO_INT_set_vreg_f
+#endif
+
+.LFLOAT_TO_INT_max:
+ .word 0x4f000000
+.LFLOAT_TO_INT_min:
+ .word 0xcf000000
+.LFLOAT_TO_INT_ret_max:
+ .word 0x7fffffff
+.LFLOAT_TO_INT_ret_min:
+ .word 0x80000000
+
+
+/* continuation for OP_FLOAT_TO_LONG */
+
+f2l_doconv:
+#ifdef SOFT_FLOAT
+ li a1, 0x5f000000
+ move rBIX, a0
+ JAL(__gesf2)
+
+ move t0, v0
+ li rRESULT0, ~0
+ li rRESULT1, ~0x80000000
+ bgez t0, .LOP_FLOAT_TO_LONG_set_vreg
+
+ move a0, rBIX
+ li a1, 0xdf000000
+ JAL(__lesf2)
+
+ move t0, v0
+ li rRESULT0, 0
+ li rRESULT1, 0x80000000
+ blez t0, .LOP_FLOAT_TO_LONG_set_vreg
+
+ move a0, rBIX
+ move a1, rBIX
+ JAL(__nesf2)
+
+ move t0, v0
+ li rRESULT0, 0
+ li rRESULT1, 0
+ bnez t0, .LOP_FLOAT_TO_LONG_set_vreg
+
+ move a0, rBIX
+ JAL(__fixsfdi)
+
+#else
+ l.s fa1, .LLONG_TO_max
+ c.ole.s fcc0, fa1, fa0
+ li rRESULT0, ~0
+ li rRESULT1, ~0x80000000
+ bc1t .LOP_FLOAT_TO_LONG_set_vreg
+
+ l.s fa1, .LLONG_TO_min
+ c.ole.s fcc0, fa0, fa1
+ li rRESULT0, 0
+ li rRESULT1, 0x80000000
+ bc1t .LOP_FLOAT_TO_LONG_set_vreg
+
+ mov.s fa1, fa0
+ c.un.s fcc0, fa0, fa1
+ li rRESULT0, 0
+ li rRESULT1, 0
+ bc1t .LOP_FLOAT_TO_LONG_set_vreg
+
+ JAL(__fixsfdi)
+#endif
+
+ b .LOP_FLOAT_TO_LONG_set_vreg
+
+.LLONG_TO_max:
+ .word 0x5f000000
+
+.LLONG_TO_min:
+ .word 0xdf000000
+
+/* continuation for OP_DOUBLE_TO_INT */
+
+
+d2i_doconv:
+#ifdef SOFT_FLOAT
+ la t0, .LDOUBLE_TO_INT_max
+ LOAD64(rARG2, rARG3, t0)
+ move rBIX, rARG0 # save a0
+ move rTEMP, rARG1 # and a1
+ JAL(__gedf2) # is arg >= maxint?
+
+ move t0, v0
+ li v0, ~0x80000000 # return maxint (7fffffff)
+ bgez t0, .LOP_DOUBLE_TO_INT_set_vreg # nonzero == yes
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rTEMP
+ la t0, .LDOUBLE_TO_INT_min
+ LOAD64(rARG2, rARG3, t0)
+ JAL(__ledf2) # is arg <= minint?
+
+ move t0, v0
+ li v0, 0x80000000 # return minint (80000000)
+ blez t0, .LOP_DOUBLE_TO_INT_set_vreg # nonzero == yes
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rTEMP
+ move rARG2, rBIX # compare against self
+ move rARG3, rTEMP
+ JAL(__nedf2) # is arg == self?
+
+ move t0, v0 # zero == no
+ li v0, 0
+ bnez t0, .LOP_DOUBLE_TO_INT_set_vreg # return zero for NaN
+
+ move rARG0, rBIX # recover arg
+ move rARG1, rTEMP
+ JAL(__fixdfsi) # convert double to int
+ b .LOP_DOUBLE_TO_INT_set_vreg
+#else
+ la t0, .LDOUBLE_TO_INT_max
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa1, fa0
+ l.s fv0, .LDOUBLE_TO_INT_maxret
+ bc1t .LOP_DOUBLE_TO_INT_set_vreg_f
+
+ la t0, .LDOUBLE_TO_INT_min
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa0, fa1
+ l.s fv0, .LDOUBLE_TO_INT_minret
+ bc1t .LOP_DOUBLE_TO_INT_set_vreg_f
+
+ mov.d fa1, fa0
+ c.un.d fcc0, fa0, fa1
+ li.s fv0, 0
+ bc1t .LOP_DOUBLE_TO_INT_set_vreg_f
+
+ trunc.w.d fv0, fa0
+ b .LOP_DOUBLE_TO_INT_set_vreg_f
+#endif
+
+
+.LDOUBLE_TO_INT_max:
+ .dword 0x41dfffffffc00000
+.LDOUBLE_TO_INT_min:
+ .dword 0xc1e0000000000000 # minint, as a double (high word)
+.LDOUBLE_TO_INT_maxret:
+ .word 0x7fffffff
+.LDOUBLE_TO_INT_minret:
+ .word 0x80000000
+
+/* continuation for OP_DOUBLE_TO_LONG */
+
+d2l_doconv:
+#ifdef SOFT_FLOAT
+ la t0, .LDOUBLE_TO_LONG_max
+ LOAD64(rARG2, rARG3, t0)
+ move rBIX, rARG0 # save a0
+ move rTEMP, rARG1 # and a1
+ JAL(__gedf2)
+
+ move t1, v0
+ la t0, .LDOUBLE_TO_LONG_ret_max
+ LOAD64(rRESULT0, rRESULT1, t0)
+ bgez t1, .LOP_DOUBLE_TO_LONG_set_vreg
+
+ move rARG0, rBIX
+ move rARG1, rTEMP
+ la t0, .LDOUBLE_TO_LONG_min
+ LOAD64(rARG2, rARG3, t0)
+ JAL(__ledf2)
+
+ move t1, v0
+ la t0, .LDOUBLE_TO_LONG_ret_min
+ LOAD64(rRESULT0, rRESULT1, t0)
+ blez t1, .LOP_DOUBLE_TO_LONG_set_vreg
+
+ move rARG0, rBIX
+ move rARG1, rTEMP
+ move rARG2, rBIX
+ move rARG3, rTEMP
+ JAL(__nedf2)
+
+ move t0, v0
+ li rRESULT0, 0
+ li rRESULT1, 0
+ bnez t0, .LOP_DOUBLE_TO_LONG_set_vreg
+
+ move rARG0, rBIX
+ move rARG1, rTEMP
+ JAL(__fixdfdi)
+
+#else
+ la t0, .LDOUBLE_TO_LONG_max
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa1, fa0
+ la t0, .LDOUBLE_TO_LONG_ret_max
+ LOAD64(rRESULT0, rRESULT1, t0)
+ bc1t .LOP_DOUBLE_TO_LONG_set_vreg
+
+ la t0, .LDOUBLE_TO_LONG_min
+ LOAD64_F(fa1, fa1f, t0)
+ c.ole.d fcc0, fa0, fa1
+ la t0, .LDOUBLE_TO_LONG_ret_min
+ LOAD64(rRESULT0, rRESULT1, t0)
+ bc1t .LOP_DOUBLE_TO_LONG_set_vreg
+
+ mov.d fa1, fa0
+ c.un.d fcc0, fa0, fa1
+ li rRESULT0, 0
+ li rRESULT1, 0
+ bc1t .LOP_DOUBLE_TO_LONG_set_vreg
+ JAL(__fixdfdi)
+#endif
+ b .LOP_DOUBLE_TO_LONG_set_vreg
+
+
+.LDOUBLE_TO_LONG_max:
+ .dword 0x43e0000000000000 # maxlong, as a double (high word)
+.LDOUBLE_TO_LONG_min:
+ .dword 0xc3e0000000000000 # minlong, as a double (high word)
+.LDOUBLE_TO_LONG_ret_max:
+ .dword 0x7fffffffffffffff
+.LDOUBLE_TO_LONG_ret_min:
+ .dword 0x8000000000000000
+
+/* continuation for OP_MUL_LONG */
+
+.LOP_MUL_LONG_finish:
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(v0, v1, a0) # vAA::vAA+1 <- v0(low) :: v1(high)
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IGET_VOLATILE */
+
+ /*
+ * Currently:
+ * v0 holds resolved field
+ * rOBJ holds object (caller saved)
+ */
+.LOP_IGET_VOLATILE_finish:
+ #BAL(common_squeak0)
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ addu a3, a3, rOBJ # form address
+ lw a0, (a3) # a0 <- obj.field (8/16/32 bits)
+ SMP_DMB # acquiring load
+ GET_OPA4(a2) # a2 <- A+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IPUT_VOLATILE */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IPUT_VOLATILE_finish:
+ #BAL(common_squeak0)
+ GET_OPA4(a1) # a1 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ GET_VREG(a0, a1) # a0 <- fp[A]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu rOBJ, rOBJ, a3 # form address
+ SMP_DMB_ST # releasing store
+ sw a0, (rOBJ) # obj.field (8/16/32 bits) <- a0
+ SMP_DMB
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_SGET_VOLATILE */
+
+.LOP_SGET_VOLATILE_finish:
+ LOAD_base_offStaticField_value(a1, a0) # a1 <- field value
+ SMP_DMB # acquiring load
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a1, a2, t0) # fp[AA] <- a1
+
+/* continuation for OP_SPUT_VOLATILE */
+
+.LOP_SPUT_VOLATILE_finish:
+ # field ptr in a0
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[AA]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SMP_DMB_ST # releasing store
+ sw a1, offStaticField_value(a0) # field <- vAA
+ SMP_DMB
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * v0 holds resolved field
+ * rOBJ holds object (caller saved)
+ */
+.LOP_IGET_OBJECT_VOLATILE_finish:
+ #BAL(common_squeak0)
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ addu a3, a3, rOBJ # form address
+ lw a0, (a3) # a0 <- obj.field (8/16/32 bits)
+ SMP_DMB # acquiring load
+ GET_OPA4(a2) # a2 <- A+
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG(a0, a2) # fp[A] <- a0
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IGET_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IGET_WIDE_VOLATILE_finish:
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ beqz rOBJ, common_errNullObject # object was null
+ GET_OPA4(a2) # a2 <- A+
+ addu rOBJ, rOBJ, a3 # form address
+ .if 1
+ vLOAD64(a0, a1, rOBJ) # a0/a1 <- obj.field (64-bit align ok)
+ .else
+ LOAD64(a0, a1, rOBJ) # a0/a1 <- obj.field (64-bit align ok)
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a3, rFP, a2) # a3 <- &fp[A]
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ STORE64(a0, a1, a3) # fp[A] <- a0/a1
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_IPUT_WIDE_VOLATILE */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IPUT_WIDE_VOLATILE_finish:
+ GET_OPA4(a2) # a2 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ EAS2(a2, rFP, a2) # a2 <- &fp[A]
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ LOAD64(a0, a1, a2) # a0/a1 <- fp[A]
+ GET_INST_OPCODE(rBIX) # extract opcode from rINST
+ addu a2, rOBJ, a3 # form address
+ .if 1
+ JAL(dvmQuasiAtomicSwap64Sync) # stores r0/r1 into addr r2
+# STORE64(a0, a1, a2) # obj.field (64 bits, aligned) <- a0 a1
+ .else
+ STORE64(a0, a1, a2) # obj.field (64 bits, aligned) <- a0 a1
+ .endif
+ GOTO_OPCODE(rBIX) # jump to next instruction
+
+
+/* continuation for OP_SGET_WIDE_VOLATILE */
+
+.LOP_SGET_WIDE_VOLATILE_finish:
+ GET_OPA(a1) # a1 <- AA
+ .if 1
+ vLOAD64_off(a2, a3, a0, offStaticField_value) # a2/a3 <- field value (aligned)
+ .else
+ LOAD64_off(a2, a3, a0, offStaticField_value) # a2/a3 <- field value (aligned)
+ .endif
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ EAS2(a1, rFP, a1) # a1 <- &fp[AA]
+ STORE64(a2, a3, a1) # vAA/vAA+1 <- a2/a3
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+
+/* continuation for OP_SPUT_WIDE_VOLATILE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * a1: BBBB field ref
+ * rOBJ: &fp[AA]
+ * rBIX: dvmDex->pResFields
+ *
+ * Returns StaticField pointer in a2.
+ */
+.LOP_SPUT_WIDE_VOLATILE_resolve:
+ LOAD_rSELF_method(a2) # a2 <- current method
+#if defined(WITH_JIT)
+ EAS2(rBIX, rBIX, a1) # rBIX<- &dvmDex->pResFields[field]
+#endif
+ EXPORT_PC() # resolve() could throw, so export now
+ LOAD_base_offMethod_clazz(a0, a2) # a0 <- method->clazz
+ JAL(dvmResolveStaticField) # v0 <- resolved StaticField ptr
+ # success ?
+ move a0, v0
+ beqz v0, common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including this instruction.
+ */
+ JAL(common_verifyField)
+#endif
+ move a2, v0
+ b .LOP_SPUT_WIDE_VOLATILE_finish # resume
+
+/* continuation for OP_EXECUTE_INLINE */
+
+ /*
+ * Extract args, call function.
+ * a0 = #of args (0-4)
+ * rBIX = call index
+ *
+ * Other ideas:
+ * - Use a jump table from the main piece to jump directly into the
+ * AND/LW pairs. Costs a data load, saves a branch.
+ * - Have five separate pieces that do the loading, so we can work the
+ * interleave a little better. Increases code size.
+ */
+.LOP_EXECUTE_INLINE_continue:
+ FETCH(rINST, 2) # rINST <- FEDC
+ beq a0, 0, 0f
+ beq a0, 1, 1f
+ beq a0, 2, 2f
+ beq a0, 3, 3f
+ beq a0, 4, 4f
+ JAL(common_abort) # too many arguments
+
+4:
+ and t0, rINST, 0xf000 # isolate F
+ ESRN(t1, rFP, t0, 10)
+ lw a3, 0(t1) # a3 <- vF (shift right 12, left 2)
+3:
+ and t0, rINST, 0x0f00 # isolate E
+ ESRN(t1, rFP, t0, 6)
+ lw a2, 0(t1) # a2 <- vE
+2:
+ and t0, rINST, 0x00f0 # isolate D
+ ESRN(t1, rFP, t0, 2)
+ lw a1, 0(t1) # a1 <- vD
+1:
+ and t0, rINST, 0x000f # isolate C
+ EASN(t1, rFP, t0, 2)
+ lw a0, 0(t1) # a0 <- vC
+0:
+ la rINST, gDvmInlineOpsTable # table of InlineOperation
+ EAS4(t1, rINST, rBIX) # t1 <- rINST + rBIX<<4
+ lw t9, 0(t1)
+ jr t9 # sizeof=16, "func" is first entry
+ # (not reached)
+
+ /*
+ * We're debugging or profiling.
+ * rBIX: opIndex
+ */
+.LOP_EXECUTE_INLINE_debugmode:
+ move a0, rBIX
+ JAL(dvmResolveInlineNative)
+ beqz v0, .LOP_EXECUTE_INLINE_resume # did it resolve? no, just move on
+ move rOBJ, v0 # remember method
+ move a0, v0
+ move a1, rSELF
+ JAL(dvmFastMethodTraceEnter) # (method, self)
+ addu a1, rSELF, offThread_retval # a1<- &self->retval
+ GET_OPB(a0) # a0 <- B
+ # Stack should have 16/20 available
+ sw a1, 16(sp) # push &self->retval
+ BAL(.LOP_EXECUTE_INLINE_continue) # make call; will return after
+ lw gp, STACK_OFFSET_GP(sp) # restore gp
+ move rINST, v0 # save result of inline
+ move a0, rOBJ # a0<- method
+ move a1, rSELF # a1<- self
+ JAL(dvmFastMethodTraceExit) # (method, self)
+ beqz v0, common_exceptionThrown # returned false, handle exception
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* continuation for OP_EXECUTE_INLINE_RANGE */
+
+ /*
+ * Extract args, call function.
+ * a0 = #of args (0-4)
+ * rBIX = call index
+ * ra = return addr, above [DO NOT JAL out of here w/o preserving ra]
+ */
+.LOP_EXECUTE_INLINE_RANGE_continue:
+ FETCH(rOBJ, 2) # rOBJ <- CCCC
+ beq a0, 0, 0f
+ beq a0, 1, 1f
+ beq a0, 2, 2f
+ beq a0, 3, 3f
+ beq a0, 4, 4f
+ JAL(common_abort) # too many arguments
+
+4:
+ add t0, rOBJ, 3
+ GET_VREG(a3, t0)
+3:
+ add t0, rOBJ, 2
+ GET_VREG(a2, t0)
+2:
+ add t0, rOBJ, 1
+ GET_VREG(a1, t0)
+1:
+ GET_VREG(a0, rOBJ)
+0:
+ la rOBJ, gDvmInlineOpsTable # table of InlineOperation
+ EAS4(t1, rOBJ, rBIX) # t1 <- rINST + rBIX<<4
+ lw t9, 0(t1)
+ jr t9 # sizeof=16, "func" is first entry
+ # not reached
+
+ /*
+ * We're debugging or profiling.
+ * rBIX: opIndex
+ */
+.LOP_EXECUTE_INLINE_RANGE_debugmode:
+ move a0, rBIX
+ JAL(dvmResolveInlineNative)
+ beqz v0, .LOP_EXECUTE_INLINE_RANGE_resume # did it resolve? no, just move on
+ move rOBJ, v0 # remember method
+ move a0, v0
+ move a1, rSELF
+ JAL(dvmFastMethodTraceEnter) # (method, self)
+ addu a1, rSELF, offThread_retval # a1<- &self->retval
+ GET_OPA(a0) # a0 <- A
+ # Stack should have 16/20 available
+ sw a1, 16(sp) # push &self->retval
+ move rINST, rOBJ # rINST<- method
+ BAL(.LOP_EXECUTE_INLINE_RANGE_continue) # make call; will return after
+ lw gp, STACK_OFFSET_GP(sp) # restore gp
+ move rOBJ, v0 # save result of inline
+ move a0, rINST # a0<- method
+ move a1, rSELF # a1<- self
+ JAL(dvmFastNativeMethodTraceExit) # (method, self)
+ beqz rOBJ, common_exceptionThrown # returned false, handle exception
+ FETCH_ADVANCE_INST(3) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/* continuation for OP_INVOKE_OBJECT_INIT_RANGE */
+ /*
+ * A debugger is attached, so we need to go ahead and do
+ * this. For simplicity, we'll just jump directly to the
+ * corresponding handler. Note that we can't use
+ * rIBASE here because it may be in single-step mode.
+ * Load the primary table base directly.
+ */
+.LOP_INVOKE_OBJECT_INIT_RANGE_debugger:
+ lw a1, offThread_mainHandlerTable(rSELF)
+ .if 0
+ li t0, OP_INVOKE_DIRECT_JUMBO
+ .else
+ li t0, OP_INVOKE_DIRECT_RANGE
+ .endif
+ GOTO_OPCODE_BASE(a1, t0) # execute it
+
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+ /*
+ * Currently:
+ * a0 holds resolved field
+ * rOBJ holds object
+ */
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+ #BAL(common_squeak0)
+ GET_OPA4(a1) # a1 <- A+
+ LOAD_base_offInstField_byteOffset(a3, a0) # a3 <- byte offset of field
+ GET_VREG(a0, a1) # a0 <- fp[A]
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ # check object for null
+ beqz rOBJ, common_errNullObject # object was null
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ addu t2, rOBJ, a3 # form address
+ SMP_DMB_ST # releasing store
+ sw a0, (t2) # obj.field (32 bits) <- a0
+ SMP_DMB
+ beqz a0, 1f # stored a null reference?
+ srl t1, rOBJ, GC_CARD_SHIFT
+ addu t2, a2, t1
+ sb a2, (t2) # mark card if not
+1:
+ GOTO_OPCODE(t0) # jump to next instruction
+
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+.LOP_SGET_OBJECT_VOLATILE_finish:
+ LOAD_base_offStaticField_value(a1, a0) # a1 <- field value
+ SMP_DMB # acquiring load
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SET_VREG_GOTO(a1, a2, t0) # fp[AA] <- a1
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+.LOP_SPUT_OBJECT_VOLATILE_finish: # field ptr in a0
+ GET_OPA(a2) # a2 <- AA
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_VREG(a1, a2) # a1 <- fp[AA]
+ lw a2, offThread_cardTable(rSELF) # a2 <- card table base
+ lw t1, offField_clazz(a0) # t1 <- field->clazz
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ SMP_DMB_ST # releasing store
+ sw a1, offStaticField_value(a0) # field <- vAA
+ SMP_DMB
+ beqz a1, 1f
+ srl t2, t1, GC_CARD_SHIFT
+ addu t3, a2, t2
+ sb a2, (t3)
+1:
+ GOTO_OPCODE(t0) # jump to next instruction
+
+ .size dvmAsmSisterStart, .-dvmAsmSisterStart
+ .global dvmAsmSisterEnd
+dvmAsmSisterEnd:
+
+/* File: mips/footer.S */
+/*
+ * ===========================================================================
+ * Common subroutines and data
+ * ===========================================================================
+ */
+
+ .text
+ .align 2
+
+#if defined(WITH_JIT)
+#if defined(WITH_SELF_VERIFICATION)
+
+/*
+ * "longjmp" to a translation after single-stepping. Before returning
+ * to translation, must save state for self-verification.
+ */
+ .global dvmJitResumeTranslation # (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+ move rSELF, a0 # restore self
+ move rPC, a1 # restore Dalvik pc
+ move rFP, a2 # restore Dalvik fp
+ lw rBIX, offThread_jitResumeNPC(rSELF)
+ sw zero, offThread_jitResumeNPC(rSELF) # reset resume address
+ lw sp, offThread_jitResumeNSP(rSELF) # cut back native stack
+ b jitSVShadowRunStart # resume as if cache hit
+ # expects resume addr in rBIX
+
+ .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+ li a2, kSVSPunt # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+ move rPC, a0 # set up dalvik pc
+ EXPORT_PC()
+ sw ra, offThread_jitResumeNPC(rSELF)
+ sw a1, offThread_jitResumeDPC(rSELF)
+ li a2, kSVSSingleStep # a2 <- interpreter entry point
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+ move a0, rPC # pass our target PC
+ li a2, kSVSNoProfile # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+ move a0, rPC # pass our target PC
+ li a2, kSVSTraceSelect # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+ lw a0, 0(ra) # pass our target PC
+ li a2, kSVSTraceSelect # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpBackwardBranch
+dvmJitToInterpBackwardBranch:
+ lw a0, 0(ra) # pass our target PC
+ li a2, kSVSBackwardBranch # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+ lw a0, 0(ra) # pass our target PC
+ li a2, kSVSNormal # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+
+ .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+ move a0, rPC # pass our target PC
+ li a2, kSVSNoChain # a2 <- interpreter entry point
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ b jitSVShadowRunEnd # doesn't return
+#else /* WITH_SELF_VERIFICATION */
+
+
+/*
+ * "longjmp" to a translation after single-stepping.
+ */
+ .global dvmJitResumeTranslation # (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+ move rSELF, a0 # restore self
+ move rPC, a1 # restore Dalvik pc
+ move rFP, a2 # restore Dalvik fp
+ lw a0, offThread_jitResumeNPC(rSELF)
+ sw zero, offThread_jitResumeNPC(rSELF) # reset resume address
+ lw sp, offThread_jitResumeNSP(rSELF) # cut back native stack
+ jr a0 # resume translation
+
+
+/*
+ * Return from the translation cache to the interpreter when the compiler is
+ * having issues translating/executing a Dalvik instruction. We have to skip
+ * the code cache lookup otherwise it is possible to indefinitely bouce
+ * between the interpreter and the code cache if the instruction that fails
+ * to be compiled happens to be at a trace start.
+ */
+ .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+ lw gp, STACK_OFFSET_GP(sp)
+ move rPC, a0
+#if defined(WITH_JIT_TUNING)
+ move a0, ra
+ JAL(dvmBumpPunt)
+#endif
+ EXPORT_PC()
+ sw zero, offThread_inJitCodeCache(rSELF) # Back to the interp land
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * On entry:
+ * rPC <= Dalvik PC of instrucion to interpret
+ * a1 <= Dalvik PC of resume instruction
+ * ra <= resume point in translation
+ */
+
+ .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+ lw gp, STACK_OFFSET_GP(sp)
+ move rPC, a0 # set up dalvik pc
+ EXPORT_PC()
+ sw ra, offThread_jitResumeNPC(rSELF)
+ sw sp, offThread_jitResumeNSP(rSELF)
+ sw a1, offThread_jitResumeDPC(rSELF)
+ li a1, 1
+ sw a1, offThread_singleStepCount(rSELF) # just step once
+ move a0, rSELF
+ li a1, kSubModeCountedStep
+ JAL(dvmEnableSubMode) # (self, subMode)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target. Commonly used for callees.
+ */
+ .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+ lw gp, STACK_OFFSET_GP(sp)
+#if defined(WITH_JIT_TUNING)
+ JAL(dvmBumpNoChain)
+#endif
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # (pc, self)
+ move a0, v0
+ sw a0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+ beqz a0, 2f # 0 means translation does not exist
+ jr a0
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target. Commonly used following
+ * invokes.
+ */
+ .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+ lw gp, STACK_OFFSET_GP(sp)
+ lw rPC, (ra) # get our target PC
+ subu rINST, ra, 8 # save start of chain branch
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # @ (pc, self)
+ sw v0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ beqz v0, 2f
+ move a0, v0
+ move a1, rINST
+ JAL(dvmJitChain) # v0 <- dvmJitChain(codeAddr, chainAddr)
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+ move a0, v0
+ beqz a0, toInterpreter # didn't chain - resume with interpreter
+
+ jr a0 # continue native execution
+
+/* No translation, so request one if profiling isn't disabled */
+2:
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ lw a0, offThread_pJitProfTable(rSELF)
+ FETCH_INST()
+ li t0, kJitTSelectRequestHot
+ movn a2, t0, a0 # ask for trace selection
+ bnez a0, common_selectTrace
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+
+/*
+ * Return from the translation cache to the interpreter.
+ * The return was done with a BLX from thumb mode, and
+ * the following 32-bit word contains the target rPC value.
+ * Note that lr (r14) will have its low-order bit set to denote
+ * its thumb-mode origin.
+ *
+ * We'll need to stash our lr origin away, recover the new
+ * target and then check to see if there is a translation available
+ * for our new target. If so, we do a translation chain and
+ * go back to native execution. Otherwise, it's back to the
+ * interpreter (after treating this entry as a potential
+ * trace start).
+ */
+ .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+ lw gp, STACK_OFFSET_GP(sp)
+ lw rPC, (ra) # get our target PC
+ subu rINST, ra, 8 # save start of chain branch
+#if defined(WITH_JIT_TUNING)
+ JAL(dvmBumpNormal)
+#endif
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # @ (pc, self)
+ move a0, v0
+ sw a0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ beqz a0, toInterpreter # go if not, otherwise do chain
+ move a1, rINST
+ JAL(dvmJitChain) # v0 <- dvmJitChain(codeAddr, chainAddr)
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+ move a0, v0
+ beqz a0, toInterpreter # didn't chain - resume with interpreter
+
+ jr a0 # continue native execution
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
+ .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+ JAL(dvmBumpNoChain)
+#endif
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # (pc, self)
+ move a0, v0
+ sw a0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+ beqz a0, footer235
+
+ jr a0 # continue native execution if so
+footer235:
+ EXPORT_PC()
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
+
+ .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+ lw gp, STACK_OFFSET_GP(sp)
+#if defined(WITH_JIT_TUNING)
+ JAL(dvmBumpNoChain)
+#endif
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # (pc, self)
+ move a0, v0
+ sw a0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+ beqz a0, 1f
+ jr a0 # continue native execution if so
+1:
+#endif /* WITH_SELF_VERIFICATION */
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rSELF & rFP were preserved in the translated code, and rPC has
+ * already been restored by the time we get here. We'll need to set
+ * up rIBASE & rINST, and load the address of the JitTable into r0.
+ */
+
+toInterpreter:
+ EXPORT_PC()
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ lw a0, offThread_pJitProfTable(rSELF)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ # NOTE: intended fallthrough
+
+/*
+ * Similar to common_updateProfile, but tests for null pJitProfTable
+ * r0 holds pJifProfTAble, rINST is loaded, rPC is current and
+ * rIBASE has been recently refreshed.
+ */
+
+common_testUpdateProfile:
+
+ beqz a0, 4f
+
+/*
+ * Common code to update potential trace start counter, and initiate
+ * a trace-build if appropriate.
+ * On entry here:
+ * r0 <= pJitProfTable (verified non-NULL)
+ * rPC <= Dalvik PC
+ * rINST <= next instruction
+ */
+common_updateProfile:
+ srl a3, rPC, 12 # cheap, but fast hash function
+ xor a3, a3, rPC
+ andi a3, a3, JIT_PROF_SIZE-1 # eliminate excess bits
+ addu t1, a0, a3
+ lbu a1, (t1) # get counter
+ GET_INST_OPCODE(t0)
+ subu a1, a1, 1 # decrement counter
+ sb a1, (t1) # and store it
+ beqz a1, 1f
+ GOTO_OPCODE(t0) # if not threshold, fallthrough otherwise
+1:
+ /* Looks good, reset the counter */
+ lw a1, offThread_jitThreshold(rSELF)
+ sb a1, (t1)
+ EXPORT_PC()
+ move a0, rPC
+ move a1, rSELF
+ JAL(dvmJitGetTraceAddrThread) # (pc, self)
+ move a0, v0
+ sw v0, offThread_inJitCodeCache(rSELF) # set the inJitCodeCache flag
+ move a1, rPC # arg1 of translation may need this
+ move ra, zero # in case target is HANDLER_INTERPRET
+
+#if !defined(WITH_SELF_VERIFICATION)
+ li t0, kJitTSelectRequest # ask for trace selection
+ movz a2, t0, a0
+ beqz a0, common_selectTrace
+ jr a0 # jump to the translation
+#else
+
+ bne a0, zero, skip_ask_for_trace_selection
+ li a2, kJitTSelectRequest # ask for trace selection
+ j common_selectTrace
+
+skip_ask_for_trace_selection:
+ /*
+ * At this point, we have a target translation. However, if
+ * that translation is actually the interpret-only pseudo-translation
+ * we want to treat it the same as no translation.
+ */
+ move rBIX, a0 # save target
+ jal dvmCompilerGetInterpretTemplate
+ # special case?
+ bne v0, rBIX, jitSVShadowRunStart # set up self verification shadow space
+ # Need to clear the inJitCodeCache flag
+ sw zero, offThread_inJitCodeCache(rSELF) # back to the interp land
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+ /* no return */
+#endif
+
+/*
+ * On entry:
+ * r2 is jit state.
+ */
+
+common_selectTrace:
+ lhu a0, offThread_subMode(rSELF)
+ andi a0, (kSubModeJitTraceBuild | kSubModeJitSV)
+ bnez a0, 3f # already doing JIT work, continue
+ sw a2, offThread_jitState(rSELF)
+ move a0, rSELF
+
+/*
+ * Call out to validate trace-building request. If successful,
+ * rIBASE will be swapped to to send us into single-stepping trace
+ * building mode, so we need to refresh before we continue.
+ */
+
+ EXPORT_PC()
+ SAVE_PC_TO_SELF()
+ SAVE_FP_TO_SELF()
+ JAL(dvmJitCheckTraceRequest)
+3:
+ FETCH_INST()
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+4:
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0)
+ /* no return */
+#endif
+
+#if defined(WITH_SELF_VERIFICATION)
+
+/*
+ * Save PC and registers to shadow memory for self verification mode
+ * before jumping to native translation.
+ * On entry:
+ * rPC, rFP, rSELF: the values that they should contain
+ * r10: the address of the target translation.
+ */
+jitSVShadowRunStart:
+ move a0, rPC # r0 <- program counter
+ move a1, rFP # r1 <- frame pointer
+ move a2, rSELF # r2 <- InterpState pointer
+ move a3, rBIX # r3 <- target translation
+ jal dvmSelfVerificationSaveState # save registers to shadow space
+ lw rFP, offShadowSpace_shadowFP(v0) # rFP <- fp in shadow space
+ jr rBIX # jump to the translation
+
+/*
+ * Restore PC, registers, and interpState to original values
+ * before jumping back to the interpreter.
+ */
+jitSVShadowRunEnd:
+ move a1, rFP # pass ending fp
+ move a3, rSELF # pass self ptr for convenience
+ jal dvmSelfVerificationRestoreState # restore pc and fp values
+ LOAD_PC_FP_FROM_SELF() # restore pc, fp
+ lw a1, offShadowSpace_svState(a0) # get self verification state
+ beq a1, zero, 1f # check for punt condition
+
+ # Setup SV single-stepping
+ move a0, rSELF
+ li a1, kSubModeJitSV
+ JAL(dvmEnableSubMode) # (self, subMode)
+ li a2, kJitSelfVerification # ask for self verification
+ sw a2, offThread_jitState(rSELF)
+ # Intentional fallthrough
+
+1:
+ # exit to interpreter without check
+ EXPORT_PC()
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+#endif
+
+/*
+ * The equivalent of "goto bail", this calls through the "bail handler".
+ * It will end this interpreter activation, and return to the caller
+ * of dvmMterpStdRun.
+ *
+ * State registers will be saved to the "thread" area before bailing
+ * debugging purposes
+ */
+ .ent common_gotoBail
+common_gotoBail:
+ SAVE_PC_FP_TO_SELF() # export state to "thread"
+ move a0, rSELF # a0 <- self ptr
+ b dvmMterpStdBail # call(self, changeInterp)
+ .end common_gotoBail
+
+/*
+ * The JIT's invoke method needs to remember the callsite class and
+ * target pair. Save them here so that they are available to
+ * dvmCheckJit following the interpretation of this invoke.
+ */
+#if defined(WITH_JIT)
+save_callsiteinfo:
+ beqz rOBJ, 1f
+ lw rOBJ, offObject_clazz(rOBJ)
+1:
+ sw a0, offThread_methodToCall(rSELF)
+ sw rOBJ, offThread_callsiteClass(rSELF)
+ jr ra
+#endif
+
+/*
+ * Common code for jumbo method invocation.
+ * NOTE: this adjusts rPC to account for the difference in instruction width.
+ * As a result, the savedPc in the stack frame will not be wholly accurate. So
+ * long as that is only used for source file line number calculations, we're
+ * okay.
+ */
+common_invokeMethodJumboNoThis:
+#if defined(WITH_JIT)
+ /* On entry: a0 is "Method* methodToCall */
+ li rOBJ, 0 # clear "this"
+#endif
+common_invokeMethodJumbo:
+ /* On entry: a0 is "Method* methodToCall, rOBJ is "this" */
+.LinvokeNewJumbo:
+#if defined(WITH_JIT)
+ lhu a1, offThread_subMode(rSELF)
+ andi a1, kSubModeJitTraceBuild
+ beqz a1, 1f
+ JAL(save_callsiteinfo)
+#endif
+/* prepare to copy args to "outs" area of current frame */
+1:
+ add rPC, rPC, 4 # adjust pc to make return consistent
+ FETCH(a2, 1)
+ SAVEAREA_FROM_FP(rBIX, rFP) # rBIX <- stack save area
+ beqz a2, .LinvokeArgsDone # if no args, skip the rest
+ FETCH(a1, 2) # a1 <- CCCC
+ b .LinvokeRangeArgs # handle args like invoke range
+
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ * a0 is "Method* methodToCall", the method we're trying to call
+ */
+common_invokeMethodRange:
+.LinvokeNewRange:
+#if defined(WITH_JIT)
+ lhu a1, offThread_subMode(rSELF)
+ andi a1, kSubModeJitTraceBuild
+ beqz a1, 1f
+ JAL(save_callsiteinfo)
+#endif
+ # prepare to copy args to "outs" area of current frame
+1:
+ GET_OPA(a2)
+ SAVEAREA_FROM_FP(rBIX, rFP) # rBIX <- stack save area
+ beqz a2, .LinvokeArgsDone
+ FETCH(a1, 2) # a1 <- CCCC
+.LinvokeRangeArgs:
+ # a0=methodToCall, a1=CCCC, a2=count, rBIX=outs
+ # (very few methods have > 10 args; could unroll for common cases)
+ EAS2(a3, rFP, a1)
+ sll t0, a2, 2
+ subu rBIX, rBIX, t0
+
+1:
+ lw a1, 0(a3)
+ addu a3, a3, 4
+ subu a2, a2, 1
+ sw a1, 0(rBIX)
+ addu rBIX, 4
+ bnez a2, 1b
+ b .LinvokeArgsDone
+
+/*
+ * Common code for method invocation without range.
+ *
+ * On entry:
+ * a0 is "Method* methodToCall", "rOBJ is this"
+ */
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+#if defined(WITH_JIT)
+ lhu a1, offThread_subMode(rSELF)
+ andi a1, kSubModeJitTraceBuild
+ beqz a1, 1f
+ JAL(save_callsiteinfo)
+#endif
+
+ # prepare to copy args to "outs" area of current frame
+1:
+ GET_OPB(a2)
+ SAVEAREA_FROM_FP(rBIX, rFP)
+ beqz a2, .LinvokeArgsDone
+ FETCH(a1, 2)
+
+ # a0=methodToCall, a1=GFED, a2=count,
+.LinvokeNonRange:
+ beq a2, 0, 0f
+ beq a2, 1, 1f
+ beq a2, 2, 2f
+ beq a2, 3, 3f
+ beq a2, 4, 4f
+ beq a2, 5, 5f
+
+5:
+ and t0, rINST, 0x0f00
+ ESRN(t2, rFP, t0, 6)
+ lw a3, (t2)
+ subu rBIX, 4
+ sw a3, 0(rBIX)
+
+4:
+ and t0, a1, 0xf000
+ ESRN(t2, rFP, t0, 10)
+ lw a3, (t2)
+ subu rBIX, 4
+ sw a3, 0(rBIX)
+
+3:
+ and t0, a1, 0x0f00
+ ESRN(t2, rFP, t0, 6)
+ lw a3, (t2)
+ subu rBIX, 4
+ sw a3, 0(rBIX)
+
+2:
+ and t0, a1, 0x00f0
+ ESRN(t2, rFP, t0, 2)
+ lw a3, (t2)
+ subu rBIX, 4
+ sw a3, 0(rBIX)
+
+1:
+ and t0, a1, 0x000f
+ EASN(t2, rFP, t0, 2)
+ lw a3, (t2)
+ subu rBIX, 4
+ sw a3, 0(rBIX)
+
+0:
+ #fall through .LinvokeArgsDone
+
+
+.LinvokeArgsDone: # a0=methodToCall
+ lhu rOBJ, offMethod_registersSize(a0)
+ lhu a3, offMethod_outsSize(a0)
+ lw a2, offMethod_insns(a0)
+ lw rINST, offMethod_clazz(a0)
+ # find space for the new stack frame, check for overflow
+ SAVEAREA_FROM_FP(a1, rFP) # a1 <- stack save area
+ sll t0, rOBJ, 2 # a1 <- newFp (old savearea - regsSize)
+ subu a1, a1, t0
+ SAVEAREA_FROM_FP(rBIX, a1)
+ lw rOBJ, offThread_interpStackEnd(rSELF) # t3 <- interpStackEnd
+ sll t2, a3, 2
+ subu t0, rBIX, t2
+ lhu ra, offThread_subMode(rSELF)
+ lw a3, offMethod_accessFlags(a0) # a3 <- methodToCall->accessFlags
+ bltu t0, rOBJ, .LstackOverflow # yes, this frame will overflow stack
+
+
+ # set up newSaveArea
+#ifdef EASY_GDB
+ SAVEAREA_FROM_FP(t0, rFP)
+ sw t0, offStackSaveArea_prevSave(rBIX)
+#endif
+ sw rFP, (offStackSaveArea_prevFrame)(rBIX)
+ sw rPC, (offStackSaveArea_savedPc)(rBIX)
+#if defined(WITH_JIT)
+ sw zero, (offStackSaveArea_returnAddr)(rBIX)
+#endif
+ sw a0, (offStackSaveArea_method)(rBIX)
+ # Profiling?
+ bnez ra, 2f
+1:
+ and t2, a3, ACC_NATIVE
+ bnez t2, .LinvokeNative
+ lhu rOBJ, (a2) # rOBJ -< load Inst from New PC
+ lw a3, offClassObject_pDvmDex(rINST)
+ move rPC, a2 # Publish new rPC
+ # Update state values for the new method
+ # a0=methodToCall, a1=newFp, a3=newMethodClass, rOBJ=newINST
+ sw a0, offThread_method(rSELF)
+ sw a3, offThread_methodClassDex(rSELF)
+ li a2, 1
+ sw a2, offThread_debugIsMethodEntry(rSELF)
+
+#if defined(WITH_JIT)
+ lw a0, offThread_pJitProfTable(rSELF)
+ move rFP, a1 # fp = newFp
+ GET_PREFETCHED_OPCODE(t0, rOBJ) # extract prefetched opcode from rOBJ
+ move rINST, rOBJ # publish new rINST
+ sw a1, offThread_curFrame(rSELF)
+ bnez a0, common_updateProfile
+ GOTO_OPCODE(t0)
+#else
+ move rFP, a1
+ GET_PREFETCHED_OPCODE(t0, rOBJ)
+ move rINST, rOBJ
+ sw a1, offThread_curFrame(rSELF)
+ GOTO_OPCODE(t0)
+#endif
+
+2:
+ # Profiling - record method entry. a0: methodToCall
+ STACK_STORE(a0, 0)
+ STACK_STORE(a1, 4)
+ STACK_STORE(a2, 8)
+ STACK_STORE(a3, 12)
+ sw rPC, offThread_pc(rSELF) # update interpSave.pc
+ move a1, a0
+ move a0, rSELF
+ JAL(dvmReportInvoke)
+ STACK_LOAD(a3, 12) # restore a0-a3
+ STACK_LOAD(a2, 8)
+ STACK_LOAD(a1, 4)
+ STACK_LOAD(a0, 0)
+ b 1b
+.LinvokeNative:
+ # Prep for the native call
+ # a0=methodToCall, a1=newFp, rBIX=newSaveArea
+ lhu ra, offThread_subMode(rSELF)
+ lw t3, offThread_jniLocal_topCookie(rSELF)
+ sw a1, offThread_curFrame(rSELF)
+ sw t3, offStackSaveArea_localRefCookie(rBIX) # newFp->localRefCookie=top
+ move a2, a0
+ move a0, a1
+ addu a1, rSELF, offThread_retval
+ move a3, rSELF
+#ifdef ASSIST_DEBUGGER
+ /* insert fake function header to help gdb find the stack frame */
+ b .Lskip
+ .ent dalvik_mterp
+dalvik_mterp:
+ STACK_STORE_FULL()
+.Lskip:
+#endif
+ bnez ra, 11f # Any special SubModes active?
+ lw t9, offMethod_nativeFunc(a2)
+ jalr t9
+ lw gp, STACK_OFFSET_GP(sp)
+7:
+ # native return; rBIX=newSaveArea
+ # equivalent to dvmPopJniLocals
+ lw a0, offStackSaveArea_localRefCookie(rBIX)
+ lw a1, offThread_exception(rSELF)
+ sw rFP, offThread_curFrame(rSELF)
+ sw a0, offThread_jniLocal_topCookie(rSELF) # new top <- old top
+ bnez a1, common_exceptionThrown
+
+ FETCH_ADVANCE_INST(3)
+ GET_INST_OPCODE(t0)
+ GOTO_OPCODE(t0)
+11:
+ # a0=newFp, a1=&retval, a2=methodToCall, a3=self, ra=subModes
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+ move a0, a2 # a0 <- methodToCall
+ move a1, rSELF
+ move a2, rFP
+ JAL(dvmReportPreNativeInvoke) # (methodToCall, self, fp)
+ SCRATCH_LOAD(a3, 12) # restore a0-a3
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+
+ # Call the native method
+ lw t9, offMethod_nativeFunc(a2) # t9<-methodToCall->nativeFunc
+ jalr t9
+ lw gp, STACK_OFFSET_GP(sp)
+
+ # Restore the pre-call arguments
+ SCRATCH_LOAD(a3, 12) # restore a0-a3
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a0, 0)
+
+ # Finish up any post-invoke subMode requirements
+ move a0, a2
+ move a1, rSELF
+ move a2, rFP
+ JAL(dvmReportPostNativeInvoke) # (methodToCall, self, fp)
+ b 7b
+
+
+.LstackOverflow: # a0=methodToCall
+ move a1, a0 # a1 <- methodToCall
+ move a0, rSELF # a0 <- self
+ JAL(dvmHandleStackOverflow) # dvmHandleStackOverflow(self, methodToCall)
+ b common_exceptionThrown
+#ifdef ASSIST_DEBUGGER
+ .end dalvik_mterp
+#endif
+
+ /*
+ * Common code for method invocation, calling through "glue code".
+ *
+ * TODO: now that we have range and non-range invoke handlers, this
+ * needs to be split into two. Maybe just create entry points
+ * that set r9 and jump here?
+ *
+ * On entry:
+ * r0 is "Method* methodToCall", the method we're trying to call
+ * r9 is "bool methodCallRange", indicating if this is a /range variant
+ */
+
+/*
+ * Common code for handling a return instruction.
+ *
+ * This does not return.
+ */
+common_returnFromMethod:
+.LreturnNew:
+ lhu t0, offThread_subMode(rSELF)
+ SAVEAREA_FROM_FP(a0, rFP)
+ lw rOBJ, offStackSaveArea_savedPc(a0) # rOBJ = saveArea->savedPc
+ bnez t0, 19f
+14:
+ lw rFP, offStackSaveArea_prevFrame(a0) # fp = saveArea->prevFrame
+ lw a2, (offStackSaveArea_method - sizeofStackSaveArea)(rFP)
+ # a2<- method we're returning to
+ # is this a break frame?
+ beqz a2, common_gotoBail # break frame, bail out completely
+
+ lw rBIX, offMethod_clazz(a2) # rBIX<- method->clazz
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh rIBASE
+ PREFETCH_ADVANCE_INST(rINST, rOBJ, 3) # advance rOBJ, update new rINST
+ sw a2, offThread_method(rSELF) # self->method = newSave->method
+ lw a1, offClassObject_pDvmDex(rBIX) # r1<- method->clazz->pDvmDex
+ sw rFP, offThread_curFrame(rSELF) # curFrame = fp
+#if defined(WITH_JIT)
+ lw rBIX, offStackSaveArea_returnAddr(a0)
+ move rPC, rOBJ # publish new rPC
+ sw a1, offThread_methodClassDex(rSELF)
+ sw rBIX, offThread_inJitCodeCache(rSELF) # may return to JIT'ed land
+ beqz rBIX, 15f # caller is compiled code
+ move t9, rBIX
+ jalr t9
+ lw gp, STACK_OFFSET_GP(sp)
+15:
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+#else
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ move rPC, rOBJ # publish new rPC
+ sw a1, offThread_methodClassDex(rSELF)
+ GOTO_OPCODE(t0)
+#endif
+
+19:
+ # Handle special actions
+ # On entry, a0: StackSaveArea
+ lw a1, offStackSaveArea_prevFrame(a0) # a1<- prevFP
+ sw rPC, offThread_pc(rSELF) # update interpSave.pc
+ sw a1, offThread_curFrame(rSELF) # update interpSave.curFrame
+ move a0, rSELF
+ JAL(dvmReportReturn)
+ SAVEAREA_FROM_FP(a0, rFP) # restore StackSaveArea
+ b 14b
+
+ .if 0
+ /*
+ * Return handling, calls through "glue code".
+ */
+.LreturnOld:
+ SAVE_PC_FP_TO_SELF() # export state
+ move a0, rSELF # arg to function
+ JAL(dvmMterp_returnFromMethod)
+ b common_resumeAfterGlueCall
+ .endif
+
+/*
+ * Somebody has thrown an exception. Handle it.
+ *
+ * If the exception processing code returns to us (instead of falling
+ * out of the interpreter), continue with whatever the next instruction
+ * now happens to be.
+ *
+ * This does not return.
+ */
+ .global dvmMterpCommonExceptionThrown
+dvmMterpCommonExceptionThrown:
+common_exceptionThrown:
+.LexceptionNew:
+
+ EXPORT_PC()
+ move a0, rSELF
+ JAL(dvmCheckSuspendPending)
+ lw rOBJ, offThread_exception(rSELF)
+ move a1, rSELF
+ move a0, rOBJ
+ JAL(dvmAddTrackedAlloc)
+ lhu a2, offThread_subMode(rSELF)
+ sw zero, offThread_exception(rSELF)
+
+ # Special subMode?
+ bnez a2, 7f # any special subMode handling needed?
+8:
+ /* set up args and a local for "&fp" */
+ sw rFP, 20(sp) # store rFP => tmp
+ addu t0, sp, 20 # compute &tmp
+ sw t0, STACK_OFFSET_ARG04(sp) # save it in arg4 as per ABI
+ li a3, 0 # a3 <- false
+ lw a1, offThread_method(rSELF)
+ move a0, rSELF
+ lw a1, offMethod_insns(a1)
+ lhu ra, offThread_subMode(rSELF)
+ move a2, rOBJ
+ subu a1, rPC, a1
+ sra a1, a1, 1
+
+ /* call, r0 gets catchRelPc (a code-unit offset) */
+ JAL(dvmFindCatchBlock) # call(self, relPc, exc, scan?, &fp)
+ lw rFP, 20(sp) # retrieve the updated rFP
+
+ /* update frame pointer and check result from dvmFindCatchBlock */
+ move a0, v0
+ bltz v0, .LnotCaughtLocally
+
+ /* fix earlier stack overflow if necessary; Preserve a0 */
+ lbu a1, offThread_stackOverflowed(rSELF)
+ beqz a1, 1f
+ move rBIX, a0
+ move a0, rSELF
+ move a1, rOBJ
+ JAL(dvmCleanupStackOverflow)
+ move a0, rBIX
+
+1:
+
+/* adjust locals to match self->interpSave.curFrame and updated PC */
+ SAVEAREA_FROM_FP(a1, rFP) # a1<- new save area
+ lw a1, offStackSaveArea_method(a1)
+ sw a1, offThread_method(rSELF)
+ lw a2, offMethod_clazz(a1)
+ lw a3, offMethod_insns(a1)
+ lw a2, offClassObject_pDvmDex(a2)
+ EAS1(rPC, a3, a0)
+ sw a2, offThread_methodClassDex(rSELF)
+
+ /* release the tracked alloc on the exception */
+ move a0, rOBJ
+ move a1, rSELF
+ JAL(dvmReleaseTrackedAlloc)
+
+ /* restore the exception if the handler wants it */
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ FETCH_INST()
+ GET_INST_OPCODE(t0)
+ bne t0, OP_MOVE_EXCEPTION, 2f
+ sw rOBJ, offThread_exception(rSELF)
+2:
+ GOTO_OPCODE(t0)
+
+ # Manage debugger bookkeeping
+7:
+ sw rPC, offThread_pc(rSELF)
+ sw rFP, offThread_curFrame(rSELF)
+ move a0, rSELF
+ move a1, rOBJ
+ JAL(dvmReportExceptionThrow)
+ b 8b
+
+.LnotCaughtLocally: # rOBJ = exception
+ /* fix stack overflow if necessary */
+ lbu a1, offThread_stackOverflowed(rSELF)
+ beqz a1, 3f
+ move a0, rSELF
+ move a1, rOBJ
+ JAL(dvmCleanupStackOverflow) # dvmCleanupStackOverflow(self, exception)
+
+3:
+ # may want to show "not caught locally" debug messages here
+#if DVM_SHOW_EXCEPTION >= 2
+ /* call __android_log_print(prio, tag, format, ...) */
+ /* "Exception %s from %s:%d not caught locally" */
+ lw a0, offThread_method(rSELF)
+ lw a1, offMethod_insns(a0)
+ subu a1, rPC, a1
+ sra a1, a1, 1
+ JAL(dvmLineNumFromPC)
+ sw v0, 20(sp)
+ # dvmGetMethodSourceFile(method)
+ lw a0, offThread_method(rSELF)
+ JAL(dvmGetMethodSourceFile)
+ sw v0, 16(sp)
+ # exception->clazz->descriptor
+ lw a3, offObject_clazz(rOBJ)
+ lw a3, offClassObject_descriptor(a3)
+ la a2, .LstrExceptionNotCaughtLocally
+ la a1, .LstrLogTag
+ li a0, 3
+ JAL(__android_log_print)
+#endif
+ sw rOBJ, offThread_exception(rSELF)
+ move a0, rOBJ
+ move a1, rSELF
+ JAL(dvmReleaseTrackedAlloc)
+ b common_gotoBail
+
+ /*
+ * Exception handling, calls through "glue code".
+ */
+ .if 0
+.LexceptionOld:
+ SAVE_PC_TO_SELF() # export state
+ SAVE_FP_TO_SELF()
+ move a0, rSELF # arg to function
+ JAL(dvmMterp_exceptionThrown)
+ b common_resumeAfterGlueCall
+ .endif
+
+#if defined(WITH_JIT)
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including the current
+ * instruction.
+ *
+ * On entry:
+ * rBIX: &dvmDex->pResFields[field]
+ * a0: field pointer (must preserve)
+ */
+common_verifyField:
+ lhu a3, offThread_subMode(rSELF)
+ andi a3, kSubModeJitTraceBuild
+ bnez a3, 1f # Not building trace, continue
+ jr ra
+1:
+ lw a1, (rBIX)
+ beqz a1, 2f # resolution complete ?
+ jr ra
+2:
+ SCRATCH_STORE(a0, 0)
+ SCRATCH_STORE(a1, 4)
+ SCRATCH_STORE(a2, 8)
+ SCRATCH_STORE(a3, 12)
+ SCRATCH_STORE(ra, 16)
+ move a0, rSELF
+ move a1, rPC
+ JAL(dvmJitEndTraceSelect) #(self,pc) end trace before this inst)
+ SCRATCH_LOAD(a0, 0)
+ SCRATCH_LOAD(a1, 4)
+ SCRATCH_LOAD(a2, 8)
+ SCRATCH_LOAD(a3, 12)
+ SCRATCH_LOAD(ra, 16)
+ jr ra # return
+#endif
+
+/*
+ * After returning from a "glued" function, pull out the updated
+ * values and start executing at the next instruction.
+ */
+common_resumeAfterGlueCall:
+ LOAD_PC_FP_FROM_SELF() # pull rPC and rFP out of thread
+ lw rIBASE, offThread_curHandlerTable(rSELF) # refresh
+ FETCH_INST() # load rINST from rPC
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+/*
+ * Invalid array index. Note that our calling convention is strange; we use a1
+ * and a3 because those just happen to be the registers all our callers are
+ * using. We move a3 before calling the C function, but a1 happens to match.
+ * a1: index
+ * a3: size
+ */
+common_errArrayIndex:
+ EXPORT_PC()
+ move a0, a3
+ JAL(dvmThrowArrayIndexOutOfBoundsException)
+ b common_exceptionThrown
+
+/*
+ * Integer divide or mod by zero.
+ */
+common_errDivideByZero:
+ EXPORT_PC()
+ la a0, .LstrDivideByZero
+ JAL(dvmThrowArithmeticException)
+ b common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry: length in a1
+ */
+common_errNegativeArraySize:
+ EXPORT_PC()
+ move a0, a1 # arg0 <- len
+ JAL(dvmThrowNegativeArraySizeException) # (len)
+ b common_exceptionThrown
+
+/*
+ * Invocation of a non-existent method.
+ * On entry: method name in a1
+ */
+common_errNoSuchMethod:
+ EXPORT_PC()
+ move a0, a1
+ JAL(dvmThrowNoSuchMethodError)
+ b common_exceptionThrown
+
+/*
+ * We encountered a null object when we weren't expecting one. We
+ * export the PC, throw a NullPointerException, and goto the exception
+ * processing code.
+ */
+common_errNullObject:
+ EXPORT_PC()
+ li a0, 0
+ JAL(dvmThrowNullPointerException)
+ b common_exceptionThrown
+
+/*
+ * For debugging, cause an immediate fault. The source address will be in ra. Use a jal to jump here.
+ */
+common_abort:
+ lw zero,-4(zero) # generate SIGSEGV
+
+/*
+ * Spit out a "we were here", preserving all registers.
+ */
+ .macro SQUEAK num
+common_squeak\num:
+ STACK_STORE_RA();
+ la a0, .LstrSqueak
+ LOAD_IMM(a1, \num);
+ JAL(printf);
+ STACK_LOAD_RA();
+ RETURN;
+ .endm
+
+ SQUEAK 0
+ SQUEAK 1
+ SQUEAK 2
+ SQUEAK 3
+ SQUEAK 4
+ SQUEAK 5
+
+/*
+ * Spit out the number in a0, preserving registers.
+ */
+common_printNum:
+ STACK_STORE_RA()
+ MOVE_REG(a1, a0)
+ la a0, .LstrSqueak
+ JAL(printf)
+ STACK_LOAD_RA()
+ RETURN
+
+/*
+ * Print a newline, preserving registers.
+ */
+common_printNewline:
+ STACK_STORE_RA()
+ la a0, .LstrNewline
+ JAL(printf)
+ STACK_LOAD_RA()
+ RETURN
+
+ /*
+ * Print the 32-bit quantity in a0 as a hex value, preserving registers.
+ */
+common_printHex:
+ STACK_STORE_RA()
+ MOVE_REG(a1, a0)
+ la a0, .LstrPrintHex
+ JAL(printf)
+ STACK_LOAD_RA()
+RETURN;
+
+/*
+ * Print the 64-bit quantity in a0-a1, preserving registers.
+ */
+common_printLong:
+ STACK_STORE_RA()
+ MOVE_REG(a3, a1)
+ MOVE_REG(a2, a0)
+ la a0, .LstrPrintLong
+ JAL(printf)
+ STACK_LOAD_RA()
+ RETURN;
+
+/*
+ * Print full method info. Pass the Method* in a0. Preserves regs.
+ */
+common_printMethod:
+ STACK_STORE_RA()
+ JAL(dvmMterpPrintMethod)
+ STACK_LOAD_RA()
+ RETURN
+
+/*
+ * Call a C helper function that dumps regs and possibly some
+ * additional info. Requires the C function to be compiled in.
+ */
+ .if 0
+common_dumpRegs:
+ STACK_STORE_RA()
+ JAL(dvmMterpDumpMipsRegs)
+ STACK_LOAD_RA()
+ RETURN
+ .endif
+
+/*
+ * Zero-terminated ASCII string data.
+ */
+ .data
+
+.LstrBadEntryPoint:
+ .asciiz "Bad entry point %d\n"
+.LstrDivideByZero:
+ .asciiz "divide by zero"
+.LstrFilledNewArrayNotImpl:
+ .asciiz "filled-new-array only implemented for 'int'"
+.LstrLogTag:
+ .asciiz "mterp"
+.LstrExceptionNotCaughtLocally:
+ .asciiz "Exception %s from %s:%d not caught locally\n"
+
+.LstrNewline:
+ .asciiz "\n"
+.LstrSqueak:
+ .asciiz "<%d>"
+.LstrPrintHex:
+ .asciiz "<0x%x>"
+.LstrPrintLong:
+ .asciiz "<%lld>"
+
+
+ .global dvmAsmAltInstructionStart
+ .type dvmAsmAltInstructionStart, %function
+ .text
+
+dvmAsmAltInstructionStart = .L_ALT_OP_NOP
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_NOP: /* 0x00 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (0 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE: /* 0x01 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (1 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_FROM16: /* 0x02 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (2 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_16: /* 0x03 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (3 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_WIDE: /* 0x04 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (4 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (5 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (6 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_OBJECT: /* 0x07 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (7 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (8 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (9 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_RESULT: /* 0x0a */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (10 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (11 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (12 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (13 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_RETURN_VOID: /* 0x0e */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (14 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_RETURN: /* 0x0f */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (15 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_RETURN_WIDE: /* 0x10 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (16 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_RETURN_OBJECT: /* 0x11 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (17 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST_4: /* 0x12 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (18 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST_16: /* 0x13 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (19 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST: /* 0x14 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (20 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST_HIGH16: /* 0x15 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (21 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST_WIDE_16: /* 0x16 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (22 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST_WIDE_32: /* 0x17 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (23 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST_WIDE: /* 0x18 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (24 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (25 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST_STRING: /* 0x1a */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (26 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (27 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CONST_CLASS: /* 0x1c */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (28 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MONITOR_ENTER: /* 0x1d */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (29 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MONITOR_EXIT: /* 0x1e */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (30 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CHECK_CAST: /* 0x1f */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (31 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INSTANCE_OF: /* 0x20 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (32 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (33 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_NEW_INSTANCE: /* 0x22 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (34 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_NEW_ARRAY: /* 0x23 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (35 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (36 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (37 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (38 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_THROW: /* 0x27 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (39 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_GOTO: /* 0x28 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (40 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_GOTO_16: /* 0x29 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (41 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_GOTO_32: /* 0x2a */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (42 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_PACKED_SWITCH: /* 0x2b */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (43 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (44 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CMPL_FLOAT: /* 0x2d */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (45 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CMPG_FLOAT: /* 0x2e */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (46 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (47 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (48 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_CMP_LONG: /* 0x31 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (49 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_EQ: /* 0x32 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (50 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_NE: /* 0x33 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (51 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_LT: /* 0x34 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (52 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_GE: /* 0x35 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (53 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_GT: /* 0x36 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (54 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_LE: /* 0x37 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (55 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_EQZ: /* 0x38 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (56 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_NEZ: /* 0x39 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (57 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_LTZ: /* 0x3a */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (58 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_GEZ: /* 0x3b */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (59 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_GTZ: /* 0x3c */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (60 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IF_LEZ: /* 0x3d */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (61 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_UNUSED_3E: /* 0x3e */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (62 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_UNUSED_3F: /* 0x3f */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (63 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_UNUSED_40: /* 0x40 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (64 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_UNUSED_41: /* 0x41 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (65 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_UNUSED_42: /* 0x42 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (66 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_UNUSED_43: /* 0x43 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (67 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AGET: /* 0x44 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (68 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AGET_WIDE: /* 0x45 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (69 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AGET_OBJECT: /* 0x46 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (70 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (71 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AGET_BYTE: /* 0x48 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (72 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AGET_CHAR: /* 0x49 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (73 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AGET_SHORT: /* 0x4a */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (74 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_APUT: /* 0x4b */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (75 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_APUT_WIDE: /* 0x4c */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (76 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_APUT_OBJECT: /* 0x4d */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (77 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (78 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_APUT_BYTE: /* 0x4f */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (79 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_APUT_CHAR: /* 0x50 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (80 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_APUT_SHORT: /* 0x51 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (81 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET: /* 0x52 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (82 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_WIDE: /* 0x53 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (83 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_OBJECT: /* 0x54 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (84 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (85 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_BYTE: /* 0x56 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (86 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_CHAR: /* 0x57 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (87 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_SHORT: /* 0x58 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (88 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT: /* 0x59 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (89 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_WIDE: /* 0x5a */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (90 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_OBJECT: /* 0x5b */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (91 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (92 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_BYTE: /* 0x5d */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (93 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_CHAR: /* 0x5e */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (94 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_SHORT: /* 0x5f */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (95 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SGET: /* 0x60 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (96 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SGET_WIDE: /* 0x61 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (97 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SGET_OBJECT: /* 0x62 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (98 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SGET_BOOLEAN: /* 0x63 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (99 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SGET_BYTE: /* 0x64 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (100 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SGET_CHAR: /* 0x65 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (101 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SGET_SHORT: /* 0x66 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (102 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPUT: /* 0x67 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (103 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPUT_WIDE: /* 0x68 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (104 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPUT_OBJECT: /* 0x69 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (105 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (106 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPUT_BYTE: /* 0x6b */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (107 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPUT_CHAR: /* 0x6c */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (108 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPUT_SHORT: /* 0x6d */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (109 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (110 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_SUPER: /* 0x6f */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (111 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (112 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_STATIC: /* 0x71 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (113 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (114 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_UNUSED_73: /* 0x73 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (115 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (116 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (117 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (118 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (119 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (120 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_UNUSED_79: /* 0x79 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (121 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_UNUSED_7A: /* 0x7a */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (122 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_NEG_INT: /* 0x7b */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (123 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_NOT_INT: /* 0x7c */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (124 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_NEG_LONG: /* 0x7d */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (125 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_NOT_LONG: /* 0x7e */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (126 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_NEG_FLOAT: /* 0x7f */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (127 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_NEG_DOUBLE: /* 0x80 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (128 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INT_TO_LONG: /* 0x81 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (129 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (130 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (131 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_LONG_TO_INT: /* 0x84 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (132 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (133 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (134 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (135 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (136 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (137 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (138 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (139 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (140 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INT_TO_BYTE: /* 0x8d */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (141 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INT_TO_CHAR: /* 0x8e */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (142 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INT_TO_SHORT: /* 0x8f */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (143 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ADD_INT: /* 0x90 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (144 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SUB_INT: /* 0x91 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (145 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MUL_INT: /* 0x92 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (146 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DIV_INT: /* 0x93 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (147 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_REM_INT: /* 0x94 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (148 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AND_INT: /* 0x95 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (149 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_OR_INT: /* 0x96 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (150 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_XOR_INT: /* 0x97 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (151 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SHL_INT: /* 0x98 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (152 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SHR_INT: /* 0x99 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (153 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_USHR_INT: /* 0x9a */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (154 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ADD_LONG: /* 0x9b */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (155 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SUB_LONG: /* 0x9c */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (156 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MUL_LONG: /* 0x9d */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (157 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DIV_LONG: /* 0x9e */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (158 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_REM_LONG: /* 0x9f */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (159 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AND_LONG: /* 0xa0 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (160 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_OR_LONG: /* 0xa1 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (161 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_XOR_LONG: /* 0xa2 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (162 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SHL_LONG: /* 0xa3 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (163 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SHR_LONG: /* 0xa4 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (164 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_USHR_LONG: /* 0xa5 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (165 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ADD_FLOAT: /* 0xa6 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (166 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SUB_FLOAT: /* 0xa7 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (167 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MUL_FLOAT: /* 0xa8 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (168 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DIV_FLOAT: /* 0xa9 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (169 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_REM_FLOAT: /* 0xaa */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (170 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ADD_DOUBLE: /* 0xab */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (171 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SUB_DOUBLE: /* 0xac */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (172 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MUL_DOUBLE: /* 0xad */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (173 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DIV_DOUBLE: /* 0xae */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (174 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_REM_DOUBLE: /* 0xaf */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (175 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (176 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (177 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (178 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (179 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (180 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (181 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (182 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (183 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (184 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (185 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (186 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (187 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (188 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (189 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (190 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (191 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (192 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (193 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (194 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (195 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (196 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (197 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (198 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (199 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (200 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (201 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (202 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (203 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (204 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (205 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (206 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (207 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (208 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_RSUB_INT: /* 0xd1 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (209 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (210 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (211 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (212 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (213 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (214 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (215 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (216 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (217 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_MUL_INT_LIT8: /* 0xda */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (218 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (219 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_REM_INT_LIT8: /* 0xdc */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (220 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_AND_INT_LIT8: /* 0xdd */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (221 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_OR_INT_LIT8: /* 0xde */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (222 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (223 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (224 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (225 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (226 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (227 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (228 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (229 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (230 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (231 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (232 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (233 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (234 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (235 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_BREAKPOINT: /* 0xec */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (236 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (237 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_EXECUTE_INLINE: /* 0xee */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (238 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (239 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (240 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (241 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_QUICK: /* 0xf2 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (242 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (243 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (244 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_QUICK: /* 0xf5 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (245 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (246 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (247 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (248 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (249 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (250 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (251 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (252 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (253 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (254 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+/* ------------------------------ */
+ .balign 128
+.L_ALT_OP_UNUSED_FF: /* 0xff */
+/* File: mips/alt_stub.S */
+/*
+ * Inter-instruction transfer stub. Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler. Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0. Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+ lbu a3, offThread_breakFlags(rSELF)
+ la rBIX, dvmAsmInstructionStart + (255 * 128)
+ lw rIBASE, offThread_curHandlerTable(rSELF)
+ bnez a3, 1f
+ jr rBIX # nothing to do - jump to real handler
+1:
+ EXPORT_PC()
+ move a0, rPC # arg0
+ move a1, rFP # arg1
+ move a2, rSELF # arg2
+ JAL(dvmCheckBefore)
+ jr rBIX
+
+ .balign 128
+ .size dvmAsmAltInstructionStart, .-dvmAsmAltInstructionStart
+ .global dvmAsmAltInstructionEnd
+dvmAsmAltInstructionEnd:
diff --git a/vm/mterp/out/InterpAsm-x86-atom.S b/vm/mterp/out/InterpAsm-x86-atom.S
deleted file mode 100644
index aa27f89..0000000
--- a/vm/mterp/out/InterpAsm-x86-atom.S
+++ /dev/null
@@ -1,18505 +0,0 @@
-/*
- * This file was generated automatically by gen-mterp.py for 'x86-atom'.
- *
- * --> DO NOT EDIT <--
- */
-
-/* File: x86-atom/header.S */
- /* 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.
- */
-
- /*
- * File: header.S
- */
-
- /*
- * IA32 calling convention and general notes:
- *
- * EAX, ECX, EDX - general purpose scratch registers (caller-saved);
- *
- * The stack (%esp) - used to pass arguments to functions
- *
- * EAX - holds the first 4 bytes of a return
- * EDX - holds the second 4 bytes of a return
- *
- * EBX, ESI, EDI, EBP - are callee saved
- *
- * CS, DS, SS - are segment registers
- * ES, FS, GS - are segment registers. We will try to avoid using these registers
- *
- * The stack is "full descending". Only the arguments that do not fit * in the first two arg registers are placed on the stack.
- * "%esp" points to the first stacked argument (i.e. the 3rd arg).
- */
-
- /*
- * Mterp and IA32 notes
- *
- * mem nick purpose
- * (%ebp) rGLUE InterpState base pointer (A.K.A. MterpGlue Pointer)
- * %esi rPC interpreted program counter, used for fetching
- * instructions
- * %ebx rINST first 16-bit code unit of current instruction
- * %edi rFP interpreted frame pointer, used for accessing
- * locals and args
- */
-
- /*
- * Includes
- */
-
-#include "../common/asm-constants.h"
-
- /*
- * Reserved registers
- */
-
-#define rGLUE (%ebp)
-#define rINST %ebx
-#define rINSTbl %bl
-#define rINSTbh %bh
-#define rINSTw %bx
-#define rPC %esi
-#define rFP %edi
-
- /*
- * Temporary register used when finishing an opcode
- */
-
-#define rFinish %edx
-
- /*
- * Stack locations used for temporary data. For convenience.
- */
-
-#define sReg0 4(%ebp)
-#define sReg1 8(%ebp)
-#define sReg2 12(%ebp)
-#define sReg3 16(%ebp)
-
- /*
- * Save the PC and FP to the glue struct
- */
-
- .macro SAVE_PC_FP_TO_GLUE _reg
- movl rGLUE, \_reg
- movl rPC, offGlue_pc(\_reg)
- movl rFP, offGlue_fp(\_reg)
- .endm
-
- /*
- * Restore the PC and FP from the glue struct
- */
-
- .macro LOAD_PC_FP_FROM_GLUE
- movl rGLUE, rFP
- movl offGlue_pc(rFP), rPC
- movl offGlue_fp(rFP), rFP
- .endm
-
- /*
- * "Export" the PC to the stack frame, f/b/o future exception objects. This must
- * be done *before* something calls dvmThrowException.
- *
- * In C this is "SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc", i.e.
- * fp - sizeof(StackSaveArea) + offsetof(SaveArea, xtra.currentPc)
- *
- * It's okay to do this more than once.
- */
-
- .macro EXPORT_PC
- movl rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP)
- .endm
-
- /*
- * Given a frame pointer, find the stack save area.
- * In C this is "((StackSaveArea*)(_fp) -1)".
- */
-
- .macro SAVEAREA_FROM_FP _reg
- lea -sizeofStackSaveArea(rFP), \_reg
- .endm
-
- /*
- * Get the 32-bit value from a dalvik register.
- */
-
- .macro GET_VREG _vreg
- movl (rFP,\_vreg, 4), \_vreg
- .endm
-
- /*
- * Set the 32-bit value from a dalvik register.
- */
-
- .macro SET_VREG _reg _vreg
- movl \_reg, (rFP,\_vreg, 4)
- .endm
-
- /*
- * Fetch the next instruction from rPC into rINST. Does not advance rPC.
- */
-
- .macro FETCH_INST
- movzwl (rPC), rINST
- .endm
-
- /*
- * Fetch the next instruction from the specified offset. Advances rPC
- * to point to the next instruction. "_count" is in 16-bit code units.
- *
- * This must come AFTER anything that can throw an exception, or the
- * exception catch may miss. (This also implies that it must come after
- * EXPORT_PC())
- */
-
- .macro FETCH_ADVANCE_INST _count
- add $(\_count*2), rPC
- movzwl (rPC), rINST
- .endm
-
- /*
- * Fetch the next instruction from an offset specified by _reg. Updates
- * rPC to point to the next instruction. "_reg" must specify the distance
- * in bytes, *not* 16-bit code units, and may be a signed value.
- */
-
- .macro FETCH_ADVANCE_INST_RB _reg
- addl \_reg, rPC
- movzwl (rPC), rINST
- .endm
-
- /*
- * Fetch a half-word code unit from an offset past the current PC. The
- * "_count" value is in 16-bit code units. Does not advance rPC.
- * For example, given instruction of format: AA|op BBBB, it
- * fetches BBBB.
- */
-
- .macro FETCH _count _reg
- movzwl (\_count*2)(rPC), \_reg
- .endm
-
- /*
- * Fetch a half-word code unit from an offset past the current PC. The
- * "_count" value is in 16-bit code units. Does not advance rPC.
- * This variant treats the value as signed.
- */
-
- .macro FETCHs _count _reg
- movswl (\_count*2)(rPC), \_reg
- .endm
-
- /*
- * Fetch the first byte from an offset past the current PC. The
- * "_count" value is in 16-bit code units. Does not advance rPC.
- * For example, given instruction of format: AA|op CC|BB, it
- * fetches BB.
- */
-
- .macro FETCH_BB _count _reg
- movzbl (\_count*2)(rPC), \_reg
- .endm
-
- /*
- * Fetch the second byte from an offset past the current PC. The
- * "_count" value is in 16-bit code units. Does not advance rPC.
- * For example, given instruction of format: AA|op CC|BB, it
- * fetches CC.
- */
-
- .macro FETCH_CC _count _reg
- movzbl (\_count*2 + 1)(rPC), \_reg
- .endm
-
- /*
- * Fetch the second byte from an offset past the current PC. The
- * "_count" value is in 16-bit code units. Does not advance rPC.
- * This variant treats the value as signed.
- */
-
- .macro FETCH_CCs _count _reg
- movsbl (\_count*2 + 1)(rPC), \_reg
- .endm
-
-
- /*
- * Fetch one byte from an offset past the current PC. Pass in the same
- * "_count" as you would for FETCH, and an additional 0/1 indicating which
- * byte of the halfword you want (lo/hi).
- */
-
- .macro FETCH_B _reg _count _byte
- movzbl (\_count*2+\_byte)(rPC), \_reg
- .endm
-
- /*
- * Put the instruction's opcode field into the specified register.
- */
-
- .macro GET_INST_OPCODE _reg
- movzbl rINSTbl, \_reg
- .endm
-
- /*
- * Begin executing the opcode in _reg.
- */
-
- .macro GOTO_OPCODE _reg
- shl $6, \_reg
- addl $dvmAsmInstructionStart,\_reg
- jmp *\_reg
- .endm
-
-
-
- /*
- * Macros pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
- * by using a jump table. _rFinish should must be the same register for
- * both macros.
- */
-
- .macro FFETCH _rFinish
- movzbl (rPC), \_rFinish
- .endm
-
- .macro FGETOP_JMPa _rFinish
- movzbl 1(rPC), rINST
- jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
- .endm
-
- /*
- * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
- * by using a jump table. _rFinish and _count should must be the same register for
- * both macros.
- */
-
- .macro FFETCH_ADV _count _rFinish
- movzbl (\_count*2)(rPC), \_rFinish
- .endm
-
- .macro FGETOP_JMP _count _rFinish
- movzbl (\_count*2 + 1)(rPC), rINST
- addl $(\_count*2), rPC
- jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
- .endm
-
- /*
- * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
- * by using a jump table. _rFinish and _reg should must be the same register for
- * both macros.
- */
-
- .macro FFETCH_ADV_RB _reg _rFinish
- movzbl (\_reg, rPC), \_rFinish
- .endm
-
- .macro FGETOP_RB_JMP _reg _rFinish
- movzbl 1(\_reg, rPC), rINST
- addl \_reg, rPC
- jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
- .endm
-
- /*
- * Attempts to speed up FETCH_INST, GET_INST_OPCODE using
- * a jump table. This macro should be called before FINISH_JMP where
- * rFinish should be the same register containing the opcode value.
- * This is an attempt to split up FINISH in order to reduce or remove
- * potential stalls due to the wait for rFINISH.
- */
-
- .macro FINISH_FETCH _rFinish
- movzbl (rPC), \_rFinish
- movzbl 1(rPC), rINST
- .endm
-
-
- /*
- * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE using
- * a jump table. This macro should be called before FINISH_JMP where
- * rFinish should be the same register containing the opcode value.
- * This is an attempt to split up FINISH in order to reduce or remove
- * potential stalls due to the wait for rFINISH.
- */
-
- .macro FINISH_FETCH_ADVANCE _count _rFinish
- movzbl (\_count*2)(rPC), \_rFinish
- movzbl (\_count*2 + 1)(rPC), rINST
- addl $(\_count*2), rPC
- .endm
-
- /*
- * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE using
- * a jump table. This macro should be called before FINISH_JMP where
- * rFinish should be the same register containing the opcode value.
- * This is an attempt to split up FINISH in order to reduce or remove
- * potential stalls due to the wait for rFINISH.
- */
-
- .macro FINISH_FETCH_ADVANCE_RB _reg _rFinish
- movzbl (\_reg, rPC), \_rFinish
- movzbl 1(\_reg, rPC), rINST
- addl \_reg, rPC
- .endm
-
- /*
- * Attempts to speed up GOTO_OPCODE using a jump table. This macro should
- * be called after a FINISH_FETCH* instruction where rFinish should be the
- * same register containing the opcode value. This is an attempt to split up
- * FINISH in order to reduce or remove potential stalls due to the wait for rFINISH.
- */
-
- .macro FINISH_JMP _rFinish
- jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
- .endm
-
- /*
- * Attempts to speed up FETCH_INST, GET_INST_OPCODE, GOTO_OPCODE by using
- * a jump table. Uses a single macro - but it should be faster if we
- * split up the fetch for rFinish and the jump using rFinish.
- */
-
- .macro FINISH_A
- movzbl (rPC), rFinish
- movzbl 1(rPC), rINST
- jmp *dvmAsmInstructionJmpTable(,rFinish, 4)
- .endm
-
- /*
- * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE,
- * GOTO_OPCODE by using a jump table. Uses a single macro -
- * but it should be faster if we split up the fetch for rFinish
- * and the jump using rFinish.
- */
-
- .macro FINISH _count
- movzbl (\_count*2)(rPC), rFinish
- movzbl (\_count*2 + 1)(rPC), rINST
- addl $(\_count*2), rPC
- jmp *dvmAsmInstructionJmpTable(,rFinish, 4)
- .endm
-
- /*
- * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE,
- * GOTO_OPCODE by using a jump table. Uses a single macro -
- * but it should be faster if we split up the fetch for rFinish
- * and the jump using rFinish.
- */
-
- .macro FINISH_RB _reg _rFinish
- movzbl (\_reg, rPC), \_rFinish
- movzbl 1(\_reg, rPC), rINST
- addl \_reg, rPC
- jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
- .endm
-
- /*
- * Hard coded helper values.
- */
-
-.balign 16
-
-.LdoubNeg:
- .quad 0x8000000000000000
-
-.L64bits:
- .quad 0xFFFFFFFFFFFFFFFF
-
-.LshiftMask2:
- .quad 0x0000000000000000
-.LshiftMask:
- .quad 0x000000000000003F
-
-.Lvalue64:
- .quad 0x0000000000000040
-
-.LvaluePosInfLong:
- .quad 0x7FFFFFFFFFFFFFFF
-
-.LvalueNegInfLong:
- .quad 0x8000000000000000
-
-.LvalueNanLong:
- .quad 0x0000000000000000
-
-.LintMin:
-.long 0x80000000
-
-.LintMax:
-.long 0x7FFFFFFF
-
-
- .global dvmAsmInstructionStart
- .type dvmAsmInstructionStart, %function
-dvmAsmInstructionStart = .L_OP_NOP
- .text
-
-/* ------------------------------ */
- .balign 64
-.L_OP_NOP: /* 0x00 */
-/* File: x86-atom/OP_NOP.S */
- /* 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.
- */
-
- /*
- * File: OP_NOP.S
- *
- * Code: Use a cycle. Uses no substitutions.
- *
- * For: nop
- *
- * Description: No operation. Use a cycle
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- FINISH 1 # jump to next instruction
-
-#ifdef ASSIST_DEBUGGER
-
- /*
- * insert fake function header to help gdb find the stack frame
- */
-
- .type dalvik_inst, %function
-dalvik_inst:
- MTERP_ENTRY
-#endif
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE: /* 0x01 */
-/* File: x86-atom/OP_MOVE.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE.S
- *
- * Code: Copies contents from one register to another. Uses no
- * substitutions.
- *
- * For: move, move-object, long-to-int
- *
- * Description: Copies contents from one non-object register to another.
- * vA<- vB; fp[A]<- fp[B]
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, rINST # rINST<- B
- and $15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vB
- SET_VREG rINST, %ecx # vA<- vB; %edx
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_FROM16: /* 0x02 */
-/* File: x86-atom/OP_MOVE_FROM16.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_FROM16.S
- *
- * Code: Copies contents from one register to another
- *
- * For: move/from16, move-object/from16
- *
- * Description: Copies contents from one non-object register to another.
- * vA<- vB; fp[A]<- fp[B]
- *
- * Format: AA|op BBBB (22x)
- *
- * Syntax: op vAA, vBBBB
- */
-
- FETCH 1, %edx # %edx<- BBBB
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- SET_VREG %edx, rINST # vA<- vB; %edx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_16: /* 0x03 */
-/* File: x86-atom/OP_MOVE_16.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_16.S
- *
- * Code: Copies contents from one register to another
- *
- * For: move/16, move-object/16
- *
- * Description: Copies contents from one non-object register to another.
- * fp[A]<- fp[B]
- *
- * Format: ØØ|op AAAA BBBB (32x)
- *
- * Syntax: op vAAAA, vBBBB
- */
-
- FETCH 2, %edx # %edx<- BBBB
- FETCH 1, %ecx # %ecx<- AAAA
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- SET_VREG %edx, %ecx # vA<- vB; %edx
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_WIDE: /* 0x04 */
-/* File: x86-atom/OP_MOVE_WIDE.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_WIDE.S
- *
- * Code: Copies contents from one register to another. Uses no
- * substitutions.
- *
- * For: move-wide
- *
- * Description: Copies contents from one non-object register to another.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA+
- shr $4, %edx # %edx<- B
- and $15, rINST # rINST<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq %xmm0, (rFP, rINST, 4) # vA<- vB
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
-/* File: x86-atom/OP_MOVE_WIDE_FROM16.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_WIDE_FROM16.S
- *
- * Code: Copies contents from one register to another
- *
- * For: move-wide/from16
- *
- * Description: Copies contents from one non-object register to another.
- *
- * Format: AA|op BBBB (22x)
- *
- * Syntax: op vAA, vBBBB
- */
-
- FETCH 1, %edx # %edx<- BBBB
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq %xmm0, (rFP, rINST, 4) # vA<- vB
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_WIDE_16: /* 0x06 */
-/* File: x86-atom/OP_MOVE_WIDE_16.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_WIDE_16.S
- *
- * Code: Copies contents from one register to another. Uses no
- * substitutions.
- *
- * For: move-wide/16
- *
- * Description: Copies contents from one non-object register to another.
- *
- * Format: ØØ|op AAAA BBBB (32x)
- *
- * Syntax: op vAAAA, vBBBB
- */
-
- FETCH 2, %edx # %edx<- BBBB
- FETCH 1, %ecx # %ecx<- AAAA
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq %xmm0, (rFP, %ecx, 4) # vA<- vB; %xmm0
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_OBJECT: /* 0x07 */
-/* File: x86-atom/OP_MOVE_OBJECT.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_OBJECT.S
- */
-
-/* File: x86-atom/OP_MOVE.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE.S
- *
- * Code: Copies contents from one register to another. Uses no
- * substitutions.
- *
- * For: move, move-object, long-to-int
- *
- * Description: Copies contents from one non-object register to another.
- * vA<- vB; fp[A]<- fp[B]
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, rINST # rINST<- B
- and $15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vB
- SET_VREG rINST, %ecx # vA<- vB; %edx
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
-/* File: x86-atom/OP_MOVE_OBJECT_FROM16.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_OBJECT_FROM16.S
- */
-
-/* File: x86-atom/OP_MOVE_FROM16.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_FROM16.S
- *
- * Code: Copies contents from one register to another
- *
- * For: move/from16, move-object/from16
- *
- * Description: Copies contents from one non-object register to another.
- * vA<- vB; fp[A]<- fp[B]
- *
- * Format: AA|op BBBB (22x)
- *
- * Syntax: op vAA, vBBBB
- */
-
- FETCH 1, %edx # %edx<- BBBB
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- SET_VREG %edx, rINST # vA<- vB; %edx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_OBJECT_16: /* 0x09 */
-/* File: x86-atom/OP_MOVE_OBJECT_16.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_OBJECT_16.S
- */
-
-/* File: x86-atom/OP_MOVE_16.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_16.S
- *
- * Code: Copies contents from one register to another
- *
- * For: move/16, move-object/16
- *
- * Description: Copies contents from one non-object register to another.
- * fp[A]<- fp[B]
- *
- * Format: ØØ|op AAAA BBBB (32x)
- *
- * Syntax: op vAAAA, vBBBB
- */
-
- FETCH 2, %edx # %edx<- BBBB
- FETCH 1, %ecx # %ecx<- AAAA
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- SET_VREG %edx, %ecx # vA<- vB; %edx
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_RESULT: /* 0x0a */
-/* File: x86-atom/OP_MOVE_RESULT.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_RESULT.S
- *
- * Code: Copies a return value to a register
- *
- * For: move-result, move-result-object
- *
- * Description: Move the single-word non-object result of the most
- * recent method invocation into the indicated register. This
- * must be done as the instruction immediately after a
- * method invocation whose (single-word, non-object) result
- * is not to be ignored; anywhere else is invalid.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- FFETCH_ADV 1, %ecx # %ecx<- next instruction hi; fetch, advance
- movl offGlue_retval(%eax), %edx # %edx<- glue->retval
- SET_VREG %edx, rINST # vA<- glue->retval
- FGETOP_JMP 1, %ecx # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
-/* File: x86-atom/OP_MOVE_RESULT_WIDE.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_RESULT_WIDE.S
- *
- * Code: Copies a return value to a register
- *
- * For: move-result-wide
- *
- * Description: Move the double-word non-object result of the most
- * recent method invocation into the indicated register. This
- * must be done as the instruction immediately after a
- * method invocation whose (single-word, non-object) result
- * is not to be ignored; anywhere else is invalid.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- movq offGlue_retval(%eax), %xmm0 # %xmm0<- glue->retval
- movq %xmm0, (rFP, rINST, 4) # vA<- glue->retval
- FFETCH_ADV 1, %edx # %edx<- next instruction hi; fetch, advance
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
-/* File: x86-atom/OP_MOVE_RESULT_OBJECT.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_RESULT_OBJECT.S
- */
-
-/* File: x86-atom/OP_MOVE_RESULT.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_RESULT.S
- *
- * Code: Copies a return value to a register
- *
- * For: move-result, move-result-object
- *
- * Description: Move the single-word non-object result of the most
- * recent method invocation into the indicated register. This
- * must be done as the instruction immediately after a
- * method invocation whose (single-word, non-object) result
- * is not to be ignored; anywhere else is invalid.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- FFETCH_ADV 1, %ecx # %ecx<- next instruction hi; fetch, advance
- movl offGlue_retval(%eax), %edx # %edx<- glue->retval
- SET_VREG %edx, rINST # vA<- glue->retval
- FGETOP_JMP 1, %ecx # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MOVE_EXCEPTION: /* 0x0d */
-/* File: x86-atom/OP_MOVE_EXCEPTION.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE_EXCEPTION.S
- *
- * Code: Moves an exception to a register
- *
- * For: move-exception
- *
- * Description: Save a just-caught exception into the given register. This
- * instruction is only valid as the first instruction of an
- * exception handler.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_self(%eax), %ecx # %ecx<- glue->self
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- movl offThread_exception(%ecx), %edx # %edx<- glue->self->exception
- movl $0, offThread_exception(%ecx) # clear exception
- SET_VREG %edx, rINST # vAA<- glue->self->exception
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_RETURN_VOID: /* 0x0e */
-/* File: x86-atom/OP_RETURN_VOID.S */
- /* 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.
- */
-
- /*
- * File: OP_RETURN_VOID.S
- */
-
- jmp common_returnFromMethod
-
-/* ------------------------------ */
- .balign 64
-.L_OP_RETURN: /* 0x0f */
-/* File: x86-atom/OP_RETURN.S */
- /* 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.
- */
-
- /*
- * File: OP_RETURN.S
- */
-
-/* File: x86-atom/OP_RETURN_COMMON.S */
- /* 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.
- */
-
- /*
- * File: OP_RETURN_COMMON.S
- *
- * Code: Return a 32-bit value. Uses no substitutions.
- *
- * For: return, return-object
- *
- * Description: Copies the return value into the "glue"
- * structure, then jumps to the return handler.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- GET_VREG rINST # rINST<- vAA
- movl rINST, offGlue_retval(%edx) # glue->retval<- vAA
- jmp common_returnFromMethod # jump to common return code
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_RETURN_WIDE: /* 0x10 */
-/* File: x86-atom/OP_RETURN_WIDE.S */
- /* 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.
- */
-
- /*
- * File: OP_RETURN_WIDE.S
- *
- * Code: Return a 64-bit value. Uses no substitutions.
- *
- * For: return-wide
- *
- * Description: Copies the return value into the "glue"
- * structure, then jumps to the return handler.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vAA
- movq %xmm0, offGlue_retval(%edx)# glue->retval<- vAA
- jmp common_returnFromMethod # jump to common return code
-
-/* ------------------------------ */
- .balign 64
-.L_OP_RETURN_OBJECT: /* 0x11 */
-/* File: x86-atom/OP_RETURN_OBJECT.S */
- /* 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.
- */
-
- /*
- * File: OP_RETURN_OBJECT.S
- */
-
-/* File: x86-atom/OP_RETURN_COMMON.S */
- /* 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.
- */
-
- /*
- * File: OP_RETURN_COMMON.S
- *
- * Code: Return a 32-bit value. Uses no substitutions.
- *
- * For: return, return-object
- *
- * Description: Copies the return value into the "glue"
- * structure, then jumps to the return handler.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- GET_VREG rINST # rINST<- vAA
- movl rINST, offGlue_retval(%edx) # glue->retval<- vAA
- jmp common_returnFromMethod # jump to common return code
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST_4: /* 0x12 */
-/* File: x86-atom/OP_CONST_4.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST_4.S
- *
- * Code: Moves a literal to a register. Uses no substitutions.
- *
- * For: const/4
- *
- * Description: Move the given literal value (right-zero-extended to 32
- * bits) into the specified register.
- *
- * Format: B|A|op (11n)
- *
- * Syntax: op vA, #+B
- */
-
- movl rINST, %edx # %edx<- BA
- andl $15, rINST # rINST<- A
- shl $24, %edx # %edx<- B000
- sar $28, %edx # %edx<- right-zero-extended B
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- SET_VREG %edx, rINST # vA<- %edx; literal
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST_16: /* 0x13 */
-/* File: x86-atom/OP_CONST_16.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST_16.S
- *
- * Code: Moves a literal to a register. Uses no substitutions.
- *
- * For: const/16
- *
- * Description: Move the given literal value (right-zero-extended to 32
- * bits) into the specified register
- *
- * Format: AA|op BBBB (21s)
- *
- * Syntax: op vAA, #+BBBB
- */
-
- FETCHs 1, %edx # %edx<- BBBB
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- SET_VREG %edx rINST # vAA<- BBBB; literal
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST: /* 0x14 */
-/* File: x86-atom/OP_CONST.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST.S
- *
- * Code: Move a literal to a register. Uses no substitutions.
- *
- * For: const
- *
- * Description: Move the given literal value into the specified register
- *
- * Format: AA|op BBBBlo BBBBhi (31i)
- *
- * Syntax: op vAA, #+BBBBBBBB
- */
-
- FETCH 2, %edx # %edx<- BBBBhi
- FETCH 1, %ecx # %ecx<- BBBBlo
- shl $16, %edx # move BBBB to high bits
- or %edx, %ecx # %ecx<- #+BBBBBBBB
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- SET_VREG %ecx, rINST # vAA<- %ecx; literal
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST_HIGH16: /* 0x15 */
-/* File: x86-atom/OP_CONST_HIGH16.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST_HIGH16.S
- *
- * Code: Move a literal to a register. Uses no substitutions.
- *
- * For: const/high16
- *
- * Description: Move the given literal value (right-zero-extended to 32
- * bits) into the specified register
- *
- * Format: AA|op BBBB (21h)
- *
- * Syntax: op vAA, #+BBBB0000
- */
-
- FETCH 1, %ecx # %ecx<- 0000BBBB (zero-extended)
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- shl $16, %ecx # %ecx<- BBBB0000
- SET_VREG %ecx, rINST # vAA<- %ecx; BBBB0000
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST_WIDE_16: /* 0x16 */
-/* File: x86-atom/OP_CONST_WIDE_16.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST_WIDE_16.S
- *
- * Code: Move a literal to a register. Uses no substitutions.
- *
- * For: const-wide/16
- *
- * Description: Move the given literal value (sign-extended to 64 bits)
- * into the specified register-pair
- *
- * Format: AA|op BBBB (21s)
- *
- * Syntax: op vAA, #+BBBB
- */
-
- FETCHs 1, %ecx # %ecx<- ssssBBBB (sign-extended)
- movl %ecx, %edx # %edx<- ssssBBBB (sign-extended)
- sar $31, %ecx # %ecx<- sign bit
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl %edx, (rFP, rINST, 4) # vAA<- ssssBBBB
- movl %ecx, 4(rFP, rINST, 4) # vAA+1<- ssssssss
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST_WIDE_32: /* 0x17 */
-/* File: x86-atom/OP_CONST_WIDE_32.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST_WIDE_32.S
- *
- * Code: Move a literal to a register. Uses no substitutions.
- *
- * For: const-wide/32
- *
- * Description: Move the given literal value (sign-extended to 64 bits)
- * into the specified register-pair
- *
- * Format: AA|op BBBBlo BBBBhi (31i)
- *
- * Syntax: op vAA, #+BBBBBBBB
- */
-
- FETCH 1, %edx # %edx<- BBBBlo
- FETCHs 2, %ecx # %ecx<- BBBBhi
- shl $16, %ecx # prepare to create #+BBBBBBBB
- or %ecx, %edx # %edx<- %edx<- #+BBBBBBBB
- sar $31, %ecx # %ecx<- sign bit
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- movl %edx, (rFP, rINST, 4) # vAA<- BBBBBBBB
- movl %ecx, 4(rFP, rINST, 4) # vAA+1<- ssssssss
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST_WIDE: /* 0x18 */
-/* File: x86-atom/OP_CONST_WIDE.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST_WIDE.S
- *
- * Code: Move a literal to a register. Uses no substitutions.
- *
- * For: const-wide
- *
- * Description: Move the given literal value into the specified
- * register pair
- *
- * Format: AA|op BBBBlolo BBBBlohi BBBBhilo BBBBhihi (51l)
- *
- * Syntax: op vAA, #+BBBBBBBBBBBBBBBB
- */
-
- FETCH 1, %ecx # %ecx<- BBBBlolo
- FETCH 2, %edx # %edx<- BBBBlohi
- shl $16, %edx # %edx<- prepare to create #+BBBBBBBBlo
- or %edx, %ecx # %ecx<- #+BBBBBBBBlo
- movl %ecx, (rFP, rINST, 4) # vAA <- #+BBBBBBBBlo
- FETCH 3, %ecx # %ecx<- BBBBhilo
- FETCH 4, %edx # %edx<- BBBBhihi
- FFETCH_ADV 5, %eax # %eax<- next instruction hi; fetch, advance
- shl $16, %edx # %edx<- prepare to create #+BBBBBBBBhi
- or %edx, %ecx # %ecx<- #+BBBBBBBBhi
- movl %ecx, 4(rFP, rINST, 4) # vAA+1 <- #+BBBBBBBBlo
- FGETOP_JMP 5, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
-/* File: x86-atom/OP_CONST_WIDE_HIGH16.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST_WIDE_HIGH16.S
- *
- * Code: Move a literal value to a register. Uses no substitutions.
- *
- * For: const-wide/high16
- *
- * Description: Move the given literal value (right-zero-extended to 64
- * bits) into the specified register
- *
- * Format: AA|op BBBB (21h)
- *
- * Syntax: op vAA, #+BBBB000000000000
- */
-
- FETCH 1, %ecx # %ecx<- 0000BBBB (zero-extended)
- shl $16, %ecx # rINST<- AA
- movl $0, (rFP, rINST, 4) # vAAlow<- 00000000
- movl %ecx, 4(rFP, rINST, 4) # vAAhigh<- %ecx; BBBB0000
- FINISH 2 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST_STRING: /* 0x1a */
-/* File: x86-atom/OP_CONST_STRING.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST_STRING.S
- *
- * Code: Move a string reference to a register. Uses no substitutions.
- *
- * For: const/string
- *
- * Description: Move a referece to the string specified by the given
- * index into the specified register. vAA <- pResString[BBBB]
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- FETCH 1, %ecx # %ecx<- BBBB
- movl rGLUE, %edx # get MterpGlue pointer
- movl offGlue_methodClassDex(%edx), %eax # %eax<- glue->methodClassDex
- movl offDvmDex_pResStrings(%eax), %eax # %eax<- glue->methodClassDex->pResStrings
- movl (%eax, %ecx, 4), %eax # %eax<- pResStrings[BBBB]
- cmp $0, %eax # check if string is resolved
- je .LOP_CONST_STRING_resolve # resolve string reference
- SET_VREG %eax, rINST # vAA<- %eax; pResString[BBBB]
- FINISH 2 # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST_STRING_JUMBO: /* 0x1b */
-/* File: x86-atom/OP_CONST_STRING_JUMBO.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST_STRING_JUMBO.S
- *
- * Code: Move a string reference to a register. Uses no substitutions.
- *
- * For: const/string-jumbo
- *
- * Description: Move a reference to the string specified by the given
- * index into the specified register. vAA <- pResString[BBBB]
- *
- * Format: AA|op BBBBlo BBBBhi (31c)
- *
- * Syntax: op vAA, string@BBBBBBBB
- */
-
- movl rGLUE, %edx # get MterpGlue pointer
- movl offGlue_methodClassDex(%edx), %eax # %eax<- glue->methodClassDex
- movl offDvmDex_pResStrings(%eax), %eax # %eax<- glue->methodClassDex->pResStrings
- FETCH 1, %ecx # %ecx<- BBBBlo
- FETCH 2, %edx # %edx<- BBBBhi
- shl $16, %edx # %edx<- prepare to create &BBBBBBBB
- or %edx, %ecx # %ecx<- &BBBBBBBB
- movl (%eax, %ecx, 4), %eax # %eax<- pResStrings[BBBB]
- cmp $0, %eax # check if string is resolved
- je .LOP_CONST_STRING_JUMBO_resolve # resolve string reference
- SET_VREG %eax, rINST # vAA<- %eax; pResString[BBBB]
- FINISH 3 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CONST_CLASS: /* 0x1c */
-/* File: x86-atom/OP_CONST_CLASS.S */
- /* 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.
- */
-
- /*
- * File: OP_CONST_CLASS.S
- *
- * Code: Move a class reference to a register. Uses no substitutions.
- *
- * For: const/class
- *
- * Description: Move a reference to the class specified
- * by the given index into the specified register.
- * In the case where the indicated type is primitive,
- * this will store a reference to the primitive type's
- * degenerate class.
- *
- * Format: AA|op BBBBlo BBBBhi (21c)
- *
- * Syntax: op vAA, field@BBBB
- */
-
- movl rGLUE, %edx # get MterpGlue pointer
- FETCH 1, %ecx # %ecx<- BBBB
- movl offGlue_methodClassDex(%edx), %eax # %eax<- pDvmDex
- movl offDvmDex_pResClasses(%eax), %eax # %eax<- pDvmDex->pResClasses
- movl (%eax, %ecx, 4), %eax # %eax<- resolved class
- cmp $0, %eax # check if classes is resolved before?
- je .LOP_CONST_CLASS_resolve # resolve class
- SET_VREG %eax, rINST # vAA<- resolved class
- FINISH 2 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MONITOR_ENTER: /* 0x1d */
-/* File: x86-atom/OP_MONITOR_ENTER.S */
- /* 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.
- */
-
- /*
- * File: OP_MONITOR_ENTER.S
- *
- * Code: Aquire a monitor
- *
- * For: monitor-enter
- *
- * Description: Aquire a monitor for the indicated object.
- *
- *
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- GET_VREG rINST # rINST<- vAA
- cmp $0, rINST # check for null object
- movl offGlue_self(%eax), %eax # %eax<- glue->self
- EXPORT_PC # need for precise GC
- je common_errNullObject # handle null object
-# jmp .LOP_MONITOR_ENTER_finish
-#%break
-#.LOP_MONITOR_ENTER_finish:
- movl rINST, -4(%esp) # push parameter reference
- movl %eax, -8(%esp) # push parameter
- lea -8(%esp), %esp
- call dvmLockObject # call: (struct Thread* self,
- # struct Object* obj)
- # return: void
- FFETCH_ADV 1, %edx # %edx<- next instruction hi; fetch, advance
- lea 8(%esp), %esp
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MONITOR_EXIT: /* 0x1e */
-/* File: x86-atom/OP_MONITOR_EXIT.S */
- /* 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.
- */
-
- /*
- * File: OP_MONITOR_EXIT.S
- *
- * Code: Release a monitor
- *
- * For: monitor-exit
- *
- * Description: Release a monitor for the indicated object. If this instruction needs
- * to throw an execption, it must do so as if the pc has already
- * advanced pased the instruction.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- EXPORT_PC # export the pc
- GET_VREG rINST # rINST<- vAA
- cmp $0, rINST # rINST<- check for null object
- je common_errNullObject # handle null object
- push rINST # push parameter object
- push offGlue_self(%eax) # push parameter self
- call dvmUnlockObject # call: (struct Thread* self,
- # struct Object* obj)
- # return: bool
- FINISH_FETCH_ADVANCE 1, %edx # advance pc before exception
- cmp $0, %eax # check for success
- lea 8(%esp), %esp
- je common_exceptionThrown # handle exception
- FINISH_JMP %edx # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CHECK_CAST: /* 0x1f */
-/* File: x86-atom/OP_CHECK_CAST.S */
- /* 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.
- */
-
- /*
- * File: OP_CHECK_CAST.S
- *
- * Code: Checks to see if a cast is allowed. Uses no substitutions.
- *
- * For: check-cast
- *
- * Description: Throw if the reference in the given register cannot be
- * cast to the indicated type. The type must be a reference
- * type (not a primitive type).
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, type@BBBB
- */
-
- movl rGLUE, %edx # get MterpGlue pointer
- movl offGlue_methodClassDex(%edx), %eax # %eax<- pDvmDex
- GET_VREG rINST # rINST<- vAA
- movl offDvmDex_pResClasses(%eax), %eax # %eax<- pDvmDex->pResClasses
- cmp $0, rINST # check for null reference object
- je .LOP_CHECK_CAST_okay # can always cast null object
- FETCH 1, %ecx # %ecx<- BBBB
- movl (%eax, %ecx, 4), %ecx # %ecx<- resolved class
- cmp $0, %ecx # check if classes is resolved before?
- je .LOP_CHECK_CAST_resolve # resolve class
- jmp .LOP_CHECK_CAST_resolved # continue
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INSTANCE_OF: /* 0x20 */
-/* File: x86-atom/OP_INSTANCE_OF.S */
- /* 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.
- */
-
- /*
- * File: OP_INSTANCE_OF.S
- *
- * Code: Checks if object is instance of a class. Uses no substitutions.
- *
- * For: instance-of
- *
- * Description: Store in the given destination register 1 if the indicated
- * reference is an instance of the given type, or 0 if not.
- * The type must be a reference type (not a primitive type).
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- GET_VREG %edx # %edx<- vB
- cmp $0, %edx # check for null object
- je .LOP_INSTANCE_OF_store # null object
- jmp .LOP_INSTANCE_OF_break
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ARRAY_LENGTH: /* 0x21 */
-/* File: x86-atom/OP_ARRAY_LENGTH.S */
- /* 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.
- */
-
- /*
- * File: OP_ARRAY_LENGTH.S
- *
- * Code: 32-bit array length operation.
- *
- * For: array-length
- *
- * Description: Store the length of the indicated array in the given
- * destination register. vB <- offArrayObject_length(vA)
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %eax # %eax<- BA
- shr $4, %eax # %eax<- B
- andl $15, rINST # rINST<- A
- GET_VREG %eax # %eax<- vB
- cmp $0, %eax # check for null array object
- je common_errNullObject # handle null array object
- FFETCH_ADV 1, %edx # %edx<- next instruction hi; fetch, advance
- movl offArrayObject_length(%eax), %eax # %eax<- array length
- movl %eax, (rFP, rINST, 4) # vA<- %eax; array length
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_NEW_INSTANCE: /* 0x22 */
-/* File: x86-atom/OP_NEW_INSTANCE.S */
- /* 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.
- */
-
- /*
- * File: OP_NEW_INSTANCE.S
- *
- * Code: Create a new instance of a given type. Uses no substitutions.
- *
- * For: new-instance
- *
- * Description: Construct a new instance of the indicated type,
- * storing a reference to it in the destination.
- * The type must refer to a non-array class.
- *
- *
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, type@BBBB
- * op vAA, field@BBBB
- * op vAA, string@BBBB
- */
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_methodClassDex(%ecx), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %edx # %edx<- BBBB
- movl offDvmDex_pResClasses(%ecx), %ecx # %ecx<- glue->pDvmDex->pResClasses
- movl (%ecx, %edx, 4), %edx # %edx<- vB
- EXPORT_PC # required for resolve
- cmp $0, %edx # check for null
- je .LOP_NEW_INSTANCE_resolve # need to resolve
-
- /*
- * %edx holds class object
- */
-
-.LOP_NEW_INSTANCE_resolved:
- movzbl offClassObject_status(%edx), %eax # %eax<- class status
- cmp $CLASS_INITIALIZED, %eax # check if class is initialized
- jne .LOP_NEW_INSTANCE_needinit # initialize class
-
- /*
- * %edx holds class object
- */
-
-.LOP_NEW_INSTANCE_initialized:
- testl $(ACC_INTERFACE|ACC_ABSTRACT), offClassObject_accessFlags(%edx)
- mov $ALLOC_DONT_TRACK, %eax # %eax<- flag for alloc call
- je .LOP_NEW_INSTANCE_finish # continue
- jmp .LOP_NEW_INSTANCE_abstract # handle abstract or interface
-
- /*
- * %edx holds class object
- * %eax holds flags for alloc call
- */
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_NEW_ARRAY: /* 0x23 */
-/* File: x86-atom/OP_NEW_ARRAY.S */
- /* 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.
- */
-
- /*
- * File: OP_NEW_ARRAY.S
- *
- * Code: Create a new array. Uses no substitutions.
- *
- * For: new-array
- *
- * Description: Construct a new array of the indicated type and size.
- * The type must be an array type.
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- movl offGlue_methodClassDex(%eax), %eax # %eax<- glue->pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- GET_VREG %edx # %edx<- vB
- movl offDvmDex_pResClasses(%eax), %eax # %eax<- glue->pDvmDex->pResClasses
- cmp $0, %edx # check for negative length
- movl (%eax, %ecx, 4), %eax # %eax<- resolved class
- js common_errNegativeArraySize # handle negative array length
- cmp $0, %eax # check for null
- EXPORT_PC # required for resolve
- jne .LOP_NEW_ARRAY_finish # already resovled so continue
- jmp .LOP_NEW_ARRAY_resolve # need to resolve
-
-/* ------------------------------ */
- .balign 64
-.L_OP_FILLED_NEW_ARRAY: /* 0x24 */
-/* File: x86-atom/OP_FILLED_NEW_ARRAY.S */
- /* 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.
- */
-
- /*
- * File: OP_FILLED_NEW_ARRAY.S
- *
- * Code: Constructs and fills an array with the given data. Provides
- *
- * For: float-to-int
- *
- * Description: Construct an array of the given type and size,
- * filling it with the supplied contents. The type
- * must be an array type. The array's contents
- * must be single-word. The constructed instance
- * is stored as a result in the same way that the
- * method invocation instructions store their results,
- * so the constructed instance must be moved to a
- * register with a subsequent move-result-object
- * instruction.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc) (range)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, vtaboff@CCCC
- * [B=4] op {vD, vE, vF, vG}, vtaboff@CCCC
- * [B=3] op {vD, vE, vF}, vtaboff@CCCC
- * [B=2] op {vD, vE}, vtaboff@CCCC
- * [B=1] op {vD}, vtaboff@CCCC
- *
- * op {vCCCC .. vNNNN}, meth@BBBB
- * op {vCCCC .. vNNNN}, type@BBBB
- */
-
-
- movl rGLUE, %edx # %edx<- MterpGlue pointer
- movl offGlue_methodClassDex(%edx), %edx # %edx<- glue->methodClassDex
- movl offDvmDex_pResClasses(%edx), %edx # %edx<- glue->methodClassDex->pResClasses
- FETCH 1, %ecx # %ecx<- BBBB
- EXPORT_PC
- movl (%edx, %ecx, 4), %eax # %eax<- possibly resolved class
- cmp $0, %eax # %eax<- check if already resolved
- jne .LOP_FILLED_NEW_ARRAY_continue
- jmp .LOP_FILLED_NEW_ARRAY_break
-
-/* ------------------------------ */
- .balign 64
-.L_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
-/* File: x86-atom/OP_FILLED_NEW_ARRAY_RANGE.S */
- /* 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.
- */
-
- /*
- * File: OP_FILLED_NEW_ARRAY_RANGE.S
- */
-
-/* File: x86-atom/OP_FILLED_NEW_ARRAY.S */
- /* 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.
- */
-
- /*
- * File: OP_FILLED_NEW_ARRAY.S
- *
- * Code: Constructs and fills an array with the given data. Provides
- *
- * For: float-to-int
- *
- * Description: Construct an array of the given type and size,
- * filling it with the supplied contents. The type
- * must be an array type. The array's contents
- * must be single-word. The constructed instance
- * is stored as a result in the same way that the
- * method invocation instructions store their results,
- * so the constructed instance must be moved to a
- * register with a subsequent move-result-object
- * instruction.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc) (range)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, vtaboff@CCCC
- * [B=4] op {vD, vE, vF, vG}, vtaboff@CCCC
- * [B=3] op {vD, vE, vF}, vtaboff@CCCC
- * [B=2] op {vD, vE}, vtaboff@CCCC
- * [B=1] op {vD}, vtaboff@CCCC
- *
- * op {vCCCC .. vNNNN}, meth@BBBB
- * op {vCCCC .. vNNNN}, type@BBBB
- */
-
-
- movl rGLUE, %edx # %edx<- MterpGlue pointer
- movl offGlue_methodClassDex(%edx), %edx # %edx<- glue->methodClassDex
- movl offDvmDex_pResClasses(%edx), %edx # %edx<- glue->methodClassDex->pResClasses
- FETCH 1, %ecx # %ecx<- BBBB
- EXPORT_PC
- movl (%edx, %ecx, 4), %eax # %eax<- possibly resolved class
- cmp $0, %eax # %eax<- check if already resolved
- jne .LOP_FILLED_NEW_ARRAY_RANGE_continue
- jmp .LOP_FILLED_NEW_ARRAY_RANGE_break
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_FILL_ARRAY_DATA: /* 0x26 */
-/* File: x86-atom/OP_FILL_ARRAY_DATA.S */
- /* 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.
- */
-
- /*
- * File: OP_FILL_ARRAY_DATA.S
- *
- * Code: Fills an array with given data. Uses no substitutions.
- *
- * For: fill-array-data
- *
- * Description: Fill the given array with the idicated data. The reference
- * must be an array of primitives, and the data table must
- * match it in type and size
- *
- * Format: AA|op BBBBlo BBBBhi (31t)
- *
- * Syntax: op vAA, +BBBBBBBB
- */
-
- FETCH 1, %ecx # %ecx<- BBBBlo
- FETCH 2, %edx # %edx<- BBBBhi
- shl $16, %edx # prepare to create +BBBBBBBB
- or %ecx, %edx # %edx<- +BBBBBBBB
- lea (rPC, %edx, 2), %edx # %edx<- PC + +BBBBBBBB; array data location
- EXPORT_PC
- push %edx
- push (rFP, rINST, 4)
- call dvmInterpHandleFillArrayData # call: (ArrayObject* arrayObject, const u2* arrayData)
- # return: bool
- FFETCH_ADV 3, %edx # %edx<- next instruction hi; fetch, advance
- cmp $0, %eax
- lea 8(%esp), %esp
- je common_exceptionThrown
- FGETOP_JMP 3, %edx # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_THROW: /* 0x27 */
-/* File: x86-atom/OP_THROW.S */
- /* 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.
- */
-
- /*
- * File: OP_THROW.S
- *
- * Code: Throw an exception
- *
- * For: throw
- *
- * Description: Throw an exception object in the current thread.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- EXPORT_PC # export the pc
- GET_VREG rINST # rINST<- vAA
- cmp $0, rINST # check for null
- movl offGlue_self(%eax), %ecx # %ecx<- glue->self
- je common_errNullObject # handle null object
- movl rINST, offThread_exception(%ecx) # thread->exception<- object
- jmp common_exceptionThrown # handle exception
-
-/* ------------------------------ */
- .balign 64
-.L_OP_GOTO: /* 0x28 */
-/* File: x86-atom/OP_GOTO.S */
- /* 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.
- */
-
- /*
- * File: OP_GOTO.S
- *
- * Code: Do an unconditional branch. Uses no substitutions.
- *
- * For: goto
- *
- * Description: Performs an unconditionally jump to the indicated instruction.
- * The branch uses an 8-bit offset that cannot be zero.
- *
- * Format: AA|op (10t)
- *
- * Syntax: op +AA
- */
-
-LOP_GOTO.S:
-
- movsbl rINSTbl, %edx # %edx<- +AA
- shl $1, %edx # %edx is shifted for byte offset
- js common_periodicChecks_backwardBranch # do check on backwards branch
- FINISH_RB %edx, %ecx # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_GOTO_16: /* 0x29 */
-/* File: x86-atom/OP_GOTO_16.S */
- /* 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.
- */
-
- /*
- * File: OP_GOTO_16.S
- *
- * Code: Do an unconditional branch. Uses no substitutions.
- *
- * For: goto/16
- *
- * Description: Performs an unconditionally jump to the indicated instruction.
- * The branch uses a 16-bit offset that cannot be zero.
- *
- * Format: ØØ|op AAAA (20t)
- *
- * Syntax: op +AAAA
- */
-
- FETCHs 1, %edx # %edx<- ssssAAAA (sign-extended)
- shl $1, %edx # %edx is doubled to get the byte offset
- js common_periodicChecks_backwardBranch # do check on backwards branch
- FINISH_RB %edx, %ecx # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_GOTO_32: /* 0x2a */
-/* File: x86-atom/OP_GOTO_32.S */
- /* 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.
- */
-
- /*
- * File: OP_GOTO_32.S
- *
- * Code: Do an unconditional branch. Uses no substitutions.
- *
- * For: goto/32
- *
- * Description: Performs an unconditionally jump to the indicated instruction.
- * The branch uses a 32-bit offset that can be zero.
- *
- * Format: ØØ|op AAAAlo AAAAhi (30t)
- *
- * Syntax: op +AAAAAAAA
- */
-
- FETCH 1, %edx # %edx<- AAAAlo
- FETCH 2, %ecx # %ecx<- AAAAhi
- shl $16, %ecx # prepare to create +AAAAAAAA
- or %ecx, %edx # %edx<- +AAAAAAAA
- shl $1, %edx # %edx is doubled to get the byte offset
- jle common_periodicChecks_backwardBranch # do check on backwards branch
- FINISH_RB %edx, %ecx # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_PACKED_SWITCH: /* 0x2b */
-/* File: x86-atom/OP_PACKED_SWITCH.S */
- /* 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.
- */
-
- /*
- * File: OP_PACKED_SWITCH.S
- *
- * Code: Jump to a new instruction using a jump table
- *
- * For: packed-switch, sparse-switch
- *
- * Description: Jump to a new instruction based on the value in the given
- * register, using a table of offsets corresponding to each
- * value in a particular integral range, or fall through to
- * the next instruction if there is no match.
- *
- * Format: AA|op BBBBlo BBBBhi (31t)
- *
- * Syntax: op vAA, +BBBBBBBB
- */
-
-
- FETCH 1, %ecx # %ecx<- BBBBlo
- FETCH 2, %edx # %edx<- BBBBhi
- shl $16, %edx # prepare to create +BBBBBBBB
- or %edx, %ecx # %ecx<- +BBBBBBBB
- GET_VREG rINST # rINST<- vAA
- movl rINST, -4(%esp) # push parameter vAA
- lea (rPC, %ecx, 2), %ecx # %ecx<- PC + +BBBBBBBB*2
- movl %ecx, -8(%esp) # push parameter PC + +BBBBBBBB*2
- lea -8(%esp), %esp
- call dvmInterpHandlePackedSwitch # call code-unit branch offset
- shl $1, %eax # shift for byte offset
- movl %eax, %edx # %edx<- offset
- lea 8(%esp), %esp
- jle common_periodicChecks_backwardBranch # do backward branch
- jmp .LOP_PACKED_SWITCH_finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SPARSE_SWITCH: /* 0x2c */
-/* File: x86-atom/OP_SPARSE_SWITCH.S */
- /* 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.
- */
-
- /*
- * File: OP_SPARSE_SWITCH.S
- */
-
-/* File: x86-atom/OP_PACKED_SWITCH.S */
- /* 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.
- */
-
- /*
- * File: OP_PACKED_SWITCH.S
- *
- * Code: Jump to a new instruction using a jump table
- *
- * For: packed-switch, sparse-switch
- *
- * Description: Jump to a new instruction based on the value in the given
- * register, using a table of offsets corresponding to each
- * value in a particular integral range, or fall through to
- * the next instruction if there is no match.
- *
- * Format: AA|op BBBBlo BBBBhi (31t)
- *
- * Syntax: op vAA, +BBBBBBBB
- */
-
-
- FETCH 1, %ecx # %ecx<- BBBBlo
- FETCH 2, %edx # %edx<- BBBBhi
- shl $16, %edx # prepare to create +BBBBBBBB
- or %edx, %ecx # %ecx<- +BBBBBBBB
- GET_VREG rINST # rINST<- vAA
- movl rINST, -4(%esp) # push parameter vAA
- lea (rPC, %ecx, 2), %ecx # %ecx<- PC + +BBBBBBBB*2
- movl %ecx, -8(%esp) # push parameter PC + +BBBBBBBB*2
- lea -8(%esp), %esp
- call dvmInterpHandleSparseSwitch # call code-unit branch offset
- shl $1, %eax # shift for byte offset
- movl %eax, %edx # %edx<- offset
- lea 8(%esp), %esp
- jle common_periodicChecks_backwardBranch # do backward branch
- jmp .LOP_SPARSE_SWITCH_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CMPL_FLOAT: /* 0x2d */
-/* File: x86-atom/OP_CMPL_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_CMPL_FLOAT.S
- *
- * Code: Provides a "nan" variable to specify the return value for
- * NaN. Provides a variable "sod" which appends a "s" or a "d"
- * to the move and comparison instructions, depending on if we
- * are working with a float or a double. For instructions
- * cmpx-float and cmpx-double, the x will be eiher a g or a l
- * to specify positive or negative bias for NaN.
- *
- * For: cmpg-double, dmpg-float, cmpl-double, cmpl-float
- *
- * Description: Perform the indicated floating point or long comparison,
- * storing 0 if the two arguments are equal, 1 if the second
- * argument is larger, or -1 if the first argument is larger.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movss (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- comiss (rFP, %edx, 4), %xmm0 # do comparison
- ja .LOP_CMPL_FLOAT_greater
- jp .LOP_CMPL_FLOAT_finalNan
- jz .LOP_CMPL_FLOAT_final
-
-.LOP_CMPL_FLOAT_less:
- movl $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CMPG_FLOAT: /* 0x2e */
-/* File: x86-atom/OP_CMPG_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_CMPG_FLOAT.S
- */
-
-/* File: x86-atom/OP_CMPL_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_CMPL_FLOAT.S
- *
- * Code: Provides a "nan" variable to specify the return value for
- * NaN. Provides a variable "sod" which appends a "s" or a "d"
- * to the move and comparison instructions, depending on if we
- * are working with a float or a double. For instructions
- * cmpx-float and cmpx-double, the x will be eiher a g or a l
- * to specify positive or negative bias for NaN.
- *
- * For: cmpg-double, dmpg-float, cmpl-double, cmpl-float
- *
- * Description: Perform the indicated floating point or long comparison,
- * storing 0 if the two arguments are equal, 1 if the second
- * argument is larger, or -1 if the first argument is larger.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movss (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- comiss (rFP, %edx, 4), %xmm0 # do comparison
- ja .LOP_CMPG_FLOAT_greater
- jp .LOP_CMPG_FLOAT_finalNan
- jz .LOP_CMPG_FLOAT_final
-
-.LOP_CMPG_FLOAT_less:
- movl $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CMPL_DOUBLE: /* 0x2f */
-/* File: x86-atom/OP_CMPL_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_CMPL_DOUBLE.S
- */
-
-/* File: x86-atom/OP_CMPL_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_CMPL_FLOAT.S
- *
- * Code: Provides a "nan" variable to specify the return value for
- * NaN. Provides a variable "sod" which appends a "s" or a "d"
- * to the move and comparison instructions, depending on if we
- * are working with a float or a double. For instructions
- * cmpx-float and cmpx-double, the x will be eiher a g or a l
- * to specify positive or negative bias for NaN.
- *
- * For: cmpg-double, dmpg-float, cmpl-double, cmpl-float
- *
- * Description: Perform the indicated floating point or long comparison,
- * storing 0 if the two arguments are equal, 1 if the second
- * argument is larger, or -1 if the first argument is larger.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movsd (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- comisd (rFP, %edx, 4), %xmm0 # do comparison
- ja .LOP_CMPL_DOUBLE_greater
- jp .LOP_CMPL_DOUBLE_finalNan
- jz .LOP_CMPL_DOUBLE_final
-
-.LOP_CMPL_DOUBLE_less:
- movl $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CMPG_DOUBLE: /* 0x30 */
-/* File: x86-atom/OP_CMPG_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_CMPG_DOUBLE.S
- */
-
-/* File: x86-atom/OP_CMPL_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_CMPL_FLOAT.S
- *
- * Code: Provides a "nan" variable to specify the return value for
- * NaN. Provides a variable "sod" which appends a "s" or a "d"
- * to the move and comparison instructions, depending on if we
- * are working with a float or a double. For instructions
- * cmpx-float and cmpx-double, the x will be eiher a g or a l
- * to specify positive or negative bias for NaN.
- *
- * For: cmpg-double, dmpg-float, cmpl-double, cmpl-float
- *
- * Description: Perform the indicated floating point or long comparison,
- * storing 0 if the two arguments are equal, 1 if the second
- * argument is larger, or -1 if the first argument is larger.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movsd (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- comisd (rFP, %edx, 4), %xmm0 # do comparison
- ja .LOP_CMPG_DOUBLE_greater
- jp .LOP_CMPG_DOUBLE_finalNan
- jz .LOP_CMPG_DOUBLE_final
-
-.LOP_CMPG_DOUBLE_less:
- movl $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_CMP_LONG: /* 0x31 */
-/* File: x86-atom/OP_CMP_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_CMP_LONG.S
- *
- * Code: Compare floating point values. Uses no substitutions.
- *
- * For: cmp-long
- *
- * Description: Perform a long comparison, storing 0 if the two
- * arguments are equal, 1 if the second argument is larger
- * or -1 if the first argument is larger.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- movl 4(rFP, %ecx, 4), %eax # %eax<- vBBhi
- cmp 4(rFP, %edx, 4), %eax # compare vCChi and vBBhi
- jl .LOP_CMP_LONG_less
- jg .LOP_CMP_LONG_greater
- movl (rFP, %ecx, 4), %eax # %eax<- vBBlo
- cmp (rFP, %edx, 4), %eax # compare vCClo and vBBlo
- ja .LOP_CMP_LONG_greater
- jne .LOP_CMP_LONG_less
- jmp .LOP_CMP_LONG_final
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_EQ: /* 0x32 */
-/* File: x86-atom/OP_IF_EQ.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_EQ.S
- */
-
-/* File: x86-atom/bincmp.S */
- /* 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.
- */
-
- /*
- * File: bincmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform.
- *
- * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
- *
- * Description: Branch to the given destination if the comparison
- * test between the given registers values is true.
- *
- * Format: B|A|op CCCC (22t)
- *
- * Syntax: op vA, vB, +CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- andl $15, rINST # rINST<- A
- shr $4, %eax # %eax<- B
- GET_VREG rINST # rINST<- vA
- movl $4, %edx # %edx<- 4
- cmp (rFP, %eax, 4), rINST # compare vA and vB
- jne 1f # goto next instruction if reverse
- # comparison is true
- FETCHs 1, %edx # %edx<- +CCCC, Branch offset
- sal $1, %edx
- js common_periodicChecks_backwardBranch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_NE: /* 0x33 */
-/* File: x86-atom/OP_IF_NE.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_NE.S
- */
-
-/* File: x86-atom/bincmp.S */
- /* 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.
- */
-
- /*
- * File: bincmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform.
- *
- * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
- *
- * Description: Branch to the given destination if the comparison
- * test between the given registers values is true.
- *
- * Format: B|A|op CCCC (22t)
- *
- * Syntax: op vA, vB, +CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- andl $15, rINST # rINST<- A
- shr $4, %eax # %eax<- B
- GET_VREG rINST # rINST<- vA
- movl $4, %edx # %edx<- 4
- cmp (rFP, %eax, 4), rINST # compare vA and vB
- je 1f # goto next instruction if reverse
- # comparison is true
- FETCHs 1, %edx # %edx<- +CCCC, Branch offset
- sal $1, %edx
- js common_periodicChecks_backwardBranch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_LT: /* 0x34 */
-/* File: x86-atom/OP_IF_LT.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_LT.S
- */
-
-/* File: x86-atom/bincmp.S */
- /* 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.
- */
-
- /*
- * File: bincmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform.
- *
- * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
- *
- * Description: Branch to the given destination if the comparison
- * test between the given registers values is true.
- *
- * Format: B|A|op CCCC (22t)
- *
- * Syntax: op vA, vB, +CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- andl $15, rINST # rINST<- A
- shr $4, %eax # %eax<- B
- GET_VREG rINST # rINST<- vA
- movl $4, %edx # %edx<- 4
- cmp (rFP, %eax, 4), rINST # compare vA and vB
- jge 1f # goto next instruction if reverse
- # comparison is true
- FETCHs 1, %edx # %edx<- +CCCC, Branch offset
- sal $1, %edx
- js common_periodicChecks_backwardBranch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_GE: /* 0x35 */
-/* File: x86-atom/OP_IF_GE.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_GE.S
- */
-
-/* File: x86-atom/bincmp.S */
- /* 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.
- */
-
- /*
- * File: bincmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform.
- *
- * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
- *
- * Description: Branch to the given destination if the comparison
- * test between the given registers values is true.
- *
- * Format: B|A|op CCCC (22t)
- *
- * Syntax: op vA, vB, +CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- andl $15, rINST # rINST<- A
- shr $4, %eax # %eax<- B
- GET_VREG rINST # rINST<- vA
- movl $4, %edx # %edx<- 4
- cmp (rFP, %eax, 4), rINST # compare vA and vB
- jl 1f # goto next instruction if reverse
- # comparison is true
- FETCHs 1, %edx # %edx<- +CCCC, Branch offset
- sal $1, %edx
- js common_periodicChecks_backwardBranch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_GT: /* 0x36 */
-/* File: x86-atom/OP_IF_GT.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_GT.S
- */
-
-/* File: x86-atom/bincmp.S */
- /* 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.
- */
-
- /*
- * File: bincmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform.
- *
- * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
- *
- * Description: Branch to the given destination if the comparison
- * test between the given registers values is true.
- *
- * Format: B|A|op CCCC (22t)
- *
- * Syntax: op vA, vB, +CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- andl $15, rINST # rINST<- A
- shr $4, %eax # %eax<- B
- GET_VREG rINST # rINST<- vA
- movl $4, %edx # %edx<- 4
- cmp (rFP, %eax, 4), rINST # compare vA and vB
- jle 1f # goto next instruction if reverse
- # comparison is true
- FETCHs 1, %edx # %edx<- +CCCC, Branch offset
- sal $1, %edx
- js common_periodicChecks_backwardBranch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_LE: /* 0x37 */
-/* File: x86-atom/OP_IF_LE.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_LE.S
- */
-
-/* File: x86-atom/bincmp.S */
- /* 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.
- */
-
- /*
- * File: bincmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform.
- *
- * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
- *
- * Description: Branch to the given destination if the comparison
- * test between the given registers values is true.
- *
- * Format: B|A|op CCCC (22t)
- *
- * Syntax: op vA, vB, +CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- andl $15, rINST # rINST<- A
- shr $4, %eax # %eax<- B
- GET_VREG rINST # rINST<- vA
- movl $4, %edx # %edx<- 4
- cmp (rFP, %eax, 4), rINST # compare vA and vB
- jg 1f # goto next instruction if reverse
- # comparison is true
- FETCHs 1, %edx # %edx<- +CCCC, Branch offset
- sal $1, %edx
- js common_periodicChecks_backwardBranch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_EQZ: /* 0x38 */
-/* File: x86-atom/OP_IF_EQZ.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_EQZ.S
- */
-
-/* File: x86-atom/zcmp.S */
- /* 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.
- */
-
- /*
- * File: zcmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform
- *
- * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
- *
- * Description: Branch to the given destination if the given register's
- * value compares with 0 as specified.
- *
- * Format: AA|op BBBB (21t)
- *
- * Syntax: op vAA, +BBBB
- */
-
- cmp $0, (rFP, rINST, 4) # compare vAA with zero
- jne OP_IF_EQZ_2f # goto next instruction or branch
- FETCHs 1, %edx # %edx<- BBBB; branch offset
- sal $1, %edx # %edx<- adjust byte offset
-
- /*
- * Inline common_backwardBranch
- */
-
- js common_periodicChecks_backwardBranch # jump on backwards branch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
- /*
- * FINISH code
- */
-
-OP_IF_EQZ_2f:
- movzbl 4(rPC), %edx # grab the next opcode
- movzbl 5(rPC), rINST # update the instruction
- addl $4, rPC # update the program counter
- jmp *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_NEZ: /* 0x39 */
-/* File: x86-atom/OP_IF_NEZ.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_NEZ.S
- */
-
-/* File: x86-atom/zcmp.S */
- /* 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.
- */
-
- /*
- * File: zcmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform
- *
- * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
- *
- * Description: Branch to the given destination if the given register's
- * value compares with 0 as specified.
- *
- * Format: AA|op BBBB (21t)
- *
- * Syntax: op vAA, +BBBB
- */
-
- cmp $0, (rFP, rINST, 4) # compare vAA with zero
- je OP_IF_NEZ_2f # goto next instruction or branch
- FETCHs 1, %edx # %edx<- BBBB; branch offset
- sal $1, %edx # %edx<- adjust byte offset
-
- /*
- * Inline common_backwardBranch
- */
-
- js common_periodicChecks_backwardBranch # jump on backwards branch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
- /*
- * FINISH code
- */
-
-OP_IF_NEZ_2f:
- movzbl 4(rPC), %edx # grab the next opcode
- movzbl 5(rPC), rINST # update the instruction
- addl $4, rPC # update the program counter
- jmp *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_LTZ: /* 0x3a */
-/* File: x86-atom/OP_IF_LTZ.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_LTZ.S
- */
-
-/* File: x86-atom/zcmp.S */
- /* 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.
- */
-
- /*
- * File: zcmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform
- *
- * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
- *
- * Description: Branch to the given destination if the given register's
- * value compares with 0 as specified.
- *
- * Format: AA|op BBBB (21t)
- *
- * Syntax: op vAA, +BBBB
- */
-
- cmp $0, (rFP, rINST, 4) # compare vAA with zero
- jge OP_IF_LTZ_2f # goto next instruction or branch
- FETCHs 1, %edx # %edx<- BBBB; branch offset
- sal $1, %edx # %edx<- adjust byte offset
-
- /*
- * Inline common_backwardBranch
- */
-
- js common_periodicChecks_backwardBranch # jump on backwards branch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
- /*
- * FINISH code
- */
-
-OP_IF_LTZ_2f:
- movzbl 4(rPC), %edx # grab the next opcode
- movzbl 5(rPC), rINST # update the instruction
- addl $4, rPC # update the program counter
- jmp *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_GEZ: /* 0x3b */
-/* File: x86-atom/OP_IF_GEZ.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_GEZ.S
- */
-
-/* File: x86-atom/zcmp.S */
- /* 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.
- */
-
- /*
- * File: zcmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform
- *
- * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
- *
- * Description: Branch to the given destination if the given register's
- * value compares with 0 as specified.
- *
- * Format: AA|op BBBB (21t)
- *
- * Syntax: op vAA, +BBBB
- */
-
- cmp $0, (rFP, rINST, 4) # compare vAA with zero
- jl OP_IF_GEZ_2f # goto next instruction or branch
- FETCHs 1, %edx # %edx<- BBBB; branch offset
- sal $1, %edx # %edx<- adjust byte offset
-
- /*
- * Inline common_backwardBranch
- */
-
- js common_periodicChecks_backwardBranch # jump on backwards branch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
- /*
- * FINISH code
- */
-
-OP_IF_GEZ_2f:
- movzbl 4(rPC), %edx # grab the next opcode
- movzbl 5(rPC), rINST # update the instruction
- addl $4, rPC # update the program counter
- jmp *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_GTZ: /* 0x3c */
-/* File: x86-atom/OP_IF_GTZ.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_GTZ.S
- */
-
-/* File: x86-atom/zcmp.S */
- /* 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.
- */
-
- /*
- * File: zcmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform
- *
- * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
- *
- * Description: Branch to the given destination if the given register's
- * value compares with 0 as specified.
- *
- * Format: AA|op BBBB (21t)
- *
- * Syntax: op vAA, +BBBB
- */
-
- cmp $0, (rFP, rINST, 4) # compare vAA with zero
- jle OP_IF_GTZ_2f # goto next instruction or branch
- FETCHs 1, %edx # %edx<- BBBB; branch offset
- sal $1, %edx # %edx<- adjust byte offset
-
- /*
- * Inline common_backwardBranch
- */
-
- js common_periodicChecks_backwardBranch # jump on backwards branch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
- /*
- * FINISH code
- */
-
-OP_IF_GTZ_2f:
- movzbl 4(rPC), %edx # grab the next opcode
- movzbl 5(rPC), rINST # update the instruction
- addl $4, rPC # update the program counter
- jmp *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IF_LEZ: /* 0x3d */
-/* File: x86-atom/OP_IF_LEZ.S */
- /* 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.
- */
-
- /*
- * File: OP_IF_LEZ.S
- */
-
-/* File: x86-atom/zcmp.S */
- /* 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.
- */
-
- /*
- * File: zcmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform
- *
- * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
- *
- * Description: Branch to the given destination if the given register's
- * value compares with 0 as specified.
- *
- * Format: AA|op BBBB (21t)
- *
- * Syntax: op vAA, +BBBB
- */
-
- cmp $0, (rFP, rINST, 4) # compare vAA with zero
- jg OP_IF_LEZ_2f # goto next instruction or branch
- FETCHs 1, %edx # %edx<- BBBB; branch offset
- sal $1, %edx # %edx<- adjust byte offset
-
- /*
- * Inline common_backwardBranch
- */
-
- js common_periodicChecks_backwardBranch # jump on backwards branch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
- /*
- * FINISH code
- */
-
-OP_IF_LEZ_2f:
- movzbl 4(rPC), %edx # grab the next opcode
- movzbl 5(rPC), rINST # update the instruction
- addl $4, rPC # update the program counter
- jmp *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_UNUSED_3E: /* 0x3e */
-/* File: x86-atom/OP_UNUSED_3E.S */
- /* 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.
- */
-
- /*
- * File: OP_UNUSED_3E.S
- */
-
-/* File: x86-atom/unused.S */
- /* 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_UNUSED_3F: /* 0x3f */
-/* File: x86-atom/OP_UNUSED_3F.S */
- /* 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.
- */
-
- /*
- * File: OP_UNUSED_3F.S
- */
-
-/* File: x86-atom/unused.S */
- /* 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_UNUSED_40: /* 0x40 */
-/* File: x86-atom/OP_UNUSED_40.S */
- /* 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.
- */
-
- /*
- * File: OP_UNUSED_40.S
- */
-
-/* File: x86-atom/unused.S */
- /* 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_UNUSED_41: /* 0x41 */
-/* File: x86-atom/OP_UNUSED_41.S */
- /* 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.
- */
-
- /*
- * File: OP_UNUSED_41.S
- */
-
-/* File: x86-atom/unused.S */
- /* 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_UNUSED_42: /* 0x42 */
-/* File: x86-atom/OP_UNUSED_42.S */
- /* 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.
- */
-
- /*
- * File: OP_UNUSED_42.S
- */
-
-/* File: x86-atom/unused.S */
- /* 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_UNUSED_43: /* 0x43 */
-/* File: x86-atom/OP_UNUSED_43.S */
- /* 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.
- */
-
- /*
- * File: OP_UNUSED_43.S
- */
-
-/* File: x86-atom/unused.S */
- /* 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AGET: /* 0x44 */
-/* File: x86-atom/OP_AGET.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET.S
- *
- * Code: Generic 32-bit array "get" operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * mov performed also dependent on the type of the array element.
- *
- * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
- *
- * Description: Perform an array get operation at the identified index
- * of a given array; load the array value into the value
- * register. vAA <- vBB[vCC].
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- lea (%ecx, %edx, 4), %ecx # %ecx<- &vBB[vCC]
- # trying: lea (%ecx, %edx, scale), %ecx
- # to reduce code size
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
- # doing this and the previous instr
- # with one instr was not faster
- SET_VREG %edx rINST # vAA<- %edx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AGET_WIDE: /* 0x45 */
-/* File: x86-atom/OP_AGET_WIDE.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET_WIDE.S
- *
- * Code: 64-bit array get operation.
- *
- * For: aget-wide
- *
- * Description: Perform an array get operation at the identified index
- * of a given array; load the array value into the destination
- * register. vAA <- vBB[vCC].
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq offArrayObject_contents(%ecx, %edx, 8), %xmm0 # %xmm0<- vBB[vCC]
- movq %xmm0, (rFP, rINST, 4) # vAA<- %xmm0; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AGET_OBJECT: /* 0x46 */
-/* File: x86-atom/OP_AGET_OBJECT.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET_OBJECT.S
- */
-
-/* File: x86-atom/OP_AGET.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET.S
- *
- * Code: Generic 32-bit array "get" operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * mov performed also dependent on the type of the array element.
- *
- * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
- *
- * Description: Perform an array get operation at the identified index
- * of a given array; load the array value into the value
- * register. vAA <- vBB[vCC].
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- lea (%ecx, %edx, 4), %ecx # %ecx<- &vBB[vCC]
- # trying: lea (%ecx, %edx, scale), %ecx
- # to reduce code size
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
- # doing this and the previous instr
- # with one instr was not faster
- SET_VREG %edx rINST # vAA<- %edx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AGET_BOOLEAN: /* 0x47 */
-/* File: x86-atom/OP_AGET_BOOLEAN.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET_BOOLEAN.S
- */
-
-/* File: x86-atom/OP_AGET.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET.S
- *
- * Code: Generic 32-bit array "get" operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * mov performed also dependent on the type of the array element.
- *
- * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
- *
- * Description: Perform an array get operation at the identified index
- * of a given array; load the array value into the value
- * register. vAA <- vBB[vCC].
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- lea (%ecx, %edx, 1), %ecx # %ecx<- &vBB[vCC]
- # trying: lea (%ecx, %edx, scale), %ecx
- # to reduce code size
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movzbl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
- # doing this and the previous instr
- # with one instr was not faster
- SET_VREG %edx rINST # vAA<- %edx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AGET_BYTE: /* 0x48 */
-/* File: x86-atom/OP_AGET_BYTE.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET_BYTE.S
- */
-
-/* File: x86-atom/OP_AGET.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET.S
- *
- * Code: Generic 32-bit array "get" operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * mov performed also dependent on the type of the array element.
- *
- * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
- *
- * Description: Perform an array get operation at the identified index
- * of a given array; load the array value into the value
- * register. vAA <- vBB[vCC].
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- lea (%ecx, %edx, 1), %ecx # %ecx<- &vBB[vCC]
- # trying: lea (%ecx, %edx, scale), %ecx
- # to reduce code size
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movsbl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
- # doing this and the previous instr
- # with one instr was not faster
- SET_VREG %edx rINST # vAA<- %edx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AGET_CHAR: /* 0x49 */
-/* File: x86-atom/OP_AGET_CHAR.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET_CHAR.S
- */
-
-/* File: x86-atom/OP_AGET.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET.S
- *
- * Code: Generic 32-bit array "get" operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * mov performed also dependent on the type of the array element.
- *
- * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
- *
- * Description: Perform an array get operation at the identified index
- * of a given array; load the array value into the value
- * register. vAA <- vBB[vCC].
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- lea (%ecx, %edx, 2), %ecx # %ecx<- &vBB[vCC]
- # trying: lea (%ecx, %edx, scale), %ecx
- # to reduce code size
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movzwl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
- # doing this and the previous instr
- # with one instr was not faster
- SET_VREG %edx rINST # vAA<- %edx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AGET_SHORT: /* 0x4a */
-/* File: x86-atom/OP_AGET_SHORT.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET_SHORT.S
- */
-
-/* File: x86-atom/OP_AGET.S */
- /* 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.
- */
-
- /*
- * File: OP_AGET.S
- *
- * Code: Generic 32-bit array "get" operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * mov performed also dependent on the type of the array element.
- *
- * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
- *
- * Description: Perform an array get operation at the identified index
- * of a given array; load the array value into the value
- * register. vAA <- vBB[vCC].
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- lea (%ecx, %edx, 2), %ecx # %ecx<- &vBB[vCC]
- # trying: lea (%ecx, %edx, scale), %ecx
- # to reduce code size
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movswl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
- # doing this and the previous instr
- # with one instr was not faster
- SET_VREG %edx rINST # vAA<- %edx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_APUT: /* 0x4b */
-/* File: x86-atom/OP_APUT.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT.S
- *
- * Code: Generic 32-bit array put operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * move performed also dependent on the type of the array element.
- * Provides a "value" register to specify the source of the move
- *
- * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
- *
- * Description: Perform an array put operation from the value register;
- * store the value register at the identified index of a
- * given array. vBB[vCC] <- vAA
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- lea (%ecx, %edx, 4), %ecx # %ecx<- &vBB[vCC]
- GET_VREG rINST # rINST<- vAA
- movl rINST, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_APUT_WIDE: /* 0x4c */
-/* File: x86-atom/OP_APUT_WIDE.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT_WIDE.S
- *
- * Code: 64-bit array put operation.
- *
- * For: aput-wide
- *
- * Description: Perform an array put operation from the value register;
- * store the value register at the identified index of a
- * given array. vBB[vCC] <- vAA.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vAA
- movq %xmm0, offArrayObject_contents(%ecx, %edx, 8) # vBB[vCC]<- %xmm0; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_APUT_OBJECT: /* 0x4d */
-/* File: x86-atom/OP_APUT_OBJECT.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT_OBJECT.S
- *
- * Code: 32-bit array put operation. Provides an "scale" variable
- * specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * mov performed also dependent on the type of the array element.
- * Provides a "value" register to specify the source of the mov
- *
- * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
- *
- * Description: Perform an array put operation from the value register;
- * store the value register at the identified index of a
- * given array. vBB[vCC] <- vAA
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %eax # %eax<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %eax # %eax<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %eax # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%eax), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- GET_VREG rINST # rINST<- vAA
- lea (%eax, %edx, 4), %edx # %edx<- &vBB[vCC]
- cmp $0, rINST # check for null reference
- je .LOP_APUT_OBJECT_skip_check # reference is null so skip type check
- jmp .LOP_APUT_OBJECT_finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_APUT_BOOLEAN: /* 0x4e */
-/* File: x86-atom/OP_APUT_BOOLEAN.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT_BOOLEAN.S
- */
-
-/* File: x86-atom/OP_APUT.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT.S
- *
- * Code: Generic 32-bit array put operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * move performed also dependent on the type of the array element.
- * Provides a "value" register to specify the source of the move
- *
- * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
- *
- * Description: Perform an array put operation from the value register;
- * store the value register at the identified index of a
- * given array. vBB[vCC] <- vAA
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- lea (%ecx, %edx, 1), %ecx # %ecx<- &vBB[vCC]
- GET_VREG rINST # rINST<- vAA
- movb rINSTbl, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_APUT_BYTE: /* 0x4f */
-/* File: x86-atom/OP_APUT_BYTE.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT_BYTE.S
- */
-
-/* File: x86-atom/OP_APUT.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT.S
- *
- * Code: Generic 32-bit array put operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * move performed also dependent on the type of the array element.
- * Provides a "value" register to specify the source of the move
- *
- * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
- *
- * Description: Perform an array put operation from the value register;
- * store the value register at the identified index of a
- * given array. vBB[vCC] <- vAA
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- lea (%ecx, %edx, 1), %ecx # %ecx<- &vBB[vCC]
- GET_VREG rINST # rINST<- vAA
- movb rINSTbl, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_APUT_CHAR: /* 0x50 */
-/* File: x86-atom/OP_APUT_CHAR.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT_CHAR.S
- */
-
-/* File: x86-atom/OP_APUT.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT.S
- *
- * Code: Generic 32-bit array put operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * move performed also dependent on the type of the array element.
- * Provides a "value" register to specify the source of the move
- *
- * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
- *
- * Description: Perform an array put operation from the value register;
- * store the value register at the identified index of a
- * given array. vBB[vCC] <- vAA
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- lea (%ecx, %edx, 2), %ecx # %ecx<- &vBB[vCC]
- GET_VREG rINST # rINST<- vAA
- movw rINSTw, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_APUT_SHORT: /* 0x51 */
-/* File: x86-atom/OP_APUT_SHORT.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT_SHORT.S
- */
-
-/* File: x86-atom/OP_APUT.S */
- /* 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.
- */
-
- /*
- * File: OP_APUT.S
- *
- * Code: Generic 32-bit array put operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * move performed also dependent on the type of the array element.
- * Provides a "value" register to specify the source of the move
- *
- * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
- *
- * Description: Perform an array put operation from the value register;
- * store the value register at the identified index of a
- * given array. vBB[vCC] <- vAA
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- lea (%ecx, %edx, 2), %ecx # %ecx<- &vBB[vCC]
- GET_VREG rINST # rINST<- vAA
- movw rINSTw, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET: /* 0x52 */
-/* File: x86-atom/OP_IGET.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET.S
- *
- * Code: Generic 32-bit instance field "get" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iget's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iget-boolean, iget-byte, iget-char, iget-object, iget
- * iget-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IGET_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %edx # %edx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- jmp .LOP_IGET_finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_WIDE: /* 0x53 */
-/* File: x86-atom/OP_IGET_WIDE.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET_WIDE.S
- *
- * Code: 64 bit instance field "get" operation. Uses no substitutions.
- *
- * For: iget-wide
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
- movl rGLUE, %eax # %eax<- MterpGlue pointer
- movl offGlue_methodClassDex(%eax), %ecx # %ecx<- pDvmDex
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- CCCC
- FETCH 1, %edx # %edx<- pDvmDex->pResFields
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved InstField ptr
- cmp $0, %ecx # check for null ptr; resolved InstField ptr
- jne .LOP_IGET_WIDE_finish
- movl offGlue_method(%eax), %ecx # %ecx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%ecx), %ecx # %ecx<- method->clazz
- movl %ecx, -8(%esp) # push parameter CCCC; field ref
- movl %edx, -4(%esp) # push parameter method->clazz
- jmp .LOP_IGET_WIDE_finish2
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_OBJECT: /* 0x54 */
-/* File: x86-atom/OP_IGET_OBJECT.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET_OBJECT.S
- */
-
-/* File: x86-atom/OP_IGET.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET.S
- *
- * Code: Generic 32-bit instance field "get" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iget's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iget-boolean, iget-byte, iget-char, iget-object, iget
- * iget-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IGET_OBJECT_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %edx # %edx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- jmp .LOP_IGET_OBJECT_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_BOOLEAN: /* 0x55 */
-/* File: x86-atom/OP_IGET_BOOLEAN.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET_BOOLEAN.S
- */
-
-/* File: x86-atom/OP_IGET.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET.S
- *
- * Code: Generic 32-bit instance field "get" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iget's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iget-boolean, iget-byte, iget-char, iget-object, iget
- * iget-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IGET_BOOLEAN_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %edx # %edx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- jmp .LOP_IGET_BOOLEAN_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_BYTE: /* 0x56 */
-/* File: x86-atom/OP_IGET_BYTE.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET_BYTE.S
- */
-
-/* File: x86-atom/OP_IGET.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET.S
- *
- * Code: Generic 32-bit instance field "get" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iget's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iget-boolean, iget-byte, iget-char, iget-object, iget
- * iget-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IGET_BYTE_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %edx # %edx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- jmp .LOP_IGET_BYTE_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_CHAR: /* 0x57 */
-/* File: x86-atom/OP_IGET_CHAR.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET_CHAR.S
- */
-
-/* File: x86-atom/OP_IGET.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET.S
- *
- * Code: Generic 32-bit instance field "get" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iget's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iget-boolean, iget-byte, iget-char, iget-object, iget
- * iget-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IGET_CHAR_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %edx # %edx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- jmp .LOP_IGET_CHAR_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_SHORT: /* 0x58 */
-/* File: x86-atom/OP_IGET_SHORT.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET_SHORT.S
- */
-
-/* File: x86-atom/OP_IGET.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET.S
- *
- * Code: Generic 32-bit instance field "get" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iget's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iget-boolean, iget-byte, iget-char, iget-object, iget
- * iget-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IGET_SHORT_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %edx # %edx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- jmp .LOP_IGET_SHORT_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT: /* 0x59 */
-/* File: x86-atom/OP_IPUT.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT.S
- *
- * Code: Generic 32-bit instance field "put" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iput's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iput-boolean, iput-byte, iput-char, iput-object, iput
- * iput-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IPUT_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- jmp .LOP_IPUT_finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_WIDE: /* 0x5a */
-/* File: x86-atom/OP_IPUT_WIDE.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT_WIDE.S
- *
- * Code: 64 bit instance field "put" operation. Uses no substitutions.
- *
- * For: iget-wide
- *
- * Description: Perform the object instance field "put" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
- movl rGLUE, %eax # %eax<- MterpGlue pointer
- movl offGlue_methodClassDex(%eax), %ecx # %ecx<- pDvmDex
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- CCCC
- FETCH 1, %edx # %edx<- pDvmDex->pResFields
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved InstField ptr
- cmp $0, %ecx # check for null ptr; resolved InstField ptr
- jne .LOP_IPUT_WIDE_finish
- movl offGlue_method(%eax), %ecx # %ecx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%ecx), %ecx # %ecx<- method->clazz
- movl %ecx, -8(%esp) # push parameter CCCC; field ref
- movl %edx, -4(%esp) # push parameter method->clazz
- jmp .LOP_IPUT_WIDE_finish2
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_OBJECT: /* 0x5b */
-/* File: x86-atom/OP_IPUT_OBJECT.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT.S
- *
- * Code: Generic 32-bit instance field "put" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iput's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iput-boolean, iput-byte, iput-char, iput-object, iput
- * iput-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IPUT_OBJECT_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- jmp .LOP_IPUT_OBJECT_finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_BOOLEAN: /* 0x5c */
-/* File: x86-atom/OP_IPUT_BOOLEAN.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT_BOOLEAN.S
- */
-
-/* File: x86-atom/OP_IPUT.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT.S
- *
- * Code: Generic 32-bit instance field "put" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iput's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iput-boolean, iput-byte, iput-char, iput-object, iput
- * iput-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IPUT_BOOLEAN_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- jmp .LOP_IPUT_BOOLEAN_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_BYTE: /* 0x5d */
-/* File: x86-atom/OP_IPUT_BYTE.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT_BYTE.S
- */
-
-/* File: x86-atom/OP_IPUT.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT.S
- *
- * Code: Generic 32-bit instance field "put" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iput's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iput-boolean, iput-byte, iput-char, iput-object, iput
- * iput-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IPUT_BYTE_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- jmp .LOP_IPUT_BYTE_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_CHAR: /* 0x5e */
-/* File: x86-atom/OP_IPUT_CHAR.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT_CHAR.S
- */
-
-/* File: x86-atom/OP_IPUT.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT.S
- *
- * Code: Generic 32-bit instance field "put" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iput's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iput-boolean, iput-byte, iput-char, iput-object, iput
- * iput-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IPUT_CHAR_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- jmp .LOP_IPUT_CHAR_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_SHORT: /* 0x5f */
-/* File: x86-atom/OP_IPUT_SHORT.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT_SHORT.S
- */
-
-/* File: x86-atom/OP_IPUT.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT.S
- *
- * Code: Generic 32-bit instance field "put" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iput's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iput-boolean, iput-byte, iput-char, iput-object, iput
- * iput-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .LOP_IPUT_SHORT_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- jmp .LOP_IPUT_SHORT_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SGET: /* 0x60 */
-/* File: x86-atom/OP_SGET.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET.S
- *
- * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
- *
- * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; load the field value
- * into the value register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SGET_resolve
- jmp .LOP_SGET_finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SGET_WIDE: /* 0x61 */
-/* File: x86-atom/OP_SGET_WIDE.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET_WIDE.S
- *
- * Code: 64-bit static field "get" operation. Uses no substitutions.
- *
- * For: sget-wide
- *
- * Description: Perform the identified object static field operation
- * with the identified static field, loading or storing
- * into the value register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_methodClassDex(%eax), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %edx # %edx<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %edx, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SGET_WIDE_resolve
-
-.LOP_SGET_WIDE_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq offStaticField_value(%ecx), %xmm0 # %xmm0<- field value
- movq %xmm0, (rFP, rINST, 4) # vAA<- field value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SGET_OBJECT: /* 0x62 */
-/* File: x86-atom/OP_SGET_OBJECT.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET_OBJECT.S
- */
-
-/* File: x86-atom/OP_SGET.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET.S
- *
- * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
- *
- * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; load the field value
- * into the value register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SGET_OBJECT_resolve
- jmp .LOP_SGET_OBJECT_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SGET_BOOLEAN: /* 0x63 */
-/* File: x86-atom/OP_SGET_BOOLEAN.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET_BOOLEAN.S
- */
-
-/* File: x86-atom/OP_SGET.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET.S
- *
- * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
- *
- * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; load the field value
- * into the value register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SGET_BOOLEAN_resolve
- jmp .LOP_SGET_BOOLEAN_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SGET_BYTE: /* 0x64 */
-/* File: x86-atom/OP_SGET_BYTE.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET_BYTE.S
- */
-
-/* File: x86-atom/OP_SGET.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET.S
- *
- * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
- *
- * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; load the field value
- * into the value register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SGET_BYTE_resolve
- jmp .LOP_SGET_BYTE_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SGET_CHAR: /* 0x65 */
-/* File: x86-atom/OP_SGET_CHAR.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET_CHAR.S
- */
-
-/* File: x86-atom/OP_SGET.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET.S
- *
- * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
- *
- * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; load the field value
- * into the value register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SGET_CHAR_resolve
- jmp .LOP_SGET_CHAR_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SGET_SHORT: /* 0x66 */
-/* File: x86-atom/OP_SGET_SHORT.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET_SHORT.S
- */
-
-/* File: x86-atom/OP_SGET.S */
- /* 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.
- */
-
- /*
- * File: OP_SGET.S
- *
- * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
- *
- * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; load the field value
- * into the value register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SGET_SHORT_resolve
- jmp .LOP_SGET_SHORT_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SPUT: /* 0x67 */
-/* File: x86-atom/OP_SPUT.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT.S
- *
- * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
- *
- * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; store the field value
- * register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SPUT_resolve
- jmp .LOP_SPUT_finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SPUT_WIDE: /* 0x68 */
-/* File: x86-atom/OP_SPUT_WIDE.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT_WIDE.S
- *
- * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
- *
- * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; store the field value
- * register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_methodClassDex(%eax), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %edx # %edx<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %edx, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SPUT_WIDE_resolve
-
-.LOP_SPUT_WIDE_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vAA
- movq %xmm0, offStaticField_value(%ecx) # field value<- field value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SPUT_OBJECT: /* 0x69 */
-/* File: x86-atom/OP_SPUT_OBJECT.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT_OBJECT.S
- *
- * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
- *
- * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; store the field value
- * register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField
- je .LOP_SPUT_OBJECT_resolve
- jmp .LOP_SPUT_OBJECT_finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SPUT_BOOLEAN: /* 0x6a */
-/* File: x86-atom/OP_SPUT_BOOLEAN.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT_BOOLEAN.S
- */
-
-/* File: x86-atom/OP_SPUT.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT.S
- *
- * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
- *
- * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; store the field value
- * register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SPUT_BOOLEAN_resolve
- jmp .LOP_SPUT_BOOLEAN_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SPUT_BYTE: /* 0x6b */
-/* File: x86-atom/OP_SPUT_BYTE.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT_BYTE.S
- */
-
-/* File: x86-atom/OP_SPUT.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT.S
- *
- * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
- *
- * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; store the field value
- * register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SPUT_BYTE_resolve
- jmp .LOP_SPUT_BYTE_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SPUT_CHAR: /* 0x6c */
-/* File: x86-atom/OP_SPUT_CHAR.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT_CHAR.S
- */
-
-/* File: x86-atom/OP_SPUT.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT.S
- *
- * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
- *
- * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; store the field value
- * register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SPUT_CHAR_resolve
- jmp .LOP_SPUT_CHAR_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SPUT_SHORT: /* 0x6d */
-/* File: x86-atom/OP_SPUT_SHORT.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT_SHORT.S
- */
-
-/* File: x86-atom/OP_SPUT.S */
- /* 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.
- */
-
- /*
- * File: OP_SPUT.S
- *
- * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
- *
- * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; store the field value
- * register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .LOP_SPUT_SHORT_resolve
- jmp .LOP_SPUT_SHORT_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_VIRTUAL: /* 0x6e */
-/* File: x86-atom/OP_INVOKE_VIRTUAL.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_VIRTUAL.S
- *
- * Code: Call a virtual method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_direct that allows up to 255 arguments.
- *
- * For: invoke-virtual, invoke-virtual/range
- *
- * Description: invoke-virtual is used to invoke a normal virtual method;
- * a method that is not static or final, and is not a constructor.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- EXPORT_PC # must export pc for invoke
- movl offGlue_methodClassDex(%eax), %eax # %eax<- pDvmDex
- FETCH 1, %ecx # %ecx<- method index
- movl offDvmDex_pResMethods(%eax), %eax # %eax<- pDvmDex->pResMethods
- FETCH 2, %edx # %edx<- GFED or CCCC
- .if (!0)
- and $15, %edx # %edx<- D if not range
- .endif
- cmp $0, (%eax, %ecx, 4) # check if already resolved
- je .LOP_INVOKE_VIRTUAL_break
- movl (%eax, %ecx, 4), %eax # %eax<- resolved base method
- jmp .LOP_INVOKE_VIRTUAL_continue
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_SUPER: /* 0x6f */
-/* File: x86-atom/OP_INVOKE_SUPER.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_SUPER.S
- *
- * Code: Call super method.
- *
- * For: invoke-super, invoke-super/range
- *
- * Description: invoke-super is used to invoke the closest superclass's virtual
- * method (as opposed to the one with the same method_id in the
- * calling class).
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- FETCH 2, %eax # %eax<- GFED or CCCC
- movl offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
- .if (!0)
- and $15, %eax # %eax<- D if not range
- .endif
- FETCH 1, %edx # %edx<- method index
- movl offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
- cmp $0, (rFP, %eax, 4) # check for null object
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved base method
- je common_errNullObject # handle null object
- jmp .LOP_INVOKE_SUPER_continue2
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_DIRECT: /* 0x70 */
-/* File: x86-atom/OP_INVOKE_DIRECT.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_DIRECT.S
- *
- * Code: Call a non-static direct method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_direct that allows up to 255 arguments.
- *
- * For: invoke-direct, invoke-direct/range
- *
- * Description: invoke-direct is used to invoke a non-static direct method;
- * an instance method that is non-overridable, for example,
- * either a private instance method or a constructor.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- method index
- movl offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
- FETCH 2, %edx # %edx<- GFED or CCCC
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved method to call
- .if (!0)
- andl $15, %edx # %edx<- D if not range
- .endif
- EXPORT_PC # must export for invoke
- movl %edx, -4(%esp) # save "this" pointer register
- cmp $0, %ecx # check if already resolved
- GET_VREG %edx # %edx<- "this" pointer
- je .LOP_INVOKE_DIRECT_resolve # handle resolve
-
-.LOP_INVOKE_DIRECT_finish:
- cmp $0, %edx # check for null "this"
- jne common_invokeMethodNoRange # invoke method common code
- jmp common_errNullObject
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_STATIC: /* 0x71 */
-/* File: x86-atom/OP_INVOKE_STATIC.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_STATIC.S
- *
- * Code: Call static direct method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_static that allows up to 255 arguments.
- *
- * For: invoke-static, invoke-static/range
- *
- * Description: invoke-static is used to invoke static direct method.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %edx<- pDvmDex
- FETCH 1, %eax # %eax<- method index
- movl offDvmDex_pResMethods(%ecx), %ecx # %edx<- pDvmDex->pResMethods
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved method to call
- cmp $0, %ecx # check if already resolved
- EXPORT_PC # must export for invoke
- jne common_invokeMethodNoRange # invoke method common code
- jmp .LOP_INVOKE_STATIC_break
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_INTERFACE: /* 0x72 */
-/* File: x86-atom/OP_INVOKE_INTERFACE.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_INTERFACE.S
- *
- * Code: Call at method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_interface that allows up to 255 arguments.
- *
- * For: invoke-interface, invoke-interface-range
- *
- * Description: invoke-interface is used to invoke an interface method; on an
- * object whose concrete class isn't known, using a method_id that
- * refers to an interface.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-
- FETCH 2, %edx # %edx<- GFED or CCCC
- FETCH 1, %ecx # %ecx<- method index
- movl %ecx, -12(%esp) # push argument method index
- .if (!0)
- and $15, %edx # %edx<- D if not range
- .endif
- EXPORT_PC # must export for invoke
- GET_VREG %edx # %edx<- first arg "this pointer"
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_methodClassDex(%eax), %eax # %eax<- glue->pDvmDex
- movl %eax, -4(%esp) # push parameter class
- cmp $0, %edx # check for null object
- je common_errNullObject # handle null object
- jmp .LOP_INVOKE_INTERFACE_break
-
-/* ------------------------------ */
- .balign 64
-.L_OP_UNUSED_73: /* 0x73 */
-/* File: x86-atom/OP_UNUSED_73.S */
- /* 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.
- */
-
- /*
- * File: OP_UNUSED_73.S
- */
-
-/* File: x86-atom/unused.S */
- /* 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
-/* File: x86-atom/OP_INVOKE_VIRTUAL_RANGE.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_VIRTUAL_RANGE.S
- */
-
-/* File: x86-atom/OP_INVOKE_VIRTUAL.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_VIRTUAL.S
- *
- * Code: Call a virtual method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_direct that allows up to 255 arguments.
- *
- * For: invoke-virtual, invoke-virtual/range
- *
- * Description: invoke-virtual is used to invoke a normal virtual method;
- * a method that is not static or final, and is not a constructor.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- EXPORT_PC # must export pc for invoke
- movl offGlue_methodClassDex(%eax), %eax # %eax<- pDvmDex
- FETCH 1, %ecx # %ecx<- method index
- movl offDvmDex_pResMethods(%eax), %eax # %eax<- pDvmDex->pResMethods
- FETCH 2, %edx # %edx<- GFED or CCCC
- .if (!1)
- and $15, %edx # %edx<- D if not range
- .endif
- cmp $0, (%eax, %ecx, 4) # check if already resolved
- je .LOP_INVOKE_VIRTUAL_RANGE_break
- movl (%eax, %ecx, 4), %eax # %eax<- resolved base method
- jmp .LOP_INVOKE_VIRTUAL_RANGE_continue
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_SUPER_RANGE: /* 0x75 */
-/* File: x86-atom/OP_INVOKE_SUPER_RANGE.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_SUPER_RANGE.S
- */
-
-/* File: x86-atom/OP_INVOKE_SUPER.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_SUPER.S
- *
- * Code: Call super method.
- *
- * For: invoke-super, invoke-super/range
- *
- * Description: invoke-super is used to invoke the closest superclass's virtual
- * method (as opposed to the one with the same method_id in the
- * calling class).
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- FETCH 2, %eax # %eax<- GFED or CCCC
- movl offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
- .if (!1)
- and $15, %eax # %eax<- D if not range
- .endif
- FETCH 1, %edx # %edx<- method index
- movl offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
- cmp $0, (rFP, %eax, 4) # check for null object
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved base method
- je common_errNullObject # handle null object
- jmp .LOP_INVOKE_SUPER_RANGE_continue2
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
-/* File: x86-atom/OP_INVOKE_DIRECT_RANGE.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_DIRECT_RANGE.S
- */
-
-/* File: x86-atom/OP_INVOKE_DIRECT.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_DIRECT.S
- *
- * Code: Call a non-static direct method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_direct that allows up to 255 arguments.
- *
- * For: invoke-direct, invoke-direct/range
- *
- * Description: invoke-direct is used to invoke a non-static direct method;
- * an instance method that is non-overridable, for example,
- * either a private instance method or a constructor.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- method index
- movl offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
- FETCH 2, %edx # %edx<- GFED or CCCC
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved method to call
- .if (!1)
- andl $15, %edx # %edx<- D if not range
- .endif
- EXPORT_PC # must export for invoke
- movl %edx, -4(%esp) # save "this" pointer register
- cmp $0, %ecx # check if already resolved
- GET_VREG %edx # %edx<- "this" pointer
- je .LOP_INVOKE_DIRECT_RANGE_resolve # handle resolve
-
-.LOP_INVOKE_DIRECT_RANGE_finish:
- cmp $0, %edx # check for null "this"
- jne common_invokeMethodRange # invoke method common code
- jmp common_errNullObject
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_STATIC_RANGE: /* 0x77 */
-/* File: x86-atom/OP_INVOKE_STATIC_RANGE.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_STATIC_RANGE.S
- */
-
-/* File: x86-atom/OP_INVOKE_STATIC.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_STATIC.S
- *
- * Code: Call static direct method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_static that allows up to 255 arguments.
- *
- * For: invoke-static, invoke-static/range
- *
- * Description: invoke-static is used to invoke static direct method.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %edx<- pDvmDex
- FETCH 1, %eax # %eax<- method index
- movl offDvmDex_pResMethods(%ecx), %ecx # %edx<- pDvmDex->pResMethods
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved method to call
- cmp $0, %ecx # check if already resolved
- EXPORT_PC # must export for invoke
- jne common_invokeMethodRange # invoke method common code
- jmp .LOP_INVOKE_STATIC_RANGE_break
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
-/* File: x86-atom/OP_INVOKE_INTERFACE_RANGE.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_INTERFACE_RANGE.S
- */
-
-/* File: x86-atom/OP_INVOKE_INTERFACE.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_INTERFACE.S
- *
- * Code: Call at method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_interface that allows up to 255 arguments.
- *
- * For: invoke-interface, invoke-interface-range
- *
- * Description: invoke-interface is used to invoke an interface method; on an
- * object whose concrete class isn't known, using a method_id that
- * refers to an interface.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-
- FETCH 2, %edx # %edx<- GFED or CCCC
- FETCH 1, %ecx # %ecx<- method index
- movl %ecx, -12(%esp) # push argument method index
- .if (!1)
- and $15, %edx # %edx<- D if not range
- .endif
- EXPORT_PC # must export for invoke
- GET_VREG %edx # %edx<- first arg "this pointer"
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_methodClassDex(%eax), %eax # %eax<- glue->pDvmDex
- movl %eax, -4(%esp) # push parameter class
- cmp $0, %edx # check for null object
- je common_errNullObject # handle null object
- jmp .LOP_INVOKE_INTERFACE_RANGE_break
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_UNUSED_79: /* 0x79 */
-/* File: x86-atom/OP_UNUSED_79.S */
- /* 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.
- */
-
- /*
- * File: OP_UNUSED_79.S
- */
-
-/* File: x86-atom/unused.S */
- /* 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_UNUSED_7A: /* 0x7a */
-/* File: x86-atom/OP_UNUSED_7A.S */
- /* 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.
- */
-
- /*
- * File: OP_UNUSED_7A.S
- */
-
-/* File: x86-atom/unused.S */
- /* 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_NEG_INT: /* 0x7b */
-/* File: x86-atom/OP_NEG_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_NEG_INT.S
- */
-
-/* File: x86-atom/unop.S */
- /* 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.
- */
-
- /*
- * File: unop.S
- *
- * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%ecx = op %edx".
- *
- * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- # do operation part 1
- neg %ecx # do operation part 2
- SET_VREG %ecx, rINST # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_NOT_INT: /* 0x7c */
-/* File: x86-atom/OP_NOT_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_NOT_INT.S
- */
-
-/* File: x86-atom/unop.S */
- /* 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.
- */
-
- /*
- * File: unop.S
- *
- * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%ecx = op %edx".
- *
- * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- # do operation part 1
- not %ecx # do operation part 2
- SET_VREG %ecx, rINST # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_NEG_LONG: /* 0x7d */
-/* File: x86-atom/OP_NEG_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_NEG_LONG.S
- */
-
-/* File: x86-atom/unopWide.S */
- /* 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.
- */
-
- /*
- * File: unopWide.S
- *
- * Code: Generic 64-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%xmm0 = op %xmm1".
- *
- * For: neg-double, neg-long, not-long
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, rINST # rINST<- B
- and $15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vB
- xorps %xmm1, %xmm1 # do operation part 1
- psubq %xmm0, %xmm1 # do operation part 2
- movq %xmm1, (rFP, %ecx, 4) # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_NOT_LONG: /* 0x7e */
-/* File: x86-atom/OP_NOT_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_NOT_LONG.S
- */
-
-/* File: x86-atom/unopWide.S */
- /* 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.
- */
-
- /*
- * File: unopWide.S
- *
- * Code: Generic 64-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%xmm0 = op %xmm1".
- *
- * For: neg-double, neg-long, not-long
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, rINST # rINST<- B
- and $15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vB
- # do operation part 1
- pandn 0xFFFFFFFF, %xmm0 # do operation part 2
- movq %xmm0, (rFP, %ecx, 4) # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_NEG_FLOAT: /* 0x7f */
-/* File: x86-atom/OP_NEG_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_NEG_FLOAT.S
- */
-
-/* File: x86-atom/unop.S */
- /* 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.
- */
-
- /*
- * File: unop.S
- *
- * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%ecx = op %edx".
- *
- * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- # do operation part 1
- addl $0x80000000, %ecx # do operation part 2
- SET_VREG %ecx, rINST # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_NEG_DOUBLE: /* 0x80 */
-/* File: x86-atom/OP_NEG_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_NEG_DOUBLE.S
- */
-
-/* File: x86-atom/unopWide.S */
- /* 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.
- */
-
- /*
- * File: unopWide.S
- *
- * Code: Generic 64-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%xmm0 = op %xmm1".
- *
- * For: neg-double, neg-long, not-long
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, rINST # rINST<- B
- and $15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vB
- movq .LdoubNeg, %xmm1 # do operation part 1
- pxor %xmm1, %xmm0 # do operation part 2
- movq %xmm0, (rFP, %ecx, 4) # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INT_TO_LONG: /* 0x81 */
-/* File: x86-atom/OP_INT_TO_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_INT_TO_LONG.S
- *
- * Code: Convert an int to a long. Uses no substitutions.
- *
- * For:
- *
- * Description: Convert an int in the source register, to a long, and
- * stores the result in the destintation register. vA<- (long) vB
- *
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %eax # %eax<- BA+
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %eax # %eax<- B
- andl $15, %ecx # %ecx<- A
- GET_VREG %eax # %eax<- vB
- cdq # %edx:%eax<- sign-extend of %eax
- movl %eax, (rFP, %ecx, 4) # vA<- lo part
- movl %edx, 4(rFP, %ecx, 4) # vA+1<- hi part
- FINISH 1 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INT_TO_FLOAT: /* 0x82 */
-/* File: x86-atom/OP_INT_TO_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_INT_TO_FLOAT.S
- *
- * Code: Convert an int to a float. Uses no substitutions.
- *
- * For: int-to-float
- *
- * Description: Convert an int in the source register, to a float, and
- * stores the result in the destintation register. vA<- (float) vB
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %eax # %eax<- BA+
- shr $4, %eax # %eax<- B
- andl $15, rINST # rINST<- A
- cvtsi2ss (rFP,%eax,4), %xmm0 # %xmm0<- vB
- movss %xmm0, (rFP, rINST, 4) # vA<- %xmm0
- FINISH 1 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INT_TO_DOUBLE: /* 0x83 */
-/* File: x86-atom/OP_INT_TO_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_INT_TO_DOUBLE.S
- *
- * Code: Convert an int to a double. Uses no substitutions.
- *
- * For: int-to-double
- *
- * Description: Converts an int in the source register, to a double, and
- * stores the result in the destination register. vA<- (double) vB
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %eax # %eax<- BA+
- shr $4, %eax # %eax<- B
- andl $15, rINST # rINST<- A
- cvtsi2sd (rFP, %eax, 4), %xmm0 # %xmm0<- vB
- movq %xmm0, (rFP, rINST, 4) # vA<- %xmm0; (double) vB
- FFETCH_ADV 1, %edx # %edx<- next instruction hi; fetch, advance
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_LONG_TO_INT: /* 0x84 */
-/* File: x86-atom/OP_LONG_TO_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_LONG_TO_INT.S
- */
-
-/* File: x86-atom/OP_MOVE.S */
- /* 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.
- */
-
- /*
- * File: OP_MOVE.S
- *
- * Code: Copies contents from one register to another. Uses no
- * substitutions.
- *
- * For: move, move-object, long-to-int
- *
- * Description: Copies contents from one non-object register to another.
- * vA<- vB; fp[A]<- fp[B]
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, rINST # rINST<- B
- and $15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vB
- SET_VREG rINST, %ecx # vA<- vB; %edx
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_LONG_TO_FLOAT: /* 0x85 */
-/* File: x86-atom/OP_LONG_TO_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_LONG_TO_FLOAT.S
- *
- * Code: Convert a long to a float. Uses no substitutions.
- *
- * For: int-to-float
- *
- * Description: Converts a float in the source register, to a float, and
- * stores the result in the destination register. vA<- (double) vB
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, rINST # rINST<- B
- and $15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- fildll (rFP, rINST, 4) # FPU<- vB
- fstps (rFP, %ecx, 4) # vA<- FPU; (float) vB
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_LONG_TO_DOUBLE: /* 0x86 */
-/* File: x86-atom/OP_LONG_TO_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_LONG_TO_DOUBLE.S
- *
- * Code: Convert a long to a dobule. Uses no substitutions.
- *
- * For: long-to-double
- *
- * Description: Converts a long in the source register to a double, and
- * stores the result in the destination register. vA<- (double) vB
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, rINST # rINST<- B
- and $15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- fildll (rFP, rINST, 4) # FPU<- vB
- fstpl (rFP, %ecx, 4) # vA<- FPU; (double) vB
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_FLOAT_TO_INT: /* 0x87 */
-/* File: x86-atom/OP_FLOAT_TO_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_FLOAT_TO_INT.S
- *
- * Code: Converts a float to a int. Uses no substitutions.
- *
- * For: float-to-int
- *
- * Description: Convert the float in source register to a int
- * and store the result in the destintation register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- and $15, %edx # %edx<- A
- flds (rFP, rINST, 4) # push vB to floating point stack
- fildl .LintMax # push max int value
- fildl .LintMin # push min int value
- fucomip %st(2), %st(0) # check for negInf
- jae .LOP_FLOAT_TO_INT_negInf # handle negInf
- fucomip %st(1), %st(0) # check for posInf or NaN
- jc .LOP_FLOAT_TO_INT_nanInf # handle posInf or NaN
- jmp .LOP_FLOAT_TO_INT_break # do conversion
-
-/* ------------------------------ */
- .balign 64
-.L_OP_FLOAT_TO_LONG: /* 0x88 */
-/* File: x86-atom/OP_FLOAT_TO_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_FLOAT_TO_LONG.S
- *
- * Code: Converts a float to a long. Uses no substitutions.
- *
- * For: float-to-long
- *
- * Description: Convert the float in source register to a long
- * and store the result in the destintation register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- and $15, %edx # %edx<- A
- flds (rFP, rINST, 4) # push vB to floating point stack
- fildll .LvaluePosInfLong # push max int value
- fildll .LvalueNegInfLong # push min int value
- fucomip %st(2), %st(0) # check for negInf
- jae .LOP_FLOAT_TO_LONG_negInf # handle negInf
- fucomip %st(1), %st(0) # check for posInf or NaN
- jc .LOP_FLOAT_TO_LONG_nanInf # handle posInf or NaN
- jmp .LOP_FLOAT_TO_LONG_break # do conversion
-
-/* ------------------------------ */
- .balign 64
-.L_OP_FLOAT_TO_DOUBLE: /* 0x89 */
-/* File: x86-atom/OP_FLOAT_TO_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_FLOAT_TO_DOUBLE.S
- *
- * Code: Converts a float to a double. Uses no substitutions.
- *
- * For: float-to-double
- *
- * Description: Convert the float in source register to a double
- * and store the result in the destintation register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- and $15, %edx # %edx<- A
- flds (rFP, rINST, 4) # load float
- fstpl (rFP, %edx, 4) # store double
- FINISH 1 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DOUBLE_TO_INT: /* 0x8a */
-/* File: x86-atom/OP_DOUBLE_TO_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_DOUBLE_TO_INT.S
- *
- * Code: Converts a double to an integer. Uses no substitutions.
- *
- * For: double-to-int
- *
- * Description: Convert the source register (a double) to an integer
- * and store the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- and $15, %edx # %edx<- A
- fldl (rFP, rINST, 4) # load &vB
- fildl .LintMax # push max int value
- fildl .LintMin # push min int value
- fucomip %st(2), %st(0) # check for negInf
- jae .LOP_DOUBLE_TO_INT_negInf # handle negInf
- fucomip %st(1), %st(0) # check for posInf or NaN
- jc .LOP_DOUBLE_TO_INT_nanInf # handle posInf or NaN
- jmp .LOP_DOUBLE_TO_INT_break # do conversion
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DOUBLE_TO_LONG: /* 0x8b */
-/* File: x86-atom/OP_DOUBLE_TO_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_DOUBLE_TO_LONG.S
- *
- * Code: Converts a double to a long. Uses no substitutions.
- *
- * For: double-to-long
- *
- * Description: Convert the double in source register to a long
- * and store in the destintation register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %ecx<- BA
- shr $4, rINST # rINST<- B
- and $15, %edx # %ecx<- A
- fldl (rFP, rINST, 4) # push vB to floating point stack
- fildll .LvaluePosInfLong # push max int value
- fildll .LvalueNegInfLong # push min int value
- fucomip %st(2), %st(0) # check for negInf
- jae .LOP_DOUBLE_TO_LONG_negInf # handle negInf
- fucomip %st(1), %st(0) # check for posInf or NaN
- jc .LOP_DOUBLE_TO_LONG_nanInf # handle posInf or NaN
- jmp .LOP_DOUBLE_TO_LONG_break # do conversion
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
-/* File: x86-atom/OP_DOUBLE_TO_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_DOUBLE_TO_FLOAT.S
- *
- * Code: Converts a double to a float. Uses no substitutions.
- *
- * For: double-to-float
- *
- * Description: Convert the source register (a double) to a float
- * and store the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- and $15, %edx # %edx<- A
- fldl (rFP, rINST, 4) # load &vB
- fstps (rFP, %edx, 4) # store float
- FINISH 1 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INT_TO_BYTE: /* 0x8d */
-/* File: x86-atom/OP_INT_TO_BYTE.S */
- /* 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.
- */
-
- /*
- * File: OP_INT_TO_BYTE.S
- */
-
-/* File: x86-atom/unop.S */
- /* 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.
- */
-
- /*
- * File: unop.S
- *
- * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%ecx = op %edx".
- *
- * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- sal $24, %ecx # do operation part 1
- sar $24, %ecx # do operation part 2
- SET_VREG %ecx, rINST # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INT_TO_CHAR: /* 0x8e */
-/* File: x86-atom/OP_INT_TO_CHAR.S */
- /* 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.
- */
-
- /*
- * File: OP_INT_TO_CHAR.S
- */
-
-/* File: x86-atom/unop.S */
- /* 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.
- */
-
- /*
- * File: unop.S
- *
- * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%ecx = op %edx".
- *
- * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- sal $16, %ecx # do operation part 1
- shr $16, %ecx # do operation part 2
- SET_VREG %ecx, rINST # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INT_TO_SHORT: /* 0x8f */
-/* File: x86-atom/OP_INT_TO_SHORT.S */
- /* 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.
- */
-
- /*
- * File: OP_INT_TO_SHORT.S
- */
-
-/* File: x86-atom/unop.S */
- /* 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.
- */
-
- /*
- * File: unop.S
- *
- * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%ecx = op %edx".
- *
- * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- sal $16, %ecx # do operation part 1
- sar $16, %ecx # do operation part 2
- SET_VREG %ecx, rINST # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ADD_INT: /* 0x90 */
-/* File: x86-atom/OP_ADD_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_ADD_INT.S
- */
-
-/* File: x86-atom/binop.S */
- /* 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.
- */
-
- /*
- * File: binop.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- addl %edx, %ecx # %ecx<- vBB op vCC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SUB_INT: /* 0x91 */
-/* File: x86-atom/OP_SUB_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_SUB_INT.S
- */
-
-/* File: x86-atom/binop.S */
- /* 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.
- */
-
- /*
- * File: binop.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- subl %edx, %ecx # %ecx<- vBB op vCC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MUL_INT: /* 0x92 */
-/* File: x86-atom/OP_MUL_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_MUL_INT.S
- */
-
-/* File: x86-atom/binop.S */
- /* 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.
- */
-
- /*
- * File: binop.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- imul %edx, %ecx # %ecx<- vBB op vCC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DIV_INT: /* 0x93 */
-/* File: x86-atom/OP_DIV_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_DIV_INT.S
- */
-
-/* File: x86-atom/binopD.S */
- /* 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.
- */
-
- /*
- * File: binopD.S
- *
- * Code: 32-bit integer divide operation. If "div" is set, the code
- * returns the quotient, else it returns the remainder.
- * Also, a divide-by-zero check is done.
- *
- * For: div-int, rem-int
- *
- * Description: Perform a binary operation on two source
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %eax # %eax<- BB
- FETCH_CC 1, %ecx # %ecx<- CC
- GET_VREG %eax # %eax<- vBB
- GET_VREG %ecx # %ecx<- vCC
- cmp $0, %ecx # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- cmpl $-1, %ecx # handle -1 special case divide error
- jne .LOP_DIV_INT_noerror
- cmpl $0x80000000,%eax # handle min int special case divide error
- je .LOP_DIV_INT_break
-.LOP_DIV_INT_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- .if 1
- SET_VREG %eax rINST # vAA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vAA<- %edx (remainder)
- .endif
- jmp .LOP_DIV_INT_break2
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_REM_INT: /* 0x94 */
-/* File: x86-atom/OP_REM_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_REM_INT.S
- */
-
-/* File: x86-atom/binopD.S */
- /* 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.
- */
-
- /*
- * File: binopD.S
- *
- * Code: 32-bit integer divide operation. If "div" is set, the code
- * returns the quotient, else it returns the remainder.
- * Also, a divide-by-zero check is done.
- *
- * For: div-int, rem-int
- *
- * Description: Perform a binary operation on two source
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_BB 1, %eax # %eax<- BB
- FETCH_CC 1, %ecx # %ecx<- CC
- GET_VREG %eax # %eax<- vBB
- GET_VREG %ecx # %ecx<- vCC
- cmp $0, %ecx # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- cmpl $-1, %ecx # handle -1 special case divide error
- jne .LOP_REM_INT_noerror
- cmpl $0x80000000,%eax # handle min int special case divide error
- je .LOP_REM_INT_break
-.LOP_REM_INT_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- .if 0
- SET_VREG %eax rINST # vAA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vAA<- %edx (remainder)
- .endif
- jmp .LOP_REM_INT_break2
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AND_INT: /* 0x95 */
-/* File: x86-atom/OP_AND_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_AND_INT.S
- */
-
-/* File: x86-atom/binop.S */
- /* 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.
- */
-
- /*
- * File: binop.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- andl %edx, %ecx # %ecx<- vBB op vCC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_OR_INT: /* 0x96 */
-/* File: x86-atom/OP_OR_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_OR_INT.S
- */
-
-/* File: x86-atom/binop.S */
- /* 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.
- */
-
- /*
- * File: binop.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- or %edx, %ecx # %ecx<- vBB op vCC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_XOR_INT: /* 0x97 */
-/* File: x86-atom/OP_XOR_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_XOR_INT.S
- */
-
-/* File: x86-atom/binop.S */
- /* 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.
- */
-
- /*
- * File: binop.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- xor %edx, %ecx # %ecx<- vBB op vCC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SHL_INT: /* 0x98 */
-/* File: x86-atom/OP_SHL_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_SHL_INT.S
- */
-
-/* File: x86-atom/binopS.S */
- /* 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.
- */
-
- /*
- * File: binopS.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%edx = %edx op %cl"
- *
- * For: shl-int, shr-int, ushr-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %edx # %edx<- BB
- FETCH_CC 1, %ecx # %ecx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vBB
- GET_VREG %ecx # %ecx<- vCC
- sal %cl, %edx # %edx<- vBB op +CC
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SHR_INT: /* 0x99 */
-/* File: x86-atom/OP_SHR_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_SHR_INT.S
- */
-
-/* File: x86-atom/binopS.S */
- /* 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.
- */
-
- /*
- * File: binopS.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%edx = %edx op %cl"
- *
- * For: shl-int, shr-int, ushr-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %edx # %edx<- BB
- FETCH_CC 1, %ecx # %ecx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vBB
- GET_VREG %ecx # %ecx<- vCC
- sar %cl, %edx # %edx<- vBB op +CC
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_USHR_INT: /* 0x9a */
-/* File: x86-atom/OP_USHR_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_USHR_INT.S
- */
-
-/* File: x86-atom/binopS.S */
- /* 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.
- */
-
- /*
- * File: binopS.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%edx = %edx op %cl"
- *
- * For: shl-int, shr-int, ushr-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %edx # %edx<- BB
- FETCH_CC 1, %ecx # %ecx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vBB
- GET_VREG %ecx # %ecx<- vCC
- shr %cl, %edx # %edx<- vBB op +CC
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ADD_LONG: /* 0x9b */
-/* File: x86-atom/OP_ADD_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_ADD_LONG.S
- */
-
-/* File: x86-atom/binopWide.S */
- /* 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.
- */
-
- /*
- * File: binopWide.S
- *
- * Code: Generic 64-bit binary operation. Provides an "instr" variable to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-double, add-long, and-long, mul-double, or-long,
- * sub-double, sub-long, xor-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- paddq %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movq %xmm0, (rFP, rINST, 4) # vAA<- %ecx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SUB_LONG: /* 0x9c */
-/* File: x86-atom/OP_SUB_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_SUB_LONG.S
- */
-
-/* File: x86-atom/binopWide.S */
- /* 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.
- */
-
- /*
- * File: binopWide.S
- *
- * Code: Generic 64-bit binary operation. Provides an "instr" variable to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-double, add-long, and-long, mul-double, or-long,
- * sub-double, sub-long, xor-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- psubq %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movq %xmm0, (rFP, rINST, 4) # vAA<- %ecx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MUL_LONG: /* 0x9d */
-/* File: x86-atom/OP_MUL_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_MUL_LONG.S
- *
- * Code: 64-bit integer multiply
- *
- * For: mul-long
- *
- * Description: Multiply two source registers and store the
- * result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- /*
- * Signed 64-bit integer multiply.
- *
- * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
- * WX
- * x YZ
- * --------
- * ZW ZX
- * YW YX
- *
- * The low word of the result holds ZX, the high word holds
- * (ZW+YX) + (the high overflow from ZX). YW doesn't matter because
- * it doesn't fit in the low 64 bits.
- */
-
- movl rINST, -4(%esp) # -4(%esp)<- AA+
- FETCH_BB 1, rINST # rINST<- BB
- FETCH_CC 1, %edx # %edx<- CC
- jmp .LOP_MUL_LONG_finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DIV_LONG: /* 0x9e */
-/* File: x86-atom/OP_DIV_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_DIV_LONG.S
- */
-
-/* File: x86-atom/binopDivRemLong.S */
- /* 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.
- */
-
- /*
- * File: binopDivRemLong.S
- *
- * Code: 64-bit long divide operation. Variable
- * "func" defines the function called to do the operation.
- *
- * For: div-long, rem-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_CC 1, %edx # %edx<- CC
- movl (rFP, %edx, 4), %eax # %eax<- vCC
- movl 4(rFP, %edx, 4), %ecx # %ecx<- vCC+1
- movl %eax, -8(%esp) # push arg vCC
- or %ecx, %eax # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- FETCH_BB 1, %edx # %edx<- BB
- movl %ecx, -4(%esp) # push arg vCC+1
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vBB,vBB+1
- jmp .LOP_DIV_LONG_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_REM_LONG: /* 0x9f */
-/* File: x86-atom/OP_REM_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_REM_LONG.S
- */
-
-/* File: x86-atom/binopDivRemLong.S */
- /* 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.
- */
-
- /*
- * File: binopDivRemLong.S
- *
- * Code: 64-bit long divide operation. Variable
- * "func" defines the function called to do the operation.
- *
- * For: div-long, rem-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-
- FETCH_CC 1, %edx # %edx<- CC
- movl (rFP, %edx, 4), %eax # %eax<- vCC
- movl 4(rFP, %edx, 4), %ecx # %ecx<- vCC+1
- movl %eax, -8(%esp) # push arg vCC
- or %ecx, %eax # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- FETCH_BB 1, %edx # %edx<- BB
- movl %ecx, -4(%esp) # push arg vCC+1
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vBB,vBB+1
- jmp .LOP_REM_LONG_finish
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AND_LONG: /* 0xa0 */
-/* File: x86-atom/OP_AND_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_AND_LONG.S
- */
-
-/* File: x86-atom/binopWide.S */
- /* 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.
- */
-
- /*
- * File: binopWide.S
- *
- * Code: Generic 64-bit binary operation. Provides an "instr" variable to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-double, add-long, and-long, mul-double, or-long,
- * sub-double, sub-long, xor-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- pand %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movq %xmm0, (rFP, rINST, 4) # vAA<- %ecx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_OR_LONG: /* 0xa1 */
-/* File: x86-atom/OP_OR_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_OR_LONG.S
- */
-
-/* File: x86-atom/binopWide.S */
- /* 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.
- */
-
- /*
- * File: binopWide.S
- *
- * Code: Generic 64-bit binary operation. Provides an "instr" variable to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-double, add-long, and-long, mul-double, or-long,
- * sub-double, sub-long, xor-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- por %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movq %xmm0, (rFP, rINST, 4) # vAA<- %ecx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_XOR_LONG: /* 0xa2 */
-/* File: x86-atom/OP_XOR_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_XOR_LONG.S
- */
-
-/* File: x86-atom/binopWide.S */
- /* 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.
- */
-
- /*
- * File: binopWide.S
- *
- * Code: Generic 64-bit binary operation. Provides an "instr" variable to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-double, add-long, and-long, mul-double, or-long,
- * sub-double, sub-long, xor-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- pxor %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movq %xmm0, (rFP, rINST, 4) # vAA<- %ecx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SHL_LONG: /* 0xa3 */
-/* File: x86-atom/OP_SHL_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_SHL_LONG.S
- *
- * Code: Performs a shift left long. Uses no substitutions.
- *
- * For: shl-long
- *
- * Description: Perform a binary shift operation using two source registers
- * where one is the shift amount and the other is the value to shift.
- * Store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_CC 1, %eax # %eax<- CC
- FETCH_BB 1, %edx # %edx<- BB
- movq .LshiftMask, %xmm2 # %xmm2<- mask for the shift bits
- movss (rFP, %eax, 4), %xmm0 # %xmm0<- vCC
- pand %xmm2, %xmm0 # %xmm0<- masked shift bits
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vBB
- psllq %xmm0, %xmm1 # %xmm1<- shifted vBB
- movq %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
- FINISH 2 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SHR_LONG: /* 0xa4 */
-/* File: x86-atom/OP_SHR_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_SHR_LONG.S
- *
- * Code: Performs a shift right long
- *
- * For: shl-long
- *
- * Description: Perform a binary shift operation using two source registers
- * where one is the shift amount and the other is the value to shift.
- * Store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %edx # %edx<- BB
- FETCH_CC 1, %eax # %eax<- CC
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vBB
- movss (rFP, %eax, 4), %xmm0 # %xmm0<- vCC
- movq .LshiftMask, %xmm2
- pand %xmm2, %xmm0 # %xmm0<- masked for the shift bits
- psrlq %xmm0, %xmm1 # %xmm1<- shifted vBB
- cmpl $0, 4(rFP, %edx, 4) # check if we need to consider sign
- jl .LOP_SHR_LONG_finish # consider sign
- jmp .LOP_SHR_LONG_final # sign is fine, finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_USHR_LONG: /* 0xa5 */
-/* File: x86-atom/OP_USHR_LONG.S */
- /* 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.
- */
-
- /*
- * File: OP_USHR_LONG.S
- *
- * Code: Performs an unsigned shift right long operation. Uses no substitutions.
- *
- * For: ushr-long
- *
- * Description: Perform a binary shift operation using two source registers
- * where one is the shift amount and the other is the value to shift.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_CC 1, %eax # %eax<- CC
- FETCH_BB 1, %edx # %edx<- BB
- movsd .LshiftMask, %xmm2 # %xmm2<- mask for the shift bits
- movss (rFP, %eax, 4), %xmm0 # %xmm0<- vCC
- pand %xmm2, %xmm0 # %xmm0<- masked shift bits
- movsd (rFP, %edx, 4), %xmm1 # %xmm1<- vBB
- psrlq %xmm0, %xmm1 # %xmm1<- shifted vBB
- movsd %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
- FINISH 2 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ADD_FLOAT: /* 0xa6 */
-/* File: x86-atom/OP_ADD_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_ADD_FLOAT.S
- */
-
-/* File: x86-atom/binopF.S */
- /* 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.
- */
-
- /*
- * File: binopF.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-float, mul-float, sub-float
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movss (rFP, %ecx, 4), %xmm0 # %xmm0<-vBB
- movss (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- addss %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movss %xmm0, (rFP, rINST, 4) # vAA<- %xmm0; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SUB_FLOAT: /* 0xa7 */
-/* File: x86-atom/OP_SUB_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_SUB_FLOAT.S
- */
-
-/* File: x86-atom/binopF.S */
- /* 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.
- */
-
- /*
- * File: binopF.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-float, mul-float, sub-float
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movss (rFP, %ecx, 4), %xmm0 # %xmm0<-vBB
- movss (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- subss %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movss %xmm0, (rFP, rINST, 4) # vAA<- %xmm0; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MUL_FLOAT: /* 0xa8 */
-/* File: x86-atom/OP_MUL_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_MUL_FLOAT.S
- */
-
-/* File: x86-atom/binopF.S */
- /* 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.
- */
-
- /*
- * File: binopF.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-float, mul-float, sub-float
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movss (rFP, %ecx, 4), %xmm0 # %xmm0<-vBB
- movss (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- mulss %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movss %xmm0, (rFP, rINST, 4) # vAA<- %xmm0; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DIV_FLOAT: /* 0xa9 */
-/* File: x86-atom/OP_DIV_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_DIV_FLOAT.S
- *
- * Code: Divides floats. Uses no substitutions.
- *
- * For: div-float
- *
- * Description: Divide operation on two source registers, storing
- * the result in a destiniation register
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %eax # %eax<- BB
- FETCH_CC 1, %ecx # %ecx<- CC
- flds (rFP, %eax, 4) # floating point stack vBB
- fdivs (rFP, %ecx, 4) # divide double; vBB/vCC
- fstps (rFP, rINST, 4) # vAA<- result
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_REM_FLOAT: /* 0xaa */
-/* File: x86-atom/OP_REM_FLOAT.S */
- /* 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.
- */
-
- /*
- * File: OP_REM_FLOAT.S
- *
- * Code: Computes the remainder of a division. Performs no substitutions.
- *
- * For: rem-float
- *
- * Description: Calls fmod to compute the remainder of the result of dividing a
- * source register by a second, and stores the result in a
- * destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- movl %ecx, -8(%esp) # push parameter float
- movl %edx, -4(%esp) # push parameter float
- lea -8(%esp), %esp
- call fmodf # call: (float x, float y)
- # return: float
- lea 8(%esp), %esp
- fstps (rFP, rINST, 4) # vAA<- remainder; return of fmod
- FINISH 2 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ADD_DOUBLE: /* 0xab */
-/* File: x86-atom/OP_ADD_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_ADD_DOUBLE.S
- */
-
-/* File: x86-atom/binopWide.S */
- /* 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.
- */
-
- /*
- * File: binopWide.S
- *
- * Code: Generic 64-bit binary operation. Provides an "instr" variable to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-double, add-long, and-long, mul-double, or-long,
- * sub-double, sub-long, xor-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- addsd %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movq %xmm0, (rFP, rINST, 4) # vAA<- %ecx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SUB_DOUBLE: /* 0xac */
-/* File: x86-atom/OP_SUB_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_SUB_DOUBLE.S
- */
-
-/* File: x86-atom/binopWide.S */
- /* 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.
- */
-
- /*
- * File: binopWide.S
- *
- * Code: Generic 64-bit binary operation. Provides an "instr" variable to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-double, add-long, and-long, mul-double, or-long,
- * sub-double, sub-long, xor-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- subsd %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movq %xmm0, (rFP, rINST, 4) # vAA<- %ecx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MUL_DOUBLE: /* 0xad */
-/* File: x86-atom/OP_MUL_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_MUL_DOUBLE.S
- */
-
-/* File: x86-atom/binopWide.S */
- /* 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.
- */
-
- /*
- * File: binopWide.S
- *
- * Code: Generic 64-bit binary operation. Provides an "instr" variable to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-double, add-long, and-long, mul-double, or-long,
- * sub-double, sub-long, xor-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- mulsd %xmm1, %xmm0 # %xmm0<- vBB op vCC
- movq %xmm0, (rFP, rINST, 4) # vAA<- %ecx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DIV_DOUBLE: /* 0xae */
-/* File: x86-atom/OP_DIV_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_DIV_DOUBLE.S
- *
- * Code: Divides doubles. Uses no substitutions.
- *
- * For: div-double
- *
- * Description: Divide operation on two source registers, storing
- * the result in a destination register
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- fldl (rFP, %ecx, 4) # floating point stack vBB
- fdivl (rFP, %edx, 4) # divide double; vBB/vCC
- fstpl (rFP, rINST, 4) # vAA<- result
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_REM_DOUBLE: /* 0xaf */
-/* File: x86-atom/OP_REM_DOUBLE.S */
- /* 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.
- */
-
- /*
- * File: OP_REM_DOUBLE.S
- *
- * Code: Computes the remainder of a division. Performs no substitutions.
- *
- * For: rem-double
- *
- * Description: Calls fmod to compute the remainder of the result of dividing a
- * source register by a second, and stores the result in a
- * destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- movl (rFP, %ecx, 4), %eax # %eax<- vBBlo
- movl %eax, -16(%esp) # push parameter double lo
- movl 4(rFP, %ecx, 4), %eax # %eax<- vBBhi
- movl %eax, -12(%esp) # push parameter double hi
- movl (rFP, %edx, 4), %eax # %eax<- vCClo
- movl %eax, -8(%esp) # push parameter double lo
- movl 4(rFP, %edx, 4), %eax # %eax<- vCChi
- movl %eax, -4(%esp) # push parameter double hi
- lea -16(%esp), %esp
- jmp .LOP_REM_DOUBLE_break
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ADD_INT_2ADDR: /* 0xb0 */
-/* File: x86-atom/OP_ADD_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_ADD_INT_2ADDR.S
- */
-
-/* File: x86-atom/binop2addr.S */
- /* 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.
- */
-
- /*
- * File: binop2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%ecx = %ecx op %edx".
- *
- * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
- * sub-int/2addr, xor-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- movl rINST, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- GET_VREG %ecx # %ecx<- vA
- addl %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SUB_INT_2ADDR: /* 0xb1 */
-/* File: x86-atom/OP_SUB_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_SUB_INT_2ADDR.S
- */
-
-/* File: x86-atom/binop2addr.S */
- /* 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.
- */
-
- /*
- * File: binop2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%ecx = %ecx op %edx".
- *
- * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
- * sub-int/2addr, xor-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- movl rINST, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- GET_VREG %ecx # %ecx<- vA
- subl %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MUL_INT_2ADDR: /* 0xb2 */
-/* File: x86-atom/OP_MUL_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_MUL_INT_2ADDR.S
- */
-
-/* File: x86-atom/binop2addr.S */
- /* 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.
- */
-
- /*
- * File: binop2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%ecx = %ecx op %edx".
- *
- * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
- * sub-int/2addr, xor-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- movl rINST, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- GET_VREG %ecx # %ecx<- vA
- imul %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DIV_INT_2ADDR: /* 0xb3 */
-/* File: x86-atom/OP_DIV_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_DIV_INT_2ADDR.S
- */
-
-/* File: x86-atom/binopD2addr.S */
- /* 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.
- */
-
- /*
- * File: binopD2addr.S
- *
- * Code: 32-bit "/2addr" integer divde operation. If "div"
- * is set, the code returns the quotient, else it returns
- * the remainder. Also, a divide-by-zero check is done.
- *
- * For: div-int/2addr, rem-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- andl $15, rINST # rINST<- A, to be used as dest
- movl rINST, %eax # %eax<- A
- shr $4, %ecx # %ecx<- B
- GET_VREG %eax # %eax<- vA
- GET_VREG %ecx # %edx<- vB
- cmp $0, %ecx # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- cmpl $-1, %ecx # handle -1 special case divide error
- jne .LOP_DIV_INT_2ADDR_noerror
- cmpl $0x80000000,%eax # handle min int special case divide error
- je .LOP_DIV_INT_2ADDR_break
-.LOP_DIV_INT_2ADDR_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- .if 1
- SET_VREG %eax rINST # vAA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vAA<- %edx (remainder)
- .endif
- jmp .LOP_DIV_INT_2ADDR_break2
- #FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
- #FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_REM_INT_2ADDR: /* 0xb4 */
-/* File: x86-atom/OP_REM_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_REM_INT_2ADDR.S
- */
-
-/* File: x86-atom/binopD2addr.S */
- /* 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.
- */
-
- /*
- * File: binopD2addr.S
- *
- * Code: 32-bit "/2addr" integer divde operation. If "div"
- * is set, the code returns the quotient, else it returns
- * the remainder. Also, a divide-by-zero check is done.
- *
- * For: div-int/2addr, rem-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- andl $15, rINST # rINST<- A, to be used as dest
- movl rINST, %eax # %eax<- A
- shr $4, %ecx # %ecx<- B
- GET_VREG %eax # %eax<- vA
- GET_VREG %ecx # %edx<- vB
- cmp $0, %ecx # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- cmpl $-1, %ecx # handle -1 special case divide error
- jne .LOP_REM_INT_2ADDR_noerror
- cmpl $0x80000000,%eax # handle min int special case divide error
- je .LOP_REM_INT_2ADDR_break
-.LOP_REM_INT_2ADDR_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- .if 0
- SET_VREG %eax rINST # vAA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vAA<- %edx (remainder)
- .endif
- jmp .LOP_REM_INT_2ADDR_break2
- #FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
- #FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AND_INT_2ADDR: /* 0xb5 */
-/* File: x86-atom/OP_AND_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_AND_INT_2ADDR.S
- */
-
-/* File: x86-atom/binop2addr.S */
- /* 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.
- */
-
- /*
- * File: binop2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%ecx = %ecx op %edx".
- *
- * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
- * sub-int/2addr, xor-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- movl rINST, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- GET_VREG %ecx # %ecx<- vA
- andl %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_OR_INT_2ADDR: /* 0xb6 */
-/* File: x86-atom/OP_OR_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_OR_INT_2ADDR.S
- */
-
-/* File: x86-atom/binop2addr.S */
- /* 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.
- */
-
- /*
- * File: binop2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%ecx = %ecx op %edx".
- *
- * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
- * sub-int/2addr, xor-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- movl rINST, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- GET_VREG %ecx # %ecx<- vA
- or %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_XOR_INT_2ADDR: /* 0xb7 */
-/* File: x86-atom/OP_XOR_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_XOR_INT_2ADDR.S
- */
-
-/* File: x86-atom/binop2addr.S */
- /* 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.
- */
-
- /*
- * File: binop2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%ecx = %ecx op %edx".
- *
- * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
- * sub-int/2addr, xor-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- movl rINST, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- GET_VREG %ecx # %ecx<- vA
- xor %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SHL_INT_2ADDR: /* 0xb8 */
-/* File: x86-atom/OP_SHL_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_SHL_INT_2ADDR.S
- */
-
-/* File: x86-atom/binopS2addr.S */
- /* 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.
- */
-
- /*
- * File: binopS2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%edx = %edx op %cl".
- *
- * For: shl-int/2addr, shr-int/2addr, ushr-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- andl $15, rINST # rINST<- A
- movl rINST, %edx # %edx<- A
- FFETCH_ADV 1, %eax # %ecx<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- GET_VREG %edx # %edx<- vA
- sal %cl, %edx # %edx<- vA op vB
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SHR_INT_2ADDR: /* 0xb9 */
-/* File: x86-atom/OP_SHR_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_SHR_INT_2ADDR.S
- */
-
-/* File: x86-atom/binopS2addr.S */
- /* 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.
- */
-
- /*
- * File: binopS2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%edx = %edx op %cl".
- *
- * For: shl-int/2addr, shr-int/2addr, ushr-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- andl $15, rINST # rINST<- A
- movl rINST, %edx # %edx<- A
- FFETCH_ADV 1, %eax # %ecx<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- GET_VREG %edx # %edx<- vA
- sar %cl, %edx # %edx<- vA op vB
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_USHR_INT_2ADDR: /* 0xba */
-/* File: x86-atom/OP_USHR_INT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_USHR_INT_2ADDR.S
- */
-
-/* File: x86-atom/binopS2addr.S */
- /* 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.
- */
-
- /*
- * File: binopS2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%edx = %edx op %cl".
- *
- * For: shl-int/2addr, shr-int/2addr, ushr-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- andl $15, rINST # rINST<- A
- movl rINST, %edx # %edx<- A
- FFETCH_ADV 1, %eax # %ecx<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- GET_VREG %edx # %edx<- vA
- shr %cl, %edx # %edx<- vA op vB
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ADD_LONG_2ADDR: /* 0xbb */
-/* File: x86-atom/OP_ADD_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_ADD_LONG_2ADDR.S
- */
-
-/* File: x86-atom/binopWide2addr.S */
- /* 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.
- */
-
- /*
- * File: binopWide2addr.S
- *
- * Code: Generic 64-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0= %xmm0 op %xmm1".
- *
- * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
- * or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- andl $15, %edx # %edx<- A
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vA
- paddq %xmm1, %xmm0 # %xmm0<- vA op vB
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; result
- FINISH 1 # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SUB_LONG_2ADDR: /* 0xbc */
-/* File: x86-atom/OP_SUB_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_SUB_LONG_2ADDR.S
- */
-
-/* File: x86-atom/binopWide2addr.S */
- /* 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.
- */
-
- /*
- * File: binopWide2addr.S
- *
- * Code: Generic 64-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0= %xmm0 op %xmm1".
- *
- * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
- * or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- andl $15, %edx # %edx<- A
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vA
- psubq %xmm1, %xmm0 # %xmm0<- vA op vB
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; result
- FINISH 1 # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MUL_LONG_2ADDR: /* 0xbd */
-/* File: x86-atom/OP_MUL_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_MUL_LONG_2ADDR.S
- *
- * Code: 64-bit integer multiply
- *
- * For: mul-long/2addr
- *
- * Description: Multiply two sources registers and store the result
- * in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- /*
- * Signed 64-bit integer multiply.
- *
- * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
- * WX
- * x YZ
- * --------
- * ZW ZX
- * YW YX
- *
- * The low word of the result holds ZX, the high word holds
- * (ZW+YX) + (the high overflow from ZX). YW doesn't matter because
- * it doesn't fit in the low 64 bits.
- */
-
- movl rINST, %edx # %edx<- BA+
- shr $4, rINST # rINST<- B
- andl $15, %edx # %edx<- A
- movl %edx, sReg0 # sReg0<- A
- jmp .LOP_MUL_LONG_2ADDR_finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DIV_LONG_2ADDR: /* 0xbe */
-/* File: x86-atom/OP_DIV_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_DIV_LONG_2ADDR.S
- */
-
-/* File: x86-atom/binopDivRemLong2Addr.S */
- /* 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.
- */
-
- /*
- * File: binopDivRemLong2Addr.S
- *
- * Code: 64-bit "/2addr" long divide operation. Variable
- * "func" defines the function called to do the operation.
- *
- * For: div-long/2addr, rem-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- and $15, rINST # rINST<- A
- movl (rFP, %edx, 4), %eax # %eax<- vB
- movl %eax, -12(%esp) # push arg vB
- movl 4(rFP, %edx, 4), %ecx # %ecx<- vB+1
- or %ecx, %eax # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- movl %ecx, -8(%esp) # push arg vB+1
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vA,vA+1
- jmp .LOP_DIV_LONG_2ADDR_break
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_REM_LONG_2ADDR: /* 0xbf */
-/* File: x86-atom/OP_REM_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_REM_LONG_2ADDR.S
- */
-
-/* File: x86-atom/binopDivRemLong2Addr.S */
- /* 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.
- */
-
- /*
- * File: binopDivRemLong2Addr.S
- *
- * Code: 64-bit "/2addr" long divide operation. Variable
- * "func" defines the function called to do the operation.
- *
- * For: div-long/2addr, rem-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- and $15, rINST # rINST<- A
- movl (rFP, %edx, 4), %eax # %eax<- vB
- movl %eax, -12(%esp) # push arg vB
- movl 4(rFP, %edx, 4), %ecx # %ecx<- vB+1
- or %ecx, %eax # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- movl %ecx, -8(%esp) # push arg vB+1
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vA,vA+1
- jmp .LOP_REM_LONG_2ADDR_break
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AND_LONG_2ADDR: /* 0xc0 */
-/* File: x86-atom/OP_AND_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_AND_LONG_2ADDR.S
- */
-
-/* File: x86-atom/binopWide2addr.S */
- /* 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.
- */
-
- /*
- * File: binopWide2addr.S
- *
- * Code: Generic 64-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0= %xmm0 op %xmm1".
- *
- * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
- * or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- andl $15, %edx # %edx<- A
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vA
- pand %xmm1, %xmm0 # %xmm0<- vA op vB
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; result
- FINISH 1 # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_OR_LONG_2ADDR: /* 0xc1 */
-/* File: x86-atom/OP_OR_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_OR_LONG_2ADDR.S
- */
-
-/* File: x86-atom/binopWide2addr.S */
- /* 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.
- */
-
- /*
- * File: binopWide2addr.S
- *
- * Code: Generic 64-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0= %xmm0 op %xmm1".
- *
- * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
- * or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- andl $15, %edx # %edx<- A
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vA
- por %xmm1, %xmm0 # %xmm0<- vA op vB
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; result
- FINISH 1 # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
-/* File: x86-atom/OP_XOR_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_XOR_LONG_2ADDR.S
- */
-
-/* File: x86-atom/binopWide2addr.S */
- /* 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.
- */
-
- /*
- * File: binopWide2addr.S
- *
- * Code: Generic 64-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0= %xmm0 op %xmm1".
- *
- * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
- * or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- andl $15, %edx # %edx<- A
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vA
- pxor %xmm1, %xmm0 # %xmm0<- vA op vB
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; result
- FINISH 1 # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
-/* File: x86-atom/OP_SHL_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_SHL_LONG_2ADDR.S
- *
- * Code: Performs a shift left long. Uses no substitutions.
- *
- * For: shl-long/2addr
- *
- * Description: Perform a binary shift operation using two source registers
- * where the fist is the value to shift and the second is the
- * shift amount. Store the result in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- movss (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vA
- movq .LshiftMask, %xmm2 # %xmm2<- mask for the shift bits
- pand %xmm2, %xmm0 # %xmm0<- masked shift bits
- psllq %xmm0, %xmm1 # %xmm1<- shifted vA
- movq %xmm1, (rFP, rINST, 4) # vA<- shifted vA
- FINISH 1 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SHR_LONG_2ADDR: /* 0xc4 */
-/* File: x86-atom/OP_SHR_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_SHR_LONG_2ADDR.S
- *
- * Code: Performs a shift left long
- *
- * For: shl-long/2addr
- *
- * Description: Perform a binary shift operation using two source registers
- * where the fist is the value to shift and the second is the
- * shift amount. Store the result in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- BA
- movss (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vA
- movq .LshiftMask, %xmm2
- pand %xmm2, %xmm0 # %xmm0<- masked for the shift bits
- psrlq %xmm0, %xmm1 # %xmm1<- shifted vBB
- cmpl $0, 4(rFP, rINST, 4) # check if we need to consider sign
- jl .LOP_SHR_LONG_2ADDR_finish # consider sign
- jmp .LOP_SHR_LONG_2ADDR_final # sign is fine, finish
-
-/* ------------------------------ */
- .balign 64
-.L_OP_USHR_LONG_2ADDR: /* 0xc5 */
-/* File: x86-atom/OP_USHR_LONG_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_USHR_LONG_2ADDR.S
- *
- * Code: Performs an unsigned shift right long operation. Uses no substiutions.
- *
- * For: ushr-long/2addr
- *
- * Description: Perform a binary shift operation using two source registers
- * where the fist is the value to shift and the second is the
- * shift amount. Store the result in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- movq .LshiftMask, %xmm2 # %xmm2<- mask for the shift bits
- movss (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vA
- pand %xmm2, %xmm0 # %xmm0<- masked shift bits
- psrlq %xmm0, %xmm1 # %xmm1<- shifted vA
- movq %xmm1, (rFP, rINST, 4) # vA<- shifted vA
- FINISH 1 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
-/* File: x86-atom/OP_ADD_FLOAT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_ADD_FLOAT_2ADDR.S
- */
-
-/* File: x86-atom/binopF2addr.S */
- /* 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.
- */
-
- /*
- * File: binopF2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0 = %xmm0 op %xmm1".
- *
- * For: add-float/2addr, mul-float/2addr, sub-float/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- andl $15, %ecx # %ecx<- A
- shr $4, rINST # rINST<- B
- FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
- movss (rFP, %ecx, 4), %xmm0 # %xmm0<- vA
- movss (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- addss %xmm1, %xmm0 # %xmm0<- vA op vB
- movss %xmm0, (rFP, %ecx, 4) # vA<- %xmm0; result
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
-/* File: x86-atom/OP_SUB_FLOAT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_SUB_FLOAT_2ADDR.S
- */
-
-/* File: x86-atom/binopF2addr.S */
- /* 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.
- */
-
- /*
- * File: binopF2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0 = %xmm0 op %xmm1".
- *
- * For: add-float/2addr, mul-float/2addr, sub-float/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- andl $15, %ecx # %ecx<- A
- shr $4, rINST # rINST<- B
- FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
- movss (rFP, %ecx, 4), %xmm0 # %xmm0<- vA
- movss (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- subss %xmm1, %xmm0 # %xmm0<- vA op vB
- movss %xmm0, (rFP, %ecx, 4) # vA<- %xmm0; result
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
-/* File: x86-atom/OP_MUL_FLOAT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_MUL_FLOAT_2ADDR.S
- */
-
-/* File: x86-atom/binopF2addr.S */
- /* 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.
- */
-
- /*
- * File: binopF2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0 = %xmm0 op %xmm1".
- *
- * For: add-float/2addr, mul-float/2addr, sub-float/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- andl $15, %ecx # %ecx<- A
- shr $4, rINST # rINST<- B
- FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
- movss (rFP, %ecx, 4), %xmm0 # %xmm0<- vA
- movss (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- mulss %xmm1, %xmm0 # %xmm0<- vA op vB
- movss %xmm0, (rFP, %ecx, 4) # vA<- %xmm0; result
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
-/* File: x86-atom/OP_DIV_FLOAT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_DIV_FLOAT_2ADDR.S
- *
- * Code: Divides floats. Uses no substitutions.
- *
- * For: div-float/2addr
- *
- * Description: Divide operation on two source registers, storing
- * the result in the first source reigster
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- andl $15, %ecx # %ecx<- A
- shr $4, rINST # rINST<- B
- flds (rFP, %ecx, 4) # %xmm0<- vA
- fdivs (rFP, rINST, 4) # divide double; vA/vB
- fstps (rFP, %ecx, 4) # vAA<- result
- FINISH 1 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_REM_FLOAT_2ADDR: /* 0xca */
-/* File: x86-atom/OP_REM_FLOAT_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_REM_FLOAT_2ADDR.S
- *
- * Code: Computes the remainder of a division. Performs no substitutions.
- *
- * For: rem-float/2addr
- *
- * Description: Calls fmod to compute the remainder of the result of dividing a
- * source register by a second, and stores the result in the first
- * source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- GET_VREG %edx # %edx<- vB
- movl (rFP, rINST, 4), %ecx # %ecx<- vA
- movl %ecx, -8(%esp) # push parameter vA
- movl %edx, -4(%esp) # push parameter vB
- lea -8(%esp), %esp
- call fmodf # call: (float x, float y)
- # return: float
- lea 8(%esp), %esp
- fstps (rFP, rINST, 4)
- FINISH 1 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
-/* File: x86-atom/OP_ADD_DOUBLE_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_ADD_DOUBLE_2ADDR.S
- */
-
-/* File: x86-atom/binopWide2addr.S */
- /* 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.
- */
-
- /*
- * File: binopWide2addr.S
- *
- * Code: Generic 64-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0= %xmm0 op %xmm1".
- *
- * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
- * or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- andl $15, %edx # %edx<- A
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vA
- addsd %xmm1, %xmm0 # %xmm0<- vA op vB
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; result
- FINISH 1 # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
-/* File: x86-atom/OP_SUB_DOUBLE_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_SUB_DOUBLE_2ADDR.S
- */
-
-/* File: x86-atom/binopWide2addr.S */
- /* 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.
- */
-
- /*
- * File: binopWide2addr.S
- *
- * Code: Generic 64-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0= %xmm0 op %xmm1".
- *
- * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
- * or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- andl $15, %edx # %edx<- A
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vA
- subsd %xmm1, %xmm0 # %xmm0<- vA op vB
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; result
- FINISH 1 # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
-/* File: x86-atom/OP_MUL_DOUBLE_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_MUL_DOUBLE_2ADDR.S
- */
-
-/* File: x86-atom/binopWide2addr.S */
- /* 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.
- */
-
- /*
- * File: binopWide2addr.S
- *
- * Code: Generic 64-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0= %xmm0 op %xmm1".
- *
- * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
- * or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, rINST # rINST<- B
- andl $15, %edx # %edx<- A
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vA
- mulsd %xmm1, %xmm0 # %xmm0<- vA op vB
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; result
- FINISH 1 # jump to next instruction
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
-/* File: x86-atom/OP_DIV_DOUBLE_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_DIV_DOUBLE_2ADDR.S
- *
- * Code: Divides doubles. Uses no substitutions.
- *
- * For: div-double/2addr
- *
- * Description: Divide operation on two source registers, storing
- * the result in the first source reigster
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- andl $15, %edx # %edx<- A
- shr $4, rINST # rINST<- B
- fldl (rFP, %edx, 4) # %xmm0<- vA
- fdivl (rFP, rINST, 4) # divide double; vA/vB
- fstpl (rFP, %edx, 4) # vAA<- result
- FINISH 1 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
-/* File: x86-atom/OP_REM_DOUBLE_2ADDR.S */
- /* 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.
- */
-
- /*
- * File: OP_REM_DOUBLE_2ADDR.S
- *
- * Code: Computes the remainder of a division. Performs no substitutions.
- *
- * For: rem-double/2addr
- *
- * Description: Calls fmod to compute the remainder of the result of dividing a
- * source register by a second, and stores the result in the first
- * source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- and $15, rINST # rINST<- A
- shr $4, %edx # %edx<- B
- movl (rFP, rINST, 4), %eax # %eax<- vAlo
- movl %eax, -20(%esp) # push parameter vAAlo
- movl 4(rFP, rINST, 4), %eax # %eax<- vAhi
- movl %eax, -16(%esp) # push parameter vAAhi
- movl (rFP, %edx, 4), %eax # %eax<- vBlo
- movl %eax, -12(%esp) # push parameter vBBlo
- movl 4(rFP, %edx, 4), %eax # %eax<- vBhi
- movl %eax, -8(%esp) # push parameter vBBhi
- lea -20(%esp), %esp
- jmp .LOP_REM_DOUBLE_2ADDR_break
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ADD_INT_LIT16: /* 0xd0 */
-/* File: x86-atom/OP_ADD_INT_LIT16.S */
- /* 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.
- */
-
- /*
- * File: OP_ADD_INT_LIT16.S
- */
-
-/* File: x86-atom/binopLit16.S */
- /* 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.
- */
-
- /*
- * File: binopLit16.S
- *
- * Code: 32-bit "lit16" operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
- * xor-int/lit16
- *
- * Description: Perform a binary operation on a register and a
- * sign extended 16-bit literal value and store the
- * result in a destination register.
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- andl $15, rINST # rINST<- A
- FETCHs 1, %edx # %edx<- +CCCC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- addl %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_RSUB_INT: /* 0xd1 */
-/* File: x86-atom/OP_RSUB_INT.S */
- /* 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.
- */
-
- /*
- * File: OP_RSUB_INT.S
- *
- * Code: 32-bit reverse-subtraction. Uses no substitutions.
- *
- * For: rsub-int
- *
- * Description: Perform a reverse subtraction on a register and a
- * signed extended 16-bit literal value and store the
- * result in a destination register.
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- andl $15, rINST # rINST<- A
- FETCHs 1, %edx # %edx<- +CCCC, sign-extended literal
- GET_VREG %ecx # %ecx<- vB
- subl %ecx, %edx # %edx<- +CCCC sub vB
- SET_VREG %edx, rINST # vA<- %edx; result
- FINISH 2 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MUL_INT_LIT16: /* 0xd2 */
-/* File: x86-atom/OP_MUL_INT_LIT16.S */
- /* 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.
- */
-
- /*
- * File: OP_MUL_INT_LIT16.S
- */
-
-/* File: x86-atom/binopLit16.S */
- /* 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.
- */
-
- /*
- * File: binopLit16.S
- *
- * Code: 32-bit "lit16" operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
- * xor-int/lit16
- *
- * Description: Perform a binary operation on a register and a
- * sign extended 16-bit literal value and store the
- * result in a destination register.
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- andl $15, rINST # rINST<- A
- FETCHs 1, %edx # %edx<- +CCCC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- imul %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DIV_INT_LIT16: /* 0xd3 */
-/* File: x86-atom/OP_DIV_INT_LIT16.S */
- /* 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.
- */
-
- /*
- * File: OP_DIV_INT_LIT16.S
- */
-
-/* File: x86-atom/binopDLit16.S */
- /* 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.
- */
-
- /*
- * File: binopDLit16.S
- *
- * Code: 32-bit "lit16" divide operation. If "div" is set, the code
- * returns the quotient, else it returns the remainder.
- * Also, a divide-by-zero check is done.
- *
- * For: div-int/lit16, rem-int/lit16
- *
- * Description: Perform a binary operation on a register and a
- * sign extended 16-bit literal value
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
-
- movl rINST, %eax # %eax<- BA
- shr $4, %eax # %eax<- B
- FETCHs 1, %ecx # %ecx<- +CCCC, sign-extended literal
- cmp $0, %ecx # check for divide by zero
- GET_VREG %eax # %eax<- vB
- je common_errDivideByZero # handle divide by zero
- andl $15, rINST # rINST<- A
- cmpl $-1, %ecx # handle -1 special case divide error
- jne .LOP_DIV_INT_LIT16_noerror
- cmpl $0x80000000,%eax # handle min int special case divide error
- je .LOP_DIV_INT_LIT16_break
-.LOP_DIV_INT_LIT16_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- #FFETCH_ADV 2, %ecx # %ecx<- next instruction hi; fetch, advance
- .if 1
- SET_VREG %eax rINST # vA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vA<- %edx (remainder)
- .endif
- jmp .LOP_DIV_INT_LIT16_break2
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_REM_INT_LIT16: /* 0xd4 */
-/* File: x86-atom/OP_REM_INT_LIT16.S */
- /* 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.
- */
-
- /*
- * File: OP_REM_INT_LIT16.S
- */
-
-/* File: x86-atom/binopDLit16.S */
- /* 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.
- */
-
- /*
- * File: binopDLit16.S
- *
- * Code: 32-bit "lit16" divide operation. If "div" is set, the code
- * returns the quotient, else it returns the remainder.
- * Also, a divide-by-zero check is done.
- *
- * For: div-int/lit16, rem-int/lit16
- *
- * Description: Perform a binary operation on a register and a
- * sign extended 16-bit literal value
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
-
- movl rINST, %eax # %eax<- BA
- shr $4, %eax # %eax<- B
- FETCHs 1, %ecx # %ecx<- +CCCC, sign-extended literal
- cmp $0, %ecx # check for divide by zero
- GET_VREG %eax # %eax<- vB
- je common_errDivideByZero # handle divide by zero
- andl $15, rINST # rINST<- A
- cmpl $-1, %ecx # handle -1 special case divide error
- jne .LOP_REM_INT_LIT16_noerror
- cmpl $0x80000000,%eax # handle min int special case divide error
- je .LOP_REM_INT_LIT16_break
-.LOP_REM_INT_LIT16_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- #FFETCH_ADV 2, %ecx # %ecx<- next instruction hi; fetch, advance
- .if 0
- SET_VREG %eax rINST # vA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vA<- %edx (remainder)
- .endif
- jmp .LOP_REM_INT_LIT16_break2
-
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AND_INT_LIT16: /* 0xd5 */
-/* File: x86-atom/OP_AND_INT_LIT16.S */
- /* 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.
- */
-
- /*
- * File: OP_AND_INT_LIT16.S
- */
-
-/* File: x86-atom/binopLit16.S */
- /* 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.
- */
-
- /*
- * File: binopLit16.S
- *
- * Code: 32-bit "lit16" operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
- * xor-int/lit16
- *
- * Description: Perform a binary operation on a register and a
- * sign extended 16-bit literal value and store the
- * result in a destination register.
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- andl $15, rINST # rINST<- A
- FETCHs 1, %edx # %edx<- +CCCC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- andl %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_OR_INT_LIT16: /* 0xd6 */
-/* File: x86-atom/OP_OR_INT_LIT16.S */
- /* 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.
- */
-
- /*
- * File: OP_OR_INT_LIT16.S
- */
-
-/* File: x86-atom/binopLit16.S */
- /* 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.
- */
-
- /*
- * File: binopLit16.S
- *
- * Code: 32-bit "lit16" operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
- * xor-int/lit16
- *
- * Description: Perform a binary operation on a register and a
- * sign extended 16-bit literal value and store the
- * result in a destination register.
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- andl $15, rINST # rINST<- A
- FETCHs 1, %edx # %edx<- +CCCC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- or %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_XOR_INT_LIT16: /* 0xd7 */
-/* File: x86-atom/OP_XOR_INT_LIT16.S */
- /* 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.
- */
-
- /*
- * File: OP_XOR_INT_LIT16.S
- */
-
-/* File: x86-atom/binopLit16.S */
- /* 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.
- */
-
- /*
- * File: binopLit16.S
- *
- * Code: 32-bit "lit16" operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
- * xor-int/lit16
- *
- * Description: Perform a binary operation on a register and a
- * sign extended 16-bit literal value and store the
- * result in a destination register.
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- andl $15, rINST # rINST<- A
- FETCHs 1, %edx # %edx<- +CCCC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- xor %edx, %ecx # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_ADD_INT_LIT8: /* 0xd8 */
-/* File: x86-atom/OP_ADD_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_ADD_INT_LIT8.S
- */
-
-/* File: x86-atom/binopLit8.S */
- /* 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.
- */
-
- /*
- * File: binopLit8.S
- *
- * Code: 32-bit "lit8" divide operation. Provides an "instr" line
- * to specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
- * xor-int/lit8
- *
- * Description: Perform a binary operation on a register and a
- * signed extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CCs 1, %edx # %edx<- +CC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- addl %edx, %ecx # %ecx<- vBB op +CC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_RSUB_INT_LIT8: /* 0xd9 */
-/* File: x86-atom/OP_RSUB_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_RSUB_INT_LIT8.S
- *
- * Code: 32-bit reverse-subtraction. Uses no substitutions.
- *
- * For: rsub-int/lit8
- *
- * Description: Perform a reverse subtraction on a register and a
- * signed extended 8-bit literal value.
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CCs 1, %edx # %edx<- +CC, sign-extended literal
- GET_VREG %ecx # %ecx<- vBB
- sub %ecx, %edx # %edx<- +CC sub vBB
- SET_VREG %edx, rINST # vAA<- %edx; result
- FINISH 2 # jump to next instruction
-
-/* ------------------------------ */
- .balign 64
-.L_OP_MUL_INT_LIT8: /* 0xda */
-/* File: x86-atom/OP_MUL_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_MUL_INT_LIT8.S
- */
-
-/* File: x86-atom/binopLit8.S */
- /* 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.
- */
-
- /*
- * File: binopLit8.S
- *
- * Code: 32-bit "lit8" divide operation. Provides an "instr" line
- * to specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
- * xor-int/lit8
- *
- * Description: Perform a binary operation on a register and a
- * signed extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CCs 1, %edx # %edx<- +CC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- imul %edx, %ecx # %ecx<- vBB op +CC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_DIV_INT_LIT8: /* 0xdb */
-/* File: x86-atom/OP_DIV_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_DIV_INT_LIT8.S
- */
-
-/* File: x86-atom/binopDLit8.S */
- /* 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.
- */
-
- /*
- * File: binopDLit8.S
- *
- * Code: 32-bit "lit8" divide operation. If "div" is set, the code
- * returns the quotient, else it returns the remainder.
- * Also, a divide-by-zero check is done.
- *
- * For: div-int/lit8, rem-int/lit8
- *
- * Description: Perform a binary operation on a register and a
- * signe extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
-
- FETCH_BB 1, %eax # %eax<- BB
- FETCH_CCs 1, %ecx # %ecx<- +CC, sign-extended literal
- cmp $0, %ecx # check for divide by zero
- GET_VREG %eax # %eax<- vBB
- je common_errDivideByZero # handle divide by zero
-
- cmpl $-1, %ecx # handle -1 special case divide error
- jne .LOP_DIV_INT_LIT8_noerror
- cmpl $0x80000000,%eax # handle min int special case divide error
- je .LOP_DIV_INT_LIT8_break
-.LOP_DIV_INT_LIT8_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- #FFETCH_ADV 2, %ecx # %ecx<- next instruction hi; fetch, advance
- .if 1
- SET_VREG %eax rINST # vAA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vAA<- %edx (remainder)
- .endif
- jmp .LOP_DIV_INT_LIT8_break2
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_REM_INT_LIT8: /* 0xdc */
-/* File: x86-atom/OP_REM_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_REM_INT_LIT8.S
- */
-
-/* File: x86-atom/binopDLit8.S */
- /* 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.
- */
-
- /*
- * File: binopDLit8.S
- *
- * Code: 32-bit "lit8" divide operation. If "div" is set, the code
- * returns the quotient, else it returns the remainder.
- * Also, a divide-by-zero check is done.
- *
- * For: div-int/lit8, rem-int/lit8
- *
- * Description: Perform a binary operation on a register and a
- * signe extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
-
- FETCH_BB 1, %eax # %eax<- BB
- FETCH_CCs 1, %ecx # %ecx<- +CC, sign-extended literal
- cmp $0, %ecx # check for divide by zero
- GET_VREG %eax # %eax<- vBB
- je common_errDivideByZero # handle divide by zero
-
- cmpl $-1, %ecx # handle -1 special case divide error
- jne .LOP_REM_INT_LIT8_noerror
- cmpl $0x80000000,%eax # handle min int special case divide error
- je .LOP_REM_INT_LIT8_break
-.LOP_REM_INT_LIT8_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- #FFETCH_ADV 2, %ecx # %ecx<- next instruction hi; fetch, advance
- .if 0
- SET_VREG %eax rINST # vAA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vAA<- %edx (remainder)
- .endif
- jmp .LOP_REM_INT_LIT8_break2
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_AND_INT_LIT8: /* 0xdd */
-/* File: x86-atom/OP_AND_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_AND_INT_LIT8.S
- */
-
-/* File: x86-atom/binopLit8.S */
- /* 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.
- */
-
- /*
- * File: binopLit8.S
- *
- * Code: 32-bit "lit8" divide operation. Provides an "instr" line
- * to specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
- * xor-int/lit8
- *
- * Description: Perform a binary operation on a register and a
- * signed extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CCs 1, %edx # %edx<- +CC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- andl %edx, %ecx # %ecx<- vBB op +CC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_OR_INT_LIT8: /* 0xde */
-/* File: x86-atom/OP_OR_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_OR_INT_LIT8.S
- */
-
-/* File: x86-atom/binopLit8.S */
- /* 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.
- */
-
- /*
- * File: binopLit8.S
- *
- * Code: 32-bit "lit8" divide operation. Provides an "instr" line
- * to specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
- * xor-int/lit8
- *
- * Description: Perform a binary operation on a register and a
- * signed extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CCs 1, %edx # %edx<- +CC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- or %edx, %ecx # %ecx<- vBB op +CC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_XOR_INT_LIT8: /* 0xdf */
-/* File: x86-atom/OP_XOR_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_XOR_INT_LIT8.S
- */
-
-/* File: x86-atom/binopLit8.S */
- /* 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.
- */
-
- /*
- * File: binopLit8.S
- *
- * Code: 32-bit "lit8" divide operation. Provides an "instr" line
- * to specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
- * xor-int/lit8
- *
- * Description: Perform a binary operation on a register and a
- * signed extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CCs 1, %edx # %edx<- +CC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- xor %edx, %ecx # %ecx<- vBB op +CC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SHL_INT_LIT8: /* 0xe0 */
-/* File: x86-atom/OP_SHL_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_SHL_INT_LIT8.S
- */
-
-/* File: x86-atom/binopLit8S.S */
- /* 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.
- */
-
- /*
- * File: binopLit8S.S
- *
- * Code: 32-bit "lit8" divide operation. Provides an "instr" line
- * to specify an instruction that performs "%edx = %edx op %cl"
- *
- *
- * For: shl-int/lit8, shr-int/lit8, ushr-int/lit8
- *
- *
- * Description: Perform a binary operation on a register and a
- * signed extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %edx # %edx<- BB
- FETCH_CCs 1, %ecx # %ecx<- +CC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vBB
- sal %cl, %edx # %edx<- vBB op +CC
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_SHR_INT_LIT8: /* 0xe1 */
-/* File: x86-atom/OP_SHR_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_SHR_INT_LIT8.S
- */
-
-/* File: x86-atom/binopLit8S.S */
- /* 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.
- */
-
- /*
- * File: binopLit8S.S
- *
- * Code: 32-bit "lit8" divide operation. Provides an "instr" line
- * to specify an instruction that performs "%edx = %edx op %cl"
- *
- *
- * For: shl-int/lit8, shr-int/lit8, ushr-int/lit8
- *
- *
- * Description: Perform a binary operation on a register and a
- * signed extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %edx # %edx<- BB
- FETCH_CCs 1, %ecx # %ecx<- +CC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vBB
- sar %cl, %edx # %edx<- vBB op +CC
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_USHR_INT_LIT8: /* 0xe2 */
-/* File: x86-atom/OP_USHR_INT_LIT8.S */
- /* 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.
- */
-
- /*
- * File: OP_USHR_INT_LIT8.S
- */
-
-/* File: x86-atom/binopLit8S.S */
- /* 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.
- */
-
- /*
- * File: binopLit8S.S
- *
- * Code: 32-bit "lit8" divide operation. Provides an "instr" line
- * to specify an instruction that performs "%edx = %edx op %cl"
- *
- *
- * For: shl-int/lit8, shr-int/lit8, ushr-int/lit8
- *
- *
- * Description: Perform a binary operation on a register and a
- * signed extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %edx # %edx<- BB
- FETCH_CCs 1, %ecx # %ecx<- +CC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vBB
- shr %cl, %edx # %edx<- vBB op +CC
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_VOLATILE: /* 0xe3 */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_IGET_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_VOLATILE: /* 0xe4 */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_IPUT_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_SGET_VOLATILE: /* 0xe5 */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_SGET_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_SPUT_VOLATILE: /* 0xe6 */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_SPUT_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_IGET_OBJECT_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_IGET_WIDE_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_IPUT_WIDE_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_SGET_WIDE_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_SPUT_WIDE_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_BREAKPOINT: /* 0xec */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_BREAKPOINT # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
-/* File: x86-atom/OP_THROW_VERIFICATION_ERROR.S */
- /* 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.
- */
-
- /*
- * File: OP_THROW_VERIFICATION_ERROR.S
- *
- * Code:
- *
- * For: throw-verification-error
- *
- * Description: Throws an exception for an error discovered during verification.
- * The exception is indicated by AA with details provided by BBBB.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, ref@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %ecx # %ecx<- glue->method
- EXPORT_PC # in case an exception is thrown
- FETCH 1, %eax # %eax<- BBBB
- movl %eax, -4(%esp) # push parameter BBBB; ref
- movl rINST, -8(%esp) # push parameter AA
- movl %ecx, -12(%esp) # push parameter glue->method
- lea -12(%esp), %esp
- call dvmThrowVerificationError # call: (const Method* method, int kind, int ref)
- jmp common_exceptionThrown # failed; handle exception
-
-/* ------------------------------ */
- .balign 64
-.L_OP_EXECUTE_INLINE: /* 0xee */
-/* File: x86-atom/OP_EXECUTE_INLINE.S */
- /* 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.
- */
-
- /*
- * File: OP_EXECUTE_INLINE.S
- *
- * Code: Executes a "native inline" instruction. Uses no substitutions.
- *
- * For: execute-inline
- *
- * Description: Executes a "native inline" instruction. This instruction
- * is generated by the optimizer.
- *
- * Format:
- *
- * Syntax: vAA, {vC, vD, vE, vF}, inline@BBBB
- */
-
- FETCH 1, %ecx # %ecx<- BBBB
- movl rGLUE, %eax # %eax<- MterpGlue pointer
- addl $offGlue_retval, %eax # %eax<- &glue->retval
- EXPORT_PC
- shr $4, rINST # rINST<- B
- movl %eax, -8(%esp) # push parameter glue->retval
- lea -24(%esp), %esp
- jmp .LOP_EXECUTE_INLINE_continue
-
-/* ------------------------------ */
- .balign 64
-.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_EXECUTE_INLINE_RANGE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_INVOKE_OBJECT_INIT_RANGE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_RETURN_VOID_BARRIER: /* 0xf1 */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_RETURN_VOID_BARRIER # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_QUICK: /* 0xf2 */
-/* File: x86-atom/OP_IGET_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET_QUICK.S
- *
- * Code: Optimization for iget
- *
- * For: iget-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- shr $4, %eax # %eax<- B
- and $15, rINST # rINST<- A
- GET_VREG %eax # %eax<- vB; object to operate on
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- cmp $0, %eax # check if object is null
- je common_errNullObject # handle null object
- FFETCH_ADV 2, %edx # %eax<- next instruction hi; fetch, advance
- movl (%ecx, %eax), %eax # %eax<- object field
- SET_VREG %eax, rINST # fp[A]<- %eax
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
-/* File: x86-atom/OP_IGET_WIDE_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET_WIDE_QUICK.S
- *
- * Code: Optimization for iget
- *
- * For: iget/wide-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- GET_VREG %edx # %edx<- vB; object to operate on
- cmp $0, %edx # check if object is null
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- je common_errNullObject # handle null object
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- movq (%ecx, %edx), %xmm0 # %xmm0<- object field
- movq %xmm0, (rFP, rINST, 4) # fp[A]<- %xmm0
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
-/* File: x86-atom/OP_IGET_OBJECT_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET_OBJECT_QUICK.S
- */
-
-/* File: x86-atom/OP_IGET_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_IGET_QUICK.S
- *
- * Code: Optimization for iget
- *
- * For: iget-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- shr $4, %eax # %eax<- B
- and $15, rINST # rINST<- A
- GET_VREG %eax # %eax<- vB; object to operate on
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- cmp $0, %eax # check if object is null
- je common_errNullObject # handle null object
- FFETCH_ADV 2, %edx # %eax<- next instruction hi; fetch, advance
- movl (%ecx, %eax), %eax # %eax<- object field
- SET_VREG %eax, rINST # fp[A]<- %eax
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_QUICK: /* 0xf5 */
-/* File: x86-atom/OP_IPUT_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT_QUICK.S
- * Code: Optimization for iput
- *
- * For: iput-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- shr $4, %eax # %eax<- B
- and $15, rINST # rINST<- A
- GET_VREG %eax # %eax<- vB; object to operate on
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- cmp $0, %eax # check if object is null
- je common_errNullObject # handle null object
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vA
- movl rINST, (%eax, %ecx) # object field<- vA
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
-/* File: x86-atom/OP_IPUT_WIDE_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT_WIDE_QUICK.S
- *
- * Code: Optimization for iput
- *
- * For: iput/wide-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- GET_VREG %edx # %edx<- vB; object to operate on
- cmp $0, %edx # check if object is null
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- je common_errNullObject # handle null object
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- fp[A]
- movq %xmm0, (%edx, %ecx) # object field<- %xmm0; fp[A]
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
-/* File: x86-atom/OP_IPUT_OBJECT_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_IPUT_QUICK.S
- * Code: Optimization for iput
- *
- * For: iput-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- shr $4, %eax # %eax<- B
- and $15, rINST # rINST<- A
- GET_VREG %eax # %eax<- vB; object to operate on
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- cmp $0, %eax # check if object is null
- je common_errNullObject # handle null object
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vA
- movl rINST, (%eax, %ecx) # object field<- vA
- testl rINST, rINST # did we write a null object
- je 1f
- movl rGLUE, %ecx # get glue
- movl offGlue_cardTable(%ecx), %ecx # get card table base
- shrl $GC_CARD_SHIFT, %eax # get gc card index
- movb %cl, (%eax, %ecx) # mark gc card in table
-1:
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
-/* File: x86-atom/OP_INVOKE_VIRTUAL_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_VIRTUAL_QUICK.S
- *
- * Code: Optimization for invoke-virtual and invoke-virtual/range
- *
- * For: invoke-virtual/quick, invoke-virtual/quick-range
- */
-
-
- FETCH 2, %edx # %edx<- GFED or CCCC
- .if (!0)
- and $15, %edx # %edx<- D if not range
- .endif
- FETCH 1, %ecx # %ecx<- method index
- GET_VREG %edx # %edx<- "this" ptr
- cmp $0, %edx # %edx<- check for null "this"
- EXPORT_PC # must export pc for invoke
- je common_errNullObject
- movl offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
- movl offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
- movl (%edx, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
- jmp common_invokeMethodNoRange # invoke method common code
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
-/* File: x86-atom/OP_INVOKE_VIRTUAL_QUICK_RANGE.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_VIRTUAL_QUICK_RANGE.S
- */
-
-/* File: x86-atom/OP_INVOKE_VIRTUAL_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_VIRTUAL_QUICK.S
- *
- * Code: Optimization for invoke-virtual and invoke-virtual/range
- *
- * For: invoke-virtual/quick, invoke-virtual/quick-range
- */
-
-
- FETCH 2, %edx # %edx<- GFED or CCCC
- .if (!1)
- and $15, %edx # %edx<- D if not range
- .endif
- FETCH 1, %ecx # %ecx<- method index
- GET_VREG %edx # %edx<- "this" ptr
- cmp $0, %edx # %edx<- check for null "this"
- EXPORT_PC # must export pc for invoke
- je common_errNullObject
- movl offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
- movl offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
- movl (%edx, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
- jmp common_invokeMethodRange # invoke method common code
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_SUPER_QUICK: /* 0xfa */
-/* File: x86-atom/OP_INVOKE_SUPER_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_SUPER_QUICK.S
- *
- * Code: Optimization for invoke-super and invoke-super/range
- *
- * For: invoke-super/quick, invoke-super/quick-range
- */
-
-
- FETCH 2, %edx # %edx<- GFED or CCCC
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_method(%ecx), %eax # %eax<- glue->method
- .if (!0)
- and $15, %edx # %edx<- D if not range
- .endif
- FETCH 1, %ecx # %ecx<- method index
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- movl offClassObject_super(%eax), %eax # %eax<- glue->method->clazz->super
- EXPORT_PC # must export for invoke
- movl offClassObject_vtable(%eax), %eax # %edx<- glue->method->clazz->super->vtable
- cmp $0, (rFP, %edx, 4) # check for null object
- movl (%eax, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
- je common_errNullObject # handle null object
- jmp common_invokeMethodNoRange # invoke method common code
-
-/* ------------------------------ */
- .balign 64
-.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
-/* File: x86-atom/OP_INVOKE_SUPER_QUICK_RANGE.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_SUPER_QUICK_RANGE.S
- */
-
-/* File: x86-atom/OP_INVOKE_SUPER_QUICK.S */
- /* 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.
- */
-
- /*
- * File: OP_INVOKE_SUPER_QUICK.S
- *
- * Code: Optimization for invoke-super and invoke-super/range
- *
- * For: invoke-super/quick, invoke-super/quick-range
- */
-
-
- FETCH 2, %edx # %edx<- GFED or CCCC
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_method(%ecx), %eax # %eax<- glue->method
- .if (!1)
- and $15, %edx # %edx<- D if not range
- .endif
- FETCH 1, %ecx # %ecx<- method index
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- movl offClassObject_super(%eax), %eax # %eax<- glue->method->clazz->super
- EXPORT_PC # must export for invoke
- movl offClassObject_vtable(%eax), %eax # %edx<- glue->method->clazz->super->vtable
- cmp $0, (rFP, %edx, 4) # check for null object
- movl (%eax, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
- je common_errNullObject # handle null object
- jmp common_invokeMethodRange # invoke method common code
-
-
-/* ------------------------------ */
- .balign 64
-.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_IPUT_OBJECT_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_SGET_OBJECT_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
- /* 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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_OP_SPUT_OBJECT_VOLATILE # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
-/* ------------------------------ */
- .balign 64
-.L_OP_UNUSED_FF: /* 0xff */
-/* File: x86-atom/OP_UNUSED_FF.S */
- /* 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.
- */
-
-/* File: x86-atom/unused.S */
- /* 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
- .balign 64
- .size dvmAsmInstructionStart, .-dvmAsmInstructionStart
- .global dvmAsmInstructionEnd
-dvmAsmInstructionEnd:
-
-/*
- * ===========================================================================
- * Sister implementations
- * ===========================================================================
- */
- .global dvmAsmSisterStart
- .type dvmAsmSisterStart, %function
- .text
- .balign 4
-dvmAsmSisterStart:
-
-/* continuation for OP_CONST_STRING */
-
-
- /*
- * Continuation if the Class has not yet been resolved.
- * %ecx: BBBB (Class ref)
- * need: target register
- */
-
-.LOP_CONST_STRING_resolve:
- EXPORT_PC
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %ecx, -4(%esp) # push parameter class ref
- movl %edx, -8(%esp) # push parameter glue->method->clazz
- lea -8(%esp), %esp
- call dvmResolveString # resolve string reference
- # call: (const ClassObject* referrer, u4 stringIdx)
- # return: StringObject*
- lea 8(%esp), %esp
- cmp $0, %eax # check if resolved string failed
- je common_exceptionThrown # resolve failed; exception thrown
- SET_VREG %eax, rINST # vAA<- %eax; pResString[BBBB]
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* continuation for OP_CONST_STRING_JUMBO */
-
-
- /*
- * Continuation if the Class has not yet been resolved.
- * %ecx: BBBB (Class ref)
- * need: target register
- */
-.LOP_CONST_STRING_JUMBO_resolve:
- EXPORT_PC
- movl rGLUE, %edx # get MterpGlue pointer
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl offMethod_clazz(%edx), %edx # %edx <- glue->method->clazz
- movl %ecx, -4(%esp) # push parameter class ref
- movl %edx, -8(%esp) # push parameter glue->method->clazz
- lea -8(%esp), %esp
- call dvmResolveString # resolve string reference
- # call: (const ClassObject* referrer, u4 stringIdx)
- # return: StringObject*
- lea 8(%esp), %esp
- cmp $0, %eax # check if resolved string failed
- je common_exceptionThrown # resolve failed; exception thrown
- SET_VREG %eax, rINST # vAA<- %eax; pResString[BBBB]
- FINISH 3 # jump to next instruction
-
-/* continuation for OP_CONST_CLASS */
-
- /*
- * Continuation if the Class has not yet been resolved.
- * %ecx: BBBB (Class ref)
- * need: target register
- */
-
-.LOP_CONST_CLASS_resolve:
- EXPORT_PC
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl $1, -4(%esp) # push parameter true
- movl %ecx, -8(%esp) # push parameter
- movl %edx, -12(%esp) # push parameter glue->method->clazz
- lea -12(%esp), %esp
- call dvmResolveClass # resolve ClassObject pointer
- # class: (const ClassObject* referrer, u4 classIdx,
- # bool fromUnverifiedConstant)
- # return: ClassObject*
- lea 12(%esp), %esp
- cmp $0, %eax # check for null pointer
- je common_exceptionThrown # handle exception
- SET_VREG %eax, rINST # vAA<- resolved class
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_CHECK_CAST */
-
-.LOP_CHECK_CAST_resolved:
- cmp %ecx, offObject_clazz(rINST) # check for same class
- jne .LOP_CHECK_CAST_fullcheck # not same class; do full check
-
-.LOP_CHECK_CAST_okay:
- FINISH 2 # jump to next instruction
-
- /*
- * Trivial test failed, need to perform full check.
- * offObject_clazz(rINST) holds obj->clazz
- * %ecx holds class resolved from BBBB
- * rINST holds object
- */
-
-.LOP_CHECK_CAST_fullcheck:
- movl offObject_clazz(rINST), %eax # %eax<- obj->clazz
- movl %eax, -12(%esp) # push parameter obj->clazz
- movl %ecx, -8(%esp) # push parameter # push parameter resolved class
- lea -12(%esp), %esp
- call dvmInstanceofNonTrivial # call: (ClassObject* instance, ClassObject* clazz)
- # return: int
- lea 12(%esp), %esp
- cmp $0, %eax # failed?
- jne .LOP_CHECK_CAST_okay # success
-
- /*
- * A cast has failed. We need to throw a ClassCastException with the
- * class of the object that failed to be cast.
- */
-
- EXPORT_PC # we will throw an exception
-#error BIT ROT!!!
- /*
- * TODO: Code here needs to call dvmThrowClassCastException with two
- * arguments.
- */
-#if 0
- /* old obsolete code that called dvmThrowExceptionWithClassMessage */
- movl $.LstrClassCastExceptionPtr, -8(%esp) # push parameter message
- movl offObject_clazz(rINST), rINST # rINST<- obj->clazz
- movl offClassObject_descriptor(rINST), rINST # rINST<- obj->clazz->descriptor
- movl rINST, -4(%esp) # push parameter obj->clazz->descriptor
- lea -8(%esp), %esp
- call dvmThrowExceptionWithClassMessage # call: (const char* exceptionDescriptor,
- # const char* messageDescriptor, Object* cause)
- # return: void
-#endif
- lea 8(%esp), %esp
- jmp common_exceptionThrown
-
- /*
- * Resolution required. This is the least-likely path.
- *
- * rINST holds object
- */
-
-.LOP_CHECK_CAST_resolve:
- movl offGlue_method(%edx), %eax # %eax<- glue->method
- FETCH 1, %ecx # %ecx holds BBBB
- EXPORT_PC # in case we throw an exception
- movl $0, -8(%esp) # push parameter false
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- movl %ecx, -12(%esp) # push parameter BBBB
- movl %eax, -16(%esp) # push parameter glue->method>clazz
- lea -16(%esp), %esp
- call dvmResolveClass # resolve ClassObject pointer
- # call: (const ClassObject* referrer, u4 classIdx,
- # bool fromUnverifiedConstant)
- # return ClassObject*
- lea 16(%esp), %esp
- cmp $0, %eax # check for null pointer
- je common_exceptionThrown # handle excpetion
- movl %eax, %ecx # %ecx<- resolved class
- jmp .LOP_CHECK_CAST_resolved
-
-/* continuation for OP_INSTANCE_OF */
-
-.LOP_INSTANCE_OF_break:
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- CCCC
- movl offDvmDex_pResClasses(%ecx), %ecx # %ecx<- pDvmDex->pResClasses
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved class
- movl offObject_clazz(%edx), %edx # %edx<- obj->clazz
- cmp $0, %ecx # check if already resovled
- je .LOP_INSTANCE_OF_resolve # not resolved before, so resolve now
-
-.LOP_INSTANCE_OF_resolved:
- cmp %ecx, %edx # check if same class
- je .LOP_INSTANCE_OF_trivial # yes, finish
- jmp .LOP_INSTANCE_OF_fullcheck # no, do full check
-
- /*
- * The trivial test failed, we need to perform a full check.
- * %edx holds obj->clazz
- * %ecx holds class resolved from BBBB
- */
-
-.LOP_INSTANCE_OF_fullcheck:
- movl %edx, -8(%esp) # push parameter obj->clazz
- movl %ecx, -4(%esp) # push parameter resolved class
- lea -8(%esp), %esp
- call dvmInstanceofNonTrivial # perform full check
- # call: (ClassObject* instance, ClassObject* clazz)
- # return: int
- andl $15, rINST # rINST<- A
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- lea 8(%esp), %esp
- SET_VREG %eax, rINST # vA<- r0
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
- /*
- * %edx holds boolean result
- */
-
-.LOP_INSTANCE_OF_store:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- andl $15, rINST # rINST<- A
- SET_VREG %edx, rINST # vA<- r0
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
- /*
- * Trivial test succeeded, save and bail.
- */
-
-.LOP_INSTANCE_OF_trivial:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- andl $15, rINST # rINST<- A
- SET_VREG $1, rINST # vA<- r0
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
- /*
- * Resolution required. This is the least-likely path.
- * %eax holds BBBB
- */
-
-.LOP_INSTANCE_OF_resolve:
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- EXPORT_PC
- movl offGlue_method(%ecx), %ecx # %ecx<- glue->method
- movl offMethod_clazz(%ecx), %ecx # %ecx<- glue->method->clazz
- movl %ecx, -12(%esp) # push parameter glue->method->clazz
- movl %eax, -8(%esp) # push parameter CCCC; type index
- movl $1, -4(%esp) # push parameter true
- lea -12(%esp), %esp
- call dvmResolveClass # call: (const ClassObject* referrer, u4 classIdx,
- # bool fromUnverifiedConstant)
- # return: ClassObject*
- lea 12(%esp), %esp
- cmp $0, %eax # check for null
- je common_exceptionThrown # handle exception
- movl rINST, %edx # %edx<- BA+
- shr $4, %edx # %edx<- B
- movl %eax, %ecx # need class in %ecx
- GET_VREG %edx # %edx<- vB
- movl offObject_clazz(%edx), %edx # %edx<- obj->clazz
- jmp .LOP_INSTANCE_OF_resolved # clazz resolved, continue
-
-/* continuation for OP_NEW_INSTANCE */
-.balign 32
-.LOP_NEW_INSTANCE_finish:
- movl %edx, -8(%esp) # push parameter object
- movl %eax, -4(%esp) # push parameter flags
- lea -8(%esp), %esp
- call dvmAllocObject # call: (ClassObject* clazz, int flags)
- # return: Object*
- cmp $0, %eax # check for failure
- lea 8(%esp), %esp
- je common_exceptionThrown # handle exception
- SET_VREG %eax, rINST # vAA<- pObject
- FINISH 2 # jump to next instruction
-
- /*
- * Class initialization required.
- *
- * %edx holds class object
- */
-
-.LOP_NEW_INSTANCE_needinit:
- movl %edx, -4(%esp) # push parameter object
- lea -4(%esp), %esp
- call dvmInitClass # call: (ClassObject* clazz)
- # return: bool
- lea 4(%esp), %esp
- cmp $0, %eax # check for failure
- movl -4(%esp), %edx # %edx<- object
- je common_exceptionThrown # handle exception
- testl $(ACC_INTERFACE|ACC_ABSTRACT), offClassObject_accessFlags(%edx)
- mov $ALLOC_DONT_TRACK, %eax # %eax<- flag for alloc call
- je .LOP_NEW_INSTANCE_finish # continue
- jmp .LOP_NEW_INSTANCE_abstract # handle abstract or interface
-
- /*
- * Resolution required. This is the least-likely path.
- *
- * BBBB in %eax
- */
-
-.LOP_NEW_INSTANCE_resolve:
-
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- FETCH 1, %eax # %eax<- BBBB
- movl offGlue_method(%ecx), %ecx # %ecx<- glue->method
- movl offMethod_clazz(%ecx), %ecx # %ecx<- glue->method->clazz
- movl %ecx, -12(%esp) # push parameter clazz
- movl $0, -4(%esp) # push parameter false
- movl %eax, -8(%esp) # push parameter BBBB
- lea -12(%esp), %esp
- call dvmResolveClass # call: (const ClassObject* referrer,
- # u4 classIdx, bool fromUnverifiedConstant)
- # return: ClassObject*
- lea 12(%esp), %esp
- movl %eax, %edx # %edx<- pObject
- cmp $0, %edx # check for failure
- jne .LOP_NEW_INSTANCE_resolved # continue
- jmp common_exceptionThrown # handle exception
-
- /*
- * We can't instantiate an abstract class or interface, so throw an
- * InstantiationError with the class descriptor as the message.
- *
- * %edx holds class object
- */
-
-.LOP_NEW_INSTANCE_abstract:
- movl offClassObject_descriptor(%edx), %ecx # %ecx<- descriptor
- movl %ecx, -4(%esp) # push parameter descriptor
- movl $.LstrInstantiationErrorPtr, -8(%esp) # push parameter message
- lea -8(%esp), %esp
- call dvmThrowExceptionWithClassMessage # call: (const char* exceptionDescriptor,
- # const char* messageDescriptor)
- # return: void
- jmp common_exceptionThrown # handle exception
-
-.LstrInstantiationErrorPtr:
-.asciz "Ljava/lang/InstantiationError;"
-
-/* continuation for OP_NEW_ARRAY */
-
- /*
- * Resolve class. (This is an uncommon case.)
- *
- * %edx holds array length
- * %ecx holds class ref CCCC
- */
-
-.LOP_NEW_ARRAY_resolve:
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_method(%eax), %eax # %eax<- glue->method
- movl %edx, -4(%esp) # save length
- movl $0, -8(%esp) # push parameter false
- movl %ecx, -12(%esp) # push parameter class ref
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- movl %eax, -16(%esp) # push parameter clazz
- lea -16(%esp), %esp
- call dvmResolveClass # call: (const ClassObject* referrer,
- # u4 classIdx, bool fromUnverifiedConstant)
- # return: ClassObject*
- cmp $0, %eax # check for failure
- lea 16(%esp), %esp
- je common_exceptionThrown # handle exception
- movl -4(%esp), %edx # %edx<- length
-
- /*
- * Finish allocation.
- *
- * %eax holds class
- * %edx holds array length
- */
-
-.LOP_NEW_ARRAY_finish:
- movl %eax, -12(%esp) # push parameter class
- movl %edx, -8(%esp) # push parameter length
- movl $ALLOC_DONT_TRACK, -4(%esp)
- lea -12(%esp), %esp
- call dvmAllocArrayByClass # call: (ClassObject* arrayClass,
- # size_t length, int allocFlags)
- # return: ArrayObject*
- and $15, rINST # rINST<- A
- cmp $0, %eax # check for allocation failure
- lea 12(%esp), %esp
- je common_exceptionThrown # handle exception
- SET_VREG %eax, rINST # vA<- pArray
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_FILLED_NEW_ARRAY */
-
-.LOP_FILLED_NEW_ARRAY_break:
- movl $0, -8(%esp) # push parameter false
- movl %ecx, -12(%esp) # push parameter BBBB
- movl rGLUE, %edx # %edx<- MterpGlue pointer
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, -16(%esp) # push parameter glue->method->clazz
- lea -16(%esp), %esp
- call dvmResolveClass # call: (const ClassObject* referrer, u4 classIdx,
- # bool fromUnverifiedConstant)
- # return: ClassObject*
- lea 16(%esp), %esp
- cmp $0, %eax # check for null return
- je common_exceptionThrown # handle exception
-
- /*
- * On entry:
- * %eax holds array class
- * rINST holds BA or AA
- */
-
-.LOP_FILLED_NEW_ARRAY_continue:
- movl offClassObject_descriptor(%eax), %eax # %eax<- arrayClass->descriptor
- movzbl 1(%eax), %eax # %eax<- descriptor[1]
- cmpb $'I', %al # check if array of ints
- je 1f
- cmpb $'L', %al
- je 1f
- cmpb $'[', %al
- jne .LOP_FILLED_NEW_ARRAY_notimpl # jump to not implemented
-1:
- movl %eax, sReg0 # save type
- movl rINST, -12(%esp) # push parameter length
- movl %eax, -16(%esp) # push parameter descriptor[1]
- movl $ALLOC_DONT_TRACK, -8(%esp) # push parameter to allocate flags
- .if (!0)
- shrl $4, -12(%esp) # parameter length is B
- .endif
- lea -16(%esp), %esp
- call dvmAllocPrimitiveArray # call: (char type, size_t length, int allocFlags)
- # return: ArrayObject*
- lea 16(%esp), %esp
- cmp $0, %eax # check for null return
- je common_exceptionThrown # handle exception
-
- FETCH 2, %edx # %edx<- FEDC or CCCC
- movl rGLUE, %ecx # %ecx<- MterpGlue pointer
- movl %eax, offGlue_retval(%ecx) # retval<- new array
- lea offArrayObject_contents(%eax), %eax # %eax<- newArray->contents
- subl $1, -12(%esp) # length--; check for negative
- js 2f # if length was zero, finish
-
- /*
- * copy values from registers into the array
- * %eax=array, %edx=CCCC/FEDC, -12(%esp)=length (from AA or B), rINST=AA/BA
- */
-
- .if 0
- lea (rFP, %edx, 4), %ecx # %ecx<- &fpp[CCCC]
-1:
- movl (%ecx), %edx # %edx<- %ecx++
- lea 4(%ecx), %ecx # %ecx++
- movl %edx, (%eax) # *contents<- vX
- lea 4(%eax), %eax # %eax++; contents++
- subl $1, -12(%esp) # length--
- jns 1b # or continue at 2
- .else
- cmp $4, -12(%esp) # check length
- jne 1f # has four args
- and $15, rINST # rINST<- A
- GET_VREG rINST # rINST<- vA
- subl $1, -12(%esp) # count--
- movl rINST, 16(%eax) # contents[4]<- vA
-1:
- movl %edx, %ecx # %ecx<- %edx; ecx for temp
- andl $15, %ecx # %ecx<- G/F/E/D
- GET_VREG %ecx # %ecx<- vG/vF/vE/vD
- shr $4, %edx # %edx<- put next reg in low 4
- subl $1, -12(%esp) # count--
- movl %ecx, (%eax) # *contents<- vX
- lea 4(%eax), %eax # %eax++; contents++
- jns 1b # or continue at 2
- .endif
-2:
- cmpb $'I', sReg0 # check for int array
- je 3f
- movl rGLUE, %ecx # %ecx<- MterpGlue pointer
- movl offGlue_retval(%ecx), %eax # Object head
- movl offGlue_cardTable(%ecx), %ecx # card table base
- shrl $GC_CARD_SHIFT, %eax # convert to card num
- movb %cl,(%ecx, %eax) # mark card based on object head
-3:
- FINISH 3 # jump to next instruction
-
- /*
- * Throw an exception to indicate this mode of filled-new-array
- * has not been implemented.
- */
-
-.LOP_FILLED_NEW_ARRAY_notimpl:
- movl $.LstrInternalError, -8(%esp)
- movl $.LstrFilledNewArrayNotImpl, -4(%esp)
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor,
- # const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown
-
-.if (!0) # define in one or the other, not both
-.LstrFilledNewArrayNotImpl:
-.asciz "filled-new-array only implemented for 'int'"
-.LstrInternalError:
-.asciz "Ljava/lang/InternalError;"
-.endif
-
-/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
-
-.LOP_FILLED_NEW_ARRAY_RANGE_break:
- movl $0, -8(%esp) # push parameter false
- movl %ecx, -12(%esp) # push parameter BBBB
- movl rGLUE, %edx # %edx<- MterpGlue pointer
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, -16(%esp) # push parameter glue->method->clazz
- lea -16(%esp), %esp
- call dvmResolveClass # call: (const ClassObject* referrer, u4 classIdx,
- # bool fromUnverifiedConstant)
- # return: ClassObject*
- lea 16(%esp), %esp
- cmp $0, %eax # check for null return
- je common_exceptionThrown # handle exception
-
- /*
- * On entry:
- * %eax holds array class
- * rINST holds BA or AA
- */
-
-.LOP_FILLED_NEW_ARRAY_RANGE_continue:
- movl offClassObject_descriptor(%eax), %eax # %eax<- arrayClass->descriptor
- movzbl 1(%eax), %eax # %eax<- descriptor[1]
- cmpb $'I', %al # check if array of ints
- je 1f
- cmpb $'L', %al
- je 1f
- cmpb $'[', %al
- jne .LOP_FILLED_NEW_ARRAY_RANGE_notimpl # jump to not implemented
-1:
- movl %eax, sReg0 # save type
- movl rINST, -12(%esp) # push parameter length
- movl %eax, -16(%esp) # push parameter descriptor[1]
- movl $ALLOC_DONT_TRACK, -8(%esp) # push parameter to allocate flags
- .if (!1)
- shrl $4, -12(%esp) # parameter length is B
- .endif
- lea -16(%esp), %esp
- call dvmAllocPrimitiveArray # call: (char type, size_t length, int allocFlags)
- # return: ArrayObject*
- lea 16(%esp), %esp
- cmp $0, %eax # check for null return
- je common_exceptionThrown # handle exception
-
- FETCH 2, %edx # %edx<- FEDC or CCCC
- movl rGLUE, %ecx # %ecx<- MterpGlue pointer
- movl %eax, offGlue_retval(%ecx) # retval<- new array
- lea offArrayObject_contents(%eax), %eax # %eax<- newArray->contents
- subl $1, -12(%esp) # length--; check for negative
- js 2f # if length was zero, finish
-
- /*
- * copy values from registers into the array
- * %eax=array, %edx=CCCC/FEDC, -12(%esp)=length (from AA or B), rINST=AA/BA
- */
-
- .if 1
- lea (rFP, %edx, 4), %ecx # %ecx<- &fpp[CCCC]
-1:
- movl (%ecx), %edx # %edx<- %ecx++
- lea 4(%ecx), %ecx # %ecx++
- movl %edx, (%eax) # *contents<- vX
- lea 4(%eax), %eax # %eax++; contents++
- subl $1, -12(%esp) # length--
- jns 1b # or continue at 2
- .else
- cmp $4, -12(%esp) # check length
- jne 1f # has four args
- and $15, rINST # rINST<- A
- GET_VREG rINST # rINST<- vA
- subl $1, -12(%esp) # count--
- movl rINST, 16(%eax) # contents[4]<- vA
-1:
- movl %edx, %ecx # %ecx<- %edx; ecx for temp
- andl $15, %ecx # %ecx<- G/F/E/D
- GET_VREG %ecx # %ecx<- vG/vF/vE/vD
- shr $4, %edx # %edx<- put next reg in low 4
- subl $1, -12(%esp) # count--
- movl %ecx, (%eax) # *contents<- vX
- lea 4(%eax), %eax # %eax++; contents++
- jns 1b # or continue at 2
- .endif
-2:
- cmpb $'I', sReg0 # check for int array
- je 3f
- movl rGLUE, %ecx # %ecx<- MterpGlue pointer
- movl offGlue_retval(%ecx), %eax # Object head
- movl offGlue_cardTable(%ecx), %ecx # card table base
- shrl $GC_CARD_SHIFT, %eax # convert to card num
- movb %cl,(%ecx, %eax) # mark card based on object head
-3:
- FINISH 3 # jump to next instruction
-
- /*
- * Throw an exception to indicate this mode of filled-new-array
- * has not been implemented.
- */
-
-.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
- movl $.LstrInternalError, -8(%esp)
- movl $.LstrFilledNewArrayNotImpl, -4(%esp)
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor,
- # const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown
-
-.if (!1) # define in one or the other, not both
-.LstrFilledNewArrayNotImpl:
-.asciz "filled-new-array only implemented for 'int'"
-.LstrInternalError:
-.asciz "Ljava/lang/InternalError;"
-.endif
-
-/* continuation for OP_PACKED_SWITCH */
-.LOP_PACKED_SWITCH_finish:
- FINISH_RB %edx, %ecx # jump to next instruction
-
-/* continuation for OP_SPARSE_SWITCH */
-.LOP_SPARSE_SWITCH_finish:
- FINISH_RB %edx, %ecx # jump to next instruction
-
-/* continuation for OP_CMPL_FLOAT */
-.LOP_CMPL_FLOAT_greater:
- movl $0x1, (rFP, rINST, 4) # vAA<- greater than
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-.LOP_CMPL_FLOAT_final:
- movl $0x0, (rFP, rINST, 4) # vAA<- equal
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-.LOP_CMPL_FLOAT_finalNan:
- movl $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- NaN
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_CMPG_FLOAT */
-.LOP_CMPG_FLOAT_greater:
- movl $0x1, (rFP, rINST, 4) # vAA<- greater than
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-.LOP_CMPG_FLOAT_final:
- movl $0x0, (rFP, rINST, 4) # vAA<- equal
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-.LOP_CMPG_FLOAT_finalNan:
- movl $0x1, (rFP, rINST, 4) # vAA<- NaN
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_CMPL_DOUBLE */
-.LOP_CMPL_DOUBLE_greater:
- movl $0x1, (rFP, rINST, 4) # vAA<- greater than
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-.LOP_CMPL_DOUBLE_final:
- movl $0x0, (rFP, rINST, 4) # vAA<- equal
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-.LOP_CMPL_DOUBLE_finalNan:
- movl $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- NaN
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_CMPG_DOUBLE */
-.LOP_CMPG_DOUBLE_greater:
- movl $0x1, (rFP, rINST, 4) # vAA<- greater than
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-.LOP_CMPG_DOUBLE_final:
- movl $0x0, (rFP, rINST, 4) # vAA<- equal
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-.LOP_CMPG_DOUBLE_finalNan:
- movl $0x1, (rFP, rINST, 4) # vAA<- NaN
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_CMP_LONG */
-
-.LOP_CMP_LONG_final:
- movl $0x0, (rFP, rINST, 4) # vAA<- equal
- FINISH 2 # jump to next instruction
-
-.LOP_CMP_LONG_less:
- movl $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
- FINISH 2 # jump to next instruction
-
-.LOP_CMP_LONG_greater:
- movl $0x1, (rFP, rINST, 4) # vAA<- greater than
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_APUT_OBJECT */
-
-.LOP_APUT_OBJECT_finish:
- movl %edx, sReg0 # save &vBB[vCC]
- movl %eax, sReg1 # save object head
- movl offObject_clazz(rINST), %edx # %edx<- obj->clazz
- movl %edx, -8(%esp) # push parameter obj->clazz
- movl offObject_clazz(%eax), %eax # %eax<- arrayObj->clazz
- movl %eax, -4(%esp) # push parameter arrayObj->clazz
- lea -8(%esp), %esp
- call dvmCanPutArrayElement # test object type vs. array type
- # call: ClassObject* elemClass, ClassObject* arrayClass)
- # return: bool
- lea 8(%esp), %esp
- testl %eax, %eax # check for invalid array value
- je common_errArrayStore # handle invalid array value
- movl sReg0, %edx # restore &vBB[vCC]
- movl rINST, offArrayObject_contents(%edx)
- movl rGLUE, %eax
- FFETCH_ADV 2, %ecx # %ecx<- next instruction hi; fetch, advance
- movl offGlue_cardTable(%eax), %eax # get card table base
- movl sReg1, %edx # restore object head
- shrl $GC_CARD_SHIFT, %edx # object head to card number
- movb %al, (%eax, %edx) # mark card using object head
- FGETOP_JMP 2, %ecx # jump to next instruction; getop, jmp
-.LOP_APUT_OBJECT_skip_check:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl rINST, offArrayObject_contents(%edx)
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IGET */
-
-.LOP_IGET_finish:
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- cmp $0, %eax # check if resolved
- lea 8(%esp), %esp
- je common_exceptionThrown # not resolved; handle exception
-
- /*
- * %eax holds resolved field
- */
-
-.LOP_IGET_finish2:
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
-
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl (%ecx, %edx), %edx # %edx<- object field
- SET_VREG %edx, rINST # vA<- %edx; object field
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IGET_WIDE */
-
-.LOP_IGET_WIDE_finish2:
- lea -8(%esp), %esp
- call dvmResolveInstField # resolve InstField ptr
- # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- cmp $0, %eax # check if resolved
- lea 8(%esp), %esp
- movl %eax, %ecx # %ecx<- %eax; %ecx expected to hold field
- je common_exceptionThrown
-
- /*
- * %ecx holds resolved field
- */
-
-.LOP_IGET_WIDE_finish:
-
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- GET_VREG %edx # %edx<- vB
- cmp $0, %edx # check for null object
- je common_errNullObject
- movl offInstField_byteOffset(%ecx), %ecx # %ecx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (%ecx, %edx), %xmm0 # %xmm0<- object field
- movq %xmm0, (rFP, rINST, 4) # vA<- %xmm0; object field
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IGET_OBJECT */
-
-.LOP_IGET_OBJECT_finish:
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- cmp $0, %eax # check if resolved
- lea 8(%esp), %esp
- je common_exceptionThrown # not resolved; handle exception
-
- /*
- * %eax holds resolved field
- */
-
-.LOP_IGET_OBJECT_finish2:
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
-
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl (%ecx, %edx), %edx # %edx<- object field
- SET_VREG %edx, rINST # vA<- %edx; object field
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IGET_BOOLEAN */
-
-.LOP_IGET_BOOLEAN_finish:
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- cmp $0, %eax # check if resolved
- lea 8(%esp), %esp
- je common_exceptionThrown # not resolved; handle exception
-
- /*
- * %eax holds resolved field
- */
-
-.LOP_IGET_BOOLEAN_finish2:
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
-
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl (%ecx, %edx), %edx # %edx<- object field
- SET_VREG %edx, rINST # vA<- %edx; object field
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IGET_BYTE */
-
-.LOP_IGET_BYTE_finish:
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- cmp $0, %eax # check if resolved
- lea 8(%esp), %esp
- je common_exceptionThrown # not resolved; handle exception
-
- /*
- * %eax holds resolved field
- */
-
-.LOP_IGET_BYTE_finish2:
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
-
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl (%ecx, %edx), %edx # %edx<- object field
- SET_VREG %edx, rINST # vA<- %edx; object field
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IGET_CHAR */
-
-.LOP_IGET_CHAR_finish:
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- cmp $0, %eax # check if resolved
- lea 8(%esp), %esp
- je common_exceptionThrown # not resolved; handle exception
-
- /*
- * %eax holds resolved field
- */
-
-.LOP_IGET_CHAR_finish2:
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
-
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl (%ecx, %edx), %edx # %edx<- object field
- SET_VREG %edx, rINST # vA<- %edx; object field
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IGET_SHORT */
-
-.LOP_IGET_SHORT_finish:
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- cmp $0, %eax # check if resolved
- lea 8(%esp), %esp
- je common_exceptionThrown # not resolved; handle exception
-
- /*
- * %eax holds resolved field
- */
-
-.LOP_IGET_SHORT_finish2:
- movl rINST, %ecx # %ecx<- BA
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
-
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl (%ecx, %edx), %edx # %edx<- object field
- SET_VREG %edx, rINST # vA<- %edx; object field
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IPUT */
-
-.LOP_IPUT_finish:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- lea -8(%esp), %esp
- movl %edx, (%esp) # push parameter method->clazz
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- lea 8(%esp), %esp
- cmp $0, %eax # check if resolved
- jne .LOP_IPUT_finish2
- jmp common_exceptionThrown # not resolved; handle exception
-
-.LOP_IPUT_finish2:
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vA
- movl rINST, (%edx, %ecx) # object field<- vA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IPUT_WIDE */
-
-.LOP_IPUT_WIDE_finish2:
- lea -8(%esp), %esp
- call dvmResolveInstField # resolve InstField ptr
- cmp $0, %eax # check if resolved
- lea 8(%esp), %esp
- movl %eax, %ecx # %ecx<- %eax; %ecx expected to hold field
- jne .LOP_IPUT_WIDE_finish
- jmp common_exceptionThrown
-
- /*
- * Currently:
- * %ecx holds resolved field
- * %edx does not hold object yet
- */
-
-.LOP_IPUT_WIDE_finish:
- movl rINST, %edx # %edx<- BA
- shr $4, %edx # %edx<- B
- andl $15, rINST # rINST<- A
- GET_VREG %edx # %edx<- vB
- cmp $0, %edx # check for null object
- je common_errNullObject
- movl offInstField_byteOffset(%ecx), %ecx # %ecx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vA
- movq %xmm0, (%ecx, %edx) # object field<- %xmm0; vA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IPUT_OBJECT */
-
-.LOP_IPUT_OBJECT_finish:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- lea -8(%esp), %esp
- movl %edx, (%esp) # push parameter method->clazz
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- lea 8(%esp), %esp
- cmp $0, %eax # check if resolved
- jne .LOP_IPUT_OBJECT_finish2
- jmp common_exceptionThrown # not resolved; handle exception
-
-.LOP_IPUT_OBJECT_finish2:
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- GET_VREG rINST # rINST<- vA
- movl rINST, (%edx, %ecx) # object field<- vA
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- movl rGLUE, %eax # get glue
- movl offGlue_cardTable(%eax), %eax # get card table base
- testl rINST, rINST # test if we stored a null value
- je 1f # skip card mark if null stored
- shrl $GC_CARD_SHIFT, %ecx # set obeject head to card number
- movb %al, (%eax, %ecx)
-1:
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* continuation for OP_IPUT_BOOLEAN */
-
-.LOP_IPUT_BOOLEAN_finish:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- lea -8(%esp), %esp
- movl %edx, (%esp) # push parameter method->clazz
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- lea 8(%esp), %esp
- cmp $0, %eax # check if resolved
- jne .LOP_IPUT_BOOLEAN_finish2
- jmp common_exceptionThrown # not resolved; handle exception
-
-.LOP_IPUT_BOOLEAN_finish2:
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vA
- movl rINST, (%edx, %ecx) # object field<- vA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IPUT_BYTE */
-
-.LOP_IPUT_BYTE_finish:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- lea -8(%esp), %esp
- movl %edx, (%esp) # push parameter method->clazz
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- lea 8(%esp), %esp
- cmp $0, %eax # check if resolved
- jne .LOP_IPUT_BYTE_finish2
- jmp common_exceptionThrown # not resolved; handle exception
-
-.LOP_IPUT_BYTE_finish2:
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vA
- movl rINST, (%edx, %ecx) # object field<- vA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IPUT_CHAR */
-
-.LOP_IPUT_CHAR_finish:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- lea -8(%esp), %esp
- movl %edx, (%esp) # push parameter method->clazz
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- lea 8(%esp), %esp
- cmp $0, %eax # check if resolved
- jne .LOP_IPUT_CHAR_finish2
- jmp common_exceptionThrown # not resolved; handle exception
-
-.LOP_IPUT_CHAR_finish2:
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vA
- movl rINST, (%edx, %ecx) # object field<- vA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_IPUT_SHORT */
-
-.LOP_IPUT_SHORT_finish:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- lea -8(%esp), %esp
- movl %edx, (%esp) # push parameter method->clazz
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- lea 8(%esp), %esp
- cmp $0, %eax # check if resolved
- jne .LOP_IPUT_SHORT_finish2
- jmp common_exceptionThrown # not resolved; handle exception
-
-.LOP_IPUT_SHORT_finish2:
- movl rINST, %ecx # %ecx<- BA+
- shr $4, %ecx # %ecx<- B
- and $15, rINST # rINST<- A
- GET_VREG %ecx # %ecx<- vB
- cmp $0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vA
- movl rINST, (%edx, %ecx) # object field<- vA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_SGET */
-
-.LOP_SGET_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- mov %eax, %ecx # %ecx<- result
-
-.LOP_SGET_finish:
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- movl offStaticField_value(%ecx), %eax # %eax<- field value
- SET_VREG %eax, rINST # vAA<- field value
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* continuation for OP_SGET_WIDE */
-
- /*
- * Continuation if the field has not yet been resolved.
- * %edx: BBBB field ref
- */
-
-.LOP_SGET_WIDE_resolve:
- movl offGlue_method(%eax), %eax # %eax <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %edx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%eax), %eax # %eax<- method->clazz
- movl %eax, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- lea 8(%esp), %esp
- cmp $0, %eax # check if initalization failed
- movl %eax, %ecx # %ecx<- result
- jne .LOP_SGET_WIDE_finish # success, continue
- jmp common_exceptionThrown # failed; handle exception
-
-/* continuation for OP_SGET_OBJECT */
-
-.LOP_SGET_OBJECT_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- mov %eax, %ecx # %ecx<- result
-
-.LOP_SGET_OBJECT_finish:
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- movl offStaticField_value(%ecx), %eax # %eax<- field value
- SET_VREG %eax, rINST # vAA<- field value
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* continuation for OP_SGET_BOOLEAN */
-
-.LOP_SGET_BOOLEAN_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- mov %eax, %ecx # %ecx<- result
-
-.LOP_SGET_BOOLEAN_finish:
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- movl offStaticField_value(%ecx), %eax # %eax<- field value
- SET_VREG %eax, rINST # vAA<- field value
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* continuation for OP_SGET_BYTE */
-
-.LOP_SGET_BYTE_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- mov %eax, %ecx # %ecx<- result
-
-.LOP_SGET_BYTE_finish:
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- movl offStaticField_value(%ecx), %eax # %eax<- field value
- SET_VREG %eax, rINST # vAA<- field value
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* continuation for OP_SGET_CHAR */
-
-.LOP_SGET_CHAR_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- mov %eax, %ecx # %ecx<- result
-
-.LOP_SGET_CHAR_finish:
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- movl offStaticField_value(%ecx), %eax # %eax<- field value
- SET_VREG %eax, rINST # vAA<- field value
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* continuation for OP_SGET_SHORT */
-
-.LOP_SGET_SHORT_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- mov %eax, %ecx # %ecx<- result
-
-.LOP_SGET_SHORT_finish:
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- movl offStaticField_value(%ecx), %eax # %eax<- field value
- SET_VREG %eax, rINST # vAA<- field value
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
-/* continuation for OP_SPUT */
-
-.LOP_SPUT_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- movl %eax, %ecx # %ecx<- result
-
-.LOP_SPUT_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vAA
- movl rINST, offStaticField_value(%ecx) # field value<- vAA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_SPUT_WIDE */
-
- /*
- * Continuation if the field has not yet been resolved.
- * %edx: BBBB field ref
- */
-
-.LOP_SPUT_WIDE_resolve:
- movl offGlue_method(%eax), %eax # %eax <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %edx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%eax), %eax # %eax<- method->clazz
- movl %eax, -8(%esp)
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- lea 8(%esp), %esp
- cmp $0, %eax # check if initalization failed
- movl %eax, %ecx # %ecx<- result
- jne .LOP_SPUT_WIDE_finish # success, continue
- jmp common_exceptionThrown # failed; handle exception
-
-/* continuation for OP_SPUT_OBJECT */
-
-.LOP_SPUT_OBJECT_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- movl %eax, %ecx # %ecx<- result
-
-.LOP_SPUT_OBJECT_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vAA
-
-
- movl rINST, offStaticField_value(%ecx) # field value<- vAA
- testl rINST, rINST # stored null object ptr?
- je 1f
- movl rGLUE, %edx # get glue
- movl offField_clazz(%ecx), %ecx # ecx<- field->clazz
- movl offGlue_cardTable(%edx), %edx # get card table base
- shrl $GC_CARD_SHIFT, %ecx # head to card number
- movb %dl, (%edx, %ecx) # mark card
-1:
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_SPUT_BOOLEAN */
-
-.LOP_SPUT_BOOLEAN_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- movl %eax, %ecx # %ecx<- result
-
-.LOP_SPUT_BOOLEAN_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vAA
- movl rINST, offStaticField_value(%ecx) # field value<- vAA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_SPUT_BYTE */
-
-.LOP_SPUT_BYTE_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- movl %eax, %ecx # %ecx<- result
-
-.LOP_SPUT_BYTE_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vAA
- movl rINST, offStaticField_value(%ecx) # field value<- vAA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_SPUT_CHAR */
-
-.LOP_SPUT_CHAR_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- movl %eax, %ecx # %ecx<- result
-
-.LOP_SPUT_CHAR_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vAA
- movl rINST, offStaticField_value(%ecx) # field value<- vAA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_SPUT_SHORT */
-
-.LOP_SPUT_SHORT_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- movl %eax, %ecx # %ecx<- result
-
-.LOP_SPUT_SHORT_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vAA
- movl rINST, offStaticField_value(%ecx) # field value<- vAA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-/* continuation for OP_INVOKE_VIRTUAL */
-
-.LOP_INVOKE_VIRTUAL_break:
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl %edx, -4(%esp) # save "this" pointer register
- movl offGlue_method(%eax), %eax # %eax<- glue->method
- movl $METHOD_VIRTUAL, -8(%esp) # push parameter method type
- movl %ecx, -12(%esp) # push paramter method index
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- lea -16(%esp), %esp
- movl %eax, (%esp) # push parameter clazz
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 16(%esp), %esp
- cmp $0, %eax # check for null method return
- movl -4(%esp), %edx # get "this" pointer register
- jne .LOP_INVOKE_VIRTUAL_continue
- jmp common_exceptionThrown # null pointer; handle exception
-
- /*
- * At this point:
- * %eax = resolved base method
- * %edx = D or CCCC (index of first arg, which is the "this" ptr)
- */
-
-.LOP_INVOKE_VIRTUAL_continue:
- GET_VREG %edx # %edx<- "this" ptr
- movzwl offMethod_methodIndex(%eax), %eax # %eax<- baseMethod->methodIndex
- cmp $0, %edx # %edx<- check for null "this"
- je common_errNullObject # handle null object
- movl offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
- movl offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
- movl (%edx, %eax, 4), %ecx # %ecx<- vtable[methodIndex]
- jmp common_invokeMethodNoRange # invoke method common code
-
-/* continuation for OP_INVOKE_SUPER */
-
-.LOP_INVOKE_SUPER_continue2:
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_method(%eax), %eax # %eax<- glue->method
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- EXPORT_PC # must export for invoke
- cmp $0, %ecx # check if already resolved
- jne .LOP_INVOKE_SUPER_continue
- jmp .LOP_INVOKE_SUPER_resolve # handle resolve
-
- /*
- * %ecx = resolved base method
- * %eax = method->clazz
- */
-
-.LOP_INVOKE_SUPER_continue:
- movl offClassObject_super(%eax), %edx # %edx<- glue->method->clazz->super
- movzwl offMethod_methodIndex(%ecx), %ecx # %ecx<- baseMethod->methodIndex
- cmp offClassObject_vtableCount(%edx), %ecx # compare vtableCount with methodIndex
- EXPORT_PC # must export for invoke
- jnc .LOP_INVOKE_SUPER_nsm # handle method not present
- movl offClassObject_vtable(%edx), %edx # %edx<- glue->method->clazz->super->vtable
- movl (%edx, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
- jmp common_invokeMethodNoRange # invoke method common code
-
-.LOP_INVOKE_SUPER_resolve:
- movl %eax, -12(%esp) # push parameter clazz
- movl %edx, -8(%esp) # push parameter method index
- movl $METHOD_VIRTUAL, -4(%esp) # push parameter method type
- lea -12(%esp), %esp
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 12(%esp), %esp
- movl %eax, %ecx # %ecx<- method
- cmp $0, %ecx # check for null method return
- movl -12(%esp), %eax # %eax<- glue->method->clazz
- jne .LOP_INVOKE_SUPER_continue
- jmp common_exceptionThrown # null pointer; handle exception
-
- /*
- * Throw a NoSuchMethodError with the method name as the message.
- * %ecx = resolved base method
- */
-
-.LOP_INVOKE_SUPER_nsm:
- movl offMethod_name(%ecx), %edx # %edx<- method name
- jmp common_errNoSuchMethod
-
-/* continuation for OP_INVOKE_DIRECT */
-
- /*
- * %eax = reference (BBBB or CCCC)
- * -4(%esp) = "this" register
- */
-
-.LOP_INVOKE_DIRECT_resolve:
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl $METHOD_DIRECT, -8(%esp) # push parameter method type
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl %eax, -12(%esp) # push parameter reference
- lea -16(%esp), %esp
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, (%esp) # push parameter clazz
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 16(%esp), %esp
- cmp $0, %eax # check for null method return
- movl -4(%esp), %edx # get "this" pointer register
- GET_VREG %edx # get "this" pointer
- je common_exceptionThrown # null pointer; handle exception
- cmp $0, %edx # check for null "this"
- movl %eax, %ecx # %ecx<- method
- jne common_invokeMethodNoRange # invoke method common code
- jmp common_errNullObject # handle null object
-
-/* continuation for OP_INVOKE_STATIC */
-
-.LOP_INVOKE_STATIC_break:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl $METHOD_STATIC, -4(%esp) # resolver method type
- movl %eax, -8(%esp) # push parameter method index
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, -12(%esp) # push parameter method
- lea -12(%esp), %esp
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 12(%esp), %esp
- cmp $0, %eax # check for null method
- je common_exceptionThrown
- movl %eax, %ecx # %ecx<- method
- jmp common_invokeMethodNoRange # invoke method common code
-
-/* continuation for OP_INVOKE_INTERFACE */
-.LOP_INVOKE_INTERFACE_break:
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_method(%ecx), %ecx # %ecx<- glue->method
- movl %ecx, -8(%esp) # push parameter method
- movl offObject_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, -16(%esp) # push parameter
- lea -16(%esp), %esp
- call dvmFindInterfaceMethodInCache # call: (ClassObject* thisClass, u4 methodIdx,
- # const Method* method, DvmDex* methodClassDex)
- # return: Method*
- lea 16(%esp), %esp
- cmp $0, %eax # check if find failed
- je common_exceptionThrown # handle exception
- movl %eax, %ecx # %ecx<- method
- jmp common_invokeMethodNoRange # invoke method common code
-
-/* continuation for OP_INVOKE_VIRTUAL_RANGE */
-
-.LOP_INVOKE_VIRTUAL_RANGE_break:
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl %edx, -4(%esp) # save "this" pointer register
- movl offGlue_method(%eax), %eax # %eax<- glue->method
- movl $METHOD_VIRTUAL, -8(%esp) # push parameter method type
- movl %ecx, -12(%esp) # push paramter method index
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- lea -16(%esp), %esp
- movl %eax, (%esp) # push parameter clazz
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 16(%esp), %esp
- cmp $0, %eax # check for null method return
- movl -4(%esp), %edx # get "this" pointer register
- jne .LOP_INVOKE_VIRTUAL_RANGE_continue
- jmp common_exceptionThrown # null pointer; handle exception
-
- /*
- * At this point:
- * %eax = resolved base method
- * %edx = D or CCCC (index of first arg, which is the "this" ptr)
- */
-
-.LOP_INVOKE_VIRTUAL_RANGE_continue:
- GET_VREG %edx # %edx<- "this" ptr
- movzwl offMethod_methodIndex(%eax), %eax # %eax<- baseMethod->methodIndex
- cmp $0, %edx # %edx<- check for null "this"
- je common_errNullObject # handle null object
- movl offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
- movl offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
- movl (%edx, %eax, 4), %ecx # %ecx<- vtable[methodIndex]
- jmp common_invokeMethodRange # invoke method common code
-
-/* continuation for OP_INVOKE_SUPER_RANGE */
-
-.LOP_INVOKE_SUPER_RANGE_continue2:
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_method(%eax), %eax # %eax<- glue->method
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- EXPORT_PC # must export for invoke
- cmp $0, %ecx # check if already resolved
- jne .LOP_INVOKE_SUPER_RANGE_continue
- jmp .LOP_INVOKE_SUPER_RANGE_resolve # handle resolve
-
- /*
- * %ecx = resolved base method
- * %eax = method->clazz
- */
-
-.LOP_INVOKE_SUPER_RANGE_continue:
- movl offClassObject_super(%eax), %edx # %edx<- glue->method->clazz->super
- movzwl offMethod_methodIndex(%ecx), %ecx # %ecx<- baseMethod->methodIndex
- cmp offClassObject_vtableCount(%edx), %ecx # compare vtableCount with methodIndex
- EXPORT_PC # must export for invoke
- jnc .LOP_INVOKE_SUPER_RANGE_nsm # handle method not present
- movl offClassObject_vtable(%edx), %edx # %edx<- glue->method->clazz->super->vtable
- movl (%edx, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
- jmp common_invokeMethodRange # invoke method common code
-
-.LOP_INVOKE_SUPER_RANGE_resolve:
- movl %eax, -12(%esp) # push parameter clazz
- movl %edx, -8(%esp) # push parameter method index
- movl $METHOD_VIRTUAL, -4(%esp) # push parameter method type
- lea -12(%esp), %esp
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 12(%esp), %esp
- movl %eax, %ecx # %ecx<- method
- cmp $0, %ecx # check for null method return
- movl -12(%esp), %eax # %eax<- glue->method->clazz
- jne .LOP_INVOKE_SUPER_RANGE_continue
- jmp common_exceptionThrown # null pointer; handle exception
-
- /*
- * Throw a NoSuchMethodError with the method name as the message.
- * %ecx = resolved base method
- */
-
-.LOP_INVOKE_SUPER_RANGE_nsm:
- movl offMethod_name(%ecx), %edx # %edx<- method name
- jmp common_errNoSuchMethod
-
-/* continuation for OP_INVOKE_DIRECT_RANGE */
-
- /*
- * %eax = reference (BBBB or CCCC)
- * -4(%esp) = "this" register
- */
-
-.LOP_INVOKE_DIRECT_RANGE_resolve:
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl $METHOD_DIRECT, -8(%esp) # push parameter method type
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl %eax, -12(%esp) # push parameter reference
- lea -16(%esp), %esp
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, (%esp) # push parameter clazz
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 16(%esp), %esp
- cmp $0, %eax # check for null method return
- movl -4(%esp), %edx # get "this" pointer register
- GET_VREG %edx # get "this" pointer
- je common_exceptionThrown # null pointer; handle exception
- cmp $0, %edx # check for null "this"
- movl %eax, %ecx # %ecx<- method
- jne common_invokeMethodRange # invoke method common code
- jmp common_errNullObject # handle null object
-
-/* continuation for OP_INVOKE_STATIC_RANGE */
-
-.LOP_INVOKE_STATIC_RANGE_break:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl $METHOD_STATIC, -4(%esp) # resolver method type
- movl %eax, -8(%esp) # push parameter method index
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, -12(%esp) # push parameter method
- lea -12(%esp), %esp
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 12(%esp), %esp
- cmp $0, %eax # check for null method
- je common_exceptionThrown
- movl %eax, %ecx # %ecx<- method
- jmp common_invokeMethodRange # invoke method common code
-
-/* continuation for OP_INVOKE_INTERFACE_RANGE */
-.LOP_INVOKE_INTERFACE_RANGE_break:
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_method(%ecx), %ecx # %ecx<- glue->method
- movl %ecx, -8(%esp) # push parameter method
- movl offObject_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, -16(%esp) # push parameter
- lea -16(%esp), %esp
- call dvmFindInterfaceMethodInCache # call: (ClassObject* thisClass, u4 methodIdx,
- # const Method* method, DvmDex* methodClassDex)
- # return: Method*
- lea 16(%esp), %esp
- cmp $0, %eax # check if find failed
- je common_exceptionThrown # handle exception
- movl %eax, %ecx # %ecx<- method
- jmp common_invokeMethodRange # invoke method common code
-
-/* continuation for OP_FLOAT_TO_INT */
-
-.LOP_FLOAT_TO_INT_break:
- fnstcw -2(%esp) # save control word
- orl $0xc00, -2(%esp) # reset control
- fldcw -2(%esp) # load control word
- xorl $0xc00, -2(%esp) # reset control
- fistpl (rFP, %edx, 4) # move converted int
- fldcw -2(%esp) # load saved control word
- FINISH 1 # jump to next instruction
-
-.LOP_FLOAT_TO_INT_nanInf:
- jnp .LOP_FLOAT_TO_INT_posInf # handle posInf
- fstps (rFP, %edx, 4) # pop floating point stack
- movl $0x00000000, (rFP, %edx, 4) # vA<- NaN
- FINISH 1 # jump to next instruction
-
-.LOP_FLOAT_TO_INT_posInf:
- fstps (rFP, %edx, 4) # pop floating point stack
- movl $0x7FFFFFFF, (rFP, %edx, 4) # vA<- posInf
- FINISH 1 # jump to next instruction
-
-.LOP_FLOAT_TO_INT_negInf:
- fstps (rFP, %edx, 4) # pop floating point stack
- fstps (rFP, %edx, 4) # pop floating point stack
- movl $0x80000000, (rFP, %edx, 4) # vA<- negInf
- FINISH 1 # jump to next instruction
-
-/* continuation for OP_FLOAT_TO_LONG */
-
-.LOP_FLOAT_TO_LONG_break:
- fnstcw -2(%esp) # save control word
- orl $0xc00, -2(%esp) # update control
- fldcw -2(%esp) # load control word
- xorl $0xc00, -2(%esp) # reset control
- fistpll (rFP, %edx, 4) # move converted int
- fldcw -2(%esp) # load saved control word
- FINISH 1 # jump to next instruction
-
-.LOP_FLOAT_TO_LONG_nanInf:
- jnp .LOP_FLOAT_TO_LONG_posInf
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvalueNanLong, %xmm0 # %xmm0<- NaN
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; NaN
- FINISH 1 # jump to next instruction
-
-.LOP_FLOAT_TO_LONG_posInf:
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvaluePosInfLong, %xmm0 # %xmm0<- posInf
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; posInf
- FINISH 1 # jump to next instruction
-
-.LOP_FLOAT_TO_LONG_negInf:
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvalueNegInfLong, %xmm0 # %xmm0<- negInf
- fstpl (rFP, %edx, 4) # move converted int
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; negInf
- FINISH 1 # jump to next instruction
-
-/* continuation for OP_DOUBLE_TO_INT */
-
-.LOP_DOUBLE_TO_INT_break:
- fnstcw -2(%esp) # save control word
- orl $0xc00, -2(%esp) # reset control
- fldcw -2(%esp) # load control word
- xorl $0xc00, -2(%esp) # reset control
- fistpl (rFP, %edx, 4) # move converted int
- fldcw -2(%esp) # load saved control word
- FINISH 1 # jump to next instruction
-
-.LOP_DOUBLE_TO_INT_nanInf:
- jnp .LOP_DOUBLE_TO_INT_posInf
- fstps (rFP, %edx, 4)
- movl $0x00000000, (rFP, %edx, 4) # vA<- NaN
- FINISH 1 # jump to next instruction
-
-.LOP_DOUBLE_TO_INT_posInf:
- fstps (rFP, %edx, 4)
- movl $0x7FFFFFFF, (rFP, %edx, 4) # vA<- posInf
- FINISH 1 # jump to next instruction
-
-.LOP_DOUBLE_TO_INT_negInf:
- fstps (rFP, %edx, 4)
- fstps (rFP, %edx, 4)
- movl $0x80000000, (rFP, %edx, 4) # vA<- negInf
- FINISH 1 # jump to next instruction
-
-/* continuation for OP_DOUBLE_TO_LONG */
-
-.LOP_DOUBLE_TO_LONG_break:
- fnstcw -2(%esp) # save control word
- orl $0xc00, -2(%esp) # reset control
- fldcw -2(%esp) # load control word
- xorl $0xc00, -2(%esp) # reset control
- fistpll (rFP, %edx, 4) # move converted int
- fldcw -2(%esp) # load saved control word
- FINISH 1 # jump to next instruction
-
-.LOP_DOUBLE_TO_LONG_nanInf:
- jnp .LOP_DOUBLE_TO_LONG_posInf
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvalueNanLong, %xmm0 # %xmm0<- NaN
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; NaN
- FINISH 1 # jump to next instruction
-
-.LOP_DOUBLE_TO_LONG_posInf:
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvaluePosInfLong, %xmm0 # %xmm0<- posInf
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; posInf
- FINISH 1 # jump to next instruction
-
-.LOP_DOUBLE_TO_LONG_negInf:
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvalueNegInfLong, %xmm0 # %xmm0<- negInf
- fstpl (rFP, %edx, 4) # move converted int
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; negInf
- FINISH 1 # jump to next instruction
-
-/* continuation for OP_DIV_INT */
-.LOP_DIV_INT_break:
- .if 1
- movl $0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $0, (rFP, rINST, 4) # vAA<- 0
- .endif
-.LOP_DIV_INT_break2:
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_REM_INT */
-.LOP_REM_INT_break:
- .if 0
- movl $0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $0, (rFP, rINST, 4) # vAA<- 0
- .endif
-.LOP_REM_INT_break2:
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_MUL_LONG */
-
- /*
- * X = (rFP, rINST, 4)
- * W = 4(rFP, rINST, 4)
- * Z = (rFP, %edx, 4)
- * Y = 4(rFP, %edx, 4)
- */
-
-.LOP_MUL_LONG_finish:
- movl 4(rFP, rINST, 4), %ecx # %ecx<- W
- imull (rFP, %edx, 4), %ecx # %ecx<- WxZ
- mov 4(rFP, %edx, 4), %eax # %ecx<- Y
- imull (rFP, rINST, 4), %eax # %eax<- XxY
- addl %eax, %ecx # %ecx<- (WZ + XY)
- movl (rFP, %edx, 4), %eax # %eax<- Z
- mull (rFP, rINST, 4) # %edx:eax<- XZ
- movzbl -4(%esp), rINST # rINST<- AA
- addl %edx, %ecx # %ecx<- carry + (WZ + XY)
- movl %ecx, 4(rFP, rINST, 4) # vAA+1<- results hi
- movl %eax, (rFP, rINST, 4) # vAA<- results lo
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_DIV_LONG */
-.LOP_DIV_LONG_finish:
- movq %xmm0, -16(%esp) # push arg vBB,vBB+1
- lea -16(%esp), %esp
- call __divdi3 # call func
- lea 16(%esp), %esp
- movl %eax, (rFP, rINST, 4) # vAA<- return low
- movl %edx, 4(rFP, rINST, 4) # vAA+1<- return high
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_REM_LONG */
-.LOP_REM_LONG_finish:
- movq %xmm0, -16(%esp) # push arg vBB,vBB+1
- lea -16(%esp), %esp
- call __moddi3 # call func
- lea 16(%esp), %esp
- movl %eax, (rFP, rINST, 4) # vAA<- return low
- movl %edx, 4(rFP, rINST, 4) # vAA+1<- return high
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_SHR_LONG */
-
-.LOP_SHR_LONG_finish:
- movq .Lvalue64, %xmm3 # %xmm3<- 64
- psubq %xmm0, %xmm3 # %xmm3<- 64 - shift amount
- movq .L64bits, %xmm4 # %xmm4<- lower 64 bits set
- psllq %xmm3, %xmm4 # %xmm4<- correct mask for sign bits
- por %xmm4, %xmm1 # %xmm1<- signed and shifted vBB
-
-.LOP_SHR_LONG_final:
- movq %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_REM_DOUBLE */
-
-.LOP_REM_DOUBLE_break:
- call fmod # call: (long double x, long double y)
- # return: double
- lea 16(%esp), %esp
- fstpl (rFP, rINST, 4) # vAA<- remainder; return of fmod
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_DIV_INT_2ADDR */
-.LOP_DIV_INT_2ADDR_break:
- .if 1
- movl $0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $0, (rFP, rINST, 4) # vAA<- 0
- .endif
-.LOP_DIV_INT_2ADDR_break2:
- FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-
-/* continuation for OP_REM_INT_2ADDR */
-.LOP_REM_INT_2ADDR_break:
- .if 0
- movl $0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $0, (rFP, rINST, 4) # vAA<- 0
- .endif
-.LOP_REM_INT_2ADDR_break2:
- FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-
-/* continuation for OP_MUL_LONG_2ADDR */
-
- /*
- * X = (rFP, rINST, 4)
- * W = 4(rFP, rINST, 4)
- * Z = (rFP, %edx, 4)
- * Y = 4(rFP, %edx, 4)
- */
-
-.LOP_MUL_LONG_2ADDR_finish:
- movl 4(rFP, rINST, 4), %ecx # %ecx<- W
- imull (rFP, %edx, 4), %ecx # %ecx<- WxZ
- movl 4(rFP, %edx, 4), %eax # %eax<- Y
- imull (rFP, rINST, 4), %eax # %eax<- X*Y
- addl %eax, %ecx # %ecx<- (WZ + XY)
- movl (rFP, %edx, 4), %eax # %eax<- Z
- mull (rFP, rINST, 4) # %edx:eax<- XZ
- addl %edx, %ecx # %ecx<- carry + (WZ + XY)
- movl sReg0, %edx # %edx<- A
- movl %ecx, 4(rFP, %edx, 4) # vA+1<- results hi
- movl %eax, (rFP, %edx, 4) # vA<- results lo
- FINISH 1 # jump to next instruction
-
-/* continuation for OP_DIV_LONG_2ADDR */
-.LOP_DIV_LONG_2ADDR_break:
- movq %xmm0, -20(%esp) # push arg vA, vA+1
- lea -20(%esp), %esp
- call __divdi3 # call func
- lea 20(%esp), %esp
- movl %eax, (rFP, rINST, 4) # vA<- return low
- movl %edx, 4(rFP, rINST, 4) # vA<- return high
- FFETCH_ADV 1, %ecx # %ecx<- next instruction hi; fetch, advance
- FGETOP_JMP 1, %ecx # jump to next instruction; getop, jmp
-
-/* continuation for OP_REM_LONG_2ADDR */
-.LOP_REM_LONG_2ADDR_break:
- movq %xmm0, -20(%esp) # push arg vA, vA+1
- lea -20(%esp), %esp
- call __moddi3 # call func
- lea 20(%esp), %esp
- movl %eax, (rFP, rINST, 4) # vA<- return low
- movl %edx, 4(rFP, rINST, 4) # vA<- return high
- FFETCH_ADV 1, %ecx # %ecx<- next instruction hi; fetch, advance
- FGETOP_JMP 1, %ecx # jump to next instruction; getop, jmp
-
-/* continuation for OP_SHR_LONG_2ADDR */
-
-.LOP_SHR_LONG_2ADDR_finish:
- movq .Lvalue64, %xmm3 # %xmm3<- 64
- psubq %xmm0, %xmm3 # %xmm3<- 64 - shift amount
- movq .L64bits, %xmm4 # %xmm4<- lower 64 bits set
- psllq %xmm3, %xmm4 # %xmm4<- correct mask for sign bits
- por %xmm4, %xmm1 # %xmm1<- signed and shifted vBB
-
-.LOP_SHR_LONG_2ADDR_final:
- movq %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
- FINISH 1 # jump to next instruction
-
-/* continuation for OP_REM_DOUBLE_2ADDR */
-
-.LOP_REM_DOUBLE_2ADDR_break:
- call fmod # call: (long double x, long double y)
- # return: double
- lea 20(%esp), %esp
- fstpl (rFP, rINST, 4) # vAA<- remainder; return of fmod
- FINISH 1 # jump to next instruction
-
-/* continuation for OP_DIV_INT_LIT16 */
-.LOP_DIV_INT_LIT16_break:
- .if 1
- movl $0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $0, (rFP, rINST, 4) # vAA<- 0
- .endif
-.LOP_DIV_INT_LIT16_break2:
-
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_REM_INT_LIT16 */
-.LOP_REM_INT_LIT16_break:
- .if 0
- movl $0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $0, (rFP, rINST, 4) # vAA<- 0
- .endif
-.LOP_REM_INT_LIT16_break2:
-
- FINISH 2 # jump to next instruction
-
-/* continuation for OP_DIV_INT_LIT8 */
-.LOP_DIV_INT_LIT8_break:
- .if 1
- movl $0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $0, (rFP, rINST, 4) # vAA<- 0
- .endif
-
-.LOP_DIV_INT_LIT8_break2:
- FINISH 2 # jump to next instruction
- #FGETOP_JMP 2, %ecx # jump to next instruction; getop, jmp
-
-/* continuation for OP_REM_INT_LIT8 */
-.LOP_REM_INT_LIT8_break:
- .if 0
- movl $0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $0, (rFP, rINST, 4) # vAA<- 0
- .endif
-
-.LOP_REM_INT_LIT8_break2:
- FINISH 2 # jump to next instruction
- #FGETOP_JMP 2, %ecx # jump to next instruction; getop, jmp
-
-/* continuation for OP_EXECUTE_INLINE */
-
- /*
- * Extract args, call function.
- * rINST = #of args (0-4)
- * %ecx = call index
- */
-
-.LOP_EXECUTE_INLINE_continue:
- FETCH 2, %edx # %edx<- FEDC
- cmp $1, rINST # determine number of arguments
- jl 0f # handle zero args
- je 1f # handle one arg
- cmp $3, rINST
- jl 2f # handle two args
- je 3f # handle three args
-4:
- movl %edx, rINST # rINST<- FEDC
- and $0xf000, rINST # isolate F
- shr $10, rINST
- movl (rFP, rINST), rINST # rINST<- vF
- movl rINST, 12(%esp) # push parameter vF
-3:
- movl %edx, rINST # rINST<- FEDC
- and $0x0f00, rINST # isolate E
- shr $6, rINST
- movl (rFP, rINST), rINST # rINST<- vE
- movl rINST, 8(%esp) # push parameter E
-2:
- movl %edx, rINST # rINST<- FEDC
- and $0x00f0, rINST # isolate D
- shr $2, rINST
- movl (rFP, rINST), rINST # rINST<- vD
- movl rINST, 4(%esp) # push parameter D
-1:
- and $0x000f, %edx # isolate C
- movl (rFP, %edx, 4), %edx # rINST<- vC
- movl %edx, (%esp) # push parameter C
-0:
- shl $4, %ecx
- movl $gDvmInlineOpsTable, %eax # %eax<- address for table of inline operations
- call *(%eax, %ecx) # call function
-
- cmp $0, %eax # check boolean result of inline
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- lea 24(%esp), %esp # update stack pointer
- je common_exceptionThrown # handle exception
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
-
- .size dvmAsmSisterStart, .-dvmAsmSisterStart
- .global dvmAsmSisterEnd
-dvmAsmSisterEnd:
-
-/* File: x86-atom/entry.S */
- /* 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.
- */
-
- /*
- * File: entry.S
- */
-
-#define ASSIST_DEBUGGER 1
- .text
- .align 2
- .global dvmMterpStdRun
- .type dvmMterpStdRun, %function
-
- /*
- * Save registers, initialize sp and fp.
- * On entry:
- * bool MterpGlue(glue *)
- */
-
- .macro MTERP_ENTRY
- movl 4(%esp), %ecx # get first argument
- movl %ebp, -4(%esp) # save caller base pointer
- movl %ebx, -8(%esp) # save %ebx
- movl %esi, -12(%esp) # save %esi
- movl %edi, -16(%esp) # save %edi
- lea -40(%esp), %ebp # set callee base pointer
- lea -40(%esp), %esp # set callee stack pointer
- .endm
-
- /*
- * Restore registers.
- * This function returns a boolean "changeInterp" value.
- * The return value is from dvmMterpStdBail().
- */
-
- .macro MTERP_EXIT
- lea 40(%esp), %esp # correct stack pointer
- movl -16(%esp), %edi # restore %edi
- movl -12(%esp), %esi # restore %esi
- movl -8(%esp), %ebx # restore %ebx
- movl -4(%esp), %ebp # restore caller base pointer
- ret # return
- .endm
-
- /*
- * DvmMterpStdRun entry point: save stack pointer, setup memory locations, get
- * entry point, start executing instructions.
- */
-
-dvmMterpStdRun:
- MTERP_ENTRY
- movl %ecx, rGLUE # save value for pMterpGlue
- movl offGlue_pc(%ecx), rPC # get program counter
- cmp $kInterpEntryInstr, offGlue_entryPoint(%ecx) # check instruction
- movl offGlue_fp(%ecx), rFP # get frame pointer
- movl %esp, offGlue_bailPtr(%ecx) # save SP for eventual return
- FFETCH %edx # %edx<- opcode
- jne .Lnot_instr # no, handle it
- FGETOP_JMPa %edx # start executing the instruction at rPC
-
- /*
- * Not an instruction. Are we returning from a method?
- */
-
-.Lnot_instr:
- cmpl $kInterpEntryReturn, offGlue_entryPoint(%ecx)
- je common_returnFromMethod
-
- /*
- * No, are we throwing an exception?
- */
-
-.Lnot_return:
- cmpl $kInterpEntryThrow, offGlue_entryPoint(%ecx)
- je common_exceptionThrown
-
- /*
- * No, then we must abort.
- */
-
-.Lbad_arg:
- pushl offGlue_entryPoint(%ecx)
- movl $.LstrBadEntryPoint, -4(%esp)
- lea -4(%esp), %esp
- call printf
- lea 8(%esp), %esp
- call dvmAbort # call (void)
-
- /*
- * Restore the stack pointer and PC from the save point established on entry and
- * return to whoever called dvmMterpStdRun.
- *
- * On entry:
- * 4(%esp) MterpGlue* glue
- * 8(%esp) bool changeInterp
- */
-
- .global dvmMterpStdBail
- .type dvmMterpStdBail, %function
-
-dvmMterpStdBail:
- movl 4(%esp), %ecx # get first argument
- movl 8(%esp), %eax # get second argument
- movl offGlue_bailPtr(%ecx), %esp # sp <- saved SP
- MTERP_EXIT
-
- /*
- * String references.
- */
-
-.LstrBadEntryPoint:
- .asciz "Bad entry point %d\n"
-
-
-dvmAsmInstructionJmpTable = .LdvmAsmInstructionJmpTable
-.LdvmAsmInstructionJmpTable:
-.long .L_OP_NOP
-.long .L_OP_MOVE
-.long .L_OP_MOVE_FROM16
-.long .L_OP_MOVE_16
-.long .L_OP_MOVE_WIDE
-.long .L_OP_MOVE_WIDE_FROM16
-.long .L_OP_MOVE_WIDE_16
-.long .L_OP_MOVE_OBJECT
-.long .L_OP_MOVE_OBJECT_FROM16
-.long .L_OP_MOVE_OBJECT_16
-.long .L_OP_MOVE_RESULT
-.long .L_OP_MOVE_RESULT_WIDE
-.long .L_OP_MOVE_RESULT_OBJECT
-.long .L_OP_MOVE_EXCEPTION
-.long .L_OP_RETURN_VOID
-.long .L_OP_RETURN
-.long .L_OP_RETURN_WIDE
-.long .L_OP_RETURN_OBJECT
-.long .L_OP_CONST_4
-.long .L_OP_CONST_16
-.long .L_OP_CONST
-.long .L_OP_CONST_HIGH16
-.long .L_OP_CONST_WIDE_16
-.long .L_OP_CONST_WIDE_32
-.long .L_OP_CONST_WIDE
-.long .L_OP_CONST_WIDE_HIGH16
-.long .L_OP_CONST_STRING
-.long .L_OP_CONST_STRING_JUMBO
-.long .L_OP_CONST_CLASS
-.long .L_OP_MONITOR_ENTER
-.long .L_OP_MONITOR_EXIT
-.long .L_OP_CHECK_CAST
-.long .L_OP_INSTANCE_OF
-.long .L_OP_ARRAY_LENGTH
-.long .L_OP_NEW_INSTANCE
-.long .L_OP_NEW_ARRAY
-.long .L_OP_FILLED_NEW_ARRAY
-.long .L_OP_FILLED_NEW_ARRAY_RANGE
-.long .L_OP_FILL_ARRAY_DATA
-.long .L_OP_THROW
-.long .L_OP_GOTO
-.long .L_OP_GOTO_16
-.long .L_OP_GOTO_32
-.long .L_OP_PACKED_SWITCH
-.long .L_OP_SPARSE_SWITCH
-.long .L_OP_CMPL_FLOAT
-.long .L_OP_CMPG_FLOAT
-.long .L_OP_CMPL_DOUBLE
-.long .L_OP_CMPG_DOUBLE
-.long .L_OP_CMP_LONG
-.long .L_OP_IF_EQ
-.long .L_OP_IF_NE
-.long .L_OP_IF_LT
-.long .L_OP_IF_GE
-.long .L_OP_IF_GT
-.long .L_OP_IF_LE
-.long .L_OP_IF_EQZ
-.long .L_OP_IF_NEZ
-.long .L_OP_IF_LTZ
-.long .L_OP_IF_GEZ
-.long .L_OP_IF_GTZ
-.long .L_OP_IF_LEZ
-.long .L_OP_UNUSED_3E
-.long .L_OP_UNUSED_3F
-.long .L_OP_UNUSED_40
-.long .L_OP_UNUSED_41
-.long .L_OP_UNUSED_42
-.long .L_OP_UNUSED_43
-.long .L_OP_AGET
-.long .L_OP_AGET_WIDE
-.long .L_OP_AGET_OBJECT
-.long .L_OP_AGET_BOOLEAN
-.long .L_OP_AGET_BYTE
-.long .L_OP_AGET_CHAR
-.long .L_OP_AGET_SHORT
-.long .L_OP_APUT
-.long .L_OP_APUT_WIDE
-.long .L_OP_APUT_OBJECT
-.long .L_OP_APUT_BOOLEAN
-.long .L_OP_APUT_BYTE
-.long .L_OP_APUT_CHAR
-.long .L_OP_APUT_SHORT
-.long .L_OP_IGET
-.long .L_OP_IGET_WIDE
-.long .L_OP_IGET_OBJECT
-.long .L_OP_IGET_BOOLEAN
-.long .L_OP_IGET_BYTE
-.long .L_OP_IGET_CHAR
-.long .L_OP_IGET_SHORT
-.long .L_OP_IPUT
-.long .L_OP_IPUT_WIDE
-.long .L_OP_IPUT_OBJECT
-.long .L_OP_IPUT_BOOLEAN
-.long .L_OP_IPUT_BYTE
-.long .L_OP_IPUT_CHAR
-.long .L_OP_IPUT_SHORT
-.long .L_OP_SGET
-.long .L_OP_SGET_WIDE
-.long .L_OP_SGET_OBJECT
-.long .L_OP_SGET_BOOLEAN
-.long .L_OP_SGET_BYTE
-.long .L_OP_SGET_CHAR
-.long .L_OP_SGET_SHORT
-.long .L_OP_SPUT
-.long .L_OP_SPUT_WIDE
-.long .L_OP_SPUT_OBJECT
-.long .L_OP_SPUT_BOOLEAN
-.long .L_OP_SPUT_BYTE
-.long .L_OP_SPUT_CHAR
-.long .L_OP_SPUT_SHORT
-.long .L_OP_INVOKE_VIRTUAL
-.long .L_OP_INVOKE_SUPER
-.long .L_OP_INVOKE_DIRECT
-.long .L_OP_INVOKE_STATIC
-.long .L_OP_INVOKE_INTERFACE
-.long .L_OP_UNUSED_73
-.long .L_OP_INVOKE_VIRTUAL_RANGE
-.long .L_OP_INVOKE_SUPER_RANGE
-.long .L_OP_INVOKE_DIRECT_RANGE
-.long .L_OP_INVOKE_STATIC_RANGE
-.long .L_OP_INVOKE_INTERFACE_RANGE
-.long .L_OP_UNUSED_79
-.long .L_OP_UNUSED_7A
-.long .L_OP_NEG_INT
-.long .L_OP_NOT_INT
-.long .L_OP_NEG_LONG
-.long .L_OP_NOT_LONG
-.long .L_OP_NEG_FLOAT
-.long .L_OP_NEG_DOUBLE
-.long .L_OP_INT_TO_LONG
-.long .L_OP_INT_TO_FLOAT
-.long .L_OP_INT_TO_DOUBLE
-.long .L_OP_LONG_TO_INT
-.long .L_OP_LONG_TO_FLOAT
-.long .L_OP_LONG_TO_DOUBLE
-.long .L_OP_FLOAT_TO_INT
-.long .L_OP_FLOAT_TO_LONG
-.long .L_OP_FLOAT_TO_DOUBLE
-.long .L_OP_DOUBLE_TO_INT
-.long .L_OP_DOUBLE_TO_LONG
-.long .L_OP_DOUBLE_TO_FLOAT
-.long .L_OP_INT_TO_BYTE
-.long .L_OP_INT_TO_CHAR
-.long .L_OP_INT_TO_SHORT
-.long .L_OP_ADD_INT
-.long .L_OP_SUB_INT
-.long .L_OP_MUL_INT
-.long .L_OP_DIV_INT
-.long .L_OP_REM_INT
-.long .L_OP_AND_INT
-.long .L_OP_OR_INT
-.long .L_OP_XOR_INT
-.long .L_OP_SHL_INT
-.long .L_OP_SHR_INT
-.long .L_OP_USHR_INT
-.long .L_OP_ADD_LONG
-.long .L_OP_SUB_LONG
-.long .L_OP_MUL_LONG
-.long .L_OP_DIV_LONG
-.long .L_OP_REM_LONG
-.long .L_OP_AND_LONG
-.long .L_OP_OR_LONG
-.long .L_OP_XOR_LONG
-.long .L_OP_SHL_LONG
-.long .L_OP_SHR_LONG
-.long .L_OP_USHR_LONG
-.long .L_OP_ADD_FLOAT
-.long .L_OP_SUB_FLOAT
-.long .L_OP_MUL_FLOAT
-.long .L_OP_DIV_FLOAT
-.long .L_OP_REM_FLOAT
-.long .L_OP_ADD_DOUBLE
-.long .L_OP_SUB_DOUBLE
-.long .L_OP_MUL_DOUBLE
-.long .L_OP_DIV_DOUBLE
-.long .L_OP_REM_DOUBLE
-.long .L_OP_ADD_INT_2ADDR
-.long .L_OP_SUB_INT_2ADDR
-.long .L_OP_MUL_INT_2ADDR
-.long .L_OP_DIV_INT_2ADDR
-.long .L_OP_REM_INT_2ADDR
-.long .L_OP_AND_INT_2ADDR
-.long .L_OP_OR_INT_2ADDR
-.long .L_OP_XOR_INT_2ADDR
-.long .L_OP_SHL_INT_2ADDR
-.long .L_OP_SHR_INT_2ADDR
-.long .L_OP_USHR_INT_2ADDR
-.long .L_OP_ADD_LONG_2ADDR
-.long .L_OP_SUB_LONG_2ADDR
-.long .L_OP_MUL_LONG_2ADDR
-.long .L_OP_DIV_LONG_2ADDR
-.long .L_OP_REM_LONG_2ADDR
-.long .L_OP_AND_LONG_2ADDR
-.long .L_OP_OR_LONG_2ADDR
-.long .L_OP_XOR_LONG_2ADDR
-.long .L_OP_SHL_LONG_2ADDR
-.long .L_OP_SHR_LONG_2ADDR
-.long .L_OP_USHR_LONG_2ADDR
-.long .L_OP_ADD_FLOAT_2ADDR
-.long .L_OP_SUB_FLOAT_2ADDR
-.long .L_OP_MUL_FLOAT_2ADDR
-.long .L_OP_DIV_FLOAT_2ADDR
-.long .L_OP_REM_FLOAT_2ADDR
-.long .L_OP_ADD_DOUBLE_2ADDR
-.long .L_OP_SUB_DOUBLE_2ADDR
-.long .L_OP_MUL_DOUBLE_2ADDR
-.long .L_OP_DIV_DOUBLE_2ADDR
-.long .L_OP_REM_DOUBLE_2ADDR
-.long .L_OP_ADD_INT_LIT16
-.long .L_OP_RSUB_INT
-.long .L_OP_MUL_INT_LIT16
-.long .L_OP_DIV_INT_LIT16
-.long .L_OP_REM_INT_LIT16
-.long .L_OP_AND_INT_LIT16
-.long .L_OP_OR_INT_LIT16
-.long .L_OP_XOR_INT_LIT16
-.long .L_OP_ADD_INT_LIT8
-.long .L_OP_RSUB_INT_LIT8
-.long .L_OP_MUL_INT_LIT8
-.long .L_OP_DIV_INT_LIT8
-.long .L_OP_REM_INT_LIT8
-.long .L_OP_AND_INT_LIT8
-.long .L_OP_OR_INT_LIT8
-.long .L_OP_XOR_INT_LIT8
-.long .L_OP_SHL_INT_LIT8
-.long .L_OP_SHR_INT_LIT8
-.long .L_OP_USHR_INT_LIT8
-.long .L_OP_IGET_VOLATILE
-.long .L_OP_IPUT_VOLATILE
-.long .L_OP_SGET_VOLATILE
-.long .L_OP_SPUT_VOLATILE
-.long .L_OP_IGET_OBJECT_VOLATILE
-.long .L_OP_IGET_WIDE_VOLATILE
-.long .L_OP_IPUT_WIDE_VOLATILE
-.long .L_OP_SGET_WIDE_VOLATILE
-.long .L_OP_SPUT_WIDE_VOLATILE
-.long .L_OP_BREAKPOINT
-.long .L_OP_THROW_VERIFICATION_ERROR
-.long .L_OP_EXECUTE_INLINE
-.long .L_OP_EXECUTE_INLINE_RANGE
-.long .L_OP_INVOKE_OBJECT_INIT_RANGE
-.long .L_OP_RETURN_VOID_BARRIER
-.long .L_OP_IGET_QUICK
-.long .L_OP_IGET_WIDE_QUICK
-.long .L_OP_IGET_OBJECT_QUICK
-.long .L_OP_IPUT_QUICK
-.long .L_OP_IPUT_WIDE_QUICK
-.long .L_OP_IPUT_OBJECT_QUICK
-.long .L_OP_INVOKE_VIRTUAL_QUICK
-.long .L_OP_INVOKE_VIRTUAL_QUICK_RANGE
-.long .L_OP_INVOKE_SUPER_QUICK
-.long .L_OP_INVOKE_SUPER_QUICK_RANGE
-.long .L_OP_IPUT_OBJECT_VOLATILE
-.long .L_OP_SGET_OBJECT_VOLATILE
-.long .L_OP_SPUT_OBJECT_VOLATILE
-.long .L_OP_UNUSED_FF
-
-/* File: x86-atom/footer.S */
- /* 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.
- */
-
- /*
- * File: footer.S
- */
-
- .text
- .align 2
-
- /*
- * Check to see if the thread needs to be suspended or debugger/profiler
- * activity has begun.
- *
- * On entry:
- * %ecx is reentry type, e.g. kInterpEntryInstr
- * %edx is PC adjustment in bytes
- */
-
-common_periodicChecks:
- movl %edx, -8(%esp) # save pc adjustments
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl %ebx, -4(%esp) # save %ebx to the stack
- movl offGlue_pSelfSuspendCount(%edx), %ebx # %ebx<- pSuspendCount (int)
-4:
- movl offGlue_pDebuggerActive(%edx), %eax # %eax<- pDebuggerActive
- testl %eax, %eax
- je 5f
- movzbl (%eax), %eax # %eax<- get debuggerActive (boolean)
-5:
- cmp $0, (%ebx) # check if suspend is pending
- jne 2f # handle suspend
- movl offGlue_pActiveProfilers(%edx), %ebx # %ebx<- activeProfilers (int)
- orl (%ebx), %eax # %eax<- merge activeProfilers and debuggerActive
- movl -8(%esp), %edx # %edx<- restore %edx
- jne 3f # debugger or profiler active; switch interp
- movl -4(%esp), %ebx # %ebx<- restore %ebx
- ret # return
-2: # check suspended
- EXPORT_PC
- movl offGlue_self(%edx), %eax # %eax<- glue->self
- movl %eax, -12(%esp) # push parameter boolean
- lea -12(%esp), %esp
- call dvmCheckSuspendPending # call: (Thread* self)
- # return: bool
- movl 4(%esp), %edx # %edx<- restore %edx
- movl 8(%esp), %ebx # %ebx<- restore %ebx
- lea 12(%esp), %esp
- ret
-3: # debugger/profiler enabled, bail out
- leal (rPC, %edx, 2), rPC # adjust pc to show target
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movb $kInterpEntryInstr, offGlue_entryPoint(%ecx)
- movl $1, %edx # switch interpreter
- jmp common_gotoBail # bail
-
- /*
- * Check to see if the thread needs to be suspended or debugger/profiler
- * activity has begun. With this variant, the reentry type is hard coded
- * as kInterpEntryInstr.
- *
- * On entry:
- * %edx is PC adjustment in bytes
- */
-
-common_periodicChecks_backwardBranch:
- EXPORT_PC
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_pSelfSuspendCount(%ecx), rINST # %ebx<- pSuspendCount (int)
-4:
- movl offGlue_pDebuggerActive(%ecx), %eax # %eax<- pDebuggerActive
- testl %eax, %eax # test for NULL pointer
- je 5f
- movzbl (%eax), %eax # %eax<- get debuggerActive count
-5:
- cmp $0, (rINST) # check if suspend is pending
- jne 2f # handle suspend
- movl offGlue_pActiveProfilers(%ecx), rINST # %edx<- activeProfilers (int)
- orl (rINST), %eax # %eax<- merge activeProfilers and debuggerActive
- jne 3f # debugger or profiler active; switch interp
- FINISH_RB %edx, %ecx # jump to next instruction
-2: # check suspended
- movl offGlue_self(%ecx), %eax# %eax<- glue->self
- movl %edx, rINST
- movl %eax, -12(%esp) # push parameter boolean
- lea -12(%esp), %esp
- call dvmCheckSuspendPending # call: (Thread* self)
- # return: bool
- movl rINST, %edx # %edx<- restore %edx
- lea 12(%esp), %esp
- FINISH_RB %edx, %ecx
-3: # debugger/profiler enabled, bail out
- leal (rPC, %edx, 2), rPC # adjust pc to show target
- movb $kInterpEntryInstr, offGlue_entryPoint(%ecx)
- movl $1, %edx # switch interpreter
- jmp common_gotoBail # bail
-
- /*
- * The equivalent of "goto bail", this calls through the "bail handler".
- * State registers will be saved to the "glue" area before bailing.
- *
- * On entry:
- * %edx is "bool changeInterp", indicating if we want to switch to the
- * other interpreter or just bail all the way out
- */
-
-common_gotoBail:
- SAVE_PC_FP_TO_GLUE %ecx # save program counter and frame pointer
-
- /*
- * Inlined dvmMterpStdBail
- */
-
- lea 40(%ebp), %esp
- movl %edx, %eax
- movl 24(%ebp), %edi
- movl 28(%ebp), %esi
- movl 32(%ebp), %ebx
- movl 36(%ebp), %ebp
- ret
-
- /*
- * Common code for method invocation with range.
- *
- * On entry:
- * %ecx is "Method* methodToCall", the method we're trying to call
- */
-
-common_invokeMethodRange:
-.LinvokeNewRange:
-
- /*
- * prepare to copy args to "outs" area of current frame
- */
-
- SAVEAREA_FROM_FP %eax # %eax<- &outs; &StackSaveArea
- test rINST, rINST # test for no args
- movl rINST, sReg0 # sReg0<- AA
- jz .LinvokeArgsDone # no args; jump to args done
- FETCH 2, %edx # %edx<- CCCC
-
- /*
- * %ecx=methodToCall, %edx=CCCC, sReg0=count, %eax=&outs (&stackSaveArea)
- * (very few methods have > 10 args; could unroll for common cases)
- */
-
- movl %ebx, sReg1 # sReg1<- save %ebx
- lea (rFP, %edx, 4), %edx # %edx<- &vCCCC
- shll $2, sReg0 # sReg0<- offset
- subl sReg0, %eax # %eax<- update &outs
- shrl $2, sReg0 # sReg0<- offset
-1:
- movl (%edx), %ebx # %ebx<- vCCCC
- lea 4(%edx), %edx # %edx<- &vCCCC++
- subl $1, sReg0 # sReg<- sReg--
- movl %ebx, (%eax) # *outs<- vCCCC
- lea 4(%eax), %eax # outs++
- jne 1b # loop if count (sReg0) not zero
- movl sReg1, %ebx # %ebx<- restore %ebx
- jmp .LinvokeArgsDone # continue
-
- /*
- * %ecx is "Method* methodToCall", the method we're trying to call
- * prepare to copy args to "outs" area of current frame
- */
-
-common_invokeMethodNoRange:
-.LinvokeNewNoRange:
- movl rINST, sReg0 # sReg0<- BA
- shrl $4, sReg0 # sReg0<- B
- je .LinvokeArgsDone # no args; jump to args done
- SAVEAREA_FROM_FP %eax # %eax<- &outs; &StackSaveArea
- FETCH 2, %edx # %edx<- GFED
-
- /*
- * %ecx=methodToCall, %edx=GFED, sReg0=count, %eax=outs
- */
-
-.LinvokeNonRange:
- cmp $2, sReg0 # compare sReg0 to 2
- movl %edx, sReg1 # sReg1<- GFED
- jl 1f # handle 1 arg
- je 2f # handle 2 args
- cmp $4, sReg0 # compare sReg0 to 4
- jl 3f # handle 3 args
- je 4f # handle 4 args
-5:
- andl $15, rINST # rINST<- A
- lea -4(%eax), %eax # %eax<- update &outs; &outs--
- movl (rFP, rINST, 4), %edx # %edx<- vA
- movl %edx, (%eax) # *outs<- vA
- movl sReg1, %edx # %edx<- GFED
-4:
- shr $12, %edx # %edx<- G
- lea -4(%eax), %eax # %eax<- update &outs; &outs--
- movl (rFP, %edx, 4), %edx # %edx<- vG
- movl %edx, (%eax) # *outs<- vG
- movl sReg1, %edx # %edx<- GFED
-3:
- and $0x0f00, %edx # %edx<- 0F00
- shr $6, %edx # %edx<- F at correct offset
- lea -4(%eax), %eax # %eax<- update &outs; &outs--
- movl (rFP, %edx), %edx # %edx<- vF
- movl %edx, (%eax) # *outs<- vF
- movl sReg1, %edx # %edx<- GFED
-2:
- and $0x00f0, %edx # %edx<- 00E0
- shr $2, %edx # %edx<- E at correct offset
- lea -4(%eax), %eax # %eax<- update &outs; &outs--
- movl (rFP, %edx), %edx # %edx<- vE
- movl %edx, (%eax) # *outs<- vE
- movl sReg1, %edx # %edx<- GFED
-1:
- and $0x000f, %edx # %edx<- 000D
- movl (rFP, %edx, 4), %edx # %edx<- vD
- movl %edx, -4(%eax) # *--outs<- vD
-0:
-
- /*
- * %ecx is "Method* methodToCall", the method we're trying to call
- * find space for the new stack frame, check for overflow
- */
-
-.LinvokeArgsDone:
- movzwl offMethod_registersSize(%ecx), %eax # %eax<- methodToCall->regsSize
- movzwl offMethod_outsSize(%ecx), %edx # %edx<- methodToCall->outsSize
- movl %ecx, sReg0 # sReg<- methodToCall
- shl $2, %eax # %eax<- update offset
- SAVEAREA_FROM_FP %ecx # %ecx<- &outs; &StackSaveArea
- subl %eax, %ecx # %ecx<- newFP; (old savearea - regsSize)
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl %ecx, sReg1 # sReg1<- &outs
- subl $sizeofStackSaveArea, %ecx # %ecx<- newSaveArea (stack save area using newFP)
- movl offGlue_interpStackEnd(%eax), %eax # %eax<- glue->interpStackEnd
- movl %eax, sReg2 # sReg2<- glue->interpStackEnd
- shl $2, %edx # %edx<- update offset for outsSize
- movl %ecx, %eax # %eax<- newSaveArea
- sub %edx, %ecx # %ecx<- bottom; (newSaveArea - outsSize)
- cmp sReg2, %ecx # compare interpStackEnd and bottom
- movl sReg0, %ecx # %ecx<- restore methodToCall
- jl .LstackOverflow # handle frame overflow
-
- /*
- * set up newSaveArea
- */
-
-#ifdef EASY_GDB
- SAVEAREA_FROM_FP %edx # %edx<- &outs; &StackSaveArea
- movl %edx, offStackSaveArea_prevSave(%eax) # newSaveArea->prevSave<- &outs
-#endif
- movl rFP, offStackSaveArea_prevFrame(%eax) # newSaveArea->prevFrame<- rFP
- movl rPC, offStackSaveArea_savedPc(%eax) # newSaveArea->savedPc<- rPC
- testl $ACC_NATIVE, offMethod_accessFlags(%ecx) # check for native call
- movl %ecx, offStackSaveArea_method(%eax) # newSaveArea->method<- method to call
- jne .LinvokeNative # handle native call
-
- /*
- * Update "glue" values for the new method
- * %ecx=methodToCall, sReg1=newFp
- */
-
- movl offMethod_clazz(%ecx), %edx # %edx<- method->clazz
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl %ecx, offGlue_method(%eax) # glue->method<- methodToCall
- movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
- movl offMethod_insns(%ecx), rPC # rPC<- methodToCall->insns
- movl %edx, offGlue_methodClassDex(%eax) # glue->methodClassDex<- method->clazz->pDvmDex
- movl offGlue_self(%eax), %ecx # %ecx<- glue->self
- movl sReg1, rFP # rFP<- newFP
- movl rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
- FINISH_A # jump to methodToCall->insns
-
- /*
- * Prep for the native call
- * %ecx=methodToCall, sReg1=newFP, %eax=newSaveArea
- */
-
-.LinvokeNative:
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl %ecx, -20(%esp) # push parameter methodToCall
- movl offGlue_self(%edx), %edx # %edx<- glue->self
- movl offThread_jniLocal_topCookie(%edx), %ecx # %ecx<- glue->self->thread->refNext
- movl %ecx, offStackSaveArea_localRefCookie(%eax) # newSaveArea->localRefCookie<- refNext
- movl %eax, -4(%esp) # save newSaveArea
- movl sReg1, %eax # %eax<- newFP
- movl %eax, offThread_curFrame(%edx) # glue->self->curFrame<- newFP
- movl %edx, -8(%esp) # save glue->self
- movl %edx, -16(%esp) # push parameter glue->self
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl -20(%esp), %ecx # %ecx<- methodToCall
- lea offGlue_retval(%edx), %edx # %edx<- &retval
- movl %edx, -24(%esp) # push parameter pMterpGlue
- movl %eax, -28(%esp) # push parameter newFP
- lea -28(%esp), %esp
-
-#ifdef ASSIST_DEBUGGER
- jmp .Lskip
- .type dalvik_mterp, %function
-dalvik_mterp:
- MTERP_ENTRY
-.Lskip:
-#endif
- call *offMethod_nativeFunc(%ecx) # call methodToCall->nativeFunc
- lea 28(%esp), %esp
- movl -4(%esp), %edx # %edx<- newSaveArea
- movl -8(%esp), %ecx # %ecx<- glue->self
- movl offStackSaveArea_localRefCookie(%edx), %eax # %eax<- newSaveArea->localRefCookie
- FFETCH_ADV 3, %edx # %edx<- next instruction hi; fetch, advance
- cmp $0, offThread_exception(%ecx) # check for exception
- movl rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
- movl %eax, offThread_jniLocal_topCookie(%ecx) # glue->self<- newSaveArea->localRefCookie
- jne common_exceptionThrown # handle exception
- FGETOP_JMP 3, %edx # jump to next instruction; getop, jmp
-
-.LstackOverflow:
- movl %ecx, -4(%esp) # push method to call
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_self(%ecx), %ecx # %ecx<- glue->self
- movl %ecx, -8(%esp) # push parameter self
- lea -8(%esp), %esp
- call dvmHandleStackOverflow # call: (Thread* self, Method *meth)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-#ifdef ASSIST_DEBUGGER
-#endif
-
- /*
- * Common code for handling a return instruction.
- *
- * This does not return.
- */
-
-common_returnFromMethod:
-.LreturnNew:
-
- /*
- * Inline common periodic checks
- */
-
- movl rGLUE, rINST # %ecx<- pMterpGlue
- movl offGlue_pSelfSuspendCount(rINST), %edx # %ebx<- pSuspendCount (int)
- movl offGlue_pDebuggerActive(rINST), %eax # %eax<- pDebuggerActive
- movl (%eax), %eax # %eax<- get debuggerActive (boolean)
- and $7, %eax # %eax<- mask for boolean (just how many bits does it take?)
- cmp $0, (%edx) # check if suspend is pending
- jne 2f # handle suspend
- movl offGlue_pActiveProfilers(rINST), %edx # %edx<- activeProfilers (int)
- or (%edx), %eax # %eax<- merge activeProfilers and debuggerActive
- cmp $0, %eax # check for debuggerActive
- jne 3f # debugger or profiler active; switch interp
- jmp 4f
-2: # check suspended
- movl offGlue_self(rINST), %eax# %eax<- glue->self
- movl %eax, -12(%esp) # push parameter boolean
- lea -12(%esp), %esp
- call dvmCheckSuspendPending # call: (Thread* self)
- # return: bool
- lea 12(%esp), %esp
- jmp 4f
-3: # debugger/profiler enabled, bail out
- movl $kInterpEntryInstr, offGlue_entryPoint(rINST) # glue->entryPoint<- reentry type
- movl $1, %edx # switch to interp<- true
- jmp common_gotoBail # bail
-
-
- /*
- * Get save area; rGLUE is %ebx, rFP is %eax
- */
-4:
- SAVEAREA_FROM_FP %ecx # %ecx<- saveArea(old)
- movl offStackSaveArea_prevFrame(%ecx), rFP # rFP<- saveArea->PrevFrame
- movl (offStackSaveArea_method - sizeofStackSaveArea)(rFP), %edx # %edx<- method we are returning to
- cmpl $0, %edx # check for break frame
- je common_gotoBail # bail if break frame
- movl offStackSaveArea_savedPc(%ecx), rPC # rPC<- saveAreaOld->savedPc
- movl offGlue_self(rINST), %ecx # %eax<- glue->self
- movl %edx, offGlue_method(rINST) # glue->method<- newSave->method
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- FFETCH_ADV 3, %eax # %ecx<- next instruction hi; fetch, advance
- movl rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
- movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
- movl %edx, offGlue_methodClassDex(rINST) # glue->pDvmDex<- method->clazz->pDvmDex
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
-
- /*
- * Handle thrown an exception. If the exception processing code
- * returns to us (instead of falling out of the interpreter),
- * continue with whatever the next instruction now happens to be.
- * This does not return.
- */
-
-common_exceptionThrown:
-.LexceptionNew:
- movl $kInterpEntryThrow, %ecx # %ecx<- reentry type
- movl $0, %edx # %edx<- pc adjustment
- call common_periodicChecks
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_self(%eax), %edx # %edx<- glue->self
- movl offThread_exception(%edx), %ecx # %ecx<- pMterpGlue->self->exception
- movl %edx, -4(%esp) # push parameter self
- movl %ecx, -8(%esp) # push parameter obj
- lea -8(%esp), %esp
- call dvmAddTrackedAlloc # don't allow the exception to be GC'd
- # call: (Object* obj, Thread* self)
- # return: void
- movl 4(%esp), %edx # %edx<- glue->self
- movl $0, offThread_exception(%edx) # glue->self->exception<- NULL
-
- /*
- * set up args and a local for &fp
- */
-
- movl rFP, -4(%esp) # move fp to stack
- lea -4(%esp), %esp # update %esp
- movl %esp, -4(%esp) # push parameter 4<- &fp
- movl $0, -8(%esp) # push parameter 3<- false
- movl 4(%esp), %edx
- movl %edx, -12(%esp) # push parameter 2<- glue->self->exception
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_method(%eax), %edx # %edx<- glue->method
- movl offMethod_insns(%edx), %edx # %edx<- glue->method->insns
- movl rPC, %ecx # %ecx<- rPC
- subl %edx, %ecx # %ecx<- pc - glue->method->insns
- sar $1, %ecx # %ecx<- adjust %ecx for offset
- movl %ecx, -16(%esp) # push parameter 1<- glue->method->insns
- movl 8(%esp), %edx
- movl %edx, -20(%esp) # push parameter 0<- glue->self
- lea -20(%esp), %esp
-
- /*
- * call dvmFindCatchBlock, %eax gets catchRelPc (a code-unit offset)
- */
-
- call dvmFindCatchBlock # call: (Thread* self, int relPc, Object* exception,
- # bool doUnroll, void** newFrame)
- # return: int
- lea 32(%esp), %esp
- movl -12(%esp), rFP # rFP<- updated rFP
- cmp $0, %eax # check for catchRelPc < 0
- jl .LnotCaughtLocally # handle not caught locally
-
- /*
- * fix stack overflow if necessary
- */
-
- movl -4(%esp), %ecx # %ecx<- glue->self
- cmp $0, offThread_stackOverflowed(%ecx)
- je 1f
- movl %eax, -4(%esp) # save %eax for later
- movl %ecx, -12(%esp) # push parameter 2 glue->self
- lea -12(%esp), %esp
- call dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
- # return: void
- lea 12(%esp), %esp
- movl -4(%esp), %eax # %eax<- restore %eax
- jmp 2f
-1:
- movl %ecx, -12(%esp) # push parameter 2 glue->self
-2:
-
- /*
- * adjust locals to match self->curFrame and updated PC
- *
- */
-
- SAVEAREA_FROM_FP %edx # %edx<- get newSaveArea
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offStackSaveArea_method(%edx), rPC # rPC<- newMethod
- movl rPC, offGlue_method(%ecx) # glue->method<- newMethod
- movl offMethod_clazz(rPC), %edx # %edx<- method->clazz
- movl offMethod_insns(rPC), rPC # rPC<- method->insns
- movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
- lea (rPC, %eax, 2), rPC # rPC<- method->insns + catchRelPc
- movl %edx, offGlue_methodClassDex(%ecx) # glue->pDvmDex<- method->clazz->pDvmDex
- movl -8(%esp), %eax
- movl %eax, -16(%esp) # push parameter 1 obj
- lea -16(%esp), %esp
- call dvmReleaseTrackedAlloc # call: (Object* obj, Thread* self)
- # return: void
- lea 16(%esp), %esp
- FINISH_FETCH %eax
- cmp $OP_MOVE_EXCEPTION, %eax # is it a move exception
- jne 1f
- movl -12(%esp), %edx # %edx<- glue->self
- movl -8(%esp), %ecx # %ecx<- exception
- movl %ecx, offThread_exception(%edx) # restore the exception
-1:
- FINISH_JMP %eax
-
- /*
- * -8(%esp) = exception, -4(%esp) = self
- */
-
-.LnotCaughtLocally:
- movl -4(%esp), %edx # %edx<- glue->self
- movzb offThread_stackOverflowed(%edx), %eax # %eax<- self->stackOverflowed
- cmp $0, %eax # check for stack overflow;
- # maybe should use cmpb
- je 1f #
- movl %edx, -12(%esp) # push parameter 1 glue->self
- lea -12(%esp), %esp
- call dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
- # return: void
- lea 12(%esp), %esp
-
- /*
- * Release the exception
- * -8(%esp) = exception, -4(%esp) = self
- */
-1:
- movl -8(%esp), %ecx # %ecx<- exception
- movl -4(%esp), %edx # %edx<- glue->self
- movl %ecx, offThread_exception(%edx) # glue->self<- exception
- lea -8(%esp), %esp
- call dvmReleaseTrackedAlloc # call: (Object* obj, Thread* self)
- # return: void
- lea 8(%esp), %esp
- movl $0, %edx # switch to interp<- false
- jmp common_gotoBail # bail
-
- /*
- * After returning from a "glued" function, pull out the updated
- * values and start executing at the next instruction.
- */
-
-common_resumeAfterGlueCall:
- LOAD_PC_FP_FROM_GLUE # pull rPC and rFP out of glue
- FINISH_A # jump to next instruction
-
- /*
- * For debugging, cause an immediate fault.
- */
-
-common_abort:
- jmp .LdeadFood
-
-.LdeadFood:
-.int 0xdeadf00d
-
- /*
- * Invalid array index.
- */
-
-common_errArrayIndex:
- EXPORT_PC
- movl $.LstrArrayIndexException, -8(%esp) # push parameter description
- movl $0, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * Invalid array value.
- */
-
-common_errArrayStore:
- EXPORT_PC
- movl $.LstrArrayStoreException, -8(%esp) # push parameter description
- movl $0, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * Integer divide or mod by zero.
- */
-
-common_errDivideByZero:
- EXPORT_PC
- movl $.LstrArithmeticException, -8(%esp) # push parameter description
- movl $.LstrDivideByZero, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * Attempt to allocate an array with a negative size.
- */
-
-common_errNegativeArraySize:
- EXPORT_PC
- movl $.LstrNegativeArraySizeException, -8(%esp) # push parameter description
- movl $0, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * Invocation of a non-existent method.
- */
-
-common_errNoSuchMethod:
- EXPORT_PC
- movl $.LstrNoSuchMethodError, -8(%esp) # push parameter description
- movl $0, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * Unexpected null object.
- */
-
-common_errNullObject:
- EXPORT_PC
- movl $.LstrNullPointerException, -8(%esp) # push parameter description
- movl $0, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * String references
- */
-
- .align 4
- .section .rodata
-.LstrArithmeticException:
- .asciz "Ljava/lang/ArithmeticException;"
-.LstrArrayIndexException:
- .asciz "Ljava/lang/ArrayIndexOutOfBoundsException;"
-.LstrArrayStoreException:
- .asciz "Ljava/lang/ArrayStoreException;"
-.LstrDivideByZero:
- .asciz "divide by zero"
-.LstrInstantiationError:
- .asciz "Ljava/lang/InstantiationError;"
-.LstrNegativeArraySizeException:
- .asciz "Ljava/lang/NegativeArraySizeException;"
-.LstrNoSuchMethodError:
- .asciz "Ljava/lang/NoSuchMethodError;"
-.LstrNullPointerException:
- .asciz "Ljava/lang/NullPointerException;"
-.LstrExceptionNotCaughtLocally:
- .asciz "Exception %s from %s:%d not caught locally\n"
-
diff --git a/vm/mterp/out/InterpAsm-x86.S b/vm/mterp/out/InterpAsm-x86.S
index 9fcebf6..0aa94eb 100644
--- a/vm/mterp/out/InterpAsm-x86.S
+++ b/vm/mterp/out/InterpAsm-x86.S
@@ -58,8 +58,8 @@
to callee save registers).
nick reg purpose
- rPC edi interpreted program counter, used for fetching instructions
- rFP esi interpreted frame pointer, used for accessing locals and args
+ rPC esi interpreted program counter, used for fetching instructions
+ rFP edi interpreted frame pointer, used for accessing locals and args
rINSTw bx first 16-bit code of current instruction
rINSTbl bl opcode portion of instruction word
rINSTbh bh high byte of inst word, usually contains src/tgt reg names
@@ -106,7 +106,14 @@
#define OUT_ARG2 ( 8)
#define OUT_ARG1 ( 4)
#define OUT_ARG0 ( 0) /* <- dvmMterpStdRun esp */
+#if defined(WITH_JIT)
+/* for spill region: increase size by 48 (to keep 16-byte alignment) */
+/* 76 + 48 = 124 */
+#define JIT_SPILL (-56)
+#define FRAME_SIZE 124
+#else
#define FRAME_SIZE 76
+#endif
#define SPILL(reg) movl reg##,reg##_SPILL(%ebp)
#define UNSPILL(reg) movl reg##_SPILL(%ebp),reg
@@ -156,6 +163,10 @@
movl rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP)
.endm
+.macro GET_PC
+ movl (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP), rPC
+.endm
+
/*
* Given a frame pointer, find the stack save area.
*
@@ -257,6 +268,13 @@
#define sReg2 LOCAL2_OFFSET(%ebp)
/*
+ * x86 JIT Helpers
+ */
+
+ .macro dumpSwitch _regData _regScratch1 _regScratch2
+ .endm
+
+ /*
* Hard coded helper values.
*/
@@ -1007,8 +1025,12 @@
movzwl 2(rPC),%eax # eax<- BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
SPILL(rIBASE)
+ SPILL_TMP2(%ebx)
movl offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
EXPORT_PC
+#if defined(WITH_JIT)
+ lea (%ecx,%eax,4),%ebx # ebx <- &resolved class
+#endif
movl (%ecx,%eax,4),%ecx # ecx<- resolved class
testl %ecx,%ecx # resolved?
je .LOP_NEW_INSTANCE_resolve # no, go do it
@@ -1019,14 +1041,48 @@
movl $ALLOC_DONT_TRACK,OUT_ARG1(%esp)
movl %ecx,OUT_ARG0(%esp)
call dvmAllocObject # eax<- new object
- FETCH_INST_OPCODE 2 %ecx
- UNSPILL(rIBASE)
testl %eax,%eax # success?
je common_exceptionThrown # no, bail out
+#if defined(WITH_JIT)
+ /*
+ * The JIT needs the class to be fully resolved before it can
+ * include this instruction in a trace.
+ */
+ movl rSELF, %ecx
+ movl offThread_subMode(%ecx), %ecx
+ andl $kSubModeJitTraceBuild, %ecx # under construction?
+ jne .LOP_NEW_INSTANCE_jitCheck
+#endif
+.LOP_NEW_INSTANCE_end:
+ UNSPILL_TMP2(%ebx)
SET_VREG %eax rINST
+ UNSPILL(rIBASE)
+ FETCH_INST_OPCODE 2 %ecx
ADVANCE_PC 2
GOTO_NEXT_R %ecx
+#if defined(WITH_JIT)
+ /*
+ * Check to see if we need to stop the trace building early.
+ * eax: new object
+ */
+.LOP_NEW_INSTANCE_jitCheck:
+ cmp $0, (%ebx) # okay?
+ jne .LOP_NEW_INSTANCE_end # yes, finish
+ SPILL_TMP1(%eax) # preserve new object
+ movl rSELF, %ecx
+ movl %ecx, OUT_ARG0(%esp)
+ movl rPC, OUT_ARG1(%esp)
+ call dvmJitEndTraceSelect # (self, pc)
+ UNSPILL_TMP1(%eax)
+ UNSPILL_TMP2(%ebx)
+ SET_VREG %eax rINST # vAA <- new object
+ UNSPILL(rIBASE)
+ FETCH_INST_OPCODE 2 %ecx
+ ADVANCE_PC 2
+ GOTO_NEXT_R %ecx
+#endif
+
/*
* Class initialization required.
*
@@ -1435,6 +1491,11 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
/* ------------------------------ */
@@ -1451,6 +1512,11 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
/* ------------------------------ */
@@ -1467,6 +1533,11 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
/* ------------------------------ */
@@ -1492,6 +1563,11 @@
ADVANCE_PC_INDEXED %eax
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
/* ------------------------------ */
@@ -1518,6 +1594,11 @@
ADVANCE_PC_INDEXED %eax
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1722,6 +1803,11 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1750,6 +1836,11 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1778,6 +1869,11 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1806,6 +1902,11 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1834,6 +1935,11 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1862,6 +1968,11 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1878,14 +1989,19 @@
*/
/* if-cmp vAA, +BBBB */
cmpl $0,(rFP,rINST,4) # compare (vA, 0)
+ movl rSELF,%ecx
movl $2,%eax # assume branch not taken
jne 1f
- movl rSELF,%ecx
movswl 2(rPC),%eax # fetch signed displacement
movl offThread_curHandlerTable(%ecx),rIBASE
1:
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1902,14 +2018,19 @@
*/
/* if-cmp vAA, +BBBB */
cmpl $0,(rFP,rINST,4) # compare (vA, 0)
+ movl rSELF,%ecx
movl $2,%eax # assume branch not taken
je 1f
- movl rSELF,%ecx
movswl 2(rPC),%eax # fetch signed displacement
movl offThread_curHandlerTable(%ecx),rIBASE
1:
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1926,14 +2047,19 @@
*/
/* if-cmp vAA, +BBBB */
cmpl $0,(rFP,rINST,4) # compare (vA, 0)
+ movl rSELF,%ecx
movl $2,%eax # assume branch not taken
jge 1f
- movl rSELF,%ecx
movswl 2(rPC),%eax # fetch signed displacement
movl offThread_curHandlerTable(%ecx),rIBASE
1:
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1950,14 +2076,19 @@
*/
/* if-cmp vAA, +BBBB */
cmpl $0,(rFP,rINST,4) # compare (vA, 0)
+ movl rSELF,%ecx
movl $2,%eax # assume branch not taken
jl 1f
- movl rSELF,%ecx
movswl 2(rPC),%eax # fetch signed displacement
movl offThread_curHandlerTable(%ecx),rIBASE
1:
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1974,14 +2105,19 @@
*/
/* if-cmp vAA, +BBBB */
cmpl $0,(rFP,rINST,4) # compare (vA, 0)
+ movl rSELF,%ecx
movl $2,%eax # assume branch not taken
jle 1f
- movl rSELF,%ecx
movswl 2(rPC),%eax # fetch signed displacement
movl offThread_curHandlerTable(%ecx),rIBASE
1:
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -1998,14 +2134,19 @@
*/
/* if-cmp vAA, +BBBB */
cmpl $0,(rFP,rINST,4) # compare (vA, 0)
+ movl rSELF,%ecx
movl $2,%eax # assume branch not taken
jg 1f
- movl rSELF,%ecx
movswl 2(rPC),%eax # fetch signed displacement
movl offThread_curHandlerTable(%ecx),rIBASE
1:
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
@@ -3246,6 +3387,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SGET_resolve # if not, make it so
@@ -3271,8 +3418,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SGET_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SGET_finish # success, continue
/* ------------------------------ */
.L_OP_SGET_WIDE: /* 0x61 */
@@ -3286,6 +3439,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SGET_WIDE_resolve # if not, make it so
@@ -3313,8 +3472,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SGET_WIDE_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SGET_WIDE_finish # success, continue
/* ------------------------------ */
.L_OP_SGET_OBJECT: /* 0x62 */
@@ -3330,6 +3495,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SGET_OBJECT_resolve # if not, make it so
@@ -3355,8 +3526,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SGET_OBJECT_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SGET_OBJECT_finish # success, continue
/* ------------------------------ */
@@ -3373,6 +3550,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SGET_BOOLEAN_resolve # if not, make it so
@@ -3398,8 +3581,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SGET_BOOLEAN_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SGET_BOOLEAN_finish # success, continue
/* ------------------------------ */
@@ -3416,6 +3605,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SGET_BYTE_resolve # if not, make it so
@@ -3441,8 +3636,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SGET_BYTE_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SGET_BYTE_finish # success, continue
/* ------------------------------ */
@@ -3459,6 +3660,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SGET_CHAR_resolve # if not, make it so
@@ -3484,8 +3691,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SGET_CHAR_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SGET_CHAR_finish # success, continue
/* ------------------------------ */
@@ -3502,6 +3715,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SGET_SHORT_resolve # if not, make it so
@@ -3527,8 +3746,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SGET_SHORT_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SGET_SHORT_finish # success, continue
/* ------------------------------ */
@@ -3544,6 +3769,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SPUT_resolve # if not, make it so
@@ -3560,7 +3791,7 @@
.LOP_SPUT_resolve:
movl rSELF,%ecx
movzwl 2(rPC),%eax # eax<- field ref BBBB
- movl offThread_method(%ecx),%ecx # ecx<- current method
+ movl offThread_method(%ecx),%ecx # ecx<- current method
EXPORT_PC # could throw, need to export
movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
movl %eax,OUT_ARG1(%esp)
@@ -3569,9 +3800,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SPUT_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
-
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SPUT_finish # success, continue
/* ------------------------------ */
.L_OP_SPUT_WIDE: /* 0x68 */
/* File: x86/OP_SPUT_WIDE.S */
@@ -3585,6 +3821,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SPUT_WIDE_resolve # if not, make it so
@@ -3612,8 +3854,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SPUT_WIDE_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SPUT_WIDE_finish # success, continue
/* ------------------------------ */
.L_OP_SPUT_OBJECT: /* 0x69 */
@@ -3626,6 +3874,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField
testl %eax,%eax # resolved entry null?
je .LOP_SPUT_OBJECT_resolve # if not, make it so
@@ -3657,8 +3911,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SPUT_OBJECT_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SPUT_OBJECT_finish # success, continue
/* ------------------------------ */
.L_OP_SPUT_BOOLEAN: /* 0x6a */
@@ -3674,6 +3934,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SPUT_BOOLEAN_resolve # if not, make it so
@@ -3690,7 +3956,7 @@
.LOP_SPUT_BOOLEAN_resolve:
movl rSELF,%ecx
movzwl 2(rPC),%eax # eax<- field ref BBBB
- movl offThread_method(%ecx),%ecx # ecx<- current method
+ movl offThread_method(%ecx),%ecx # ecx<- current method
EXPORT_PC # could throw, need to export
movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
movl %eax,OUT_ARG1(%esp)
@@ -3699,9 +3965,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SPUT_BOOLEAN_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
-
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SPUT_BOOLEAN_finish # success, continue
/* ------------------------------ */
.L_OP_SPUT_BYTE: /* 0x6b */
@@ -3717,6 +3988,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SPUT_BYTE_resolve # if not, make it so
@@ -3733,7 +4010,7 @@
.LOP_SPUT_BYTE_resolve:
movl rSELF,%ecx
movzwl 2(rPC),%eax # eax<- field ref BBBB
- movl offThread_method(%ecx),%ecx # ecx<- current method
+ movl offThread_method(%ecx),%ecx # ecx<- current method
EXPORT_PC # could throw, need to export
movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
movl %eax,OUT_ARG1(%esp)
@@ -3742,9 +4019,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SPUT_BYTE_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
-
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SPUT_BYTE_finish # success, continue
/* ------------------------------ */
.L_OP_SPUT_CHAR: /* 0x6c */
@@ -3760,6 +4042,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SPUT_CHAR_resolve # if not, make it so
@@ -3776,7 +4064,7 @@
.LOP_SPUT_CHAR_resolve:
movl rSELF,%ecx
movzwl 2(rPC),%eax # eax<- field ref BBBB
- movl offThread_method(%ecx),%ecx # ecx<- current method
+ movl offThread_method(%ecx),%ecx # ecx<- current method
EXPORT_PC # could throw, need to export
movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
movl %eax,OUT_ARG1(%esp)
@@ -3785,9 +4073,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SPUT_CHAR_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
-
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SPUT_CHAR_finish # success, continue
/* ------------------------------ */
.L_OP_SPUT_SHORT: /* 0x6d */
@@ -3803,6 +4096,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SPUT_SHORT_resolve # if not, make it so
@@ -3819,7 +4118,7 @@
.LOP_SPUT_SHORT_resolve:
movl rSELF,%ecx
movzwl 2(rPC),%eax # eax<- field ref BBBB
- movl offThread_method(%ecx),%ecx # ecx<- current method
+ movl offThread_method(%ecx),%ecx # ecx<- current method
EXPORT_PC # could throw, need to export
movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
movl %eax,OUT_ARG1(%esp)
@@ -3828,9 +4127,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SPUT_SHORT_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
-
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SPUT_SHORT_finish # success, continue
/* ------------------------------ */
.L_OP_INVOKE_VIRTUAL: /* 0x6e */
@@ -3875,9 +4179,9 @@
movzwl offMethod_methodIndex(%eax),%eax # eax<- baseMethod->methodIndex
testl %ecx,%ecx # null this?
je common_errNullObject # go if so
- movl offObject_clazz(%ecx),%ecx # ecx<- thisPtr->clazz
- movl offClassObject_vtable(%ecx),%ecx # ecx<- thisPtr->clazz->vtable
- movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
+ movl offObject_clazz(%ecx),%edx # edx<- thisPtr->clazz
+ movl offClassObject_vtable(%edx),%edx # edx<- thisPtr->clazz->vtable
+ movl (%edx,%eax,4),%eax # eax<- vtable[methodIndex]
jmp common_invokeMethodNoRange
/* ------------------------------ */
@@ -3901,8 +4205,9 @@
.if (!0)
andl $0xf,rINST # rINST<- D (or stays CCCC)
.endif
- GET_VREG_R rINST rINST # rINST<- "this" ptr
- testl rINST,rINST # null "this"?
+ GET_VREG_R %edx rINST # %edx<- "this" ptr
+ testl %edx,%edx # null "this"?
+ SPILL_TMP1(%edx)
je common_errNullObject # yes, throw
movl offMethod_clazz(%eax),%eax # eax<- method->clazz
testl %ecx,%ecx # already resolved?
@@ -3914,11 +4219,13 @@
*/
.LOP_INVOKE_SUPER_continue:
movl offClassObject_super(%eax),%eax # eax<- method->clazz->super
- movzwl offMethod_methodIndex(%ecx),%ecx # ecx<- baseMthod->methodIndex
- cmpl offClassObject_vtableCount(%eax),%ecx # compare(methodIndex,vtableCount)
+ movzwl offMethod_methodIndex(%ecx),%edx # edx<- baseMthod->methodIndex
+ cmpl offClassObject_vtableCount(%eax),%edx # compare(methodIndex,vtableCount)
jae .LOP_INVOKE_SUPER_nsm # method not present in superclass
movl offClassObject_vtable(%eax),%eax # eax<- ...clazz->super->vtable
- movl (%eax,%ecx,4),%eax # eax<- vtable[methodIndex]
+ movl (%eax,%edx,4),%eax # eax<- vtable[methodIndex]
+ UNSPILL_TMP1(%edx)
+ movl %edx, %ecx
jmp common_invokeMethodNoRange
@@ -3927,7 +4234,7 @@
* eax = method->clazz
*/
.LOP_INVOKE_SUPER_resolve:
- SPILL_TMP1(%eax) # method->clazz
+ SPILL_TMP2(%eax) # method->clazz
movl %eax,OUT_ARG0(%esp) # arg0<- method->clazz
movzwl 2(rPC),%ecx # ecx<- BBBB
movl $METHOD_VIRTUAL,OUT_ARG2(%esp) # arg2<- resolver method type
@@ -3935,7 +4242,7 @@
call dvmResolveMethod # eax<- call(clazz, ref, flags)
testl %eax,%eax # got null?
movl %eax,%ecx # ecx<- resolved base method
- UNSPILL_TMP1(%eax) # restore method->clazz
+ UNSPILL_TMP2(%eax) # restore method->clazz
jne .LOP_INVOKE_SUPER_continue # good to go - continue
jmp common_exceptionThrown # handle exception
@@ -4016,9 +4323,17 @@
movl offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
EXPORT_PC
movl offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
+#if defined(WITH_JIT)
+ movl %edx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4), %edx
+ movl %edx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %edx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved methodToCall
+ movl $0, %ecx # make "this" null
testl %eax,%eax
jne common_invokeMethodNoRange
+
movl rSELF,%ecx
movl offThread_method(%ecx),%ecx # ecx<- self->method
movzwl 2(rPC),%eax
@@ -4027,10 +4342,40 @@
movl %ecx,OUT_ARG0(%esp) # arg0<- clazz
movl $METHOD_STATIC,%eax
movl %eax,OUT_ARG2(%esp) # arg2<- flags
+ SPILL(rIBASE)
call dvmResolveMethod # call(clazz,ref,flags)
+ UNSPILL(rIBASE)
testl %eax,%eax # got null?
+#if defined(WITH_JIT)
+ movl TMP_SPILL1(%ebp), %edx
+ movl rSELF,%ecx
+ movzwl offThread_subMode(%ecx), %ecx
+ je common_exceptionThrown # null, handle exception
+ andl $kSubModeJitTraceBuild, %ecx # is trace under construction?
+ movl $0, %ecx # make "this" null
+ je common_invokeMethodNoRange # no (%eax=method, %ecx="this")
+ movl TMP_SPILL2(%ebp), %edx
+ cmpl $0, (%edx) # finished resolving
+ movl TMP_SPILL1(%ebp), %edx
+ jne common_invokeMethodNoRange # yes (%eax=method, %ecx="this")
+ movl rSELF, %edx
+ movl %edx, OUT_ARG0(%esp)
+ movl rPC, OUT_ARG1(%esp)
+ movl %eax, TMP_SPILL2(%ebp)
+ movl %ecx, TMP_SPILL3(%ebp)
+ SPILL(rIBASE)
+ call dvmJitEndTraceSelect
+ UNSPILL(rIBASE)
+ movl TMP_SPILL1(%ebp), %edx
+ movl TMP_SPILL2(%ebp), %eax
+ movl TMP_SPILL3(%ebp), %ecx
+ jmp common_invokeMethodNoRange
+#else
+ movl $0, %ecx # make "this" null
jne common_invokeMethodNoRange
jmp common_exceptionThrown
+#endif
+
/* ------------------------------ */
.L_OP_INVOKE_INTERFACE: /* 0x72 */
@@ -4051,6 +4396,7 @@
EXPORT_PC
testl %eax,%eax # null this?
je common_errNullObject # yes, fail
+ movl %eax, TMP_SPILL1(%ebp)
movl offObject_clazz(%eax),%eax# eax<- thisPtr->clazz
movl %eax,OUT_ARG0(%esp) # arg0<- class
movl offThread_methodClassDex(%ecx),%eax # eax<- methodClassDex
@@ -4062,6 +4408,7 @@
call dvmFindInterfaceMethodInCache # eax<- call(class, ref, method, dex)
testl %eax,%eax
je common_exceptionThrown
+ movl TMP_SPILL1(%ebp), %ecx
jmp common_invokeMethodNoRange
/* ------------------------------ */
@@ -4115,9 +4462,9 @@
movzwl offMethod_methodIndex(%eax),%eax # eax<- baseMethod->methodIndex
testl %ecx,%ecx # null this?
je common_errNullObject # go if so
- movl offObject_clazz(%ecx),%ecx # ecx<- thisPtr->clazz
- movl offClassObject_vtable(%ecx),%ecx # ecx<- thisPtr->clazz->vtable
- movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
+ movl offObject_clazz(%ecx),%edx # edx<- thisPtr->clazz
+ movl offClassObject_vtable(%edx),%edx # edx<- thisPtr->clazz->vtable
+ movl (%edx,%eax,4),%eax # eax<- vtable[methodIndex]
jmp common_invokeMethodRange
@@ -4143,8 +4490,9 @@
.if (!1)
andl $0xf,rINST # rINST<- D (or stays CCCC)
.endif
- GET_VREG_R rINST rINST # rINST<- "this" ptr
- testl rINST,rINST # null "this"?
+ GET_VREG_R %edx rINST # %edx<- "this" ptr
+ testl %edx,%edx # null "this"?
+ SPILL_TMP1(%edx)
je common_errNullObject # yes, throw
movl offMethod_clazz(%eax),%eax # eax<- method->clazz
testl %ecx,%ecx # already resolved?
@@ -4156,11 +4504,13 @@
*/
.LOP_INVOKE_SUPER_RANGE_continue:
movl offClassObject_super(%eax),%eax # eax<- method->clazz->super
- movzwl offMethod_methodIndex(%ecx),%ecx # ecx<- baseMthod->methodIndex
- cmpl offClassObject_vtableCount(%eax),%ecx # compare(methodIndex,vtableCount)
+ movzwl offMethod_methodIndex(%ecx),%edx # edx<- baseMthod->methodIndex
+ cmpl offClassObject_vtableCount(%eax),%edx # compare(methodIndex,vtableCount)
jae .LOP_INVOKE_SUPER_RANGE_nsm # method not present in superclass
movl offClassObject_vtable(%eax),%eax # eax<- ...clazz->super->vtable
- movl (%eax,%ecx,4),%eax # eax<- vtable[methodIndex]
+ movl (%eax,%edx,4),%eax # eax<- vtable[methodIndex]
+ UNSPILL_TMP1(%edx)
+ movl %edx, %ecx
jmp common_invokeMethodRange
@@ -4169,7 +4519,7 @@
* eax = method->clazz
*/
.LOP_INVOKE_SUPER_RANGE_resolve:
- SPILL_TMP1(%eax) # method->clazz
+ SPILL_TMP2(%eax) # method->clazz
movl %eax,OUT_ARG0(%esp) # arg0<- method->clazz
movzwl 2(rPC),%ecx # ecx<- BBBB
movl $METHOD_VIRTUAL,OUT_ARG2(%esp) # arg2<- resolver method type
@@ -4177,7 +4527,7 @@
call dvmResolveMethod # eax<- call(clazz, ref, flags)
testl %eax,%eax # got null?
movl %eax,%ecx # ecx<- resolved base method
- UNSPILL_TMP1(%eax) # restore method->clazz
+ UNSPILL_TMP2(%eax) # restore method->clazz
jne .LOP_INVOKE_SUPER_RANGE_continue # good to go - continue
jmp common_exceptionThrown # handle exception
@@ -4262,9 +4612,17 @@
movl offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
EXPORT_PC
movl offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
+#if defined(WITH_JIT)
+ movl %edx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4), %edx
+ movl %edx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %edx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved methodToCall
+ movl $0, %ecx # make "this" null
testl %eax,%eax
jne common_invokeMethodRange
+
movl rSELF,%ecx
movl offThread_method(%ecx),%ecx # ecx<- self->method
movzwl 2(rPC),%eax
@@ -4273,10 +4631,40 @@
movl %ecx,OUT_ARG0(%esp) # arg0<- clazz
movl $METHOD_STATIC,%eax
movl %eax,OUT_ARG2(%esp) # arg2<- flags
+ SPILL(rIBASE)
call dvmResolveMethod # call(clazz,ref,flags)
+ UNSPILL(rIBASE)
testl %eax,%eax # got null?
+#if defined(WITH_JIT)
+ movl TMP_SPILL1(%ebp), %edx
+ movl rSELF,%ecx
+ movzwl offThread_subMode(%ecx), %ecx
+ je common_exceptionThrown # null, handle exception
+ andl $kSubModeJitTraceBuild, %ecx # is trace under construction?
+ movl $0, %ecx # make "this" null
+ je common_invokeMethodRange # no (%eax=method, %ecx="this")
+ movl TMP_SPILL2(%ebp), %edx
+ cmpl $0, (%edx) # finished resolving
+ movl TMP_SPILL1(%ebp), %edx
+ jne common_invokeMethodRange # yes (%eax=method, %ecx="this")
+ movl rSELF, %edx
+ movl %edx, OUT_ARG0(%esp)
+ movl rPC, OUT_ARG1(%esp)
+ movl %eax, TMP_SPILL2(%ebp)
+ movl %ecx, TMP_SPILL3(%ebp)
+ SPILL(rIBASE)
+ call dvmJitEndTraceSelect
+ UNSPILL(rIBASE)
+ movl TMP_SPILL1(%ebp), %edx
+ movl TMP_SPILL2(%ebp), %eax
+ movl TMP_SPILL3(%ebp), %ecx
+ jmp common_invokeMethodRange
+#else
+ movl $0, %ecx # make "this" null
jne common_invokeMethodRange
jmp common_exceptionThrown
+#endif
+
/* ------------------------------ */
@@ -4299,6 +4687,7 @@
EXPORT_PC
testl %eax,%eax # null this?
je common_errNullObject # yes, fail
+ movl %eax, TMP_SPILL1(%ebp)
movl offObject_clazz(%eax),%eax# eax<- thisPtr->clazz
movl %eax,OUT_ARG0(%esp) # arg0<- class
movl offThread_methodClassDex(%ecx),%eax # eax<- methodClassDex
@@ -4310,6 +4699,7 @@
call dvmFindInterfaceMethodInCache # eax<- call(class, ref, method, dex)
testl %eax,%eax
je common_exceptionThrown
+ movl TMP_SPILL1(%ebp), %ecx
jmp common_invokeMethodRange
@@ -5650,62 +6040,56 @@
/* ------------------------------ */
.L_OP_ADD_DOUBLE: /* 0xab */
/* File: x86/OP_ADD_DOUBLE.S */
-/* File: x86/binflop.S */
- /*
- * Generic 32-bit binary float operation.
- *
- * For: add-fp, sub-fp, mul-fp, div-fp
- */
- /* binop vAA, vBB, vCC */
- movzbl 2(rPC),%eax # eax<- CC
- movzbl 3(rPC),%ecx # ecx<- BB
- fldl (rFP,%eax,4) # vCC to fp stack
- faddl (rFP,%ecx,4) # ex: faddp
+ /*
+ * File: OP_ADD_DOUBLE.S
+ */
+
+ movzbl 2(rPC),%eax # eax<- BB
+ movzbl 3(rPC),%ecx # ecx<- CC
+ movq (rFP, %eax, 4), %xmm0 # %xmm0<- vBB
+ movq (rFP, %ecx, 4), %xmm1 # %xmm1<- vCC
FETCH_INST_OPCODE 2 %ecx
+ addsd %xmm1, %xmm0
ADVANCE_PC 2
- fstpl (rFP,rINST,4) # %st to vAA
+ movq %xmm0, (rFP, rINST, 4) # vAA<- vBB * vCC
GOTO_NEXT_R %ecx
/* ------------------------------ */
.L_OP_SUB_DOUBLE: /* 0xac */
/* File: x86/OP_SUB_DOUBLE.S */
-/* File: x86/binflop.S */
- /*
- * Generic 32-bit binary float operation.
- *
- * For: add-fp, sub-fp, mul-fp, div-fp
- */
- /* binop vAA, vBB, vCC */
- movzbl 2(rPC),%eax # eax<- CC
- movzbl 3(rPC),%ecx # ecx<- BB
- fldl (rFP,%eax,4) # vCC to fp stack
- fsubl (rFP,%ecx,4) # ex: faddp
- FETCH_INST_OPCODE 2 %ecx
- ADVANCE_PC 2
- fstpl (rFP,rINST,4) # %st to vAA
- GOTO_NEXT_R %ecx
+ /*
+ * File: OP_SUB_DOUBLE.S
+ */
+ movzbl 2(rPC),%eax # eax<- BB
+ movzbl 3(rPC),%ecx # ecx<- CC
+ # TODO: movsd?
+ movq (rFP, %eax, 4), %xmm0 # %xmm0<- vBB
+ movq (rFP, %ecx, 4), %xmm1 # %xmm1<- vCC
+ FETCH_INST_OPCODE 2 %ecx
+ subsd %xmm1, %xmm0
+ ADVANCE_PC 2
+ movq %xmm0, (rFP, rINST, 4) # vAA<- vBB - vCC
+ GOTO_NEXT_R %ecx
/* ------------------------------ */
.L_OP_MUL_DOUBLE: /* 0xad */
/* File: x86/OP_MUL_DOUBLE.S */
-/* File: x86/binflop.S */
- /*
- * Generic 32-bit binary float operation.
- *
- * For: add-fp, sub-fp, mul-fp, div-fp
- */
- /* binop vAA, vBB, vCC */
- movzbl 2(rPC),%eax # eax<- CC
- movzbl 3(rPC),%ecx # ecx<- BB
- fldl (rFP,%eax,4) # vCC to fp stack
- fmull (rFP,%ecx,4) # ex: faddp
- FETCH_INST_OPCODE 2 %ecx
- ADVANCE_PC 2
- fstpl (rFP,rINST,4) # %st to vAA
- GOTO_NEXT_R %ecx
+ /*
+ * File: OP_MUL_DOUBLE.S
+ */
+ movzbl 2(rPC),%eax # eax<- BB
+ movzbl 3(rPC),%ecx # ecx<- CC
+ # TODO: movsd?
+ movq (rFP, %eax, 4), %xmm0 # %xmm0<- vBB
+ movq (rFP, %ecx, 4), %xmm1 # %xmm1<- vCC
+ FETCH_INST_OPCODE 2 %ecx
+ mulsd %xmm1, %xmm0
+ ADVANCE_PC 2
+ movq %xmm0, (rFP, rINST, 4) # vAA<- vBB * vCC
+ GOTO_NEXT_R %ecx
/* ------------------------------ */
.L_OP_DIV_DOUBLE: /* 0xae */
@@ -5753,11 +6137,7 @@
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
- * This could be an ARM instruction or a function call. (If the result
- * comes back in a register other than r0, you can override "result".)
- *
- * If "chkzero" is set to 1, we perform a divide-by-zero check on
- * vCC (r1). Useful for integer division and modulus.
+ * This could be an instruction or a function call.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
@@ -5766,7 +6146,7 @@
*/
/* binop/2addr vA, vB */
movzx rINSTbl,%ecx # ecx<- A+
- sarl $4,rINST # rINST<- B
+ sarl $4,rINST # rINST<- B
GET_VREG_R %eax rINST # eax<- vB
andb $0xf,%cl # ecx<- A
addl %eax,(rFP,%ecx,4) # for ex: addl %eax,(rFP,%ecx,4)
@@ -5782,11 +6162,7 @@
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
- * This could be an ARM instruction or a function call. (If the result
- * comes back in a register other than r0, you can override "result".)
- *
- * If "chkzero" is set to 1, we perform a divide-by-zero check on
- * vCC (r1). Useful for integer division and modulus.
+ * This could be an instruction or a function call.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
@@ -5795,7 +6171,7 @@
*/
/* binop/2addr vA, vB */
movzx rINSTbl,%ecx # ecx<- A+
- sarl $4,rINST # rINST<- B
+ sarl $4,rINST # rINST<- B
GET_VREG_R %eax rINST # eax<- vB
andb $0xf,%cl # ecx<- A
subl %eax,(rFP,%ecx,4) # for ex: addl %eax,(rFP,%ecx,4)
@@ -5903,11 +6279,7 @@
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
- * This could be an ARM instruction or a function call. (If the result
- * comes back in a register other than r0, you can override "result".)
- *
- * If "chkzero" is set to 1, we perform a divide-by-zero check on
- * vCC (r1). Useful for integer division and modulus.
+ * This could be an instruction or a function call.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
@@ -5916,7 +6288,7 @@
*/
/* binop/2addr vA, vB */
movzx rINSTbl,%ecx # ecx<- A+
- sarl $4,rINST # rINST<- B
+ sarl $4,rINST # rINST<- B
GET_VREG_R %eax rINST # eax<- vB
andb $0xf,%cl # ecx<- A
andl %eax,(rFP,%ecx,4) # for ex: addl %eax,(rFP,%ecx,4)
@@ -5932,11 +6304,7 @@
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
- * This could be an ARM instruction or a function call. (If the result
- * comes back in a register other than r0, you can override "result".)
- *
- * If "chkzero" is set to 1, we perform a divide-by-zero check on
- * vCC (r1). Useful for integer division and modulus.
+ * This could be an instruction or a function call.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
@@ -5945,7 +6313,7 @@
*/
/* binop/2addr vA, vB */
movzx rINSTbl,%ecx # ecx<- A+
- sarl $4,rINST # rINST<- B
+ sarl $4,rINST # rINST<- B
GET_VREG_R %eax rINST # eax<- vB
andb $0xf,%cl # ecx<- A
orl %eax,(rFP,%ecx,4) # for ex: addl %eax,(rFP,%ecx,4)
@@ -5961,11 +6329,7 @@
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
- * This could be an ARM instruction or a function call. (If the result
- * comes back in a register other than r0, you can override "result".)
- *
- * If "chkzero" is set to 1, we perform a divide-by-zero check on
- * vCC (r1). Useful for integer division and modulus.
+ * This could be an instruction or a function call.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
@@ -5974,7 +6338,7 @@
*/
/* binop/2addr vA, vB */
movzx rINSTbl,%ecx # ecx<- A+
- sarl $4,rINST # rINST<- B
+ sarl $4,rINST # rINST<- B
GET_VREG_R %eax rINST # eax<- vB
andb $0xf,%cl # ecx<- A
xorl %eax,(rFP,%ecx,4) # for ex: addl %eax,(rFP,%ecx,4)
@@ -6490,69 +6854,59 @@
/* ------------------------------ */
.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
/* File: x86/OP_ADD_DOUBLE_2ADDR.S */
-/* File: x86/binflop2addr.S */
- /*
- * Generic 32-bit binary float operation.
- *
- * For: add-fp, sub-fp, mul-fp, div-fp
- */
+ /*
+ * File: OP_ADD_DOUBLE_2ADDR.S
+ */
- /* binop/2addr vA, vB */
- movzx rINSTbl,%ecx # ecx<- A+
- andb $0xf,%cl # ecx<- A
- fldl (rFP,%ecx,4) # vAA to fp stack
- sarl $4,rINST # rINST<- B
- faddl (rFP,rINST,4) # ex: faddp
+ movzx rINSTbl,%ecx # ecx<- A+
+ andb $0xf,%cl # ecx<- A
+ sarl $4,rINST # rINST<- B
+ movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
+ movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vA
FETCH_INST_OPCODE 1 %eax
+ addsd %xmm1, %xmm0 # %xmm0<- vA op vB
ADVANCE_PC 1
- fstpl (rFP,%ecx,4) # %st to vA
+ movq %xmm0, (rFP, %ecx, 4) # vA<- %xmm0; result
GOTO_NEXT_R %eax
-
/* ------------------------------ */
.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
/* File: x86/OP_SUB_DOUBLE_2ADDR.S */
-/* File: x86/binflop2addr.S */
- /*
- * Generic 32-bit binary float operation.
- *
- * For: add-fp, sub-fp, mul-fp, div-fp
- */
+ /*
+ * File: OP_SUB_DOUBLE_2ADDR.S
+ */
- /* binop/2addr vA, vB */
- movzx rINSTbl,%ecx # ecx<- A+
- andb $0xf,%cl # ecx<- A
- fldl (rFP,%ecx,4) # vAA to fp stack
- sarl $4,rINST # rINST<- B
- fsubl (rFP,rINST,4) # ex: faddp
+ movzx rINSTbl,%ecx # ecx<- A+
+ andb $0xf,%cl # ecx<- A
+ sarl $4,rINST # rINST<- B
+ # TODO: movsd?
+ movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
+ movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vA
FETCH_INST_OPCODE 1 %eax
+ subsd %xmm1, %xmm0 # %xmm0<- vA op vB
ADVANCE_PC 1
- fstpl (rFP,%ecx,4) # %st to vA
+ movq %xmm0, (rFP, %ecx, 4) # vA<- %xmm0; result
GOTO_NEXT_R %eax
-
/* ------------------------------ */
.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
/* File: x86/OP_MUL_DOUBLE_2ADDR.S */
-/* File: x86/binflop2addr.S */
- /*
- * Generic 32-bit binary float operation.
- *
- * For: add-fp, sub-fp, mul-fp, div-fp
- */
+ /*
+ * File: OP_MUL_DOUBLE_2ADDR.S
+ */
- /* binop/2addr vA, vB */
- movzx rINSTbl,%ecx # ecx<- A+
- andb $0xf,%cl # ecx<- A
- fldl (rFP,%ecx,4) # vAA to fp stack
- sarl $4,rINST # rINST<- B
- fmull (rFP,rINST,4) # ex: faddp
+ movzx rINSTbl,%ecx # ecx<- A+
+ andb $0xf,%cl # ecx<- A
+ sarl $4,rINST # rINST<- B
+ # TODO: movsd?
+ movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
+ movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vA
FETCH_INST_OPCODE 1 %eax
+ mulsd %xmm1, %xmm0 # %xmm0<- vA op vB
ADVANCE_PC 1
- fstpl (rFP,%ecx,4) # %st to vA
+ movq %xmm0, (rFP, %ecx, 4) # vA<- %xmm0; result
GOTO_NEXT_R %eax
-
/* ------------------------------ */
.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
/* File: x86/OP_DIV_DOUBLE_2ADDR.S */
@@ -7229,6 +7583,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SGET_VOLATILE_resolve # if not, make it so
@@ -7254,8 +7614,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SGET_VOLATILE_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SGET_VOLATILE_finish # success, continue
/* ------------------------------ */
@@ -7272,6 +7638,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SPUT_VOLATILE_resolve # if not, make it so
@@ -7288,7 +7660,7 @@
.LOP_SPUT_VOLATILE_resolve:
movl rSELF,%ecx
movzwl 2(rPC),%eax # eax<- field ref BBBB
- movl offThread_method(%ecx),%ecx # ecx<- current method
+ movl offThread_method(%ecx),%ecx # ecx<- current method
EXPORT_PC # could throw, need to export
movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
movl %eax,OUT_ARG1(%esp)
@@ -7297,9 +7669,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SPUT_VOLATILE_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
-
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SPUT_VOLATILE_finish # success, continue
/* ------------------------------ */
.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
@@ -7456,14 +7833,18 @@
movl rSELF,%ecx
EXPORT_PC
movzwl 2(rPC),%eax # eax<- BBBB
- leal offThread_retval(%ecx),%ecx # ecx<- & self->retval
SPILL(rIBASE) # preserve rIBASE
+ movl offThread_subMode(%ecx), %edx # edx<- submode flags
+ andl $kSubModeDebugProfile, %edx # debug or profile mode active?
+ jnz .LOP_EXECUTE_INLINE_debugprofile # yes, take slow path
+.LOP_EXECUTE_INLINE_resume:
+ leal offThread_retval(%ecx),%ecx # ecx<- &self->retval
movl %ecx,OUT_ARG4(%esp)
call .LOP_EXECUTE_INLINE_continue # make call; will return after
UNSPILL(rIBASE) # restore rIBASE
testl %eax,%eax # successful?
+ jz common_exceptionThrown # no, handle exception
FETCH_INST_OPCODE 3 %ecx
- je common_exceptionThrown # no, handle exception
ADVANCE_PC 3
GOTO_NEXT_R %ecx
@@ -7507,6 +7888,42 @@
jmp *gDvmInlineOpsTable(%eax)
# will return to caller of .LOP_EXECUTE_INLINE_continue
+ /*
+ * We're debugging or profiling.
+ * eax: opIndex
+ */
+.LOP_EXECUTE_INLINE_debugprofile:
+ movl %eax,OUT_ARG0(%esp) # arg0<- BBBB
+ SPILL_TMP1(%eax) # save opIndex
+ call dvmResolveInlineNative # dvmResolveInlineNative(opIndex)
+ movl rSELF,%ecx # restore self
+ testl %eax,%eax # method resolved?
+ movl %eax,%edx # save possibly resolved method in edx
+ UNSPILL_TMP1(%eax) # in case not resolved, restore opIndex
+ jz .LOP_EXECUTE_INLINE_resume # not resolved, just move on
+ SPILL_TMP2(%edx) # save method
+ movl %edx,OUT_ARG0(%esp) # arg0<- method
+ movl %ecx,OUT_ARG1(%esp) # arg1<- self
+ call dvmFastMethodTraceEnter # dvmFastMethodTraceEnter(method,self)
+ movl rSELF,%ecx # restore self
+ UNSPILL_TMP1(%eax) # restore opIndex
+ leal offThread_retval(%ecx),%ecx # ecx<- &self->retval
+ movl %ecx,OUT_ARG4(%esp) # needed for pResult of inline operation handler
+ call .LOP_EXECUTE_INLINE_continue # make call; will return after
+ SPILL_TMP1(%eax) # save result of inline
+ UNSPILL_TMP2(%eax) # restore method
+ movl rSELF,%ecx # restore self
+ movl %eax,OUT_ARG0(%esp) # arg0<- method
+ movl %ecx,OUT_ARG1(%esp) # arg1<- self
+ call dvmFastNativeMethodTraceExit # dvmFastNativeMethodTraceExit(method,self)
+ UNSPILL(rIBASE) # restore rIBASE
+ UNSPILL_TMP1(%eax) # restore result of inline
+ testl %eax,%eax # successful?
+ jz common_exceptionThrown # no, handle exception
+ FETCH_INST_OPCODE 3 %ecx
+ ADVANCE_PC 3
+ GOTO_NEXT_R %ecx
+
/* ------------------------------ */
.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */
/* (stub) */
@@ -7673,18 +8090,18 @@
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
- movzwl 4(rPC),%eax # eax<- FEDC or CCCC
- movzwl 2(rPC),%ecx # ecx<- BBBB
+ movzwl 4(rPC),%ecx # eax<- FEDC or CCCC
+ movzwl 2(rPC),%edx # ecx<- BBBB
.if (!0)
- andl $0xf,%eax # eax<- C (or stays CCCC)
+ andl $0xf,%ecx # eax<- C (or stays CCCC)
.endif
- GET_VREG_R %eax %eax # eax<- vC ("this" ptr)
- testl %eax,%eax # null?
+ GET_VREG_R %ecx %ecx # ecx<- vC ("this" ptr)
+ testl %ecx,%ecx # null?
je common_errNullObject # yep, throw exception
- movl offObject_clazz(%eax),%eax # eax<- thisPtr->clazz
+ movl offObject_clazz(%ecx),%eax # eax<- thisPtr->clazz
movl offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
EXPORT_PC # might throw later - get ready
- movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
+ movl (%eax,%edx,4),%eax # eax<- vtable[BBBB]
jmp common_invokeMethodNoRange
/* ------------------------------ */
@@ -7698,18 +8115,18 @@
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
- movzwl 4(rPC),%eax # eax<- FEDC or CCCC
- movzwl 2(rPC),%ecx # ecx<- BBBB
+ movzwl 4(rPC),%ecx # eax<- FEDC or CCCC
+ movzwl 2(rPC),%edx # ecx<- BBBB
.if (!1)
- andl $0xf,%eax # eax<- C (or stays CCCC)
+ andl $0xf,%ecx # eax<- C (or stays CCCC)
.endif
- GET_VREG_R %eax %eax # eax<- vC ("this" ptr)
- testl %eax,%eax # null?
+ GET_VREG_R %ecx %ecx # ecx<- vC ("this" ptr)
+ testl %ecx,%ecx # null?
je common_errNullObject # yep, throw exception
- movl offObject_clazz(%eax),%eax # eax<- thisPtr->clazz
+ movl offObject_clazz(%ecx),%eax # eax<- thisPtr->clazz
movl offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
EXPORT_PC # might throw later - get ready
- movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
+ movl (%eax,%edx,4),%eax # eax<- vtable[BBBB]
jmp common_invokeMethodRange
@@ -7734,10 +8151,12 @@
movl offClassObject_super(%ecx),%ecx # ecx<- method->clazz->super
testl %eax,%eax # null "this"?
je common_errNullObject # "this" is null, throw exception
+ movl %eax, TMP_SPILL1(%ebp)
movzwl 2(rPC),%eax # eax<- BBBB
movl offClassObject_vtable(%ecx),%ecx # ecx<- vtable
EXPORT_PC
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
+ movl TMP_SPILL1(%ebp), %ecx
jmp common_invokeMethodNoRange
/* ------------------------------ */
@@ -7762,10 +8181,12 @@
movl offClassObject_super(%ecx),%ecx # ecx<- method->clazz->super
testl %eax,%eax # null "this"?
je common_errNullObject # "this" is null, throw exception
+ movl %eax, TMP_SPILL1(%ebp)
movzwl 2(rPC),%eax # eax<- BBBB
movl offClassObject_vtable(%ecx),%ecx # ecx<- vtable
EXPORT_PC
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
+ movl TMP_SPILL1(%ebp), %ecx
jmp common_invokeMethodRange
@@ -7844,6 +8265,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .LOP_SGET_OBJECT_VOLATILE_resolve # if not, make it so
@@ -7869,8 +8296,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SGET_OBJECT_VOLATILE_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SGET_OBJECT_VOLATILE_finish # success, continue
/* ------------------------------ */
@@ -7885,6 +8318,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField
testl %eax,%eax # resolved entry null?
je .LOP_SPUT_OBJECT_VOLATILE_resolve # if not, make it so
@@ -7916,8 +8355,14 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .LOP_SPUT_OBJECT_VOLATILE_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .LOP_SPUT_OBJECT_VOLATILE_finish # success, continue
/* ------------------------------ */
@@ -15164,11 +15609,19 @@
movl offThread_curFrame(%ecx),rFP
movl offThread_curHandlerTable(%ecx),rIBASE
-/* Remember %esp for future "longjmp" */
+ /* Remember %esp for future "longjmp" */
movl %esp,offThread_bailPtr(%ecx)
- /* Normal case: start executing the instruction at rPC */
+ /* Fetch next instruction before potential jump */
FETCH_INST
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ movl $0, offThread_inJitCodeCache(%ecx)
+ cmpl $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
+
+ /* Normal case: start executing the instruction at rPC */
GOTO_NEXT
.global dvmMterpStdBail
@@ -15190,7 +15643,7 @@
dvmMterpStdBail:
movl 4(%esp),%ecx # grab self
movl 8(%esp),%eax # changeInterp to return reg
- movl offThread_bailPtr(%ecx),%esp # Restore "setjmp" esp
+ movl offThread_bailPtr(%ecx),%esp # Restore "setjmp" esp
movl %esp,%ebp
addl $(FRAME_SIZE-4), %ebp # Restore %ebp at point of setjmp
movl EDI_SPILL(%ebp),%edi
@@ -15201,6 +15654,18 @@
ret # return to dvmMterpStdRun's caller
+#ifdef WITH_JIT
+ .global dvmNcgInvokeInterpreter
+ .type dvmNcgInvokeInterpreter, %function
+/* input: start of method in %eax */
+dvmNcgInvokeInterpreter:
+ movl %eax, rPC
+ movl rSELF, %ecx
+ movl offThread_curHandlerTable(%ecx),rIBASE
+ FETCH_INST_R %ecx # %edx<- opcode
+ GOTO_NEXT_R %ecx # start executing the instruction at rPC
+#endif
+
/*
* Strings
*/
@@ -15247,12 +15712,14 @@
* the interpreter and code cache. rPC must be set on entry.
*/
dvmJitToInterpPunt:
+ GET_PC
#if defined(WITH_JIT_TUNING)
movl rPC, OUT_ARG0(%esp)
call dvmBumpPunt
#endif
movl rSELF, %ecx
movl offThread_curHandlerTable(%ecx),rIBASE
+ movl $0, offThread_inJitCodeCache(%ecx)
FETCH_INST_R %ecx
GOTO_NEXT_R %ecx
@@ -15289,17 +15756,19 @@
#if defined(WITH_JIT_TUNING)
call dvmBumpNoChain
#endif
+ movl %eax, rPC
movl rSELF, %eax
movl rPC,OUT_ARG0(%esp)
movl %eax,OUT_ARG1(%esp)
- call dvmJitGetTraceAddrThread # (pc, self)
+ call dvmJitGetTraceAddrThread # (pc, self)
movl rSELF,%ecx # ecx <- self
movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
cmpl $0, %eax
jz 1f
- call *%eax # exec translation if we've got one
+ jmp *%eax # exec translation if we've got one
# won't return
1:
+ EXPORT_PC
movl rSELF, %ecx
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_R %ecx
@@ -15307,7 +15776,7 @@
/*
* Return from the translation cache and immediately request a
- * translation fro the exit target, but don't attempt to chain.
+ * translation from the exit target, but don't attempt to chain.
* rPC set on entry.
*/
.global dvmJitToInterpTraceSelectNoChain
@@ -15315,15 +15784,17 @@
#if defined(WITH_JIT_TUNING)
call dvmBumpNoChain
#endif
+ movl %ebx, rPC
+ lea 4(%esp), %esp #to recover the esp update due to function call
movl rSELF, %eax
movl rPC,OUT_ARG0(%esp)
movl %eax,OUT_ARG1(%esp)
- call dvmJitGetTraceAddrThread # (pc, self)
+ call dvmJitGetTraceAddrThread # (pc, self)
movl rSELF,%ecx
cmpl $0,%eax
movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
jz 1f
- call *%eax # jump to tranlation
+ jmp *%eax # jump to tranlation
# won't return
/* No Translation - request one */
@@ -15336,7 +15807,8 @@
FETCH_INST_R %ecx # Continue interpreting if not
GOTO_NEXT_R %ecx
2:
- movl $kJitTSelectRequestHot,rINST # ask for trace select
+ ## Looks like an EXPORT_PC is needed here. Now jmp to common_selectTrace2
+ movl $kJitTSelectRequestHot,%eax # ask for trace select
jmp common_selectTrace
/*
@@ -15346,21 +15818,32 @@
*/
.global dvmJitToInterpTraceSelect
dvmJitToInterpTraceSelect:
- pop rINST # save chain cell address in callee save reg
- movl (rINST),rPC
+ movl 0(%esp), %eax # get return address
+ movl %ebx, rPC # get first argument (target rPC)
+
+ ## TODO, need to clean up stack manipulation ... this isn't signal safe and
+ ## doesn't use the calling conventions of header.S
+ lea 4(%esp), %esp #to recover the esp update due to function call
+
+ ## An additional 5B instruction "jump 0" was added for a thread-safe
+ ## chaining cell update in JIT code cache. So the offset is now -17=-12-5.
+ lea -17(%eax), %ebx #$JIT_OFFSET_CHAIN_START(%eax), %ebx
+ lea -4(%esp), %esp
movl rSELF, %eax
movl rPC,OUT_ARG0(%esp)
movl %eax,OUT_ARG1(%esp)
call dvmJitGetTraceAddrThread # (pc, self)
+ lea 4(%esp), %esp
cmpl $0,%eax
+ movl rSELF, %ecx
+ movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
jz 1b # no - ask for one
movl %eax,OUT_ARG0(%esp)
-# TODO - need to adjust rINST to beginning of sequence
movl rINST,OUT_ARG1(%esp)
call dvmJitChain # Attempt dvmJitChain(codeAddr,chainAddr)
cmpl $0,%eax # Success?
jz toInterpreter # didn't chain - interpret
- call *%eax
+ jmp *%eax
# won't return
/*
@@ -15368,71 +15851,210 @@
*/
.global dvmJitToInterpBackwardBranch
dvmJitToInterpBackwardBranch:
+
+ .global dvmJitToExceptionThrown
+dvmJitToExceptionThrown: //rPC in
+ movl rSELF, %edx
+ GET_PC
+ movl $0, offThread_inJitCodeCache(%edx)
+ jmp common_exceptionThrown
+
.global dvmJitToInterpNormal
dvmJitToInterpNormal:
+/* one input: the target rPC value */
+ movl 0(%esp), %eax # get return address
+ movl %ebx, rPC # get first argument (target rPC)
+
+ ## TODO, need to clean up stack manipulation ... this isn't signal safe and
+ ## doesn't use the calling conventions of header.S
+
+ ## An additional 5B instruction "jump 0" was added for a thread-safe
+ ## chaining cell update in JIT code cache. So the offset is now -17=-12-5.
+ lea -17(%eax), %ebx #$JIT_OFFSET_CHAIN_START(%eax), %ebx
+ lea 4(%esp), %esp
+ movl rPC, OUT_ARG0(%esp)
+ movl rSELF, %ecx
+ movl %ecx, OUT_ARG1(%esp)
+ call dvmJitGetTraceAddrThread
+ ## Here is the change from using rGLUE to rSELF for accessing the
+ ## JIT code cache flag
+ movl rSELF, %ecx
+ movl %eax, offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
+ #lea 4(%esp), %esp
+ cmp $0, %eax
+ je toInterpreter
+ #lea -8(%esp), %esp
+ movl %ebx, OUT_ARG1(%esp) # %ebx live thorugh dvmJitGetTraceAddrThread
+ movl %eax, OUT_ARG0(%esp) # first argument
+ call dvmJitChain
+ #lea 8(%esp), %esp
+ cmp $0, %eax
+ je toInterpreter
+ jmp *%eax #to native address
+
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
+dvmJitToInterpNoChain: #rPC in eax
+ ## TODO, need to clean up stack manipulation ... this isn't signal safe and
+ ## doesn't use the calling conventions of header.S
+ movl %eax, rPC
+ movl rPC, OUT_ARG0(%esp)
+ movl rSELF, %ecx
+ movl %ecx, OUT_ARG1(%esp)
+ call dvmJitGetTraceAddrThread
+ ## Here is the change from using rGLUE to rSELF for accessing the
+ ## JIT code cache flag
+ movl rSELF, %ecx
+ movl %eax, offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
+ cmp $0, %eax
+ je toInterpreter
+ jmp *%eax #to native address
+
toInterpreter:
- jmp common_abort
+ EXPORT_PC
+ movl rSELF, %ecx
+ movl offThread_curHandlerTable(%ecx), rIBASE
+ FETCH_INST
+ movl offThread_pJitProfTable(%ecx), %eax
+ #Fallthrough
+
+/* ebx holds the pointer to the jit profile table
+ edx has the opCode */
+common_testUpdateProfile:
+ cmp $0, %eax
+ je 4f
+/* eax holds the pointer to the jit profile table
+ edx has the opCode
+ rPC points to the next bytecode */
common_updateProfile:
# quick & dirty hash
- movl rPC, %eax
- shrl $12, %eax
- xorl rPC, %eax
- andl $((1<<JIT_PROF_SIZE_LOG_2)-1),%eax
- decb (%edx,%eax)
+ movl rPC, %ecx
+ shrl $12, %ecx
+ xorl rPC, %ecx
+ andl $((1<<JIT_PROF_SIZE_LOG_2)-1), %ecx
+ decb (%ecx,%eax)
+ #jmp 1f # remove
jz 2f
1:
GOTO_NEXT
2:
+common_Profile:
/*
* Here, we switch to the debug interpreter to request
* trace selection. First, though, check to see if there
* is already a native translation in place (and, if so,
* jump to it now.
*/
- GET_JIT_THRESHOLD %ecx rINST # leaves rSELF in %ecx
+ SPILL(rIBASE)
+ SPILL_TMP1(rINST)
+ movl rSELF, rIBASE
+ GET_JIT_THRESHOLD rIBASE rINST # leaves rSELF in %ecx
EXPORT_PC
- movb rINSTbl,(%edx,%eax) # reset counter
- movl %ecx,rINST # preserve rSELF
+ movb rINSTbl,(%ecx,%eax) # reset counter
+ movl rIBASE,rINST # preserve rSELF
movl rSELF, %eax
movl rPC,OUT_ARG0(%esp)
- movl %eax,OUT_ARG1(%esp)
- call dvmJitGetTraceAddr # (pc, self)
+ movl rIBASE,OUT_ARG1(%esp)
+ call dvmJitGetTraceAddrThread # (pc, self)
+ UNSPILL(rIBASE)
movl %eax,offThread_inJitCodeCache(rINST) # set the inJitCodeCache flag
+ UNSPILL_TMP1(rINST)
cmpl $0,%eax
+ #jmp 1f # remove
jz 1f
- call *%eax # TODO: decide call vs/ jmp!. No return either way
+ jmp *%eax # TODO: decide call vs/ jmp!. No return either way
1:
movl $kJitTSelectRequest,%eax
# On entry, eax<- jitState, rPC valid
common_selectTrace:
-/* TODO */
- call dvmAbort
-#if 0
- movl rSELF,%ecx
- movl %eax,offThread_jitState(%ecx)
- movl $kInterpEntryInstr,offThread_entryPoint(%ecx)
- movl $1,rINST
- jmp common_gotoBail
-#endif
-#endif
+ mov %ebx, EBX_SPILL(%ebp)
+ movl rSELF, %ebx
+ movzwl offThread_subMode(%ebx), %ecx
+ and $(kSubModeJitTraceBuild | kSubModeJitSV), %ecx
+ jne 3f # already doing JIT work, continue
+ movl %eax, offThread_jitState(%ebx)
+ movl rSELF, %eax
+ movl %eax, OUT_ARG0(%esp)
+
+/*
+ * Call out to validate trace-building request. If successful, rIBASE will be swapped
+ * to send us into single-steppign trace building mode, so we need to refresh before
+ * we continue.
+ */
+
+ EXPORT_PC
+ SAVE_PC_FP_TO_SELF %ecx
+ call dvmJitCheckTraceRequest
+3:
+ mov EBX_SPILL(%ebp), %ebx
+ FETCH_INST
+ movl rSELF, %ecx
+ movl offThread_curHandlerTable(%ecx), rIBASE
+4:
+ GOTO_NEXT
+
+common_selectTrace2:
+ mov %ebx, EBX_SPILL(%ebp)
+ movl rSELF, %ebx
+ movl %ebx, OUT_ARG0(%esp)
+ movl %eax, offThread_jitState(%ebx)
+ movzwl offThread_subMode(%ebx), %ecx
+ mov EBX_SPILL(%ebp), %ebx
+ and (kSubModeJitTraceBuild | kSubModeJitSV), %ecx
+ jne 3f # already doing JIT work, continue
/*
+ * Call out to validate trace-building request. If successful, rIBASE will be swapped
+ * to send us into single-steppign trace building mode, so we need to refresh before
+ * we continue.
+ */
+
+ EXPORT_PC
+ SAVE_PC_FP_TO_SELF %ecx
+ call dvmJitCheckTraceRequest
+3:
+ FETCH_INST
+ movl rSELF, %ecx
+ movl offThread_curHandlerTable(%ecx), rIBASE
+4:
+ GOTO_NEXT
+
+#endif
+
+/*
+ * For the invoke codes we need to know what register holds the "this" pointer. However
+ * it seems the this pointer is assigned consistently most times it is in %ecx but other
+ * times it is in OP_INVOKE_INTERFACE_JUMBO OP_INVOKE_INTERFACE OP_INVOKE_SUPER_QUICK and
+ * OP_INVOKE_VIRTUAL_QUICK
+*/
+
+/*
* Common code for method invocation with range.
*
* On entry:
* eax = Method* methodToCall
+ * ecx = "this"
* rINSTw trashed, must reload
* rIBASE trashed, must reload before resuming interpreter
*/
common_invokeMethodRange:
.LinvokeNewRange:
-
+#if defined(WITH_JIT)
+ SPILL_TMP1(%edx)
+ SPILL_TMP2(%ebx)
+ movl rSELF, %edx
+ movzwl offThread_subMode(%edx), %ebx
+ and $kSubModeJitTraceBuild, %ebx
+ jz 6f
+ call save_callsiteinfo
+6:
+ UNSPILL_TMP2(%ebx)
+ UNSPILL_TMP1(%edx)
+#endif
/*
* prepare to copy args to "outs" area of current frame
*/
@@ -15474,6 +16096,18 @@
*/
common_invokeMethodNoRange:
+#if defined(WITH_JIT)
+ SPILL_TMP1(%edx)
+ SPILL_TMP2(%ebx)
+ movl rSELF, %edx
+ movzwl offThread_subMode(%edx), %ebx
+ and $kSubModeJitTraceBuild, %ebx
+ jz 6f
+ call save_callsiteinfo
+6:
+ UNSPILL_TMP2(%ebx)
+ UNSPILL_TMP1(%edx)
+#endif
.LinvokeNewNoRange:
movzbl 1(rPC),rINST # rINST<- BA
movl rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
@@ -15561,6 +16195,9 @@
movl rSELF,%ecx # %ecx<- pthread
movl rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
movl rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
+#if defined(WITH_JIT)
+ movl $0, offStackSaveArea_returnAddr(%edx)
+#endif
/* Any special actions to take? */
cmpw $0, offThread_subMode(%ecx)
@@ -15584,6 +16221,12 @@
movl rFP, offThread_curFrame(%ecx) # curFrame<-newFP
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST
+#if defined(WITH_JIT)
+ /* rPC is already updated */
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT # jump to methodToCall->insns
2:
@@ -15643,8 +16286,8 @@
*/
SPILL_TMP1(%eax) # save methodTocall
movl rPC, offThread_pc(%ecx)
- movl %eax, OUT_ARG0(%esp)
movl %ecx, OUT_ARG1(%esp)
+ movl %eax, OUT_ARG0(%esp)
movl rFP, OUT_ARG2(%esp)
call dvmReportPreNativeInvoke # (methodToCall, self, fp)
UNSPILL_TMP1(%eax) # restore methodToCall
@@ -15660,8 +16303,8 @@
UNSPILL_TMP1(%eax) # restore methodToCall
movl rSELF, %ecx
- movl %eax, OUT_ARG0(%esp)
movl %ecx, OUT_ARG1(%esp)
+ movl %eax, OUT_ARG0(%esp)
movl rFP, OUT_ARG2(%esp)
call dvmReportPostNativeInvoke # (methodToCall, self, fp)
jmp 7b # rejoin
@@ -15678,36 +16321,68 @@
* Common code for handling a return instruction
*/
common_returnFromMethod:
- movl rSELF,%ecx
- SAVEAREA_FROM_FP %eax # eax<- saveArea (old)
+ movl rSELF, %ecx
+ SAVEAREA_FROM_FP %eax # %eax<- saveArea(old)
cmpw $0, offThread_subMode(%ecx) # special action needed?
jne 19f # go if so
14:
- movl offStackSaveArea_prevFrame(%eax),rFP # rFP<- prevFrame
- movl (offStackSaveArea_method-sizeofStackSaveArea)(rFP),rINST
- cmpl $0,rINST # break?
- je common_gotoBail # break frame, bail out completely
- movl offStackSaveArea_savedPc(%eax),rPC # pc<- saveArea->savedPC
- movl rINST,offThread_method(%ecx) # self->method = newSave->meethod
- movl rFP,offThread_curFrame(%ecx) # curFrame = fp
- movl offMethod_clazz(rINST),%eax # eax<- method->clazz
- movl offThread_curHandlerTable(%ecx),rIBASE
- movl offClassObject_pDvmDex(%eax),rINST # rINST<- method->clazz->pDvmDex
- FETCH_INST_OPCODE 3 %eax
- movl rINST,offThread_methodClassDex(%ecx)
+ movl offStackSaveArea_prevFrame(%eax), rFP # rFP<- saveArea->PrevFrame
+ movl (offStackSaveArea_method - sizeofStackSaveArea)(rFP), rINST # rINST<- method we are returning to
+ cmpl $0, rINST # check for break frame
+ je common_gotoBail # bail if break frame
+ movl offThread_curHandlerTable(%ecx),rIBASE
+ movl offStackSaveArea_savedPc(%eax), rPC # rPC<- saveAreaOld->savedPc
+#if defined(WITH_JIT)
+ movl offStackSaveArea_returnAddr(%eax), %ecx
+#endif
+ movl rSELF, %eax
+ movl rINST, offThread_method(%eax) # glue->method<- newSave->method
+ movl offMethod_clazz(rINST), rINST # rINST<- method->clazz
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
+#if defined(WITH_JIT)
+ //update self->offThread_inJitCodeCache
+ movl %ecx, offThread_inJitCodeCache(%eax)
+#endif
+ movl offClassObject_pDvmDex(rINST), rINST # rINST<- method->clazz->pDvmDex
+ movl rINST, offThread_methodClassDex(%eax) # glue->pDvmDex<- method->clazz->pDvmDex
+#if defined(WITH_JIT)
+ cmp $0, %ecx
+ je .returnToBC
+ movl %ecx, %eax
+ jmp *%eax
+#endif
+
+.returnToBC:
+
+#if defined(WITH_JIT)
+ FETCH_INST_OPCODE 3, %ecx # %eax<- next instruction hi; fetch, advance
+ // %ecx has the opcode
+ addl $6, rPC # 3*2 = 6
+ SPILL_TMP1 (%ecx)
+ movl rSELF, %ecx
+ FETCH_INST
+ UNSPILL_TMP1 (%ecx)
+ movzbl 1(rPC), rINST
+ jmp *(rIBASE,%ecx,4)
+#else
+ FETCH_INST_WORD 3
ADVANCE_PC 3
- GOTO_NEXT_R %eax
+ GOTO_NEXT
+#endif
19:
/*
* Handle special subMode actions
* On entry, rFP: prevFP, %ecx: self, %eax: saveArea
*/
- movl rFP, offThread_curFrame(%ecx) # update interpSave.curFrame
+ SPILL_TMP1(%ebx)
+ movl offStackSaveArea_prevFrame(%eax), %ebx # %ebx<- saveArea->PrevFrame
movl rPC, offThread_pc(%ecx) # update interpSave.pc
+ movl %ebx, offThread_curFrame(%ecx) # update interpSave.curFrame
movl %ecx, OUT_ARG0(%esp) # parameter self
call dvmReportReturn # (self)
+ UNSPILL_TMP1(%ebx)
movl rSELF, %ecx # restore self
SAVEAREA_FROM_FP %eax # restore saveArea
jmp 14b
@@ -15730,12 +16405,74 @@
movl rINST,OUT_ARG1(%esp) # changeInterp in arg1
call dvmMterpStdBail # bail out....
+/*
+ * The JIT's invoke method needs to remember the callsite class and
+ * target pair. Save them here so that they are available to
+ * dvmCheckJit following the interpretation of this invoke.
+ *
+ * eax = Method* methodToCall
+ * ecx = "this"
+ * edx = rSELF
+ * ebx = free to use
+ */
+#if defined(WITH_JIT)
+save_callsiteinfo:
+ cmp $0, %ecx
+ je 2f
+ movl offObject_clazz(%ecx), %ecx
+2:
+ movl rSELF, %ebx
+ movl %eax, offThread_methodToCall(%ebx)
+ movl %ecx, offThread_callsiteClass(%ebx)
+ ret
+#endif
+
+#if defined(WITH_JIT)
+
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including the current
+ * instruction.
+ *
+ * On entry:
+ * %ecx: &dvmDex->pResFields[field]
+ * %eax: field pointer (must preserve)
+ */
+common_verifyField:
+ movl %ebx, TMP_SPILL1(%ebp)
+ movl rSELF, %ebx
+ movzwl offThread_subMode(%ebx), %ebx
+ andl $kSubModeJitTraceBuild, %ebx
+ movl TMP_SPILL1(%ebp), %ebx
+ jne 1f
+ ret
+1:
+ movl (%ecx), %ecx
+ cmp $0, %ecx
+ je 1f
+ ret
+1:
+ SPILL_TMP1(%eax)
+ SPILL_TMP2(%edx)
+ movl rSELF, %ecx
+ # Because we call into this helper from a bytecode, we have
+ # to be careful not to write over the return address when using
+ # the OUT_ARG macros
+ lea -8(%esp), %esp
+ movl %ecx, OUT_ARG0(%esp)
+ movl rPC, OUT_ARG1(%esp)
+ call dvmJitEndTraceSelect
+ lea 8(%esp), %esp
+ UNSPILL_TMP2(%edx)
+ UNSPILL_TMP1(%eax)
+ ret
+#endif
/*
* After returning from a "selfd" function, pull out the updated values
* and start executing at the next instruction.
*/
- common_resumeAfterGlueCall:
+common_resumeAfterGlueCall:
movl rSELF, %eax
movl offThread_pc(%eax),rPC
movl offThread_curFrame(%eax),rFP
@@ -15768,7 +16505,6 @@
* On entry, method name in eax
*/
common_errNoSuchMethod:
-
EXPORT_PC
movl %eax,OUT_ARG0(%esp)
call dvmThrowNoSuchMethodError
@@ -15811,12 +16547,132 @@
* This does not return.
*/
common_exceptionThrown:
- movl rSELF,%ecx
- movl rPC,offThread_pc(%ecx)
- movl rFP,offThread_curFrame(%ecx)
- movl %ecx,OUT_ARG0(%esp)
- call dvmMterp_exceptionThrown
- jmp common_resumeAfterGlueCall
+.LexceptionNew:
+
+ EXPORT_PC
+ movl rSELF, %ecx
+ movl %ecx, OUT_ARG0(%esp)
+ call dvmCheckSuspendPending
+
+ movl rSELF, %ecx
+ movl offThread_exception(%ecx), %edx # %edx <- self->exception
+ movl %edx, OUT_ARG0(%esp)
+ movl %ecx, OUT_ARG1(%esp)
+ SPILL_TMP1(%edx)
+ call dvmAddTrackedAlloc # don't let the exception be GCed
+ UNSPILL_TMP1(%edx)
+ movl rSELF, %ecx
+ movl offThread_subMode(%ecx), %eax # get subMode flags
+ movl $0, offThread_exception(%ecx)
+
+ # Special subMode?
+ cmpl $0, %eax # any special subMode handling needed?
+ je 8f # go if so
+
+ # Manage debugger bookkeeping
+ movl rPC, offThread_pc(%ecx) # update interpSave.pc
+ movl rFP, offThread_curFrame(%ecx) # update interpSave.curFrame
+ movl %ecx, OUT_ARG0(%esp)
+ movl %edx, OUT_ARG1(%esp)
+ SPILL_TMP1(%edx)
+ call dvmReportExceptionThrow # (self, exception)
+ UNSPILL_TMP1(%edx)
+ movl rSELF, %ecx
+
+8:
+ /*
+ * set up args and a local for &fp
+ */
+ lea 20(%esp), %esp # raise %esp
+ movl rFP, (%esp) # save fp
+ movl %esp, %eax # %eax = &fp
+ lea -20(%esp), %esp # reset %esp
+ movl %eax, OUT_ARG4(%esp) # Arg 4 = &fp
+ movl $0, OUT_ARG3(%esp) # Arg 3 = false
+ movl %edx, OUT_ARG2(%esp) # Arg 2 = exception
+ movl %ecx, OUT_ARG0(%esp) # Arg 0 = self
+
+ movl offThread_method(%ecx), %eax # %eax = self->method
+ movl offMethod_insns(%eax), %eax # %eax = self->method->insn
+ # ldrh lr, [rSELF, #offThread_subMode] @ lr<- subMode flags # TODO
+ movl rPC, %ecx
+ subl %eax, %ecx # %ecx = pc - self->method->insn
+ sar $1, %ecx # adjust %ecx for code offset
+ movl %ecx, OUT_ARG1(%esp) # Arg 1 = %ecx
+
+ /* call, %eax gets catchRelPc (a code-unit offset) */
+ SPILL_TMP1(%edx) # save exception
+ call dvmFindCatchBlock # call(self, relPc, exc, scan?, &fp)
+ UNSPILL_TMP1(%edx) # restore exception
+
+ /* fix earlier stack overflow if necessary; may trash rFP */
+ movl rSELF, %ecx
+ cmpl $0, offThread_stackOverflowed(%ecx) # did we overflow?
+ je 1f # no, skip ahead
+ movl %eax, rFP # save relPc result in rFP
+ movl %ecx, OUT_ARG0(%esp) # Arg 0 = self
+ movl %edx, OUT_ARG1(%esp) # Arg 1 = exception
+ SPILL_TMP1(%edx)
+ call dvmCleanupStackOverflow # call(self, exception)
+ UNSPILL_TMP1(%edx)
+ movl rFP, %eax # restore result
+ movl rSELF, %ecx
+1:
+
+ /* update frame pointer and check result from dvmFindCatchBlock */
+ movl 20(%esp), rFP # retrieve the updated rFP
+ cmpl $0, %eax # is catchRelPc < 0?
+ jl .LnotCaughtLocally
+
+ /* adjust locals to match self->interpSave.curFrame and updated PC */
+ SAVEAREA_FROM_FP rINST # rINST<- new save area
+ movl offStackSaveArea_method(rINST), rINST # rINST<- new method
+ movl rINST, offThread_method(%ecx) # self->method = new method
+ movl offMethod_clazz(rINST), %ecx # %ecx = method->clazz
+ movl offMethod_insns(rINST), rINST # rINST = method->insn
+ movl offClassObject_pDvmDex(%ecx), %ecx # %ecx = method->clazz->pDvmDex
+ lea (rINST, %eax, 2), rPC # rPC<- method->insns + catchRelPc
+ movl rSELF, rINST
+ movl %ecx, offThread_methodClassDex(rINST) # self->pDvmDex = method->clazz->pDvmDex
+
+ /* release the tracked alloc on the exception */
+ movl %edx, OUT_ARG0(%esp) # Arg 0 = exception
+ movl rINST, OUT_ARG1(%esp) # Arg 1 = self
+ SPILL_TMP1(%edx)
+ call dvmReleaseTrackedAlloc # release the exception
+ UNSPILL_TMP1(%edx)
+
+ /* restore the exception if the handler wants it */
+ movl rSELF, %ecx
+ FETCH_INST
+ movzbl rINSTbl, %eax
+ cmpl $OP_MOVE_EXCEPTION, %eax # is it "move-exception"?
+ jne 1f
+ movl %edx, offThread_exception(%ecx) # restore exception
+1:
+ movl offThread_curHandlerTable(%ecx), rIBASE # refresh rIBASE
+ GOTO_NEXT
+
+.LnotCaughtLocally: # %edx = exception
+ /* fix stack overflow if necessary */
+ movl rSELF, %ecx
+ movl offThread_stackOverflowed(%ecx), %eax
+ cmpl $0, %eax # did we overflow earlier?
+ je 1f
+ movl %ecx, OUT_ARG0(%esp)
+ movl %edx, OUT_ARG1(%esp)
+ SPILL_TMP1(%edx)
+ call dvmCleanupStackOverflow
+ UNSPILL_TMP1(%edx)
+
+1:
+ movl rSELF, %ecx
+ movl %edx, offThread_exception(%ecx) #restore exception
+ movl %edx, OUT_ARG0(%esp)
+ movl %ecx, OUT_ARG1(%esp)
+ call dvmReleaseTrackedAlloc # release the exception
+ movl rSELF, %ecx
+ jmp common_gotoBail # bail out
common_abort:
movl $0xdeadf00d,%eax
diff --git a/vm/mterp/out/InterpC-allstubs.cpp b/vm/mterp/out/InterpC-allstubs.cpp
index 0fcee85..1ef8783 100644
--- a/vm/mterp/out/InterpC-allstubs.cpp
+++ b/vm/mterp/out/InterpC-allstubs.cpp
@@ -68,6 +68,14 @@
#if defined(__ARM_EABI__)
# define NO_UNALIGN_64__UNION
#endif
+/*
+ * MIPS ABI requires 64-bit alignment for access to 64-bit data types.
+ *
+ * Use memcpy() to do the transfer
+ */
+#if defined(__mips__)
+/* # define NO_UNALIGN_64__UNION */
+#endif
//#define LOG_INSTR /* verbose debugging */
@@ -452,6 +460,8 @@
}
#endif
+#define FINISH_BKPT(_opcode) /* FIXME? */
+#define DISPATCH_EXTENDED(_opcode) /* FIXME? */
/*
* The "goto label" statements turn into function calls followed by
@@ -488,7 +498,7 @@
* As a special case, "goto bail" turns into a longjmp.
*/
#define GOTO_bail() \
- dvmMterpStdBail(self, false);
+ dvmMterpStdBail(self)
/*
* Periodically check for thread suspension.
@@ -1031,7 +1041,7 @@
} \
SET_REGISTER##_regsize(vdst, \
dvmGetField##_ftype(obj, ifield->byteOffset)); \
- ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1075,7 +1085,7 @@
} \
dvmSetField##_ftype(obj, ifield->byteOffset, \
GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1125,7 +1135,7 @@
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1148,7 +1158,7 @@
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1832,7 +1842,7 @@
vsrc1 = INST_AA(inst);
offset = FETCH(1) | (((s4) FETCH(2)) << 16);
- ILOGV("|packed-switch v%d +0x%04x", vsrc1, vsrc2);
+ ILOGV("|packed-switch v%d +0x%04x", vsrc1, offset);
switchData = pc + offset; // offset in 16-bit units
#ifndef NDEBUG
if (switchData < curMethod->insns ||
@@ -1863,7 +1873,7 @@
vsrc1 = INST_AA(inst);
offset = FETCH(1) | (((s4) FETCH(2)) << 16);
- ILOGV("|sparse-switch v%d +0x%04x", vsrc1, vsrc2);
+ ILOGV("|sparse-switch v%d +0x%04x", vsrc1, offset);
switchData = pc + offset; // offset in 16-bit units
#ifndef NDEBUG
if (switchData < curMethod->insns ||
@@ -2040,7 +2050,7 @@
if (!dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
obj->clazz->descriptor, obj,
- arrayObj->obj.clazz->descriptor, arrayObj);
+ arrayObj->clazz->descriptor, arrayObj);
dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
GOTO_exceptionThrown();
}
@@ -2847,7 +2857,7 @@
;
}
- if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+ if (self->interpBreak.ctl.subMode & kSubModeDebugProfile) {
if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
GOTO_exceptionThrown();
} else {
@@ -2892,7 +2902,7 @@
;
}
- if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+ if (self->interpBreak.ctl.subMode & kSubModeDebugProfile) {
if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
GOTO_exceptionThrown();
} else {
@@ -3015,7 +3025,7 @@
* Handler function table, one entry per opcode.
*/
#undef H
-#define H(_op) dvmMterp_##_op
+#define H(_op) (const void*) dvmMterp_##_op
DEFINE_GOTO_TABLE(gDvmMterpHandlers)
#undef H
@@ -3034,12 +3044,12 @@
{
jmp_buf jmpBuf;
- self->bailPtr = &jmpBuf;
+ self->interpSave.bailPtr = &jmpBuf;
/* We exit via a longjmp */
if (setjmp(jmpBuf)) {
LOGVV("mterp threadid=%d returning", dvmThreadSelf()->threadId);
- return
+ return;
}
/* run until somebody longjmp()s out */
@@ -3053,8 +3063,8 @@
* FINISH code. For allstubs, we must do an explicit check
* in the interpretation loop.
*/
- if (self-interpBreak.ctl.subMode) {
- dvmCheckBefore(pc, fp, self, curMethod);
+ if (self->interpBreak.ctl.subMode) {
+ dvmCheckBefore(pc, fp, self);
}
Handler handler = (Handler) gDvmMterpHandlers[inst & 0xff];
(void) gDvmMterpHandlerNames; /* avoid gcc "defined but not used" */
@@ -3069,7 +3079,7 @@
*/
void dvmMterpStdBail(Thread* self)
{
- jmp_buf* pJmpBuf = self->bailPtr;
+ jmp_buf* pJmpBuf = (jmp_buf*) self->interpSave.bailPtr;
longjmp(*pJmpBuf, 1);
}
@@ -3993,7 +4003,7 @@
DUMP_REGS(methodToCall, newFp, true); // show input args
if (self->interpBreak.ctl.subMode != 0) {
- dvmReportPreNativeInvoke(methodToCall, self, fp);
+ dvmReportPreNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
}
ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
@@ -4007,12 +4017,13 @@
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
if (self->interpBreak.ctl.subMode != 0) {
- dvmReportPostNativeInvoke(methodToCall, self, fp);
+ dvmReportPostNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
}
/* pop frame off */
dvmPopJniLocals(self, newSaveArea);
- self->interpSave.curFrame = fp;
+ self->interpSave.curFrame = newSaveArea->prevFrame;
+ fp = newSaveArea->prevFrame;
/*
* If the native code threw an exception, or interpreted code
diff --git a/vm/mterp/out/InterpC-armv5te-vfp.cpp b/vm/mterp/out/InterpC-armv5te-vfp.cpp
index dde9463..9d6b458 100644
--- a/vm/mterp/out/InterpC-armv5te-vfp.cpp
+++ b/vm/mterp/out/InterpC-armv5te-vfp.cpp
@@ -68,6 +68,14 @@
#if defined(__ARM_EABI__)
# define NO_UNALIGN_64__UNION
#endif
+/*
+ * MIPS ABI requires 64-bit alignment for access to 64-bit data types.
+ *
+ * Use memcpy() to do the transfer
+ */
+#if defined(__mips__)
+/* # define NO_UNALIGN_64__UNION */
+#endif
//#define LOG_INSTR /* verbose debugging */
@@ -452,6 +460,8 @@
}
#endif
+#define FINISH_BKPT(_opcode) /* FIXME? */
+#define DISPATCH_EXTENDED(_opcode) /* FIXME? */
/*
* The "goto label" statements turn into function calls followed by
@@ -488,7 +498,7 @@
* As a special case, "goto bail" turns into a longjmp.
*/
#define GOTO_bail() \
- dvmMterpStdBail(self, false);
+ dvmMterpStdBail(self)
/*
* Periodically check for thread suspension.
@@ -1031,7 +1041,7 @@
} \
SET_REGISTER##_regsize(vdst, \
dvmGetField##_ftype(obj, ifield->byteOffset)); \
- ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1075,7 +1085,7 @@
} \
dvmSetField##_ftype(obj, ifield->byteOffset, \
GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1125,7 +1135,7 @@
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1148,7 +1158,7 @@
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
diff --git a/vm/mterp/out/InterpC-armv5te.cpp b/vm/mterp/out/InterpC-armv5te.cpp
index 13c243b..99831b1 100644
--- a/vm/mterp/out/InterpC-armv5te.cpp
+++ b/vm/mterp/out/InterpC-armv5te.cpp
@@ -68,6 +68,14 @@
#if defined(__ARM_EABI__)
# define NO_UNALIGN_64__UNION
#endif
+/*
+ * MIPS ABI requires 64-bit alignment for access to 64-bit data types.
+ *
+ * Use memcpy() to do the transfer
+ */
+#if defined(__mips__)
+/* # define NO_UNALIGN_64__UNION */
+#endif
//#define LOG_INSTR /* verbose debugging */
@@ -452,6 +460,8 @@
}
#endif
+#define FINISH_BKPT(_opcode) /* FIXME? */
+#define DISPATCH_EXTENDED(_opcode) /* FIXME? */
/*
* The "goto label" statements turn into function calls followed by
@@ -488,7 +498,7 @@
* As a special case, "goto bail" turns into a longjmp.
*/
#define GOTO_bail() \
- dvmMterpStdBail(self, false);
+ dvmMterpStdBail(self)
/*
* Periodically check for thread suspension.
@@ -1031,7 +1041,7 @@
} \
SET_REGISTER##_regsize(vdst, \
dvmGetField##_ftype(obj, ifield->byteOffset)); \
- ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1075,7 +1085,7 @@
} \
dvmSetField##_ftype(obj, ifield->byteOffset, \
GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1125,7 +1135,7 @@
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1148,7 +1158,7 @@
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
diff --git a/vm/mterp/out/InterpC-armv7-a-neon.cpp b/vm/mterp/out/InterpC-armv7-a-neon.cpp
index ca81a08..7a3434c 100644
--- a/vm/mterp/out/InterpC-armv7-a-neon.cpp
+++ b/vm/mterp/out/InterpC-armv7-a-neon.cpp
@@ -68,6 +68,14 @@
#if defined(__ARM_EABI__)
# define NO_UNALIGN_64__UNION
#endif
+/*
+ * MIPS ABI requires 64-bit alignment for access to 64-bit data types.
+ *
+ * Use memcpy() to do the transfer
+ */
+#if defined(__mips__)
+/* # define NO_UNALIGN_64__UNION */
+#endif
//#define LOG_INSTR /* verbose debugging */
@@ -452,6 +460,8 @@
}
#endif
+#define FINISH_BKPT(_opcode) /* FIXME? */
+#define DISPATCH_EXTENDED(_opcode) /* FIXME? */
/*
* The "goto label" statements turn into function calls followed by
@@ -488,7 +498,7 @@
* As a special case, "goto bail" turns into a longjmp.
*/
#define GOTO_bail() \
- dvmMterpStdBail(self, false);
+ dvmMterpStdBail(self)
/*
* Periodically check for thread suspension.
@@ -1031,7 +1041,7 @@
} \
SET_REGISTER##_regsize(vdst, \
dvmGetField##_ftype(obj, ifield->byteOffset)); \
- ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1075,7 +1085,7 @@
} \
dvmSetField##_ftype(obj, ifield->byteOffset, \
GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1125,7 +1135,7 @@
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1148,7 +1158,7 @@
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
diff --git a/vm/mterp/out/InterpC-armv7-a.cpp b/vm/mterp/out/InterpC-armv7-a.cpp
index d90cbdc..1dcfb68 100644
--- a/vm/mterp/out/InterpC-armv7-a.cpp
+++ b/vm/mterp/out/InterpC-armv7-a.cpp
@@ -68,6 +68,14 @@
#if defined(__ARM_EABI__)
# define NO_UNALIGN_64__UNION
#endif
+/*
+ * MIPS ABI requires 64-bit alignment for access to 64-bit data types.
+ *
+ * Use memcpy() to do the transfer
+ */
+#if defined(__mips__)
+/* # define NO_UNALIGN_64__UNION */
+#endif
//#define LOG_INSTR /* verbose debugging */
@@ -452,6 +460,8 @@
}
#endif
+#define FINISH_BKPT(_opcode) /* FIXME? */
+#define DISPATCH_EXTENDED(_opcode) /* FIXME? */
/*
* The "goto label" statements turn into function calls followed by
@@ -488,7 +498,7 @@
* As a special case, "goto bail" turns into a longjmp.
*/
#define GOTO_bail() \
- dvmMterpStdBail(self, false);
+ dvmMterpStdBail(self)
/*
* Periodically check for thread suspension.
@@ -1031,7 +1041,7 @@
} \
SET_REGISTER##_regsize(vdst, \
dvmGetField##_ftype(obj, ifield->byteOffset)); \
- ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1075,7 +1085,7 @@
} \
dvmSetField##_ftype(obj, ifield->byteOffset, \
GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1125,7 +1135,7 @@
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1148,7 +1158,7 @@
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
diff --git a/vm/mterp/out/InterpC-mips.cpp b/vm/mterp/out/InterpC-mips.cpp
new file mode 100644
index 0000000..69260da
--- /dev/null
+++ b/vm/mterp/out/InterpC-mips.cpp
@@ -0,0 +1,2268 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'mips'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.cpp */
+/*
+ * 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.
+ */
+
+/* common includes */
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "mterp/Mterp.h"
+#include <math.h> // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
+
+/*
+ * Configuration defines. These affect the C implementations, i.e. the
+ * portable interpreter(s) and C stubs.
+ *
+ * Some defines are controlled by the Makefile, e.g.:
+ * WITH_INSTR_CHECKS
+ * WITH_TRACKREF_CHECKS
+ * EASY_GDB
+ * NDEBUG
+ */
+
+#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * Some architectures require 64-bit alignment for access to 64-bit data
+ * types. We can't just use pointers to copy 64-bit values out of our
+ * interpreted register set, because gcc may assume the pointer target is
+ * aligned and generate invalid code.
+ *
+ * There are two common approaches:
+ * (1) Use a union that defines a 32-bit pair and a 64-bit value.
+ * (2) Call memcpy().
+ *
+ * Depending upon what compiler you're using and what options are specified,
+ * one may be faster than the other. For example, the compiler might
+ * convert a memcpy() of 8 bytes into a series of instructions and omit
+ * the call. The union version could cause some strange side-effects,
+ * e.g. for a while ARM gcc thought it needed separate storage for each
+ * inlined instance, and generated instructions to zero out ~700 bytes of
+ * stack space at the top of the interpreter.
+ *
+ * The default is to use memcpy(). The current gcc for ARM seems to do
+ * better with the union.
+ */
+#if defined(__ARM_EABI__)
+# define NO_UNALIGN_64__UNION
+#endif
+/*
+ * MIPS ABI requires 64-bit alignment for access to 64-bit data types.
+ *
+ * Use memcpy() to do the transfer
+ */
+#if defined(__mips__)
+/* # define NO_UNALIGN_64__UNION */
+#endif
+
+
+//#define LOG_INSTR /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code. This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
+ * Adjust the program counter. "_offset" is a signed int, in 16-bit units.
+ *
+ * Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
+ *
+ * We don't advance the program counter until we finish an instruction or
+ * branch, because we do want to have to unroll the PC if there's an
+ * exception.
+ */
+#ifdef CHECK_BRANCH_OFFSETS
+# define ADJUST_PC(_offset) do { \
+ int myoff = _offset; /* deref only once */ \
+ if (pc + myoff < curMethod->insns || \
+ pc + myoff >= curMethod->insns + dvmGetMethodInsnsSize(curMethod)) \
+ { \
+ char* desc; \
+ desc = dexProtoCopyMethodDescriptor(&curMethod->prototype); \
+ ALOGE("Invalid branch %d at 0x%04x in %s.%s %s", \
+ myoff, (int) (pc - curMethod->insns), \
+ curMethod->clazz->descriptor, curMethod->name, desc); \
+ free(desc); \
+ dvmAbort(); \
+ } \
+ pc += myoff; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
+#else
+# define ADJUST_PC(_offset) do { \
+ pc += _offset; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
+#endif
+
+/*
+ * If enabled, log instructions as we execute them.
+ */
+#ifdef LOG_INSTR
+# define ILOGD(...) ILOG(LOG_DEBUG, __VA_ARGS__)
+# define ILOGV(...) ILOG(LOG_VERBOSE, __VA_ARGS__)
+# define ILOG(_level, ...) do { \
+ char debugStrBuf[128]; \
+ snprintf(debugStrBuf, sizeof(debugStrBuf), __VA_ARGS__); \
+ if (curMethod != NULL) \
+ ALOG(_level, LOG_TAG"i", "%-2d|%04x%s", \
+ self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+ else \
+ ALOG(_level, LOG_TAG"i", "%-2d|####%s", \
+ self->threadId, debugStrBuf); \
+ } while(false)
+void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly);
+# define DUMP_REGS(_meth, _frame, _inOnly) dvmDumpRegs(_meth, _frame, _inOnly)
+static const char kSpacing[] = " ";
+#else
+# define ILOGD(...) ((void)0)
+# define ILOGV(...) ((void)0)
+# define DUMP_REGS(_meth, _frame, _inOnly) ((void)0)
+#endif
+
+/* get a long from an array of u4 */
+static inline s8 getLongFromArray(const u4* ptr, int idx)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { s8 ll; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.parts[0] = ptr[0];
+ conv.parts[1] = ptr[1];
+ return conv.ll;
+#else
+ s8 val;
+ memcpy(&val, &ptr[idx], 8);
+ return val;
+#endif
+}
+
+/* store a long into an array of u4 */
+static inline void putLongToArray(u4* ptr, int idx, s8 val)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { s8 ll; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.ll = val;
+ ptr[0] = conv.parts[0];
+ ptr[1] = conv.parts[1];
+#else
+ memcpy(&ptr[idx], &val, 8);
+#endif
+}
+
+/* get a double from an array of u4 */
+static inline double getDoubleFromArray(const u4* ptr, int idx)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { double d; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.parts[0] = ptr[0];
+ conv.parts[1] = ptr[1];
+ return conv.d;
+#else
+ double dval;
+ memcpy(&dval, &ptr[idx], 8);
+ return dval;
+#endif
+}
+
+/* store a double into an array of u4 */
+static inline void putDoubleToArray(u4* ptr, int idx, double dval)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { double d; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.d = dval;
+ ptr[0] = conv.parts[0];
+ ptr[1] = conv.parts[1];
+#else
+ memcpy(&ptr[idx], &dval, 8);
+#endif
+}
+
+/*
+ * If enabled, validate the register number on every access. Otherwise,
+ * just do an array access.
+ *
+ * Assumes the existence of "u4* fp".
+ *
+ * "_idx" may be referenced more than once.
+ */
+#ifdef CHECK_REGISTER_INDICES
+# define GET_REGISTER(_idx) \
+ ( (_idx) < curMethod->registersSize ? \
+ (fp[(_idx)]) : (assert(!"bad reg"),1969) )
+# define SET_REGISTER(_idx, _val) \
+ ( (_idx) < curMethod->registersSize ? \
+ (fp[(_idx)] = (u4)(_val)) : (assert(!"bad reg"),1969) )
+# define GET_REGISTER_AS_OBJECT(_idx) ((Object *)GET_REGISTER(_idx))
+# define SET_REGISTER_AS_OBJECT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_INT(_idx) ((s4) GET_REGISTER(_idx))
+# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_WIDE(_idx) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ getLongFromArray(fp, (_idx)) : (assert(!"bad reg"),1969) )
+# define SET_REGISTER_WIDE(_idx, _val) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+# define GET_REGISTER_FLOAT(_idx) \
+ ( (_idx) < curMethod->registersSize ? \
+ (*((float*) &fp[(_idx)])) : (assert(!"bad reg"),1969.0f) )
+# define SET_REGISTER_FLOAT(_idx, _val) \
+ ( (_idx) < curMethod->registersSize ? \
+ (*((float*) &fp[(_idx)]) = (_val)) : (assert(!"bad reg"),1969.0f) )
+# define GET_REGISTER_DOUBLE(_idx) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ getDoubleFromArray(fp, (_idx)) : (assert(!"bad reg"),1969.0) )
+# define SET_REGISTER_DOUBLE(_idx, _val) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+#else
+# define GET_REGISTER(_idx) (fp[(_idx)])
+# define SET_REGISTER(_idx, _val) (fp[(_idx)] = (_val))
+# define GET_REGISTER_AS_OBJECT(_idx) ((Object*) fp[(_idx)])
+# define SET_REGISTER_AS_OBJECT(_idx, _val) (fp[(_idx)] = (u4)(_val))
+# define GET_REGISTER_INT(_idx) ((s4)GET_REGISTER(_idx))
+# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_WIDE(_idx) getLongFromArray(fp, (_idx))
+# define SET_REGISTER_WIDE(_idx, _val) putLongToArray(fp, (_idx), (_val))
+# define GET_REGISTER_FLOAT(_idx) (*((float*) &fp[(_idx)]))
+# define SET_REGISTER_FLOAT(_idx, _val) (*((float*) &fp[(_idx)]) = (_val))
+# define GET_REGISTER_DOUBLE(_idx) getDoubleFromArray(fp, (_idx))
+# define SET_REGISTER_DOUBLE(_idx, _val) putDoubleToArray(fp, (_idx), (_val))
+#endif
+
+/*
+ * Get 16 bits from the specified offset of the program counter. We always
+ * want to load 16 bits at a time from the instruction stream -- it's more
+ * efficient than 8 and won't have the alignment problems that 32 might.
+ *
+ * Assumes existence of "const u2* pc".
+ */
+#define FETCH(_offset) (pc[(_offset)])
+
+/*
+ * Extract instruction byte from 16-bit fetch (_inst is a u2).
+ */
+#define INST_INST(_inst) ((_inst) & 0xff)
+
+/*
+ * Replace the opcode (used when handling breakpoints). _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
+ * Extract the "vA, vB" 4-bit registers from the instruction word (_inst is u2).
+ */
+#define INST_A(_inst) (((_inst) >> 8) & 0x0f)
+#define INST_B(_inst) ((_inst) >> 12)
+
+/*
+ * Get the 8-bit "vAA" 8-bit register index from the instruction word.
+ * (_inst is u2)
+ */
+#define INST_AA(_inst) ((_inst) >> 8)
+
+/*
+ * The current PC must be available to Throwable constructors, e.g.
+ * those created by the various exception throw routines, so that the
+ * exception stack trace can be generated correctly. If we don't do this,
+ * the offset within the current method won't be shown correctly. See the
+ * notes in Exception.c.
+ *
+ * This is also used to determine the address for precise GC.
+ *
+ * Assumes existence of "u4* fp" and "const u2* pc".
+ */
+#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
+
+/*
+ * Check to see if "obj" is NULL. If so, throw an exception. Assumes the
+ * pc has already been exported to the stack.
+ *
+ * Perform additional checks on debug builds.
+ *
+ * Use this to check for NULL when the instruction handler calls into
+ * something that could throw an exception (so we have already called
+ * EXPORT_PC at the top).
+ */
+static inline bool checkForNull(Object* obj)
+{
+ if (obj == NULL) {
+ dvmThrowNullPointerException(NULL);
+ return false;
+ }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+ if (!dvmIsHeapAddress(obj)) {
+ ALOGE("Invalid object %p", obj);
+ dvmAbort();
+ }
+#endif
+#ifndef NDEBUG
+ if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+ /* probable heap corruption */
+ ALOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+ dvmAbort();
+ }
+#endif
+ return true;
+}
+
+/*
+ * Check to see if "obj" is NULL. If so, export the PC into the stack
+ * frame and throw an exception.
+ *
+ * Perform additional checks on debug builds.
+ *
+ * Use this to check for NULL when the instruction handler doesn't do
+ * anything else that can throw an exception.
+ */
+static inline bool checkForNullExportPC(Object* obj, u4* fp, const u2* pc)
+{
+ if (obj == NULL) {
+ EXPORT_PC();
+ dvmThrowNullPointerException(NULL);
+ return false;
+ }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+ if (!dvmIsHeapAddress(obj)) {
+ ALOGE("Invalid object %p", obj);
+ dvmAbort();
+ }
+#endif
+#ifndef NDEBUG
+ if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+ /* probable heap corruption */
+ ALOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+ dvmAbort();
+ }
+#endif
+ return true;
+}
+
+/* File: cstubs/stubdefs.cpp */
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...) \
+ extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
+
+/* (void)xxx to quiet unused variable compiler warnings. */
+#define GOTO_TARGET(_target, ...) \
+ void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) { \
+ u2 ref, vsrc1, vsrc2, vdst; \
+ u2 inst = FETCH(0); \
+ const Method* methodToCall; \
+ StackSaveArea* debugSaveArea; \
+ (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst; \
+ (void)methodToCall; (void)debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into Thread struct
+ * references. (These are undefined down in "footer.cpp".)
+ */
+#define retval self->interpSave.retval
+#define pc self->interpSave.pc
+#define fp self->interpSave.curFrame
+#define curMethod self->interpSave.method
+#define methodClassDex self->interpSave.methodClassDex
+#define debugTrackedRefStart self->interpSave.debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+#if defined(WITH_JIT)
+#define JIT_STUB_HACK(x) x
+#else
+#define JIT_STUB_HACK(x)
+#endif
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine. Because the portable interpreter uses local
+ * variables for these, we must flush prior. Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()
+#define PC_TO_SELF()
+
+/*
+ * Opcode handler framing macros. Here, each opcode is a separate function
+ * that takes a "self" argument and returns void. We can't declare
+ * these "static" because they may be called from an assembly stub.
+ * (void)xxx to quiet unused variable compiler warnings.
+ */
+#define HANDLE_OPCODE(_op) \
+ extern "C" void dvmMterp_##_op(Thread* self); \
+ void dvmMterp_##_op(Thread* self) { \
+ u4 ref; \
+ u2 vsrc1, vsrc2, vdst; \
+ u2 inst = FETCH(0); \
+ (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done. Further, debugger/profiler checks are handled
+ * before handler execution in mterp, so we don't do them here either.
+ */
+#if defined(WITH_JIT)
+#define FINISH(_offset) { \
+ ADJUST_PC(_offset); \
+ if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) { \
+ dvmCheckJit(pc, self); \
+ } \
+ return; \
+ }
+#else
+#define FINISH(_offset) { \
+ ADJUST_PC(_offset); \
+ return; \
+ }
+#endif
+
+#define FINISH_BKPT(_opcode) /* FIXME? */
+#define DISPATCH_EXTENDED(_opcode) /* FIXME? */
+
+/*
+ * The "goto label" statements turn into function calls followed by
+ * return statements. Some of the functions take arguments, which in the
+ * portable interpreter are handled by assigning values to globals.
+ */
+
+#define GOTO_exceptionThrown() \
+ do { \
+ dvmMterp_exceptionThrown(self); \
+ return; \
+ } while(false)
+
+#define GOTO_returnFromMethod() \
+ do { \
+ dvmMterp_returnFromMethod(self); \
+ return; \
+ } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange) \
+ do { \
+ dvmMterp_##_target(self, _methodCallRange); \
+ return; \
+ } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst) \
+ do { \
+ dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall, \
+ _vsrc1, _vdst); \
+ return; \
+ } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp.
+ */
+#define GOTO_bail() \
+ dvmMterpStdBail(self)
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started.
+ */
+#define PERIODIC_CHECKS(_pcadj) { \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
+ }
+
+/* File: c/opcommon.cpp */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange);
+GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall,
+ u2 count, u2 regs);
+GOTO_TARGET_DECL(returnFromMethod);
+GOTO_TARGET_DECL(exceptionThrown);
+
+/*
+ * ===========================================================================
+ *
+ * What follows are opcode definitions shared between multiple opcodes with
+ * minor substitutions handled by the C pre-processor. These should probably
+ * use the mterp substitution mechanism instead, with the code here moved
+ * into common fragment files (like the asm "binop.S"), although it's hard
+ * to give up the C preprocessor in favor of the much simpler text subst.
+ *
+ * ===========================================================================
+ */
+
+#define HANDLE_NUMCONV(_opcode, _opname, _fromtype, _totype) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER##_totype(vdst, \
+ GET_REGISTER##_fromtype(vsrc1)); \
+ FINISH(1);
+
+#define HANDLE_FLOAT_TO_INT(_opcode, _opname, _fromvtype, _fromrtype, \
+ _tovtype, _tortype) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ { \
+ /* spec defines specific handling for +/- inf and NaN values */ \
+ _fromvtype val; \
+ _tovtype intMin, intMax, result; \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
+ val = GET_REGISTER##_fromrtype(vsrc1); \
+ intMin = (_tovtype) 1 << (sizeof(_tovtype) * 8 -1); \
+ intMax = ~intMin; \
+ result = (_tovtype) val; \
+ if (val >= intMax) /* +inf */ \
+ result = intMax; \
+ else if (val <= intMin) /* -inf */ \
+ result = intMin; \
+ else if (val != val) /* NaN */ \
+ result = 0; \
+ else \
+ result = (_tovtype) val; \
+ SET_REGISTER##_tortype(vdst, result); \
+ } \
+ FINISH(1);
+
+#define HANDLE_INT_TO_SMALL(_opcode, _opname, _type) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|int-to-%s v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER(vdst, (_type) GET_REGISTER(vsrc1)); \
+ FINISH(1);
+
+/* NOTE: the comparison result is always a signed 4-byte integer */
+#define HANDLE_OP_CMPX(_opcode, _opname, _varType, _type, _nanVal) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ int result; \
+ u2 regs; \
+ _varType val1, val2; \
+ vdst = INST_AA(inst); \
+ regs = FETCH(1); \
+ vsrc1 = regs & 0xff; \
+ vsrc2 = regs >> 8; \
+ ILOGV("|cmp%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ val1 = GET_REGISTER##_type(vsrc1); \
+ val2 = GET_REGISTER##_type(vsrc2); \
+ if (val1 == val2) \
+ result = 0; \
+ else if (val1 < val2) \
+ result = -1; \
+ else if (val1 > val2) \
+ result = 1; \
+ else \
+ result = (_nanVal); \
+ ILOGV("+ result=%d", result); \
+ SET_REGISTER(vdst, result); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_IF_XX(_opcode, _opname, _cmp) \
+ HANDLE_OPCODE(_opcode /*vA, vB, +CCCC*/) \
+ vsrc1 = INST_A(inst); \
+ vsrc2 = INST_B(inst); \
+ if ((s4) GET_REGISTER(vsrc1) _cmp (s4) GET_REGISTER(vsrc2)) { \
+ int branchOffset = (s2)FETCH(1); /* sign-extended */ \
+ ILOGV("|if-%s v%d,v%d,+0x%04x", (_opname), vsrc1, vsrc2, \
+ branchOffset); \
+ ILOGV("> branch taken"); \
+ if (branchOffset < 0) \
+ PERIODIC_CHECKS(branchOffset); \
+ FINISH(branchOffset); \
+ } else { \
+ ILOGV("|if-%s v%d,v%d,-", (_opname), vsrc1, vsrc2); \
+ FINISH(2); \
+ }
+
+#define HANDLE_OP_IF_XXZ(_opcode, _opname, _cmp) \
+ HANDLE_OPCODE(_opcode /*vAA, +BBBB*/) \
+ vsrc1 = INST_AA(inst); \
+ if ((s4) GET_REGISTER(vsrc1) _cmp 0) { \
+ int branchOffset = (s2)FETCH(1); /* sign-extended */ \
+ ILOGV("|if-%s v%d,+0x%04x", (_opname), vsrc1, branchOffset); \
+ ILOGV("> branch taken"); \
+ if (branchOffset < 0) \
+ PERIODIC_CHECKS(branchOffset); \
+ FINISH(branchOffset); \
+ } else { \
+ ILOGV("|if-%s v%d,-", (_opname), vsrc1); \
+ FINISH(2); \
+ }
+
+#define HANDLE_UNOP(_opcode, _opname, _pfx, _sfx, _type) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER##_type(vdst, _pfx GET_REGISTER##_type(vsrc1) _sfx); \
+ FINISH(1);
+
+#define HANDLE_OP_X_INT(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER(vsrc1); \
+ secondVal = GET_REGISTER(vsrc2); \
+ if (secondVal == 0) { \
+ EXPORT_PC(); \
+ dvmThrowArithmeticException("divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && secondVal == -1) { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ /* non-div/rem case */ \
+ SET_REGISTER(vdst, \
+ (s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2)); \
+ } \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER(vdst, \
+ _cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ vsrc2 = FETCH(1); \
+ ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x", \
+ (_opname), vdst, vsrc1, vsrc2); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, result; \
+ firstVal = GET_REGISTER(vsrc1); \
+ if ((s2) vsrc2 == 0) { \
+ EXPORT_PC(); \
+ dvmThrowArithmeticException("divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) { \
+ /* won't generate /lit16 instr for this; check anyway */ \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op (s2) vsrc2; \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ /* non-div/rem case */ \
+ SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \
+ { \
+ u2 litInfo; \
+ vdst = INST_AA(inst); \
+ litInfo = FETCH(1); \
+ vsrc1 = litInfo & 0xff; \
+ vsrc2 = litInfo >> 8; /* constant */ \
+ ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \
+ (_opname), vdst, vsrc1, vsrc2); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, result; \
+ firstVal = GET_REGISTER(vsrc1); \
+ if ((s1) vsrc2 == 0) { \
+ EXPORT_PC(); \
+ dvmThrowArithmeticException("divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op ((s1) vsrc2); \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ SET_REGISTER(vdst, \
+ (s4) GET_REGISTER(vsrc1) _op (s1) vsrc2); \
+ } \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \
+ { \
+ u2 litInfo; \
+ vdst = INST_AA(inst); \
+ litInfo = FETCH(1); \
+ vsrc1 = litInfo & 0xff; \
+ vsrc2 = litInfo >> 8; /* constant */ \
+ ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \
+ (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER(vdst, \
+ _cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER(vdst); \
+ secondVal = GET_REGISTER(vsrc1); \
+ if (secondVal == 0) { \
+ EXPORT_PC(); \
+ dvmThrowArithmeticException("divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && secondVal == -1) { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ SET_REGISTER(vdst, \
+ (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1)); \
+ } \
+ FINISH(1);
+
+#define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER(vdst, \
+ _cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f)); \
+ FINISH(1);
+
+#define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ if (_chkdiv != 0) { \
+ s8 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER_WIDE(vsrc1); \
+ secondVal = GET_REGISTER_WIDE(vsrc2); \
+ if (secondVal == 0LL) { \
+ EXPORT_PC(); \
+ dvmThrowArithmeticException("divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u8)firstVal == 0x8000000000000000ULL && \
+ secondVal == -1LL) \
+ { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER_WIDE(vdst, result); \
+ } else { \
+ SET_REGISTER_WIDE(vdst, \
+ (s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \
+ } \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER_WIDE(vdst, \
+ _cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ if (_chkdiv != 0) { \
+ s8 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER_WIDE(vdst); \
+ secondVal = GET_REGISTER_WIDE(vsrc1); \
+ if (secondVal == 0LL) { \
+ EXPORT_PC(); \
+ dvmThrowArithmeticException("divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u8)firstVal == 0x8000000000000000ULL && \
+ secondVal == -1LL) \
+ { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER_WIDE(vdst, result); \
+ } else { \
+ SET_REGISTER_WIDE(vdst, \
+ (s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\
+ } \
+ FINISH(1);
+
+#define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER_WIDE(vdst, \
+ _cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \
+ FINISH(1);
+
+#define HANDLE_OP_X_FLOAT(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER_FLOAT(vdst, \
+ GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER_DOUBLE(vdst, \
+ GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER_FLOAT(vdst, \
+ GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1)); \
+ FINISH(1);
+
+#define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER_DOUBLE(vdst, \
+ GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1)); \
+ FINISH(1);
+
+#define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ ArrayObject* arrayObj; \
+ u2 arrayInfo; \
+ EXPORT_PC(); \
+ vdst = INST_AA(inst); \
+ arrayInfo = FETCH(1); \
+ vsrc1 = arrayInfo & 0xff; /* array ptr */ \
+ vsrc2 = arrayInfo >> 8; /* index */ \
+ ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \
+ if (!checkForNull((Object*) arrayObj)) \
+ GOTO_exceptionThrown(); \
+ if (GET_REGISTER(vsrc2) >= arrayObj->length) { \
+ dvmThrowArrayIndexOutOfBoundsException( \
+ arrayObj->length, GET_REGISTER(vsrc2)); \
+ GOTO_exceptionThrown(); \
+ } \
+ SET_REGISTER##_regsize(vdst, \
+ ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]); \
+ ILOGV("+ AGET[%d]=%#x", GET_REGISTER(vsrc2), GET_REGISTER(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ ArrayObject* arrayObj; \
+ u2 arrayInfo; \
+ EXPORT_PC(); \
+ vdst = INST_AA(inst); /* AA: source value */ \
+ arrayInfo = FETCH(1); \
+ vsrc1 = arrayInfo & 0xff; /* BB: array ptr */ \
+ vsrc2 = arrayInfo >> 8; /* CC: index */ \
+ ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \
+ if (!checkForNull((Object*) arrayObj)) \
+ GOTO_exceptionThrown(); \
+ if (GET_REGISTER(vsrc2) >= arrayObj->length) { \
+ dvmThrowArrayIndexOutOfBoundsException( \
+ arrayObj->length, GET_REGISTER(vsrc2)); \
+ GOTO_exceptionThrown(); \
+ } \
+ ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+ ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)] = \
+ GET_REGISTER##_regsize(vdst); \
+ } \
+ FINISH(2);
+
+/*
+ * It's possible to get a bad value out of a field with sub-32-bit stores
+ * because the -quick versions always operate on 32 bits. Consider:
+ * short foo = -1 (sets a 32-bit register to 0xffffffff)
+ * iput-quick foo (writes all 32 bits to the field)
+ * short bar = 1 (sets a 32-bit register to 0x00000001)
+ * iput-short (writes the low 16 bits to the field)
+ * iget-quick foo (reads all 32 bits from the field, yielding 0xffff0001)
+ * This can only happen when optimized and non-optimized code has interleaved
+ * access to the same field. This is unlikely but possible.
+ *
+ * The easiest way to fix this is to always read/write 32 bits at a time. On
+ * a device with a 16-bit data bus this is sub-optimal. (The alternative
+ * approach is to have sub-int versions of iget-quick, but now we're wasting
+ * Dalvik instruction space and making it less likely that handler code will
+ * already be in the CPU i-cache.)
+ */
+#define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ InstField* ifield; \
+ Object* obj; \
+ EXPORT_PC(); \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNull(obj)) \
+ GOTO_exceptionThrown(); \
+ ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
+ if (ifield == NULL) { \
+ ifield = dvmResolveInstField(curMethod->clazz, ref); \
+ if (ifield == NULL) \
+ GOTO_exceptionThrown(); \
+ } \
+ SET_REGISTER##_regsize(vdst, \
+ dvmGetField##_ftype(obj, ifield->byteOffset)); \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->name, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ Object* obj; \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field offset */ \
+ ILOGV("|iget%s-quick v%d,v%d,field@+%u", \
+ (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNullExportPC(obj, fp, pc)) \
+ GOTO_exceptionThrown(); \
+ SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref)); \
+ ILOGV("+ IGETQ %d=0x%08llx", ref, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ InstField* ifield; \
+ Object* obj; \
+ EXPORT_PC(); \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNull(obj)) \
+ GOTO_exceptionThrown(); \
+ ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
+ if (ifield == NULL) { \
+ ifield = dvmResolveInstField(curMethod->clazz, ref); \
+ if (ifield == NULL) \
+ GOTO_exceptionThrown(); \
+ } \
+ dvmSetField##_ftype(obj, ifield->byteOffset, \
+ GET_REGISTER##_regsize(vdst)); \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->name, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ Object* obj; \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field offset */ \
+ ILOGV("|iput%s-quick v%d,v%d,field@0x%04x", \
+ (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNullExportPC(obj, fp, pc)) \
+ GOTO_exceptionThrown(); \
+ dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst)); \
+ ILOGV("+ IPUTQ %d=0x%08llx", ref, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ } \
+ FINISH(2);
+
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Because the portable interpreter is not involved with the JIT
+ * and trace building, we only need the extra check here when this
+ * code is massaged into a stub called from an assembly interpreter.
+ * This is controlled by the JIT_STUB_HACK maco.
+ */
+
+#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
+ { \
+ StaticField* sfield; \
+ vdst = INST_AA(inst); \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref); \
+ sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+ if (sfield == NULL) { \
+ EXPORT_PC(); \
+ sfield = dvmResolveStaticField(curMethod->clazz, ref); \
+ if (sfield == NULL) \
+ GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc)); \
+ } \
+ } \
+ SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
+ ILOGV("+ SGET '%s'=0x%08llx", \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
+ { \
+ StaticField* sfield; \
+ vdst = INST_AA(inst); \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref); \
+ sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+ if (sfield == NULL) { \
+ EXPORT_PC(); \
+ sfield = dvmResolveStaticField(curMethod->clazz, ref); \
+ if (sfield == NULL) \
+ GOTO_exceptionThrown(); \
+ if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
+ JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc)); \
+ } \
+ } \
+ dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
+ ILOGV("+ SPUT '%s'=0x%08llx", \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
+ } \
+ FINISH(2);
+
+/* File: c/OP_BREAKPOINT.cpp */
+HANDLE_OPCODE(OP_BREAKPOINT)
+ {
+ /*
+ * Restart this instruction with the original opcode. We do
+ * this by simply jumping to the handler.
+ *
+ * It's probably not necessary to update "inst", but we do it
+ * for the sake of anything that needs to do disambiguation in a
+ * common handler with INST_INST.
+ *
+ * The breakpoint itself is handled over in updateDebugger(),
+ * because we need to detect other events (method entry, single
+ * step) and report them in the same event packet, and we're not
+ * yet handling those through breakpoint instructions. By the
+ * time we get here, the breakpoint has already been handled and
+ * the thread resumed.
+ */
+ u1 originalOpcode = dvmGetOriginalOpcode(pc);
+ ALOGV("+++ break 0x%02x (0x%04x -> 0x%04x)", originalOpcode, inst,
+ INST_REPLACE_OP(inst, originalOpcode));
+ inst = INST_REPLACE_OP(inst, originalOpcode);
+ FINISH_BKPT(originalOpcode);
+ }
+OP_END
+
+/* File: c/gotoTargets.cpp */
+/*
+ * C footer. This has some common code shared by the various targets.
+ */
+
+/*
+ * Everything from here on is a "goto target". In the basic interpreter
+ * we jump into these targets and then jump directly to the handler for
+ * next instruction. Here, these are subroutines that return to the caller.
+ */
+
+GOTO_TARGET(filledNewArray, bool methodCallRange, bool)
+ {
+ ClassObject* arrayClass;
+ ArrayObject* newArray;
+ u4* contents;
+ char typeCh;
+ int i;
+ u4 arg5;
+
+ EXPORT_PC();
+
+ ref = FETCH(1); /* class ref */
+ vdst = FETCH(2); /* first 4 regs -or- range base */
+
+ if (methodCallRange) {
+ vsrc1 = INST_AA(inst); /* #of elements */
+ arg5 = -1; /* silence compiler warning */
+ ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}",
+ vsrc1, ref, vdst, vdst+vsrc1-1);
+ } else {
+ arg5 = INST_A(inst);
+ vsrc1 = INST_B(inst); /* #of elements */
+ ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}",
+ vsrc1, ref, vdst, arg5);
+ }
+
+ /*
+ * Resolve the array class.
+ */
+ arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+ if (arrayClass == NULL) {
+ arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+ if (arrayClass == NULL)
+ GOTO_exceptionThrown();
+ }
+ /*
+ if (!dvmIsArrayClass(arrayClass)) {
+ dvmThrowRuntimeException(
+ "filled-new-array needs array class");
+ GOTO_exceptionThrown();
+ }
+ */
+ /* verifier guarantees this is an array class */
+ assert(dvmIsArrayClass(arrayClass));
+ assert(dvmIsClassInitialized(arrayClass));
+
+ /*
+ * Create an array of the specified type.
+ */
+ LOGVV("+++ filled-new-array type is '%s'", arrayClass->descriptor);
+ typeCh = arrayClass->descriptor[1];
+ if (typeCh == 'D' || typeCh == 'J') {
+ /* category 2 primitives not allowed */
+ dvmThrowRuntimeException("bad filled array req");
+ GOTO_exceptionThrown();
+ } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') {
+ /* TODO: requires multiple "fill in" loops with different widths */
+ ALOGE("non-int primitives not implemented");
+ dvmThrowInternalError(
+ "filled-new-array not implemented for anything but 'int'");
+ GOTO_exceptionThrown();
+ }
+
+ newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK);
+ if (newArray == NULL)
+ GOTO_exceptionThrown();
+
+ /*
+ * Fill in the elements. It's legal for vsrc1 to be zero.
+ */
+ contents = (u4*)(void*)newArray->contents;
+ if (methodCallRange) {
+ for (i = 0; i < vsrc1; i++)
+ contents[i] = GET_REGISTER(vdst+i);
+ } else {
+ assert(vsrc1 <= 5);
+ if (vsrc1 == 5) {
+ contents[4] = GET_REGISTER(arg5);
+ vsrc1--;
+ }
+ for (i = 0; i < vsrc1; i++) {
+ contents[i] = GET_REGISTER(vdst & 0x0f);
+ vdst >>= 4;
+ }
+ }
+ if (typeCh == 'L' || typeCh == '[') {
+ dvmWriteBarrierArray(newArray, 0, newArray->length);
+ }
+
+ retval.l = (Object*)newArray;
+ }
+ FINISH(3);
+GOTO_TARGET_END
+
+
+GOTO_TARGET(invokeVirtual, bool methodCallRange, bool)
+ {
+ Method* baseMethod;
+ Object* thisPtr;
+
+ EXPORT_PC();
+
+ vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
+ ref = FETCH(1); /* method ref */
+ vdst = FETCH(2); /* 4 regs -or- first reg */
+
+ /*
+ * The object against which we are executing a method is always
+ * in the first argument.
+ */
+ if (methodCallRange) {
+ assert(vsrc1 > 0);
+ ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}",
+ vsrc1, ref, vdst, vdst+vsrc1-1);
+ thisPtr = (Object*) GET_REGISTER(vdst);
+ } else {
+ assert((vsrc1>>4) > 0);
+ ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}",
+ vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+ thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+ }
+
+ if (!checkForNull(thisPtr))
+ GOTO_exceptionThrown();
+
+ /*
+ * Resolve the method. This is the correct method for the static
+ * type of the object. We also verify access permissions here.
+ */
+ baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+ if (baseMethod == NULL) {
+ baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+ if (baseMethod == NULL) {
+ ILOGV("+ unknown method or access denied");
+ GOTO_exceptionThrown();
+ }
+ }
+
+ /*
+ * Combine the object we found with the vtable offset in the
+ * method.
+ */
+ assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
+ methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+ self->methodToCall = methodToCall;
+ self->callsiteClass = thisPtr->clazz;
+#endif
+
+#if 0
+ if (dvmIsAbstractMethod(methodToCall)) {
+ /*
+ * This can happen if you create two classes, Base and Sub, where
+ * Sub is a sub-class of Base. Declare a protected abstract
+ * method foo() in Base, and invoke foo() from a method in Base.
+ * Base is an "abstract base class" and is never instantiated
+ * directly. Now, Override foo() in Sub, and use Sub. This
+ * Works fine unless Sub stops providing an implementation of
+ * the method.
+ */
+ dvmThrowAbstractMethodError("abstract method not implemented");
+ GOTO_exceptionThrown();
+ }
+#else
+ assert(!dvmIsAbstractMethod(methodToCall) ||
+ methodToCall->nativeFunc != NULL);
+#endif
+
+ LOGVV("+++ base=%s.%s virtual[%d]=%s.%s",
+ baseMethod->clazz->descriptor, baseMethod->name,
+ (u4) baseMethod->methodIndex,
+ methodToCall->clazz->descriptor, methodToCall->name);
+ assert(methodToCall != NULL);
+
+#if 0
+ if (vsrc1 != methodToCall->insSize) {
+ ALOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s",
+ baseMethod->clazz->descriptor, baseMethod->name,
+ (u4) baseMethod->methodIndex,
+ methodToCall->clazz->descriptor, methodToCall->name);
+ //dvmDumpClass(baseMethod->clazz);
+ //dvmDumpClass(methodToCall->clazz);
+ dvmDumpAllClasses(0);
+ }
+#endif
+
+ GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+ }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuper, bool methodCallRange)
+ {
+ Method* baseMethod;
+ u2 thisReg;
+
+ EXPORT_PC();
+
+ vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
+ ref = FETCH(1); /* method ref */
+ vdst = FETCH(2); /* 4 regs -or- first reg */
+
+ if (methodCallRange) {
+ ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
+ vsrc1, ref, vdst, vdst+vsrc1-1);
+ thisReg = vdst;
+ } else {
+ ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
+ vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+ thisReg = vdst & 0x0f;
+ }
+
+ /* impossible in well-formed code, but we must check nevertheless */
+ if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+ GOTO_exceptionThrown();
+
+ /*
+ * Resolve the method. This is the correct method for the static
+ * type of the object. We also verify access permissions here.
+ * The first arg to dvmResolveMethod() is just the referring class
+ * (used for class loaders and such), so we don't want to pass
+ * the superclass into the resolution call.
+ */
+ baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+ if (baseMethod == NULL) {
+ baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+ if (baseMethod == NULL) {
+ ILOGV("+ unknown method or access denied");
+ GOTO_exceptionThrown();
+ }
+ }
+
+ /*
+ * Combine the object we found with the vtable offset in the
+ * method's class.
+ *
+ * We're using the current method's class' superclass, not the
+ * superclass of "this". This is because we might be executing
+ * in a method inherited from a superclass, and we want to run
+ * in that class' superclass.
+ */
+ if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
+ /*
+ * Method does not exist in the superclass. Could happen if
+ * superclass gets updated.
+ */
+ dvmThrowNoSuchMethodError(baseMethod->name);
+ GOTO_exceptionThrown();
+ }
+ methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
+
+#if 0
+ if (dvmIsAbstractMethod(methodToCall)) {
+ dvmThrowAbstractMethodError("abstract method not implemented");
+ GOTO_exceptionThrown();
+ }
+#else
+ assert(!dvmIsAbstractMethod(methodToCall) ||
+ methodToCall->nativeFunc != NULL);
+#endif
+ LOGVV("+++ base=%s.%s super-virtual=%s.%s",
+ baseMethod->clazz->descriptor, baseMethod->name,
+ methodToCall->clazz->descriptor, methodToCall->name);
+ assert(methodToCall != NULL);
+
+ GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+ }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeInterface, bool methodCallRange)
+ {
+ Object* thisPtr;
+ ClassObject* thisClass;
+
+ EXPORT_PC();
+
+ vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
+ ref = FETCH(1); /* method ref */
+ vdst = FETCH(2); /* 4 regs -or- first reg */
+
+ /*
+ * The object against which we are executing a method is always
+ * in the first argument.
+ */
+ if (methodCallRange) {
+ assert(vsrc1 > 0);
+ ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}",
+ vsrc1, ref, vdst, vdst+vsrc1-1);
+ thisPtr = (Object*) GET_REGISTER(vdst);
+ } else {
+ assert((vsrc1>>4) > 0);
+ ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}",
+ vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+ thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+ }
+
+ if (!checkForNull(thisPtr))
+ GOTO_exceptionThrown();
+
+ thisClass = thisPtr->clazz;
+
+ /*
+ * Given a class and a method index, find the Method* with the
+ * actual code we want to execute.
+ */
+ methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
+ methodClassDex);
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+ self->callsiteClass = thisClass;
+ self->methodToCall = methodToCall;
+#endif
+ if (methodToCall == NULL) {
+ assert(dvmCheckException(self));
+ GOTO_exceptionThrown();
+ }
+
+ GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+ }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeDirect, bool methodCallRange)
+ {
+ u2 thisReg;
+
+ EXPORT_PC();
+
+ vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
+ ref = FETCH(1); /* method ref */
+ vdst = FETCH(2); /* 4 regs -or- first reg */
+
+ if (methodCallRange) {
+ ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}",
+ vsrc1, ref, vdst, vdst+vsrc1-1);
+ thisReg = vdst;
+ } else {
+ ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}",
+ vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+ thisReg = vdst & 0x0f;
+ }
+
+ if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+ GOTO_exceptionThrown();
+
+ methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+ if (methodToCall == NULL) {
+ methodToCall = dvmResolveMethod(curMethod->clazz, ref,
+ METHOD_DIRECT);
+ if (methodToCall == NULL) {
+ ILOGV("+ unknown direct method"); // should be impossible
+ GOTO_exceptionThrown();
+ }
+ }
+ GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+ }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeStatic, bool methodCallRange)
+ EXPORT_PC();
+
+ vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
+ ref = FETCH(1); /* method ref */
+ vdst = FETCH(2); /* 4 regs -or- first reg */
+
+ if (methodCallRange)
+ ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}",
+ vsrc1, ref, vdst, vdst+vsrc1-1);
+ else
+ ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}",
+ vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+
+ methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+ if (methodToCall == NULL) {
+ methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC);
+ if (methodToCall == NULL) {
+ ILOGV("+ unknown method");
+ GOTO_exceptionThrown();
+ }
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+ /*
+ * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+ * Include the check if this code is being used as a stub
+ * called from the assembly interpreter.
+ */
+ if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+ (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL)) {
+ /* Class initialization is still ongoing */
+ dvmJitEndTraceSelect(self,pc);
+ }
+#endif
+ }
+ GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
+ {
+ Object* thisPtr;
+
+ EXPORT_PC();
+
+ vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
+ ref = FETCH(1); /* vtable index */
+ vdst = FETCH(2); /* 4 regs -or- first reg */
+
+ /*
+ * The object against which we are executing a method is always
+ * in the first argument.
+ */
+ if (methodCallRange) {
+ assert(vsrc1 > 0);
+ ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+ vsrc1, ref, vdst, vdst+vsrc1-1);
+ thisPtr = (Object*) GET_REGISTER(vdst);
+ } else {
+ assert((vsrc1>>4) > 0);
+ ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}",
+ vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+ thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+ }
+
+ if (!checkForNull(thisPtr))
+ GOTO_exceptionThrown();
+
+
+ /*
+ * Combine the object we found with the vtable offset in the
+ * method.
+ */
+ assert(ref < (unsigned int) thisPtr->clazz->vtableCount);
+ methodToCall = thisPtr->clazz->vtable[ref];
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+ self->callsiteClass = thisPtr->clazz;
+ self->methodToCall = methodToCall;
+#endif
+
+#if 0
+ if (dvmIsAbstractMethod(methodToCall)) {
+ dvmThrowAbstractMethodError("abstract method not implemented");
+ GOTO_exceptionThrown();
+ }
+#else
+ assert(!dvmIsAbstractMethod(methodToCall) ||
+ methodToCall->nativeFunc != NULL);
+#endif
+
+ LOGVV("+++ virtual[%d]=%s.%s",
+ ref, methodToCall->clazz->descriptor, methodToCall->name);
+ assert(methodToCall != NULL);
+
+ GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+ }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuperQuick, bool methodCallRange)
+ {
+ u2 thisReg;
+
+ EXPORT_PC();
+
+ vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
+ ref = FETCH(1); /* vtable index */
+ vdst = FETCH(2); /* 4 regs -or- first reg */
+
+ if (methodCallRange) {
+ ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+ vsrc1, ref, vdst, vdst+vsrc1-1);
+ thisReg = vdst;
+ } else {
+ ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}",
+ vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+ thisReg = vdst & 0x0f;
+ }
+ /* impossible in well-formed code, but we must check nevertheless */
+ if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+ GOTO_exceptionThrown();
+
+#if 0 /* impossible in optimized + verified code */
+ if (ref >= curMethod->clazz->super->vtableCount) {
+ dvmThrowNoSuchMethodError(NULL);
+ GOTO_exceptionThrown();
+ }
+#else
+ assert(ref < (unsigned int) curMethod->clazz->super->vtableCount);
+#endif
+
+ /*
+ * Combine the object we found with the vtable offset in the
+ * method's class.
+ *
+ * We're using the current method's class' superclass, not the
+ * superclass of "this". This is because we might be executing
+ * in a method inherited from a superclass, and we want to run
+ * in the method's class' superclass.
+ */
+ methodToCall = curMethod->clazz->super->vtable[ref];
+
+#if 0
+ if (dvmIsAbstractMethod(methodToCall)) {
+ dvmThrowAbstractMethodError("abstract method not implemented");
+ GOTO_exceptionThrown();
+ }
+#else
+ assert(!dvmIsAbstractMethod(methodToCall) ||
+ methodToCall->nativeFunc != NULL);
+#endif
+ LOGVV("+++ super-virtual[%d]=%s.%s",
+ ref, methodToCall->clazz->descriptor, methodToCall->name);
+ assert(methodToCall != NULL);
+ GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+ }
+GOTO_TARGET_END
+
+
+ /*
+ * General handling for return-void, return, and return-wide. Put the
+ * return value in "retval" before jumping here.
+ */
+GOTO_TARGET(returnFromMethod)
+ {
+ StackSaveArea* saveArea;
+
+ /*
+ * We must do this BEFORE we pop the previous stack frame off, so
+ * that the GC can see the return value (if any) in the local vars.
+ *
+ * Since this is now an interpreter switch point, we must do it before
+ * we do anything at all.
+ */
+ PERIODIC_CHECKS(0);
+
+ ILOGV("> retval=0x%llx (leaving %s.%s %s)",
+ retval.j, curMethod->clazz->descriptor, curMethod->name,
+ curMethod->shorty);
+ //DUMP_REGS(curMethod, fp);
+
+ saveArea = SAVEAREA_FROM_FP(fp);
+
+#ifdef EASY_GDB
+ debugSaveArea = saveArea;
+#endif
+
+ /* back up to previous frame and see if we hit a break */
+ fp = (u4*)saveArea->prevFrame;
+ assert(fp != NULL);
+
+ /* Handle any special subMode requirements */
+ if (self->interpBreak.ctl.subMode != 0) {
+ PC_FP_TO_SELF();
+ dvmReportReturn(self);
+ }
+
+ if (dvmIsBreakFrame(fp)) {
+ /* bail without popping the method frame from stack */
+ LOGVV("+++ returned into break frame");
+ GOTO_bail();
+ }
+
+ /* update thread FP, and reset local variables */
+ self->interpSave.curFrame = fp;
+ curMethod = SAVEAREA_FROM_FP(fp)->method;
+ self->interpSave.method = curMethod;
+ //methodClass = curMethod->clazz;
+ methodClassDex = curMethod->clazz->pDvmDex;
+ pc = saveArea->savedPc;
+ ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
+ curMethod->name, curMethod->shorty);
+
+ /* use FINISH on the caller's invoke instruction */
+ //u2 invokeInstr = INST_INST(FETCH(0));
+ if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+ invokeInstr <= OP_INVOKE_INTERFACE*/)
+ {
+ FINISH(3);
+ } else {
+ //ALOGE("Unknown invoke instr %02x at %d",
+ // invokeInstr, (int) (pc - curMethod->insns));
+ assert(false);
+ }
+ }
+GOTO_TARGET_END
+
+
+ /*
+ * Jump here when the code throws an exception.
+ *
+ * By the time we get here, the Throwable has been created and the stack
+ * trace has been saved off.
+ */
+GOTO_TARGET(exceptionThrown)
+ {
+ Object* exception;
+ int catchRelPc;
+
+ PERIODIC_CHECKS(0);
+
+ /*
+ * We save off the exception and clear the exception status. While
+ * processing the exception we might need to load some Throwable
+ * classes, and we don't want class loader exceptions to get
+ * confused with this one.
+ */
+ assert(dvmCheckException(self));
+ exception = dvmGetException(self);
+ dvmAddTrackedAlloc(exception, self);
+ dvmClearException(self);
+
+ ALOGV("Handling exception %s at %s:%d",
+ exception->clazz->descriptor, curMethod->name,
+ dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+
+ /*
+ * Report the exception throw to any "subMode" watchers.
+ *
+ * TODO: if the exception was thrown by interpreted code, control
+ * fell through native, and then back to us, we will report the
+ * exception at the point of the throw and again here. We can avoid
+ * this by not reporting exceptions when we jump here directly from
+ * the native call code above, but then we won't report exceptions
+ * that were thrown *from* the JNI code (as opposed to *through* it).
+ *
+ * The correct solution is probably to ignore from-native exceptions
+ * here, and have the JNI exception code do the reporting to the
+ * debugger.
+ */
+ if (self->interpBreak.ctl.subMode != 0) {
+ PC_FP_TO_SELF();
+ dvmReportExceptionThrow(self, exception);
+ }
+
+ /*
+ * We need to unroll to the catch block or the nearest "break"
+ * frame.
+ *
+ * A break frame could indicate that we have reached an intermediate
+ * native call, or have gone off the top of the stack and the thread
+ * needs to exit. Either way, we return from here, leaving the
+ * exception raised.
+ *
+ * If we do find a catch block, we want to transfer execution to
+ * that point.
+ *
+ * Note this can cause an exception while resolving classes in
+ * the "catch" blocks.
+ */
+ catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
+ exception, false, (void**)(void*)&fp);
+
+ /*
+ * Restore the stack bounds after an overflow. This isn't going to
+ * be correct in all circumstances, e.g. if JNI code devours the
+ * exception this won't happen until some other exception gets
+ * thrown. If the code keeps pushing the stack bounds we'll end
+ * up aborting the VM.
+ *
+ * Note we want to do this *after* the call to dvmFindCatchBlock,
+ * because that may need extra stack space to resolve exception
+ * classes (e.g. through a class loader).
+ *
+ * It's possible for the stack overflow handling to cause an
+ * exception (specifically, class resolution in a "catch" block
+ * during the call above), so we could see the thread's overflow
+ * flag raised but actually be running in a "nested" interpreter
+ * frame. We don't allow doubled-up StackOverflowErrors, so
+ * we can check for this by just looking at the exception type
+ * in the cleanup function. Also, we won't unroll past the SOE
+ * point because the more-recent exception will hit a break frame
+ * as it unrolls to here.
+ */
+ if (self->stackOverflowed)
+ dvmCleanupStackOverflow(self, exception);
+
+ if (catchRelPc < 0) {
+ /* falling through to JNI code or off the bottom of the stack */
+#if DVM_SHOW_EXCEPTION >= 2
+ ALOGD("Exception %s from %s:%d not caught locally",
+ exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+ dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+#endif
+ dvmSetException(self, exception);
+ dvmReleaseTrackedAlloc(exception, self);
+ GOTO_bail();
+ }
+
+#if DVM_SHOW_EXCEPTION >= 3
+ {
+ const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method;
+ ALOGD("Exception %s thrown from %s:%d to %s:%d",
+ exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+ dvmLineNumFromPC(curMethod, pc - curMethod->insns),
+ dvmGetMethodSourceFile(catchMethod),
+ dvmLineNumFromPC(catchMethod, catchRelPc));
+ }
+#endif
+
+ /*
+ * Adjust local variables to match self->interpSave.curFrame and the
+ * updated PC.
+ */
+ //fp = (u4*) self->interpSave.curFrame;
+ curMethod = SAVEAREA_FROM_FP(fp)->method;
+ self->interpSave.method = curMethod;
+ //methodClass = curMethod->clazz;
+ methodClassDex = curMethod->clazz->pDvmDex;
+ pc = curMethod->insns + catchRelPc;
+ ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+ curMethod->name, curMethod->shorty);
+ DUMP_REGS(curMethod, fp, false); // show all regs
+
+ /*
+ * Restore the exception if the handler wants it.
+ *
+ * The Dalvik spec mandates that, if an exception handler wants to
+ * do something with the exception, the first instruction executed
+ * must be "move-exception". We can pass the exception along
+ * through the thread struct, and let the move-exception instruction
+ * clear it for us.
+ *
+ * If the handler doesn't call move-exception, we don't want to
+ * finish here with an exception still pending.
+ */
+ if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION)
+ dvmSetException(self, exception);
+
+ dvmReleaseTrackedAlloc(exception, self);
+ FINISH(0);
+ }
+GOTO_TARGET_END
+
+
+
+ /*
+ * General handling for invoke-{virtual,super,direct,static,interface},
+ * including "quick" variants.
+ *
+ * Set "methodToCall" to the Method we're calling, and "methodCallRange"
+ * depending on whether this is a "/range" instruction.
+ *
+ * For a range call:
+ * "vsrc1" holds the argument count (8 bits)
+ * "vdst" holds the first argument in the range
+ * For a non-range call:
+ * "vsrc1" holds the argument count (4 bits) and the 5th argument index
+ * "vdst" holds four 4-bit register indices
+ *
+ * The caller must EXPORT_PC before jumping here, because any method
+ * call can throw a stack overflow exception.
+ */
+GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
+ u2 count, u2 regs)
+ {
+ STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;);
+
+ //printf("range=%d call=%p count=%d regs=0x%04x\n",
+ // methodCallRange, methodToCall, count, regs);
+ //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
+ // methodToCall->name, methodToCall->shorty);
+
+ u4* outs;
+ int i;
+
+ /*
+ * Copy args. This may corrupt vsrc1/vdst.
+ */
+ if (methodCallRange) {
+ // could use memcpy or a "Duff's device"; most functions have
+ // so few args it won't matter much
+ assert(vsrc1 <= curMethod->outsSize);
+ assert(vsrc1 == methodToCall->insSize);
+ outs = OUTS_FROM_FP(fp, vsrc1);
+ for (i = 0; i < vsrc1; i++)
+ outs[i] = GET_REGISTER(vdst+i);
+ } else {
+ u4 count = vsrc1 >> 4;
+
+ assert(count <= curMethod->outsSize);
+ assert(count == methodToCall->insSize);
+ assert(count <= 5);
+
+ outs = OUTS_FROM_FP(fp, count);
+#if 0
+ if (count == 5) {
+ outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+ count--;
+ }
+ for (i = 0; i < (int) count; i++) {
+ outs[i] = GET_REGISTER(vdst & 0x0f);
+ vdst >>= 4;
+ }
+#else
+ // This version executes fewer instructions but is larger
+ // overall. Seems to be a teensy bit faster.
+ assert((vdst >> 16) == 0); // 16 bits -or- high 16 bits clear
+ switch (count) {
+ case 5:
+ outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+ case 4:
+ outs[3] = GET_REGISTER(vdst >> 12);
+ case 3:
+ outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8);
+ case 2:
+ outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4);
+ case 1:
+ outs[0] = GET_REGISTER(vdst & 0x0f);
+ default:
+ ;
+ }
+#endif
+ }
+ }
+
+ /*
+ * (This was originally a "goto" target; I've kept it separate from the
+ * stuff above in case we want to refactor things again.)
+ *
+ * At this point, we have the arguments stored in the "outs" area of
+ * the current method's stack frame, and the method to call in
+ * "methodToCall". Push a new stack frame.
+ */
+ {
+ StackSaveArea* newSaveArea;
+ u4* newFp;
+
+ ILOGV("> %s%s.%s %s",
+ dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
+ methodToCall->clazz->descriptor, methodToCall->name,
+ methodToCall->shorty);
+
+ newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
+ newSaveArea = SAVEAREA_FROM_FP(newFp);
+
+ /* verify that we have enough space */
+ if (true) {
+ u1* bottom;
+ bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
+ if (bottom < self->interpStackEnd) {
+ /* stack overflow */
+ ALOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')",
+ self->interpStackStart, self->interpStackEnd, bottom,
+ (u1*) fp - bottom, self->interpStackSize,
+ methodToCall->name);
+ dvmHandleStackOverflow(self, methodToCall);
+ assert(dvmCheckException(self));
+ GOTO_exceptionThrown();
+ }
+ //ALOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p",
+ // fp, newFp, newSaveArea, bottom);
+ }
+
+#ifdef LOG_INSTR
+ if (methodToCall->registersSize > methodToCall->insSize) {
+ /*
+ * This makes valgrind quiet when we print registers that
+ * haven't been initialized. Turn it off when the debug
+ * messages are disabled -- we want valgrind to report any
+ * used-before-initialized issues.
+ */
+ memset(newFp, 0xcc,
+ (methodToCall->registersSize - methodToCall->insSize) * 4);
+ }
+#endif
+
+#ifdef EASY_GDB
+ newSaveArea->prevSave = SAVEAREA_FROM_FP(fp);
+#endif
+ newSaveArea->prevFrame = fp;
+ newSaveArea->savedPc = pc;
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+ newSaveArea->returnAddr = 0;
+#endif
+ newSaveArea->method = methodToCall;
+
+ if (self->interpBreak.ctl.subMode != 0) {
+ /*
+ * We mark ENTER here for both native and non-native
+ * calls. For native calls, we'll mark EXIT on return.
+ * For non-native calls, EXIT is marked in the RETURN op.
+ */
+ PC_TO_SELF();
+ dvmReportInvoke(self, methodToCall);
+ }
+
+ if (!dvmIsNativeMethod(methodToCall)) {
+ /*
+ * "Call" interpreted code. Reposition the PC, update the
+ * frame pointer and other local state, and continue.
+ */
+ curMethod = methodToCall;
+ self->interpSave.method = curMethod;
+ methodClassDex = curMethod->clazz->pDvmDex;
+ pc = methodToCall->insns;
+ fp = newFp;
+ self->interpSave.curFrame = fp;
+#ifdef EASY_GDB
+ debugSaveArea = SAVEAREA_FROM_FP(newFp);
+#endif
+ self->debugIsMethodEntry = true; // profiling, debugging
+ ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+ curMethod->name, curMethod->shorty);
+ DUMP_REGS(curMethod, fp, true); // show input args
+ FINISH(0); // jump to method start
+ } else {
+ /* set this up for JNI locals, even if not a JNI native */
+ newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+
+ self->interpSave.curFrame = newFp;
+
+ DUMP_REGS(methodToCall, newFp, true); // show input args
+
+ if (self->interpBreak.ctl.subMode != 0) {
+ dvmReportPreNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
+ }
+
+ ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+ methodToCall->name, methodToCall->shorty);
+
+ /*
+ * Jump through native call bridge. Because we leave no
+ * space for locals on native calls, "newFp" points directly
+ * to the method arguments.
+ */
+ (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
+
+ if (self->interpBreak.ctl.subMode != 0) {
+ dvmReportPostNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
+ }
+
+ /* pop frame off */
+ dvmPopJniLocals(self, newSaveArea);
+ self->interpSave.curFrame = newSaveArea->prevFrame;
+ fp = newSaveArea->prevFrame;
+
+ /*
+ * If the native code threw an exception, or interpreted code
+ * invoked by the native call threw one and nobody has cleared
+ * it, jump to our local exception handling.
+ */
+ if (dvmCheckException(self)) {
+ ALOGV("Exception thrown by/below native code");
+ GOTO_exceptionThrown();
+ }
+
+ ILOGD("> retval=0x%llx (leaving native)", retval.j);
+ ILOGD("> (return from native %s.%s to %s.%s %s)",
+ methodToCall->clazz->descriptor, methodToCall->name,
+ curMethod->clazz->descriptor, curMethod->name,
+ curMethod->shorty);
+
+ //u2 invokeInstr = INST_INST(FETCH(0));
+ if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+ invokeInstr <= OP_INVOKE_INTERFACE*/)
+ {
+ FINISH(3);
+ } else {
+ //ALOGE("Unknown invoke instr %02x at %d",
+ // invokeInstr, (int) (pc - curMethod->insns));
+ assert(false);
+ }
+ }
+ }
+ assert(false); // should not get here
+GOTO_TARGET_END
+
+/* File: cstubs/enddefs.cpp */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
+/* File: mips/debug.cpp */
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+
+/*
+ * Dump the fixed-purpose MIPS registers, along with some other info.
+ *
+ */
+void dvmMterpDumpMipsRegs(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3)
+{
+ register uint32_t rPC asm("s0");
+ register uint32_t rFP asm("s1");
+ register uint32_t rSELF asm("s2");
+ register uint32_t rIBASE asm("s3");
+ register uint32_t rINST asm("s4");
+ register uint32_t rOBJ asm("s5");
+ register uint32_t rBIX asm("s6");
+ register uint32_t rTEMP asm("s7");
+
+ //extern char dvmAsmInstructionStart[];
+
+ printf("REGS: a0=%08x a1=%08x a2=%08x a3=%08x\n", a0, a1, a2, a3);
+ printf(" : rPC=%08x rFP=%08x rSELF=%08x rIBASE=%08x\n",
+ rPC, rFP, rSELF, rIBASE);
+ printf(" : rINST=%08x rOBJ=%08x rBIX=%08x rTEMP=%08x \n", rINST, rOBJ, rBIX, rTEMP);
+
+ //Thread* self = (Thread*) rSELF;
+ //const Method* method = self->method;
+ printf(" + self is %p\n", dvmThreadSelf());
+ //printf(" + currently in %s.%s %s\n",
+ // method->clazz->descriptor, method->name, method->signature);
+ //printf(" + dvmAsmInstructionStart = %p\n", dvmAsmInstructionStart);
+ //printf(" + next handler for 0x%02x = %p\n",
+ // rINST & 0xff, dvmAsmInstructionStart + (rINST & 0xff) * 64);
+}
+
+/*
+ * Dump the StackSaveArea for the specified frame pointer.
+ */
+void dvmDumpFp(void* fp, StackSaveArea* otherSaveArea)
+{
+ StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
+ printf("StackSaveArea for fp %p [%p/%p]:\n", fp, saveArea, otherSaveArea);
+#ifdef EASY_GDB
+ printf(" prevSave=%p, prevFrame=%p savedPc=%p meth=%p curPc=%p\n",
+ saveArea->prevSave, saveArea->prevFrame, saveArea->savedPc,
+ saveArea->method, saveArea->xtra.currentPc);
+#else
+ printf(" prevFrame=%p savedPc=%p meth=%p curPc=%p fp[0]=0x%08x\n",
+ saveArea->prevFrame, saveArea->savedPc,
+ saveArea->method, saveArea->xtra.currentPc,
+ *(u4*)fp);
+#endif
+}
+
+/*
+ * Does the bulk of the work for common_printMethod().
+ */
+void dvmMterpPrintMethod(Method* method)
+{
+ /*
+ * It is a direct (non-virtual) method if it is static, private,
+ * or a constructor.
+ */
+ bool isDirect =
+ ((method->accessFlags & (ACC_STATIC|ACC_PRIVATE)) != 0) ||
+ (method->name[0] == '<');
+
+ char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+
+ printf("<%c:%s.%s %s> ",
+ isDirect ? 'D' : 'V',
+ method->clazz->descriptor,
+ method->name,
+ desc);
+
+ free(desc);
+}
+
diff --git a/vm/mterp/out/InterpC-portable.cpp b/vm/mterp/out/InterpC-portable.cpp
index 2111a98..0328aa8 100644
--- a/vm/mterp/out/InterpC-portable.cpp
+++ b/vm/mterp/out/InterpC-portable.cpp
@@ -68,6 +68,14 @@
#if defined(__ARM_EABI__)
# define NO_UNALIGN_64__UNION
#endif
+/*
+ * MIPS ABI requires 64-bit alignment for access to 64-bit data types.
+ *
+ * Use memcpy() to do the transfer
+ */
+#if defined(__mips__)
+/* # define NO_UNALIGN_64__UNION */
+#endif
//#define LOG_INSTR /* verbose debugging */
@@ -979,7 +987,7 @@
} \
SET_REGISTER##_regsize(vdst, \
dvmGetField##_ftype(obj, ifield->byteOffset)); \
- ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1023,7 +1031,7 @@
} \
dvmSetField##_ftype(obj, ifield->byteOffset, \
GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1073,7 +1081,7 @@
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1096,7 +1104,7 @@
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1845,7 +1853,7 @@
vsrc1 = INST_AA(inst);
offset = FETCH(1) | (((s4) FETCH(2)) << 16);
- ILOGV("|packed-switch v%d +0x%04x", vsrc1, vsrc2);
+ ILOGV("|packed-switch v%d +0x%04x", vsrc1, offset);
switchData = pc + offset; // offset in 16-bit units
#ifndef NDEBUG
if (switchData < curMethod->insns ||
@@ -1876,7 +1884,7 @@
vsrc1 = INST_AA(inst);
offset = FETCH(1) | (((s4) FETCH(2)) << 16);
- ILOGV("|sparse-switch v%d +0x%04x", vsrc1, vsrc2);
+ ILOGV("|sparse-switch v%d +0x%04x", vsrc1, offset);
switchData = pc + offset; // offset in 16-bit units
#ifndef NDEBUG
if (switchData < curMethod->insns ||
@@ -2053,7 +2061,7 @@
if (!dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
obj->clazz->descriptor, obj,
- arrayObj->obj.clazz->descriptor, arrayObj);
+ arrayObj->clazz->descriptor, arrayObj);
dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
GOTO_exceptionThrown();
}
@@ -2860,7 +2868,7 @@
;
}
- if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+ if (self->interpBreak.ctl.subMode & kSubModeDebugProfile) {
if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
GOTO_exceptionThrown();
} else {
@@ -2905,7 +2913,7 @@
;
}
- if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+ if (self->interpBreak.ctl.subMode & kSubModeDebugProfile) {
if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
GOTO_exceptionThrown();
} else {
@@ -3943,7 +3951,7 @@
DUMP_REGS(methodToCall, newFp, true); // show input args
if (self->interpBreak.ctl.subMode != 0) {
- dvmReportPreNativeInvoke(methodToCall, self, fp);
+ dvmReportPreNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
}
ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
@@ -3957,12 +3965,13 @@
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
if (self->interpBreak.ctl.subMode != 0) {
- dvmReportPostNativeInvoke(methodToCall, self, fp);
+ dvmReportPostNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
}
/* pop frame off */
dvmPopJniLocals(self, newSaveArea);
- self->interpSave.curFrame = fp;
+ self->interpSave.curFrame = newSaveArea->prevFrame;
+ fp = newSaveArea->prevFrame;
/*
* If the native code threw an exception, or interpreted code
diff --git a/vm/mterp/out/InterpC-x86-atom.cpp b/vm/mterp/out/InterpC-x86-atom.cpp
deleted file mode 100644
index 1083f8b..0000000
--- a/vm/mterp/out/InterpC-x86-atom.cpp
+++ /dev/null
@@ -1,2297 +0,0 @@
-/*
- * This file was generated automatically by gen-mterp.py for 'x86-atom'.
- *
- * --> DO NOT EDIT <--
- */
-
-/* File: c/header.cpp */
-/*
- * 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.
- */
-
-/* common includes */
-#include "Dalvik.h"
-#include "interp/InterpDefs.h"
-#include "mterp/Mterp.h"
-#include <math.h> // needed for fmod, fmodf
-#include "mterp/common/FindInterface.h"
-
-/*
- * Configuration defines. These affect the C implementations, i.e. the
- * portable interpreter(s) and C stubs.
- *
- * Some defines are controlled by the Makefile, e.g.:
- * WITH_INSTR_CHECKS
- * WITH_TRACKREF_CHECKS
- * EASY_GDB
- * NDEBUG
- */
-
-#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
-# define CHECK_BRANCH_OFFSETS
-# define CHECK_REGISTER_INDICES
-#endif
-
-/*
- * Some architectures require 64-bit alignment for access to 64-bit data
- * types. We can't just use pointers to copy 64-bit values out of our
- * interpreted register set, because gcc may assume the pointer target is
- * aligned and generate invalid code.
- *
- * There are two common approaches:
- * (1) Use a union that defines a 32-bit pair and a 64-bit value.
- * (2) Call memcpy().
- *
- * Depending upon what compiler you're using and what options are specified,
- * one may be faster than the other. For example, the compiler might
- * convert a memcpy() of 8 bytes into a series of instructions and omit
- * the call. The union version could cause some strange side-effects,
- * e.g. for a while ARM gcc thought it needed separate storage for each
- * inlined instance, and generated instructions to zero out ~700 bytes of
- * stack space at the top of the interpreter.
- *
- * The default is to use memcpy(). The current gcc for ARM seems to do
- * better with the union.
- */
-#if defined(__ARM_EABI__)
-# define NO_UNALIGN_64__UNION
-#endif
-
-
-//#define LOG_INSTR /* verbose debugging */
-/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
-
-/*
- * Export another copy of the PC on every instruction; this is largely
- * redundant with EXPORT_PC and the debugger code. This value can be
- * compared against what we have stored on the stack with EXPORT_PC to
- * help ensure that we aren't missing any export calls.
- */
-#if WITH_EXTRA_GC_CHECKS > 1
-# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
-#else
-# define EXPORT_EXTRA_PC()
-#endif
-
-/*
- * Adjust the program counter. "_offset" is a signed int, in 16-bit units.
- *
- * Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
- *
- * We don't advance the program counter until we finish an instruction or
- * branch, because we do want to have to unroll the PC if there's an
- * exception.
- */
-#ifdef CHECK_BRANCH_OFFSETS
-# define ADJUST_PC(_offset) do { \
- int myoff = _offset; /* deref only once */ \
- if (pc + myoff < curMethod->insns || \
- pc + myoff >= curMethod->insns + dvmGetMethodInsnsSize(curMethod)) \
- { \
- char* desc; \
- desc = dexProtoCopyMethodDescriptor(&curMethod->prototype); \
- ALOGE("Invalid branch %d at 0x%04x in %s.%s %s", \
- myoff, (int) (pc - curMethod->insns), \
- curMethod->clazz->descriptor, curMethod->name, desc); \
- free(desc); \
- dvmAbort(); \
- } \
- pc += myoff; \
- EXPORT_EXTRA_PC(); \
- } while (false)
-#else
-# define ADJUST_PC(_offset) do { \
- pc += _offset; \
- EXPORT_EXTRA_PC(); \
- } while (false)
-#endif
-
-/*
- * If enabled, log instructions as we execute them.
- */
-#ifdef LOG_INSTR
-# define ILOGD(...) ILOG(LOG_DEBUG, __VA_ARGS__)
-# define ILOGV(...) ILOG(LOG_VERBOSE, __VA_ARGS__)
-# define ILOG(_level, ...) do { \
- char debugStrBuf[128]; \
- snprintf(debugStrBuf, sizeof(debugStrBuf), __VA_ARGS__); \
- if (curMethod != NULL) \
- ALOG(_level, LOG_TAG"i", "%-2d|%04x%s", \
- self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
- else \
- ALOG(_level, LOG_TAG"i", "%-2d|####%s", \
- self->threadId, debugStrBuf); \
- } while(false)
-void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly);
-# define DUMP_REGS(_meth, _frame, _inOnly) dvmDumpRegs(_meth, _frame, _inOnly)
-static const char kSpacing[] = " ";
-#else
-# define ILOGD(...) ((void)0)
-# define ILOGV(...) ((void)0)
-# define DUMP_REGS(_meth, _frame, _inOnly) ((void)0)
-#endif
-
-/* get a long from an array of u4 */
-static inline s8 getLongFromArray(const u4* ptr, int idx)
-{
-#if defined(NO_UNALIGN_64__UNION)
- union { s8 ll; u4 parts[2]; } conv;
-
- ptr += idx;
- conv.parts[0] = ptr[0];
- conv.parts[1] = ptr[1];
- return conv.ll;
-#else
- s8 val;
- memcpy(&val, &ptr[idx], 8);
- return val;
-#endif
-}
-
-/* store a long into an array of u4 */
-static inline void putLongToArray(u4* ptr, int idx, s8 val)
-{
-#if defined(NO_UNALIGN_64__UNION)
- union { s8 ll; u4 parts[2]; } conv;
-
- ptr += idx;
- conv.ll = val;
- ptr[0] = conv.parts[0];
- ptr[1] = conv.parts[1];
-#else
- memcpy(&ptr[idx], &val, 8);
-#endif
-}
-
-/* get a double from an array of u4 */
-static inline double getDoubleFromArray(const u4* ptr, int idx)
-{
-#if defined(NO_UNALIGN_64__UNION)
- union { double d; u4 parts[2]; } conv;
-
- ptr += idx;
- conv.parts[0] = ptr[0];
- conv.parts[1] = ptr[1];
- return conv.d;
-#else
- double dval;
- memcpy(&dval, &ptr[idx], 8);
- return dval;
-#endif
-}
-
-/* store a double into an array of u4 */
-static inline void putDoubleToArray(u4* ptr, int idx, double dval)
-{
-#if defined(NO_UNALIGN_64__UNION)
- union { double d; u4 parts[2]; } conv;
-
- ptr += idx;
- conv.d = dval;
- ptr[0] = conv.parts[0];
- ptr[1] = conv.parts[1];
-#else
- memcpy(&ptr[idx], &dval, 8);
-#endif
-}
-
-/*
- * If enabled, validate the register number on every access. Otherwise,
- * just do an array access.
- *
- * Assumes the existence of "u4* fp".
- *
- * "_idx" may be referenced more than once.
- */
-#ifdef CHECK_REGISTER_INDICES
-# define GET_REGISTER(_idx) \
- ( (_idx) < curMethod->registersSize ? \
- (fp[(_idx)]) : (assert(!"bad reg"),1969) )
-# define SET_REGISTER(_idx, _val) \
- ( (_idx) < curMethod->registersSize ? \
- (fp[(_idx)] = (u4)(_val)) : (assert(!"bad reg"),1969) )
-# define GET_REGISTER_AS_OBJECT(_idx) ((Object *)GET_REGISTER(_idx))
-# define SET_REGISTER_AS_OBJECT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
-# define GET_REGISTER_INT(_idx) ((s4) GET_REGISTER(_idx))
-# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
-# define GET_REGISTER_WIDE(_idx) \
- ( (_idx) < curMethod->registersSize-1 ? \
- getLongFromArray(fp, (_idx)) : (assert(!"bad reg"),1969) )
-# define SET_REGISTER_WIDE(_idx, _val) \
- ( (_idx) < curMethod->registersSize-1 ? \
- (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
-# define GET_REGISTER_FLOAT(_idx) \
- ( (_idx) < curMethod->registersSize ? \
- (*((float*) &fp[(_idx)])) : (assert(!"bad reg"),1969.0f) )
-# define SET_REGISTER_FLOAT(_idx, _val) \
- ( (_idx) < curMethod->registersSize ? \
- (*((float*) &fp[(_idx)]) = (_val)) : (assert(!"bad reg"),1969.0f) )
-# define GET_REGISTER_DOUBLE(_idx) \
- ( (_idx) < curMethod->registersSize-1 ? \
- getDoubleFromArray(fp, (_idx)) : (assert(!"bad reg"),1969.0) )
-# define SET_REGISTER_DOUBLE(_idx, _val) \
- ( (_idx) < curMethod->registersSize-1 ? \
- (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
-#else
-# define GET_REGISTER(_idx) (fp[(_idx)])
-# define SET_REGISTER(_idx, _val) (fp[(_idx)] = (_val))
-# define GET_REGISTER_AS_OBJECT(_idx) ((Object*) fp[(_idx)])
-# define SET_REGISTER_AS_OBJECT(_idx, _val) (fp[(_idx)] = (u4)(_val))
-# define GET_REGISTER_INT(_idx) ((s4)GET_REGISTER(_idx))
-# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
-# define GET_REGISTER_WIDE(_idx) getLongFromArray(fp, (_idx))
-# define SET_REGISTER_WIDE(_idx, _val) putLongToArray(fp, (_idx), (_val))
-# define GET_REGISTER_FLOAT(_idx) (*((float*) &fp[(_idx)]))
-# define SET_REGISTER_FLOAT(_idx, _val) (*((float*) &fp[(_idx)]) = (_val))
-# define GET_REGISTER_DOUBLE(_idx) getDoubleFromArray(fp, (_idx))
-# define SET_REGISTER_DOUBLE(_idx, _val) putDoubleToArray(fp, (_idx), (_val))
-#endif
-
-/*
- * Get 16 bits from the specified offset of the program counter. We always
- * want to load 16 bits at a time from the instruction stream -- it's more
- * efficient than 8 and won't have the alignment problems that 32 might.
- *
- * Assumes existence of "const u2* pc".
- */
-#define FETCH(_offset) (pc[(_offset)])
-
-/*
- * Extract instruction byte from 16-bit fetch (_inst is a u2).
- */
-#define INST_INST(_inst) ((_inst) & 0xff)
-
-/*
- * Replace the opcode (used when handling breakpoints). _opcode is a u1.
- */
-#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
-
-/*
- * Extract the "vA, vB" 4-bit registers from the instruction word (_inst is u2).
- */
-#define INST_A(_inst) (((_inst) >> 8) & 0x0f)
-#define INST_B(_inst) ((_inst) >> 12)
-
-/*
- * Get the 8-bit "vAA" 8-bit register index from the instruction word.
- * (_inst is u2)
- */
-#define INST_AA(_inst) ((_inst) >> 8)
-
-/*
- * The current PC must be available to Throwable constructors, e.g.
- * those created by the various exception throw routines, so that the
- * exception stack trace can be generated correctly. If we don't do this,
- * the offset within the current method won't be shown correctly. See the
- * notes in Exception.c.
- *
- * This is also used to determine the address for precise GC.
- *
- * Assumes existence of "u4* fp" and "const u2* pc".
- */
-#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
-
-/*
- * Check to see if "obj" is NULL. If so, throw an exception. Assumes the
- * pc has already been exported to the stack.
- *
- * Perform additional checks on debug builds.
- *
- * Use this to check for NULL when the instruction handler calls into
- * something that could throw an exception (so we have already called
- * EXPORT_PC at the top).
- */
-static inline bool checkForNull(Object* obj)
-{
- if (obj == NULL) {
- dvmThrowNullPointerException(NULL);
- return false;
- }
-#ifdef WITH_EXTRA_OBJECT_VALIDATION
- if (!dvmIsHeapAddress(obj)) {
- ALOGE("Invalid object %p", obj);
- dvmAbort();
- }
-#endif
-#ifndef NDEBUG
- if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
- /* probable heap corruption */
- ALOGE("Invalid object class %p (in %p)", obj->clazz, obj);
- dvmAbort();
- }
-#endif
- return true;
-}
-
-/*
- * Check to see if "obj" is NULL. If so, export the PC into the stack
- * frame and throw an exception.
- *
- * Perform additional checks on debug builds.
- *
- * Use this to check for NULL when the instruction handler doesn't do
- * anything else that can throw an exception.
- */
-static inline bool checkForNullExportPC(Object* obj, u4* fp, const u2* pc)
-{
- if (obj == NULL) {
- EXPORT_PC();
- dvmThrowNullPointerException(NULL);
- return false;
- }
-#ifdef WITH_EXTRA_OBJECT_VALIDATION
- if (!dvmIsHeapAddress(obj)) {
- ALOGE("Invalid object %p", obj);
- dvmAbort();
- }
-#endif
-#ifndef NDEBUG
- if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
- /* probable heap corruption */
- ALOGE("Invalid object class %p (in %p)", obj->clazz, obj);
- dvmAbort();
- }
-#endif
- return true;
-}
-
-/* File: cstubs/stubdefs.cpp */
-/*
- * In the C mterp stubs, "goto" is a function call followed immediately
- * by a return.
- */
-
-#define GOTO_TARGET_DECL(_target, ...) \
- extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
-
-/* (void)xxx to quiet unused variable compiler warnings. */
-#define GOTO_TARGET(_target, ...) \
- void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) { \
- u2 ref, vsrc1, vsrc2, vdst; \
- u2 inst = FETCH(0); \
- const Method* methodToCall; \
- StackSaveArea* debugSaveArea; \
- (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst; \
- (void)methodToCall; (void)debugSaveArea;
-
-#define GOTO_TARGET_END }
-
-/*
- * Redefine what used to be local variable accesses into Thread struct
- * references. (These are undefined down in "footer.cpp".)
- */
-#define retval self->interpSave.retval
-#define pc self->interpSave.pc
-#define fp self->interpSave.curFrame
-#define curMethod self->interpSave.method
-#define methodClassDex self->interpSave.methodClassDex
-#define debugTrackedRefStart self->interpSave.debugTrackedRefStart
-
-/* ugh */
-#define STUB_HACK(x) x
-#if defined(WITH_JIT)
-#define JIT_STUB_HACK(x) x
-#else
-#define JIT_STUB_HACK(x)
-#endif
-
-/*
- * InterpSave's pc and fp must be valid when breaking out to a
- * "Reportxxx" routine. Because the portable interpreter uses local
- * variables for these, we must flush prior. Stubs, however, use
- * the interpSave vars directly, so this is a nop for stubs.
- */
-#define PC_FP_TO_SELF()
-#define PC_TO_SELF()
-
-/*
- * Opcode handler framing macros. Here, each opcode is a separate function
- * that takes a "self" argument and returns void. We can't declare
- * these "static" because they may be called from an assembly stub.
- * (void)xxx to quiet unused variable compiler warnings.
- */
-#define HANDLE_OPCODE(_op) \
- extern "C" void dvmMterp_##_op(Thread* self); \
- void dvmMterp_##_op(Thread* self) { \
- u4 ref; \
- u2 vsrc1, vsrc2, vdst; \
- u2 inst = FETCH(0); \
- (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
-
-#define OP_END }
-
-/*
- * Like the "portable" FINISH, but don't reload "inst", and return to caller
- * when done. Further, debugger/profiler checks are handled
- * before handler execution in mterp, so we don't do them here either.
- */
-#if defined(WITH_JIT)
-#define FINISH(_offset) { \
- ADJUST_PC(_offset); \
- if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) { \
- dvmCheckJit(pc, self); \
- } \
- return; \
- }
-#else
-#define FINISH(_offset) { \
- ADJUST_PC(_offset); \
- return; \
- }
-#endif
-
-
-/*
- * The "goto label" statements turn into function calls followed by
- * return statements. Some of the functions take arguments, which in the
- * portable interpreter are handled by assigning values to globals.
- */
-
-#define GOTO_exceptionThrown() \
- do { \
- dvmMterp_exceptionThrown(self); \
- return; \
- } while(false)
-
-#define GOTO_returnFromMethod() \
- do { \
- dvmMterp_returnFromMethod(self); \
- return; \
- } while(false)
-
-#define GOTO_invoke(_target, _methodCallRange) \
- do { \
- dvmMterp_##_target(self, _methodCallRange); \
- return; \
- } while(false)
-
-#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst) \
- do { \
- dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall, \
- _vsrc1, _vdst); \
- return; \
- } while(false)
-
-/*
- * As a special case, "goto bail" turns into a longjmp.
- */
-#define GOTO_bail() \
- dvmMterpStdBail(self, false);
-
-/*
- * Periodically check for thread suspension.
- *
- * While we're at it, see if a debugger has attached or the profiler has
- * started.
- */
-#define PERIODIC_CHECKS(_pcadj) { \
- if (dvmCheckSuspendQuick(self)) { \
- EXPORT_PC(); /* need for precise GC */ \
- dvmCheckSuspendPending(self); \
- } \
- }
-
-/* File: c/opcommon.cpp */
-/* forward declarations of goto targets */
-GOTO_TARGET_DECL(filledNewArray, bool methodCallRange);
-GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange);
-GOTO_TARGET_DECL(invokeSuper, bool methodCallRange);
-GOTO_TARGET_DECL(invokeInterface, bool methodCallRange);
-GOTO_TARGET_DECL(invokeDirect, bool methodCallRange);
-GOTO_TARGET_DECL(invokeStatic, bool methodCallRange);
-GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange);
-GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange);
-GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall,
- u2 count, u2 regs);
-GOTO_TARGET_DECL(returnFromMethod);
-GOTO_TARGET_DECL(exceptionThrown);
-
-/*
- * ===========================================================================
- *
- * What follows are opcode definitions shared between multiple opcodes with
- * minor substitutions handled by the C pre-processor. These should probably
- * use the mterp substitution mechanism instead, with the code here moved
- * into common fragment files (like the asm "binop.S"), although it's hard
- * to give up the C preprocessor in favor of the much simpler text subst.
- *
- * ===========================================================================
- */
-
-#define HANDLE_NUMCONV(_opcode, _opname, _fromtype, _totype) \
- HANDLE_OPCODE(_opcode /*vA, vB*/) \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
- SET_REGISTER##_totype(vdst, \
- GET_REGISTER##_fromtype(vsrc1)); \
- FINISH(1);
-
-#define HANDLE_FLOAT_TO_INT(_opcode, _opname, _fromvtype, _fromrtype, \
- _tovtype, _tortype) \
- HANDLE_OPCODE(_opcode /*vA, vB*/) \
- { \
- /* spec defines specific handling for +/- inf and NaN values */ \
- _fromvtype val; \
- _tovtype intMin, intMax, result; \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
- val = GET_REGISTER##_fromrtype(vsrc1); \
- intMin = (_tovtype) 1 << (sizeof(_tovtype) * 8 -1); \
- intMax = ~intMin; \
- result = (_tovtype) val; \
- if (val >= intMax) /* +inf */ \
- result = intMax; \
- else if (val <= intMin) /* -inf */ \
- result = intMin; \
- else if (val != val) /* NaN */ \
- result = 0; \
- else \
- result = (_tovtype) val; \
- SET_REGISTER##_tortype(vdst, result); \
- } \
- FINISH(1);
-
-#define HANDLE_INT_TO_SMALL(_opcode, _opname, _type) \
- HANDLE_OPCODE(_opcode /*vA, vB*/) \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- ILOGV("|int-to-%s v%d,v%d", (_opname), vdst, vsrc1); \
- SET_REGISTER(vdst, (_type) GET_REGISTER(vsrc1)); \
- FINISH(1);
-
-/* NOTE: the comparison result is always a signed 4-byte integer */
-#define HANDLE_OP_CMPX(_opcode, _opname, _varType, _type, _nanVal) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
- { \
- int result; \
- u2 regs; \
- _varType val1, val2; \
- vdst = INST_AA(inst); \
- regs = FETCH(1); \
- vsrc1 = regs & 0xff; \
- vsrc2 = regs >> 8; \
- ILOGV("|cmp%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
- val1 = GET_REGISTER##_type(vsrc1); \
- val2 = GET_REGISTER##_type(vsrc2); \
- if (val1 == val2) \
- result = 0; \
- else if (val1 < val2) \
- result = -1; \
- else if (val1 > val2) \
- result = 1; \
- else \
- result = (_nanVal); \
- ILOGV("+ result=%d", result); \
- SET_REGISTER(vdst, result); \
- } \
- FINISH(2);
-
-#define HANDLE_OP_IF_XX(_opcode, _opname, _cmp) \
- HANDLE_OPCODE(_opcode /*vA, vB, +CCCC*/) \
- vsrc1 = INST_A(inst); \
- vsrc2 = INST_B(inst); \
- if ((s4) GET_REGISTER(vsrc1) _cmp (s4) GET_REGISTER(vsrc2)) { \
- int branchOffset = (s2)FETCH(1); /* sign-extended */ \
- ILOGV("|if-%s v%d,v%d,+0x%04x", (_opname), vsrc1, vsrc2, \
- branchOffset); \
- ILOGV("> branch taken"); \
- if (branchOffset < 0) \
- PERIODIC_CHECKS(branchOffset); \
- FINISH(branchOffset); \
- } else { \
- ILOGV("|if-%s v%d,v%d,-", (_opname), vsrc1, vsrc2); \
- FINISH(2); \
- }
-
-#define HANDLE_OP_IF_XXZ(_opcode, _opname, _cmp) \
- HANDLE_OPCODE(_opcode /*vAA, +BBBB*/) \
- vsrc1 = INST_AA(inst); \
- if ((s4) GET_REGISTER(vsrc1) _cmp 0) { \
- int branchOffset = (s2)FETCH(1); /* sign-extended */ \
- ILOGV("|if-%s v%d,+0x%04x", (_opname), vsrc1, branchOffset); \
- ILOGV("> branch taken"); \
- if (branchOffset < 0) \
- PERIODIC_CHECKS(branchOffset); \
- FINISH(branchOffset); \
- } else { \
- ILOGV("|if-%s v%d,-", (_opname), vsrc1); \
- FINISH(2); \
- }
-
-#define HANDLE_UNOP(_opcode, _opname, _pfx, _sfx, _type) \
- HANDLE_OPCODE(_opcode /*vA, vB*/) \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
- SET_REGISTER##_type(vdst, _pfx GET_REGISTER##_type(vsrc1) _sfx); \
- FINISH(1);
-
-#define HANDLE_OP_X_INT(_opcode, _opname, _op, _chkdiv) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
- { \
- u2 srcRegs; \
- vdst = INST_AA(inst); \
- srcRegs = FETCH(1); \
- vsrc1 = srcRegs & 0xff; \
- vsrc2 = srcRegs >> 8; \
- ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \
- if (_chkdiv != 0) { \
- s4 firstVal, secondVal, result; \
- firstVal = GET_REGISTER(vsrc1); \
- secondVal = GET_REGISTER(vsrc2); \
- if (secondVal == 0) { \
- EXPORT_PC(); \
- dvmThrowArithmeticException("divide by zero"); \
- GOTO_exceptionThrown(); \
- } \
- if ((u4)firstVal == 0x80000000 && secondVal == -1) { \
- if (_chkdiv == 1) \
- result = firstVal; /* division */ \
- else \
- result = 0; /* remainder */ \
- } else { \
- result = firstVal _op secondVal; \
- } \
- SET_REGISTER(vdst, result); \
- } else { \
- /* non-div/rem case */ \
- SET_REGISTER(vdst, \
- (s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2)); \
- } \
- } \
- FINISH(2);
-
-#define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
- { \
- u2 srcRegs; \
- vdst = INST_AA(inst); \
- srcRegs = FETCH(1); \
- vsrc1 = srcRegs & 0xff; \
- vsrc2 = srcRegs >> 8; \
- ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \
- SET_REGISTER(vdst, \
- _cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f)); \
- } \
- FINISH(2);
-
-#define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv) \
- HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/) \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- vsrc2 = FETCH(1); \
- ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x", \
- (_opname), vdst, vsrc1, vsrc2); \
- if (_chkdiv != 0) { \
- s4 firstVal, result; \
- firstVal = GET_REGISTER(vsrc1); \
- if ((s2) vsrc2 == 0) { \
- EXPORT_PC(); \
- dvmThrowArithmeticException("divide by zero"); \
- GOTO_exceptionThrown(); \
- } \
- if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) { \
- /* won't generate /lit16 instr for this; check anyway */ \
- if (_chkdiv == 1) \
- result = firstVal; /* division */ \
- else \
- result = 0; /* remainder */ \
- } else { \
- result = firstVal _op (s2) vsrc2; \
- } \
- SET_REGISTER(vdst, result); \
- } else { \
- /* non-div/rem case */ \
- SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2); \
- } \
- FINISH(2);
-
-#define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \
- { \
- u2 litInfo; \
- vdst = INST_AA(inst); \
- litInfo = FETCH(1); \
- vsrc1 = litInfo & 0xff; \
- vsrc2 = litInfo >> 8; /* constant */ \
- ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \
- (_opname), vdst, vsrc1, vsrc2); \
- if (_chkdiv != 0) { \
- s4 firstVal, result; \
- firstVal = GET_REGISTER(vsrc1); \
- if ((s1) vsrc2 == 0) { \
- EXPORT_PC(); \
- dvmThrowArithmeticException("divide by zero"); \
- GOTO_exceptionThrown(); \
- } \
- if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) { \
- if (_chkdiv == 1) \
- result = firstVal; /* division */ \
- else \
- result = 0; /* remainder */ \
- } else { \
- result = firstVal _op ((s1) vsrc2); \
- } \
- SET_REGISTER(vdst, result); \
- } else { \
- SET_REGISTER(vdst, \
- (s4) GET_REGISTER(vsrc1) _op (s1) vsrc2); \
- } \
- } \
- FINISH(2);
-
-#define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \
- { \
- u2 litInfo; \
- vdst = INST_AA(inst); \
- litInfo = FETCH(1); \
- vsrc1 = litInfo & 0xff; \
- vsrc2 = litInfo >> 8; /* constant */ \
- ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \
- (_opname), vdst, vsrc1, vsrc2); \
- SET_REGISTER(vdst, \
- _cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f)); \
- } \
- FINISH(2);
-
-#define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv) \
- HANDLE_OPCODE(_opcode /*vA, vB*/) \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \
- if (_chkdiv != 0) { \
- s4 firstVal, secondVal, result; \
- firstVal = GET_REGISTER(vdst); \
- secondVal = GET_REGISTER(vsrc1); \
- if (secondVal == 0) { \
- EXPORT_PC(); \
- dvmThrowArithmeticException("divide by zero"); \
- GOTO_exceptionThrown(); \
- } \
- if ((u4)firstVal == 0x80000000 && secondVal == -1) { \
- if (_chkdiv == 1) \
- result = firstVal; /* division */ \
- else \
- result = 0; /* remainder */ \
- } else { \
- result = firstVal _op secondVal; \
- } \
- SET_REGISTER(vdst, result); \
- } else { \
- SET_REGISTER(vdst, \
- (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1)); \
- } \
- FINISH(1);
-
-#define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op) \
- HANDLE_OPCODE(_opcode /*vA, vB*/) \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \
- SET_REGISTER(vdst, \
- _cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f)); \
- FINISH(1);
-
-#define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
- { \
- u2 srcRegs; \
- vdst = INST_AA(inst); \
- srcRegs = FETCH(1); \
- vsrc1 = srcRegs & 0xff; \
- vsrc2 = srcRegs >> 8; \
- ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
- if (_chkdiv != 0) { \
- s8 firstVal, secondVal, result; \
- firstVal = GET_REGISTER_WIDE(vsrc1); \
- secondVal = GET_REGISTER_WIDE(vsrc2); \
- if (secondVal == 0LL) { \
- EXPORT_PC(); \
- dvmThrowArithmeticException("divide by zero"); \
- GOTO_exceptionThrown(); \
- } \
- if ((u8)firstVal == 0x8000000000000000ULL && \
- secondVal == -1LL) \
- { \
- if (_chkdiv == 1) \
- result = firstVal; /* division */ \
- else \
- result = 0; /* remainder */ \
- } else { \
- result = firstVal _op secondVal; \
- } \
- SET_REGISTER_WIDE(vdst, result); \
- } else { \
- SET_REGISTER_WIDE(vdst, \
- (s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \
- } \
- } \
- FINISH(2);
-
-#define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
- { \
- u2 srcRegs; \
- vdst = INST_AA(inst); \
- srcRegs = FETCH(1); \
- vsrc1 = srcRegs & 0xff; \
- vsrc2 = srcRegs >> 8; \
- ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
- SET_REGISTER_WIDE(vdst, \
- _cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \
- } \
- FINISH(2);
-
-#define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv) \
- HANDLE_OPCODE(_opcode /*vA, vB*/) \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \
- if (_chkdiv != 0) { \
- s8 firstVal, secondVal, result; \
- firstVal = GET_REGISTER_WIDE(vdst); \
- secondVal = GET_REGISTER_WIDE(vsrc1); \
- if (secondVal == 0LL) { \
- EXPORT_PC(); \
- dvmThrowArithmeticException("divide by zero"); \
- GOTO_exceptionThrown(); \
- } \
- if ((u8)firstVal == 0x8000000000000000ULL && \
- secondVal == -1LL) \
- { \
- if (_chkdiv == 1) \
- result = firstVal; /* division */ \
- else \
- result = 0; /* remainder */ \
- } else { \
- result = firstVal _op secondVal; \
- } \
- SET_REGISTER_WIDE(vdst, result); \
- } else { \
- SET_REGISTER_WIDE(vdst, \
- (s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\
- } \
- FINISH(1);
-
-#define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op) \
- HANDLE_OPCODE(_opcode /*vA, vB*/) \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \
- SET_REGISTER_WIDE(vdst, \
- _cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \
- FINISH(1);
-
-#define HANDLE_OP_X_FLOAT(_opcode, _opname, _op) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
- { \
- u2 srcRegs; \
- vdst = INST_AA(inst); \
- srcRegs = FETCH(1); \
- vsrc1 = srcRegs & 0xff; \
- vsrc2 = srcRegs >> 8; \
- ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
- SET_REGISTER_FLOAT(vdst, \
- GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2)); \
- } \
- FINISH(2);
-
-#define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
- { \
- u2 srcRegs; \
- vdst = INST_AA(inst); \
- srcRegs = FETCH(1); \
- vsrc1 = srcRegs & 0xff; \
- vsrc2 = srcRegs >> 8; \
- ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
- SET_REGISTER_DOUBLE(vdst, \
- GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2)); \
- } \
- FINISH(2);
-
-#define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op) \
- HANDLE_OPCODE(_opcode /*vA, vB*/) \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1); \
- SET_REGISTER_FLOAT(vdst, \
- GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1)); \
- FINISH(1);
-
-#define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op) \
- HANDLE_OPCODE(_opcode /*vA, vB*/) \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); \
- ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1); \
- SET_REGISTER_DOUBLE(vdst, \
- GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1)); \
- FINISH(1);
-
-#define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
- { \
- ArrayObject* arrayObj; \
- u2 arrayInfo; \
- EXPORT_PC(); \
- vdst = INST_AA(inst); \
- arrayInfo = FETCH(1); \
- vsrc1 = arrayInfo & 0xff; /* array ptr */ \
- vsrc2 = arrayInfo >> 8; /* index */ \
- ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
- arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \
- if (!checkForNull((Object*) arrayObj)) \
- GOTO_exceptionThrown(); \
- if (GET_REGISTER(vsrc2) >= arrayObj->length) { \
- dvmThrowArrayIndexOutOfBoundsException( \
- arrayObj->length, GET_REGISTER(vsrc2)); \
- GOTO_exceptionThrown(); \
- } \
- SET_REGISTER##_regsize(vdst, \
- ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]); \
- ILOGV("+ AGET[%d]=%#x", GET_REGISTER(vsrc2), GET_REGISTER(vdst)); \
- } \
- FINISH(2);
-
-#define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize) \
- HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
- { \
- ArrayObject* arrayObj; \
- u2 arrayInfo; \
- EXPORT_PC(); \
- vdst = INST_AA(inst); /* AA: source value */ \
- arrayInfo = FETCH(1); \
- vsrc1 = arrayInfo & 0xff; /* BB: array ptr */ \
- vsrc2 = arrayInfo >> 8; /* CC: index */ \
- ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
- arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \
- if (!checkForNull((Object*) arrayObj)) \
- GOTO_exceptionThrown(); \
- if (GET_REGISTER(vsrc2) >= arrayObj->length) { \
- dvmThrowArrayIndexOutOfBoundsException( \
- arrayObj->length, GET_REGISTER(vsrc2)); \
- GOTO_exceptionThrown(); \
- } \
- ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
- ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)] = \
- GET_REGISTER##_regsize(vdst); \
- } \
- FINISH(2);
-
-/*
- * It's possible to get a bad value out of a field with sub-32-bit stores
- * because the -quick versions always operate on 32 bits. Consider:
- * short foo = -1 (sets a 32-bit register to 0xffffffff)
- * iput-quick foo (writes all 32 bits to the field)
- * short bar = 1 (sets a 32-bit register to 0x00000001)
- * iput-short (writes the low 16 bits to the field)
- * iget-quick foo (reads all 32 bits from the field, yielding 0xffff0001)
- * This can only happen when optimized and non-optimized code has interleaved
- * access to the same field. This is unlikely but possible.
- *
- * The easiest way to fix this is to always read/write 32 bits at a time. On
- * a device with a 16-bit data bus this is sub-optimal. (The alternative
- * approach is to have sub-int versions of iget-quick, but now we're wasting
- * Dalvik instruction space and making it less likely that handler code will
- * already be in the CPU i-cache.)
- */
-#define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize) \
- HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
- { \
- InstField* ifield; \
- Object* obj; \
- EXPORT_PC(); \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); /* object ptr */ \
- ref = FETCH(1); /* field ref */ \
- ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
- obj = (Object*) GET_REGISTER(vsrc1); \
- if (!checkForNull(obj)) \
- GOTO_exceptionThrown(); \
- ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
- if (ifield == NULL) { \
- ifield = dvmResolveInstField(curMethod->clazz, ref); \
- if (ifield == NULL) \
- GOTO_exceptionThrown(); \
- } \
- SET_REGISTER##_regsize(vdst, \
- dvmGetField##_ftype(obj, ifield->byteOffset)); \
- ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
- (u8) GET_REGISTER##_regsize(vdst)); \
- } \
- FINISH(2);
-
-#define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize) \
- HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
- { \
- Object* obj; \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); /* object ptr */ \
- ref = FETCH(1); /* field offset */ \
- ILOGV("|iget%s-quick v%d,v%d,field@+%u", \
- (_opname), vdst, vsrc1, ref); \
- obj = (Object*) GET_REGISTER(vsrc1); \
- if (!checkForNullExportPC(obj, fp, pc)) \
- GOTO_exceptionThrown(); \
- SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref)); \
- ILOGV("+ IGETQ %d=0x%08llx", ref, \
- (u8) GET_REGISTER##_regsize(vdst)); \
- } \
- FINISH(2);
-
-#define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize) \
- HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
- { \
- InstField* ifield; \
- Object* obj; \
- EXPORT_PC(); \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); /* object ptr */ \
- ref = FETCH(1); /* field ref */ \
- ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
- obj = (Object*) GET_REGISTER(vsrc1); \
- if (!checkForNull(obj)) \
- GOTO_exceptionThrown(); \
- ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
- if (ifield == NULL) { \
- ifield = dvmResolveInstField(curMethod->clazz, ref); \
- if (ifield == NULL) \
- GOTO_exceptionThrown(); \
- } \
- dvmSetField##_ftype(obj, ifield->byteOffset, \
- GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
- (u8) GET_REGISTER##_regsize(vdst)); \
- } \
- FINISH(2);
-
-#define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize) \
- HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
- { \
- Object* obj; \
- vdst = INST_A(inst); \
- vsrc1 = INST_B(inst); /* object ptr */ \
- ref = FETCH(1); /* field offset */ \
- ILOGV("|iput%s-quick v%d,v%d,field@0x%04x", \
- (_opname), vdst, vsrc1, ref); \
- obj = (Object*) GET_REGISTER(vsrc1); \
- if (!checkForNullExportPC(obj, fp, pc)) \
- GOTO_exceptionThrown(); \
- dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ IPUTQ %d=0x%08llx", ref, \
- (u8) GET_REGISTER##_regsize(vdst)); \
- } \
- FINISH(2);
-
-/*
- * The JIT needs dvmDexGetResolvedField() to return non-null.
- * Because the portable interpreter is not involved with the JIT
- * and trace building, we only need the extra check here when this
- * code is massaged into a stub called from an assembly interpreter.
- * This is controlled by the JIT_STUB_HACK maco.
- */
-
-#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
- HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
- { \
- StaticField* sfield; \
- vdst = INST_AA(inst); \
- ref = FETCH(1); /* field ref */ \
- ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref); \
- sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
- if (sfield == NULL) { \
- EXPORT_PC(); \
- sfield = dvmResolveStaticField(curMethod->clazz, ref); \
- if (sfield == NULL) \
- GOTO_exceptionThrown(); \
- if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
- JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc)); \
- } \
- } \
- SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
- ILOGV("+ SGET '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
- } \
- FINISH(2);
-
-#define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize) \
- HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
- { \
- StaticField* sfield; \
- vdst = INST_AA(inst); \
- ref = FETCH(1); /* field ref */ \
- ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref); \
- sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
- if (sfield == NULL) { \
- EXPORT_PC(); \
- sfield = dvmResolveStaticField(curMethod->clazz, ref); \
- if (sfield == NULL) \
- GOTO_exceptionThrown(); \
- if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
- JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc)); \
- } \
- } \
- dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ SPUT '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
- } \
- FINISH(2);
-
-/* File: c/OP_IGET_VOLATILE.cpp */
-HANDLE_IGET_X(OP_IGET_VOLATILE, "-volatile", IntVolatile, )
-OP_END
-
-/* File: c/OP_IPUT_VOLATILE.cpp */
-HANDLE_IPUT_X(OP_IPUT_VOLATILE, "-volatile", IntVolatile, )
-OP_END
-
-/* File: c/OP_SGET_VOLATILE.cpp */
-HANDLE_SGET_X(OP_SGET_VOLATILE, "-volatile", IntVolatile, )
-OP_END
-
-/* File: c/OP_SPUT_VOLATILE.cpp */
-HANDLE_SPUT_X(OP_SPUT_VOLATILE, "-volatile", IntVolatile, )
-OP_END
-
-/* File: c/OP_IGET_OBJECT_VOLATILE.cpp */
-HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
-OP_END
-
-/* File: c/OP_IGET_WIDE_VOLATILE.cpp */
-HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
-OP_END
-
-/* File: c/OP_IPUT_WIDE_VOLATILE.cpp */
-HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
-OP_END
-
-/* File: c/OP_SGET_WIDE_VOLATILE.cpp */
-HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
-OP_END
-
-/* File: c/OP_SPUT_WIDE_VOLATILE.cpp */
-HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE)
-OP_END
-
-/* File: c/OP_BREAKPOINT.cpp */
-HANDLE_OPCODE(OP_BREAKPOINT)
- {
- /*
- * Restart this instruction with the original opcode. We do
- * this by simply jumping to the handler.
- *
- * It's probably not necessary to update "inst", but we do it
- * for the sake of anything that needs to do disambiguation in a
- * common handler with INST_INST.
- *
- * The breakpoint itself is handled over in updateDebugger(),
- * because we need to detect other events (method entry, single
- * step) and report them in the same event packet, and we're not
- * yet handling those through breakpoint instructions. By the
- * time we get here, the breakpoint has already been handled and
- * the thread resumed.
- */
- u1 originalOpcode = dvmGetOriginalOpcode(pc);
- ALOGV("+++ break 0x%02x (0x%04x -> 0x%04x)", originalOpcode, inst,
- INST_REPLACE_OP(inst, originalOpcode));
- inst = INST_REPLACE_OP(inst, originalOpcode);
- FINISH_BKPT(originalOpcode);
- }
-OP_END
-
-/* File: c/OP_EXECUTE_INLINE_RANGE.cpp */
-HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/)
- {
- u4 arg0, arg1, arg2, arg3;
- arg0 = arg1 = arg2 = arg3 = 0; /* placate gcc */
-
- EXPORT_PC();
-
- vsrc1 = INST_AA(inst); /* #of args */
- ref = FETCH(1); /* inline call "ref" */
- vdst = FETCH(2); /* range base */
- ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}",
- vsrc1, ref, vdst, vdst+vsrc1-1);
-
- assert((vdst >> 16) == 0); // 16-bit type -or- high 16 bits clear
- assert(vsrc1 <= 4);
-
- switch (vsrc1) {
- case 4:
- arg3 = GET_REGISTER(vdst+3);
- /* fall through */
- case 3:
- arg2 = GET_REGISTER(vdst+2);
- /* fall through */
- case 2:
- arg1 = GET_REGISTER(vdst+1);
- /* fall through */
- case 1:
- arg0 = GET_REGISTER(vdst+0);
- /* fall through */
- default: // case 0
- ;
- }
-
- if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
- if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
- GOTO_exceptionThrown();
- } else {
- if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
- GOTO_exceptionThrown();
- }
- }
- FINISH(3);
-OP_END
-
-/* File: c/OP_INVOKE_OBJECT_INIT_RANGE.cpp */
-HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
- {
- Object* obj;
-
- vsrc1 = FETCH(2); /* reg number of "this" pointer */
- obj = GET_REGISTER_AS_OBJECT(vsrc1);
-
- if (!checkForNullExportPC(obj, fp, pc))
- GOTO_exceptionThrown();
-
- /*
- * The object should be marked "finalizable" when Object.<init>
- * completes normally. We're going to assume it does complete
- * (by virtue of being nothing but a return-void) and set it now.
- */
- if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
- EXPORT_PC();
- dvmSetFinalizable(obj);
- if (dvmGetException(self))
- GOTO_exceptionThrown();
- }
-
- if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
- /* behave like OP_INVOKE_DIRECT_RANGE */
- GOTO_invoke(invokeDirect, true);
- }
- FINISH(3);
- }
-OP_END
-
-/* File: c/OP_RETURN_VOID_BARRIER.cpp */
-HANDLE_OPCODE(OP_RETURN_VOID_BARRIER /**/)
- ILOGV("|return-void");
-#ifndef NDEBUG
- retval.j = 0xababababULL; /* placate valgrind */
-#endif
- ANDROID_MEMBAR_STORE();
- GOTO_returnFromMethod();
-OP_END
-
-/* File: c/OP_IPUT_OBJECT_VOLATILE.cpp */
-HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
-OP_END
-
-/* File: c/OP_SGET_OBJECT_VOLATILE.cpp */
-HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
-OP_END
-
-/* File: c/OP_SPUT_OBJECT_VOLATILE.cpp */
-HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
-OP_END
-
-/* File: c/gotoTargets.cpp */
-/*
- * C footer. This has some common code shared by the various targets.
- */
-
-/*
- * Everything from here on is a "goto target". In the basic interpreter
- * we jump into these targets and then jump directly to the handler for
- * next instruction. Here, these are subroutines that return to the caller.
- */
-
-GOTO_TARGET(filledNewArray, bool methodCallRange, bool)
- {
- ClassObject* arrayClass;
- ArrayObject* newArray;
- u4* contents;
- char typeCh;
- int i;
- u4 arg5;
-
- EXPORT_PC();
-
- ref = FETCH(1); /* class ref */
- vdst = FETCH(2); /* first 4 regs -or- range base */
-
- if (methodCallRange) {
- vsrc1 = INST_AA(inst); /* #of elements */
- arg5 = -1; /* silence compiler warning */
- ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}",
- vsrc1, ref, vdst, vdst+vsrc1-1);
- } else {
- arg5 = INST_A(inst);
- vsrc1 = INST_B(inst); /* #of elements */
- ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}",
- vsrc1, ref, vdst, arg5);
- }
-
- /*
- * Resolve the array class.
- */
- arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
- if (arrayClass == NULL) {
- arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
- if (arrayClass == NULL)
- GOTO_exceptionThrown();
- }
- /*
- if (!dvmIsArrayClass(arrayClass)) {
- dvmThrowRuntimeException(
- "filled-new-array needs array class");
- GOTO_exceptionThrown();
- }
- */
- /* verifier guarantees this is an array class */
- assert(dvmIsArrayClass(arrayClass));
- assert(dvmIsClassInitialized(arrayClass));
-
- /*
- * Create an array of the specified type.
- */
- LOGVV("+++ filled-new-array type is '%s'", arrayClass->descriptor);
- typeCh = arrayClass->descriptor[1];
- if (typeCh == 'D' || typeCh == 'J') {
- /* category 2 primitives not allowed */
- dvmThrowRuntimeException("bad filled array req");
- GOTO_exceptionThrown();
- } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') {
- /* TODO: requires multiple "fill in" loops with different widths */
- ALOGE("non-int primitives not implemented");
- dvmThrowInternalError(
- "filled-new-array not implemented for anything but 'int'");
- GOTO_exceptionThrown();
- }
-
- newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK);
- if (newArray == NULL)
- GOTO_exceptionThrown();
-
- /*
- * Fill in the elements. It's legal for vsrc1 to be zero.
- */
- contents = (u4*)(void*)newArray->contents;
- if (methodCallRange) {
- for (i = 0; i < vsrc1; i++)
- contents[i] = GET_REGISTER(vdst+i);
- } else {
- assert(vsrc1 <= 5);
- if (vsrc1 == 5) {
- contents[4] = GET_REGISTER(arg5);
- vsrc1--;
- }
- for (i = 0; i < vsrc1; i++) {
- contents[i] = GET_REGISTER(vdst & 0x0f);
- vdst >>= 4;
- }
- }
- if (typeCh == 'L' || typeCh == '[') {
- dvmWriteBarrierArray(newArray, 0, newArray->length);
- }
-
- retval.l = (Object*)newArray;
- }
- FINISH(3);
-GOTO_TARGET_END
-
-
-GOTO_TARGET(invokeVirtual, bool methodCallRange, bool)
- {
- Method* baseMethod;
- Object* thisPtr;
-
- EXPORT_PC();
-
- vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
- ref = FETCH(1); /* method ref */
- vdst = FETCH(2); /* 4 regs -or- first reg */
-
- /*
- * The object against which we are executing a method is always
- * in the first argument.
- */
- if (methodCallRange) {
- assert(vsrc1 > 0);
- ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}",
- vsrc1, ref, vdst, vdst+vsrc1-1);
- thisPtr = (Object*) GET_REGISTER(vdst);
- } else {
- assert((vsrc1>>4) > 0);
- ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}",
- vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
- thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
- }
-
- if (!checkForNull(thisPtr))
- GOTO_exceptionThrown();
-
- /*
- * Resolve the method. This is the correct method for the static
- * type of the object. We also verify access permissions here.
- */
- baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
- if (baseMethod == NULL) {
- baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
- if (baseMethod == NULL) {
- ILOGV("+ unknown method or access denied");
- GOTO_exceptionThrown();
- }
- }
-
- /*
- * Combine the object we found with the vtable offset in the
- * method.
- */
- assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
- methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
-
-#if defined(WITH_JIT) && defined(MTERP_STUB)
- self->methodToCall = methodToCall;
- self->callsiteClass = thisPtr->clazz;
-#endif
-
-#if 0
- if (dvmIsAbstractMethod(methodToCall)) {
- /*
- * This can happen if you create two classes, Base and Sub, where
- * Sub is a sub-class of Base. Declare a protected abstract
- * method foo() in Base, and invoke foo() from a method in Base.
- * Base is an "abstract base class" and is never instantiated
- * directly. Now, Override foo() in Sub, and use Sub. This
- * Works fine unless Sub stops providing an implementation of
- * the method.
- */
- dvmThrowAbstractMethodError("abstract method not implemented");
- GOTO_exceptionThrown();
- }
-#else
- assert(!dvmIsAbstractMethod(methodToCall) ||
- methodToCall->nativeFunc != NULL);
-#endif
-
- LOGVV("+++ base=%s.%s virtual[%d]=%s.%s",
- baseMethod->clazz->descriptor, baseMethod->name,
- (u4) baseMethod->methodIndex,
- methodToCall->clazz->descriptor, methodToCall->name);
- assert(methodToCall != NULL);
-
-#if 0
- if (vsrc1 != methodToCall->insSize) {
- ALOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s",
- baseMethod->clazz->descriptor, baseMethod->name,
- (u4) baseMethod->methodIndex,
- methodToCall->clazz->descriptor, methodToCall->name);
- //dvmDumpClass(baseMethod->clazz);
- //dvmDumpClass(methodToCall->clazz);
- dvmDumpAllClasses(0);
- }
-#endif
-
- GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
- }
-GOTO_TARGET_END
-
-GOTO_TARGET(invokeSuper, bool methodCallRange)
- {
- Method* baseMethod;
- u2 thisReg;
-
- EXPORT_PC();
-
- vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
- ref = FETCH(1); /* method ref */
- vdst = FETCH(2); /* 4 regs -or- first reg */
-
- if (methodCallRange) {
- ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
- vsrc1, ref, vdst, vdst+vsrc1-1);
- thisReg = vdst;
- } else {
- ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
- vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
- thisReg = vdst & 0x0f;
- }
-
- /* impossible in well-formed code, but we must check nevertheless */
- if (!checkForNull((Object*) GET_REGISTER(thisReg)))
- GOTO_exceptionThrown();
-
- /*
- * Resolve the method. This is the correct method for the static
- * type of the object. We also verify access permissions here.
- * The first arg to dvmResolveMethod() is just the referring class
- * (used for class loaders and such), so we don't want to pass
- * the superclass into the resolution call.
- */
- baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
- if (baseMethod == NULL) {
- baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
- if (baseMethod == NULL) {
- ILOGV("+ unknown method or access denied");
- GOTO_exceptionThrown();
- }
- }
-
- /*
- * Combine the object we found with the vtable offset in the
- * method's class.
- *
- * We're using the current method's class' superclass, not the
- * superclass of "this". This is because we might be executing
- * in a method inherited from a superclass, and we want to run
- * in that class' superclass.
- */
- if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
- /*
- * Method does not exist in the superclass. Could happen if
- * superclass gets updated.
- */
- dvmThrowNoSuchMethodError(baseMethod->name);
- GOTO_exceptionThrown();
- }
- methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
-
-#if 0
- if (dvmIsAbstractMethod(methodToCall)) {
- dvmThrowAbstractMethodError("abstract method not implemented");
- GOTO_exceptionThrown();
- }
-#else
- assert(!dvmIsAbstractMethod(methodToCall) ||
- methodToCall->nativeFunc != NULL);
-#endif
- LOGVV("+++ base=%s.%s super-virtual=%s.%s",
- baseMethod->clazz->descriptor, baseMethod->name,
- methodToCall->clazz->descriptor, methodToCall->name);
- assert(methodToCall != NULL);
-
- GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
- }
-GOTO_TARGET_END
-
-GOTO_TARGET(invokeInterface, bool methodCallRange)
- {
- Object* thisPtr;
- ClassObject* thisClass;
-
- EXPORT_PC();
-
- vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
- ref = FETCH(1); /* method ref */
- vdst = FETCH(2); /* 4 regs -or- first reg */
-
- /*
- * The object against which we are executing a method is always
- * in the first argument.
- */
- if (methodCallRange) {
- assert(vsrc1 > 0);
- ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}",
- vsrc1, ref, vdst, vdst+vsrc1-1);
- thisPtr = (Object*) GET_REGISTER(vdst);
- } else {
- assert((vsrc1>>4) > 0);
- ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}",
- vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
- thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
- }
-
- if (!checkForNull(thisPtr))
- GOTO_exceptionThrown();
-
- thisClass = thisPtr->clazz;
-
- /*
- * Given a class and a method index, find the Method* with the
- * actual code we want to execute.
- */
- methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
- methodClassDex);
-#if defined(WITH_JIT) && defined(MTERP_STUB)
- self->callsiteClass = thisClass;
- self->methodToCall = methodToCall;
-#endif
- if (methodToCall == NULL) {
- assert(dvmCheckException(self));
- GOTO_exceptionThrown();
- }
-
- GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
- }
-GOTO_TARGET_END
-
-GOTO_TARGET(invokeDirect, bool methodCallRange)
- {
- u2 thisReg;
-
- EXPORT_PC();
-
- vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
- ref = FETCH(1); /* method ref */
- vdst = FETCH(2); /* 4 regs -or- first reg */
-
- if (methodCallRange) {
- ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}",
- vsrc1, ref, vdst, vdst+vsrc1-1);
- thisReg = vdst;
- } else {
- ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}",
- vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
- thisReg = vdst & 0x0f;
- }
-
- if (!checkForNull((Object*) GET_REGISTER(thisReg)))
- GOTO_exceptionThrown();
-
- methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
- if (methodToCall == NULL) {
- methodToCall = dvmResolveMethod(curMethod->clazz, ref,
- METHOD_DIRECT);
- if (methodToCall == NULL) {
- ILOGV("+ unknown direct method"); // should be impossible
- GOTO_exceptionThrown();
- }
- }
- GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
- }
-GOTO_TARGET_END
-
-GOTO_TARGET(invokeStatic, bool methodCallRange)
- EXPORT_PC();
-
- vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
- ref = FETCH(1); /* method ref */
- vdst = FETCH(2); /* 4 regs -or- first reg */
-
- if (methodCallRange)
- ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}",
- vsrc1, ref, vdst, vdst+vsrc1-1);
- else
- ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}",
- vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
-
- methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
- if (methodToCall == NULL) {
- methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC);
- if (methodToCall == NULL) {
- ILOGV("+ unknown method");
- GOTO_exceptionThrown();
- }
-
-#if defined(WITH_JIT) && defined(MTERP_STUB)
- /*
- * The JIT needs dvmDexGetResolvedMethod() to return non-null.
- * Include the check if this code is being used as a stub
- * called from the assembly interpreter.
- */
- if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
- (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL)) {
- /* Class initialization is still ongoing */
- dvmJitEndTraceSelect(self,pc);
- }
-#endif
- }
- GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
-GOTO_TARGET_END
-
-GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
- {
- Object* thisPtr;
-
- EXPORT_PC();
-
- vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
- ref = FETCH(1); /* vtable index */
- vdst = FETCH(2); /* 4 regs -or- first reg */
-
- /*
- * The object against which we are executing a method is always
- * in the first argument.
- */
- if (methodCallRange) {
- assert(vsrc1 > 0);
- ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}",
- vsrc1, ref, vdst, vdst+vsrc1-1);
- thisPtr = (Object*) GET_REGISTER(vdst);
- } else {
- assert((vsrc1>>4) > 0);
- ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}",
- vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
- thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
- }
-
- if (!checkForNull(thisPtr))
- GOTO_exceptionThrown();
-
-
- /*
- * Combine the object we found with the vtable offset in the
- * method.
- */
- assert(ref < (unsigned int) thisPtr->clazz->vtableCount);
- methodToCall = thisPtr->clazz->vtable[ref];
-#if defined(WITH_JIT) && defined(MTERP_STUB)
- self->callsiteClass = thisPtr->clazz;
- self->methodToCall = methodToCall;
-#endif
-
-#if 0
- if (dvmIsAbstractMethod(methodToCall)) {
- dvmThrowAbstractMethodError("abstract method not implemented");
- GOTO_exceptionThrown();
- }
-#else
- assert(!dvmIsAbstractMethod(methodToCall) ||
- methodToCall->nativeFunc != NULL);
-#endif
-
- LOGVV("+++ virtual[%d]=%s.%s",
- ref, methodToCall->clazz->descriptor, methodToCall->name);
- assert(methodToCall != NULL);
-
- GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
- }
-GOTO_TARGET_END
-
-GOTO_TARGET(invokeSuperQuick, bool methodCallRange)
- {
- u2 thisReg;
-
- EXPORT_PC();
-
- vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */
- ref = FETCH(1); /* vtable index */
- vdst = FETCH(2); /* 4 regs -or- first reg */
-
- if (methodCallRange) {
- ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}",
- vsrc1, ref, vdst, vdst+vsrc1-1);
- thisReg = vdst;
- } else {
- ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}",
- vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
- thisReg = vdst & 0x0f;
- }
- /* impossible in well-formed code, but we must check nevertheless */
- if (!checkForNull((Object*) GET_REGISTER(thisReg)))
- GOTO_exceptionThrown();
-
-#if 0 /* impossible in optimized + verified code */
- if (ref >= curMethod->clazz->super->vtableCount) {
- dvmThrowNoSuchMethodError(NULL);
- GOTO_exceptionThrown();
- }
-#else
- assert(ref < (unsigned int) curMethod->clazz->super->vtableCount);
-#endif
-
- /*
- * Combine the object we found with the vtable offset in the
- * method's class.
- *
- * We're using the current method's class' superclass, not the
- * superclass of "this". This is because we might be executing
- * in a method inherited from a superclass, and we want to run
- * in the method's class' superclass.
- */
- methodToCall = curMethod->clazz->super->vtable[ref];
-
-#if 0
- if (dvmIsAbstractMethod(methodToCall)) {
- dvmThrowAbstractMethodError("abstract method not implemented");
- GOTO_exceptionThrown();
- }
-#else
- assert(!dvmIsAbstractMethod(methodToCall) ||
- methodToCall->nativeFunc != NULL);
-#endif
- LOGVV("+++ super-virtual[%d]=%s.%s",
- ref, methodToCall->clazz->descriptor, methodToCall->name);
- assert(methodToCall != NULL);
- GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
- }
-GOTO_TARGET_END
-
-
- /*
- * General handling for return-void, return, and return-wide. Put the
- * return value in "retval" before jumping here.
- */
-GOTO_TARGET(returnFromMethod)
- {
- StackSaveArea* saveArea;
-
- /*
- * We must do this BEFORE we pop the previous stack frame off, so
- * that the GC can see the return value (if any) in the local vars.
- *
- * Since this is now an interpreter switch point, we must do it before
- * we do anything at all.
- */
- PERIODIC_CHECKS(0);
-
- ILOGV("> retval=0x%llx (leaving %s.%s %s)",
- retval.j, curMethod->clazz->descriptor, curMethod->name,
- curMethod->shorty);
- //DUMP_REGS(curMethod, fp);
-
- saveArea = SAVEAREA_FROM_FP(fp);
-
-#ifdef EASY_GDB
- debugSaveArea = saveArea;
-#endif
-
- /* back up to previous frame and see if we hit a break */
- fp = (u4*)saveArea->prevFrame;
- assert(fp != NULL);
-
- /* Handle any special subMode requirements */
- if (self->interpBreak.ctl.subMode != 0) {
- PC_FP_TO_SELF();
- dvmReportReturn(self);
- }
-
- if (dvmIsBreakFrame(fp)) {
- /* bail without popping the method frame from stack */
- LOGVV("+++ returned into break frame");
- GOTO_bail();
- }
-
- /* update thread FP, and reset local variables */
- self->interpSave.curFrame = fp;
- curMethod = SAVEAREA_FROM_FP(fp)->method;
- self->interpSave.method = curMethod;
- //methodClass = curMethod->clazz;
- methodClassDex = curMethod->clazz->pDvmDex;
- pc = saveArea->savedPc;
- ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
- curMethod->name, curMethod->shorty);
-
- /* use FINISH on the caller's invoke instruction */
- //u2 invokeInstr = INST_INST(FETCH(0));
- if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
- invokeInstr <= OP_INVOKE_INTERFACE*/)
- {
- FINISH(3);
- } else {
- //ALOGE("Unknown invoke instr %02x at %d",
- // invokeInstr, (int) (pc - curMethod->insns));
- assert(false);
- }
- }
-GOTO_TARGET_END
-
-
- /*
- * Jump here when the code throws an exception.
- *
- * By the time we get here, the Throwable has been created and the stack
- * trace has been saved off.
- */
-GOTO_TARGET(exceptionThrown)
- {
- Object* exception;
- int catchRelPc;
-
- PERIODIC_CHECKS(0);
-
- /*
- * We save off the exception and clear the exception status. While
- * processing the exception we might need to load some Throwable
- * classes, and we don't want class loader exceptions to get
- * confused with this one.
- */
- assert(dvmCheckException(self));
- exception = dvmGetException(self);
- dvmAddTrackedAlloc(exception, self);
- dvmClearException(self);
-
- ALOGV("Handling exception %s at %s:%d",
- exception->clazz->descriptor, curMethod->name,
- dvmLineNumFromPC(curMethod, pc - curMethod->insns));
-
- /*
- * Report the exception throw to any "subMode" watchers.
- *
- * TODO: if the exception was thrown by interpreted code, control
- * fell through native, and then back to us, we will report the
- * exception at the point of the throw and again here. We can avoid
- * this by not reporting exceptions when we jump here directly from
- * the native call code above, but then we won't report exceptions
- * that were thrown *from* the JNI code (as opposed to *through* it).
- *
- * The correct solution is probably to ignore from-native exceptions
- * here, and have the JNI exception code do the reporting to the
- * debugger.
- */
- if (self->interpBreak.ctl.subMode != 0) {
- PC_FP_TO_SELF();
- dvmReportExceptionThrow(self, exception);
- }
-
- /*
- * We need to unroll to the catch block or the nearest "break"
- * frame.
- *
- * A break frame could indicate that we have reached an intermediate
- * native call, or have gone off the top of the stack and the thread
- * needs to exit. Either way, we return from here, leaving the
- * exception raised.
- *
- * If we do find a catch block, we want to transfer execution to
- * that point.
- *
- * Note this can cause an exception while resolving classes in
- * the "catch" blocks.
- */
- catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
- exception, false, (void**)(void*)&fp);
-
- /*
- * Restore the stack bounds after an overflow. This isn't going to
- * be correct in all circumstances, e.g. if JNI code devours the
- * exception this won't happen until some other exception gets
- * thrown. If the code keeps pushing the stack bounds we'll end
- * up aborting the VM.
- *
- * Note we want to do this *after* the call to dvmFindCatchBlock,
- * because that may need extra stack space to resolve exception
- * classes (e.g. through a class loader).
- *
- * It's possible for the stack overflow handling to cause an
- * exception (specifically, class resolution in a "catch" block
- * during the call above), so we could see the thread's overflow
- * flag raised but actually be running in a "nested" interpreter
- * frame. We don't allow doubled-up StackOverflowErrors, so
- * we can check for this by just looking at the exception type
- * in the cleanup function. Also, we won't unroll past the SOE
- * point because the more-recent exception will hit a break frame
- * as it unrolls to here.
- */
- if (self->stackOverflowed)
- dvmCleanupStackOverflow(self, exception);
-
- if (catchRelPc < 0) {
- /* falling through to JNI code or off the bottom of the stack */
-#if DVM_SHOW_EXCEPTION >= 2
- ALOGD("Exception %s from %s:%d not caught locally",
- exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
- dvmLineNumFromPC(curMethod, pc - curMethod->insns));
-#endif
- dvmSetException(self, exception);
- dvmReleaseTrackedAlloc(exception, self);
- GOTO_bail();
- }
-
-#if DVM_SHOW_EXCEPTION >= 3
- {
- const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method;
- ALOGD("Exception %s thrown from %s:%d to %s:%d",
- exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
- dvmLineNumFromPC(curMethod, pc - curMethod->insns),
- dvmGetMethodSourceFile(catchMethod),
- dvmLineNumFromPC(catchMethod, catchRelPc));
- }
-#endif
-
- /*
- * Adjust local variables to match self->interpSave.curFrame and the
- * updated PC.
- */
- //fp = (u4*) self->interpSave.curFrame;
- curMethod = SAVEAREA_FROM_FP(fp)->method;
- self->interpSave.method = curMethod;
- //methodClass = curMethod->clazz;
- methodClassDex = curMethod->clazz->pDvmDex;
- pc = curMethod->insns + catchRelPc;
- ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
- curMethod->name, curMethod->shorty);
- DUMP_REGS(curMethod, fp, false); // show all regs
-
- /*
- * Restore the exception if the handler wants it.
- *
- * The Dalvik spec mandates that, if an exception handler wants to
- * do something with the exception, the first instruction executed
- * must be "move-exception". We can pass the exception along
- * through the thread struct, and let the move-exception instruction
- * clear it for us.
- *
- * If the handler doesn't call move-exception, we don't want to
- * finish here with an exception still pending.
- */
- if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION)
- dvmSetException(self, exception);
-
- dvmReleaseTrackedAlloc(exception, self);
- FINISH(0);
- }
-GOTO_TARGET_END
-
-
-
- /*
- * General handling for invoke-{virtual,super,direct,static,interface},
- * including "quick" variants.
- *
- * Set "methodToCall" to the Method we're calling, and "methodCallRange"
- * depending on whether this is a "/range" instruction.
- *
- * For a range call:
- * "vsrc1" holds the argument count (8 bits)
- * "vdst" holds the first argument in the range
- * For a non-range call:
- * "vsrc1" holds the argument count (4 bits) and the 5th argument index
- * "vdst" holds four 4-bit register indices
- *
- * The caller must EXPORT_PC before jumping here, because any method
- * call can throw a stack overflow exception.
- */
-GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
- u2 count, u2 regs)
- {
- STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;);
-
- //printf("range=%d call=%p count=%d regs=0x%04x\n",
- // methodCallRange, methodToCall, count, regs);
- //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
- // methodToCall->name, methodToCall->shorty);
-
- u4* outs;
- int i;
-
- /*
- * Copy args. This may corrupt vsrc1/vdst.
- */
- if (methodCallRange) {
- // could use memcpy or a "Duff's device"; most functions have
- // so few args it won't matter much
- assert(vsrc1 <= curMethod->outsSize);
- assert(vsrc1 == methodToCall->insSize);
- outs = OUTS_FROM_FP(fp, vsrc1);
- for (i = 0; i < vsrc1; i++)
- outs[i] = GET_REGISTER(vdst+i);
- } else {
- u4 count = vsrc1 >> 4;
-
- assert(count <= curMethod->outsSize);
- assert(count == methodToCall->insSize);
- assert(count <= 5);
-
- outs = OUTS_FROM_FP(fp, count);
-#if 0
- if (count == 5) {
- outs[4] = GET_REGISTER(vsrc1 & 0x0f);
- count--;
- }
- for (i = 0; i < (int) count; i++) {
- outs[i] = GET_REGISTER(vdst & 0x0f);
- vdst >>= 4;
- }
-#else
- // This version executes fewer instructions but is larger
- // overall. Seems to be a teensy bit faster.
- assert((vdst >> 16) == 0); // 16 bits -or- high 16 bits clear
- switch (count) {
- case 5:
- outs[4] = GET_REGISTER(vsrc1 & 0x0f);
- case 4:
- outs[3] = GET_REGISTER(vdst >> 12);
- case 3:
- outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8);
- case 2:
- outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4);
- case 1:
- outs[0] = GET_REGISTER(vdst & 0x0f);
- default:
- ;
- }
-#endif
- }
- }
-
- /*
- * (This was originally a "goto" target; I've kept it separate from the
- * stuff above in case we want to refactor things again.)
- *
- * At this point, we have the arguments stored in the "outs" area of
- * the current method's stack frame, and the method to call in
- * "methodToCall". Push a new stack frame.
- */
- {
- StackSaveArea* newSaveArea;
- u4* newFp;
-
- ILOGV("> %s%s.%s %s",
- dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
- methodToCall->clazz->descriptor, methodToCall->name,
- methodToCall->shorty);
-
- newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
- newSaveArea = SAVEAREA_FROM_FP(newFp);
-
- /* verify that we have enough space */
- if (true) {
- u1* bottom;
- bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
- if (bottom < self->interpStackEnd) {
- /* stack overflow */
- ALOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')",
- self->interpStackStart, self->interpStackEnd, bottom,
- (u1*) fp - bottom, self->interpStackSize,
- methodToCall->name);
- dvmHandleStackOverflow(self, methodToCall);
- assert(dvmCheckException(self));
- GOTO_exceptionThrown();
- }
- //ALOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p",
- // fp, newFp, newSaveArea, bottom);
- }
-
-#ifdef LOG_INSTR
- if (methodToCall->registersSize > methodToCall->insSize) {
- /*
- * This makes valgrind quiet when we print registers that
- * haven't been initialized. Turn it off when the debug
- * messages are disabled -- we want valgrind to report any
- * used-before-initialized issues.
- */
- memset(newFp, 0xcc,
- (methodToCall->registersSize - methodToCall->insSize) * 4);
- }
-#endif
-
-#ifdef EASY_GDB
- newSaveArea->prevSave = SAVEAREA_FROM_FP(fp);
-#endif
- newSaveArea->prevFrame = fp;
- newSaveArea->savedPc = pc;
-#if defined(WITH_JIT) && defined(MTERP_STUB)
- newSaveArea->returnAddr = 0;
-#endif
- newSaveArea->method = methodToCall;
-
- if (self->interpBreak.ctl.subMode != 0) {
- /*
- * We mark ENTER here for both native and non-native
- * calls. For native calls, we'll mark EXIT on return.
- * For non-native calls, EXIT is marked in the RETURN op.
- */
- PC_TO_SELF();
- dvmReportInvoke(self, methodToCall);
- }
-
- if (!dvmIsNativeMethod(methodToCall)) {
- /*
- * "Call" interpreted code. Reposition the PC, update the
- * frame pointer and other local state, and continue.
- */
- curMethod = methodToCall;
- self->interpSave.method = curMethod;
- methodClassDex = curMethod->clazz->pDvmDex;
- pc = methodToCall->insns;
- fp = newFp;
- self->interpSave.curFrame = fp;
-#ifdef EASY_GDB
- debugSaveArea = SAVEAREA_FROM_FP(newFp);
-#endif
- self->debugIsMethodEntry = true; // profiling, debugging
- ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
- curMethod->name, curMethod->shorty);
- DUMP_REGS(curMethod, fp, true); // show input args
- FINISH(0); // jump to method start
- } else {
- /* set this up for JNI locals, even if not a JNI native */
- newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
-
- self->interpSave.curFrame = newFp;
-
- DUMP_REGS(methodToCall, newFp, true); // show input args
-
- if (self->interpBreak.ctl.subMode != 0) {
- dvmReportPreNativeInvoke(methodToCall, self, fp);
- }
-
- ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
- methodToCall->name, methodToCall->shorty);
-
- /*
- * Jump through native call bridge. Because we leave no
- * space for locals on native calls, "newFp" points directly
- * to the method arguments.
- */
- (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
-
- if (self->interpBreak.ctl.subMode != 0) {
- dvmReportPostNativeInvoke(methodToCall, self, fp);
- }
-
- /* pop frame off */
- dvmPopJniLocals(self, newSaveArea);
- self->interpSave.curFrame = fp;
-
- /*
- * If the native code threw an exception, or interpreted code
- * invoked by the native call threw one and nobody has cleared
- * it, jump to our local exception handling.
- */
- if (dvmCheckException(self)) {
- ALOGV("Exception thrown by/below native code");
- GOTO_exceptionThrown();
- }
-
- ILOGD("> retval=0x%llx (leaving native)", retval.j);
- ILOGD("> (return from native %s.%s to %s.%s %s)",
- methodToCall->clazz->descriptor, methodToCall->name,
- curMethod->clazz->descriptor, curMethod->name,
- curMethod->shorty);
-
- //u2 invokeInstr = INST_INST(FETCH(0));
- if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
- invokeInstr <= OP_INVOKE_INTERFACE*/)
- {
- FINISH(3);
- } else {
- //ALOGE("Unknown invoke instr %02x at %d",
- // invokeInstr, (int) (pc - curMethod->insns));
- assert(false);
- }
- }
- }
- assert(false); // should not get here
-GOTO_TARGET_END
-
-/* File: cstubs/enddefs.cpp */
-
-/* undefine "magic" name remapping */
-#undef retval
-#undef pc
-#undef fp
-#undef curMethod
-#undef methodClassDex
-#undef self
-#undef debugTrackedRefStart
-
diff --git a/vm/mterp/out/InterpC-x86.cpp b/vm/mterp/out/InterpC-x86.cpp
index 8d77b94..77dc888 100644
--- a/vm/mterp/out/InterpC-x86.cpp
+++ b/vm/mterp/out/InterpC-x86.cpp
@@ -68,6 +68,14 @@
#if defined(__ARM_EABI__)
# define NO_UNALIGN_64__UNION
#endif
+/*
+ * MIPS ABI requires 64-bit alignment for access to 64-bit data types.
+ *
+ * Use memcpy() to do the transfer
+ */
+#if defined(__mips__)
+/* # define NO_UNALIGN_64__UNION */
+#endif
//#define LOG_INSTR /* verbose debugging */
@@ -452,6 +460,8 @@
}
#endif
+#define FINISH_BKPT(_opcode) /* FIXME? */
+#define DISPATCH_EXTENDED(_opcode) /* FIXME? */
/*
* The "goto label" statements turn into function calls followed by
@@ -488,7 +498,7 @@
* As a special case, "goto bail" turns into a longjmp.
*/
#define GOTO_bail() \
- dvmMterpStdBail(self, false);
+ dvmMterpStdBail(self)
/*
* Periodically check for thread suspension.
@@ -1031,7 +1041,7 @@
} \
SET_REGISTER##_regsize(vdst, \
dvmGetField##_ftype(obj, ifield->byteOffset)); \
- ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1075,7 +1085,7 @@
} \
dvmSetField##_ftype(obj, ifield->byteOffset, \
GET_REGISTER##_regsize(vdst)); \
- ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->name, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1125,7 +1135,7 @@
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1148,7 +1158,7 @@
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
- sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
@@ -1202,7 +1212,7 @@
;
}
- if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+ if (self->interpBreak.ctl.subMode & kSubModeDebugProfile) {
if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
GOTO_exceptionThrown();
} else {
@@ -2174,7 +2184,7 @@
DUMP_REGS(methodToCall, newFp, true); // show input args
if (self->interpBreak.ctl.subMode != 0) {
- dvmReportPreNativeInvoke(methodToCall, self, fp);
+ dvmReportPreNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
}
ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
@@ -2188,12 +2198,13 @@
(*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
if (self->interpBreak.ctl.subMode != 0) {
- dvmReportPostNativeInvoke(methodToCall, self, fp);
+ dvmReportPostNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
}
/* pop frame off */
dvmPopJniLocals(self, newSaveArea);
- self->interpSave.curFrame = fp;
+ self->interpSave.curFrame = newSaveArea->prevFrame;
+ fp = newSaveArea->prevFrame;
/*
* If the native code threw an exception, or interpreted code
diff --git a/vm/mterp/rebuild.sh b/vm/mterp/rebuild.sh
index 2014324..80419a5 100755
--- a/vm/mterp/rebuild.sh
+++ b/vm/mterp/rebuild.sh
@@ -20,7 +20,7 @@
#
set -e
-for arch in portable allstubs armv5te armv5te-vfp armv7-a armv7-a-neon x86 x86-atom; do TARGET_ARCH_EXT=$arch make -f Makefile-mterp; done
+for arch in portable allstubs armv5te armv5te-vfp armv7-a armv7-a-neon mips x86; do TARGET_ARCH_EXT=$arch make -f Makefile-mterp; done
# These aren't actually used, so just go ahead and remove them. The correct
# approach is to prevent them from being generated in the first place, but
diff --git a/vm/mterp/x86-atom/OP_ADD_DOUBLE.S b/vm/mterp/x86-atom/OP_ADD_DOUBLE.S
deleted file mode 100644
index 22f3938..0000000
--- a/vm/mterp/x86-atom/OP_ADD_DOUBLE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_ADD_DOUBLE.S
- */
-
-%include "x86-atom/binopWide.S" {"instr":"addsd %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_ADD_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_ADD_DOUBLE_2ADDR.S
deleted file mode 100644
index 0b2bf4f..0000000
--- a/vm/mterp/x86-atom/OP_ADD_DOUBLE_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_ADD_DOUBLE_2ADDR.S
- */
-
-%include "x86-atom/binopWide2addr.S" {"instr":"addsd %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_ADD_FLOAT.S b/vm/mterp/x86-atom/OP_ADD_FLOAT.S
deleted file mode 100644
index aa3aa22..0000000
--- a/vm/mterp/x86-atom/OP_ADD_FLOAT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_ADD_FLOAT.S
- */
-
-%include "x86-atom/binopF.S" {"instr":"addss %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_ADD_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_ADD_FLOAT_2ADDR.S
deleted file mode 100644
index 3d62703..0000000
--- a/vm/mterp/x86-atom/OP_ADD_FLOAT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_ADD_FLOAT_2ADDR.S
- */
-
-%include "x86-atom/binopF2addr.S" {"instr":"addss %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_ADD_INT.S b/vm/mterp/x86-atom/OP_ADD_INT.S
deleted file mode 100644
index a423e75..0000000
--- a/vm/mterp/x86-atom/OP_ADD_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_ADD_INT.S
- */
-
-%include "x86-atom/binop.S" {"instr":"addl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_ADD_INT_2ADDR.S b/vm/mterp/x86-atom/OP_ADD_INT_2ADDR.S
deleted file mode 100644
index 2a91f41..0000000
--- a/vm/mterp/x86-atom/OP_ADD_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_ADD_INT_2ADDR.S
- */
-
-%include "x86-atom/binop2addr.S" {"instr":"addl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_ADD_INT_LIT16.S b/vm/mterp/x86-atom/OP_ADD_INT_LIT16.S
deleted file mode 100644
index 72479ba..0000000
--- a/vm/mterp/x86-atom/OP_ADD_INT_LIT16.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_ADD_INT_LIT16.S
- */
-
-%include "x86-atom/binopLit16.S" {"instr":"addl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_ADD_INT_LIT8.S b/vm/mterp/x86-atom/OP_ADD_INT_LIT8.S
deleted file mode 100644
index eabd4b5..0000000
--- a/vm/mterp/x86-atom/OP_ADD_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_ADD_INT_LIT8.S
- */
-
-%include "x86-atom/binopLit8.S" {"instr":"addl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_ADD_LONG.S b/vm/mterp/x86-atom/OP_ADD_LONG.S
deleted file mode 100644
index 7e31d35..0000000
--- a/vm/mterp/x86-atom/OP_ADD_LONG.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_ADD_LONG.S
- */
-
-%include "x86-atom/binopWide.S" {"instr":"paddq %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_ADD_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_ADD_LONG_2ADDR.S
deleted file mode 100644
index 4c65a45..0000000
--- a/vm/mterp/x86-atom/OP_ADD_LONG_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_ADD_LONG_2ADDR.S
- */
-
-%include "x86-atom/binopWide2addr.S" {"instr":"paddq %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_AGET.S b/vm/mterp/x86-atom/OP_AGET.S
deleted file mode 100644
index 73a27ab..0000000
--- a/vm/mterp/x86-atom/OP_AGET.S
+++ /dev/null
@@ -1,53 +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.
- */
-
- /*
- * File: OP_AGET.S
- *
- * Code: Generic 32-bit array "get" operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * mov performed also dependent on the type of the array element.
- *
- * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
- *
- * Description: Perform an array get operation at the identified index
- * of a given array; load the array value into the value
- * register. vAA <- vBB[vCC].
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-%default { "mov":"l","scale":"4"}
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $$0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- lea (%ecx, %edx, $scale), %ecx # %ecx<- &vBB[vCC]
- # trying: lea (%ecx, %edx, scale), %ecx
- # to reduce code size
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- mov$mov offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
- # doing this and the previous instr
- # with one instr was not faster
- SET_VREG %edx rINST # vAA<- %edx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_AGET_BOOLEAN.S b/vm/mterp/x86-atom/OP_AGET_BOOLEAN.S
deleted file mode 100644
index 1d28745..0000000
--- a/vm/mterp/x86-atom/OP_AGET_BOOLEAN.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AGET_BOOLEAN.S
- */
-
-%include "x86-atom/OP_AGET.S" { "mov":"zbl", "scale":"1" }
diff --git a/vm/mterp/x86-atom/OP_AGET_BYTE.S b/vm/mterp/x86-atom/OP_AGET_BYTE.S
deleted file mode 100644
index 60e4266..0000000
--- a/vm/mterp/x86-atom/OP_AGET_BYTE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AGET_BYTE.S
- */
-
-%include "x86-atom/OP_AGET.S" { "mov":"sbl", "scale":"1" }
diff --git a/vm/mterp/x86-atom/OP_AGET_CHAR.S b/vm/mterp/x86-atom/OP_AGET_CHAR.S
deleted file mode 100644
index 114d02d..0000000
--- a/vm/mterp/x86-atom/OP_AGET_CHAR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AGET_CHAR.S
- */
-
-%include "x86-atom/OP_AGET.S" { "mov":"zwl", "scale":"2" }
diff --git a/vm/mterp/x86-atom/OP_AGET_OBJECT.S b/vm/mterp/x86-atom/OP_AGET_OBJECT.S
deleted file mode 100644
index 0ed02c3..0000000
--- a/vm/mterp/x86-atom/OP_AGET_OBJECT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AGET_OBJECT.S
- */
-
-%include "x86-atom/OP_AGET.S"
diff --git a/vm/mterp/x86-atom/OP_AGET_SHORT.S b/vm/mterp/x86-atom/OP_AGET_SHORT.S
deleted file mode 100644
index 3ddb9b9..0000000
--- a/vm/mterp/x86-atom/OP_AGET_SHORT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AGET_SHORT.S
- */
-
-%include "x86-atom/OP_AGET.S" { "mov":"swl", "scale":"2" }
diff --git a/vm/mterp/x86-atom/OP_AGET_WIDE.S b/vm/mterp/x86-atom/OP_AGET_WIDE.S
deleted file mode 100644
index db5a930..0000000
--- a/vm/mterp/x86-atom/OP_AGET_WIDE.S
+++ /dev/null
@@ -1,43 +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.
- */
-
- /*
- * File: OP_AGET_WIDE.S
- *
- * Code: 64-bit array get operation.
- *
- * For: aget-wide
- *
- * Description: Perform an array get operation at the identified index
- * of a given array; load the array value into the destination
- * register. vAA <- vBB[vCC].
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $$0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq offArrayObject_contents(%ecx, %edx, 8), %xmm0 # %xmm0<- vBB[vCC]
- movq %xmm0, (rFP, rINST, 4) # vAA<- %xmm0; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_AND_INT.S b/vm/mterp/x86-atom/OP_AND_INT.S
deleted file mode 100644
index 10d223b..0000000
--- a/vm/mterp/x86-atom/OP_AND_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AND_INT.S
- */
-
-%include "x86-atom/binop.S" {"instr":"andl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_AND_INT_2ADDR.S b/vm/mterp/x86-atom/OP_AND_INT_2ADDR.S
deleted file mode 100644
index dcbd531..0000000
--- a/vm/mterp/x86-atom/OP_AND_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AND_INT_2ADDR.S
- */
-
-%include "x86-atom/binop2addr.S" {"instr":"andl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_AND_INT_LIT16.S b/vm/mterp/x86-atom/OP_AND_INT_LIT16.S
deleted file mode 100644
index 7e6493d..0000000
--- a/vm/mterp/x86-atom/OP_AND_INT_LIT16.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AND_INT_LIT16.S
- */
-
-%include "x86-atom/binopLit16.S" {"instr":"andl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_AND_INT_LIT8.S b/vm/mterp/x86-atom/OP_AND_INT_LIT8.S
deleted file mode 100644
index 511e3ae..0000000
--- a/vm/mterp/x86-atom/OP_AND_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AND_INT_LIT8.S
- */
-
-%include "x86-atom/binopLit8.S" {"instr":"andl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_AND_LONG.S b/vm/mterp/x86-atom/OP_AND_LONG.S
deleted file mode 100644
index e62e312..0000000
--- a/vm/mterp/x86-atom/OP_AND_LONG.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AND_LONG.S
- */
-
-%include "x86-atom/binopWide.S" {"instr":"pand %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_AND_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_AND_LONG_2ADDR.S
deleted file mode 100644
index 90e77e6..0000000
--- a/vm/mterp/x86-atom/OP_AND_LONG_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_AND_LONG_2ADDR.S
- */
-
-%include "x86-atom/binopWide2addr.S" {"instr":"pand %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_APUT.S b/vm/mterp/x86-atom/OP_APUT.S
deleted file mode 100644
index 93b3866..0000000
--- a/vm/mterp/x86-atom/OP_APUT.S
+++ /dev/null
@@ -1,50 +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.
- */
-
- /*
- * File: OP_APUT.S
- *
- * Code: Generic 32-bit array put operation. Provides a "scale" variable
- * to specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * move performed also dependent on the type of the array element.
- * Provides a "value" register to specify the source of the move
- *
- * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
- *
- * Description: Perform an array put operation from the value register;
- * store the value register at the identified index of a
- * given array. vBB[vCC] <- vAA
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-%default { "mov":"l","scale":"4", "value": "rINST"}
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $$0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- lea (%ecx, %edx, $scale), %ecx # %ecx<- &vBB[vCC]
- GET_VREG rINST # rINST<- vAA
- mov$mov $value, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_APUT_BOOLEAN.S b/vm/mterp/x86-atom/OP_APUT_BOOLEAN.S
deleted file mode 100644
index d9afd6d..0000000
--- a/vm/mterp/x86-atom/OP_APUT_BOOLEAN.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_APUT_BOOLEAN.S
- */
-
-%include "x86-atom/OP_APUT.S" { "mov":"b", "scale":"1", "value":"rINSTbl" }
diff --git a/vm/mterp/x86-atom/OP_APUT_BYTE.S b/vm/mterp/x86-atom/OP_APUT_BYTE.S
deleted file mode 100644
index 29cb708..0000000
--- a/vm/mterp/x86-atom/OP_APUT_BYTE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_APUT_BYTE.S
- */
-
-%include "x86-atom/OP_APUT.S" { "mov":"b", "scale":"1", "value":"rINSTbl" }
diff --git a/vm/mterp/x86-atom/OP_APUT_CHAR.S b/vm/mterp/x86-atom/OP_APUT_CHAR.S
deleted file mode 100644
index d43e540..0000000
--- a/vm/mterp/x86-atom/OP_APUT_CHAR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_APUT_CHAR.S
- */
-
-%include "x86-atom/OP_APUT.S" { "mov":"w", "scale":"2", "value":"rINSTw" }
diff --git a/vm/mterp/x86-atom/OP_APUT_OBJECT.S b/vm/mterp/x86-atom/OP_APUT_OBJECT.S
deleted file mode 100644
index 0e23d71..0000000
--- a/vm/mterp/x86-atom/OP_APUT_OBJECT.S
+++ /dev/null
@@ -1,77 +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.
- */
-
- /*
- * File: OP_APUT_OBJECT.S
- *
- * Code: 32-bit array put operation. Provides an "scale" variable
- * specify a scale value which depends on the width of the array
- * elements. Provides a "mov" variable which determines the type of
- * mov performed also dependent on the type of the array element.
- * Provides a "value" register to specify the source of the mov
- *
- * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
- *
- * Description: Perform an array put operation from the value register;
- * store the value register at the identified index of a
- * given array. vBB[vCC] <- vAA
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %eax # %eax<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %eax # %eax<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $$0, %eax # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%eax), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- GET_VREG rINST # rINST<- vAA
- lea (%eax, %edx, 4), %edx # %edx<- &vBB[vCC]
- cmp $$0, rINST # check for null reference
- je .L${opcode}_skip_check # reference is null so skip type check
- jmp .L${opcode}_finish
-%break
-
-.L${opcode}_finish:
- movl %edx, sReg0 # save &vBB[vCC]
- movl %eax, sReg1 # save object head
- movl offObject_clazz(rINST), %edx # %edx<- obj->clazz
- movl %edx, -8(%esp) # push parameter obj->clazz
- movl offObject_clazz(%eax), %eax # %eax<- arrayObj->clazz
- movl %eax, -4(%esp) # push parameter arrayObj->clazz
- lea -8(%esp), %esp
- call dvmCanPutArrayElement # test object type vs. array type
- # call: ClassObject* elemClass, ClassObject* arrayClass)
- # return: bool
- lea 8(%esp), %esp
- testl %eax, %eax # check for invalid array value
- je common_errArrayStore # handle invalid array value
- movl sReg0, %edx # restore &vBB[vCC]
- movl rINST, offArrayObject_contents(%edx)
- movl rGLUE, %eax
- FFETCH_ADV 2, %ecx # %ecx<- next instruction hi; fetch, advance
- movl offGlue_cardTable(%eax), %eax # get card table base
- movl sReg1, %edx # restore object head
- shrl $$GC_CARD_SHIFT, %edx # object head to card number
- movb %al, (%eax, %edx) # mark card using object head
- FGETOP_JMP 2, %ecx # jump to next instruction; getop, jmp
-.L${opcode}_skip_check:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl rINST, offArrayObject_contents(%edx)
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_APUT_SHORT.S b/vm/mterp/x86-atom/OP_APUT_SHORT.S
deleted file mode 100644
index daef0d8..0000000
--- a/vm/mterp/x86-atom/OP_APUT_SHORT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_APUT_SHORT.S
- */
-
-%include "x86-atom/OP_APUT.S" { "mov":"w", "scale":"2", "value":"rINSTw" }
diff --git a/vm/mterp/x86-atom/OP_APUT_WIDE.S b/vm/mterp/x86-atom/OP_APUT_WIDE.S
deleted file mode 100644
index b1b9e6a..0000000
--- a/vm/mterp/x86-atom/OP_APUT_WIDE.S
+++ /dev/null
@@ -1,43 +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.
- */
-
- /*
- * File: OP_APUT_WIDE.S
- *
- * Code: 64-bit array put operation.
- *
- * For: aput-wide
- *
- * Description: Perform an array put operation from the value register;
- * store the value register at the identified index of a
- * given array. vBB[vCC] <- vAA.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- cmp $$0, %ecx # check for null array object
- je common_errNullObject # handle null array object
- cmp offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
- jnc common_errArrayIndex # handle index >= length, bail
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vAA
- movq %xmm0, offArrayObject_contents(%ecx, %edx, 8) # vBB[vCC]<- %xmm0; value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_ARRAY_LENGTH.S b/vm/mterp/x86-atom/OP_ARRAY_LENGTH.S
deleted file mode 100644
index 485f815..0000000
--- a/vm/mterp/x86-atom/OP_ARRAY_LENGTH.S
+++ /dev/null
@@ -1,40 +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.
- */
-
- /*
- * File: OP_ARRAY_LENGTH.S
- *
- * Code: 32-bit array length operation.
- *
- * For: array-length
- *
- * Description: Store the length of the indicated array in the given
- * destination register. vB <- offArrayObject_length(vA)
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %eax # %eax<- BA
- shr $$4, %eax # %eax<- B
- andl $$15, rINST # rINST<- A
- GET_VREG %eax # %eax<- vB
- cmp $$0, %eax # check for null array object
- je common_errNullObject # handle null array object
- FFETCH_ADV 1, %edx # %edx<- next instruction hi; fetch, advance
- movl offArrayObject_length(%eax), %eax # %eax<- array length
- movl %eax, (rFP, rINST, 4) # vA<- %eax; array length
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_BREAKPOINT.S b/vm/mterp/x86-atom/OP_BREAKPOINT.S
deleted file mode 100644
index e69de29..0000000
--- a/vm/mterp/x86-atom/OP_BREAKPOINT.S
+++ /dev/null
diff --git a/vm/mterp/x86-atom/OP_CHECK_CAST.S b/vm/mterp/x86-atom/OP_CHECK_CAST.S
deleted file mode 100644
index c78f336..0000000
--- a/vm/mterp/x86-atom/OP_CHECK_CAST.S
+++ /dev/null
@@ -1,118 +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.
- */
-
- /*
- * File: OP_CHECK_CAST.S
- *
- * Code: Checks to see if a cast is allowed. Uses no substitutions.
- *
- * For: check-cast
- *
- * Description: Throw if the reference in the given register cannot be
- * cast to the indicated type. The type must be a reference
- * type (not a primitive type).
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, type@BBBB
- */
-
- movl rGLUE, %edx # get MterpGlue pointer
- movl offGlue_methodClassDex(%edx), %eax # %eax<- pDvmDex
- GET_VREG rINST # rINST<- vAA
- movl offDvmDex_pResClasses(%eax), %eax # %eax<- pDvmDex->pResClasses
- cmp $$0, rINST # check for null reference object
- je .L${opcode}_okay # can always cast null object
- FETCH 1, %ecx # %ecx<- BBBB
- movl (%eax, %ecx, 4), %ecx # %ecx<- resolved class
- cmp $$0, %ecx # check if classes is resolved before?
- je .L${opcode}_resolve # resolve class
- jmp .L${opcode}_resolved # continue
-%break
-
-.L${opcode}_resolved:
- cmp %ecx, offObject_clazz(rINST) # check for same class
- jne .L${opcode}_fullcheck # not same class; do full check
-
-.L${opcode}_okay:
- FINISH 2 # jump to next instruction
-
- /*
- * Trivial test failed, need to perform full check.
- * offObject_clazz(rINST) holds obj->clazz
- * %ecx holds class resolved from BBBB
- * rINST holds object
- */
-
-.L${opcode}_fullcheck:
- movl offObject_clazz(rINST), %eax # %eax<- obj->clazz
- movl %eax, -12(%esp) # push parameter obj->clazz
- movl %ecx, -8(%esp) # push parameter # push parameter resolved class
- lea -12(%esp), %esp
- call dvmInstanceofNonTrivial # call: (ClassObject* instance, ClassObject* clazz)
- # return: int
- lea 12(%esp), %esp
- cmp $$0, %eax # failed?
- jne .L${opcode}_okay # success
-
- /*
- * A cast has failed. We need to throw a ClassCastException with the
- * class of the object that failed to be cast.
- */
-
- EXPORT_PC # we will throw an exception
-#error BIT ROT!!!
- /*
- * TODO: Code here needs to call dvmThrowClassCastException with two
- * arguments.
- */
-#if 0
- /* old obsolete code that called dvmThrowExceptionWithClassMessage */
- movl $$.LstrClassCastExceptionPtr, -8(%esp) # push parameter message
- movl offObject_clazz(rINST), rINST # rINST<- obj->clazz
- movl offClassObject_descriptor(rINST), rINST # rINST<- obj->clazz->descriptor
- movl rINST, -4(%esp) # push parameter obj->clazz->descriptor
- lea -8(%esp), %esp
- call dvmThrowExceptionWithClassMessage # call: (const char* exceptionDescriptor,
- # const char* messageDescriptor, Object* cause)
- # return: void
-#endif
- lea 8(%esp), %esp
- jmp common_exceptionThrown
-
- /*
- * Resolution required. This is the least-likely path.
- *
- * rINST holds object
- */
-
-.L${opcode}_resolve:
- movl offGlue_method(%edx), %eax # %eax<- glue->method
- FETCH 1, %ecx # %ecx holds BBBB
- EXPORT_PC # in case we throw an exception
- movl $$0, -8(%esp) # push parameter false
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- movl %ecx, -12(%esp) # push parameter BBBB
- movl %eax, -16(%esp) # push parameter glue->method>clazz
- lea -16(%esp), %esp
- call dvmResolveClass # resolve ClassObject pointer
- # call: (const ClassObject* referrer, u4 classIdx,
- # bool fromUnverifiedConstant)
- # return ClassObject*
- lea 16(%esp), %esp
- cmp $$0, %eax # check for null pointer
- je common_exceptionThrown # handle excpetion
- movl %eax, %ecx # %ecx<- resolved class
- jmp .L${opcode}_resolved
diff --git a/vm/mterp/x86-atom/OP_CMPG_DOUBLE.S b/vm/mterp/x86-atom/OP_CMPG_DOUBLE.S
deleted file mode 100644
index 87f8a3b..0000000
--- a/vm/mterp/x86-atom/OP_CMPG_DOUBLE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_CMPG_DOUBLE.S
- */
-
-%include "x86-atom/OP_CMPL_FLOAT.S" { "nan":"$0x1", "sod":"d"}
diff --git a/vm/mterp/x86-atom/OP_CMPG_FLOAT.S b/vm/mterp/x86-atom/OP_CMPG_FLOAT.S
deleted file mode 100644
index de42969..0000000
--- a/vm/mterp/x86-atom/OP_CMPG_FLOAT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_CMPG_FLOAT.S
- */
-
-%include "x86-atom/OP_CMPL_FLOAT.S" { "nan":"$0x1" }
diff --git a/vm/mterp/x86-atom/OP_CMPL_DOUBLE.S b/vm/mterp/x86-atom/OP_CMPL_DOUBLE.S
deleted file mode 100644
index 2a603a4..0000000
--- a/vm/mterp/x86-atom/OP_CMPL_DOUBLE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_CMPL_DOUBLE.S
- */
-
-%include "x86-atom/OP_CMPL_FLOAT.S" { "sod":"d" }
diff --git a/vm/mterp/x86-atom/OP_CMPL_FLOAT.S b/vm/mterp/x86-atom/OP_CMPL_FLOAT.S
deleted file mode 100644
index 5cb3ec7..0000000
--- a/vm/mterp/x86-atom/OP_CMPL_FLOAT.S
+++ /dev/null
@@ -1,63 +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.
- */
-
- /*
- * File: OP_CMPL_FLOAT.S
- *
- * Code: Provides a "nan" variable to specify the return value for
- * NaN. Provides a variable "sod" which appends a "s" or a "d"
- * to the move and comparison instructions, depending on if we
- * are working with a float or a double. For instructions
- * cmpx-float and cmpx-double, the x will be eiher a g or a l
- * to specify positive or negative bias for NaN.
- *
- * For: cmpg-double, dmpg-float, cmpl-double, cmpl-float
- *
- * Description: Perform the indicated floating point or long comparison,
- * storing 0 if the two arguments are equal, 1 if the second
- * argument is larger, or -1 if the first argument is larger.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-%default { "nan":"$0xFFFFFFFF" , "sod":"s" }
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movs$sod (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- comis$sod (rFP, %edx, 4), %xmm0 # do comparison
- ja .L${opcode}_greater
- jp .L${opcode}_finalNan
- jz .L${opcode}_final
-
-.L${opcode}_less:
- movl $$0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-%break
-.L${opcode}_greater:
- movl $$0x1, (rFP, rINST, 4) # vAA<- greater than
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-.L${opcode}_final:
- movl $$0x0, (rFP, rINST, 4) # vAA<- equal
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
-.L${opcode}_finalNan:
- movl $nan, (rFP, rINST, 4) # vAA<- NaN
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CMP_LONG.S b/vm/mterp/x86-atom/OP_CMP_LONG.S
deleted file mode 100644
index cf021a3..0000000
--- a/vm/mterp/x86-atom/OP_CMP_LONG.S
+++ /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.
- */
-
- /*
- * File: OP_CMP_LONG.S
- *
- * Code: Compare floating point values. Uses no substitutions.
- *
- * For: cmp-long
- *
- * Description: Perform a long comparison, storing 0 if the two
- * arguments are equal, 1 if the second argument is larger
- * or -1 if the first argument is larger.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- movl 4(rFP, %ecx, 4), %eax # %eax<- vBBhi
- cmp 4(rFP, %edx, 4), %eax # compare vCChi and vBBhi
- jl .L${opcode}_less
- jg .L${opcode}_greater
- movl (rFP, %ecx, 4), %eax # %eax<- vBBlo
- cmp (rFP, %edx, 4), %eax # compare vCClo and vBBlo
- ja .L${opcode}_greater
- jne .L${opcode}_less
- jmp .L${opcode}_final
-%break
-
-.L${opcode}_final:
- movl $$0x0, (rFP, rINST, 4) # vAA<- equal
- FINISH 2 # jump to next instruction
-
-.L${opcode}_less:
- movl $$0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
- FINISH 2 # jump to next instruction
-
-.L${opcode}_greater:
- movl $$0x1, (rFP, rINST, 4) # vAA<- greater than
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_CONST.S b/vm/mterp/x86-atom/OP_CONST.S
deleted file mode 100644
index 7ff4c23..0000000
--- a/vm/mterp/x86-atom/OP_CONST.S
+++ /dev/null
@@ -1,36 +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.
- */
-
- /*
- * File: OP_CONST.S
- *
- * Code: Move a literal to a register. Uses no substitutions.
- *
- * For: const
- *
- * Description: Move the given literal value into the specified register
- *
- * Format: AA|op BBBBlo BBBBhi (31i)
- *
- * Syntax: op vAA, #+BBBBBBBB
- */
-
- FETCH 2, %edx # %edx<- BBBBhi
- FETCH 1, %ecx # %ecx<- BBBBlo
- shl $$16, %edx # move BBBB to high bits
- or %edx, %ecx # %ecx<- #+BBBBBBBB
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- SET_VREG %ecx, rINST # vAA<- %ecx; literal
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_16.S b/vm/mterp/x86-atom/OP_CONST_16.S
deleted file mode 100644
index f340696..0000000
--- a/vm/mterp/x86-atom/OP_CONST_16.S
+++ /dev/null
@@ -1,34 +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.
- */
-
- /*
- * File: OP_CONST_16.S
- *
- * Code: Moves a literal to a register. Uses no substitutions.
- *
- * For: const/16
- *
- * Description: Move the given literal value (right-zero-extended to 32
- * bits) into the specified register
- *
- * Format: AA|op BBBB (21s)
- *
- * Syntax: op vAA, #+BBBB
- */
-
- FETCHs 1, %edx # %edx<- BBBB
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- SET_VREG %edx rINST # vAA<- BBBB; literal
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_4.S b/vm/mterp/x86-atom/OP_CONST_4.S
deleted file mode 100644
index 5396d72..0000000
--- a/vm/mterp/x86-atom/OP_CONST_4.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_CONST_4.S
- *
- * Code: Moves a literal to a register. Uses no substitutions.
- *
- * For: const/4
- *
- * Description: Move the given literal value (right-zero-extended to 32
- * bits) into the specified register.
- *
- * Format: B|A|op (11n)
- *
- * Syntax: op vA, #+B
- */
-
- movl rINST, %edx # %edx<- BA
- andl $$15, rINST # rINST<- A
- shl $$24, %edx # %edx<- B000
- sar $$28, %edx # %edx<- right-zero-extended B
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- SET_VREG %edx, rINST # vA<- %edx; literal
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_CLASS.S b/vm/mterp/x86-atom/OP_CONST_CLASS.S
deleted file mode 100644
index bc6657c..0000000
--- a/vm/mterp/x86-atom/OP_CONST_CLASS.S
+++ /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.
- */
-
- /*
- * File: OP_CONST_CLASS.S
- *
- * Code: Move a class reference to a register. Uses no substitutions.
- *
- * For: const/class
- *
- * Description: Move a reference to the class specified
- * by the given index into the specified register.
- * In the case where the indicated type is primitive,
- * this will store a reference to the primitive type's
- * degenerate class.
- *
- * Format: AA|op BBBBlo BBBBhi (21c)
- *
- * Syntax: op vAA, field@BBBB
- */
-
- movl rGLUE, %edx # get MterpGlue pointer
- FETCH 1, %ecx # %ecx<- BBBB
- movl offGlue_methodClassDex(%edx), %eax # %eax<- pDvmDex
- movl offDvmDex_pResClasses(%eax), %eax # %eax<- pDvmDex->pResClasses
- movl (%eax, %ecx, 4), %eax # %eax<- resolved class
- cmp $$0, %eax # check if classes is resolved before?
- je .L${opcode}_resolve # resolve class
- SET_VREG %eax, rINST # vAA<- resolved class
- FINISH 2 # jump to next instruction
-%break
-
- /*
- * Continuation if the Class has not yet been resolved.
- * %ecx: BBBB (Class ref)
- * need: target register
- */
-
-.L${opcode}_resolve:
- EXPORT_PC
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl $$1, -4(%esp) # push parameter true
- movl %ecx, -8(%esp) # push parameter
- movl %edx, -12(%esp) # push parameter glue->method->clazz
- lea -12(%esp), %esp
- call dvmResolveClass # resolve ClassObject pointer
- # class: (const ClassObject* referrer, u4 classIdx,
- # bool fromUnverifiedConstant)
- # return: ClassObject*
- lea 12(%esp), %esp
- cmp $$0, %eax # check for null pointer
- je common_exceptionThrown # handle exception
- SET_VREG %eax, rINST # vAA<- resolved class
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_CONST_HIGH16.S b/vm/mterp/x86-atom/OP_CONST_HIGH16.S
deleted file mode 100644
index f47d34b..0000000
--- a/vm/mterp/x86-atom/OP_CONST_HIGH16.S
+++ /dev/null
@@ -1,35 +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.
- */
-
- /*
- * File: OP_CONST_HIGH16.S
- *
- * Code: Move a literal to a register. Uses no substitutions.
- *
- * For: const/high16
- *
- * Description: Move the given literal value (right-zero-extended to 32
- * bits) into the specified register
- *
- * Format: AA|op BBBB (21h)
- *
- * Syntax: op vAA, #+BBBB0000
- */
-
- FETCH 1, %ecx # %ecx<- 0000BBBB (zero-extended)
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- shl $$16, %ecx # %ecx<- BBBB0000
- SET_VREG %ecx, rINST # vAA<- %ecx; BBBB0000
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_STRING.S b/vm/mterp/x86-atom/OP_CONST_STRING.S
deleted file mode 100644
index c958ed4..0000000
--- a/vm/mterp/x86-atom/OP_CONST_STRING.S
+++ /dev/null
@@ -1,65 +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.
- */
-
- /*
- * File: OP_CONST_STRING.S
- *
- * Code: Move a string reference to a register. Uses no substitutions.
- *
- * For: const/string
- *
- * Description: Move a referece to the string specified by the given
- * index into the specified register. vAA <- pResString[BBBB]
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- FETCH 1, %ecx # %ecx<- BBBB
- movl rGLUE, %edx # get MterpGlue pointer
- movl offGlue_methodClassDex(%edx), %eax # %eax<- glue->methodClassDex
- movl offDvmDex_pResStrings(%eax), %eax # %eax<- glue->methodClassDex->pResStrings
- movl (%eax, %ecx, 4), %eax # %eax<- pResStrings[BBBB]
- cmp $$0, %eax # check if string is resolved
- je .L${opcode}_resolve # resolve string reference
- SET_VREG %eax, rINST # vAA<- %eax; pResString[BBBB]
- FINISH 2 # jump to next instruction
-
-%break
-
-
- /*
- * Continuation if the Class has not yet been resolved.
- * %ecx: BBBB (Class ref)
- * need: target register
- */
-
-.L${opcode}_resolve:
- EXPORT_PC
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %ecx, -4(%esp) # push parameter class ref
- movl %edx, -8(%esp) # push parameter glue->method->clazz
- lea -8(%esp), %esp
- call dvmResolveString # resolve string reference
- # call: (const ClassObject* referrer, u4 stringIdx)
- # return: StringObject*
- lea 8(%esp), %esp
- cmp $$0, %eax # check if resolved string failed
- je common_exceptionThrown # resolve failed; exception thrown
- SET_VREG %eax, rINST # vAA<- %eax; pResString[BBBB]
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_STRING_JUMBO.S b/vm/mterp/x86-atom/OP_CONST_STRING_JUMBO.S
deleted file mode 100644
index 09d045d..0000000
--- a/vm/mterp/x86-atom/OP_CONST_STRING_JUMBO.S
+++ /dev/null
@@ -1,66 +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.
- */
-
- /*
- * File: OP_CONST_STRING_JUMBO.S
- *
- * Code: Move a string reference to a register. Uses no substitutions.
- *
- * For: const/string-jumbo
- *
- * Description: Move a reference to the string specified by the given
- * index into the specified register. vAA <- pResString[BBBB]
- *
- * Format: AA|op BBBBlo BBBBhi (31c)
- *
- * Syntax: op vAA, string@BBBBBBBB
- */
-
- movl rGLUE, %edx # get MterpGlue pointer
- movl offGlue_methodClassDex(%edx), %eax # %eax<- glue->methodClassDex
- movl offDvmDex_pResStrings(%eax), %eax # %eax<- glue->methodClassDex->pResStrings
- FETCH 1, %ecx # %ecx<- BBBBlo
- FETCH 2, %edx # %edx<- BBBBhi
- shl $$16, %edx # %edx<- prepare to create &BBBBBBBB
- or %edx, %ecx # %ecx<- &BBBBBBBB
- movl (%eax, %ecx, 4), %eax # %eax<- pResStrings[BBBB]
- cmp $$0, %eax # check if string is resolved
- je .L${opcode}_resolve # resolve string reference
- SET_VREG %eax, rINST # vAA<- %eax; pResString[BBBB]
- FINISH 3 # jump to next instruction
-%break
-
-
- /*
- * Continuation if the Class has not yet been resolved.
- * %ecx: BBBB (Class ref)
- * need: target register
- */
-.L${opcode}_resolve:
- EXPORT_PC
- movl rGLUE, %edx # get MterpGlue pointer
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl offMethod_clazz(%edx), %edx # %edx <- glue->method->clazz
- movl %ecx, -4(%esp) # push parameter class ref
- movl %edx, -8(%esp) # push parameter glue->method->clazz
- lea -8(%esp), %esp
- call dvmResolveString # resolve string reference
- # call: (const ClassObject* referrer, u4 stringIdx)
- # return: StringObject*
- lea 8(%esp), %esp
- cmp $$0, %eax # check if resolved string failed
- je common_exceptionThrown # resolve failed; exception thrown
- SET_VREG %eax, rINST # vAA<- %eax; pResString[BBBB]
- FINISH 3 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_CONST_WIDE.S b/vm/mterp/x86-atom/OP_CONST_WIDE.S
deleted file mode 100644
index 1ce7c76..0000000
--- a/vm/mterp/x86-atom/OP_CONST_WIDE.S
+++ /dev/null
@@ -1,42 +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.
- */
-
- /*
- * File: OP_CONST_WIDE.S
- *
- * Code: Move a literal to a register. Uses no substitutions.
- *
- * For: const-wide
- *
- * Description: Move the given literal value into the specified
- * register pair
- *
- * Format: AA|op BBBBlolo BBBBlohi BBBBhilo BBBBhihi (51l)
- *
- * Syntax: op vAA, #+BBBBBBBBBBBBBBBB
- */
-
- FETCH 1, %ecx # %ecx<- BBBBlolo
- FETCH 2, %edx # %edx<- BBBBlohi
- shl $$16, %edx # %edx<- prepare to create #+BBBBBBBBlo
- or %edx, %ecx # %ecx<- #+BBBBBBBBlo
- movl %ecx, (rFP, rINST, 4) # vAA <- #+BBBBBBBBlo
- FETCH 3, %ecx # %ecx<- BBBBhilo
- FETCH 4, %edx # %edx<- BBBBhihi
- FFETCH_ADV 5, %eax # %eax<- next instruction hi; fetch, advance
- shl $$16, %edx # %edx<- prepare to create #+BBBBBBBBhi
- or %edx, %ecx # %ecx<- #+BBBBBBBBhi
- movl %ecx, 4(rFP, rINST, 4) # vAA+1 <- #+BBBBBBBBlo
- FGETOP_JMP 5, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_WIDE_16.S b/vm/mterp/x86-atom/OP_CONST_WIDE_16.S
deleted file mode 100644
index c980f10..0000000
--- a/vm/mterp/x86-atom/OP_CONST_WIDE_16.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_CONST_WIDE_16.S
- *
- * Code: Move a literal to a register. Uses no substitutions.
- *
- * For: const-wide/16
- *
- * Description: Move the given literal value (sign-extended to 64 bits)
- * into the specified register-pair
- *
- * Format: AA|op BBBB (21s)
- *
- * Syntax: op vAA, #+BBBB
- */
-
- FETCHs 1, %ecx # %ecx<- ssssBBBB (sign-extended)
- movl %ecx, %edx # %edx<- ssssBBBB (sign-extended)
- sar $$31, %ecx # %ecx<- sign bit
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movl %edx, (rFP, rINST, 4) # vAA<- ssssBBBB
- movl %ecx, 4(rFP, rINST, 4) # vAA+1<- ssssssss
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_WIDE_32.S b/vm/mterp/x86-atom/OP_CONST_WIDE_32.S
deleted file mode 100644
index 92f8450..0000000
--- a/vm/mterp/x86-atom/OP_CONST_WIDE_32.S
+++ /dev/null
@@ -1,39 +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.
- */
-
- /*
- * File: OP_CONST_WIDE_32.S
- *
- * Code: Move a literal to a register. Uses no substitutions.
- *
- * For: const-wide/32
- *
- * Description: Move the given literal value (sign-extended to 64 bits)
- * into the specified register-pair
- *
- * Format: AA|op BBBBlo BBBBhi (31i)
- *
- * Syntax: op vAA, #+BBBBBBBB
- */
-
- FETCH 1, %edx # %edx<- BBBBlo
- FETCHs 2, %ecx # %ecx<- BBBBhi
- shl $$16, %ecx # prepare to create #+BBBBBBBB
- or %ecx, %edx # %edx<- %edx<- #+BBBBBBBB
- sar $$31, %ecx # %ecx<- sign bit
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- movl %edx, (rFP, rINST, 4) # vAA<- BBBBBBBB
- movl %ecx, 4(rFP, rINST, 4) # vAA+1<- ssssssss
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_WIDE_HIGH16.S b/vm/mterp/x86-atom/OP_CONST_WIDE_HIGH16.S
deleted file mode 100644
index 5b4b4f1..0000000
--- a/vm/mterp/x86-atom/OP_CONST_WIDE_HIGH16.S
+++ /dev/null
@@ -1,35 +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.
- */
-
- /*
- * File: OP_CONST_WIDE_HIGH16.S
- *
- * Code: Move a literal value to a register. Uses no substitutions.
- *
- * For: const-wide/high16
- *
- * Description: Move the given literal value (right-zero-extended to 64
- * bits) into the specified register
- *
- * Format: AA|op BBBB (21h)
- *
- * Syntax: op vAA, #+BBBB000000000000
- */
-
- FETCH 1, %ecx # %ecx<- 0000BBBB (zero-extended)
- shl $$16, %ecx # rINST<- AA
- movl $$0, (rFP, rINST, 4) # vAAlow<- 00000000
- movl %ecx, 4(rFP, rINST, 4) # vAAhigh<- %ecx; BBBB0000
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_DIV_DOUBLE.S b/vm/mterp/x86-atom/OP_DIV_DOUBLE.S
deleted file mode 100644
index 418a230..0000000
--- a/vm/mterp/x86-atom/OP_DIV_DOUBLE.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_DIV_DOUBLE.S
- *
- * Code: Divides doubles. Uses no substitutions.
- *
- * For: div-double
- *
- * Description: Divide operation on two source registers, storing
- * the result in a destination register
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- fldl (rFP, %ecx, 4) # floating point stack vBB
- fdivl (rFP, %edx, 4) # divide double; vBB/vCC
- fstpl (rFP, rINST, 4) # vAA<- result
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_DIV_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_DIV_DOUBLE_2ADDR.S
deleted file mode 100644
index 7003e30..0000000
--- a/vm/mterp/x86-atom/OP_DIV_DOUBLE_2ADDR.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_DIV_DOUBLE_2ADDR.S
- *
- * Code: Divides doubles. Uses no substitutions.
- *
- * For: div-double/2addr
- *
- * Description: Divide operation on two source registers, storing
- * the result in the first source reigster
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- andl $$15, %edx # %edx<- A
- shr $$4, rINST # rINST<- B
- fldl (rFP, %edx, 4) # %xmm0<- vA
- fdivl (rFP, rINST, 4) # divide double; vA/vB
- fstpl (rFP, %edx, 4) # vAA<- result
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_DIV_FLOAT.S b/vm/mterp/x86-atom/OP_DIV_FLOAT.S
deleted file mode 100644
index a7aabd7..0000000
--- a/vm/mterp/x86-atom/OP_DIV_FLOAT.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_DIV_FLOAT.S
- *
- * Code: Divides floats. Uses no substitutions.
- *
- * For: div-float
- *
- * Description: Divide operation on two source registers, storing
- * the result in a destiniation register
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %eax # %eax<- BB
- FETCH_CC 1, %ecx # %ecx<- CC
- flds (rFP, %eax, 4) # floating point stack vBB
- fdivs (rFP, %ecx, 4) # divide double; vBB/vCC
- fstps (rFP, rINST, 4) # vAA<- result
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_DIV_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_DIV_FLOAT_2ADDR.S
deleted file mode 100644
index 471f30a..0000000
--- a/vm/mterp/x86-atom/OP_DIV_FLOAT_2ADDR.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_DIV_FLOAT_2ADDR.S
- *
- * Code: Divides floats. Uses no substitutions.
- *
- * For: div-float/2addr
- *
- * Description: Divide operation on two source registers, storing
- * the result in the first source reigster
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- andl $$15, %ecx # %ecx<- A
- shr $$4, rINST # rINST<- B
- flds (rFP, %ecx, 4) # %xmm0<- vA
- fdivs (rFP, rINST, 4) # divide double; vA/vB
- fstps (rFP, %ecx, 4) # vAA<- result
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_DIV_INT.S b/vm/mterp/x86-atom/OP_DIV_INT.S
deleted file mode 100644
index c7f5b27..0000000
--- a/vm/mterp/x86-atom/OP_DIV_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_DIV_INT.S
- */
-
-%include "x86-atom/binopD.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_INT_2ADDR.S b/vm/mterp/x86-atom/OP_DIV_INT_2ADDR.S
deleted file mode 100644
index 762d82f..0000000
--- a/vm/mterp/x86-atom/OP_DIV_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_DIV_INT_2ADDR.S
- */
-
-%include "x86-atom/binopD2addr.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_INT_LIT16.S b/vm/mterp/x86-atom/OP_DIV_INT_LIT16.S
deleted file mode 100644
index 9c2ce55..0000000
--- a/vm/mterp/x86-atom/OP_DIV_INT_LIT16.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_DIV_INT_LIT16.S
- */
-
-%include "x86-atom/binopDLit16.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_INT_LIT8.S b/vm/mterp/x86-atom/OP_DIV_INT_LIT8.S
deleted file mode 100644
index ef0ea7b..0000000
--- a/vm/mterp/x86-atom/OP_DIV_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_DIV_INT_LIT8.S
- */
-
-%include "x86-atom/binopDLit8.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_LONG.S b/vm/mterp/x86-atom/OP_DIV_LONG.S
deleted file mode 100644
index 38ade6a..0000000
--- a/vm/mterp/x86-atom/OP_DIV_LONG.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_DIV_LONG.S
- */
-
-%include "x86-atom/binopDivRemLong.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_DIV_LONG_2ADDR.S
deleted file mode 100644
index 41e5430..0000000
--- a/vm/mterp/x86-atom/OP_DIV_LONG_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_DIV_LONG_2ADDR.S
- */
-
-%include "x86-atom/binopDivRemLong2Addr.S"
diff --git a/vm/mterp/x86-atom/OP_DOUBLE_TO_FLOAT.S b/vm/mterp/x86-atom/OP_DOUBLE_TO_FLOAT.S
deleted file mode 100644
index 516a2e6..0000000
--- a/vm/mterp/x86-atom/OP_DOUBLE_TO_FLOAT.S
+++ /dev/null
@@ -1,36 +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.
- */
-
- /*
- * File: OP_DOUBLE_TO_FLOAT.S
- *
- * Code: Converts a double to a float. Uses no substitutions.
- *
- * For: double-to-float
- *
- * Description: Convert the source register (a double) to a float
- * and store the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, rINST # rINST<- B
- and $$15, %edx # %edx<- A
- fldl (rFP, rINST, 4) # load &vB
- fstps (rFP, %edx, 4) # store float
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_DOUBLE_TO_INT.S b/vm/mterp/x86-atom/OP_DOUBLE_TO_INT.S
deleted file mode 100644
index f377762..0000000
--- a/vm/mterp/x86-atom/OP_DOUBLE_TO_INT.S
+++ /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.
- */
-
- /*
- * File: OP_DOUBLE_TO_INT.S
- *
- * Code: Converts a double to an integer. Uses no substitutions.
- *
- * For: double-to-int
- *
- * Description: Convert the source register (a double) to an integer
- * and store the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, rINST # rINST<- B
- and $$15, %edx # %edx<- A
- fldl (rFP, rINST, 4) # load &vB
- fildl .LintMax # push max int value
- fildl .LintMin # push min int value
- fucomip %st(2), %st(0) # check for negInf
- jae .L${opcode}_negInf # handle negInf
- fucomip %st(1), %st(0) # check for posInf or NaN
- jc .L${opcode}_nanInf # handle posInf or NaN
- jmp .L${opcode}_break # do conversion
-%break
-
-.L${opcode}_break:
- fnstcw -2(%esp) # save control word
- orl $$0xc00, -2(%esp) # reset control
- fldcw -2(%esp) # load control word
- xorl $$0xc00, -2(%esp) # reset control
- fistpl (rFP, %edx, 4) # move converted int
- fldcw -2(%esp) # load saved control word
- FINISH 1 # jump to next instruction
-
-.L${opcode}_nanInf:
- jnp .L${opcode}_posInf
- fstps (rFP, %edx, 4)
- movl $$0x00000000, (rFP, %edx, 4) # vA<- NaN
- FINISH 1 # jump to next instruction
-
-.L${opcode}_posInf:
- fstps (rFP, %edx, 4)
- movl $$0x7FFFFFFF, (rFP, %edx, 4) # vA<- posInf
- FINISH 1 # jump to next instruction
-
-.L${opcode}_negInf:
- fstps (rFP, %edx, 4)
- fstps (rFP, %edx, 4)
- movl $$0x80000000, (rFP, %edx, 4) # vA<- negInf
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_DOUBLE_TO_LONG.S b/vm/mterp/x86-atom/OP_DOUBLE_TO_LONG.S
deleted file mode 100644
index 2ce9bcc..0000000
--- a/vm/mterp/x86-atom/OP_DOUBLE_TO_LONG.S
+++ /dev/null
@@ -1,71 +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.
- */
-
- /*
- * File: OP_DOUBLE_TO_LONG.S
- *
- * Code: Converts a double to a long. Uses no substitutions.
- *
- * For: double-to-long
- *
- * Description: Convert the double in source register to a long
- * and store in the destintation register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %ecx<- BA
- shr $$4, rINST # rINST<- B
- and $$15, %edx # %ecx<- A
- fldl (rFP, rINST, 4) # push vB to floating point stack
- fildll .LvaluePosInfLong # push max int value
- fildll .LvalueNegInfLong # push min int value
- fucomip %st(2), %st(0) # check for negInf
- jae .L${opcode}_negInf # handle negInf
- fucomip %st(1), %st(0) # check for posInf or NaN
- jc .L${opcode}_nanInf # handle posInf or NaN
- jmp .L${opcode}_break # do conversion
-%break
-
-.L${opcode}_break:
- fnstcw -2(%esp) # save control word
- orl $$0xc00, -2(%esp) # reset control
- fldcw -2(%esp) # load control word
- xorl $$0xc00, -2(%esp) # reset control
- fistpll (rFP, %edx, 4) # move converted int
- fldcw -2(%esp) # load saved control word
- FINISH 1 # jump to next instruction
-
-.L${opcode}_nanInf:
- jnp .L${opcode}_posInf
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvalueNanLong, %xmm0 # %xmm0<- NaN
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; NaN
- FINISH 1 # jump to next instruction
-
-.L${opcode}_posInf:
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvaluePosInfLong, %xmm0 # %xmm0<- posInf
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; posInf
- FINISH 1 # jump to next instruction
-
-.L${opcode}_negInf:
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvalueNegInfLong, %xmm0 # %xmm0<- negInf
- fstpl (rFP, %edx, 4) # move converted int
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; negInf
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_EXECUTE_INLINE.S b/vm/mterp/x86-atom/OP_EXECUTE_INLINE.S
deleted file mode 100644
index 4f01cef..0000000
--- a/vm/mterp/x86-atom/OP_EXECUTE_INLINE.S
+++ /dev/null
@@ -1,86 +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.
- */
-
- /*
- * File: OP_EXECUTE_INLINE.S
- *
- * Code: Executes a "native inline" instruction. Uses no substitutions.
- *
- * For: execute-inline
- *
- * Description: Executes a "native inline" instruction. This instruction
- * is generated by the optimizer.
- *
- * Format:
- *
- * Syntax: vAA, {vC, vD, vE, vF}, inline@BBBB
- */
-
- FETCH 1, %ecx # %ecx<- BBBB
- movl rGLUE, %eax # %eax<- MterpGlue pointer
- addl $$offGlue_retval, %eax # %eax<- &glue->retval
- EXPORT_PC
- shr $$4, rINST # rINST<- B
- movl %eax, -8(%esp) # push parameter glue->retval
- lea -24(%esp), %esp
- jmp .L${opcode}_continue
-%break
-
- /*
- * Extract args, call function.
- * rINST = #of args (0-4)
- * %ecx = call index
- */
-
-.L${opcode}_continue:
- FETCH 2, %edx # %edx<- FEDC
- cmp $$1, rINST # determine number of arguments
- jl 0f # handle zero args
- je 1f # handle one arg
- cmp $$3, rINST
- jl 2f # handle two args
- je 3f # handle three args
-4:
- movl %edx, rINST # rINST<- FEDC
- and $$0xf000, rINST # isolate F
- shr $$10, rINST
- movl (rFP, rINST), rINST # rINST<- vF
- movl rINST, 12(%esp) # push parameter vF
-3:
- movl %edx, rINST # rINST<- FEDC
- and $$0x0f00, rINST # isolate E
- shr $$6, rINST
- movl (rFP, rINST), rINST # rINST<- vE
- movl rINST, 8(%esp) # push parameter E
-2:
- movl %edx, rINST # rINST<- FEDC
- and $$0x00f0, rINST # isolate D
- shr $$2, rINST
- movl (rFP, rINST), rINST # rINST<- vD
- movl rINST, 4(%esp) # push parameter D
-1:
- and $$0x000f, %edx # isolate C
- movl (rFP, %edx, 4), %edx # rINST<- vC
- movl %edx, (%esp) # push parameter C
-0:
- shl $$4, %ecx
- movl $$gDvmInlineOpsTable, %eax # %eax<- address for table of inline operations
- call *(%eax, %ecx) # call function
-
- cmp $$0, %eax # check boolean result of inline
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- lea 24(%esp), %esp # update stack pointer
- je common_exceptionThrown # handle exception
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_EXECUTE_INLINE_RANGE.S b/vm/mterp/x86-atom/OP_EXECUTE_INLINE_RANGE.S
deleted file mode 100644
index cd5a048..0000000
--- a/vm/mterp/x86-atom/OP_EXECUTE_INLINE_RANGE.S
+++ /dev/null
@@ -1,75 +0,0 @@
- /* Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * File: OP_EXECUTE_INLINE_RANGE.S
- *
- * Code: Executes a "native inline" instruction. Uses no substitutions.
- *
- * For: execute-inline
- *
- * Description: Executes a "native inline" instruction. This instruction
- * is generated by the optimizer.
- *
- * Format:
- *
- * Syntax: AA, {vCCCC..v(CCCC+AA-1)}, inline@BBBB
- */
-
- FETCH 1, %ecx # %ecx<- BBBB
- movl rGLUE, %eax # %eax<- MterpGlue pointer
- addl $$offGlue_retval, %eax # %eax<- &glue->retval
- EXPORT_PC
- movl %eax, -8(%esp) # push parameter glue->retval
- lea -24(%esp), %esp
- jmp .L${opcode}_continue
-%break
-
- /*
- * Extract args, call function.
- * rINST = #of args (0-4)
- * %ecx = call index
- */
-
-.L${opcode}_continue:
- FETCH 2, %edx # %edx<- FEDC
- cmp $$1, rINST # determine number of arguments
- jl 0f # handle zero args
- je 1f # handle one arg
- cmp $$3, rINST
- jl 2f # handle two args
- je 3f # handle three args
-4:
- movl 12(rFP, %edx, 4), rINST # rINST<- vF
- movl rINST, 12(%esp) # push parameter vF
-3:
- movl 8(rFP, %edx, 4), rINST # rINST<- vE
- movl rINST, 8(%esp) # push parameter E
-2:
- movl 4(rFP, %edx, 4), rINST # rINST<- vD
- movl rINST, 4(%esp) # push parameter D
-1:
- movl (rFP, %edx, 4), %edx # rINST<- vC
- movl %edx, (%esp) # push parameter C
-0:
- shl $$4, %ecx
- movl $$gDvmInlineOpsTable, %eax # %eax<- address for table of inline operations
- call *(%eax, %ecx) # call function
-
- cmp $$0, %eax # check boolean result of inline
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- lea 24(%esp), %esp # update stack pointer
- je common_exceptionThrown # handle exception
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY.S b/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY.S
deleted file mode 100644
index f804f3e..0000000
--- a/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY.S
+++ /dev/null
@@ -1,173 +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.
- */
-
- /*
- * File: OP_FILLED_NEW_ARRAY.S
- *
- * Code: Constructs and fills an array with the given data. Provides
- *
- * For: float-to-int
- *
- * Description: Construct an array of the given type and size,
- * filling it with the supplied contents. The type
- * must be an array type. The array's contents
- * must be single-word. The constructed instance
- * is stored as a result in the same way that the
- * method invocation instructions store their results,
- * so the constructed instance must be moved to a
- * register with a subsequent move-result-object
- * instruction.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc) (range)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, vtaboff@CCCC
- * [B=4] op {vD, vE, vF, vG}, vtaboff@CCCC
- * [B=3] op {vD, vE, vF}, vtaboff@CCCC
- * [B=2] op {vD, vE}, vtaboff@CCCC
- * [B=1] op {vD}, vtaboff@CCCC
- *
- * op {vCCCC .. vNNNN}, meth@BBBB
- * op {vCCCC .. vNNNN}, type@BBBB
- */
-
-%default { "isrange":"0" }
-
- movl rGLUE, %edx # %edx<- MterpGlue pointer
- movl offGlue_methodClassDex(%edx), %edx # %edx<- glue->methodClassDex
- movl offDvmDex_pResClasses(%edx), %edx # %edx<- glue->methodClassDex->pResClasses
- FETCH 1, %ecx # %ecx<- BBBB
- EXPORT_PC
- movl (%edx, %ecx, 4), %eax # %eax<- possibly resolved class
- cmp $$0, %eax # %eax<- check if already resolved
- jne .L${opcode}_continue
- jmp .L${opcode}_break
-%break
-
-.L${opcode}_break:
- movl $$0, -8(%esp) # push parameter false
- movl %ecx, -12(%esp) # push parameter BBBB
- movl rGLUE, %edx # %edx<- MterpGlue pointer
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, -16(%esp) # push parameter glue->method->clazz
- lea -16(%esp), %esp
- call dvmResolveClass # call: (const ClassObject* referrer, u4 classIdx,
- # bool fromUnverifiedConstant)
- # return: ClassObject*
- lea 16(%esp), %esp
- cmp $$0, %eax # check for null return
- je common_exceptionThrown # handle exception
-
- /*
- * On entry:
- * %eax holds array class
- * rINST holds BA or AA
- */
-
-.L${opcode}_continue:
- movl offClassObject_descriptor(%eax), %eax # %eax<- arrayClass->descriptor
- movzbl 1(%eax), %eax # %eax<- descriptor[1]
- cmpb $$'I', %al # check if array of ints
- je 1f
- cmpb $$'L', %al
- je 1f
- cmpb $$'[', %al
- jne .L${opcode}_notimpl # jump to not implemented
-1:
- movl %eax, sReg0 # save type
- movl rINST, -12(%esp) # push parameter length
- movl %eax, -16(%esp) # push parameter descriptor[1]
- movl $$ALLOC_DONT_TRACK, -8(%esp) # push parameter to allocate flags
- .if (!$isrange)
- shrl $$4, -12(%esp) # parameter length is B
- .endif
- lea -16(%esp), %esp
- call dvmAllocPrimitiveArray # call: (char type, size_t length, int allocFlags)
- # return: ArrayObject*
- lea 16(%esp), %esp
- cmp $$0, %eax # check for null return
- je common_exceptionThrown # handle exception
-
- FETCH 2, %edx # %edx<- FEDC or CCCC
- movl rGLUE, %ecx # %ecx<- MterpGlue pointer
- movl %eax, offGlue_retval(%ecx) # retval<- new array
- lea offArrayObject_contents(%eax), %eax # %eax<- newArray->contents
- subl $$1, -12(%esp) # length--; check for negative
- js 2f # if length was zero, finish
-
- /*
- * copy values from registers into the array
- * %eax=array, %edx=CCCC/FEDC, -12(%esp)=length (from AA or B), rINST=AA/BA
- */
-
- .if $isrange
- lea (rFP, %edx, 4), %ecx # %ecx<- &fpp[CCCC]
-1:
- movl (%ecx), %edx # %edx<- %ecx++
- lea 4(%ecx), %ecx # %ecx++
- movl %edx, (%eax) # *contents<- vX
- lea 4(%eax), %eax # %eax++; contents++
- subl $$1, -12(%esp) # length--
- jns 1b # or continue at 2
- .else
- cmp $$4, -12(%esp) # check length
- jne 1f # has four args
- and $$15, rINST # rINST<- A
- GET_VREG rINST # rINST<- vA
- subl $$1, -12(%esp) # count--
- movl rINST, 16(%eax) # contents[4]<- vA
-1:
- movl %edx, %ecx # %ecx<- %edx; ecx for temp
- andl $$15, %ecx # %ecx<- G/F/E/D
- GET_VREG %ecx # %ecx<- vG/vF/vE/vD
- shr $$4, %edx # %edx<- put next reg in low 4
- subl $$1, -12(%esp) # count--
- movl %ecx, (%eax) # *contents<- vX
- lea 4(%eax), %eax # %eax++; contents++
- jns 1b # or continue at 2
- .endif
-2:
- cmpb $$'I', sReg0 # check for int array
- je 3f
- movl rGLUE, %ecx # %ecx<- MterpGlue pointer
- movl offGlue_retval(%ecx), %eax # Object head
- movl offGlue_cardTable(%ecx), %ecx # card table base
- shrl $$GC_CARD_SHIFT, %eax # convert to card num
- movb %cl,(%ecx, %eax) # mark card based on object head
-3:
- FINISH 3 # jump to next instruction
-
- /*
- * Throw an exception to indicate this mode of filled-new-array
- * has not been implemented.
- */
-
-.L${opcode}_notimpl:
- movl $$.LstrInternalError, -8(%esp)
- movl $$.LstrFilledNewArrayNotImpl, -4(%esp)
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor,
- # const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown
-
-.if (!$isrange) # define in one or the other, not both
-.LstrFilledNewArrayNotImpl:
-.asciz "filled-new-array only implemented for 'int'"
-.LstrInternalError:
-.asciz "Ljava/lang/InternalError;"
-.endif
diff --git a/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY_RANGE.S b/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY_RANGE.S
deleted file mode 100644
index fd8b0c5..0000000
--- a/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY_RANGE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_FILLED_NEW_ARRAY_RANGE.S
- */
-
-%include "x86-atom/OP_FILLED_NEW_ARRAY.S" { "isrange":"1" }
diff --git a/vm/mterp/x86-atom/OP_FILL_ARRAY_DATA.S b/vm/mterp/x86-atom/OP_FILL_ARRAY_DATA.S
deleted file mode 100644
index de808d9..0000000
--- a/vm/mterp/x86-atom/OP_FILL_ARRAY_DATA.S
+++ /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.
- */
-
- /*
- * File: OP_FILL_ARRAY_DATA.S
- *
- * Code: Fills an array with given data. Uses no substitutions.
- *
- * For: fill-array-data
- *
- * Description: Fill the given array with the idicated data. The reference
- * must be an array of primitives, and the data table must
- * match it in type and size
- *
- * Format: AA|op BBBBlo BBBBhi (31t)
- *
- * Syntax: op vAA, +BBBBBBBB
- */
-
- FETCH 1, %ecx # %ecx<- BBBBlo
- FETCH 2, %edx # %edx<- BBBBhi
- shl $$16, %edx # prepare to create +BBBBBBBB
- or %ecx, %edx # %edx<- +BBBBBBBB
- lea (rPC, %edx, 2), %edx # %edx<- PC + +BBBBBBBB; array data location
- EXPORT_PC
- push %edx
- push (rFP, rINST, 4)
- call dvmInterpHandleFillArrayData # call: (ArrayObject* arrayObject, const u2* arrayData)
- # return: bool
- FFETCH_ADV 3, %edx # %edx<- next instruction hi; fetch, advance
- cmp $$0, %eax
- lea 8(%esp), %esp
- je common_exceptionThrown
- FGETOP_JMP 3, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_FLOAT_TO_DOUBLE.S b/vm/mterp/x86-atom/OP_FLOAT_TO_DOUBLE.S
deleted file mode 100644
index 91866a4..0000000
--- a/vm/mterp/x86-atom/OP_FLOAT_TO_DOUBLE.S
+++ /dev/null
@@ -1,36 +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.
- */
-
- /*
- * File: OP_FLOAT_TO_DOUBLE.S
- *
- * Code: Converts a float to a double. Uses no substitutions.
- *
- * For: float-to-double
- *
- * Description: Convert the float in source register to a double
- * and store the result in the destintation register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, rINST # rINST<- B
- and $$15, %edx # %edx<- A
- flds (rFP, rINST, 4) # load float
- fstpl (rFP, %edx, 4) # store double
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_FLOAT_TO_INT.S b/vm/mterp/x86-atom/OP_FLOAT_TO_INT.S
deleted file mode 100644
index 615f187..0000000
--- a/vm/mterp/x86-atom/OP_FLOAT_TO_INT.S
+++ /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.
- */
-
- /*
- * File: OP_FLOAT_TO_INT.S
- *
- * Code: Converts a float to a int. Uses no substitutions.
- *
- * For: float-to-int
- *
- * Description: Convert the float in source register to a int
- * and store the result in the destintation register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, rINST # rINST<- B
- and $$15, %edx # %edx<- A
- flds (rFP, rINST, 4) # push vB to floating point stack
- fildl .LintMax # push max int value
- fildl .LintMin # push min int value
- fucomip %st(2), %st(0) # check for negInf
- jae .L${opcode}_negInf # handle negInf
- fucomip %st(1), %st(0) # check for posInf or NaN
- jc .L${opcode}_nanInf # handle posInf or NaN
- jmp .L${opcode}_break # do conversion
-%break
-
-.L${opcode}_break:
- fnstcw -2(%esp) # save control word
- orl $$0xc00, -2(%esp) # reset control
- fldcw -2(%esp) # load control word
- xorl $$0xc00, -2(%esp) # reset control
- fistpl (rFP, %edx, 4) # move converted int
- fldcw -2(%esp) # load saved control word
- FINISH 1 # jump to next instruction
-
-.L${opcode}_nanInf:
- jnp .L${opcode}_posInf # handle posInf
- fstps (rFP, %edx, 4) # pop floating point stack
- movl $$0x00000000, (rFP, %edx, 4) # vA<- NaN
- FINISH 1 # jump to next instruction
-
-.L${opcode}_posInf:
- fstps (rFP, %edx, 4) # pop floating point stack
- movl $$0x7FFFFFFF, (rFP, %edx, 4) # vA<- posInf
- FINISH 1 # jump to next instruction
-
-.L${opcode}_negInf:
- fstps (rFP, %edx, 4) # pop floating point stack
- fstps (rFP, %edx, 4) # pop floating point stack
- movl $$0x80000000, (rFP, %edx, 4) # vA<- negInf
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_FLOAT_TO_LONG.S b/vm/mterp/x86-atom/OP_FLOAT_TO_LONG.S
deleted file mode 100644
index 9a50b78..0000000
--- a/vm/mterp/x86-atom/OP_FLOAT_TO_LONG.S
+++ /dev/null
@@ -1,71 +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.
- */
-
- /*
- * File: OP_FLOAT_TO_LONG.S
- *
- * Code: Converts a float to a long. Uses no substitutions.
- *
- * For: float-to-long
- *
- * Description: Convert the float in source register to a long
- * and store the result in the destintation register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, rINST # rINST<- B
- and $$15, %edx # %edx<- A
- flds (rFP, rINST, 4) # push vB to floating point stack
- fildll .LvaluePosInfLong # push max int value
- fildll .LvalueNegInfLong # push min int value
- fucomip %st(2), %st(0) # check for negInf
- jae .L${opcode}_negInf # handle negInf
- fucomip %st(1), %st(0) # check for posInf or NaN
- jc .L${opcode}_nanInf # handle posInf or NaN
- jmp .L${opcode}_break # do conversion
-%break
-
-.L${opcode}_break:
- fnstcw -2(%esp) # save control word
- orl $$0xc00, -2(%esp) # update control
- fldcw -2(%esp) # load control word
- xorl $$0xc00, -2(%esp) # reset control
- fistpll (rFP, %edx, 4) # move converted int
- fldcw -2(%esp) # load saved control word
- FINISH 1 # jump to next instruction
-
-.L${opcode}_nanInf:
- jnp .L${opcode}_posInf
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvalueNanLong, %xmm0 # %xmm0<- NaN
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; NaN
- FINISH 1 # jump to next instruction
-
-.L${opcode}_posInf:
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvaluePosInfLong, %xmm0 # %xmm0<- posInf
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; posInf
- FINISH 1 # jump to next instruction
-
-.L${opcode}_negInf:
- fstpl (rFP, %edx, 4) # move converted int
- movq .LvalueNegInfLong, %xmm0 # %xmm0<- negInf
- fstpl (rFP, %edx, 4) # move converted int
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; negInf
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_GOTO.S b/vm/mterp/x86-atom/OP_GOTO.S
deleted file mode 100644
index 7bd9956..0000000
--- a/vm/mterp/x86-atom/OP_GOTO.S
+++ /dev/null
@@ -1,36 +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.
- */
-
- /*
- * File: OP_GOTO.S
- *
- * Code: Do an unconditional branch. Uses no substitutions.
- *
- * For: goto
- *
- * Description: Performs an unconditionally jump to the indicated instruction.
- * The branch uses an 8-bit offset that cannot be zero.
- *
- * Format: AA|op (10t)
- *
- * Syntax: op +AA
- */
-
-LOP_GOTO.S:
-
- movsbl rINSTbl, %edx # %edx<- +AA
- shl $$1, %edx # %edx is shifted for byte offset
- js common_periodicChecks_backwardBranch # do check on backwards branch
- FINISH_RB %edx, %ecx # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_GOTO_16.S b/vm/mterp/x86-atom/OP_GOTO_16.S
deleted file mode 100644
index 931d215..0000000
--- a/vm/mterp/x86-atom/OP_GOTO_16.S
+++ /dev/null
@@ -1,34 +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.
- */
-
- /*
- * File: OP_GOTO_16.S
- *
- * Code: Do an unconditional branch. Uses no substitutions.
- *
- * For: goto/16
- *
- * Description: Performs an unconditionally jump to the indicated instruction.
- * The branch uses a 16-bit offset that cannot be zero.
- *
- * Format: ØØ|op AAAA (20t)
- *
- * Syntax: op +AAAA
- */
-
- FETCHs 1, %edx # %edx<- ssssAAAA (sign-extended)
- shl $$1, %edx # %edx is doubled to get the byte offset
- js common_periodicChecks_backwardBranch # do check on backwards branch
- FINISH_RB %edx, %ecx # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_GOTO_32.S b/vm/mterp/x86-atom/OP_GOTO_32.S
deleted file mode 100644
index d00c3a4..0000000
--- a/vm/mterp/x86-atom/OP_GOTO_32.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_GOTO_32.S
- *
- * Code: Do an unconditional branch. Uses no substitutions.
- *
- * For: goto/32
- *
- * Description: Performs an unconditionally jump to the indicated instruction.
- * The branch uses a 32-bit offset that can be zero.
- *
- * Format: ØØ|op AAAAlo AAAAhi (30t)
- *
- * Syntax: op +AAAAAAAA
- */
-
- FETCH 1, %edx # %edx<- AAAAlo
- FETCH 2, %ecx # %ecx<- AAAAhi
- shl $$16, %ecx # prepare to create +AAAAAAAA
- or %ecx, %edx # %edx<- +AAAAAAAA
- shl $$1, %edx # %edx is doubled to get the byte offset
- jle common_periodicChecks_backwardBranch # do check on backwards branch
- FINISH_RB %edx, %ecx # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_IF_EQ.S b/vm/mterp/x86-atom/OP_IF_EQ.S
deleted file mode 100644
index 61781a0..0000000
--- a/vm/mterp/x86-atom/OP_IF_EQ.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_EQ.S
- */
-
-%include "x86-atom/bincmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/x86-atom/OP_IF_EQZ.S b/vm/mterp/x86-atom/OP_IF_EQZ.S
deleted file mode 100644
index 2f7c140..0000000
--- a/vm/mterp/x86-atom/OP_IF_EQZ.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_EQZ.S
- */
-
-%include "x86-atom/zcmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/x86-atom/OP_IF_GE.S b/vm/mterp/x86-atom/OP_IF_GE.S
deleted file mode 100644
index e90a1e5..0000000
--- a/vm/mterp/x86-atom/OP_IF_GE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_GE.S
- */
-
-%include "x86-atom/bincmp.S" { "revcmp":"l" }
diff --git a/vm/mterp/x86-atom/OP_IF_GEZ.S b/vm/mterp/x86-atom/OP_IF_GEZ.S
deleted file mode 100644
index 8ee71a8..0000000
--- a/vm/mterp/x86-atom/OP_IF_GEZ.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_GEZ.S
- */
-
-%include "x86-atom/zcmp.S" { "revcmp":"l" }
diff --git a/vm/mterp/x86-atom/OP_IF_GT.S b/vm/mterp/x86-atom/OP_IF_GT.S
deleted file mode 100644
index 7f19db9..0000000
--- a/vm/mterp/x86-atom/OP_IF_GT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_GT.S
- */
-
-%include "x86-atom/bincmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/x86-atom/OP_IF_GTZ.S b/vm/mterp/x86-atom/OP_IF_GTZ.S
deleted file mode 100644
index 3f8039f..0000000
--- a/vm/mterp/x86-atom/OP_IF_GTZ.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_GTZ.S
- */
-
-%include "x86-atom/zcmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/x86-atom/OP_IF_LE.S b/vm/mterp/x86-atom/OP_IF_LE.S
deleted file mode 100644
index 287bd0d..0000000
--- a/vm/mterp/x86-atom/OP_IF_LE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_LE.S
- */
-
-%include "x86-atom/bincmp.S" { "revcmp":"g" }
diff --git a/vm/mterp/x86-atom/OP_IF_LEZ.S b/vm/mterp/x86-atom/OP_IF_LEZ.S
deleted file mode 100644
index b7d31d1..0000000
--- a/vm/mterp/x86-atom/OP_IF_LEZ.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_LEZ.S
- */
-
-%include "x86-atom/zcmp.S" { "revcmp":"g" }
diff --git a/vm/mterp/x86-atom/OP_IF_LT.S b/vm/mterp/x86-atom/OP_IF_LT.S
deleted file mode 100644
index 7e58e18..0000000
--- a/vm/mterp/x86-atom/OP_IF_LT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_LT.S
- */
-
-%include "x86-atom/bincmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/x86-atom/OP_IF_LTZ.S b/vm/mterp/x86-atom/OP_IF_LTZ.S
deleted file mode 100644
index 0a3e56b..0000000
--- a/vm/mterp/x86-atom/OP_IF_LTZ.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_LTZ.S
- */
-
-%include "x86-atom/zcmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/x86-atom/OP_IF_NE.S b/vm/mterp/x86-atom/OP_IF_NE.S
deleted file mode 100644
index 929bd05..0000000
--- a/vm/mterp/x86-atom/OP_IF_NE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_NE.S
- */
-
-%include "x86-atom/bincmp.S" { "revcmp":"e" }
diff --git a/vm/mterp/x86-atom/OP_IF_NEZ.S b/vm/mterp/x86-atom/OP_IF_NEZ.S
deleted file mode 100644
index 07f2c87..0000000
--- a/vm/mterp/x86-atom/OP_IF_NEZ.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IF_NEZ.S
- */
-
-%include "x86-atom/zcmp.S" { "revcmp":"e" }
diff --git a/vm/mterp/x86-atom/OP_IGET.S b/vm/mterp/x86-atom/OP_IGET.S
deleted file mode 100644
index e3a72f7..0000000
--- a/vm/mterp/x86-atom/OP_IGET.S
+++ /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.
- */
-
- /*
- * File: OP_IGET.S
- *
- * Code: Generic 32-bit instance field "get" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iget's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iget-boolean, iget-byte, iget-char, iget-object, iget
- * iget-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-%default { "mov":"l" }
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $$0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .L${opcode}_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %edx # %edx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- jmp .L${opcode}_finish
-%break
-
-.L${opcode}_finish:
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- cmp $$0, %eax # check if resolved
- lea 8(%esp), %esp
- je common_exceptionThrown # not resolved; handle exception
-
- /*
- * %eax holds resolved field
- */
-
-.L${opcode}_finish2:
- movl rINST, %ecx # %ecx<- BA
- shr $$4, %ecx # %ecx<- B
- and $$15, rINST # rINST<- A
-
- GET_VREG %ecx # %ecx<- vB
- cmp $$0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- mov$mov (%ecx, %edx), %edx # %edx<- object field
- SET_VREG %edx, rINST # vA<- %edx; object field
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IGET_BOOLEAN.S b/vm/mterp/x86-atom/OP_IGET_BOOLEAN.S
deleted file mode 100644
index 12100f9..0000000
--- a/vm/mterp/x86-atom/OP_IGET_BOOLEAN.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IGET_BOOLEAN.S
- */
-
-%include "x86-atom/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_BYTE.S b/vm/mterp/x86-atom/OP_IGET_BYTE.S
deleted file mode 100644
index 6d6b870..0000000
--- a/vm/mterp/x86-atom/OP_IGET_BYTE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IGET_BYTE.S
- */
-
-%include "x86-atom/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_CHAR.S b/vm/mterp/x86-atom/OP_IGET_CHAR.S
deleted file mode 100644
index 8f285d7..0000000
--- a/vm/mterp/x86-atom/OP_IGET_CHAR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IGET_CHAR.S
- */
-
-%include "x86-atom/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_OBJECT.S b/vm/mterp/x86-atom/OP_IGET_OBJECT.S
deleted file mode 100644
index 369e1b9..0000000
--- a/vm/mterp/x86-atom/OP_IGET_OBJECT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IGET_OBJECT.S
- */
-
-%include "x86-atom/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_OBJECT_QUICK.S b/vm/mterp/x86-atom/OP_IGET_OBJECT_QUICK.S
deleted file mode 100644
index 36b7f0e..0000000
--- a/vm/mterp/x86-atom/OP_IGET_OBJECT_QUICK.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IGET_OBJECT_QUICK.S
- */
-
-%include "x86-atom/OP_IGET_QUICK.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_OBJECT_VOLATILE.S b/vm/mterp/x86-atom/OP_IGET_OBJECT_VOLATILE.S
deleted file mode 100644
index 5de2fa3..0000000
--- a/vm/mterp/x86-atom/OP_IGET_OBJECT_VOLATILE.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_QUICK.S b/vm/mterp/x86-atom/OP_IGET_QUICK.S
deleted file mode 100644
index 8ec86ec..0000000
--- a/vm/mterp/x86-atom/OP_IGET_QUICK.S
+++ /dev/null
@@ -1,38 +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.
- */
-
- /*
- * File: OP_IGET_QUICK.S
- *
- * Code: Optimization for iget
- *
- * For: iget-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- shr $$4, %eax # %eax<- B
- and $$15, rINST # rINST<- A
- GET_VREG %eax # %eax<- vB; object to operate on
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- cmp $$0, %eax # check if object is null
- je common_errNullObject # handle null object
- FFETCH_ADV 2, %edx # %eax<- next instruction hi; fetch, advance
- movl (%ecx, %eax), %eax # %eax<- object field
- SET_VREG %eax, rINST # fp[A]<- %eax
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IGET_SHORT.S b/vm/mterp/x86-atom/OP_IGET_SHORT.S
deleted file mode 100644
index 968b815..0000000
--- a/vm/mterp/x86-atom/OP_IGET_SHORT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IGET_SHORT.S
- */
-
-%include "x86-atom/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_VOLATILE.S b/vm/mterp/x86-atom/OP_IGET_VOLATILE.S
deleted file mode 100644
index 5de2fa3..0000000
--- a/vm/mterp/x86-atom/OP_IGET_VOLATILE.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_WIDE.S b/vm/mterp/x86-atom/OP_IGET_WIDE.S
deleted file mode 100644
index 370b0b0..0000000
--- a/vm/mterp/x86-atom/OP_IGET_WIDE.S
+++ /dev/null
@@ -1,74 +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.
- */
-
- /*
- * File: OP_IGET_WIDE.S
- *
- * Code: 64 bit instance field "get" operation. Uses no substitutions.
- *
- * For: iget-wide
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
- movl rGLUE, %eax # %eax<- MterpGlue pointer
- movl offGlue_methodClassDex(%eax), %ecx # %ecx<- pDvmDex
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- CCCC
- FETCH 1, %edx # %edx<- pDvmDex->pResFields
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved InstField ptr
- cmp $$0, %ecx # check for null ptr; resolved InstField ptr
- jne .L${opcode}_finish
- movl offGlue_method(%eax), %ecx # %ecx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%ecx), %ecx # %ecx<- method->clazz
- movl %ecx, -8(%esp) # push parameter CCCC; field ref
- movl %edx, -4(%esp) # push parameter method->clazz
- jmp .L${opcode}_finish2
-%break
-
-.L${opcode}_finish2:
- lea -8(%esp), %esp
- call dvmResolveInstField # resolve InstField ptr
- # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- cmp $$0, %eax # check if resolved
- lea 8(%esp), %esp
- movl %eax, %ecx # %ecx<- %eax; %ecx expected to hold field
- je common_exceptionThrown
-
- /*
- * %ecx holds resolved field
- */
-
-.L${opcode}_finish:
-
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- andl $$15, rINST # rINST<- A
- GET_VREG %edx # %edx<- vB
- cmp $$0, %edx # check for null object
- je common_errNullObject
- movl offInstField_byteOffset(%ecx), %ecx # %ecx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (%ecx, %edx), %xmm0 # %xmm0<- object field
- movq %xmm0, (rFP, rINST, 4) # vA<- %xmm0; object field
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IGET_WIDE_QUICK.S b/vm/mterp/x86-atom/OP_IGET_WIDE_QUICK.S
deleted file mode 100644
index 08a57f6..0000000
--- a/vm/mterp/x86-atom/OP_IGET_WIDE_QUICK.S
+++ /dev/null
@@ -1,38 +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.
- */
-
- /*
- * File: OP_IGET_WIDE_QUICK.S
- *
- * Code: Optimization for iget
- *
- * For: iget/wide-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- andl $$15, rINST # rINST<- A
- GET_VREG %edx # %edx<- vB; object to operate on
- cmp $$0, %edx # check if object is null
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- je common_errNullObject # handle null object
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- movq (%ecx, %edx), %xmm0 # %xmm0<- object field
- movq %xmm0, (rFP, rINST, 4) # fp[A]<- %xmm0
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_INSTANCE_OF.S b/vm/mterp/x86-atom/OP_INSTANCE_OF.S
deleted file mode 100644
index 4dde31c..0000000
--- a/vm/mterp/x86-atom/OP_INSTANCE_OF.S
+++ /dev/null
@@ -1,121 +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.
- */
-
- /*
- * File: OP_INSTANCE_OF.S
- *
- * Code: Checks if object is instance of a class. Uses no substitutions.
- *
- * For: instance-of
- *
- * Description: Store in the given destination register 1 if the indicated
- * reference is an instance of the given type, or 0 if not.
- * The type must be a reference type (not a primitive type).
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- GET_VREG %edx # %edx<- vB
- cmp $$0, %edx # check for null object
- je .L${opcode}_store # null object
- jmp .L${opcode}_break
-%break
-
-.L${opcode}_break:
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- CCCC
- movl offDvmDex_pResClasses(%ecx), %ecx # %ecx<- pDvmDex->pResClasses
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved class
- movl offObject_clazz(%edx), %edx # %edx<- obj->clazz
- cmp $$0, %ecx # check if already resovled
- je .L${opcode}_resolve # not resolved before, so resolve now
-
-.L${opcode}_resolved:
- cmp %ecx, %edx # check if same class
- je .L${opcode}_trivial # yes, finish
- jmp .L${opcode}_fullcheck # no, do full check
-
- /*
- * The trivial test failed, we need to perform a full check.
- * %edx holds obj->clazz
- * %ecx holds class resolved from BBBB
- */
-
-.L${opcode}_fullcheck:
- movl %edx, -8(%esp) # push parameter obj->clazz
- movl %ecx, -4(%esp) # push parameter resolved class
- lea -8(%esp), %esp
- call dvmInstanceofNonTrivial # perform full check
- # call: (ClassObject* instance, ClassObject* clazz)
- # return: int
- andl $$15, rINST # rINST<- A
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- lea 8(%esp), %esp
- SET_VREG %eax, rINST # vA<- r0
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
-
- /*
- * %edx holds boolean result
- */
-
-.L${opcode}_store:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- andl $$15, rINST # rINST<- A
- SET_VREG %edx, rINST # vA<- r0
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
- /*
- * Trivial test succeeded, save and bail.
- */
-
-.L${opcode}_trivial:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- andl $$15, rINST # rINST<- A
- SET_VREG $$1, rINST # vA<- r0
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-
- /*
- * Resolution required. This is the least-likely path.
- * %eax holds BBBB
- */
-
-.L${opcode}_resolve:
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- EXPORT_PC
- movl offGlue_method(%ecx), %ecx # %ecx<- glue->method
- movl offMethod_clazz(%ecx), %ecx # %ecx<- glue->method->clazz
- movl %ecx, -12(%esp) # push parameter glue->method->clazz
- movl %eax, -8(%esp) # push parameter CCCC; type index
- movl $$1, -4(%esp) # push parameter true
- lea -12(%esp), %esp
- call dvmResolveClass # call: (const ClassObject* referrer, u4 classIdx,
- # bool fromUnverifiedConstant)
- # return: ClassObject*
- lea 12(%esp), %esp
- cmp $$0, %eax # check for null
- je common_exceptionThrown # handle exception
- movl rINST, %edx # %edx<- BA+
- shr $$4, %edx # %edx<- B
- movl %eax, %ecx # need class in %ecx
- GET_VREG %edx # %edx<- vB
- movl offObject_clazz(%edx), %edx # %edx<- obj->clazz
- jmp .L${opcode}_resolved # clazz resolved, continue
diff --git a/vm/mterp/x86-atom/OP_INT_TO_BYTE.S b/vm/mterp/x86-atom/OP_INT_TO_BYTE.S
deleted file mode 100644
index 27cafe9..0000000
--- a/vm/mterp/x86-atom/OP_INT_TO_BYTE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_INT_TO_BYTE.S
- */
-
-%include "x86-atom/unop.S" { "preinstr":"sal $24, %ecx", "instr":"sar $24, %ecx" }
diff --git a/vm/mterp/x86-atom/OP_INT_TO_CHAR.S b/vm/mterp/x86-atom/OP_INT_TO_CHAR.S
deleted file mode 100644
index a28602d..0000000
--- a/vm/mterp/x86-atom/OP_INT_TO_CHAR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_INT_TO_CHAR.S
- */
-
-%include "x86-atom/unop.S" {"preinstr":"sal $16, %ecx", "instr":"shr $16, %ecx" }
diff --git a/vm/mterp/x86-atom/OP_INT_TO_DOUBLE.S b/vm/mterp/x86-atom/OP_INT_TO_DOUBLE.S
deleted file mode 100644
index cd16eea..0000000
--- a/vm/mterp/x86-atom/OP_INT_TO_DOUBLE.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_INT_TO_DOUBLE.S
- *
- * Code: Convert an int to a double. Uses no substitutions.
- *
- * For: int-to-double
- *
- * Description: Converts an int in the source register, to a double, and
- * stores the result in the destination register. vA<- (double) vB
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %eax # %eax<- BA+
- shr $$4, %eax # %eax<- B
- andl $$15, rINST # rINST<- A
- cvtsi2sd (rFP, %eax, 4), %xmm0 # %xmm0<- vB
- movq %xmm0, (rFP, rINST, 4) # vA<- %xmm0; (double) vB
- FFETCH_ADV 1, %edx # %edx<- next instruction hi; fetch, advance
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_INT_TO_FLOAT.S b/vm/mterp/x86-atom/OP_INT_TO_FLOAT.S
deleted file mode 100644
index 52ce729..0000000
--- a/vm/mterp/x86-atom/OP_INT_TO_FLOAT.S
+++ /dev/null
@@ -1,36 +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.
- */
-
- /*
- * File: OP_INT_TO_FLOAT.S
- *
- * Code: Convert an int to a float. Uses no substitutions.
- *
- * For: int-to-float
- *
- * Description: Convert an int in the source register, to a float, and
- * stores the result in the destintation register. vA<- (float) vB
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %eax # %eax<- BA+
- shr $$4, %eax # %eax<- B
- andl $$15, rINST # rINST<- A
- cvtsi2ss (rFP,%eax,4), %xmm0 # %xmm0<- vB
- movss %xmm0, (rFP, rINST, 4) # vA<- %xmm0
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_INT_TO_LONG.S b/vm/mterp/x86-atom/OP_INT_TO_LONG.S
deleted file mode 100644
index 1bc125b..0000000
--- a/vm/mterp/x86-atom/OP_INT_TO_LONG.S
+++ /dev/null
@@ -1,40 +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.
- */
-
- /*
- * File: OP_INT_TO_LONG.S
- *
- * Code: Convert an int to a long. Uses no substitutions.
- *
- * For:
- *
- * Description: Convert an int in the source register, to a long, and
- * stores the result in the destintation register. vA<- (long) vB
- *
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %eax # %eax<- BA+
- movl rINST, %ecx # %ecx<- BA+
- shr $$4, %eax # %eax<- B
- andl $$15, %ecx # %ecx<- A
- GET_VREG %eax # %eax<- vB
- cdq # %edx:%eax<- sign-extend of %eax
- movl %eax, (rFP, %ecx, 4) # vA<- lo part
- movl %edx, 4(rFP, %ecx, 4) # vA+1<- hi part
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_INT_TO_SHORT.S b/vm/mterp/x86-atom/OP_INT_TO_SHORT.S
deleted file mode 100644
index f2b0b87..0000000
--- a/vm/mterp/x86-atom/OP_INT_TO_SHORT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_INT_TO_SHORT.S
- */
-
-%include "x86-atom/unop.S" { "preinstr":"sal $16, %ecx", "instr":"sar $16, %ecx" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_DIRECT.S b/vm/mterp/x86-atom/OP_INVOKE_DIRECT.S
deleted file mode 100644
index 78b6c06..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_DIRECT.S
+++ /dev/null
@@ -1,92 +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.
- */
-
- /*
- * File: OP_INVOKE_DIRECT.S
- *
- * Code: Call a non-static direct method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_direct that allows up to 255 arguments.
- *
- * For: invoke-direct, invoke-direct/range
- *
- * Description: invoke-direct is used to invoke a non-static direct method;
- * an instance method that is non-overridable, for example,
- * either a private instance method or a constructor.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-%default { "isrange":"0", "routine":"NoRange" }
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- method index
- movl offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
- FETCH 2, %edx # %edx<- GFED or CCCC
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved method to call
- .if (!$isrange)
- andl $$15, %edx # %edx<- D if not range
- .endif
- EXPORT_PC # must export for invoke
- movl %edx, -4(%esp) # save "this" pointer register
- cmp $$0, %ecx # check if already resolved
- GET_VREG %edx # %edx<- "this" pointer
- je .L${opcode}_resolve # handle resolve
-
-.L${opcode}_finish:
- cmp $$0, %edx # check for null "this"
- jne common_invokeMethod${routine} # invoke method common code
- jmp common_errNullObject
-%break
-
- /*
- * %eax = reference (BBBB or CCCC)
- * -4(%esp) = "this" register
- */
-
-.L${opcode}_resolve:
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl $$METHOD_DIRECT, -8(%esp) # push parameter method type
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl %eax, -12(%esp) # push parameter reference
- lea -16(%esp), %esp
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, (%esp) # push parameter clazz
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 16(%esp), %esp
- cmp $$0, %eax # check for null method return
- movl -4(%esp), %edx # get "this" pointer register
- GET_VREG %edx # get "this" pointer
- je common_exceptionThrown # null pointer; handle exception
- cmp $$0, %edx # check for null "this"
- movl %eax, %ecx # %ecx<- method
- jne common_invokeMethod${routine} # invoke method common code
- jmp common_errNullObject # handle null object
diff --git a/vm/mterp/x86-atom/OP_INVOKE_DIRECT_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_DIRECT_RANGE.S
deleted file mode 100644
index 3ad26e1..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_DIRECT_RANGE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_INVOKE_DIRECT_RANGE.S
- */
-
-%include "x86-atom/OP_INVOKE_DIRECT.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_INTERFACE.S b/vm/mterp/x86-atom/OP_INVOKE_INTERFACE.S
deleted file mode 100644
index cbd7b31..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_INTERFACE.S
+++ /dev/null
@@ -1,76 +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.
- */
-
- /*
- * File: OP_INVOKE_INTERFACE.S
- *
- * Code: Call at method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_interface that allows up to 255 arguments.
- *
- * For: invoke-interface, invoke-interface-range
- *
- * Description: invoke-interface is used to invoke an interface method; on an
- * object whose concrete class isn't known, using a method_id that
- * refers to an interface.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-%default { "isrange":"0", "routine":"NoRange" }
-
- FETCH 2, %edx # %edx<- GFED or CCCC
- FETCH 1, %ecx # %ecx<- method index
- movl %ecx, -12(%esp) # push argument method index
- .if (!$isrange)
- and $$15, %edx # %edx<- D if not range
- .endif
- EXPORT_PC # must export for invoke
- GET_VREG %edx # %edx<- first arg "this pointer"
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_methodClassDex(%eax), %eax # %eax<- glue->pDvmDex
- movl %eax, -4(%esp) # push parameter class
- cmp $$0, %edx # check for null object
- je common_errNullObject # handle null object
- jmp .L${opcode}_break
-%break
-.L${opcode}_break:
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_method(%ecx), %ecx # %ecx<- glue->method
- movl %ecx, -8(%esp) # push parameter method
- movl offObject_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, -16(%esp) # push parameter
- lea -16(%esp), %esp
- call dvmFindInterfaceMethodInCache # call: (ClassObject* thisClass, u4 methodIdx,
- # const Method* method, DvmDex* methodClassDex)
- # return: Method*
- lea 16(%esp), %esp
- cmp $$0, %eax # check if find failed
- je common_exceptionThrown # handle exception
- movl %eax, %ecx # %ecx<- method
- jmp common_invokeMethod${routine} # invoke method common code
diff --git a/vm/mterp/x86-atom/OP_INVOKE_INTERFACE_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_INTERFACE_RANGE.S
deleted file mode 100644
index b323ba0..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_INTERFACE_RANGE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_INVOKE_INTERFACE_RANGE.S
- */
-
-%include "x86-atom/OP_INVOKE_INTERFACE.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_OBJECT_INIT_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_OBJECT_INIT_RANGE.S
deleted file mode 100644
index 2459a3c..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_OBJECT_INIT_RANGE.S
+++ /dev/null
@@ -1,29 +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.
- */
-
- /*
- * File: OP_INVOKE_OBJECT_INIT.S
- *
- * Code: TODO
- *
- * For: invoke-object-init
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- */
-
-<<<<<<< HEAD:vm/mterp/x86-atom/OP_INVOKE_OBJECT_INIT_RANGE.S
-=======
- FINISH 3
->>>>>>> 10185db0:vm/mterp/x86-atom/OP_INVOKE_DIRECT_EMPTY.S
diff --git a/vm/mterp/x86-atom/OP_INVOKE_STATIC.S b/vm/mterp/x86-atom/OP_INVOKE_STATIC.S
deleted file mode 100644
index 30b6d8c..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_STATIC.S
+++ /dev/null
@@ -1,70 +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.
- */
-
- /*
- * File: OP_INVOKE_STATIC.S
- *
- * Code: Call static direct method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_static that allows up to 255 arguments.
- *
- * For: invoke-static, invoke-static/range
- *
- * Description: invoke-static is used to invoke static direct method.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-%default { "routine":"NoRange" }
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %edx<- pDvmDex
- FETCH 1, %eax # %eax<- method index
- movl offDvmDex_pResMethods(%ecx), %ecx # %edx<- pDvmDex->pResMethods
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved method to call
- cmp $$0, %ecx # check if already resolved
- EXPORT_PC # must export for invoke
- jne common_invokeMethod${routine} # invoke method common code
- jmp .L${opcode}_break
-%break
-
-.L${opcode}_break:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- movl $$METHOD_STATIC, -4(%esp) # resolver method type
- movl %eax, -8(%esp) # push parameter method index
- movl offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
- movl %edx, -12(%esp) # push parameter method
- lea -12(%esp), %esp
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 12(%esp), %esp
- cmp $$0, %eax # check for null method
- je common_exceptionThrown
- movl %eax, %ecx # %ecx<- method
- jmp common_invokeMethod${routine} # invoke method common code
diff --git a/vm/mterp/x86-atom/OP_INVOKE_STATIC_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_STATIC_RANGE.S
deleted file mode 100644
index ce39e13..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_STATIC_RANGE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_INVOKE_STATIC_RANGE.S
- */
-
-%include "x86-atom/OP_INVOKE_STATIC.S" { "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER.S
deleted file mode 100644
index 539bea1..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_SUPER.S
+++ /dev/null
@@ -1,105 +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.
- */
-
- /*
- * File: OP_INVOKE_SUPER.S
- *
- * Code: Call super method.
- *
- * For: invoke-super, invoke-super/range
- *
- * Description: invoke-super is used to invoke the closest superclass's virtual
- * method (as opposed to the one with the same method_id in the
- * calling class).
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-%default { "isrange":"0", "routine":"NoRange" }
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- FETCH 2, %eax # %eax<- GFED or CCCC
- movl offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
- .if (!$isrange)
- and $$15, %eax # %eax<- D if not range
- .endif
- FETCH 1, %edx # %edx<- method index
- movl offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
- cmp $$0, (rFP, %eax, 4) # check for null object
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved base method
- je common_errNullObject # handle null object
- jmp .L${opcode}_continue2
-%break
-
-.L${opcode}_continue2:
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_method(%eax), %eax # %eax<- glue->method
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- EXPORT_PC # must export for invoke
- cmp $$0, %ecx # check if already resolved
- jne .L${opcode}_continue
- jmp .L${opcode}_resolve # handle resolve
-
- /*
- * %ecx = resolved base method
- * %eax = method->clazz
- */
-
-.L${opcode}_continue:
- movl offClassObject_super(%eax), %edx # %edx<- glue->method->clazz->super
- movzwl offMethod_methodIndex(%ecx), %ecx # %ecx<- baseMethod->methodIndex
- cmp offClassObject_vtableCount(%edx), %ecx # compare vtableCount with methodIndex
- EXPORT_PC # must export for invoke
- jnc .L${opcode}_nsm # handle method not present
- movl offClassObject_vtable(%edx), %edx # %edx<- glue->method->clazz->super->vtable
- movl (%edx, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
- jmp common_invokeMethod${routine} # invoke method common code
-
-.L${opcode}_resolve:
- movl %eax, -12(%esp) # push parameter clazz
- movl %edx, -8(%esp) # push parameter method index
- movl $$METHOD_VIRTUAL, -4(%esp) # push parameter method type
- lea -12(%esp), %esp
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 12(%esp), %esp
- movl %eax, %ecx # %ecx<- method
- cmp $$0, %ecx # check for null method return
- movl -12(%esp), %eax # %eax<- glue->method->clazz
- jne .L${opcode}_continue
- jmp common_exceptionThrown # null pointer; handle exception
-
- /*
- * Throw a NoSuchMethodError with the method name as the message.
- * %ecx = resolved base method
- */
-
-.L${opcode}_nsm:
- movl offMethod_name(%ecx), %edx # %edx<- method name
- jmp common_errNoSuchMethod
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK.S
deleted file mode 100644
index 55c7e94..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK.S
+++ /dev/null
@@ -1,40 +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.
- */
-
- /*
- * File: OP_INVOKE_SUPER_QUICK.S
- *
- * Code: Optimization for invoke-super and invoke-super/range
- *
- * For: invoke-super/quick, invoke-super/quick-range
- */
-
-%default { "isrange":"0", "routine":"NoRange" }
-
- FETCH 2, %edx # %edx<- GFED or CCCC
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_method(%ecx), %eax # %eax<- glue->method
- .if (!$isrange)
- and $$15, %edx # %edx<- D if not range
- .endif
- FETCH 1, %ecx # %ecx<- method index
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- movl offClassObject_super(%eax), %eax # %eax<- glue->method->clazz->super
- EXPORT_PC # must export for invoke
- movl offClassObject_vtable(%eax), %eax # %edx<- glue->method->clazz->super->vtable
- cmp $$0, (rFP, %edx, 4) # check for null object
- movl (%eax, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
- je common_errNullObject # handle null object
- jmp common_invokeMethod${routine} # invoke method common code
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK_RANGE.S
deleted file mode 100644
index 9e9f311..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK_RANGE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_INVOKE_SUPER_QUICK_RANGE.S
- */
-
-%include "x86-atom/OP_INVOKE_SUPER_QUICK.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER_RANGE.S
deleted file mode 100644
index 6e77c02..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_SUPER_RANGE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_INVOKE_SUPER_RANGE.S
- */
-
-%include "x86-atom/OP_INVOKE_SUPER.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL.S
deleted file mode 100644
index 46c9265..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL.S
+++ /dev/null
@@ -1,93 +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.
- */
-
- /*
- * File: OP_INVOKE_VIRTUAL.S
- *
- * Code: Call a virtual method. Provides an "isrange" variable and
- * a "routine" variable to specify this is the "range" version of
- * invoke_direct that allows up to 255 arguments.
- *
- * For: invoke-virtual, invoke-virtual/range
- *
- * Description: invoke-virtual is used to invoke a normal virtual method;
- * a method that is not static or final, and is not a constructor.
- *
- * Format: B|A|op CCCC G|F|E|D (35c)
- * AA|op BBBB CCCC (3rc)
- *
- * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
- * [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
- * [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
- * [B=3] op {vD, vE, vF}, kind@CCCC (35c)
- * [B=2] op {vD, vE}, kind@CCCC (35c)
- * [B=1] op {vD}, kind@CCCC (35c)
- * [B=0] op {}, kind@CCCC (35c)
- *
- * op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
- * op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
- * and C determines the first register)
- */
-
-%default { "isrange":"0", "routine":"NoRange" }
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- EXPORT_PC # must export pc for invoke
- movl offGlue_methodClassDex(%eax), %eax # %eax<- pDvmDex
- FETCH 1, %ecx # %ecx<- method index
- movl offDvmDex_pResMethods(%eax), %eax # %eax<- pDvmDex->pResMethods
- FETCH 2, %edx # %edx<- GFED or CCCC
- .if (!$isrange)
- and $$15, %edx # %edx<- D if not range
- .endif
- cmp $$0, (%eax, %ecx, 4) # check if already resolved
- je .L${opcode}_break
- movl (%eax, %ecx, 4), %eax # %eax<- resolved base method
- jmp .L${opcode}_continue
-%break
-
-.L${opcode}_break:
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl %edx, -4(%esp) # save "this" pointer register
- movl offGlue_method(%eax), %eax # %eax<- glue->method
- movl $$METHOD_VIRTUAL, -8(%esp) # push parameter method type
- movl %ecx, -12(%esp) # push paramter method index
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- lea -16(%esp), %esp
- movl %eax, (%esp) # push parameter clazz
- call dvmResolveMethod # call: (const ClassObject* referrer,
- # u4 methodIdx, MethodType methodType)
- # return: Method*
- lea 16(%esp), %esp
- cmp $$0, %eax # check for null method return
- movl -4(%esp), %edx # get "this" pointer register
- jne .L${opcode}_continue
- jmp common_exceptionThrown # null pointer; handle exception
-
- /*
- * At this point:
- * %eax = resolved base method
- * %edx = D or CCCC (index of first arg, which is the "this" ptr)
- */
-
-.L${opcode}_continue:
- GET_VREG %edx # %edx<- "this" ptr
- movzwl offMethod_methodIndex(%eax), %eax # %eax<- baseMethod->methodIndex
- cmp $$0, %edx # %edx<- check for null "this"
- je common_errNullObject # handle null object
- movl offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
- movl offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
- movl (%edx, %eax, 4), %ecx # %ecx<- vtable[methodIndex]
- jmp common_invokeMethod${routine} # invoke method common code
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK.S
deleted file mode 100644
index 16a4e40..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK.S
+++ /dev/null
@@ -1,38 +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.
- */
-
- /*
- * File: OP_INVOKE_VIRTUAL_QUICK.S
- *
- * Code: Optimization for invoke-virtual and invoke-virtual/range
- *
- * For: invoke-virtual/quick, invoke-virtual/quick-range
- */
-
-%default { "isrange":"0", "routine":"NoRange" }
-
- FETCH 2, %edx # %edx<- GFED or CCCC
- .if (!$isrange)
- and $$15, %edx # %edx<- D if not range
- .endif
- FETCH 1, %ecx # %ecx<- method index
- GET_VREG %edx # %edx<- "this" ptr
- cmp $$0, %edx # %edx<- check for null "this"
- EXPORT_PC # must export pc for invoke
- je common_errNullObject
- movl offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
- movl offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
- movl (%edx, %ecx, 4), %ecx # %ecx<- vtable[methodIndex]
- jmp common_invokeMethod${routine} # invoke method common code
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK_RANGE.S
deleted file mode 100644
index 888bcc0..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK_RANGE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_INVOKE_VIRTUAL_QUICK_RANGE.S
- */
-
-%include "x86-atom/OP_INVOKE_VIRTUAL_QUICK.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_RANGE.S
deleted file mode 100644
index d548a22..0000000
--- a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_RANGE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_INVOKE_VIRTUAL_RANGE.S
- */
-
-%include "x86-atom/OP_INVOKE_VIRTUAL.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_IPUT.S b/vm/mterp/x86-atom/OP_IPUT.S
deleted file mode 100644
index 4c029be..0000000
--- a/vm/mterp/x86-atom/OP_IPUT.S
+++ /dev/null
@@ -1,76 +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.
- */
-
- /*
- * File: OP_IPUT.S
- *
- * Code: Generic 32-bit instance field "put" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iput's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iput-boolean, iput-byte, iput-char, iput-object, iput
- * iput-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
-%default { "mov":"l" }
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $$0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .L${opcode}_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- jmp .L${opcode}_finish
-%break
-
-.L${opcode}_finish:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- lea -8(%esp), %esp
- movl %edx, (%esp) # push parameter method->clazz
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- lea 8(%esp), %esp
- cmp $$0, %eax # check if resolved
- jne .L${opcode}_finish2
- jmp common_exceptionThrown # not resolved; handle exception
-
-.L${opcode}_finish2:
- movl rINST, %ecx # %ecx<- BA+
- shr $$4, %ecx # %ecx<- B
- and $$15, rINST # rINST<- A
- GET_VREG %ecx # %ecx<- vB
- cmp $$0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vA
- mov$mov rINST, (%edx, %ecx) # object field<- vA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IPUT_BOOLEAN.S b/vm/mterp/x86-atom/OP_IPUT_BOOLEAN.S
deleted file mode 100644
index 46c2932..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_BOOLEAN.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IPUT_BOOLEAN.S
- */
-
-%include "x86-atom/OP_IPUT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_BYTE.S b/vm/mterp/x86-atom/OP_IPUT_BYTE.S
deleted file mode 100644
index d23f492..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_BYTE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IPUT_BYTE.S
- */
-
-%include "x86-atom/OP_IPUT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_CHAR.S b/vm/mterp/x86-atom/OP_IPUT_CHAR.S
deleted file mode 100644
index d645fae..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_CHAR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IPUT_CHAR.S
- */
-
-%include "x86-atom/OP_IPUT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_OBJECT.S b/vm/mterp/x86-atom/OP_IPUT_OBJECT.S
deleted file mode 100644
index 302cf44..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_OBJECT.S
+++ /dev/null
@@ -1,81 +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.
- */
-
- /*
- * File: OP_IPUT.S
- *
- * Code: Generic 32-bit instance field "put" operation. Provides a
- * "mov" variable which determines the type of mov performed.
- * Currently, none of the iput's use this variable - may want
- * to change this, but seems ok for now.
- *
- * For: iput-boolean, iput-byte, iput-char, iput-object, iput
- * iput-short
- *
- * Description: Perform the object instance field "get" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- movl offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
- cmp $$0, (%edx, %ecx, 4) # check for null ptr; resolved InstField ptr
- movl (%edx, %ecx, 4), %eax # %eax<- resolved InstField ptr
- jne .L${opcode}_finish2
- movl rGLUE, %edx # %edx<- pMterpGlue
- jmp .L${opcode}_finish
-%break
-
-.L${opcode}_finish:
- movl offGlue_method(%edx), %edx # %edx<- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %ecx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- lea -8(%esp), %esp
- movl %edx, (%esp) # push parameter method->clazz
- call dvmResolveInstField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: InstField*
- lea 8(%esp), %esp
- cmp $$0, %eax # check if resolved
- jne .L${opcode}_finish2
- jmp common_exceptionThrown # not resolved; handle exception
-
-.L${opcode}_finish2:
- movl rINST, %ecx # %ecx<- BA+
- shr $$4, %ecx # %ecx<- B
- and $$15, rINST # rINST<- A
- GET_VREG %ecx # %ecx<- vB
- cmp $$0, %ecx # check for null object
- je common_errNullObject # handle null object
- movl offInstField_byteOffset(%eax), %edx # %edx<- field offset
- GET_VREG rINST # rINST<- vA
- movl rINST, (%edx, %ecx) # object field<- vA
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- movl rGLUE, %eax # get glue
- movl offGlue_cardTable(%eax), %eax # get card table base
- testl rINST, rINST # test if we stored a null value
- je 1f # skip card mark if null stored
- shrl $$GC_CARD_SHIFT, %ecx # set obeject head to card number
- movb %al, (%eax, %ecx)
-1:
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IPUT_OBJECT_QUICK.S b/vm/mterp/x86-atom/OP_IPUT_OBJECT_QUICK.S
deleted file mode 100644
index eee88e9..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_OBJECT_QUICK.S
+++ /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.
- */
-
- /*
- * File: OP_IPUT_QUICK.S
- * Code: Optimization for iput
- *
- * For: iput-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- shr $$4, %eax # %eax<- B
- and $$15, rINST # rINST<- A
- GET_VREG %eax # %eax<- vB; object to operate on
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- cmp $$0, %eax # check if object is null
- je common_errNullObject # handle null object
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vA
- movl rINST, (%eax, %ecx) # object field<- vA
- testl rINST, rINST # did we write a null object
- je 1f
- movl rGLUE, %ecx # get glue
- movl offGlue_cardTable(%ecx), %ecx # get card table base
- shrl $$GC_CARD_SHIFT, %eax # get gc card index
- movb %cl, (%eax, %ecx) # mark gc card in table
-1:
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IPUT_OBJECT_VOLATILE.S b/vm/mterp/x86-atom/OP_IPUT_OBJECT_VOLATILE.S
deleted file mode 100644
index 4b024d0..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_OBJECT_VOLATILE.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/OP_IPUT_OBJECT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_QUICK.S b/vm/mterp/x86-atom/OP_IPUT_QUICK.S
deleted file mode 100644
index 572291e..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_QUICK.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_IPUT_QUICK.S
- * Code: Optimization for iput
- *
- * For: iput-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- shr $$4, %eax # %eax<- B
- and $$15, rINST # rINST<- A
- GET_VREG %eax # %eax<- vB; object to operate on
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- cmp $$0, %eax # check if object is null
- je common_errNullObject # handle null object
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vA
- movl rINST, (%eax, %ecx) # object field<- vA
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IPUT_SHORT.S b/vm/mterp/x86-atom/OP_IPUT_SHORT.S
deleted file mode 100644
index 9836283..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_SHORT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_IPUT_SHORT.S
- */
-
-%include "x86-atom/OP_IPUT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_VOLATILE.S b/vm/mterp/x86-atom/OP_IPUT_VOLATILE.S
deleted file mode 100644
index 475a0c5..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_VOLATILE.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/OP_IPUT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_WIDE.S b/vm/mterp/x86-atom/OP_IPUT_WIDE.S
deleted file mode 100644
index 1686219..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_WIDE.S
+++ /dev/null
@@ -1,74 +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.
- */
-
- /*
- * File: OP_IPUT_WIDE.S
- *
- * Code: 64 bit instance field "put" operation. Uses no substitutions.
- *
- * For: iget-wide
- *
- * Description: Perform the object instance field "put" operation
- * with the identified field; load the instance value into
- * the value register.
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
- movl rGLUE, %eax # %eax<- MterpGlue pointer
- movl offGlue_methodClassDex(%eax), %ecx # %ecx<- pDvmDex
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- CCCC
- FETCH 1, %edx # %edx<- pDvmDex->pResFields
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved InstField ptr
- cmp $$0, %ecx # check for null ptr; resolved InstField ptr
- jne .L${opcode}_finish
- movl offGlue_method(%eax), %ecx # %ecx <- current method
- EXPORT_PC # in case an exception is thrown
- movl offMethod_clazz(%ecx), %ecx # %ecx<- method->clazz
- movl %ecx, -8(%esp) # push parameter CCCC; field ref
- movl %edx, -4(%esp) # push parameter method->clazz
- jmp .L${opcode}_finish2
-%break
-
-.L${opcode}_finish2:
- lea -8(%esp), %esp
- call dvmResolveInstField # resolve InstField ptr
- cmp $$0, %eax # check if resolved
- lea 8(%esp), %esp
- movl %eax, %ecx # %ecx<- %eax; %ecx expected to hold field
- jne .L${opcode}_finish
- jmp common_exceptionThrown
-
- /*
- * Currently:
- * %ecx holds resolved field
- * %edx does not hold object yet
- */
-
-.L${opcode}_finish:
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- andl $$15, rINST # rINST<- A
- GET_VREG %edx # %edx<- vB
- cmp $$0, %edx # check for null object
- je common_errNullObject
- movl offInstField_byteOffset(%ecx), %ecx # %ecx<- field offset
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vA
- movq %xmm0, (%ecx, %edx) # object field<- %xmm0; vA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IPUT_WIDE_QUICK.S b/vm/mterp/x86-atom/OP_IPUT_WIDE_QUICK.S
deleted file mode 100644
index 5880231..0000000
--- a/vm/mterp/x86-atom/OP_IPUT_WIDE_QUICK.S
+++ /dev/null
@@ -1,38 +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.
- */
-
- /*
- * File: OP_IPUT_WIDE_QUICK.S
- *
- * Code: Optimization for iput
- *
- * For: iput/wide-quick
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, offset@CCCC
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- andl $$15, rINST # rINST<- A
- GET_VREG %edx # %edx<- vB; object to operate on
- cmp $$0, %edx # check if object is null
- FETCH 1, %ecx # %ecx<- CCCC; field byte offset
- je common_errNullObject # handle null object
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- fp[A]
- movq %xmm0, (%edx, %ecx) # object field<- %xmm0; fp[A]
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_LONG_TO_DOUBLE.S b/vm/mterp/x86-atom/OP_LONG_TO_DOUBLE.S
deleted file mode 100644
index 5705e25..0000000
--- a/vm/mterp/x86-atom/OP_LONG_TO_DOUBLE.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_LONG_TO_DOUBLE.S
- *
- * Code: Convert a long to a dobule. Uses no substitutions.
- *
- * For: long-to-double
- *
- * Description: Converts a long in the source register to a double, and
- * stores the result in the destination register. vA<- (double) vB
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA+
- shr $$4, rINST # rINST<- B
- and $$15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- fildll (rFP, rINST, 4) # FPU<- vB
- fstpl (rFP, %ecx, 4) # vA<- FPU; (double) vB
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_LONG_TO_FLOAT.S b/vm/mterp/x86-atom/OP_LONG_TO_FLOAT.S
deleted file mode 100644
index 1bb8779..0000000
--- a/vm/mterp/x86-atom/OP_LONG_TO_FLOAT.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_LONG_TO_FLOAT.S
- *
- * Code: Convert a long to a float. Uses no substitutions.
- *
- * For: int-to-float
- *
- * Description: Converts a float in the source register, to a float, and
- * stores the result in the destination register. vA<- (double) vB
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA+
- shr $$4, rINST # rINST<- B
- and $$15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- fildll (rFP, rINST, 4) # FPU<- vB
- fstps (rFP, %ecx, 4) # vA<- FPU; (float) vB
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_LONG_TO_INT.S b/vm/mterp/x86-atom/OP_LONG_TO_INT.S
deleted file mode 100644
index 0984bc0..0000000
--- a/vm/mterp/x86-atom/OP_LONG_TO_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_LONG_TO_INT.S
- */
-
-%include "x86-atom/OP_MOVE.S"
diff --git a/vm/mterp/x86-atom/OP_MONITOR_ENTER.S b/vm/mterp/x86-atom/OP_MONITOR_ENTER.S
deleted file mode 100644
index 39d0e7b..0000000
--- a/vm/mterp/x86-atom/OP_MONITOR_ENTER.S
+++ /dev/null
@@ -1,49 +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.
- */
-
- /*
- * File: OP_MONITOR_ENTER.S
- *
- * Code: Aquire a monitor
- *
- * For: monitor-enter
- *
- * Description: Aquire a monitor for the indicated object.
- *
- *
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- GET_VREG rINST # rINST<- vAA
- cmp $$0, rINST # check for null object
- movl offGlue_self(%eax), %eax # %eax<- glue->self
- EXPORT_PC # need for precise GC
- je common_errNullObject # handle null object
-# jmp .L${opcode}_finish
-#%break
-#.L${opcode}_finish:
- movl rINST, -4(%esp) # push parameter reference
- movl %eax, -8(%esp) # push parameter
- lea -8(%esp), %esp
- call dvmLockObject # call: (struct Thread* self,
- # struct Object* obj)
- # return: void
- FFETCH_ADV 1, %edx # %edx<- next instruction hi; fetch, advance
- lea 8(%esp), %esp
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MONITOR_EXIT.S b/vm/mterp/x86-atom/OP_MONITOR_EXIT.S
deleted file mode 100644
index 37738d5..0000000
--- a/vm/mterp/x86-atom/OP_MONITOR_EXIT.S
+++ /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.
- */
-
- /*
- * File: OP_MONITOR_EXIT.S
- *
- * Code: Release a monitor
- *
- * For: monitor-exit
- *
- * Description: Release a monitor for the indicated object. If this instruction needs
- * to throw an execption, it must do so as if the pc has already
- * advanced pased the instruction.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- EXPORT_PC # export the pc
- GET_VREG rINST # rINST<- vAA
- cmp $$0, rINST # rINST<- check for null object
- je common_errNullObject # handle null object
- push rINST # push parameter object
- push offGlue_self(%eax) # push parameter self
- call dvmUnlockObject # call: (struct Thread* self,
- # struct Object* obj)
- # return: bool
- FINISH_FETCH_ADVANCE 1, %edx # advance pc before exception
- cmp $$0, %eax # check for success
- lea 8(%esp), %esp
- je common_exceptionThrown # handle exception
- FINISH_JMP %edx # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_MOVE.S b/vm/mterp/x86-atom/OP_MOVE.S
deleted file mode 100644
index 9982ced..0000000
--- a/vm/mterp/x86-atom/OP_MOVE.S
+++ /dev/null
@@ -1,38 +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.
- */
-
- /*
- * File: OP_MOVE.S
- *
- * Code: Copies contents from one register to another. Uses no
- * substitutions.
- *
- * For: move, move-object, long-to-int
- *
- * Description: Copies contents from one non-object register to another.
- * vA<- vB; fp[A]<- fp[B]
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $$4, rINST # rINST<- B
- and $$15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vB
- SET_VREG rINST, %ecx # vA<- vB; %edx
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_16.S b/vm/mterp/x86-atom/OP_MOVE_16.S
deleted file mode 100644
index 013a11b..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_16.S
+++ /dev/null
@@ -1,36 +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.
- */
-
- /*
- * File: OP_MOVE_16.S
- *
- * Code: Copies contents from one register to another
- *
- * For: move/16, move-object/16
- *
- * Description: Copies contents from one non-object register to another.
- * fp[A]<- fp[B]
- *
- * Format: ØØ|op AAAA BBBB (32x)
- *
- * Syntax: op vAAAA, vBBBB
- */
-
- FETCH 2, %edx # %edx<- BBBB
- FETCH 1, %ecx # %ecx<- AAAA
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- SET_VREG %edx, %ecx # vA<- vB; %edx
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_EXCEPTION.S b/vm/mterp/x86-atom/OP_MOVE_EXCEPTION.S
deleted file mode 100644
index 76e700d..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_EXCEPTION.S
+++ /dev/null
@@ -1,38 +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.
- */
-
- /*
- * File: OP_MOVE_EXCEPTION.S
- *
- * Code: Moves an exception to a register
- *
- * For: move-exception
- *
- * Description: Save a just-caught exception into the given register. This
- * instruction is only valid as the first instruction of an
- * exception handler.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_self(%eax), %ecx # %ecx<- glue->self
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- movl offThread_exception(%ecx), %edx # %edx<- glue->self->exception
- movl $$0, offThread_exception(%ecx) # clear exception
- SET_VREG %edx, rINST # vAA<- glue->self->exception
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_FROM16.S b/vm/mterp/x86-atom/OP_MOVE_FROM16.S
deleted file mode 100644
index 55a6e96..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_FROM16.S
+++ /dev/null
@@ -1,35 +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.
- */
-
- /*
- * File: OP_MOVE_FROM16.S
- *
- * Code: Copies contents from one register to another
- *
- * For: move/from16, move-object/from16
- *
- * Description: Copies contents from one non-object register to another.
- * vA<- vB; fp[A]<- fp[B]
- *
- * Format: AA|op BBBB (22x)
- *
- * Syntax: op vAA, vBBBB
- */
-
- FETCH 1, %edx # %edx<- BBBB
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- SET_VREG %edx, rINST # vA<- vB; %edx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_OBJECT.S b/vm/mterp/x86-atom/OP_MOVE_OBJECT.S
deleted file mode 100644
index 1cd22cb..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_OBJECT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MOVE_OBJECT.S
- */
-
-%include "x86-atom/OP_MOVE.S"
diff --git a/vm/mterp/x86-atom/OP_MOVE_OBJECT_16.S b/vm/mterp/x86-atom/OP_MOVE_OBJECT_16.S
deleted file mode 100644
index a61162c..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_OBJECT_16.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MOVE_OBJECT_16.S
- */
-
-%include "x86-atom/OP_MOVE_16.S"
diff --git a/vm/mterp/x86-atom/OP_MOVE_OBJECT_FROM16.S b/vm/mterp/x86-atom/OP_MOVE_OBJECT_FROM16.S
deleted file mode 100644
index bfca7da..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_OBJECT_FROM16.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MOVE_OBJECT_FROM16.S
- */
-
-%include "x86-atom/OP_MOVE_FROM16.S"
diff --git a/vm/mterp/x86-atom/OP_MOVE_RESULT.S b/vm/mterp/x86-atom/OP_MOVE_RESULT.S
deleted file mode 100644
index 1d13bf5..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_RESULT.S
+++ /dev/null
@@ -1,38 +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.
- */
-
- /*
- * File: OP_MOVE_RESULT.S
- *
- * Code: Copies a return value to a register
- *
- * For: move-result, move-result-object
- *
- * Description: Move the single-word non-object result of the most
- * recent method invocation into the indicated register. This
- * must be done as the instruction immediately after a
- * method invocation whose (single-word, non-object) result
- * is not to be ignored; anywhere else is invalid.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- FFETCH_ADV 1, %ecx # %ecx<- next instruction hi; fetch, advance
- movl offGlue_retval(%eax), %edx # %edx<- glue->retval
- SET_VREG %edx, rINST # vA<- glue->retval
- FGETOP_JMP 1, %ecx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_RESULT_OBJECT.S b/vm/mterp/x86-atom/OP_MOVE_RESULT_OBJECT.S
deleted file mode 100644
index 6d1fa75..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_RESULT_OBJECT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MOVE_RESULT_OBJECT.S
- */
-
-%include "x86-atom/OP_MOVE_RESULT.S"
diff --git a/vm/mterp/x86-atom/OP_MOVE_RESULT_WIDE.S b/vm/mterp/x86-atom/OP_MOVE_RESULT_WIDE.S
deleted file mode 100644
index 8f15264..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_RESULT_WIDE.S
+++ /dev/null
@@ -1,38 +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.
- */
-
- /*
- * File: OP_MOVE_RESULT_WIDE.S
- *
- * Code: Copies a return value to a register
- *
- * For: move-result-wide
- *
- * Description: Move the double-word non-object result of the most
- * recent method invocation into the indicated register. This
- * must be done as the instruction immediately after a
- * method invocation whose (single-word, non-object) result
- * is not to be ignored; anywhere else is invalid.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- movq offGlue_retval(%eax), %xmm0 # %xmm0<- glue->retval
- movq %xmm0, (rFP, rINST, 4) # vA<- glue->retval
- FFETCH_ADV 1, %edx # %edx<- next instruction hi; fetch, advance
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_WIDE.S b/vm/mterp/x86-atom/OP_MOVE_WIDE.S
deleted file mode 100644
index 909243b..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_WIDE.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_MOVE_WIDE.S
- *
- * Code: Copies contents from one register to another. Uses no
- * substitutions.
- *
- * For: move-wide
- *
- * Description: Copies contents from one non-object register to another.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA+
- shr $$4, %edx # %edx<- B
- and $$15, rINST # rINST<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq %xmm0, (rFP, rINST, 4) # vA<- vB
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_WIDE_16.S b/vm/mterp/x86-atom/OP_MOVE_WIDE_16.S
deleted file mode 100644
index af266fe..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_WIDE_16.S
+++ /dev/null
@@ -1,36 +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.
- */
-
- /*
- * File: OP_MOVE_WIDE_16.S
- *
- * Code: Copies contents from one register to another. Uses no
- * substitutions.
- *
- * For: move-wide/16
- *
- * Description: Copies contents from one non-object register to another.
- *
- * Format: ØØ|op AAAA BBBB (32x)
- *
- * Syntax: op vAAAA, vBBBB
- */
-
- FETCH 2, %edx # %edx<- BBBB
- FETCH 1, %ecx # %ecx<- AAAA
- FFETCH_ADV 3, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq %xmm0, (rFP, %ecx, 4) # vA<- vB; %xmm0
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_WIDE_FROM16.S b/vm/mterp/x86-atom/OP_MOVE_WIDE_FROM16.S
deleted file mode 100644
index 4056b34..0000000
--- a/vm/mterp/x86-atom/OP_MOVE_WIDE_FROM16.S
+++ /dev/null
@@ -1,34 +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.
- */
-
- /*
- * File: OP_MOVE_WIDE_FROM16.S
- *
- * Code: Copies contents from one register to another
- *
- * For: move-wide/from16
- *
- * Description: Copies contents from one non-object register to another.
- *
- * Format: AA|op BBBB (22x)
- *
- * Syntax: op vAA, vBBBB
- */
-
- FETCH 1, %edx # %edx<- BBBB
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq %xmm0, (rFP, rINST, 4) # vA<- vB
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MUL_DOUBLE.S b/vm/mterp/x86-atom/OP_MUL_DOUBLE.S
deleted file mode 100644
index cecbf05..0000000
--- a/vm/mterp/x86-atom/OP_MUL_DOUBLE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MUL_DOUBLE.S
- */
-
-%include "x86-atom/binopWide.S" {"instr":"mulsd %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_MUL_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_MUL_DOUBLE_2ADDR.S
deleted file mode 100644
index adc61d6..0000000
--- a/vm/mterp/x86-atom/OP_MUL_DOUBLE_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MUL_DOUBLE_2ADDR.S
- */
-
-%include "x86-atom/binopWide2addr.S" {"instr":"mulsd %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_MUL_FLOAT.S b/vm/mterp/x86-atom/OP_MUL_FLOAT.S
deleted file mode 100644
index 34eba58..0000000
--- a/vm/mterp/x86-atom/OP_MUL_FLOAT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MUL_FLOAT.S
- */
-
-%include "x86-atom/binopF.S" {"instr":"mulss %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_MUL_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_MUL_FLOAT_2ADDR.S
deleted file mode 100644
index dbd615d..0000000
--- a/vm/mterp/x86-atom/OP_MUL_FLOAT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MUL_FLOAT_2ADDR.S
- */
-
-%include "x86-atom/binopF2addr.S" {"instr":"mulss %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_MUL_INT.S b/vm/mterp/x86-atom/OP_MUL_INT.S
deleted file mode 100644
index 8f5dac5..0000000
--- a/vm/mterp/x86-atom/OP_MUL_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MUL_INT.S
- */
-
-%include "x86-atom/binop.S" {"instr":"imul %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_MUL_INT_2ADDR.S b/vm/mterp/x86-atom/OP_MUL_INT_2ADDR.S
deleted file mode 100644
index b544df7..0000000
--- a/vm/mterp/x86-atom/OP_MUL_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MUL_INT_2ADDR.S
- */
-
-%include "x86-atom/binop2addr.S" {"instr":"imul %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_MUL_INT_LIT16.S b/vm/mterp/x86-atom/OP_MUL_INT_LIT16.S
deleted file mode 100644
index 241531f..0000000
--- a/vm/mterp/x86-atom/OP_MUL_INT_LIT16.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MUL_INT_LIT16.S
- */
-
-%include "x86-atom/binopLit16.S" {"instr":"imul %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_MUL_INT_LIT8.S b/vm/mterp/x86-atom/OP_MUL_INT_LIT8.S
deleted file mode 100644
index efcffe1..0000000
--- a/vm/mterp/x86-atom/OP_MUL_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_MUL_INT_LIT8.S
- */
-
-%include "x86-atom/binopLit8.S" {"instr":"imul %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_MUL_LONG.S b/vm/mterp/x86-atom/OP_MUL_LONG.S
deleted file mode 100644
index 85cccf2..0000000
--- a/vm/mterp/x86-atom/OP_MUL_LONG.S
+++ /dev/null
@@ -1,71 +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.
- */
-
- /*
- * File: OP_MUL_LONG.S
- *
- * Code: 64-bit integer multiply
- *
- * For: mul-long
- *
- * Description: Multiply two source registers and store the
- * result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- /*
- * Signed 64-bit integer multiply.
- *
- * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
- * WX
- * x YZ
- * --------
- * ZW ZX
- * YW YX
- *
- * The low word of the result holds ZX, the high word holds
- * (ZW+YX) + (the high overflow from ZX). YW doesn't matter because
- * it doesn't fit in the low 64 bits.
- */
-
- movl rINST, -4(%esp) # -4(%esp)<- AA+
- FETCH_BB 1, rINST # rINST<- BB
- FETCH_CC 1, %edx # %edx<- CC
- jmp .L${opcode}_finish
-%break
-
- /*
- * X = (rFP, rINST, 4)
- * W = 4(rFP, rINST, 4)
- * Z = (rFP, %edx, 4)
- * Y = 4(rFP, %edx, 4)
- */
-
-.L${opcode}_finish:
- movl 4(rFP, rINST, 4), %ecx # %ecx<- W
- imull (rFP, %edx, 4), %ecx # %ecx<- WxZ
- mov 4(rFP, %edx, 4), %eax # %ecx<- Y
- imull (rFP, rINST, 4), %eax # %eax<- XxY
- addl %eax, %ecx # %ecx<- (WZ + XY)
- movl (rFP, %edx, 4), %eax # %eax<- Z
- mull (rFP, rINST, 4) # %edx:eax<- XZ
- movzbl -4(%esp), rINST # rINST<- AA
- addl %edx, %ecx # %ecx<- carry + (WZ + XY)
- movl %ecx, 4(rFP, rINST, 4) # vAA+1<- results hi
- movl %eax, (rFP, rINST, 4) # vAA<- results lo
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_MUL_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_MUL_LONG_2ADDR.S
deleted file mode 100644
index d6b8c16..0000000
--- a/vm/mterp/x86-atom/OP_MUL_LONG_2ADDR.S
+++ /dev/null
@@ -1,72 +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.
- */
-
- /*
- * File: OP_MUL_LONG_2ADDR.S
- *
- * Code: 64-bit integer multiply
- *
- * For: mul-long/2addr
- *
- * Description: Multiply two sources registers and store the result
- * in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- /*
- * Signed 64-bit integer multiply.
- *
- * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
- * WX
- * x YZ
- * --------
- * ZW ZX
- * YW YX
- *
- * The low word of the result holds ZX, the high word holds
- * (ZW+YX) + (the high overflow from ZX). YW doesn't matter because
- * it doesn't fit in the low 64 bits.
- */
-
- movl rINST, %edx # %edx<- BA+
- shr $$4, rINST # rINST<- B
- andl $$15, %edx # %edx<- A
- movl %edx, sReg0 # sReg0<- A
- jmp .L${opcode}_finish
-%break
-
- /*
- * X = (rFP, rINST, 4)
- * W = 4(rFP, rINST, 4)
- * Z = (rFP, %edx, 4)
- * Y = 4(rFP, %edx, 4)
- */
-
-.L${opcode}_finish:
- movl 4(rFP, rINST, 4), %ecx # %ecx<- W
- imull (rFP, %edx, 4), %ecx # %ecx<- WxZ
- movl 4(rFP, %edx, 4), %eax # %eax<- Y
- imull (rFP, rINST, 4), %eax # %eax<- X*Y
- addl %eax, %ecx # %ecx<- (WZ + XY)
- movl (rFP, %edx, 4), %eax # %eax<- Z
- mull (rFP, rINST, 4) # %edx:eax<- XZ
- addl %edx, %ecx # %ecx<- carry + (WZ + XY)
- movl sReg0, %edx # %edx<- A
- movl %ecx, 4(rFP, %edx, 4) # vA+1<- results hi
- movl %eax, (rFP, %edx, 4) # vA<- results lo
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_NEG_DOUBLE.S b/vm/mterp/x86-atom/OP_NEG_DOUBLE.S
deleted file mode 100644
index b6fb070..0000000
--- a/vm/mterp/x86-atom/OP_NEG_DOUBLE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_NEG_DOUBLE.S
- */
-
-%include "x86-atom/unopWide.S" { "preinstr":"movq .LdoubNeg, %xmm1", "instr":"pxor %xmm1, %xmm0" }
diff --git a/vm/mterp/x86-atom/OP_NEG_FLOAT.S b/vm/mterp/x86-atom/OP_NEG_FLOAT.S
deleted file mode 100644
index 418fc0a..0000000
--- a/vm/mterp/x86-atom/OP_NEG_FLOAT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_NEG_FLOAT.S
- */
-
-%include "x86-atom/unop.S" { "instr":"addl $0x80000000, %ecx" }
diff --git a/vm/mterp/x86-atom/OP_NEG_INT.S b/vm/mterp/x86-atom/OP_NEG_INT.S
deleted file mode 100644
index 68acb89..0000000
--- a/vm/mterp/x86-atom/OP_NEG_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_NEG_INT.S
- */
-
-%include "x86-atom/unop.S" {"instr":"neg %ecx"}
diff --git a/vm/mterp/x86-atom/OP_NEG_LONG.S b/vm/mterp/x86-atom/OP_NEG_LONG.S
deleted file mode 100644
index 3f500bb..0000000
--- a/vm/mterp/x86-atom/OP_NEG_LONG.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_NEG_LONG.S
- */
-
-%include "x86-atom/unopWide.S" {"preinstr":"xorps %xmm1, %xmm1", "instr":"psubq %xmm0, %xmm1", "result":"%xmm1"}
diff --git a/vm/mterp/x86-atom/OP_NEW_ARRAY.S b/vm/mterp/x86-atom/OP_NEW_ARRAY.S
deleted file mode 100644
index a6d5fd3..0000000
--- a/vm/mterp/x86-atom/OP_NEW_ARRAY.S
+++ /dev/null
@@ -1,92 +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.
- */
-
- /*
- * File: OP_NEW_ARRAY.S
- *
- * Code: Create a new array. Uses no substitutions.
- *
- * For: new-array
- *
- * Description: Construct a new array of the indicated type and size.
- * The type must be an array type.
- *
- * Format: B|A|op CCCC (22c)
- *
- * Syntax: op vA, vB, type@CCCC
- * op vA, vB, field@CCCC
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- movl offGlue_methodClassDex(%eax), %eax # %eax<- glue->pDvmDex
- FETCH 1, %ecx # %ecx<- CCCC
- GET_VREG %edx # %edx<- vB
- movl offDvmDex_pResClasses(%eax), %eax # %eax<- glue->pDvmDex->pResClasses
- cmp $$0, %edx # check for negative length
- movl (%eax, %ecx, 4), %eax # %eax<- resolved class
- js common_errNegativeArraySize # handle negative array length
- cmp $$0, %eax # check for null
- EXPORT_PC # required for resolve
- jne .L${opcode}_finish # already resovled so continue
- jmp .L${opcode}_resolve # need to resolve
-%break
-
- /*
- * Resolve class. (This is an uncommon case.)
- *
- * %edx holds array length
- * %ecx holds class ref CCCC
- */
-
-.L${opcode}_resolve:
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_method(%eax), %eax # %eax<- glue->method
- movl %edx, -4(%esp) # save length
- movl $$0, -8(%esp) # push parameter false
- movl %ecx, -12(%esp) # push parameter class ref
- movl offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
- movl %eax, -16(%esp) # push parameter clazz
- lea -16(%esp), %esp
- call dvmResolveClass # call: (const ClassObject* referrer,
- # u4 classIdx, bool fromUnverifiedConstant)
- # return: ClassObject*
- cmp $$0, %eax # check for failure
- lea 16(%esp), %esp
- je common_exceptionThrown # handle exception
- movl -4(%esp), %edx # %edx<- length
-
- /*
- * Finish allocation.
- *
- * %eax holds class
- * %edx holds array length
- */
-
-.L${opcode}_finish:
- movl %eax, -12(%esp) # push parameter class
- movl %edx, -8(%esp) # push parameter length
- movl $$ALLOC_DONT_TRACK, -4(%esp)
- lea -12(%esp), %esp
- call dvmAllocArrayByClass # call: (ClassObject* arrayClass,
- # size_t length, int allocFlags)
- # return: ArrayObject*
- and $$15, rINST # rINST<- A
- cmp $$0, %eax # check for allocation failure
- lea 12(%esp), %esp
- je common_exceptionThrown # handle exception
- SET_VREG %eax, rINST # vA<- pArray
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_NEW_INSTANCE.S b/vm/mterp/x86-atom/OP_NEW_INSTANCE.S
deleted file mode 100644
index d65afb7..0000000
--- a/vm/mterp/x86-atom/OP_NEW_INSTANCE.S
+++ /dev/null
@@ -1,147 +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.
- */
-
- /*
- * File: OP_NEW_INSTANCE.S
- *
- * Code: Create a new instance of a given type. Uses no substitutions.
- *
- * For: new-instance
- *
- * Description: Construct a new instance of the indicated type,
- * storing a reference to it in the destination.
- * The type must refer to a non-array class.
- *
- *
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, type@BBBB
- * op vAA, field@BBBB
- * op vAA, string@BBBB
- */
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_methodClassDex(%ecx), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %edx # %edx<- BBBB
- movl offDvmDex_pResClasses(%ecx), %ecx # %ecx<- glue->pDvmDex->pResClasses
- movl (%ecx, %edx, 4), %edx # %edx<- vB
- EXPORT_PC # required for resolve
- cmp $$0, %edx # check for null
- je .L${opcode}_resolve # need to resolve
-
- /*
- * %edx holds class object
- */
-
-.L${opcode}_resolved:
- movzbl offClassObject_status(%edx), %eax # %eax<- class status
- cmp $$CLASS_INITIALIZED, %eax # check if class is initialized
- jne .L${opcode}_needinit # initialize class
-
- /*
- * %edx holds class object
- */
-
-.L${opcode}_initialized:
- testl $$(ACC_INTERFACE|ACC_ABSTRACT), offClassObject_accessFlags(%edx)
- mov $$ALLOC_DONT_TRACK, %eax # %eax<- flag for alloc call
- je .L${opcode}_finish # continue
- jmp .L${opcode}_abstract # handle abstract or interface
-
- /*
- * %edx holds class object
- * %eax holds flags for alloc call
- */
-
-%break
-.balign 32
-.L${opcode}_finish:
- movl %edx, -8(%esp) # push parameter object
- movl %eax, -4(%esp) # push parameter flags
- lea -8(%esp), %esp
- call dvmAllocObject # call: (ClassObject* clazz, int flags)
- # return: Object*
- cmp $$0, %eax # check for failure
- lea 8(%esp), %esp
- je common_exceptionThrown # handle exception
- SET_VREG %eax, rINST # vAA<- pObject
- FINISH 2 # jump to next instruction
-
- /*
- * Class initialization required.
- *
- * %edx holds class object
- */
-
-.L${opcode}_needinit:
- movl %edx, -4(%esp) # push parameter object
- lea -4(%esp), %esp
- call dvmInitClass # call: (ClassObject* clazz)
- # return: bool
- lea 4(%esp), %esp
- cmp $$0, %eax # check for failure
- movl -4(%esp), %edx # %edx<- object
- je common_exceptionThrown # handle exception
- testl $$(ACC_INTERFACE|ACC_ABSTRACT), offClassObject_accessFlags(%edx)
- mov $$ALLOC_DONT_TRACK, %eax # %eax<- flag for alloc call
- je .L${opcode}_finish # continue
- jmp .L${opcode}_abstract # handle abstract or interface
-
- /*
- * Resolution required. This is the least-likely path.
- *
- * BBBB in %eax
- */
-
-.L${opcode}_resolve:
-
-
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- FETCH 1, %eax # %eax<- BBBB
- movl offGlue_method(%ecx), %ecx # %ecx<- glue->method
- movl offMethod_clazz(%ecx), %ecx # %ecx<- glue->method->clazz
- movl %ecx, -12(%esp) # push parameter clazz
- movl $$0, -4(%esp) # push parameter false
- movl %eax, -8(%esp) # push parameter BBBB
- lea -12(%esp), %esp
- call dvmResolveClass # call: (const ClassObject* referrer,
- # u4 classIdx, bool fromUnverifiedConstant)
- # return: ClassObject*
- lea 12(%esp), %esp
- movl %eax, %edx # %edx<- pObject
- cmp $$0, %edx # check for failure
- jne .L${opcode}_resolved # continue
- jmp common_exceptionThrown # handle exception
-
- /*
- * We can't instantiate an abstract class or interface, so throw an
- * InstantiationError with the class descriptor as the message.
- *
- * %edx holds class object
- */
-
-.L${opcode}_abstract:
- movl offClassObject_descriptor(%edx), %ecx # %ecx<- descriptor
- movl %ecx, -4(%esp) # push parameter descriptor
- movl $$.LstrInstantiationErrorPtr, -8(%esp) # push parameter message
- lea -8(%esp), %esp
- call dvmThrowExceptionWithClassMessage # call: (const char* exceptionDescriptor,
- # const char* messageDescriptor)
- # return: void
- jmp common_exceptionThrown # handle exception
-
-.LstrInstantiationErrorPtr:
-.asciz "Ljava/lang/InstantiationError;"
diff --git a/vm/mterp/x86-atom/OP_NOP.S b/vm/mterp/x86-atom/OP_NOP.S
deleted file mode 100644
index 9911da3..0000000
--- a/vm/mterp/x86-atom/OP_NOP.S
+++ /dev/null
@@ -1,41 +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.
- */
-
- /*
- * File: OP_NOP.S
- *
- * Code: Use a cycle. Uses no substitutions.
- *
- * For: nop
- *
- * Description: No operation. Use a cycle
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- FINISH 1 # jump to next instruction
-
-#ifdef ASSIST_DEBUGGER
-
- /*
- * insert fake function header to help gdb find the stack frame
- */
-
- .type dalvik_inst, %function
-dalvik_inst:
- MTERP_ENTRY
-#endif
diff --git a/vm/mterp/x86-atom/OP_NOT_INT.S b/vm/mterp/x86-atom/OP_NOT_INT.S
deleted file mode 100644
index b82e5b6..0000000
--- a/vm/mterp/x86-atom/OP_NOT_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_NOT_INT.S
- */
-
-%include "x86-atom/unop.S" {"instr":"not %ecx"}
diff --git a/vm/mterp/x86-atom/OP_NOT_LONG.S b/vm/mterp/x86-atom/OP_NOT_LONG.S
deleted file mode 100644
index 98ff80b..0000000
--- a/vm/mterp/x86-atom/OP_NOT_LONG.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_NOT_LONG.S
- */
-
-%include "x86-atom/unopWide.S" {"instr":"pandn 0xFFFFFFFF, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_OR_INT.S b/vm/mterp/x86-atom/OP_OR_INT.S
deleted file mode 100644
index 0ece38c..0000000
--- a/vm/mterp/x86-atom/OP_OR_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_OR_INT.S
- */
-
-%include "x86-atom/binop.S" {"instr":"or %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_OR_INT_2ADDR.S b/vm/mterp/x86-atom/OP_OR_INT_2ADDR.S
deleted file mode 100644
index 693e099..0000000
--- a/vm/mterp/x86-atom/OP_OR_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_OR_INT_2ADDR.S
- */
-
-%include "x86-atom/binop2addr.S" {"instr":"or %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_OR_INT_LIT16.S b/vm/mterp/x86-atom/OP_OR_INT_LIT16.S
deleted file mode 100644
index 5c63867..0000000
--- a/vm/mterp/x86-atom/OP_OR_INT_LIT16.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_OR_INT_LIT16.S
- */
-
-%include "x86-atom/binopLit16.S" {"instr":"or %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_OR_INT_LIT8.S b/vm/mterp/x86-atom/OP_OR_INT_LIT8.S
deleted file mode 100644
index aacd6c3..0000000
--- a/vm/mterp/x86-atom/OP_OR_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_OR_INT_LIT8.S
- */
-
-%include "x86-atom/binopLit8.S" {"instr":"or %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_OR_LONG.S b/vm/mterp/x86-atom/OP_OR_LONG.S
deleted file mode 100644
index f698e54..0000000
--- a/vm/mterp/x86-atom/OP_OR_LONG.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_OR_LONG.S
- */
-
-%include "x86-atom/binopWide.S" {"instr":"por %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_OR_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_OR_LONG_2ADDR.S
deleted file mode 100644
index 12a88ec..0000000
--- a/vm/mterp/x86-atom/OP_OR_LONG_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_OR_LONG_2ADDR.S
- */
-
-%include "x86-atom/binopWide2addr.S" {"instr":"por %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_PACKED_SWITCH.S b/vm/mterp/x86-atom/OP_PACKED_SWITCH.S
deleted file mode 100644
index debac02..0000000
--- a/vm/mterp/x86-atom/OP_PACKED_SWITCH.S
+++ /dev/null
@@ -1,52 +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.
- */
-
- /*
- * File: OP_PACKED_SWITCH.S
- *
- * Code: Jump to a new instruction using a jump table
- *
- * For: packed-switch, sparse-switch
- *
- * Description: Jump to a new instruction based on the value in the given
- * register, using a table of offsets corresponding to each
- * value in a particular integral range, or fall through to
- * the next instruction if there is no match.
- *
- * Format: AA|op BBBBlo BBBBhi (31t)
- *
- * Syntax: op vAA, +BBBBBBBB
- */
-
-%default { "func":"dvmInterpHandlePackedSwitch" }
-
- FETCH 1, %ecx # %ecx<- BBBBlo
- FETCH 2, %edx # %edx<- BBBBhi
- shl $$16, %edx # prepare to create +BBBBBBBB
- or %edx, %ecx # %ecx<- +BBBBBBBB
- GET_VREG rINST # rINST<- vAA
- movl rINST, -4(%esp) # push parameter vAA
- lea (rPC, %ecx, 2), %ecx # %ecx<- PC + +BBBBBBBB*2
- movl %ecx, -8(%esp) # push parameter PC + +BBBBBBBB*2
- lea -8(%esp), %esp
- call $func # call code-unit branch offset
- shl $$1, %eax # shift for byte offset
- movl %eax, %edx # %edx<- offset
- lea 8(%esp), %esp
- jle common_periodicChecks_backwardBranch # do backward branch
- jmp .L${opcode}_finish
-%break
-.L${opcode}_finish:
- FINISH_RB %edx, %ecx # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_REM_DOUBLE.S b/vm/mterp/x86-atom/OP_REM_DOUBLE.S
deleted file mode 100644
index aa7d332..0000000
--- a/vm/mterp/x86-atom/OP_REM_DOUBLE.S
+++ /dev/null
@@ -1,51 +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.
- */
-
- /*
- * File: OP_REM_DOUBLE.S
- *
- * Code: Computes the remainder of a division. Performs no substitutions.
- *
- * For: rem-double
- *
- * Description: Calls fmod to compute the remainder of the result of dividing a
- * source register by a second, and stores the result in a
- * destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- movl (rFP, %ecx, 4), %eax # %eax<- vBBlo
- movl %eax, -16(%esp) # push parameter double lo
- movl 4(rFP, %ecx, 4), %eax # %eax<- vBBhi
- movl %eax, -12(%esp) # push parameter double hi
- movl (rFP, %edx, 4), %eax # %eax<- vCClo
- movl %eax, -8(%esp) # push parameter double lo
- movl 4(rFP, %edx, 4), %eax # %eax<- vCChi
- movl %eax, -4(%esp) # push parameter double hi
- lea -16(%esp), %esp
- jmp .L${opcode}_break
-%break
-
-.L${opcode}_break:
- call fmod # call: (long double x, long double y)
- # return: double
- lea 16(%esp), %esp
- fstpl (rFP, rINST, 4) # vAA<- remainder; return of fmod
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_REM_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_REM_DOUBLE_2ADDR.S
deleted file mode 100644
index 434c878..0000000
--- a/vm/mterp/x86-atom/OP_REM_DOUBLE_2ADDR.S
+++ /dev/null
@@ -1,52 +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.
- */
-
- /*
- * File: OP_REM_DOUBLE_2ADDR.S
- *
- * Code: Computes the remainder of a division. Performs no substitutions.
- *
- * For: rem-double/2addr
- *
- * Description: Calls fmod to compute the remainder of the result of dividing a
- * source register by a second, and stores the result in the first
- * source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- and $$15, rINST # rINST<- A
- shr $$4, %edx # %edx<- B
- movl (rFP, rINST, 4), %eax # %eax<- vAlo
- movl %eax, -20(%esp) # push parameter vAAlo
- movl 4(rFP, rINST, 4), %eax # %eax<- vAhi
- movl %eax, -16(%esp) # push parameter vAAhi
- movl (rFP, %edx, 4), %eax # %eax<- vBlo
- movl %eax, -12(%esp) # push parameter vBBlo
- movl 4(rFP, %edx, 4), %eax # %eax<- vBhi
- movl %eax, -8(%esp) # push parameter vBBhi
- lea -20(%esp), %esp
- jmp .L${opcode}_break
-%break
-
-.L${opcode}_break:
- call fmod # call: (long double x, long double y)
- # return: double
- lea 20(%esp), %esp
- fstpl (rFP, rINST, 4) # vAA<- remainder; return of fmod
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_REM_FLOAT.S b/vm/mterp/x86-atom/OP_REM_FLOAT.S
deleted file mode 100644
index de5e161..0000000
--- a/vm/mterp/x86-atom/OP_REM_FLOAT.S
+++ /dev/null
@@ -1,43 +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.
- */
-
- /*
- * File: OP_REM_FLOAT.S
- *
- * Code: Computes the remainder of a division. Performs no substitutions.
- *
- * For: rem-float
- *
- * Description: Calls fmod to compute the remainder of the result of dividing a
- * source register by a second, and stores the result in a
- * destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- movl %ecx, -8(%esp) # push parameter float
- movl %edx, -4(%esp) # push parameter float
- lea -8(%esp), %esp
- call fmodf # call: (float x, float y)
- # return: float
- lea 8(%esp), %esp
- fstps (rFP, rINST, 4) # vAA<- remainder; return of fmod
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_REM_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_REM_FLOAT_2ADDR.S
deleted file mode 100644
index 5ff5af5..0000000
--- a/vm/mterp/x86-atom/OP_REM_FLOAT_2ADDR.S
+++ /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.
- */
-
- /*
- * File: OP_REM_FLOAT_2ADDR.S
- *
- * Code: Computes the remainder of a division. Performs no substitutions.
- *
- * For: rem-float/2addr
- *
- * Description: Calls fmod to compute the remainder of the result of dividing a
- * source register by a second, and stores the result in the first
- * source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- andl $$15, rINST # rINST<- A
- GET_VREG %edx # %edx<- vB
- movl (rFP, rINST, 4), %ecx # %ecx<- vA
- movl %ecx, -8(%esp) # push parameter vA
- movl %edx, -4(%esp) # push parameter vB
- lea -8(%esp), %esp
- call fmodf # call: (float x, float y)
- # return: float
- lea 8(%esp), %esp
- fstps (rFP, rINST, 4)
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_REM_INT.S b/vm/mterp/x86-atom/OP_REM_INT.S
deleted file mode 100644
index 5f62d66..0000000
--- a/vm/mterp/x86-atom/OP_REM_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_REM_INT.S
- */
-
-%include "x86-atom/binopD.S" {"div":"0"}
diff --git a/vm/mterp/x86-atom/OP_REM_INT_2ADDR.S b/vm/mterp/x86-atom/OP_REM_INT_2ADDR.S
deleted file mode 100644
index 369ea5c..0000000
--- a/vm/mterp/x86-atom/OP_REM_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_REM_INT_2ADDR.S
- */
-
-%include "x86-atom/binopD2addr.S" {"div":"0"}
diff --git a/vm/mterp/x86-atom/OP_REM_INT_LIT16.S b/vm/mterp/x86-atom/OP_REM_INT_LIT16.S
deleted file mode 100644
index 0c9afa3a..0000000
--- a/vm/mterp/x86-atom/OP_REM_INT_LIT16.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_REM_INT_LIT16.S
- */
-
-%include "x86-atom/binopDLit16.S" {"div":"0"}
diff --git a/vm/mterp/x86-atom/OP_REM_INT_LIT8.S b/vm/mterp/x86-atom/OP_REM_INT_LIT8.S
deleted file mode 100644
index 6578c7c..0000000
--- a/vm/mterp/x86-atom/OP_REM_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_REM_INT_LIT8.S
- */
-
-%include "x86-atom/binopDLit8.S" {"div":"0"}
diff --git a/vm/mterp/x86-atom/OP_REM_LONG.S b/vm/mterp/x86-atom/OP_REM_LONG.S
deleted file mode 100644
index 3e3b200..0000000
--- a/vm/mterp/x86-atom/OP_REM_LONG.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_REM_LONG.S
- */
-
-%include "x86-atom/binopDivRemLong.S" {"func":"__moddi3"}
diff --git a/vm/mterp/x86-atom/OP_REM_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_REM_LONG_2ADDR.S
deleted file mode 100644
index f494caf..0000000
--- a/vm/mterp/x86-atom/OP_REM_LONG_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_REM_LONG_2ADDR.S
- */
-
-%include "x86-atom/binopDivRemLong2Addr.S" {"func":"__moddi3"}
diff --git a/vm/mterp/x86-atom/OP_RETURN.S b/vm/mterp/x86-atom/OP_RETURN.S
deleted file mode 100644
index 48d7e34..0000000
--- a/vm/mterp/x86-atom/OP_RETURN.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_RETURN.S
- */
-
-%include "x86-atom/OP_RETURN_COMMON.S"
diff --git a/vm/mterp/x86-atom/OP_RETURN_COMMON.S b/vm/mterp/x86-atom/OP_RETURN_COMMON.S
deleted file mode 100644
index d58a16c..0000000
--- a/vm/mterp/x86-atom/OP_RETURN_COMMON.S
+++ /dev/null
@@ -1,34 +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.
- */
-
- /*
- * File: OP_RETURN_COMMON.S
- *
- * Code: Return a 32-bit value. Uses no substitutions.
- *
- * For: return, return-object
- *
- * Description: Copies the return value into the "glue"
- * structure, then jumps to the return handler.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- GET_VREG rINST # rINST<- vAA
- movl rINST, offGlue_retval(%edx) # glue->retval<- vAA
- jmp common_returnFromMethod # jump to common return code
diff --git a/vm/mterp/x86-atom/OP_RETURN_OBJECT.S b/vm/mterp/x86-atom/OP_RETURN_OBJECT.S
deleted file mode 100644
index 3b9c10c..0000000
--- a/vm/mterp/x86-atom/OP_RETURN_OBJECT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_RETURN_OBJECT.S
- */
-
-%include "x86-atom/OP_RETURN_COMMON.S"
diff --git a/vm/mterp/x86-atom/OP_RETURN_VOID.S b/vm/mterp/x86-atom/OP_RETURN_VOID.S
deleted file mode 100644
index 4d8c92b..0000000
--- a/vm/mterp/x86-atom/OP_RETURN_VOID.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_RETURN_VOID.S
- */
-
- jmp common_returnFromMethod
diff --git a/vm/mterp/x86-atom/OP_RETURN_WIDE.S b/vm/mterp/x86-atom/OP_RETURN_WIDE.S
deleted file mode 100644
index 8069e85..0000000
--- a/vm/mterp/x86-atom/OP_RETURN_WIDE.S
+++ /dev/null
@@ -1,34 +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.
- */
-
- /*
- * File: OP_RETURN_WIDE.S
- *
- * Code: Return a 64-bit value. Uses no substitutions.
- *
- * For: return-wide
- *
- * Description: Copies the return value into the "glue"
- * structure, then jumps to the return handler.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vAA
- movq %xmm0, offGlue_retval(%edx)# glue->retval<- vAA
- jmp common_returnFromMethod # jump to common return code
diff --git a/vm/mterp/x86-atom/OP_RSUB_INT.S b/vm/mterp/x86-atom/OP_RSUB_INT.S
deleted file mode 100644
index 87498f9..0000000
--- a/vm/mterp/x86-atom/OP_RSUB_INT.S
+++ /dev/null
@@ -1,39 +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.
- */
-
- /*
- * File: OP_RSUB_INT.S
- *
- * Code: 32-bit reverse-subtraction. Uses no substitutions.
- *
- * For: rsub-int
- *
- * Description: Perform a reverse subtraction on a register and a
- * signed extended 16-bit literal value and store the
- * result in a destination register.
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $$4, %ecx # %ecx<- B
- andl $$15, rINST # rINST<- A
- FETCHs 1, %edx # %edx<- +CCCC, sign-extended literal
- GET_VREG %ecx # %ecx<- vB
- subl %ecx, %edx # %edx<- +CCCC sub vB
- SET_VREG %edx, rINST # vA<- %edx; result
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_RSUB_INT_LIT8.S b/vm/mterp/x86-atom/OP_RSUB_INT_LIT8.S
deleted file mode 100644
index d6114dd..0000000
--- a/vm/mterp/x86-atom/OP_RSUB_INT_LIT8.S
+++ /dev/null
@@ -1,36 +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.
- */
-
- /*
- * File: OP_RSUB_INT_LIT8.S
- *
- * Code: 32-bit reverse-subtraction. Uses no substitutions.
- *
- * For: rsub-int/lit8
- *
- * Description: Perform a reverse subtraction on a register and a
- * signed extended 8-bit literal value.
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CCs 1, %edx # %edx<- +CC, sign-extended literal
- GET_VREG %ecx # %ecx<- vBB
- sub %ecx, %edx # %edx<- +CC sub vBB
- SET_VREG %edx, rINST # vAA<- %edx; result
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_SGET.S b/vm/mterp/x86-atom/OP_SGET.S
deleted file mode 100644
index 914b4dc..0000000
--- a/vm/mterp/x86-atom/OP_SGET.S
+++ /dev/null
@@ -1,60 +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.
- */
-
- /*
- * File: OP_SGET.S
- *
- * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
- *
- * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; load the field value
- * into the value register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $$0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .L${opcode}_resolve
- jmp .L${opcode}_finish
-%break
-
-.L${opcode}_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $$0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- mov %eax, %ecx # %ecx<- result
-
-.L${opcode}_finish:
- FFETCH_ADV 2, %edx # %edx<- next instruction hi; fetch, advance
- movl offStaticField_value(%ecx), %eax # %eax<- field value
- SET_VREG %eax, rINST # vAA<- field value
- FGETOP_JMP 2, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_SGET_BOOLEAN.S b/vm/mterp/x86-atom/OP_SGET_BOOLEAN.S
deleted file mode 100644
index 8e383b4..0000000
--- a/vm/mterp/x86-atom/OP_SGET_BOOLEAN.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SGET_BOOLEAN.S
- */
-
-%include "x86-atom/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_BYTE.S b/vm/mterp/x86-atom/OP_SGET_BYTE.S
deleted file mode 100644
index c86fc20..0000000
--- a/vm/mterp/x86-atom/OP_SGET_BYTE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SGET_BYTE.S
- */
-
-%include "x86-atom/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_CHAR.S b/vm/mterp/x86-atom/OP_SGET_CHAR.S
deleted file mode 100644
index 0a3cffd..0000000
--- a/vm/mterp/x86-atom/OP_SGET_CHAR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SGET_CHAR.S
- */
-
-%include "x86-atom/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_OBJECT.S b/vm/mterp/x86-atom/OP_SGET_OBJECT.S
deleted file mode 100644
index 5145f14..0000000
--- a/vm/mterp/x86-atom/OP_SGET_OBJECT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SGET_OBJECT.S
- */
-
-%include "x86-atom/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_OBJECT_VOLATILE.S b/vm/mterp/x86-atom/OP_SGET_OBJECT_VOLATILE.S
deleted file mode 100644
index 5f64fb5..0000000
--- a/vm/mterp/x86-atom/OP_SGET_OBJECT_VOLATILE.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_SHORT.S b/vm/mterp/x86-atom/OP_SGET_SHORT.S
deleted file mode 100644
index 77064b6..0000000
--- a/vm/mterp/x86-atom/OP_SGET_SHORT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SGET_SHORT.S
- */
-
-%include "x86-atom/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_VOLATILE.S b/vm/mterp/x86-atom/OP_SGET_VOLATILE.S
deleted file mode 100644
index 5f64fb5..0000000
--- a/vm/mterp/x86-atom/OP_SGET_VOLATILE.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_WIDE.S b/vm/mterp/x86-atom/OP_SGET_WIDE.S
deleted file mode 100644
index 3ef6916..0000000
--- a/vm/mterp/x86-atom/OP_SGET_WIDE.S
+++ /dev/null
@@ -1,65 +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.
- */
-
- /*
- * File: OP_SGET_WIDE.S
- *
- * Code: 64-bit static field "get" operation. Uses no substitutions.
- *
- * For: sget-wide
- *
- * Description: Perform the identified object static field operation
- * with the identified static field, loading or storing
- * into the value register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_methodClassDex(%eax), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %edx # %edx<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $$0, (%ecx, %edx, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved StaticField ptr
- je .L${opcode}_resolve
-
-.L${opcode}_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq offStaticField_value(%ecx), %xmm0 # %xmm0<- field value
- movq %xmm0, (rFP, rINST, 4) # vAA<- field value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-%break
-
- /*
- * Continuation if the field has not yet been resolved.
- * %edx: BBBB field ref
- */
-
-.L${opcode}_resolve:
- movl offGlue_method(%eax), %eax # %eax <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %edx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%eax), %eax # %eax<- method->clazz
- movl %eax, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- lea 8(%esp), %esp
- cmp $$0, %eax # check if initalization failed
- movl %eax, %ecx # %ecx<- result
- jne .L${opcode}_finish # success, continue
- jmp common_exceptionThrown # failed; handle exception
diff --git a/vm/mterp/x86-atom/OP_SHL_INT.S b/vm/mterp/x86-atom/OP_SHL_INT.S
deleted file mode 100644
index 13e4a11..0000000
--- a/vm/mterp/x86-atom/OP_SHL_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SHL_INT.S
- */
-
-%include "x86-atom/binopS.S" {"instr":"sal %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHL_INT_2ADDR.S b/vm/mterp/x86-atom/OP_SHL_INT_2ADDR.S
deleted file mode 100644
index a27e09a..0000000
--- a/vm/mterp/x86-atom/OP_SHL_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SHL_INT_2ADDR.S
- */
-
-%include "x86-atom/binopS2addr.S" {"instr":"sal %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHL_INT_LIT8.S b/vm/mterp/x86-atom/OP_SHL_INT_LIT8.S
deleted file mode 100644
index 5141e5c..0000000
--- a/vm/mterp/x86-atom/OP_SHL_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SHL_INT_LIT8.S
- */
-
-%include "x86-atom/binopLit8S.S" {"instr":"sal %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHL_LONG.S b/vm/mterp/x86-atom/OP_SHL_LONG.S
deleted file mode 100644
index cef558c..0000000
--- a/vm/mterp/x86-atom/OP_SHL_LONG.S
+++ /dev/null
@@ -1,40 +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.
- */
-
- /*
- * File: OP_SHL_LONG.S
- *
- * Code: Performs a shift left long. Uses no substitutions.
- *
- * For: shl-long
- *
- * Description: Perform a binary shift operation using two source registers
- * where one is the shift amount and the other is the value to shift.
- * Store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_CC 1, %eax # %eax<- CC
- FETCH_BB 1, %edx # %edx<- BB
- movq .LshiftMask, %xmm2 # %xmm2<- mask for the shift bits
- movss (rFP, %eax, 4), %xmm0 # %xmm0<- vCC
- pand %xmm2, %xmm0 # %xmm0<- masked shift bits
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vBB
- psllq %xmm0, %xmm1 # %xmm1<- shifted vBB
- movq %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_SHL_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_SHL_LONG_2ADDR.S
deleted file mode 100644
index 28dfaf2..0000000
--- a/vm/mterp/x86-atom/OP_SHL_LONG_2ADDR.S
+++ /dev/null
@@ -1,41 +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.
- */
-
- /*
- * File: OP_SHL_LONG_2ADDR.S
- *
- * Code: Performs a shift left long. Uses no substitutions.
- *
- * For: shl-long/2addr
- *
- * Description: Perform a binary shift operation using two source registers
- * where the fist is the value to shift and the second is the
- * shift amount. Store the result in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- andl $$15, rINST # rINST<- A
- movss (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vA
- movq .LshiftMask, %xmm2 # %xmm2<- mask for the shift bits
- pand %xmm2, %xmm0 # %xmm0<- masked shift bits
- psllq %xmm0, %xmm1 # %xmm1<- shifted vA
- movq %xmm1, (rFP, rINST, 4) # vA<- shifted vA
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_SHR_INT.S b/vm/mterp/x86-atom/OP_SHR_INT.S
deleted file mode 100644
index e7fd28b..0000000
--- a/vm/mterp/x86-atom/OP_SHR_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SHR_INT.S
- */
-
-%include "x86-atom/binopS.S" {"instr":"sar %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHR_INT_2ADDR.S b/vm/mterp/x86-atom/OP_SHR_INT_2ADDR.S
deleted file mode 100644
index 0d0b461..0000000
--- a/vm/mterp/x86-atom/OP_SHR_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SHR_INT_2ADDR.S
- */
-
-%include "x86-atom/binopS2addr.S" {"instr":"sar %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHR_INT_LIT8.S b/vm/mterp/x86-atom/OP_SHR_INT_LIT8.S
deleted file mode 100644
index 3467bf5..0000000
--- a/vm/mterp/x86-atom/OP_SHR_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SHR_INT_LIT8.S
- */
-
-%include "x86-atom/binopLit8S.S" {"instr":"sar %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHR_LONG.S b/vm/mterp/x86-atom/OP_SHR_LONG.S
deleted file mode 100644
index be893ef..0000000
--- a/vm/mterp/x86-atom/OP_SHR_LONG.S
+++ /dev/null
@@ -1,53 +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.
- */
-
- /*
- * File: OP_SHR_LONG.S
- *
- * Code: Performs a shift right long
- *
- * For: shl-long
- *
- * Description: Perform a binary shift operation using two source registers
- * where one is the shift amount and the other is the value to shift.
- * Store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %edx # %edx<- BB
- FETCH_CC 1, %eax # %eax<- CC
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vBB
- movss (rFP, %eax, 4), %xmm0 # %xmm0<- vCC
- movq .LshiftMask, %xmm2
- pand %xmm2, %xmm0 # %xmm0<- masked for the shift bits
- psrlq %xmm0, %xmm1 # %xmm1<- shifted vBB
- cmpl $$0, 4(rFP, %edx, 4) # check if we need to consider sign
- jl .L${opcode}_finish # consider sign
- jmp .L${opcode}_final # sign is fine, finish
-%break
-
-.L${opcode}_finish:
- movq .Lvalue64, %xmm3 # %xmm3<- 64
- psubq %xmm0, %xmm3 # %xmm3<- 64 - shift amount
- movq .L64bits, %xmm4 # %xmm4<- lower 64 bits set
- psllq %xmm3, %xmm4 # %xmm4<- correct mask for sign bits
- por %xmm4, %xmm1 # %xmm1<- signed and shifted vBB
-
-.L${opcode}_final:
- movq %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_SHR_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_SHR_LONG_2ADDR.S
deleted file mode 100644
index 38aefcf..0000000
--- a/vm/mterp/x86-atom/OP_SHR_LONG_2ADDR.S
+++ /dev/null
@@ -1,54 +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.
- */
-
- /*
- * File: OP_SHR_LONG_2ADDR.S
- *
- * Code: Performs a shift left long
- *
- * For: shl-long/2addr
- *
- * Description: Perform a binary shift operation using two source registers
- * where the fist is the value to shift and the second is the
- * shift amount. Store the result in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- andl $$15, rINST # rINST<- BA
- movss (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vA
- movq .LshiftMask, %xmm2
- pand %xmm2, %xmm0 # %xmm0<- masked for the shift bits
- psrlq %xmm0, %xmm1 # %xmm1<- shifted vBB
- cmpl $$0, 4(rFP, rINST, 4) # check if we need to consider sign
- jl .L${opcode}_finish # consider sign
- jmp .L${opcode}_final # sign is fine, finish
-%break
-
-.L${opcode}_finish:
- movq .Lvalue64, %xmm3 # %xmm3<- 64
- psubq %xmm0, %xmm3 # %xmm3<- 64 - shift amount
- movq .L64bits, %xmm4 # %xmm4<- lower 64 bits set
- psllq %xmm3, %xmm4 # %xmm4<- correct mask for sign bits
- por %xmm4, %xmm1 # %xmm1<- signed and shifted vBB
-
-.L${opcode}_final:
- movq %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_SPARSE_SWITCH.S b/vm/mterp/x86-atom/OP_SPARSE_SWITCH.S
deleted file mode 100644
index 8020d1a..0000000
--- a/vm/mterp/x86-atom/OP_SPARSE_SWITCH.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SPARSE_SWITCH.S
- */
-
-%include "x86-atom/OP_PACKED_SWITCH.S" { "func":"dvmInterpHandleSparseSwitch" }
diff --git a/vm/mterp/x86-atom/OP_SPUT.S b/vm/mterp/x86-atom/OP_SPUT.S
deleted file mode 100644
index 55715a7..0000000
--- a/vm/mterp/x86-atom/OP_SPUT.S
+++ /dev/null
@@ -1,60 +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.
- */
-
- /*
- * File: OP_SPUT.S
- *
- * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
- *
- * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; store the field value
- * register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $$0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField ptr
- je .L${opcode}_resolve
- jmp .L${opcode}_finish
-%break
-
-.L${opcode}_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $$0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- movl %eax, %ecx # %ecx<- result
-
-.L${opcode}_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vAA
- movl rINST, offStaticField_value(%ecx) # field value<- vAA
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_SPUT_BOOLEAN.S b/vm/mterp/x86-atom/OP_SPUT_BOOLEAN.S
deleted file mode 100644
index 9bb64f8..0000000
--- a/vm/mterp/x86-atom/OP_SPUT_BOOLEAN.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SPUT_BOOLEAN.S
- */
-
-%include "x86-atom/OP_SPUT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_BYTE.S b/vm/mterp/x86-atom/OP_SPUT_BYTE.S
deleted file mode 100644
index 1d4f016..0000000
--- a/vm/mterp/x86-atom/OP_SPUT_BYTE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SPUT_BYTE.S
- */
-
-%include "x86-atom/OP_SPUT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_CHAR.S b/vm/mterp/x86-atom/OP_SPUT_CHAR.S
deleted file mode 100644
index 58300ef..0000000
--- a/vm/mterp/x86-atom/OP_SPUT_CHAR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SPUT_CHAR.S
- */
-
-%include "x86-atom/OP_SPUT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_OBJECT.S b/vm/mterp/x86-atom/OP_SPUT_OBJECT.S
deleted file mode 100644
index 88ebaf7..0000000
--- a/vm/mterp/x86-atom/OP_SPUT_OBJECT.S
+++ /dev/null
@@ -1,70 +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.
- */
-
- /*
- * File: OP_SPUT_OBJECT.S
- *
- * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
- *
- * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; store the field value
- * register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
- FETCH 1, %eax # %eax<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $$0, (%ecx, %eax, 4) # check for null ptr; resolved StaticField
- movl (%ecx, %eax, 4), %ecx # %ecx<- resolved StaticField
- je .L${opcode}_resolve
- jmp .L${opcode}_finish
-%break
-
-.L${opcode}_resolve:
- movl offGlue_method(%edx), %edx # %edx <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %eax, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- movl %edx, -8(%esp) # push parameter method->clazz
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- cmp $$0, %eax # check if initalization failed
- lea 8(%esp), %esp
- je common_exceptionThrown # failed; handle exception
- movl %eax, %ecx # %ecx<- result
-
-.L${opcode}_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG rINST # rINST<- vAA
-
-
- movl rINST, offStaticField_value(%ecx) # field value<- vAA
- testl rINST, rINST # stored null object ptr?
- je 1f
- movl rGLUE, %edx # get glue
- movl offField_clazz(%ecx), %ecx # ecx<- field->clazz
- movl offGlue_cardTable(%edx), %edx # get card table base
- shrl $$GC_CARD_SHIFT, %ecx # head to card number
- movb %dl, (%edx, %ecx) # mark card
-1:
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_SPUT_OBJECT_VOLATILE.S b/vm/mterp/x86-atom/OP_SPUT_OBJECT_VOLATILE.S
deleted file mode 100644
index b368e31..0000000
--- a/vm/mterp/x86-atom/OP_SPUT_OBJECT_VOLATILE.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/OP_SPUT_OBJECT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_SHORT.S b/vm/mterp/x86-atom/OP_SPUT_SHORT.S
deleted file mode 100644
index 1ecc562..0000000
--- a/vm/mterp/x86-atom/OP_SPUT_SHORT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SPUT_SHORT.S
- */
-
-%include "x86-atom/OP_SPUT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_VOLATILE.S b/vm/mterp/x86-atom/OP_SPUT_VOLATILE.S
deleted file mode 100644
index 7ee4140..0000000
--- a/vm/mterp/x86-atom/OP_SPUT_VOLATILE.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/OP_SPUT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_WIDE.S b/vm/mterp/x86-atom/OP_SPUT_WIDE.S
deleted file mode 100644
index 7d661cf..0000000
--- a/vm/mterp/x86-atom/OP_SPUT_WIDE.S
+++ /dev/null
@@ -1,65 +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.
- */
-
- /*
- * File: OP_SPUT_WIDE.S
- *
- * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
- *
- * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
- *
- * Description: Perform the identified object static field operation
- * with the identified static field; store the field value
- * register.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, string@BBBB
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_methodClassDex(%eax), %ecx # %ecx<- glue->pDvmDex
- FETCH 1, %edx # %edx<- BBBB
- movl offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
- cmp $$0, (%ecx, %edx, 4) # check for null ptr; resolved StaticField ptr
- movl (%ecx, %edx, 4), %ecx # %ecx<- resolved StaticField ptr
- je .L${opcode}_resolve
-
-.L${opcode}_finish:
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vAA
- movq %xmm0, offStaticField_value(%ecx) # field value<- field value
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
-%break
-
- /*
- * Continuation if the field has not yet been resolved.
- * %edx: BBBB field ref
- */
-
-.L${opcode}_resolve:
- movl offGlue_method(%eax), %eax # %eax <- glue->method
- EXPORT_PC # in case an exception is thrown
- movl %edx, -4(%esp) # push parameter CCCC; field ref
- movl offMethod_clazz(%eax), %eax # %eax<- method->clazz
- movl %eax, -8(%esp)
- lea -8(%esp), %esp
- call dvmResolveStaticField # call: (const ClassObject* referrer, u4 ifieldIdx)
- # return: StaticField*
- lea 8(%esp), %esp
- cmp $$0, %eax # check if initalization failed
- movl %eax, %ecx # %ecx<- result
- jne .L${opcode}_finish # success, continue
- jmp common_exceptionThrown # failed; handle exception
diff --git a/vm/mterp/x86-atom/OP_SUB_DOUBLE.S b/vm/mterp/x86-atom/OP_SUB_DOUBLE.S
deleted file mode 100644
index 5f2dbb6..0000000
--- a/vm/mterp/x86-atom/OP_SUB_DOUBLE.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SUB_DOUBLE.S
- */
-
-%include "x86-atom/binopWide.S" {"instr":"subsd %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_SUB_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_SUB_DOUBLE_2ADDR.S
deleted file mode 100644
index cd6f12a..0000000
--- a/vm/mterp/x86-atom/OP_SUB_DOUBLE_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SUB_DOUBLE_2ADDR.S
- */
-
-%include "x86-atom/binopWide2addr.S" {"instr":"subsd %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_SUB_FLOAT.S b/vm/mterp/x86-atom/OP_SUB_FLOAT.S
deleted file mode 100644
index eb79d79..0000000
--- a/vm/mterp/x86-atom/OP_SUB_FLOAT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SUB_FLOAT.S
- */
-
-%include "x86-atom/binopF.S" {"instr":"subss %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_SUB_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_SUB_FLOAT_2ADDR.S
deleted file mode 100644
index 77f23f1..0000000
--- a/vm/mterp/x86-atom/OP_SUB_FLOAT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SUB_FLOAT_2ADDR.S
- */
-
-%include "x86-atom/binopF2addr.S" {"instr":"subss %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_SUB_INT.S b/vm/mterp/x86-atom/OP_SUB_INT.S
deleted file mode 100644
index 8d342cd..0000000
--- a/vm/mterp/x86-atom/OP_SUB_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SUB_INT.S
- */
-
-%include "x86-atom/binop.S" {"instr":"subl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_SUB_INT_2ADDR.S b/vm/mterp/x86-atom/OP_SUB_INT_2ADDR.S
deleted file mode 100644
index 4d295a4..0000000
--- a/vm/mterp/x86-atom/OP_SUB_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SUB_INT_2ADDR.S
- */
-
-%include "x86-atom/binop2addr.S" {"instr":"subl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_SUB_INT_LIT8.S b/vm/mterp/x86-atom/OP_SUB_INT_LIT8.S
deleted file mode 100644
index 8bf0902..0000000
--- a/vm/mterp/x86-atom/OP_SUB_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SUB_INT_LIT8.S
- */
-
-%include "x86-atom/binopLit8.S" {"instr":"subl %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_SUB_LONG.S b/vm/mterp/x86-atom/OP_SUB_LONG.S
deleted file mode 100644
index 84e25d0..0000000
--- a/vm/mterp/x86-atom/OP_SUB_LONG.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SUB_LONG.S
- */
-
-%include "x86-atom/binopWide.S" {"instr":"psubq %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_SUB_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_SUB_LONG_2ADDR.S
deleted file mode 100644
index ca6a2ad..0000000
--- a/vm/mterp/x86-atom/OP_SUB_LONG_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_SUB_LONG_2ADDR.S
- */
-
-%include "x86-atom/binopWide2addr.S" {"instr":"psubq %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_THROW.S b/vm/mterp/x86-atom/OP_THROW.S
deleted file mode 100644
index 120b1e9..0000000
--- a/vm/mterp/x86-atom/OP_THROW.S
+++ /dev/null
@@ -1,37 +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.
- */
-
- /*
- * File: OP_THROW.S
- *
- * Code: Throw an exception
- *
- * For: throw
- *
- * Description: Throw an exception object in the current thread.
- *
- * Format: AA|op (11x)
- *
- * Syntax: op vAA
- */
-
- movl rGLUE, %eax # %eax<- pMterpGlue
- EXPORT_PC # export the pc
- GET_VREG rINST # rINST<- vAA
- cmp $$0, rINST # check for null
- movl offGlue_self(%eax), %ecx # %ecx<- glue->self
- je common_errNullObject # handle null object
- movl rINST, offThread_exception(%ecx) # thread->exception<- object
- jmp common_exceptionThrown # handle exception
diff --git a/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR.S b/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR.S
deleted file mode 100644
index f920b50..0000000
--- a/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR.S
+++ /dev/null
@@ -1,40 +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.
- */
-
- /*
- * File: OP_THROW_VERIFICATION_ERROR.S
- *
- * Code:
- *
- * For: throw-verification-error
- *
- * Description: Throws an exception for an error discovered during verification.
- * The exception is indicated by AA with details provided by BBBB.
- *
- * Format: AA|op BBBB (21c)
- *
- * Syntax: op vAA, ref@BBBB
- */
-
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl offGlue_method(%edx), %ecx # %ecx<- glue->method
- EXPORT_PC # in case an exception is thrown
- FETCH 1, %eax # %eax<- BBBB
- movl %eax, -4(%esp) # push parameter BBBB; ref
- movl rINST, -8(%esp) # push parameter AA
- movl %ecx, -12(%esp) # push parameter glue->method
- lea -12(%esp), %esp
- call dvmThrowVerificationError # call: (const Method* method, int kind, int ref)
- jmp common_exceptionThrown # failed; handle exception
diff --git a/vm/mterp/x86-atom/OP_UNUSED_3E.S b/vm/mterp/x86-atom/OP_UNUSED_3E.S
deleted file mode 100644
index d91d469..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_3E.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_UNUSED_3E.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_3F.S b/vm/mterp/x86-atom/OP_UNUSED_3F.S
deleted file mode 100644
index 84cc69d..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_3F.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_UNUSED_3F.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_40.S b/vm/mterp/x86-atom/OP_UNUSED_40.S
deleted file mode 100644
index e0853da..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_40.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_UNUSED_40.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_41.S b/vm/mterp/x86-atom/OP_UNUSED_41.S
deleted file mode 100644
index a30fbe3..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_41.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_UNUSED_41.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_42.S b/vm/mterp/x86-atom/OP_UNUSED_42.S
deleted file mode 100644
index 64c5648..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_42.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_UNUSED_42.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_43.S b/vm/mterp/x86-atom/OP_UNUSED_43.S
deleted file mode 100644
index 4a6120b..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_43.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_UNUSED_43.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_73.S b/vm/mterp/x86-atom/OP_UNUSED_73.S
deleted file mode 100644
index 9808865..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_73.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_UNUSED_73.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_79.S b/vm/mterp/x86-atom/OP_UNUSED_79.S
deleted file mode 100644
index 6ebd8ff..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_79.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_UNUSED_79.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_7A.S b/vm/mterp/x86-atom/OP_UNUSED_7A.S
deleted file mode 100644
index 79a22d0..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_7A.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_UNUSED_7A.S
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_FF.S b/vm/mterp/x86-atom/OP_UNUSED_FF.S
deleted file mode 100644
index e6acc08..0000000
--- a/vm/mterp/x86-atom/OP_UNUSED_FF.S
+++ /dev/null
@@ -1,16 +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.
- */
-
-%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_USHR_INT.S b/vm/mterp/x86-atom/OP_USHR_INT.S
deleted file mode 100644
index a1d91c6..0000000
--- a/vm/mterp/x86-atom/OP_USHR_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_USHR_INT.S
- */
-
-%include "x86-atom/binopS.S" {"instr":"shr %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_USHR_INT_2ADDR.S b/vm/mterp/x86-atom/OP_USHR_INT_2ADDR.S
deleted file mode 100644
index 9ee9c66..0000000
--- a/vm/mterp/x86-atom/OP_USHR_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_USHR_INT_2ADDR.S
- */
-
-%include "x86-atom/binopS2addr.S" {"instr":"shr %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_USHR_INT_LIT8.S b/vm/mterp/x86-atom/OP_USHR_INT_LIT8.S
deleted file mode 100644
index 5a54df7..0000000
--- a/vm/mterp/x86-atom/OP_USHR_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_USHR_INT_LIT8.S
- */
-
-%include "x86-atom/binopLit8S.S" {"instr":"shr %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_USHR_LONG.S b/vm/mterp/x86-atom/OP_USHR_LONG.S
deleted file mode 100644
index 1c404f0..0000000
--- a/vm/mterp/x86-atom/OP_USHR_LONG.S
+++ /dev/null
@@ -1,39 +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.
- */
-
- /*
- * File: OP_USHR_LONG.S
- *
- * Code: Performs an unsigned shift right long operation. Uses no substitutions.
- *
- * For: ushr-long
- *
- * Description: Perform a binary shift operation using two source registers
- * where one is the shift amount and the other is the value to shift.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_CC 1, %eax # %eax<- CC
- FETCH_BB 1, %edx # %edx<- BB
- movsd .LshiftMask, %xmm2 # %xmm2<- mask for the shift bits
- movss (rFP, %eax, 4), %xmm0 # %xmm0<- vCC
- pand %xmm2, %xmm0 # %xmm0<- masked shift bits
- movsd (rFP, %edx, 4), %xmm1 # %xmm1<- vBB
- psrlq %xmm0, %xmm1 # %xmm1<- shifted vBB
- movsd %xmm1, (rFP, rINST, 4) # vAA<- shifted vBB
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_USHR_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_USHR_LONG_2ADDR.S
deleted file mode 100644
index 31cb5bc..0000000
--- a/vm/mterp/x86-atom/OP_USHR_LONG_2ADDR.S
+++ /dev/null
@@ -1,41 +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.
- */
-
- /*
- * File: OP_USHR_LONG_2ADDR.S
- *
- * Code: Performs an unsigned shift right long operation. Uses no substiutions.
- *
- * For: ushr-long/2addr
- *
- * Description: Perform a binary shift operation using two source registers
- * where the fist is the value to shift and the second is the
- * shift amount. Store the result in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- andl $$15, rINST # rINST<- A
- movq .LshiftMask, %xmm2 # %xmm2<- mask for the shift bits
- movss (rFP, %edx, 4), %xmm0 # %xmm0<- vB
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vA
- pand %xmm2, %xmm0 # %xmm0<- masked shift bits
- psrlq %xmm0, %xmm1 # %xmm1<- shifted vA
- movq %xmm1, (rFP, rINST, 4) # vA<- shifted vA
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_XOR_INT.S b/vm/mterp/x86-atom/OP_XOR_INT.S
deleted file mode 100644
index d36b83f..0000000
--- a/vm/mterp/x86-atom/OP_XOR_INT.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_XOR_INT.S
- */
-
-%include "x86-atom/binop.S" {"instr":"xor %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_XOR_INT_2ADDR.S b/vm/mterp/x86-atom/OP_XOR_INT_2ADDR.S
deleted file mode 100644
index 0bab865..0000000
--- a/vm/mterp/x86-atom/OP_XOR_INT_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_XOR_INT_2ADDR.S
- */
-
-%include "x86-atom/binop2addr.S" {"instr":"xor %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_XOR_INT_LIT16.S b/vm/mterp/x86-atom/OP_XOR_INT_LIT16.S
deleted file mode 100644
index a26bcc5..0000000
--- a/vm/mterp/x86-atom/OP_XOR_INT_LIT16.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_XOR_INT_LIT16.S
- */
-
-%include "x86-atom/binopLit16.S" {"instr":"xor %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_XOR_INT_LIT8.S b/vm/mterp/x86-atom/OP_XOR_INT_LIT8.S
deleted file mode 100644
index 9a3c8e3..0000000
--- a/vm/mterp/x86-atom/OP_XOR_INT_LIT8.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_XOR_INT_LIT8.S
- */
-
-%include "x86-atom/binopLit8.S" {"instr":"xor %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_XOR_LONG.S b/vm/mterp/x86-atom/OP_XOR_LONG.S
deleted file mode 100644
index 58a8384..0000000
--- a/vm/mterp/x86-atom/OP_XOR_LONG.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_XOR_LONG.S
- */
-
-%include "x86-atom/binopWide.S" {"instr":"pxor %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_XOR_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_XOR_LONG_2ADDR.S
deleted file mode 100644
index 6b42cbd..0000000
--- a/vm/mterp/x86-atom/OP_XOR_LONG_2ADDR.S
+++ /dev/null
@@ -1,20 +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.
- */
-
- /*
- * File: OP_XOR_LONG_2ADDR.S
- */
-
-%include "x86-atom/binopWide2addr.S" {"instr":"pxor %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/TODO.txt b/vm/mterp/x86-atom/TODO.txt
deleted file mode 100644
index 4dfa06b..0000000
--- a/vm/mterp/x86-atom/TODO.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-Items requiring attention:
-
-(hi) Add gc card marking to aput/iput/sput/new_filled_array
-(hi) Correct stack overflow handling (dvmCleanupStackOverflow takes an
- additional argument now)
-(hi) WITH_DEBUGGER and WITH_PROFILER are no longer defined (but are
- assumed to be enabled)
-(hi) Rename dvmJitGetCodeAddr to dvmJitGetTraceAddr.
-(hi) Remove references to rGLUE and replace with rSELF
-(hi) Rework interpreter to co-exist the new switching model which
- elminiates a separate debug interpreter. Needs a dedicated
- rIBASE register (or alternate switching model with variable
- handler base).
-(hi) Add dvmReportXXXX()" calls in footer.cpp to support profilers &
- debuggers.
-(hi) Set self->debugIsMethodEntry in invoke code.
-
-(md) Correct OP_MONITOR_EXIT (need to adjust PC before throw)
-(md) OP_THROW needs to export the PC
-(md) Use dvmThrowArrayIndexOutOfBoundsException(length, index) for
- array bounds errors.
-(md) Use dvmThrowClassCastException(actual, desired) for class cast errors.
-(md) Use dvmThrowArrayStoreExceptionIncompatibleElement(actual, desired)
- for array store errors.
-(md) Use dvmThrowNegativeArraySizeException(len) forarray alloc errors
-(md) Replace any remaining use of dvmThrowException with proper helper function
-
-(lo) Implement OP_BREAKPOINT
-(lo) Implement OP_*_VOLATILE (12 instructions)
-(lo) Implement OP_RETURN_VOID_BARRIER
-(lo) Implement OP_INVOKE_OBJECT_INIT
-(lo) Implement dvmJitScanAllClassPointers
diff --git a/vm/mterp/x86-atom/bincmp.S b/vm/mterp/x86-atom/bincmp.S
deleted file mode 100644
index a8fbed5..0000000
--- a/vm/mterp/x86-atom/bincmp.S
+++ /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.
- */
-
- /*
- * File: bincmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform.
- *
- * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
- *
- * Description: Branch to the given destination if the comparison
- * test between the given registers values is true.
- *
- * Format: B|A|op CCCC (22t)
- *
- * Syntax: op vA, vB, +CCCC
- */
-
- movl rINST, %eax # %eax<- BA
- andl $$15, rINST # rINST<- A
- shr $$4, %eax # %eax<- B
- GET_VREG rINST # rINST<- vA
- movl $$4, %edx # %edx<- 4
- cmp (rFP, %eax, 4), rINST # compare vA and vB
- j${revcmp} 1f # goto next instruction if reverse
- # comparison is true
- FETCHs 1, %edx # %edx<- +CCCC, Branch offset
- sal $$1, %edx
- js common_periodicChecks_backwardBranch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
diff --git a/vm/mterp/x86-atom/binop.S b/vm/mterp/x86-atom/binop.S
deleted file mode 100644
index 1706b72..0000000
--- a/vm/mterp/x86-atom/binop.S
+++ /dev/null
@@ -1,39 +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.
- */
-
- /*
- * File: binop.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- GET_VREG %edx # %edx<- vCC
- $instr # %ecx<- vBB op vCC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binop2addr.S b/vm/mterp/x86-atom/binop2addr.S
deleted file mode 100644
index b26b25a..0000000
--- a/vm/mterp/x86-atom/binop2addr.S
+++ /dev/null
@@ -1,45 +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.
- */
-
- /*
- * File: binop2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%ecx = %ecx op %edx".
- *
- * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
- * sub-int/2addr, xor-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- andl $$15, rINST # rINST<- A
- movl rINST, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vB
- GET_VREG %ecx # %ecx<- vA
- $instr # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
-
-
diff --git a/vm/mterp/x86-atom/binopD.S b/vm/mterp/x86-atom/binopD.S
deleted file mode 100644
index 20a2e9a..0000000
--- a/vm/mterp/x86-atom/binopD.S
+++ /dev/null
@@ -1,61 +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.
- */
-
- /*
- * File: binopD.S
- *
- * Code: 32-bit integer divide operation. If "div" is set, the code
- * returns the quotient, else it returns the remainder.
- * Also, a divide-by-zero check is done.
- *
- * For: div-int, rem-int
- *
- * Description: Perform a binary operation on two source
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-%default {"div":"1"}
-
- FETCH_BB 1, %eax # %eax<- BB
- FETCH_CC 1, %ecx # %ecx<- CC
- GET_VREG %eax # %eax<- vBB
- GET_VREG %ecx # %ecx<- vCC
- cmp $$0, %ecx # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- cmpl $$-1, %ecx # handle -1 special case divide error
- jne .L${opcode}_noerror
- cmpl $$0x80000000,%eax # handle min int special case divide error
- je .L${opcode}_break
-.L${opcode}_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- .if $div
- SET_VREG %eax rINST # vAA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vAA<- %edx (remainder)
- .endif
- jmp .L${opcode}_break2
-%break
-.L${opcode}_break:
- .if $div
- movl $$0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $$0, (rFP, rINST, 4) # vAA<- 0
- .endif
-.L${opcode}_break2:
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/binopD2addr.S b/vm/mterp/x86-atom/binopD2addr.S
deleted file mode 100644
index 392b46b..0000000
--- a/vm/mterp/x86-atom/binopD2addr.S
+++ /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.
- */
-
- /*
- * File: binopD2addr.S
- *
- * Code: 32-bit "/2addr" integer divde operation. If "div"
- * is set, the code returns the quotient, else it returns
- * the remainder. Also, a divide-by-zero check is done.
- *
- * For: div-int/2addr, rem-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-%default {"div":"1"}
- movl rINST, %ecx # %ecx<- BA
- andl $$15, rINST # rINST<- A, to be used as dest
- movl rINST, %eax # %eax<- A
- shr $$4, %ecx # %ecx<- B
- GET_VREG %eax # %eax<- vA
- GET_VREG %ecx # %edx<- vB
- cmp $$0, %ecx # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- cmpl $$-1, %ecx # handle -1 special case divide error
- jne .L${opcode}_noerror
- cmpl $$0x80000000,%eax # handle min int special case divide error
- je .L${opcode}_break
-.L${opcode}_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- .if $div
- SET_VREG %eax rINST # vAA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vAA<- %edx (remainder)
- .endif
- jmp .L${opcode}_break2
- #FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
- #FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
-%break
-.L${opcode}_break:
- .if $div
- movl $$0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $$0, (rFP, rINST, 4) # vAA<- 0
- .endif
-.L${opcode}_break2:
- FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
-
diff --git a/vm/mterp/x86-atom/binopDLit16.S b/vm/mterp/x86-atom/binopDLit16.S
deleted file mode 100644
index 3e67d0a..0000000
--- a/vm/mterp/x86-atom/binopDLit16.S
+++ /dev/null
@@ -1,66 +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.
- */
-
- /*
- * File: binopDLit16.S
- *
- * Code: 32-bit "lit16" divide operation. If "div" is set, the code
- * returns the quotient, else it returns the remainder.
- * Also, a divide-by-zero check is done.
- *
- * For: div-int/lit16, rem-int/lit16
- *
- * Description: Perform a binary operation on a register and a
- * sign extended 16-bit literal value
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
-%default {"div":"1"}
-
- movl rINST, %eax # %eax<- BA
- shr $$4, %eax # %eax<- B
- FETCHs 1, %ecx # %ecx<- +CCCC, sign-extended literal
- cmp $$0, %ecx # check for divide by zero
- GET_VREG %eax # %eax<- vB
- je common_errDivideByZero # handle divide by zero
- andl $$15, rINST # rINST<- A
- cmpl $$-1, %ecx # handle -1 special case divide error
- jne .L${opcode}_noerror
- cmpl $$0x80000000,%eax # handle min int special case divide error
- je .L${opcode}_break
-.L${opcode}_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- #FFETCH_ADV 2, %ecx # %ecx<- next instruction hi; fetch, advance
- .if $div
- SET_VREG %eax rINST # vA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vA<- %edx (remainder)
- .endif
- jmp .L${opcode}_break2
-
-%break
-.L${opcode}_break:
- .if $div
- movl $$0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $$0, (rFP, rINST, 4) # vAA<- 0
- .endif
-.L${opcode}_break2:
-
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/binopDLit8.S b/vm/mterp/x86-atom/binopDLit8.S
deleted file mode 100644
index f197714..0000000
--- a/vm/mterp/x86-atom/binopDLit8.S
+++ /dev/null
@@ -1,65 +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.
- */
-
- /*
- * File: binopDLit8.S
- *
- * Code: 32-bit "lit8" divide operation. If "div" is set, the code
- * returns the quotient, else it returns the remainder.
- * Also, a divide-by-zero check is done.
- *
- * For: div-int/lit8, rem-int/lit8
- *
- * Description: Perform a binary operation on a register and a
- * signe extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
-%default {"div":"1"}
-
- FETCH_BB 1, %eax # %eax<- BB
- FETCH_CCs 1, %ecx # %ecx<- +CC, sign-extended literal
- cmp $$0, %ecx # check for divide by zero
- GET_VREG %eax # %eax<- vBB
- je common_errDivideByZero # handle divide by zero
-
- cmpl $$-1, %ecx # handle -1 special case divide error
- jne .L${opcode}_noerror
- cmpl $$0x80000000,%eax # handle min int special case divide error
- je .L${opcode}_break
-.L${opcode}_noerror:
- cdq # sign-extend %eax to %edx
- idiv %ecx # divide %edx:%eax by %ecx
- #FFETCH_ADV 2, %ecx # %ecx<- next instruction hi; fetch, advance
- .if $div
- SET_VREG %eax rINST # vAA<- %eax (quotient)
- .else
- SET_VREG %edx rINST # vAA<- %edx (remainder)
- .endif
- jmp .L${opcode}_break2
-%break
-.L${opcode}_break:
- .if $div
- movl $$0x80000000, (rFP, rINST, 4) # vAA<- min int
- .else
- movl $$0, (rFP, rINST, 4) # vAA<- 0
- .endif
-
-.L${opcode}_break2:
- FINISH 2 # jump to next instruction
- #FGETOP_JMP 2, %ecx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopDivRemLong.S b/vm/mterp/x86-atom/binopDivRemLong.S
deleted file mode 100644
index 93ed4f8..0000000
--- a/vm/mterp/x86-atom/binopDivRemLong.S
+++ /dev/null
@@ -1,52 +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.
- */
-
- /*
- * File: binopDivRemLong.S
- *
- * Code: 64-bit long divide operation. Variable
- * "func" defines the function called to do the operation.
- *
- * For: div-long, rem-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
-%default {"func":"__divdi3"}
-
- FETCH_CC 1, %edx # %edx<- CC
- movl (rFP, %edx, 4), %eax # %eax<- vCC
- movl 4(rFP, %edx, 4), %ecx # %ecx<- vCC+1
- movl %eax, -8(%esp) # push arg vCC
- or %ecx, %eax # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- FETCH_BB 1, %edx # %edx<- BB
- movl %ecx, -4(%esp) # push arg vCC+1
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vBB,vBB+1
- jmp .L${opcode}_finish
-%break
-.L${opcode}_finish:
- movq %xmm0, -16(%esp) # push arg vBB,vBB+1
- lea -16(%esp), %esp
- call $func # call func
- lea 16(%esp), %esp
- movl %eax, (rFP, rINST, 4) # vAA<- return low
- movl %edx, 4(rFP, rINST, 4) # vAA+1<- return high
- FINISH 2 # jump to next instruction
diff --git a/vm/mterp/x86-atom/binopDivRemLong2Addr.S b/vm/mterp/x86-atom/binopDivRemLong2Addr.S
deleted file mode 100644
index aa427de..0000000
--- a/vm/mterp/x86-atom/binopDivRemLong2Addr.S
+++ /dev/null
@@ -1,54 +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.
- */
-
- /*
- * File: binopDivRemLong2Addr.S
- *
- * Code: 64-bit "/2addr" long divide operation. Variable
- * "func" defines the function called to do the operation.
- *
- * For: div-long/2addr, rem-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register.
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-%default {"func":"__divdi3"}
-
- movl rINST, %edx # %edx<- BA
- shr $$4, %edx # %edx<- B
- and $$15, rINST # rINST<- A
- movl (rFP, %edx, 4), %eax # %eax<- vB
- movl %eax, -12(%esp) # push arg vB
- movl 4(rFP, %edx, 4), %ecx # %ecx<- vB+1
- or %ecx, %eax # check for divide by zero
- je common_errDivideByZero # handle divide by zero
- movl %ecx, -8(%esp) # push arg vB+1
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vA,vA+1
- jmp .L${opcode}_break
-%break
-.L${opcode}_break:
- movq %xmm0, -20(%esp) # push arg vA, vA+1
- lea -20(%esp), %esp
- call $func # call func
- lea 20(%esp), %esp
- movl %eax, (rFP, rINST, 4) # vA<- return low
- movl %edx, 4(rFP, rINST, 4) # vA<- return high
- FFETCH_ADV 1, %ecx # %ecx<- next instruction hi; fetch, advance
- FGETOP_JMP 1, %ecx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopF.S b/vm/mterp/x86-atom/binopF.S
deleted file mode 100644
index 0c07b97..0000000
--- a/vm/mterp/x86-atom/binopF.S
+++ /dev/null
@@ -1,39 +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.
- */
-
- /*
- * File: binopF.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-float, mul-float, sub-float
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movss (rFP, %ecx, 4), %xmm0 # %xmm0<-vBB
- movss (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- $instr # %xmm0<- vBB op vCC
- movss %xmm0, (rFP, rINST, 4) # vAA<- %xmm0; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopF2addr.S b/vm/mterp/x86-atom/binopF2addr.S
deleted file mode 100644
index 135ca0c..0000000
--- a/vm/mterp/x86-atom/binopF2addr.S
+++ /dev/null
@@ -1,41 +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.
- */
-
- /*
- * File: binopF2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0 = %xmm0 op %xmm1".
- *
- * For: add-float/2addr, mul-float/2addr, sub-float/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- andl $$15, %ecx # %ecx<- A
- shr $$4, rINST # rINST<- B
- FFETCH_ADV 1, %edx # %ecx<- next instruction hi; fetch, advance
- movss (rFP, %ecx, 4), %xmm0 # %xmm0<- vA
- movss (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- $instr # %xmm0<- vA op vB
- movss %xmm0, (rFP, %ecx, 4) # vA<- %xmm0; result
- FGETOP_JMP 1, %edx # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopLit16.S b/vm/mterp/x86-atom/binopLit16.S
deleted file mode 100644
index 4972b4d..0000000
--- a/vm/mterp/x86-atom/binopLit16.S
+++ /dev/null
@@ -1,43 +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.
- */
-
- /*
- * File: binopLit16.S
- *
- * Code: 32-bit "lit16" operation. Provides an "instr" line to
- * specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
- * xor-int/lit16
- *
- * Description: Perform a binary operation on a register and a
- * sign extended 16-bit literal value and store the
- * result in a destination register.
- *
- * Format: B|A|op CCCC (22s)
- *
- * Syntax: op vA, vB, #+CCCC
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $$4, %ecx # %ecx<- B
- andl $$15, rINST # rINST<- A
- FETCHs 1, %edx # %edx<- +CCCC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- $instr # %ecx<- vA op vB
- SET_VREG %ecx, rINST # vA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopLit8.S b/vm/mterp/x86-atom/binopLit8.S
deleted file mode 100644
index 239e443..0000000
--- a/vm/mterp/x86-atom/binopLit8.S
+++ /dev/null
@@ -1,40 +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.
- */
-
- /*
- * File: binopLit8.S
- *
- * Code: 32-bit "lit8" divide operation. Provides an "instr" line
- * to specify an instruction that performs "%ecx = %ecx op %edx"
- *
- *
- * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
- * xor-int/lit8
- *
- * Description: Perform a binary operation on a register and a
- * signed extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CCs 1, %edx # %edx<- +CC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vBB
- $instr # %ecx<- vBB op +CC
- SET_VREG %ecx, rINST # vAA<- %ecx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopLit8S.S b/vm/mterp/x86-atom/binopLit8S.S
deleted file mode 100644
index c0360aa..0000000
--- a/vm/mterp/x86-atom/binopLit8S.S
+++ /dev/null
@@ -1,40 +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.
- */
-
- /*
- * File: binopLit8S.S
- *
- * Code: 32-bit "lit8" divide operation. Provides an "instr" line
- * to specify an instruction that performs "%edx = %edx op %cl"
- *
- *
- * For: shl-int/lit8, shr-int/lit8, ushr-int/lit8
- *
- *
- * Description: Perform a binary operation on a register and a
- * signed extended 8-bit literal value
- *
- * Format: AA|op CC|BB (22b)
- *
- * Syntax: op vAA, vBB, #+CC
- */
-
- FETCH_BB 1, %edx # %edx<- BB
- FETCH_CCs 1, %ecx # %ecx<- +CC, sign-extended literal
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vBB
- $instr # %edx<- vBB op +CC
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopS.S b/vm/mterp/x86-atom/binopS.S
deleted file mode 100644
index b09f5c2..0000000
--- a/vm/mterp/x86-atom/binopS.S
+++ /dev/null
@@ -1,39 +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.
- */
-
- /*
- * File: binopS.S
- *
- * Code: Generic 32-bit binary operation. Provides an "instr" line to
- * specify an instruction that performs "%edx = %edx op %cl"
- *
- * For: shl-int, shr-int, ushr-int
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %edx # %edx<- BB
- FETCH_CC 1, %ecx # %ecx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %edx # %edx<- vBB
- GET_VREG %ecx # %ecx<- vCC
- $instr # %edx<- vBB op +CC
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopS2addr.S b/vm/mterp/x86-atom/binopS2addr.S
deleted file mode 100644
index 0c3c29a..0000000
--- a/vm/mterp/x86-atom/binopS2addr.S
+++ /dev/null
@@ -1,42 +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.
- */
-
- /*
- * File: binopS2addr.S
- *
- * Code: Generic 32-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%edx = %edx op %cl".
- *
- * For: shl-int/2addr, shr-int/2addr, ushr-int/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %ecx # %ecx<- BA
- shr $$4, %ecx # %ecx<- B
- andl $$15, rINST # rINST<- A
- movl rINST, %edx # %edx<- A
- FFETCH_ADV 1, %eax # %ecx<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- GET_VREG %edx # %edx<- vA
- $instr # %edx<- vA op vB
- SET_VREG %edx, rINST # vAA<- %edx; result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopWide.S b/vm/mterp/x86-atom/binopWide.S
deleted file mode 100644
index 3cd3e52..0000000
--- a/vm/mterp/x86-atom/binopWide.S
+++ /dev/null
@@ -1,40 +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.
- */
-
- /*
- * File: binopWide.S
- *
- * Code: Generic 64-bit binary operation. Provides an "instr" variable to
- * specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
- *
- * For: add-double, add-long, and-long, mul-double, or-long,
- * sub-double, sub-long, xor-long
- *
- * Description: Perform a binary operation on two source registers
- * and store the result in a destination register.
- *
- * Format: AA|op CC|BB (23x)
- *
- * Syntax: op vAA, vBB, vCC
- */
-
- FETCH_BB 1, %ecx # %ecx<- BB
- FETCH_CC 1, %edx # %edx<- CC
- FFETCH_ADV 2, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vBB
- movq (rFP, %edx, 4), %xmm1 # %xmm1<- vCC
- $instr # %xmm0<- vBB op vCC
- movq %xmm0, (rFP, rINST, 4) # vAA<- %ecx
- FGETOP_JMP 2, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopWide2addr.S b/vm/mterp/x86-atom/binopWide2addr.S
deleted file mode 100644
index f9aa29c..0000000
--- a/vm/mterp/x86-atom/binopWide2addr.S
+++ /dev/null
@@ -1,41 +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.
- */
-
- /*
- * File: binopWide2addr.S
- *
- * Code: Generic 64-bit "/2addr" binary operation. Provides an
- * "instr" line to specify an instruction that performs
- * "%xmm0= %xmm0 op %xmm1".
- *
- * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
- * or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
- *
- * Description: Perform a binary operation on two sources registers
- * and store the result in the first source register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
- movl rINST, %edx # %edx<- BA
- shr $$4, rINST # rINST<- B
- andl $$15, %edx # %edx<- A
- movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
- movq (rFP, %edx, 4), %xmm0 # %xmm0<- vA
- $instr # %xmm0<- vA op vB
- movq %xmm0, (rFP, %edx, 4) # vA<- %xmm0; result
- FINISH 1 # jump to next instruction
diff --git a/vm/mterp/x86-atom/entry.S b/vm/mterp/x86-atom/entry.S
deleted file mode 100644
index e68e49e..0000000
--- a/vm/mterp/x86-atom/entry.S
+++ /dev/null
@@ -1,384 +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.
- */
-
- /*
- * File: entry.S
- */
-
-#define ASSIST_DEBUGGER 1
- .text
- .align 2
- .global dvmMterpStdRun
- .type dvmMterpStdRun, %function
-
- /*
- * Save registers, initialize sp and fp.
- * On entry:
- * bool MterpGlue(glue *)
- */
-
- .macro MTERP_ENTRY
- movl 4(%esp), %ecx # get first argument
- movl %ebp, -4(%esp) # save caller base pointer
- movl %ebx, -8(%esp) # save %ebx
- movl %esi, -12(%esp) # save %esi
- movl %edi, -16(%esp) # save %edi
- lea -40(%esp), %ebp # set callee base pointer
- lea -40(%esp), %esp # set callee stack pointer
- .endm
-
- /*
- * Restore registers.
- * This function returns a boolean "changeInterp" value.
- * The return value is from dvmMterpStdBail().
- */
-
- .macro MTERP_EXIT
- lea 40(%esp), %esp # correct stack pointer
- movl -16(%esp), %edi # restore %edi
- movl -12(%esp), %esi # restore %esi
- movl -8(%esp), %ebx # restore %ebx
- movl -4(%esp), %ebp # restore caller base pointer
- ret # return
- .endm
-
- /*
- * DvmMterpStdRun entry point: save stack pointer, setup memory locations, get
- * entry point, start executing instructions.
- */
-
-dvmMterpStdRun:
- MTERP_ENTRY
- movl %ecx, rGLUE # save value for pMterpGlue
- movl offGlue_pc(%ecx), rPC # get program counter
- cmp $$kInterpEntryInstr, offGlue_entryPoint(%ecx) # check instruction
- movl offGlue_fp(%ecx), rFP # get frame pointer
- movl %esp, offGlue_bailPtr(%ecx) # save SP for eventual return
- FFETCH %edx # %edx<- opcode
- jne .Lnot_instr # no, handle it
- FGETOP_JMPa %edx # start executing the instruction at rPC
-
- /*
- * Not an instruction. Are we returning from a method?
- */
-
-.Lnot_instr:
- cmpl $$kInterpEntryReturn, offGlue_entryPoint(%ecx)
- je common_returnFromMethod
-
- /*
- * No, are we throwing an exception?
- */
-
-.Lnot_return:
- cmpl $$kInterpEntryThrow, offGlue_entryPoint(%ecx)
- je common_exceptionThrown
-
- /*
- * No, then we must abort.
- */
-
-.Lbad_arg:
- pushl offGlue_entryPoint(%ecx)
- movl $$.LstrBadEntryPoint, -4(%esp)
- lea -4(%esp), %esp
- call printf
- lea 8(%esp), %esp
- call dvmAbort # call (void)
-
- /*
- * Restore the stack pointer and PC from the save point established on entry and
- * return to whoever called dvmMterpStdRun.
- *
- * On entry:
- * 4(%esp) MterpGlue* glue
- * 8(%esp) bool changeInterp
- */
-
- .global dvmMterpStdBail
- .type dvmMterpStdBail, %function
-
-dvmMterpStdBail:
- movl 4(%esp), %ecx # get first argument
- movl 8(%esp), %eax # get second argument
- movl offGlue_bailPtr(%ecx), %esp # sp <- saved SP
- MTERP_EXIT
-
- /*
- * String references.
- */
-
-.LstrBadEntryPoint:
- .asciz "Bad entry point %d\n"
-
-
-dvmAsmInstructionJmpTable = .LdvmAsmInstructionJmpTable
-.LdvmAsmInstructionJmpTable:
-.long .L_OP_NOP
-.long .L_OP_MOVE
-.long .L_OP_MOVE_FROM16
-.long .L_OP_MOVE_16
-.long .L_OP_MOVE_WIDE
-.long .L_OP_MOVE_WIDE_FROM16
-.long .L_OP_MOVE_WIDE_16
-.long .L_OP_MOVE_OBJECT
-.long .L_OP_MOVE_OBJECT_FROM16
-.long .L_OP_MOVE_OBJECT_16
-.long .L_OP_MOVE_RESULT
-.long .L_OP_MOVE_RESULT_WIDE
-.long .L_OP_MOVE_RESULT_OBJECT
-.long .L_OP_MOVE_EXCEPTION
-.long .L_OP_RETURN_VOID
-.long .L_OP_RETURN
-.long .L_OP_RETURN_WIDE
-.long .L_OP_RETURN_OBJECT
-.long .L_OP_CONST_4
-.long .L_OP_CONST_16
-.long .L_OP_CONST
-.long .L_OP_CONST_HIGH16
-.long .L_OP_CONST_WIDE_16
-.long .L_OP_CONST_WIDE_32
-.long .L_OP_CONST_WIDE
-.long .L_OP_CONST_WIDE_HIGH16
-.long .L_OP_CONST_STRING
-.long .L_OP_CONST_STRING_JUMBO
-.long .L_OP_CONST_CLASS
-.long .L_OP_MONITOR_ENTER
-.long .L_OP_MONITOR_EXIT
-.long .L_OP_CHECK_CAST
-.long .L_OP_INSTANCE_OF
-.long .L_OP_ARRAY_LENGTH
-.long .L_OP_NEW_INSTANCE
-.long .L_OP_NEW_ARRAY
-.long .L_OP_FILLED_NEW_ARRAY
-.long .L_OP_FILLED_NEW_ARRAY_RANGE
-.long .L_OP_FILL_ARRAY_DATA
-.long .L_OP_THROW
-.long .L_OP_GOTO
-.long .L_OP_GOTO_16
-.long .L_OP_GOTO_32
-.long .L_OP_PACKED_SWITCH
-.long .L_OP_SPARSE_SWITCH
-.long .L_OP_CMPL_FLOAT
-.long .L_OP_CMPG_FLOAT
-.long .L_OP_CMPL_DOUBLE
-.long .L_OP_CMPG_DOUBLE
-.long .L_OP_CMP_LONG
-.long .L_OP_IF_EQ
-.long .L_OP_IF_NE
-.long .L_OP_IF_LT
-.long .L_OP_IF_GE
-.long .L_OP_IF_GT
-.long .L_OP_IF_LE
-.long .L_OP_IF_EQZ
-.long .L_OP_IF_NEZ
-.long .L_OP_IF_LTZ
-.long .L_OP_IF_GEZ
-.long .L_OP_IF_GTZ
-.long .L_OP_IF_LEZ
-.long .L_OP_UNUSED_3E
-.long .L_OP_UNUSED_3F
-.long .L_OP_UNUSED_40
-.long .L_OP_UNUSED_41
-.long .L_OP_UNUSED_42
-.long .L_OP_UNUSED_43
-.long .L_OP_AGET
-.long .L_OP_AGET_WIDE
-.long .L_OP_AGET_OBJECT
-.long .L_OP_AGET_BOOLEAN
-.long .L_OP_AGET_BYTE
-.long .L_OP_AGET_CHAR
-.long .L_OP_AGET_SHORT
-.long .L_OP_APUT
-.long .L_OP_APUT_WIDE
-.long .L_OP_APUT_OBJECT
-.long .L_OP_APUT_BOOLEAN
-.long .L_OP_APUT_BYTE
-.long .L_OP_APUT_CHAR
-.long .L_OP_APUT_SHORT
-.long .L_OP_IGET
-.long .L_OP_IGET_WIDE
-.long .L_OP_IGET_OBJECT
-.long .L_OP_IGET_BOOLEAN
-.long .L_OP_IGET_BYTE
-.long .L_OP_IGET_CHAR
-.long .L_OP_IGET_SHORT
-.long .L_OP_IPUT
-.long .L_OP_IPUT_WIDE
-.long .L_OP_IPUT_OBJECT
-.long .L_OP_IPUT_BOOLEAN
-.long .L_OP_IPUT_BYTE
-.long .L_OP_IPUT_CHAR
-.long .L_OP_IPUT_SHORT
-.long .L_OP_SGET
-.long .L_OP_SGET_WIDE
-.long .L_OP_SGET_OBJECT
-.long .L_OP_SGET_BOOLEAN
-.long .L_OP_SGET_BYTE
-.long .L_OP_SGET_CHAR
-.long .L_OP_SGET_SHORT
-.long .L_OP_SPUT
-.long .L_OP_SPUT_WIDE
-.long .L_OP_SPUT_OBJECT
-.long .L_OP_SPUT_BOOLEAN
-.long .L_OP_SPUT_BYTE
-.long .L_OP_SPUT_CHAR
-.long .L_OP_SPUT_SHORT
-.long .L_OP_INVOKE_VIRTUAL
-.long .L_OP_INVOKE_SUPER
-.long .L_OP_INVOKE_DIRECT
-.long .L_OP_INVOKE_STATIC
-.long .L_OP_INVOKE_INTERFACE
-.long .L_OP_UNUSED_73
-.long .L_OP_INVOKE_VIRTUAL_RANGE
-.long .L_OP_INVOKE_SUPER_RANGE
-.long .L_OP_INVOKE_DIRECT_RANGE
-.long .L_OP_INVOKE_STATIC_RANGE
-.long .L_OP_INVOKE_INTERFACE_RANGE
-.long .L_OP_UNUSED_79
-.long .L_OP_UNUSED_7A
-.long .L_OP_NEG_INT
-.long .L_OP_NOT_INT
-.long .L_OP_NEG_LONG
-.long .L_OP_NOT_LONG
-.long .L_OP_NEG_FLOAT
-.long .L_OP_NEG_DOUBLE
-.long .L_OP_INT_TO_LONG
-.long .L_OP_INT_TO_FLOAT
-.long .L_OP_INT_TO_DOUBLE
-.long .L_OP_LONG_TO_INT
-.long .L_OP_LONG_TO_FLOAT
-.long .L_OP_LONG_TO_DOUBLE
-.long .L_OP_FLOAT_TO_INT
-.long .L_OP_FLOAT_TO_LONG
-.long .L_OP_FLOAT_TO_DOUBLE
-.long .L_OP_DOUBLE_TO_INT
-.long .L_OP_DOUBLE_TO_LONG
-.long .L_OP_DOUBLE_TO_FLOAT
-.long .L_OP_INT_TO_BYTE
-.long .L_OP_INT_TO_CHAR
-.long .L_OP_INT_TO_SHORT
-.long .L_OP_ADD_INT
-.long .L_OP_SUB_INT
-.long .L_OP_MUL_INT
-.long .L_OP_DIV_INT
-.long .L_OP_REM_INT
-.long .L_OP_AND_INT
-.long .L_OP_OR_INT
-.long .L_OP_XOR_INT
-.long .L_OP_SHL_INT
-.long .L_OP_SHR_INT
-.long .L_OP_USHR_INT
-.long .L_OP_ADD_LONG
-.long .L_OP_SUB_LONG
-.long .L_OP_MUL_LONG
-.long .L_OP_DIV_LONG
-.long .L_OP_REM_LONG
-.long .L_OP_AND_LONG
-.long .L_OP_OR_LONG
-.long .L_OP_XOR_LONG
-.long .L_OP_SHL_LONG
-.long .L_OP_SHR_LONG
-.long .L_OP_USHR_LONG
-.long .L_OP_ADD_FLOAT
-.long .L_OP_SUB_FLOAT
-.long .L_OP_MUL_FLOAT
-.long .L_OP_DIV_FLOAT
-.long .L_OP_REM_FLOAT
-.long .L_OP_ADD_DOUBLE
-.long .L_OP_SUB_DOUBLE
-.long .L_OP_MUL_DOUBLE
-.long .L_OP_DIV_DOUBLE
-.long .L_OP_REM_DOUBLE
-.long .L_OP_ADD_INT_2ADDR
-.long .L_OP_SUB_INT_2ADDR
-.long .L_OP_MUL_INT_2ADDR
-.long .L_OP_DIV_INT_2ADDR
-.long .L_OP_REM_INT_2ADDR
-.long .L_OP_AND_INT_2ADDR
-.long .L_OP_OR_INT_2ADDR
-.long .L_OP_XOR_INT_2ADDR
-.long .L_OP_SHL_INT_2ADDR
-.long .L_OP_SHR_INT_2ADDR
-.long .L_OP_USHR_INT_2ADDR
-.long .L_OP_ADD_LONG_2ADDR
-.long .L_OP_SUB_LONG_2ADDR
-.long .L_OP_MUL_LONG_2ADDR
-.long .L_OP_DIV_LONG_2ADDR
-.long .L_OP_REM_LONG_2ADDR
-.long .L_OP_AND_LONG_2ADDR
-.long .L_OP_OR_LONG_2ADDR
-.long .L_OP_XOR_LONG_2ADDR
-.long .L_OP_SHL_LONG_2ADDR
-.long .L_OP_SHR_LONG_2ADDR
-.long .L_OP_USHR_LONG_2ADDR
-.long .L_OP_ADD_FLOAT_2ADDR
-.long .L_OP_SUB_FLOAT_2ADDR
-.long .L_OP_MUL_FLOAT_2ADDR
-.long .L_OP_DIV_FLOAT_2ADDR
-.long .L_OP_REM_FLOAT_2ADDR
-.long .L_OP_ADD_DOUBLE_2ADDR
-.long .L_OP_SUB_DOUBLE_2ADDR
-.long .L_OP_MUL_DOUBLE_2ADDR
-.long .L_OP_DIV_DOUBLE_2ADDR
-.long .L_OP_REM_DOUBLE_2ADDR
-.long .L_OP_ADD_INT_LIT16
-.long .L_OP_RSUB_INT
-.long .L_OP_MUL_INT_LIT16
-.long .L_OP_DIV_INT_LIT16
-.long .L_OP_REM_INT_LIT16
-.long .L_OP_AND_INT_LIT16
-.long .L_OP_OR_INT_LIT16
-.long .L_OP_XOR_INT_LIT16
-.long .L_OP_ADD_INT_LIT8
-.long .L_OP_RSUB_INT_LIT8
-.long .L_OP_MUL_INT_LIT8
-.long .L_OP_DIV_INT_LIT8
-.long .L_OP_REM_INT_LIT8
-.long .L_OP_AND_INT_LIT8
-.long .L_OP_OR_INT_LIT8
-.long .L_OP_XOR_INT_LIT8
-.long .L_OP_SHL_INT_LIT8
-.long .L_OP_SHR_INT_LIT8
-.long .L_OP_USHR_INT_LIT8
-.long .L_OP_IGET_VOLATILE
-.long .L_OP_IPUT_VOLATILE
-.long .L_OP_SGET_VOLATILE
-.long .L_OP_SPUT_VOLATILE
-.long .L_OP_IGET_OBJECT_VOLATILE
-.long .L_OP_IGET_WIDE_VOLATILE
-.long .L_OP_IPUT_WIDE_VOLATILE
-.long .L_OP_SGET_WIDE_VOLATILE
-.long .L_OP_SPUT_WIDE_VOLATILE
-.long .L_OP_BREAKPOINT
-.long .L_OP_THROW_VERIFICATION_ERROR
-.long .L_OP_EXECUTE_INLINE
-.long .L_OP_EXECUTE_INLINE_RANGE
-.long .L_OP_INVOKE_OBJECT_INIT_RANGE
-.long .L_OP_RETURN_VOID_BARRIER
-.long .L_OP_IGET_QUICK
-.long .L_OP_IGET_WIDE_QUICK
-.long .L_OP_IGET_OBJECT_QUICK
-.long .L_OP_IPUT_QUICK
-.long .L_OP_IPUT_WIDE_QUICK
-.long .L_OP_IPUT_OBJECT_QUICK
-.long .L_OP_INVOKE_VIRTUAL_QUICK
-.long .L_OP_INVOKE_VIRTUAL_QUICK_RANGE
-.long .L_OP_INVOKE_SUPER_QUICK
-.long .L_OP_INVOKE_SUPER_QUICK_RANGE
-.long .L_OP_IPUT_OBJECT_VOLATILE
-.long .L_OP_SGET_OBJECT_VOLATILE
-.long .L_OP_SPUT_OBJECT_VOLATILE
-.long .L_OP_UNUSED_FF
diff --git a/vm/mterp/x86-atom/footer.S b/vm/mterp/x86-atom/footer.S
deleted file mode 100644
index 7b5ed9c..0000000
--- a/vm/mterp/x86-atom/footer.S
+++ /dev/null
@@ -1,660 +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.
- */
-
- /*
- * File: footer.S
- */
-
- .text
- .align 2
-
- /*
- * Check to see if the thread needs to be suspended or debugger/profiler
- * activity has begun.
- *
- * On entry:
- * %ecx is reentry type, e.g. kInterpEntryInstr
- * %edx is PC adjustment in bytes
- */
-
-common_periodicChecks:
- movl %edx, -8(%esp) # save pc adjustments
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl %ebx, -4(%esp) # save %ebx to the stack
- movl offGlue_pSelfSuspendCount(%edx), %ebx # %ebx<- pSuspendCount (int)
-4:
- movl offGlue_pDebuggerActive(%edx), %eax # %eax<- pDebuggerActive
- testl %eax, %eax
- je 5f
- movzbl (%eax), %eax # %eax<- get debuggerActive (boolean)
-5:
- cmp $$0, (%ebx) # check if suspend is pending
- jne 2f # handle suspend
- movl offGlue_pActiveProfilers(%edx), %ebx # %ebx<- activeProfilers (int)
- orl (%ebx), %eax # %eax<- merge activeProfilers and debuggerActive
- movl -8(%esp), %edx # %edx<- restore %edx
- jne 3f # debugger or profiler active; switch interp
- movl -4(%esp), %ebx # %ebx<- restore %ebx
- ret # return
-2: # check suspended
- EXPORT_PC
- movl offGlue_self(%edx), %eax # %eax<- glue->self
- movl %eax, -12(%esp) # push parameter boolean
- lea -12(%esp), %esp
- call dvmCheckSuspendPending # call: (Thread* self)
- # return: bool
- movl 4(%esp), %edx # %edx<- restore %edx
- movl 8(%esp), %ebx # %ebx<- restore %ebx
- lea 12(%esp), %esp
- ret
-3: # debugger/profiler enabled, bail out
- leal (rPC, %edx, 2), rPC # adjust pc to show target
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movb $$kInterpEntryInstr, offGlue_entryPoint(%ecx)
- movl $$1, %edx # switch interpreter
- jmp common_gotoBail # bail
-
- /*
- * Check to see if the thread needs to be suspended or debugger/profiler
- * activity has begun. With this variant, the reentry type is hard coded
- * as kInterpEntryInstr.
- *
- * On entry:
- * %edx is PC adjustment in bytes
- */
-
-common_periodicChecks_backwardBranch:
- EXPORT_PC
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_pSelfSuspendCount(%ecx), rINST # %ebx<- pSuspendCount (int)
-4:
- movl offGlue_pDebuggerActive(%ecx), %eax # %eax<- pDebuggerActive
- testl %eax, %eax # test for NULL pointer
- je 5f
- movzbl (%eax), %eax # %eax<- get debuggerActive count
-5:
- cmp $$0, (rINST) # check if suspend is pending
- jne 2f # handle suspend
- movl offGlue_pActiveProfilers(%ecx), rINST # %edx<- activeProfilers (int)
- orl (rINST), %eax # %eax<- merge activeProfilers and debuggerActive
- jne 3f # debugger or profiler active; switch interp
- FINISH_RB %edx, %ecx # jump to next instruction
-2: # check suspended
- movl offGlue_self(%ecx), %eax# %eax<- glue->self
- movl %edx, rINST
- movl %eax, -12(%esp) # push parameter boolean
- lea -12(%esp), %esp
- call dvmCheckSuspendPending # call: (Thread* self)
- # return: bool
- movl rINST, %edx # %edx<- restore %edx
- lea 12(%esp), %esp
- FINISH_RB %edx, %ecx
-3: # debugger/profiler enabled, bail out
- leal (rPC, %edx, 2), rPC # adjust pc to show target
- movb $$kInterpEntryInstr, offGlue_entryPoint(%ecx)
- movl $$1, %edx # switch interpreter
- jmp common_gotoBail # bail
-
- /*
- * The equivalent of "goto bail", this calls through the "bail handler".
- * State registers will be saved to the "glue" area before bailing.
- *
- * On entry:
- * %edx is "bool changeInterp", indicating if we want to switch to the
- * other interpreter or just bail all the way out
- */
-
-common_gotoBail:
- SAVE_PC_FP_TO_GLUE %ecx # save program counter and frame pointer
-
- /*
- * Inlined dvmMterpStdBail
- */
-
- lea 40(%ebp), %esp
- movl %edx, %eax
- movl 24(%ebp), %edi
- movl 28(%ebp), %esi
- movl 32(%ebp), %ebx
- movl 36(%ebp), %ebp
- ret
-
- /*
- * Common code for method invocation with range.
- *
- * On entry:
- * %ecx is "Method* methodToCall", the method we're trying to call
- */
-
-common_invokeMethodRange:
-.LinvokeNewRange:
-
- /*
- * prepare to copy args to "outs" area of current frame
- */
-
- SAVEAREA_FROM_FP %eax # %eax<- &outs; &StackSaveArea
- test rINST, rINST # test for no args
- movl rINST, sReg0 # sReg0<- AA
- jz .LinvokeArgsDone # no args; jump to args done
- FETCH 2, %edx # %edx<- CCCC
-
- /*
- * %ecx=methodToCall, %edx=CCCC, sReg0=count, %eax=&outs (&stackSaveArea)
- * (very few methods have > 10 args; could unroll for common cases)
- */
-
- movl %ebx, sReg1 # sReg1<- save %ebx
- lea (rFP, %edx, 4), %edx # %edx<- &vCCCC
- shll $$2, sReg0 # sReg0<- offset
- subl sReg0, %eax # %eax<- update &outs
- shrl $$2, sReg0 # sReg0<- offset
-1:
- movl (%edx), %ebx # %ebx<- vCCCC
- lea 4(%edx), %edx # %edx<- &vCCCC++
- subl $$1, sReg0 # sReg<- sReg--
- movl %ebx, (%eax) # *outs<- vCCCC
- lea 4(%eax), %eax # outs++
- jne 1b # loop if count (sReg0) not zero
- movl sReg1, %ebx # %ebx<- restore %ebx
- jmp .LinvokeArgsDone # continue
-
- /*
- * %ecx is "Method* methodToCall", the method we're trying to call
- * prepare to copy args to "outs" area of current frame
- */
-
-common_invokeMethodNoRange:
-.LinvokeNewNoRange:
- movl rINST, sReg0 # sReg0<- BA
- shrl $$4, sReg0 # sReg0<- B
- je .LinvokeArgsDone # no args; jump to args done
- SAVEAREA_FROM_FP %eax # %eax<- &outs; &StackSaveArea
- FETCH 2, %edx # %edx<- GFED
-
- /*
- * %ecx=methodToCall, %edx=GFED, sReg0=count, %eax=outs
- */
-
-.LinvokeNonRange:
- cmp $$2, sReg0 # compare sReg0 to 2
- movl %edx, sReg1 # sReg1<- GFED
- jl 1f # handle 1 arg
- je 2f # handle 2 args
- cmp $$4, sReg0 # compare sReg0 to 4
- jl 3f # handle 3 args
- je 4f # handle 4 args
-5:
- andl $$15, rINST # rINST<- A
- lea -4(%eax), %eax # %eax<- update &outs; &outs--
- movl (rFP, rINST, 4), %edx # %edx<- vA
- movl %edx, (%eax) # *outs<- vA
- movl sReg1, %edx # %edx<- GFED
-4:
- shr $$12, %edx # %edx<- G
- lea -4(%eax), %eax # %eax<- update &outs; &outs--
- movl (rFP, %edx, 4), %edx # %edx<- vG
- movl %edx, (%eax) # *outs<- vG
- movl sReg1, %edx # %edx<- GFED
-3:
- and $$0x0f00, %edx # %edx<- 0F00
- shr $$6, %edx # %edx<- F at correct offset
- lea -4(%eax), %eax # %eax<- update &outs; &outs--
- movl (rFP, %edx), %edx # %edx<- vF
- movl %edx, (%eax) # *outs<- vF
- movl sReg1, %edx # %edx<- GFED
-2:
- and $$0x00f0, %edx # %edx<- 00E0
- shr $$2, %edx # %edx<- E at correct offset
- lea -4(%eax), %eax # %eax<- update &outs; &outs--
- movl (rFP, %edx), %edx # %edx<- vE
- movl %edx, (%eax) # *outs<- vE
- movl sReg1, %edx # %edx<- GFED
-1:
- and $$0x000f, %edx # %edx<- 000D
- movl (rFP, %edx, 4), %edx # %edx<- vD
- movl %edx, -4(%eax) # *--outs<- vD
-0:
-
- /*
- * %ecx is "Method* methodToCall", the method we're trying to call
- * find space for the new stack frame, check for overflow
- */
-
-.LinvokeArgsDone:
- movzwl offMethod_registersSize(%ecx), %eax # %eax<- methodToCall->regsSize
- movzwl offMethod_outsSize(%ecx), %edx # %edx<- methodToCall->outsSize
- movl %ecx, sReg0 # sReg<- methodToCall
- shl $$2, %eax # %eax<- update offset
- SAVEAREA_FROM_FP %ecx # %ecx<- &outs; &StackSaveArea
- subl %eax, %ecx # %ecx<- newFP; (old savearea - regsSize)
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl %ecx, sReg1 # sReg1<- &outs
- subl $$sizeofStackSaveArea, %ecx # %ecx<- newSaveArea (stack save area using newFP)
- movl offGlue_interpStackEnd(%eax), %eax # %eax<- glue->interpStackEnd
- movl %eax, sReg2 # sReg2<- glue->interpStackEnd
- shl $$2, %edx # %edx<- update offset for outsSize
- movl %ecx, %eax # %eax<- newSaveArea
- sub %edx, %ecx # %ecx<- bottom; (newSaveArea - outsSize)
- cmp sReg2, %ecx # compare interpStackEnd and bottom
- movl sReg0, %ecx # %ecx<- restore methodToCall
- jl .LstackOverflow # handle frame overflow
-
- /*
- * set up newSaveArea
- */
-
-#ifdef EASY_GDB
- SAVEAREA_FROM_FP %edx # %edx<- &outs; &StackSaveArea
- movl %edx, offStackSaveArea_prevSave(%eax) # newSaveArea->prevSave<- &outs
-#endif
- movl rFP, offStackSaveArea_prevFrame(%eax) # newSaveArea->prevFrame<- rFP
- movl rPC, offStackSaveArea_savedPc(%eax) # newSaveArea->savedPc<- rPC
- testl $$ACC_NATIVE, offMethod_accessFlags(%ecx) # check for native call
- movl %ecx, offStackSaveArea_method(%eax) # newSaveArea->method<- method to call
- jne .LinvokeNative # handle native call
-
- /*
- * Update "glue" values for the new method
- * %ecx=methodToCall, sReg1=newFp
- */
-
- movl offMethod_clazz(%ecx), %edx # %edx<- method->clazz
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl %ecx, offGlue_method(%eax) # glue->method<- methodToCall
- movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
- movl offMethod_insns(%ecx), rPC # rPC<- methodToCall->insns
- movl %edx, offGlue_methodClassDex(%eax) # glue->methodClassDex<- method->clazz->pDvmDex
- movl offGlue_self(%eax), %ecx # %ecx<- glue->self
- movl sReg1, rFP # rFP<- newFP
- movl rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
- FINISH_A # jump to methodToCall->insns
-
- /*
- * Prep for the native call
- * %ecx=methodToCall, sReg1=newFP, %eax=newSaveArea
- */
-
-.LinvokeNative:
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl %ecx, -20(%esp) # push parameter methodToCall
- movl offGlue_self(%edx), %edx # %edx<- glue->self
- movl offThread_jniLocal_topCookie(%edx), %ecx # %ecx<- glue->self->thread->refNext
- movl %ecx, offStackSaveArea_localRefCookie(%eax) # newSaveArea->localRefCookie<- refNext
- movl %eax, -4(%esp) # save newSaveArea
- movl sReg1, %eax # %eax<- newFP
- movl %eax, offThread_curFrame(%edx) # glue->self->curFrame<- newFP
- movl %edx, -8(%esp) # save glue->self
- movl %edx, -16(%esp) # push parameter glue->self
- movl rGLUE, %edx # %edx<- pMterpGlue
- movl -20(%esp), %ecx # %ecx<- methodToCall
- lea offGlue_retval(%edx), %edx # %edx<- &retval
- movl %edx, -24(%esp) # push parameter pMterpGlue
- movl %eax, -28(%esp) # push parameter newFP
- lea -28(%esp), %esp
-
-#ifdef ASSIST_DEBUGGER
- jmp .Lskip
- .type dalvik_mterp, %function
-dalvik_mterp:
- MTERP_ENTRY
-.Lskip:
-#endif
- call *offMethod_nativeFunc(%ecx) # call methodToCall->nativeFunc
- lea 28(%esp), %esp
- movl -4(%esp), %edx # %edx<- newSaveArea
- movl -8(%esp), %ecx # %ecx<- glue->self
- movl offStackSaveArea_localRefCookie(%edx), %eax # %eax<- newSaveArea->localRefCookie
- FFETCH_ADV 3, %edx # %edx<- next instruction hi; fetch, advance
- cmp $$0, offThread_exception(%ecx) # check for exception
- movl rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
- movl %eax, offThread_jniLocal_topCookie(%ecx) # glue->self<- newSaveArea->localRefCookie
- jne common_exceptionThrown # handle exception
- FGETOP_JMP 3, %edx # jump to next instruction; getop, jmp
-
-.LstackOverflow:
- movl %ecx, -4(%esp) # push method to call
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offGlue_self(%ecx), %ecx # %ecx<- glue->self
- movl %ecx, -8(%esp) # push parameter self
- lea -8(%esp), %esp
- call dvmHandleStackOverflow # call: (Thread* self, Method *meth)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-#ifdef ASSIST_DEBUGGER
-#endif
-
- /*
- * Common code for handling a return instruction.
- *
- * This does not return.
- */
-
-common_returnFromMethod:
-.LreturnNew:
-
- /*
- * Inline common periodic checks
- */
-
- movl rGLUE, rINST # %ecx<- pMterpGlue
- movl offGlue_pSelfSuspendCount(rINST), %edx # %ebx<- pSuspendCount (int)
- movl offGlue_pDebuggerActive(rINST), %eax # %eax<- pDebuggerActive
- movl (%eax), %eax # %eax<- get debuggerActive (boolean)
- and $$7, %eax # %eax<- mask for boolean (just how many bits does it take?)
- cmp $$0, (%edx) # check if suspend is pending
- jne 2f # handle suspend
- movl offGlue_pActiveProfilers(rINST), %edx # %edx<- activeProfilers (int)
- or (%edx), %eax # %eax<- merge activeProfilers and debuggerActive
- cmp $$0, %eax # check for debuggerActive
- jne 3f # debugger or profiler active; switch interp
- jmp 4f
-2: # check suspended
- movl offGlue_self(rINST), %eax# %eax<- glue->self
- movl %eax, -12(%esp) # push parameter boolean
- lea -12(%esp), %esp
- call dvmCheckSuspendPending # call: (Thread* self)
- # return: bool
- lea 12(%esp), %esp
- jmp 4f
-3: # debugger/profiler enabled, bail out
- movl $$kInterpEntryInstr, offGlue_entryPoint(rINST) # glue->entryPoint<- reentry type
- movl $$1, %edx # switch to interp<- true
- jmp common_gotoBail # bail
-
-
- /*
- * Get save area; rGLUE is %ebx, rFP is %eax
- */
-4:
- SAVEAREA_FROM_FP %ecx # %ecx<- saveArea(old)
- movl offStackSaveArea_prevFrame(%ecx), rFP # rFP<- saveArea->PrevFrame
- movl (offStackSaveArea_method - sizeofStackSaveArea)(rFP), %edx # %edx<- method we are returning to
- cmpl $$0, %edx # check for break frame
- je common_gotoBail # bail if break frame
- movl offStackSaveArea_savedPc(%ecx), rPC # rPC<- saveAreaOld->savedPc
- movl offGlue_self(rINST), %ecx # %eax<- glue->self
- movl %edx, offGlue_method(rINST) # glue->method<- newSave->method
- movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
- FFETCH_ADV 3, %eax # %ecx<- next instruction hi; fetch, advance
- movl rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
- movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
- movl %edx, offGlue_methodClassDex(rINST) # glue->pDvmDex<- method->clazz->pDvmDex
- FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
-
- /*
- * Handle thrown an exception. If the exception processing code
- * returns to us (instead of falling out of the interpreter),
- * continue with whatever the next instruction now happens to be.
- * This does not return.
- */
-
-common_exceptionThrown:
-.LexceptionNew:
- movl $$kInterpEntryThrow, %ecx # %ecx<- reentry type
- movl $$0, %edx # %edx<- pc adjustment
- call common_periodicChecks
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_self(%eax), %edx # %edx<- glue->self
- movl offThread_exception(%edx), %ecx # %ecx<- pMterpGlue->self->exception
- movl %edx, -4(%esp) # push parameter self
- movl %ecx, -8(%esp) # push parameter obj
- lea -8(%esp), %esp
- call dvmAddTrackedAlloc # don't allow the exception to be GC'd
- # call: (Object* obj, Thread* self)
- # return: void
- movl 4(%esp), %edx # %edx<- glue->self
- movl $$0, offThread_exception(%edx) # glue->self->exception<- NULL
-
- /*
- * set up args and a local for &fp
- */
-
- movl rFP, -4(%esp) # move fp to stack
- lea -4(%esp), %esp # update %esp
- movl %esp, -4(%esp) # push parameter 4<- &fp
- movl $$0, -8(%esp) # push parameter 3<- false
- movl 4(%esp), %edx
- movl %edx, -12(%esp) # push parameter 2<- glue->self->exception
- movl rGLUE, %eax # %eax<- pMterpGlue
- movl offGlue_method(%eax), %edx # %edx<- glue->method
- movl offMethod_insns(%edx), %edx # %edx<- glue->method->insns
- movl rPC, %ecx # %ecx<- rPC
- subl %edx, %ecx # %ecx<- pc - glue->method->insns
- sar $$1, %ecx # %ecx<- adjust %ecx for offset
- movl %ecx, -16(%esp) # push parameter 1<- glue->method->insns
- movl 8(%esp), %edx
- movl %edx, -20(%esp) # push parameter 0<- glue->self
- lea -20(%esp), %esp
-
- /*
- * call dvmFindCatchBlock, %eax gets catchRelPc (a code-unit offset)
- */
-
- call dvmFindCatchBlock # call: (Thread* self, int relPc, Object* exception,
- # bool doUnroll, void** newFrame)
- # return: int
- lea 32(%esp), %esp
- movl -12(%esp), rFP # rFP<- updated rFP
- cmp $$0, %eax # check for catchRelPc < 0
- jl .LnotCaughtLocally # handle not caught locally
-
- /*
- * fix stack overflow if necessary
- */
-
- movl -4(%esp), %ecx # %ecx<- glue->self
- cmp $$0, offThread_stackOverflowed(%ecx)
- je 1f
- movl %eax, -4(%esp) # save %eax for later
- movl %ecx, -12(%esp) # push parameter 2 glue->self
- lea -12(%esp), %esp
- call dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
- # return: void
- lea 12(%esp), %esp
- movl -4(%esp), %eax # %eax<- restore %eax
- jmp 2f
-1:
- movl %ecx, -12(%esp) # push parameter 2 glue->self
-2:
-
- /*
- * adjust locals to match self->curFrame and updated PC
- *
- */
-
- SAVEAREA_FROM_FP %edx # %edx<- get newSaveArea
- movl rGLUE, %ecx # %ecx<- pMterpGlue
- movl offStackSaveArea_method(%edx), rPC # rPC<- newMethod
- movl rPC, offGlue_method(%ecx) # glue->method<- newMethod
- movl offMethod_clazz(rPC), %edx # %edx<- method->clazz
- movl offMethod_insns(rPC), rPC # rPC<- method->insns
- movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
- lea (rPC, %eax, 2), rPC # rPC<- method->insns + catchRelPc
- movl %edx, offGlue_methodClassDex(%ecx) # glue->pDvmDex<- method->clazz->pDvmDex
- movl -8(%esp), %eax
- movl %eax, -16(%esp) # push parameter 1 obj
- lea -16(%esp), %esp
- call dvmReleaseTrackedAlloc # call: (Object* obj, Thread* self)
- # return: void
- lea 16(%esp), %esp
- FINISH_FETCH %eax
- cmp $$OP_MOVE_EXCEPTION, %eax # is it a move exception
- jne 1f
- movl -12(%esp), %edx # %edx<- glue->self
- movl -8(%esp), %ecx # %ecx<- exception
- movl %ecx, offThread_exception(%edx) # restore the exception
-1:
- FINISH_JMP %eax
-
- /*
- * -8(%esp) = exception, -4(%esp) = self
- */
-
-.LnotCaughtLocally:
- movl -4(%esp), %edx # %edx<- glue->self
- movzb offThread_stackOverflowed(%edx), %eax # %eax<- self->stackOverflowed
- cmp $$0, %eax # check for stack overflow;
- # maybe should use cmpb
- je 1f #
- movl %edx, -12(%esp) # push parameter 1 glue->self
- lea -12(%esp), %esp
- call dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
- # return: void
- lea 12(%esp), %esp
-
- /*
- * Release the exception
- * -8(%esp) = exception, -4(%esp) = self
- */
-1:
- movl -8(%esp), %ecx # %ecx<- exception
- movl -4(%esp), %edx # %edx<- glue->self
- movl %ecx, offThread_exception(%edx) # glue->self<- exception
- lea -8(%esp), %esp
- call dvmReleaseTrackedAlloc # call: (Object* obj, Thread* self)
- # return: void
- lea 8(%esp), %esp
- movl $$0, %edx # switch to interp<- false
- jmp common_gotoBail # bail
-
- /*
- * After returning from a "glued" function, pull out the updated
- * values and start executing at the next instruction.
- */
-
-common_resumeAfterGlueCall:
- LOAD_PC_FP_FROM_GLUE # pull rPC and rFP out of glue
- FINISH_A # jump to next instruction
-
- /*
- * For debugging, cause an immediate fault.
- */
-
-common_abort:
- jmp .LdeadFood
-
-.LdeadFood:
-.int 0xdeadf00d
-
- /*
- * Invalid array index.
- */
-
-common_errArrayIndex:
- EXPORT_PC
- movl $$.LstrArrayIndexException, -8(%esp) # push parameter description
- movl $$0, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * Invalid array value.
- */
-
-common_errArrayStore:
- EXPORT_PC
- movl $$.LstrArrayStoreException, -8(%esp) # push parameter description
- movl $$0, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * Integer divide or mod by zero.
- */
-
-common_errDivideByZero:
- EXPORT_PC
- movl $$.LstrArithmeticException, -8(%esp) # push parameter description
- movl $$.LstrDivideByZero, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * Attempt to allocate an array with a negative size.
- */
-
-common_errNegativeArraySize:
- EXPORT_PC
- movl $$.LstrNegativeArraySizeException, -8(%esp) # push parameter description
- movl $$0, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * Invocation of a non-existent method.
- */
-
-common_errNoSuchMethod:
- EXPORT_PC
- movl $$.LstrNoSuchMethodError, -8(%esp) # push parameter description
- movl $$0, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * Unexpected null object.
- */
-
-common_errNullObject:
- EXPORT_PC
- movl $$.LstrNullPointerException, -8(%esp) # push parameter description
- movl $$0, -4(%esp) # push parameter msg paramter
- lea -8(%esp), %esp
- call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
- # return: void
- lea 8(%esp), %esp
- jmp common_exceptionThrown # handle exception
-
- /*
- * String references
- */
-
- .align 4
- .section .rodata
-.LstrArithmeticException:
- .asciz "Ljava/lang/ArithmeticException;"
-.LstrArrayIndexException:
- .asciz "Ljava/lang/ArrayIndexOutOfBoundsException;"
-.LstrArrayStoreException:
- .asciz "Ljava/lang/ArrayStoreException;"
-.LstrDivideByZero:
- .asciz "divide by zero"
-.LstrInstantiationError:
- .asciz "Ljava/lang/InstantiationError;"
-.LstrNegativeArraySizeException:
- .asciz "Ljava/lang/NegativeArraySizeException;"
-.LstrNoSuchMethodError:
- .asciz "Ljava/lang/NoSuchMethodError;"
-.LstrNullPointerException:
- .asciz "Ljava/lang/NullPointerException;"
-.LstrExceptionNotCaughtLocally:
- .asciz "Exception %s from %s:%d not caught locally\n"
diff --git a/vm/mterp/x86-atom/header.S b/vm/mterp/x86-atom/header.S
deleted file mode 100644
index 28c19d6..0000000
--- a/vm/mterp/x86-atom/header.S
+++ /dev/null
@@ -1,433 +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.
- */
-
- /*
- * File: header.S
- */
-
- /*
- * IA32 calling convention and general notes:
- *
- * EAX, ECX, EDX - general purpose scratch registers (caller-saved);
- *
- * The stack (%esp) - used to pass arguments to functions
- *
- * EAX - holds the first 4 bytes of a return
- * EDX - holds the second 4 bytes of a return
- *
- * EBX, ESI, EDI, EBP - are callee saved
- *
- * CS, DS, SS - are segment registers
- * ES, FS, GS - are segment registers. We will try to avoid using these registers
- *
- * The stack is "full descending". Only the arguments that do not fit * in the first two arg registers are placed on the stack.
- * "%esp" points to the first stacked argument (i.e. the 3rd arg).
- */
-
- /*
- * Mterp and IA32 notes
- *
- * mem nick purpose
- * (%ebp) rGLUE InterpState base pointer (A.K.A. MterpGlue Pointer)
- * %esi rPC interpreted program counter, used for fetching
- * instructions
- * %ebx rINST first 16-bit code unit of current instruction
- * %edi rFP interpreted frame pointer, used for accessing
- * locals and args
- */
-
- /*
- * Includes
- */
-
-#include "../common/asm-constants.h"
-
- /*
- * Reserved registers
- */
-
-#define rGLUE (%ebp)
-#define rINST %ebx
-#define rINSTbl %bl
-#define rINSTbh %bh
-#define rINSTw %bx
-#define rPC %esi
-#define rFP %edi
-
- /*
- * Temporary register used when finishing an opcode
- */
-
-#define rFinish %edx
-
- /*
- * Stack locations used for temporary data. For convenience.
- */
-
-#define sReg0 4(%ebp)
-#define sReg1 8(%ebp)
-#define sReg2 12(%ebp)
-#define sReg3 16(%ebp)
-
- /*
- * Save the PC and FP to the glue struct
- */
-
- .macro SAVE_PC_FP_TO_GLUE _reg
- movl rGLUE, \_reg
- movl rPC, offGlue_pc(\_reg)
- movl rFP, offGlue_fp(\_reg)
- .endm
-
- /*
- * Restore the PC and FP from the glue struct
- */
-
- .macro LOAD_PC_FP_FROM_GLUE
- movl rGLUE, rFP
- movl offGlue_pc(rFP), rPC
- movl offGlue_fp(rFP), rFP
- .endm
-
- /*
- * "Export" the PC to the stack frame, f/b/o future exception objects. This must
- * be done *before* something calls dvmThrowException.
- *
- * In C this is "SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc", i.e.
- * fp - sizeof(StackSaveArea) + offsetof(SaveArea, xtra.currentPc)
- *
- * It's okay to do this more than once.
- */
-
- .macro EXPORT_PC
- movl rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP)
- .endm
-
- /*
- * Given a frame pointer, find the stack save area.
- * In C this is "((StackSaveArea*)(_fp) -1)".
- */
-
- .macro SAVEAREA_FROM_FP _reg
- lea -sizeofStackSaveArea(rFP), \_reg
- .endm
-
- /*
- * Get the 32-bit value from a dalvik register.
- */
-
- .macro GET_VREG _vreg
- movl (rFP,\_vreg, 4), \_vreg
- .endm
-
- /*
- * Set the 32-bit value from a dalvik register.
- */
-
- .macro SET_VREG _reg _vreg
- movl \_reg, (rFP,\_vreg, 4)
- .endm
-
- /*
- * Fetch the next instruction from rPC into rINST. Does not advance rPC.
- */
-
- .macro FETCH_INST
- movzwl (rPC), rINST
- .endm
-
- /*
- * Fetch the next instruction from the specified offset. Advances rPC
- * to point to the next instruction. "_count" is in 16-bit code units.
- *
- * This must come AFTER anything that can throw an exception, or the
- * exception catch may miss. (This also implies that it must come after
- * EXPORT_PC())
- */
-
- .macro FETCH_ADVANCE_INST _count
- add $$(\_count*2), rPC
- movzwl (rPC), rINST
- .endm
-
- /*
- * Fetch the next instruction from an offset specified by _reg. Updates
- * rPC to point to the next instruction. "_reg" must specify the distance
- * in bytes, *not* 16-bit code units, and may be a signed value.
- */
-
- .macro FETCH_ADVANCE_INST_RB _reg
- addl \_reg, rPC
- movzwl (rPC), rINST
- .endm
-
- /*
- * Fetch a half-word code unit from an offset past the current PC. The
- * "_count" value is in 16-bit code units. Does not advance rPC.
- * For example, given instruction of format: AA|op BBBB, it
- * fetches BBBB.
- */
-
- .macro FETCH _count _reg
- movzwl (\_count*2)(rPC), \_reg
- .endm
-
- /*
- * Fetch a half-word code unit from an offset past the current PC. The
- * "_count" value is in 16-bit code units. Does not advance rPC.
- * This variant treats the value as signed.
- */
-
- .macro FETCHs _count _reg
- movswl (\_count*2)(rPC), \_reg
- .endm
-
- /*
- * Fetch the first byte from an offset past the current PC. The
- * "_count" value is in 16-bit code units. Does not advance rPC.
- * For example, given instruction of format: AA|op CC|BB, it
- * fetches BB.
- */
-
- .macro FETCH_BB _count _reg
- movzbl (\_count*2)(rPC), \_reg
- .endm
-
- /*
- * Fetch the second byte from an offset past the current PC. The
- * "_count" value is in 16-bit code units. Does not advance rPC.
- * For example, given instruction of format: AA|op CC|BB, it
- * fetches CC.
- */
-
- .macro FETCH_CC _count _reg
- movzbl (\_count*2 + 1)(rPC), \_reg
- .endm
-
- /*
- * Fetch the second byte from an offset past the current PC. The
- * "_count" value is in 16-bit code units. Does not advance rPC.
- * This variant treats the value as signed.
- */
-
- .macro FETCH_CCs _count _reg
- movsbl (\_count*2 + 1)(rPC), \_reg
- .endm
-
-
- /*
- * Fetch one byte from an offset past the current PC. Pass in the same
- * "_count" as you would for FETCH, and an additional 0/1 indicating which
- * byte of the halfword you want (lo/hi).
- */
-
- .macro FETCH_B _reg _count _byte
- movzbl (\_count*2+\_byte)(rPC), \_reg
- .endm
-
- /*
- * Put the instruction's opcode field into the specified register.
- */
-
- .macro GET_INST_OPCODE _reg
- movzbl rINSTbl, \_reg
- .endm
-
- /*
- * Begin executing the opcode in _reg.
- */
-
- .macro GOTO_OPCODE _reg
- shl $$${handler_size_bits}, \_reg
- addl $$dvmAsmInstructionStart,\_reg
- jmp *\_reg
- .endm
-
-
-
- /*
- * Macros pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
- * by using a jump table. _rFinish should must be the same register for
- * both macros.
- */
-
- .macro FFETCH _rFinish
- movzbl (rPC), \_rFinish
- .endm
-
- .macro FGETOP_JMPa _rFinish
- movzbl 1(rPC), rINST
- jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
- .endm
-
- /*
- * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
- * by using a jump table. _rFinish and _count should must be the same register for
- * both macros.
- */
-
- .macro FFETCH_ADV _count _rFinish
- movzbl (\_count*2)(rPC), \_rFinish
- .endm
-
- .macro FGETOP_JMP _count _rFinish
- movzbl (\_count*2 + 1)(rPC), rINST
- addl $$(\_count*2), rPC
- jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
- .endm
-
- /*
- * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
- * by using a jump table. _rFinish and _reg should must be the same register for
- * both macros.
- */
-
- .macro FFETCH_ADV_RB _reg _rFinish
- movzbl (\_reg, rPC), \_rFinish
- .endm
-
- .macro FGETOP_RB_JMP _reg _rFinish
- movzbl 1(\_reg, rPC), rINST
- addl \_reg, rPC
- jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
- .endm
-
- /*
- * Attempts to speed up FETCH_INST, GET_INST_OPCODE using
- * a jump table. This macro should be called before FINISH_JMP where
- * rFinish should be the same register containing the opcode value.
- * This is an attempt to split up FINISH in order to reduce or remove
- * potential stalls due to the wait for rFINISH.
- */
-
- .macro FINISH_FETCH _rFinish
- movzbl (rPC), \_rFinish
- movzbl 1(rPC), rINST
- .endm
-
-
- /*
- * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE using
- * a jump table. This macro should be called before FINISH_JMP where
- * rFinish should be the same register containing the opcode value.
- * This is an attempt to split up FINISH in order to reduce or remove
- * potential stalls due to the wait for rFINISH.
- */
-
- .macro FINISH_FETCH_ADVANCE _count _rFinish
- movzbl (\_count*2)(rPC), \_rFinish
- movzbl (\_count*2 + 1)(rPC), rINST
- addl $$(\_count*2), rPC
- .endm
-
- /*
- * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE using
- * a jump table. This macro should be called before FINISH_JMP where
- * rFinish should be the same register containing the opcode value.
- * This is an attempt to split up FINISH in order to reduce or remove
- * potential stalls due to the wait for rFINISH.
- */
-
- .macro FINISH_FETCH_ADVANCE_RB _reg _rFinish
- movzbl (\_reg, rPC), \_rFinish
- movzbl 1(\_reg, rPC), rINST
- addl \_reg, rPC
- .endm
-
- /*
- * Attempts to speed up GOTO_OPCODE using a jump table. This macro should
- * be called after a FINISH_FETCH* instruction where rFinish should be the
- * same register containing the opcode value. This is an attempt to split up
- * FINISH in order to reduce or remove potential stalls due to the wait for rFINISH.
- */
-
- .macro FINISH_JMP _rFinish
- jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
- .endm
-
- /*
- * Attempts to speed up FETCH_INST, GET_INST_OPCODE, GOTO_OPCODE by using
- * a jump table. Uses a single macro - but it should be faster if we
- * split up the fetch for rFinish and the jump using rFinish.
- */
-
- .macro FINISH_A
- movzbl (rPC), rFinish
- movzbl 1(rPC), rINST
- jmp *dvmAsmInstructionJmpTable(,rFinish, 4)
- .endm
-
- /*
- * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE,
- * GOTO_OPCODE by using a jump table. Uses a single macro -
- * but it should be faster if we split up the fetch for rFinish
- * and the jump using rFinish.
- */
-
- .macro FINISH _count
- movzbl (\_count*2)(rPC), rFinish
- movzbl (\_count*2 + 1)(rPC), rINST
- addl $$(\_count*2), rPC
- jmp *dvmAsmInstructionJmpTable(,rFinish, 4)
- .endm
-
- /*
- * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE,
- * GOTO_OPCODE by using a jump table. Uses a single macro -
- * but it should be faster if we split up the fetch for rFinish
- * and the jump using rFinish.
- */
-
- .macro FINISH_RB _reg _rFinish
- movzbl (\_reg, rPC), \_rFinish
- movzbl 1(\_reg, rPC), rINST
- addl \_reg, rPC
- jmp *dvmAsmInstructionJmpTable(,\_rFinish, 4)
- .endm
-
- /*
- * Hard coded helper values.
- */
-
-.balign 16
-
-.LdoubNeg:
- .quad 0x8000000000000000
-
-.L64bits:
- .quad 0xFFFFFFFFFFFFFFFF
-
-.LshiftMask2:
- .quad 0x0000000000000000
-.LshiftMask:
- .quad 0x000000000000003F
-
-.Lvalue64:
- .quad 0x0000000000000040
-
-.LvaluePosInfLong:
- .quad 0x7FFFFFFFFFFFFFFF
-
-.LvalueNegInfLong:
- .quad 0x8000000000000000
-
-.LvalueNanLong:
- .quad 0x0000000000000000
-
-.LintMin:
-.long 0x80000000
-
-.LintMax:
-.long 0x7FFFFFFF
diff --git a/vm/mterp/x86-atom/stub.S b/vm/mterp/x86-atom/stub.S
deleted file mode 100644
index 54f3f54..0000000
--- a/vm/mterp/x86-atom/stub.S
+++ /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.
- */
-
- /*
- * File: stub.S
- */
-
- SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
- pushl rGLUE # push parameter glue
- call dvmMterp_${opcode} # call c-based implementation
- lea 4(%esp), %esp
- LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
- FINISH_A # jump to next instruction
diff --git a/vm/mterp/x86-atom/unop.S b/vm/mterp/x86-atom/unop.S
deleted file mode 100644
index 00f9f8d..0000000
--- a/vm/mterp/x86-atom/unop.S
+++ /dev/null
@@ -1,43 +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.
- */
-
- /*
- * File: unop.S
- *
- * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%ecx = op %edx".
- *
- * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-%default {"preinstr":"", "instr":""}
-
- movl rINST, %ecx # %ecx<- BA+
- shr $$4, %ecx # %ecx<- B
- and $$15, rINST # rINST<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- GET_VREG %ecx # %ecx<- vB
- $preinstr # do operation part 1
- $instr # do operation part 2
- SET_VREG %ecx, rINST # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/unopWide.S b/vm/mterp/x86-atom/unopWide.S
deleted file mode 100644
index 3790a2c..0000000
--- a/vm/mterp/x86-atom/unopWide.S
+++ /dev/null
@@ -1,43 +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.
- */
-
- /*
- * File: unopWide.S
- *
- * Code: Generic 64-bit unary operation. Provide an "instr" variable and a
- * preinstr variable that together specify an instruction that
- * performs, for example, "%xmm0 = op %xmm1".
- *
- * For: neg-double, neg-long, not-long
- *
- * Description: Perform the identified unary operation on the source
- * register, storing the result in the destination register
- *
- * Format: B|A|op (12x)
- *
- * Syntax: op vA, vB
- */
-
-%default {"preinstr":"","result":"%xmm0"}
-
- movl rINST, %ecx # %ecx<- BA+
- shr $$4, rINST # rINST<- B
- and $$15, %ecx # %ecx<- A
- FFETCH_ADV 1, %eax # %eax<- next instruction hi; fetch, advance
- movq (rFP, rINST, 4), %xmm0 # %xmm0<- vB
- $preinstr # do operation part 1
- $instr # do operation part 2
- movq $result, (rFP, %ecx, 4) # vA<- result
- FGETOP_JMP 1, %eax # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/unused.S b/vm/mterp/x86-atom/unused.S
deleted file mode 100644
index 8267709..0000000
--- a/vm/mterp/x86-atom/unused.S
+++ /dev/null
@@ -1,30 +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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
diff --git a/vm/mterp/x86-atom/zcmp.S b/vm/mterp/x86-atom/zcmp.S
deleted file mode 100644
index 6614dba..0000000
--- a/vm/mterp/x86-atom/zcmp.S
+++ /dev/null
@@ -1,53 +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.
- */
-
- /*
- * File: zcmp.S
- *
- * Code: Generic 32-bit comparison operation. Provides a "revcmp"
- * variable to specify the reverse comparison to perform
- *
- * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
- *
- * Description: Branch to the given destination if the given register's
- * value compares with 0 as specified.
- *
- * Format: AA|op BBBB (21t)
- *
- * Syntax: op vAA, +BBBB
- */
-
- cmp $$0, (rFP, rINST, 4) # compare vAA with zero
- j${revcmp} ${opcode}_2f # goto next instruction or branch
- FETCHs 1, %edx # %edx<- BBBB; branch offset
- sal $$1, %edx # %edx<- adjust byte offset
-
- /*
- * Inline common_backwardBranch
- */
-
- js common_periodicChecks_backwardBranch # jump on backwards branch
-1:
- FINISH_RB %edx, %ecx # jump to next instruction
-
- /*
- * FINISH code
- */
-
-${opcode}_2f:
- movzbl 4(rPC), %edx # grab the next opcode
- movzbl 5(rPC), rINST # update the instruction
- addl $$4, rPC # update the program counter
- jmp *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
diff --git a/vm/mterp/x86/OP_ADD_DOUBLE.S b/vm/mterp/x86/OP_ADD_DOUBLE.S
index 9fded29..27a47c1 100644
--- a/vm/mterp/x86/OP_ADD_DOUBLE.S
+++ b/vm/mterp/x86/OP_ADD_DOUBLE.S
@@ -1,2 +1,14 @@
-%verify "executed"
-%include "x86/binflop.S" {"instr":"faddl","load":"fldl","store":"fstpl"}
+ /*
+ * File: OP_ADD_DOUBLE.S
+ */
+
+ movzbl 2(rPC),%eax # eax<- BB
+ movzbl 3(rPC),%ecx # ecx<- CC
+ movq (rFP, %eax, 4), %xmm0 # %xmm0<- vBB
+ movq (rFP, %ecx, 4), %xmm1 # %xmm1<- vCC
+ FETCH_INST_OPCODE 2 %ecx
+ addsd %xmm1, %xmm0
+ ADVANCE_PC 2
+ movq %xmm0, (rFP, rINST, 4) # vAA<- vBB * vCC
+ GOTO_NEXT_R %ecx
+
diff --git a/vm/mterp/x86/OP_ADD_DOUBLE_2ADDR.S b/vm/mterp/x86/OP_ADD_DOUBLE_2ADDR.S
index 81e55ea..d917578 100644
--- a/vm/mterp/x86/OP_ADD_DOUBLE_2ADDR.S
+++ b/vm/mterp/x86/OP_ADD_DOUBLE_2ADDR.S
@@ -1,2 +1,14 @@
-%verify "executed"
-%include "x86/binflop2addr.S" {"instr":"faddl","load":"fldl","store":"fstpl"}
+ /*
+ * File: OP_ADD_DOUBLE_2ADDR.S
+ */
+
+ movzx rINSTbl,%ecx # ecx<- A+
+ andb $$0xf,%cl # ecx<- A
+ sarl $$4,rINST # rINST<- B
+ movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
+ movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vA
+ FETCH_INST_OPCODE 1 %eax
+ addsd %xmm1, %xmm0 # %xmm0<- vA op vB
+ ADVANCE_PC 1
+ movq %xmm0, (rFP, %ecx, 4) # vA<- %xmm0; result
+ GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_EXECUTE_INLINE.S b/vm/mterp/x86/OP_EXECUTE_INLINE.S
index ec91076..c739fdf 100644
--- a/vm/mterp/x86/OP_EXECUTE_INLINE.S
+++ b/vm/mterp/x86/OP_EXECUTE_INLINE.S
@@ -14,14 +14,18 @@
movl rSELF,%ecx
EXPORT_PC
movzwl 2(rPC),%eax # eax<- BBBB
- leal offThread_retval(%ecx),%ecx # ecx<- & self->retval
SPILL(rIBASE) # preserve rIBASE
+ movl offThread_subMode(%ecx), %edx # edx<- submode flags
+ andl $$kSubModeDebugProfile, %edx # debug or profile mode active?
+ jnz .L${opcode}_debugprofile # yes, take slow path
+.L${opcode}_resume:
+ leal offThread_retval(%ecx),%ecx # ecx<- &self->retval
movl %ecx,OUT_ARG4(%esp)
call .L${opcode}_continue # make call; will return after
UNSPILL(rIBASE) # restore rIBASE
testl %eax,%eax # successful?
+ jz common_exceptionThrown # no, handle exception
FETCH_INST_OPCODE 3 %ecx
- je common_exceptionThrown # no, handle exception
ADVANCE_PC 3
GOTO_NEXT_R %ecx
@@ -64,3 +68,39 @@
sall $$4,%eax # index *= sizeof(table entry)
jmp *gDvmInlineOpsTable(%eax)
# will return to caller of .L${opcode}_continue
+
+ /*
+ * We're debugging or profiling.
+ * eax: opIndex
+ */
+.L${opcode}_debugprofile:
+ movl %eax,OUT_ARG0(%esp) # arg0<- BBBB
+ SPILL_TMP1(%eax) # save opIndex
+ call dvmResolveInlineNative # dvmResolveInlineNative(opIndex)
+ movl rSELF,%ecx # restore self
+ testl %eax,%eax # method resolved?
+ movl %eax,%edx # save possibly resolved method in edx
+ UNSPILL_TMP1(%eax) # in case not resolved, restore opIndex
+ jz .L${opcode}_resume # not resolved, just move on
+ SPILL_TMP2(%edx) # save method
+ movl %edx,OUT_ARG0(%esp) # arg0<- method
+ movl %ecx,OUT_ARG1(%esp) # arg1<- self
+ call dvmFastMethodTraceEnter # dvmFastMethodTraceEnter(method,self)
+ movl rSELF,%ecx # restore self
+ UNSPILL_TMP1(%eax) # restore opIndex
+ leal offThread_retval(%ecx),%ecx # ecx<- &self->retval
+ movl %ecx,OUT_ARG4(%esp) # needed for pResult of inline operation handler
+ call .L${opcode}_continue # make call; will return after
+ SPILL_TMP1(%eax) # save result of inline
+ UNSPILL_TMP2(%eax) # restore method
+ movl rSELF,%ecx # restore self
+ movl %eax,OUT_ARG0(%esp) # arg0<- method
+ movl %ecx,OUT_ARG1(%esp) # arg1<- self
+ call dvmFastNativeMethodTraceExit # dvmFastNativeMethodTraceExit(method,self)
+ UNSPILL(rIBASE) # restore rIBASE
+ UNSPILL_TMP1(%eax) # restore result of inline
+ testl %eax,%eax # successful?
+ jz common_exceptionThrown # no, handle exception
+ FETCH_INST_OPCODE 3 %ecx
+ ADVANCE_PC 3
+ GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_GOTO.S b/vm/mterp/x86/OP_GOTO.S
index 2fc4c31..a7913d1 100644
--- a/vm/mterp/x86/OP_GOTO.S
+++ b/vm/mterp/x86/OP_GOTO.S
@@ -12,4 +12,9 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $$0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
diff --git a/vm/mterp/x86/OP_GOTO_16.S b/vm/mterp/x86/OP_GOTO_16.S
index de0903c..84220d0 100644
--- a/vm/mterp/x86/OP_GOTO_16.S
+++ b/vm/mterp/x86/OP_GOTO_16.S
@@ -11,4 +11,9 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $$0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
diff --git a/vm/mterp/x86/OP_GOTO_32.S b/vm/mterp/x86/OP_GOTO_32.S
index 84806b0..c3d1050 100644
--- a/vm/mterp/x86/OP_GOTO_32.S
+++ b/vm/mterp/x86/OP_GOTO_32.S
@@ -11,4 +11,9 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $$0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
diff --git a/vm/mterp/x86/OP_INVOKE_INTERFACE.S b/vm/mterp/x86/OP_INVOKE_INTERFACE.S
index 3fa4c94..26d2d5c 100644
--- a/vm/mterp/x86/OP_INVOKE_INTERFACE.S
+++ b/vm/mterp/x86/OP_INVOKE_INTERFACE.S
@@ -18,6 +18,7 @@
EXPORT_PC
testl %eax,%eax # null this?
je common_errNullObject # yes, fail
+ movl %eax, TMP_SPILL1(%ebp)
movl offObject_clazz(%eax),%eax# eax<- thisPtr->clazz
movl %eax,OUT_ARG0(%esp) # arg0<- class
movl offThread_methodClassDex(%ecx),%eax # eax<- methodClassDex
@@ -29,4 +30,5 @@
call dvmFindInterfaceMethodInCache # eax<- call(class, ref, method, dex)
testl %eax,%eax
je common_exceptionThrown
+ movl TMP_SPILL1(%ebp), %ecx
jmp common_invokeMethod${routine}
diff --git a/vm/mterp/x86/OP_INVOKE_OBJECT_INIT_RANGE.S b/vm/mterp/x86/OP_INVOKE_OBJECT_INIT_RANGE.S
index fb84b32..d5d10a6 100644
--- a/vm/mterp/x86/OP_INVOKE_OBJECT_INIT_RANGE.S
+++ b/vm/mterp/x86/OP_INVOKE_OBJECT_INIT_RANGE.S
@@ -1,4 +1,57 @@
+%default { "jumbo":"0", "cccc":"2" }
%verify "executed"
+%verify "finalizable class"
/*
- * TODO (currently punting to stub)
+ * Invoke Object.<init> on an object. In practice we know that
+ * Object's nullary constructor doesn't do anything, so we just
+ * skip it unless a debugger is active.
*/
+ movzwl 4(rPC),%eax # eax<- CCCC, offset = 2 * cccc, cccc = 4 for jumbo
+ GET_VREG_R %ecx, %eax # ecx<- "this" ptr
+ testl %ecx,%ecx # null this?
+ je common_errNullObject # yes, fail
+ movl offObject_clazz(%ecx), %eax # eax<- obj->clazz
+ SPILL_TMP1(rIBASE) # save %edx
+ movl offClassObject_accessFlags(%eax), %edx # edx<- clazz->accessFlags
+ andl $$CLASS_ISFINALIZABLE, %edx # is this class finalizable?
+ jnz .L${opcode}_setFinal # yes, go
+.L${opcode}_finish:
+ movl rSELF, %ecx
+ movl offThread_subMode(%ecx), %eax
+ andl $$kSubModeDebuggerActive, %eax # debugger active?
+ jnz .L${opcode}_debugger # Yes - skip optimization
+ UNSPILL_TMP1(rIBASE)
+ FETCH_INST_OPCODE 3 %ecx # 3 = cccc + 1
+ ADVANCE_PC 3
+ GOTO_NEXT_R %ecx
+%break
+
+.L${opcode}_setFinal:
+ EXPORT_PC # can throw
+ movl %ecx, OUT_ARG0(%esp) # arg1<- obj
+ call dvmSetFinalizable # call dvmSetFinalizable(obj)
+ movl rSELF, %ecx
+ movl offThread_exception(%ecx), %eax # eax<- self->exception
+ cmpl $$0, %eax # exception pending?
+ jne common_exceptionThrown # yes, handle it
+ jmp .L${opcode}_finish
+
+ /*
+ * A debugger is attached, so we need to go ahead and do
+ * this. For simplicity, we'll just jump directly to the
+ * corresponding handler. Note that we can't use
+ * rIBASE here because it may be in single-step mode.
+ * Load the primary table base directly.
+ */
+.L${opcode}_debugger:
+ movl offThread_mainHandlerTable(%ecx), %ecx # load main handler table
+ .if $jumbo # if jumbo is enabled
+ movl $$OP_INVOKE_DIRECT_JUMBO, %eax
+ .else
+ movl $$OP_INVOKE_DIRECT_RANGE, %eax
+ .endif
+ /*
+ * We can't use GOTO_NEXT here since we want to jump directly to
+ * handler without touching rIBASE.
+ */
+ jmp *(%ecx,%eax,4)
diff --git a/vm/mterp/x86/OP_INVOKE_STATIC.S b/vm/mterp/x86/OP_INVOKE_STATIC.S
index ca68a84..d5004bc 100644
--- a/vm/mterp/x86/OP_INVOKE_STATIC.S
+++ b/vm/mterp/x86/OP_INVOKE_STATIC.S
@@ -13,9 +13,17 @@
movl offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
EXPORT_PC
movl offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
+#if defined(WITH_JIT)
+ movl %edx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4), %edx
+ movl %edx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %edx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved methodToCall
+ movl $$0, %ecx # make "this" null
testl %eax,%eax
jne common_invokeMethod${routine}
+
movl rSELF,%ecx
movl offThread_method(%ecx),%ecx # ecx<- self->method
movzwl 2(rPC),%eax
@@ -24,7 +32,37 @@
movl %ecx,OUT_ARG0(%esp) # arg0<- clazz
movl $$METHOD_STATIC,%eax
movl %eax,OUT_ARG2(%esp) # arg2<- flags
+ SPILL(rIBASE)
call dvmResolveMethod # call(clazz,ref,flags)
+ UNSPILL(rIBASE)
testl %eax,%eax # got null?
+#if defined(WITH_JIT)
+ movl TMP_SPILL1(%ebp), %edx
+ movl rSELF,%ecx
+ movzwl offThread_subMode(%ecx), %ecx
+ je common_exceptionThrown # null, handle exception
+ andl $$kSubModeJitTraceBuild, %ecx # is trace under construction?
+ movl $$0, %ecx # make "this" null
+ je common_invokeMethod${routine} # no (%eax=method, %ecx="this")
+ movl TMP_SPILL2(%ebp), %edx
+ cmpl $$0, (%edx) # finished resolving
+ movl TMP_SPILL1(%ebp), %edx
+ jne common_invokeMethod${routine} # yes (%eax=method, %ecx="this")
+ movl rSELF, %edx
+ movl %edx, OUT_ARG0(%esp)
+ movl rPC, OUT_ARG1(%esp)
+ movl %eax, TMP_SPILL2(%ebp)
+ movl %ecx, TMP_SPILL3(%ebp)
+ SPILL(rIBASE)
+ call dvmJitEndTraceSelect
+ UNSPILL(rIBASE)
+ movl TMP_SPILL1(%ebp), %edx
+ movl TMP_SPILL2(%ebp), %eax
+ movl TMP_SPILL3(%ebp), %ecx
+ jmp common_invokeMethod${routine}
+#else
+ movl $$0, %ecx # make "this" null
jne common_invokeMethod${routine}
jmp common_exceptionThrown
+#endif
+
diff --git a/vm/mterp/x86/OP_INVOKE_SUPER.S b/vm/mterp/x86/OP_INVOKE_SUPER.S
index ecee028..d210daf 100644
--- a/vm/mterp/x86/OP_INVOKE_SUPER.S
+++ b/vm/mterp/x86/OP_INVOKE_SUPER.S
@@ -19,8 +19,9 @@
.if (!$isrange)
andl $$0xf,rINST # rINST<- D (or stays CCCC)
.endif
- GET_VREG_R rINST rINST # rINST<- "this" ptr
- testl rINST,rINST # null "this"?
+ GET_VREG_R %edx rINST # %edx<- "this" ptr
+ testl %edx,%edx # null "this"?
+ SPILL_TMP1(%edx)
je common_errNullObject # yes, throw
movl offMethod_clazz(%eax),%eax # eax<- method->clazz
testl %ecx,%ecx # already resolved?
@@ -32,11 +33,13 @@
*/
.L${opcode}_continue:
movl offClassObject_super(%eax),%eax # eax<- method->clazz->super
- movzwl offMethod_methodIndex(%ecx),%ecx # ecx<- baseMthod->methodIndex
- cmpl offClassObject_vtableCount(%eax),%ecx # compare(methodIndex,vtableCount)
+ movzwl offMethod_methodIndex(%ecx),%edx # edx<- baseMthod->methodIndex
+ cmpl offClassObject_vtableCount(%eax),%edx # compare(methodIndex,vtableCount)
jae .L${opcode}_nsm # method not present in superclass
movl offClassObject_vtable(%eax),%eax # eax<- ...clazz->super->vtable
- movl (%eax,%ecx,4),%eax # eax<- vtable[methodIndex]
+ movl (%eax,%edx,4),%eax # eax<- vtable[methodIndex]
+ UNSPILL_TMP1(%edx)
+ movl %edx, %ecx
jmp common_invokeMethod${routine}
@@ -45,7 +48,7 @@
* eax = method->clazz
*/
.L${opcode}_resolve:
- SPILL_TMP1(%eax) # method->clazz
+ SPILL_TMP2(%eax) # method->clazz
movl %eax,OUT_ARG0(%esp) # arg0<- method->clazz
movzwl 2(rPC),%ecx # ecx<- BBBB
movl $$METHOD_VIRTUAL,OUT_ARG2(%esp) # arg2<- resolver method type
@@ -53,7 +56,7 @@
call dvmResolveMethod # eax<- call(clazz, ref, flags)
testl %eax,%eax # got null?
movl %eax,%ecx # ecx<- resolved base method
- UNSPILL_TMP1(%eax) # restore method->clazz
+ UNSPILL_TMP2(%eax) # restore method->clazz
jne .L${opcode}_continue # good to go - continue
jmp common_exceptionThrown # handle exception
diff --git a/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S b/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
index 5fe098c..b93fce5 100644
--- a/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
+++ b/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
@@ -19,8 +19,10 @@
movl offClassObject_super(%ecx),%ecx # ecx<- method->clazz->super
testl %eax,%eax # null "this"?
je common_errNullObject # "this" is null, throw exception
+ movl %eax, TMP_SPILL1(%ebp)
movzwl 2(rPC),%eax # eax<- BBBB
movl offClassObject_vtable(%ecx),%ecx # ecx<- vtable
EXPORT_PC
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
+ movl TMP_SPILL1(%ebp), %ecx
jmp common_invokeMethod${routine}
diff --git a/vm/mterp/x86/OP_INVOKE_VIRTUAL.S b/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
index 24d0170..23dee67 100644
--- a/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
@@ -42,7 +42,7 @@
movzwl offMethod_methodIndex(%eax),%eax # eax<- baseMethod->methodIndex
testl %ecx,%ecx # null this?
je common_errNullObject # go if so
- movl offObject_clazz(%ecx),%ecx # ecx<- thisPtr->clazz
- movl offClassObject_vtable(%ecx),%ecx # ecx<- thisPtr->clazz->vtable
- movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
+ movl offObject_clazz(%ecx),%edx # edx<- thisPtr->clazz
+ movl offClassObject_vtable(%edx),%edx # edx<- thisPtr->clazz->vtable
+ movl (%edx,%eax,4),%eax # eax<- vtable[methodIndex]
jmp common_invokeMethod${routine}
diff --git a/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S b/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S
index 14202d8..58f784d 100644
--- a/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S
@@ -8,16 +8,16 @@
*/
/* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
/* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
- movzwl 4(rPC),%eax # eax<- FEDC or CCCC
- movzwl 2(rPC),%ecx # ecx<- BBBB
+ movzwl 4(rPC),%ecx # eax<- FEDC or CCCC
+ movzwl 2(rPC),%edx # ecx<- BBBB
.if (!$isrange)
- andl $$0xf,%eax # eax<- C (or stays CCCC)
+ andl $$0xf,%ecx # eax<- C (or stays CCCC)
.endif
- GET_VREG_R %eax %eax # eax<- vC ("this" ptr)
- testl %eax,%eax # null?
+ GET_VREG_R %ecx %ecx # ecx<- vC ("this" ptr)
+ testl %ecx,%ecx # null?
je common_errNullObject # yep, throw exception
- movl offObject_clazz(%eax),%eax # eax<- thisPtr->clazz
+ movl offObject_clazz(%ecx),%eax # eax<- thisPtr->clazz
movl offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
EXPORT_PC # might throw later - get ready
- movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
+ movl (%eax,%edx,4),%eax # eax<- vtable[BBBB]
jmp common_invokeMethod${routine}
diff --git a/vm/mterp/x86/OP_MUL_DOUBLE.S b/vm/mterp/x86/OP_MUL_DOUBLE.S
index 59a2079..7d74f78 100644
--- a/vm/mterp/x86/OP_MUL_DOUBLE.S
+++ b/vm/mterp/x86/OP_MUL_DOUBLE.S
@@ -1,2 +1,14 @@
-%verify "executed"
-%include "x86/binflop.S" {"instr":"fmull","load":"fldl","store":"fstpl"}
+ /*
+ * File: OP_MUL_DOUBLE.S
+ */
+
+ movzbl 2(rPC),%eax # eax<- BB
+ movzbl 3(rPC),%ecx # ecx<- CC
+ # TODO: movsd?
+ movq (rFP, %eax, 4), %xmm0 # %xmm0<- vBB
+ movq (rFP, %ecx, 4), %xmm1 # %xmm1<- vCC
+ FETCH_INST_OPCODE 2 %ecx
+ mulsd %xmm1, %xmm0
+ ADVANCE_PC 2
+ movq %xmm0, (rFP, rINST, 4) # vAA<- vBB * vCC
+ GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MUL_DOUBLE_2ADDR.S b/vm/mterp/x86/OP_MUL_DOUBLE_2ADDR.S
index 45a2fa3..d277689 100644
--- a/vm/mterp/x86/OP_MUL_DOUBLE_2ADDR.S
+++ b/vm/mterp/x86/OP_MUL_DOUBLE_2ADDR.S
@@ -1,2 +1,15 @@
-%verify "executed"
-%include "x86/binflop2addr.S" {"instr":"fmull","load":"fldl","store":"fstpl"}
+ /*
+ * File: OP_MUL_DOUBLE_2ADDR.S
+ */
+
+ movzx rINSTbl,%ecx # ecx<- A+
+ andb $$0xf,%cl # ecx<- A
+ sarl $$4,rINST # rINST<- B
+ # TODO: movsd?
+ movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
+ movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vA
+ FETCH_INST_OPCODE 1 %eax
+ mulsd %xmm1, %xmm0 # %xmm0<- vA op vB
+ ADVANCE_PC 1
+ movq %xmm0, (rFP, %ecx, 4) # vA<- %xmm0; result
+ GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_NEW_INSTANCE.S b/vm/mterp/x86/OP_NEW_INSTANCE.S
index 3e268c4..5638e10 100644
--- a/vm/mterp/x86/OP_NEW_INSTANCE.S
+++ b/vm/mterp/x86/OP_NEW_INSTANCE.S
@@ -14,8 +14,12 @@
movzwl 2(rPC),%eax # eax<- BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
SPILL(rIBASE)
+ SPILL_TMP2(%ebx)
movl offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
EXPORT_PC
+#if defined(WITH_JIT)
+ lea (%ecx,%eax,4),%ebx # ebx <- &resolved class
+#endif
movl (%ecx,%eax,4),%ecx # ecx<- resolved class
testl %ecx,%ecx # resolved?
je .L${opcode}_resolve # no, go do it
@@ -26,14 +30,48 @@
movl $$ALLOC_DONT_TRACK,OUT_ARG1(%esp)
movl %ecx,OUT_ARG0(%esp)
call dvmAllocObject # eax<- new object
- FETCH_INST_OPCODE 2 %ecx
- UNSPILL(rIBASE)
testl %eax,%eax # success?
je common_exceptionThrown # no, bail out
+#if defined(WITH_JIT)
+ /*
+ * The JIT needs the class to be fully resolved before it can
+ * include this instruction in a trace.
+ */
+ movl rSELF, %ecx
+ movl offThread_subMode(%ecx), %ecx
+ andl $$kSubModeJitTraceBuild, %ecx # under construction?
+ jne .L${opcode}_jitCheck
+#endif
+.L${opcode}_end:
+ UNSPILL_TMP2(%ebx)
SET_VREG %eax rINST
+ UNSPILL(rIBASE)
+ FETCH_INST_OPCODE 2 %ecx
ADVANCE_PC 2
GOTO_NEXT_R %ecx
+#if defined(WITH_JIT)
+ /*
+ * Check to see if we need to stop the trace building early.
+ * eax: new object
+ */
+.L${opcode}_jitCheck:
+ cmp $$0, (%ebx) # okay?
+ jne .L${opcode}_end # yes, finish
+ SPILL_TMP1(%eax) # preserve new object
+ movl rSELF, %ecx
+ movl %ecx, OUT_ARG0(%esp)
+ movl rPC, OUT_ARG1(%esp)
+ call dvmJitEndTraceSelect # (self, pc)
+ UNSPILL_TMP1(%eax)
+ UNSPILL_TMP2(%ebx)
+ SET_VREG %eax rINST # vAA <- new object
+ UNSPILL(rIBASE)
+ FETCH_INST_OPCODE 2 %ecx
+ ADVANCE_PC 2
+ GOTO_NEXT_R %ecx
+#endif
+
/*
* Class initialization required.
*
diff --git a/vm/mterp/x86/OP_PACKED_SWITCH.S b/vm/mterp/x86/OP_PACKED_SWITCH.S
index c762a8b..af0df62 100644
--- a/vm/mterp/x86/OP_PACKED_SWITCH.S
+++ b/vm/mterp/x86/OP_PACKED_SWITCH.S
@@ -20,4 +20,9 @@
ADVANCE_PC_INDEXED %eax
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $$0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
diff --git a/vm/mterp/x86/OP_SGET.S b/vm/mterp/x86/OP_SGET.S
index 8ff0632..27d63b1 100644
--- a/vm/mterp/x86/OP_SGET.S
+++ b/vm/mterp/x86/OP_SGET.S
@@ -12,6 +12,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .L${opcode}_resolve # if not, make it so
@@ -37,5 +43,11 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .L${opcode}_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .L${opcode}_finish # success, continue
diff --git a/vm/mterp/x86/OP_SGET_WIDE.S b/vm/mterp/x86/OP_SGET_WIDE.S
index 432763d..be97017 100644
--- a/vm/mterp/x86/OP_SGET_WIDE.S
+++ b/vm/mterp/x86/OP_SGET_WIDE.S
@@ -11,6 +11,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .L${opcode}_resolve # if not, make it so
@@ -38,5 +44,11 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .L${opcode}_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .L${opcode}_finish # success, continue
diff --git a/vm/mterp/x86/OP_SPUT.S b/vm/mterp/x86/OP_SPUT.S
index bc76533..57a1543 100644
--- a/vm/mterp/x86/OP_SPUT.S
+++ b/vm/mterp/x86/OP_SPUT.S
@@ -12,6 +12,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .L${opcode}_resolve # if not, make it so
@@ -28,7 +34,7 @@
.L${opcode}_resolve:
movl rSELF,%ecx
movzwl 2(rPC),%eax # eax<- field ref BBBB
- movl offThread_method(%ecx),%ecx # ecx<- current method
+ movl offThread_method(%ecx),%ecx # ecx<- current method
EXPORT_PC # could throw, need to export
movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
movl %eax,OUT_ARG1(%esp)
@@ -37,5 +43,11 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .L${opcode}_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .L${opcode}_finish # success, continue
\ No newline at end of file
diff --git a/vm/mterp/x86/OP_SPUT_OBJECT.S b/vm/mterp/x86/OP_SPUT_OBJECT.S
index 45d84c7..95a0a34 100644
--- a/vm/mterp/x86/OP_SPUT_OBJECT.S
+++ b/vm/mterp/x86/OP_SPUT_OBJECT.S
@@ -10,6 +10,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField
testl %eax,%eax # resolved entry null?
je .L${opcode}_resolve # if not, make it so
@@ -41,5 +47,11 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .L${opcode}_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .L${opcode}_finish # success, continue
diff --git a/vm/mterp/x86/OP_SPUT_WIDE.S b/vm/mterp/x86/OP_SPUT_WIDE.S
index d4c5841..d5825f6 100644
--- a/vm/mterp/x86/OP_SPUT_WIDE.S
+++ b/vm/mterp/x86/OP_SPUT_WIDE.S
@@ -12,6 +12,12 @@
movzwl 2(rPC),%eax # eax<- field ref BBBB
movl offThread_methodClassDex(%ecx),%ecx # ecx<- DvmDex
movl offDvmDex_pResFields(%ecx),%ecx # ecx<- dvmDex->pResFields
+#if defined(WITH_JIT)
+ movl %ecx, TMP_SPILL1(%ebp)
+ lea (%ecx,%eax,4),%ecx
+ movl %ecx, TMP_SPILL2(%ebp)
+ movl TMP_SPILL1(%ebp), %ecx
+#endif
movl (%ecx,%eax,4),%eax # eax<- resolved StaticField ptr
testl %eax,%eax # resolved entry null?
je .L${opcode}_resolve # if not, make it so
@@ -39,5 +45,11 @@
call dvmResolveStaticField # eax<- resolved StaticField ptr
UNSPILL(rIBASE)
testl %eax,%eax
- jne .L${opcode}_finish # success, continue
- jmp common_exceptionThrown # no, handle exception
+ je common_exceptionThrown # no, handle exception
+#if defined(WITH_JIT)
+ movl TMP_SPILL2(%ebp), %ecx
+ SPILL(rIBASE)
+ call common_verifyField
+ UNSPILL(rIBASE)
+#endif
+ jmp .L${opcode}_finish # success, continue
diff --git a/vm/mterp/x86/OP_SUB_DOUBLE.S b/vm/mterp/x86/OP_SUB_DOUBLE.S
index 224f3a1..cf84a65 100644
--- a/vm/mterp/x86/OP_SUB_DOUBLE.S
+++ b/vm/mterp/x86/OP_SUB_DOUBLE.S
@@ -1,2 +1,14 @@
-%verify "executed"
-%include "x86/binflop.S" {"instr":"fsubl","load":"fldl","store":"fstpl"}
+ /*
+ * File: OP_SUB_DOUBLE.S
+ */
+
+ movzbl 2(rPC),%eax # eax<- BB
+ movzbl 3(rPC),%ecx # ecx<- CC
+ # TODO: movsd?
+ movq (rFP, %eax, 4), %xmm0 # %xmm0<- vBB
+ movq (rFP, %ecx, 4), %xmm1 # %xmm1<- vCC
+ FETCH_INST_OPCODE 2 %ecx
+ subsd %xmm1, %xmm0
+ ADVANCE_PC 2
+ movq %xmm0, (rFP, rINST, 4) # vAA<- vBB - vCC
+ GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_SUB_DOUBLE_2ADDR.S b/vm/mterp/x86/OP_SUB_DOUBLE_2ADDR.S
index 991c380..05dce86 100644
--- a/vm/mterp/x86/OP_SUB_DOUBLE_2ADDR.S
+++ b/vm/mterp/x86/OP_SUB_DOUBLE_2ADDR.S
@@ -1,2 +1,15 @@
-%verify "executed"
-%include "x86/binflop2addr.S" {"instr":"fsubl","load":"fldl","store":"fstpl"}
+ /*
+ * File: OP_SUB_DOUBLE_2ADDR.S
+ */
+
+ movzx rINSTbl,%ecx # ecx<- A+
+ andb $$0xf,%cl # ecx<- A
+ sarl $$4,rINST # rINST<- B
+ # TODO: movsd?
+ movq (rFP, rINST, 4), %xmm1 # %xmm1<- vB
+ movq (rFP, %ecx, 4), %xmm0 # %xmm0<- vA
+ FETCH_INST_OPCODE 1 %eax
+ subsd %xmm1, %xmm0 # %xmm0<- vA op vB
+ ADVANCE_PC 1
+ movq %xmm0, (rFP, %ecx, 4) # vA<- %xmm0; result
+ GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/bincmp.S b/vm/mterp/x86/bincmp.S
index ffa4a24..ae68dd3 100644
--- a/vm/mterp/x86/bincmp.S
+++ b/vm/mterp/x86/bincmp.S
@@ -21,4 +21,9 @@
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $$0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
diff --git a/vm/mterp/x86/binop2addr.S b/vm/mterp/x86/binop2addr.S
index 7cd8c5b..4d30880 100644
--- a/vm/mterp/x86/binop2addr.S
+++ b/vm/mterp/x86/binop2addr.S
@@ -2,11 +2,7 @@
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
- * This could be an ARM instruction or a function call. (If the result
- * comes back in a register other than r0, you can override "result".)
- *
- * If "chkzero" is set to 1, we perform a divide-by-zero check on
- * vCC (r1). Useful for integer division and modulus.
+ * This could be an instruction or a function call.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
@@ -15,7 +11,7 @@
*/
/* binop/2addr vA, vB */
movzx rINSTbl,%ecx # ecx<- A+
- sarl $$4,rINST # rINST<- B
+ sarl $$4,rINST # rINST<- B
GET_VREG_R %eax rINST # eax<- vB
andb $$0xf,%cl # ecx<- A
$instr # for ex: addl %eax,(rFP,%ecx,4)
diff --git a/vm/mterp/x86/entry.S b/vm/mterp/x86/entry.S
index 3e2a708..f97d6a5 100644
--- a/vm/mterp/x86/entry.S
+++ b/vm/mterp/x86/entry.S
@@ -46,11 +46,19 @@
movl offThread_curFrame(%ecx),rFP
movl offThread_curHandlerTable(%ecx),rIBASE
-/* Remember %esp for future "longjmp" */
+ /* Remember %esp for future "longjmp" */
movl %esp,offThread_bailPtr(%ecx)
- /* Normal case: start executing the instruction at rPC */
+ /* Fetch next instruction before potential jump */
FETCH_INST
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ movl $$0, offThread_inJitCodeCache(%ecx)
+ cmpl $$0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
+
+ /* Normal case: start executing the instruction at rPC */
GOTO_NEXT
.global dvmMterpStdBail
@@ -72,7 +80,7 @@
dvmMterpStdBail:
movl 4(%esp),%ecx # grab self
movl 8(%esp),%eax # changeInterp to return reg
- movl offThread_bailPtr(%ecx),%esp # Restore "setjmp" esp
+ movl offThread_bailPtr(%ecx),%esp # Restore "setjmp" esp
movl %esp,%ebp
addl $$(FRAME_SIZE-4), %ebp # Restore %ebp at point of setjmp
movl EDI_SPILL(%ebp),%edi
@@ -83,6 +91,18 @@
ret # return to dvmMterpStdRun's caller
+#ifdef WITH_JIT
+ .global dvmNcgInvokeInterpreter
+ .type dvmNcgInvokeInterpreter, %function
+/* input: start of method in %eax */
+dvmNcgInvokeInterpreter:
+ movl %eax, rPC
+ movl rSELF, %ecx
+ movl offThread_curHandlerTable(%ecx),rIBASE
+ FETCH_INST_R %ecx # %edx<- opcode
+ GOTO_NEXT_R %ecx # start executing the instruction at rPC
+#endif
+
/*
* Strings
*/
diff --git a/vm/mterp/x86/footer.S b/vm/mterp/x86/footer.S
index 6de4a33..52e55e9 100644
--- a/vm/mterp/x86/footer.S
+++ b/vm/mterp/x86/footer.S
@@ -35,12 +35,14 @@
* the interpreter and code cache. rPC must be set on entry.
*/
dvmJitToInterpPunt:
+ GET_PC
#if defined(WITH_JIT_TUNING)
movl rPC, OUT_ARG0(%esp)
call dvmBumpPunt
#endif
movl rSELF, %ecx
movl offThread_curHandlerTable(%ecx),rIBASE
+ movl $$0, offThread_inJitCodeCache(%ecx)
FETCH_INST_R %ecx
GOTO_NEXT_R %ecx
@@ -77,17 +79,19 @@
#if defined(WITH_JIT_TUNING)
call dvmBumpNoChain
#endif
+ movl %eax, rPC
movl rSELF, %eax
movl rPC,OUT_ARG0(%esp)
movl %eax,OUT_ARG1(%esp)
- call dvmJitGetTraceAddrThread # (pc, self)
+ call dvmJitGetTraceAddrThread # (pc, self)
movl rSELF,%ecx # ecx <- self
movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
cmpl $$0, %eax
jz 1f
- call *%eax # exec translation if we've got one
+ jmp *%eax # exec translation if we've got one
# won't return
1:
+ EXPORT_PC
movl rSELF, %ecx
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST_R %ecx
@@ -95,7 +99,7 @@
/*
* Return from the translation cache and immediately request a
- * translation fro the exit target, but don't attempt to chain.
+ * translation from the exit target, but don't attempt to chain.
* rPC set on entry.
*/
.global dvmJitToInterpTraceSelectNoChain
@@ -103,15 +107,17 @@
#if defined(WITH_JIT_TUNING)
call dvmBumpNoChain
#endif
+ movl %ebx, rPC
+ lea 4(%esp), %esp #to recover the esp update due to function call
movl rSELF, %eax
movl rPC,OUT_ARG0(%esp)
movl %eax,OUT_ARG1(%esp)
- call dvmJitGetTraceAddrThread # (pc, self)
+ call dvmJitGetTraceAddrThread # (pc, self)
movl rSELF,%ecx
cmpl $$0,%eax
movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
jz 1f
- call *%eax # jump to tranlation
+ jmp *%eax # jump to tranlation
# won't return
/* No Translation - request one */
@@ -124,7 +130,8 @@
FETCH_INST_R %ecx # Continue interpreting if not
GOTO_NEXT_R %ecx
2:
- movl $$kJitTSelectRequestHot,rINST # ask for trace select
+ ## Looks like an EXPORT_PC is needed here. Now jmp to common_selectTrace2
+ movl $$kJitTSelectRequestHot,%eax # ask for trace select
jmp common_selectTrace
/*
@@ -134,21 +141,32 @@
*/
.global dvmJitToInterpTraceSelect
dvmJitToInterpTraceSelect:
- pop rINST # save chain cell address in callee save reg
- movl (rINST),rPC
+ movl 0(%esp), %eax # get return address
+ movl %ebx, rPC # get first argument (target rPC)
+
+ ## TODO, need to clean up stack manipulation ... this isn't signal safe and
+ ## doesn't use the calling conventions of header.S
+ lea 4(%esp), %esp #to recover the esp update due to function call
+
+ ## An additional 5B instruction "jump 0" was added for a thread-safe
+ ## chaining cell update in JIT code cache. So the offset is now -17=-12-5.
+ lea -17(%eax), %ebx #$$JIT_OFFSET_CHAIN_START(%eax), %ebx
+ lea -4(%esp), %esp
movl rSELF, %eax
movl rPC,OUT_ARG0(%esp)
movl %eax,OUT_ARG1(%esp)
call dvmJitGetTraceAddrThread # (pc, self)
+ lea 4(%esp), %esp
cmpl $$0,%eax
+ movl rSELF, %ecx
+ movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
jz 1b # no - ask for one
movl %eax,OUT_ARG0(%esp)
-# TODO - need to adjust rINST to beginning of sequence
movl rINST,OUT_ARG1(%esp)
call dvmJitChain # Attempt dvmJitChain(codeAddr,chainAddr)
cmpl $$0,%eax # Success?
jz toInterpreter # didn't chain - interpret
- call *%eax
+ jmp *%eax
# won't return
/*
@@ -156,71 +174,210 @@
*/
.global dvmJitToInterpBackwardBranch
dvmJitToInterpBackwardBranch:
+
+ .global dvmJitToExceptionThrown
+dvmJitToExceptionThrown: //rPC in
+ movl rSELF, %edx
+ GET_PC
+ movl $$0, offThread_inJitCodeCache(%edx)
+ jmp common_exceptionThrown
+
.global dvmJitToInterpNormal
dvmJitToInterpNormal:
+/* one input: the target rPC value */
+ movl 0(%esp), %eax # get return address
+ movl %ebx, rPC # get first argument (target rPC)
+
+ ## TODO, need to clean up stack manipulation ... this isn't signal safe and
+ ## doesn't use the calling conventions of header.S
+
+ ## An additional 5B instruction "jump 0" was added for a thread-safe
+ ## chaining cell update in JIT code cache. So the offset is now -17=-12-5.
+ lea -17(%eax), %ebx #$$JIT_OFFSET_CHAIN_START(%eax), %ebx
+ lea 4(%esp), %esp
+ movl rPC, OUT_ARG0(%esp)
+ movl rSELF, %ecx
+ movl %ecx, OUT_ARG1(%esp)
+ call dvmJitGetTraceAddrThread
+ ## Here is the change from using rGLUE to rSELF for accessing the
+ ## JIT code cache flag
+ movl rSELF, %ecx
+ movl %eax, offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
+ #lea 4(%esp), %esp
+ cmp $$0, %eax
+ je toInterpreter
+ #lea -8(%esp), %esp
+ movl %ebx, OUT_ARG1(%esp) # %ebx live thorugh dvmJitGetTraceAddrThread
+ movl %eax, OUT_ARG0(%esp) # first argument
+ call dvmJitChain
+ #lea 8(%esp), %esp
+ cmp $$0, %eax
+ je toInterpreter
+ jmp *%eax #to native address
+
.global dvmJitToInterpNoChain
dvmJitToInterpNoChain:
+dvmJitToInterpNoChain: #rPC in eax
+ ## TODO, need to clean up stack manipulation ... this isn't signal safe and
+ ## doesn't use the calling conventions of header.S
+ movl %eax, rPC
+ movl rPC, OUT_ARG0(%esp)
+ movl rSELF, %ecx
+ movl %ecx, OUT_ARG1(%esp)
+ call dvmJitGetTraceAddrThread
+ ## Here is the change from using rGLUE to rSELF for accessing the
+ ## JIT code cache flag
+ movl rSELF, %ecx
+ movl %eax, offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
+ cmp $$0, %eax
+ je toInterpreter
+ jmp *%eax #to native address
+
toInterpreter:
- jmp common_abort
+ EXPORT_PC
+ movl rSELF, %ecx
+ movl offThread_curHandlerTable(%ecx), rIBASE
+ FETCH_INST
+ movl offThread_pJitProfTable(%ecx), %eax
+ #Fallthrough
+
+/* ebx holds the pointer to the jit profile table
+ edx has the opCode */
+common_testUpdateProfile:
+ cmp $$0, %eax
+ je 4f
+/* eax holds the pointer to the jit profile table
+ edx has the opCode
+ rPC points to the next bytecode */
common_updateProfile:
# quick & dirty hash
- movl rPC, %eax
- shrl $$12, %eax
- xorl rPC, %eax
- andl $$((1<<JIT_PROF_SIZE_LOG_2)-1),%eax
- decb (%edx,%eax)
+ movl rPC, %ecx
+ shrl $$12, %ecx
+ xorl rPC, %ecx
+ andl $$((1<<JIT_PROF_SIZE_LOG_2)-1), %ecx
+ decb (%ecx,%eax)
+ #jmp 1f # remove
jz 2f
1:
GOTO_NEXT
2:
+common_Profile:
/*
* Here, we switch to the debug interpreter to request
* trace selection. First, though, check to see if there
* is already a native translation in place (and, if so,
* jump to it now.
*/
- GET_JIT_THRESHOLD %ecx rINST # leaves rSELF in %ecx
+ SPILL(rIBASE)
+ SPILL_TMP1(rINST)
+ movl rSELF, rIBASE
+ GET_JIT_THRESHOLD rIBASE rINST # leaves rSELF in %ecx
EXPORT_PC
- movb rINSTbl,(%edx,%eax) # reset counter
- movl %ecx,rINST # preserve rSELF
+ movb rINSTbl,(%ecx,%eax) # reset counter
+ movl rIBASE,rINST # preserve rSELF
movl rSELF, %eax
movl rPC,OUT_ARG0(%esp)
- movl %eax,OUT_ARG1(%esp)
- call dvmJitGetTraceAddr # (pc, self)
+ movl rIBASE,OUT_ARG1(%esp)
+ call dvmJitGetTraceAddrThread # (pc, self)
+ UNSPILL(rIBASE)
movl %eax,offThread_inJitCodeCache(rINST) # set the inJitCodeCache flag
+ UNSPILL_TMP1(rINST)
cmpl $$0,%eax
+ #jmp 1f # remove
jz 1f
- call *%eax # TODO: decide call vs/ jmp!. No return either way
+ jmp *%eax # TODO: decide call vs/ jmp!. No return either way
1:
movl $$kJitTSelectRequest,%eax
# On entry, eax<- jitState, rPC valid
common_selectTrace:
-/* TODO */
- call dvmAbort
-#if 0
- movl rSELF,%ecx
- movl %eax,offThread_jitState(%ecx)
- movl $$kInterpEntryInstr,offThread_entryPoint(%ecx)
- movl $$1,rINST
- jmp common_gotoBail
-#endif
-#endif
+ mov %ebx, EBX_SPILL(%ebp)
+ movl rSELF, %ebx
+ movzwl offThread_subMode(%ebx), %ecx
+ and $$(kSubModeJitTraceBuild | kSubModeJitSV), %ecx
+ jne 3f # already doing JIT work, continue
+ movl %eax, offThread_jitState(%ebx)
+ movl rSELF, %eax
+ movl %eax, OUT_ARG0(%esp)
+
+/*
+ * Call out to validate trace-building request. If successful, rIBASE will be swapped
+ * to send us into single-steppign trace building mode, so we need to refresh before
+ * we continue.
+ */
+
+ EXPORT_PC
+ SAVE_PC_FP_TO_SELF %ecx
+ call dvmJitCheckTraceRequest
+3:
+ mov EBX_SPILL(%ebp), %ebx
+ FETCH_INST
+ movl rSELF, %ecx
+ movl offThread_curHandlerTable(%ecx), rIBASE
+4:
+ GOTO_NEXT
+
+common_selectTrace2:
+ mov %ebx, EBX_SPILL(%ebp)
+ movl rSELF, %ebx
+ movl %ebx, OUT_ARG0(%esp)
+ movl %eax, offThread_jitState(%ebx)
+ movzwl offThread_subMode(%ebx), %ecx
+ mov EBX_SPILL(%ebp), %ebx
+ and (kSubModeJitTraceBuild | kSubModeJitSV), %ecx
+ jne 3f # already doing JIT work, continue
/*
+ * Call out to validate trace-building request. If successful, rIBASE will be swapped
+ * to send us into single-steppign trace building mode, so we need to refresh before
+ * we continue.
+ */
+
+ EXPORT_PC
+ SAVE_PC_FP_TO_SELF %ecx
+ call dvmJitCheckTraceRequest
+3:
+ FETCH_INST
+ movl rSELF, %ecx
+ movl offThread_curHandlerTable(%ecx), rIBASE
+4:
+ GOTO_NEXT
+
+#endif
+
+/*
+ * For the invoke codes we need to know what register holds the "this" pointer. However
+ * it seems the this pointer is assigned consistently most times it is in %ecx but other
+ * times it is in OP_INVOKE_INTERFACE_JUMBO OP_INVOKE_INTERFACE OP_INVOKE_SUPER_QUICK and
+ * OP_INVOKE_VIRTUAL_QUICK
+*/
+
+/*
* Common code for method invocation with range.
*
* On entry:
* eax = Method* methodToCall
+ * ecx = "this"
* rINSTw trashed, must reload
* rIBASE trashed, must reload before resuming interpreter
*/
common_invokeMethodRange:
.LinvokeNewRange:
-
+#if defined(WITH_JIT)
+ SPILL_TMP1(%edx)
+ SPILL_TMP2(%ebx)
+ movl rSELF, %edx
+ movzwl offThread_subMode(%edx), %ebx
+ and $$kSubModeJitTraceBuild, %ebx
+ jz 6f
+ call save_callsiteinfo
+6:
+ UNSPILL_TMP2(%ebx)
+ UNSPILL_TMP1(%edx)
+#endif
/*
* prepare to copy args to "outs" area of current frame
*/
@@ -262,6 +419,18 @@
*/
common_invokeMethodNoRange:
+#if defined(WITH_JIT)
+ SPILL_TMP1(%edx)
+ SPILL_TMP2(%ebx)
+ movl rSELF, %edx
+ movzwl offThread_subMode(%edx), %ebx
+ and $$kSubModeJitTraceBuild, %ebx
+ jz 6f
+ call save_callsiteinfo
+6:
+ UNSPILL_TMP2(%ebx)
+ UNSPILL_TMP1(%edx)
+#endif
.LinvokeNewNoRange:
movzbl 1(rPC),rINST # rINST<- BA
movl rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
@@ -349,6 +518,9 @@
movl rSELF,%ecx # %ecx<- pthread
movl rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
movl rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
+#if defined(WITH_JIT)
+ movl $$0, offStackSaveArea_returnAddr(%edx)
+#endif
/* Any special actions to take? */
cmpw $$0, offThread_subMode(%ecx)
@@ -372,6 +544,12 @@
movl rFP, offThread_curFrame(%ecx) # curFrame<-newFP
movl offThread_curHandlerTable(%ecx),rIBASE
FETCH_INST
+#if defined(WITH_JIT)
+ /* rPC is already updated */
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $$0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT # jump to methodToCall->insns
2:
@@ -431,8 +609,8 @@
*/
SPILL_TMP1(%eax) # save methodTocall
movl rPC, offThread_pc(%ecx)
- movl %eax, OUT_ARG0(%esp)
movl %ecx, OUT_ARG1(%esp)
+ movl %eax, OUT_ARG0(%esp)
movl rFP, OUT_ARG2(%esp)
call dvmReportPreNativeInvoke # (methodToCall, self, fp)
UNSPILL_TMP1(%eax) # restore methodToCall
@@ -448,8 +626,8 @@
UNSPILL_TMP1(%eax) # restore methodToCall
movl rSELF, %ecx
- movl %eax, OUT_ARG0(%esp)
movl %ecx, OUT_ARG1(%esp)
+ movl %eax, OUT_ARG0(%esp)
movl rFP, OUT_ARG2(%esp)
call dvmReportPostNativeInvoke # (methodToCall, self, fp)
jmp 7b # rejoin
@@ -466,36 +644,68 @@
* Common code for handling a return instruction
*/
common_returnFromMethod:
- movl rSELF,%ecx
- SAVEAREA_FROM_FP %eax # eax<- saveArea (old)
+ movl rSELF, %ecx
+ SAVEAREA_FROM_FP %eax # %eax<- saveArea(old)
cmpw $$0, offThread_subMode(%ecx) # special action needed?
jne 19f # go if so
14:
- movl offStackSaveArea_prevFrame(%eax),rFP # rFP<- prevFrame
- movl (offStackSaveArea_method-sizeofStackSaveArea)(rFP),rINST
- cmpl $$0,rINST # break?
- je common_gotoBail # break frame, bail out completely
- movl offStackSaveArea_savedPc(%eax),rPC # pc<- saveArea->savedPC
- movl rINST,offThread_method(%ecx) # self->method = newSave->meethod
- movl rFP,offThread_curFrame(%ecx) # curFrame = fp
- movl offMethod_clazz(rINST),%eax # eax<- method->clazz
- movl offThread_curHandlerTable(%ecx),rIBASE
- movl offClassObject_pDvmDex(%eax),rINST # rINST<- method->clazz->pDvmDex
- FETCH_INST_OPCODE 3 %eax
- movl rINST,offThread_methodClassDex(%ecx)
+ movl offStackSaveArea_prevFrame(%eax), rFP # rFP<- saveArea->PrevFrame
+ movl (offStackSaveArea_method - sizeofStackSaveArea)(rFP), rINST # rINST<- method we are returning to
+ cmpl $$0, rINST # check for break frame
+ je common_gotoBail # bail if break frame
+ movl offThread_curHandlerTable(%ecx),rIBASE
+ movl offStackSaveArea_savedPc(%eax), rPC # rPC<- saveAreaOld->savedPc
+#if defined(WITH_JIT)
+ movl offStackSaveArea_returnAddr(%eax), %ecx
+#endif
+ movl rSELF, %eax
+ movl rINST, offThread_method(%eax) # glue->method<- newSave->method
+ movl offMethod_clazz(rINST), rINST # rINST<- method->clazz
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
+#if defined(WITH_JIT)
+ //update self->offThread_inJitCodeCache
+ movl %ecx, offThread_inJitCodeCache(%eax)
+#endif
+ movl offClassObject_pDvmDex(rINST), rINST # rINST<- method->clazz->pDvmDex
+ movl rINST, offThread_methodClassDex(%eax) # glue->pDvmDex<- method->clazz->pDvmDex
+#if defined(WITH_JIT)
+ cmp $$0, %ecx
+ je .returnToBC
+ movl %ecx, %eax
+ jmp *%eax
+#endif
+
+.returnToBC:
+
+#if defined(WITH_JIT)
+ FETCH_INST_OPCODE 3, %ecx # %eax<- next instruction hi; fetch, advance
+ // %ecx has the opcode
+ addl $$6, rPC # 3*2 = 6
+ SPILL_TMP1 (%ecx)
+ movl rSELF, %ecx
+ FETCH_INST
+ UNSPILL_TMP1 (%ecx)
+ movzbl 1(rPC), rINST
+ jmp *(rIBASE,%ecx,4)
+#else
+ FETCH_INST_WORD 3
ADVANCE_PC 3
- GOTO_NEXT_R %eax
+ GOTO_NEXT
+#endif
19:
/*
* Handle special subMode actions
* On entry, rFP: prevFP, %ecx: self, %eax: saveArea
*/
- movl rFP, offThread_curFrame(%ecx) # update interpSave.curFrame
+ SPILL_TMP1(%ebx)
+ movl offStackSaveArea_prevFrame(%eax), %ebx # %ebx<- saveArea->PrevFrame
movl rPC, offThread_pc(%ecx) # update interpSave.pc
+ movl %ebx, offThread_curFrame(%ecx) # update interpSave.curFrame
movl %ecx, OUT_ARG0(%esp) # parameter self
call dvmReportReturn # (self)
+ UNSPILL_TMP1(%ebx)
movl rSELF, %ecx # restore self
SAVEAREA_FROM_FP %eax # restore saveArea
jmp 14b
@@ -518,12 +728,74 @@
movl rINST,OUT_ARG1(%esp) # changeInterp in arg1
call dvmMterpStdBail # bail out....
+/*
+ * The JIT's invoke method needs to remember the callsite class and
+ * target pair. Save them here so that they are available to
+ * dvmCheckJit following the interpretation of this invoke.
+ *
+ * eax = Method* methodToCall
+ * ecx = "this"
+ * edx = rSELF
+ * ebx = free to use
+ */
+#if defined(WITH_JIT)
+save_callsiteinfo:
+ cmp $$0, %ecx
+ je 2f
+ movl offObject_clazz(%ecx), %ecx
+2:
+ movl rSELF, %ebx
+ movl %eax, offThread_methodToCall(%ebx)
+ movl %ecx, offThread_callsiteClass(%ebx)
+ ret
+#endif
+
+#if defined(WITH_JIT)
+
+ /*
+ * If the JIT is actively building a trace we need to make sure
+ * that the field is fully resolved before including the current
+ * instruction.
+ *
+ * On entry:
+ * %ecx: &dvmDex->pResFields[field]
+ * %eax: field pointer (must preserve)
+ */
+common_verifyField:
+ movl %ebx, TMP_SPILL1(%ebp)
+ movl rSELF, %ebx
+ movzwl offThread_subMode(%ebx), %ebx
+ andl $$kSubModeJitTraceBuild, %ebx
+ movl TMP_SPILL1(%ebp), %ebx
+ jne 1f
+ ret
+1:
+ movl (%ecx), %ecx
+ cmp $$0, %ecx
+ je 1f
+ ret
+1:
+ SPILL_TMP1(%eax)
+ SPILL_TMP2(%edx)
+ movl rSELF, %ecx
+ # Because we call into this helper from a bytecode, we have
+ # to be careful not to write over the return address when using
+ # the OUT_ARG macros
+ lea -8(%esp), %esp
+ movl %ecx, OUT_ARG0(%esp)
+ movl rPC, OUT_ARG1(%esp)
+ call dvmJitEndTraceSelect
+ lea 8(%esp), %esp
+ UNSPILL_TMP2(%edx)
+ UNSPILL_TMP1(%eax)
+ ret
+#endif
/*
* After returning from a "selfd" function, pull out the updated values
* and start executing at the next instruction.
*/
- common_resumeAfterGlueCall:
+common_resumeAfterGlueCall:
movl rSELF, %eax
movl offThread_pc(%eax),rPC
movl offThread_curFrame(%eax),rFP
@@ -556,7 +828,6 @@
* On entry, method name in eax
*/
common_errNoSuchMethod:
-
EXPORT_PC
movl %eax,OUT_ARG0(%esp)
call dvmThrowNoSuchMethodError
@@ -599,12 +870,132 @@
* This does not return.
*/
common_exceptionThrown:
- movl rSELF,%ecx
- movl rPC,offThread_pc(%ecx)
- movl rFP,offThread_curFrame(%ecx)
- movl %ecx,OUT_ARG0(%esp)
- call dvmMterp_exceptionThrown
- jmp common_resumeAfterGlueCall
+.LexceptionNew:
+
+ EXPORT_PC
+ movl rSELF, %ecx
+ movl %ecx, OUT_ARG0(%esp)
+ call dvmCheckSuspendPending
+
+ movl rSELF, %ecx
+ movl offThread_exception(%ecx), %edx # %edx <- self->exception
+ movl %edx, OUT_ARG0(%esp)
+ movl %ecx, OUT_ARG1(%esp)
+ SPILL_TMP1(%edx)
+ call dvmAddTrackedAlloc # don't let the exception be GCed
+ UNSPILL_TMP1(%edx)
+ movl rSELF, %ecx
+ movl offThread_subMode(%ecx), %eax # get subMode flags
+ movl $$0, offThread_exception(%ecx)
+
+ # Special subMode?
+ cmpl $$0, %eax # any special subMode handling needed?
+ je 8f # go if so
+
+ # Manage debugger bookkeeping
+ movl rPC, offThread_pc(%ecx) # update interpSave.pc
+ movl rFP, offThread_curFrame(%ecx) # update interpSave.curFrame
+ movl %ecx, OUT_ARG0(%esp)
+ movl %edx, OUT_ARG1(%esp)
+ SPILL_TMP1(%edx)
+ call dvmReportExceptionThrow # (self, exception)
+ UNSPILL_TMP1(%edx)
+ movl rSELF, %ecx
+
+8:
+ /*
+ * set up args and a local for &fp
+ */
+ lea 20(%esp), %esp # raise %esp
+ movl rFP, (%esp) # save fp
+ movl %esp, %eax # %eax = &fp
+ lea -20(%esp), %esp # reset %esp
+ movl %eax, OUT_ARG4(%esp) # Arg 4 = &fp
+ movl $$0, OUT_ARG3(%esp) # Arg 3 = false
+ movl %edx, OUT_ARG2(%esp) # Arg 2 = exception
+ movl %ecx, OUT_ARG0(%esp) # Arg 0 = self
+
+ movl offThread_method(%ecx), %eax # %eax = self->method
+ movl offMethod_insns(%eax), %eax # %eax = self->method->insn
+ # ldrh lr, [rSELF, #offThread_subMode] @ lr<- subMode flags # TODO
+ movl rPC, %ecx
+ subl %eax, %ecx # %ecx = pc - self->method->insn
+ sar $$1, %ecx # adjust %ecx for code offset
+ movl %ecx, OUT_ARG1(%esp) # Arg 1 = %ecx
+
+ /* call, %eax gets catchRelPc (a code-unit offset) */
+ SPILL_TMP1(%edx) # save exception
+ call dvmFindCatchBlock # call(self, relPc, exc, scan?, &fp)
+ UNSPILL_TMP1(%edx) # restore exception
+
+ /* fix earlier stack overflow if necessary; may trash rFP */
+ movl rSELF, %ecx
+ cmpl $$0, offThread_stackOverflowed(%ecx) # did we overflow?
+ je 1f # no, skip ahead
+ movl %eax, rFP # save relPc result in rFP
+ movl %ecx, OUT_ARG0(%esp) # Arg 0 = self
+ movl %edx, OUT_ARG1(%esp) # Arg 1 = exception
+ SPILL_TMP1(%edx)
+ call dvmCleanupStackOverflow # call(self, exception)
+ UNSPILL_TMP1(%edx)
+ movl rFP, %eax # restore result
+ movl rSELF, %ecx
+1:
+
+ /* update frame pointer and check result from dvmFindCatchBlock */
+ movl 20(%esp), rFP # retrieve the updated rFP
+ cmpl $$0, %eax # is catchRelPc < 0?
+ jl .LnotCaughtLocally
+
+ /* adjust locals to match self->interpSave.curFrame and updated PC */
+ SAVEAREA_FROM_FP rINST # rINST<- new save area
+ movl offStackSaveArea_method(rINST), rINST # rINST<- new method
+ movl rINST, offThread_method(%ecx) # self->method = new method
+ movl offMethod_clazz(rINST), %ecx # %ecx = method->clazz
+ movl offMethod_insns(rINST), rINST # rINST = method->insn
+ movl offClassObject_pDvmDex(%ecx), %ecx # %ecx = method->clazz->pDvmDex
+ lea (rINST, %eax, 2), rPC # rPC<- method->insns + catchRelPc
+ movl rSELF, rINST
+ movl %ecx, offThread_methodClassDex(rINST) # self->pDvmDex = method->clazz->pDvmDex
+
+ /* release the tracked alloc on the exception */
+ movl %edx, OUT_ARG0(%esp) # Arg 0 = exception
+ movl rINST, OUT_ARG1(%esp) # Arg 1 = self
+ SPILL_TMP1(%edx)
+ call dvmReleaseTrackedAlloc # release the exception
+ UNSPILL_TMP1(%edx)
+
+ /* restore the exception if the handler wants it */
+ movl rSELF, %ecx
+ FETCH_INST
+ movzbl rINSTbl, %eax
+ cmpl $$OP_MOVE_EXCEPTION, %eax # is it "move-exception"?
+ jne 1f
+ movl %edx, offThread_exception(%ecx) # restore exception
+1:
+ movl offThread_curHandlerTable(%ecx), rIBASE # refresh rIBASE
+ GOTO_NEXT
+
+.LnotCaughtLocally: # %edx = exception
+ /* fix stack overflow if necessary */
+ movl rSELF, %ecx
+ movl offThread_stackOverflowed(%ecx), %eax
+ cmpl $$0, %eax # did we overflow earlier?
+ je 1f
+ movl %ecx, OUT_ARG0(%esp)
+ movl %edx, OUT_ARG1(%esp)
+ SPILL_TMP1(%edx)
+ call dvmCleanupStackOverflow
+ UNSPILL_TMP1(%edx)
+
+1:
+ movl rSELF, %ecx
+ movl %edx, offThread_exception(%ecx) #restore exception
+ movl %edx, OUT_ARG0(%esp)
+ movl %ecx, OUT_ARG1(%esp)
+ call dvmReleaseTrackedAlloc # release the exception
+ movl rSELF, %ecx
+ jmp common_gotoBail # bail out
common_abort:
movl $$0xdeadf00d,%eax
diff --git a/vm/mterp/x86/header.S b/vm/mterp/x86/header.S
index b612fd8..16f3d98 100644
--- a/vm/mterp/x86/header.S
+++ b/vm/mterp/x86/header.S
@@ -51,8 +51,8 @@
to callee save registers).
nick reg purpose
- rPC edi interpreted program counter, used for fetching instructions
- rFP esi interpreted frame pointer, used for accessing locals and args
+ rPC esi interpreted program counter, used for fetching instructions
+ rFP edi interpreted frame pointer, used for accessing locals and args
rINSTw bx first 16-bit code of current instruction
rINSTbl bl opcode portion of instruction word
rINSTbh bh high byte of inst word, usually contains src/tgt reg names
@@ -99,7 +99,14 @@
#define OUT_ARG2 ( 8)
#define OUT_ARG1 ( 4)
#define OUT_ARG0 ( 0) /* <- dvmMterpStdRun esp */
+#if defined(WITH_JIT)
+/* for spill region: increase size by 48 (to keep 16-byte alignment) */
+/* 76 + 48 = 124 */
+#define JIT_SPILL (-56)
+#define FRAME_SIZE 124
+#else
#define FRAME_SIZE 76
+#endif
#define SPILL(reg) movl reg##,reg##_SPILL(%ebp)
#define UNSPILL(reg) movl reg##_SPILL(%ebp),reg
@@ -149,6 +156,10 @@
movl rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP)
.endm
+.macro GET_PC
+ movl (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP), rPC
+.endm
+
/*
* Given a frame pointer, find the stack save area.
*
@@ -250,6 +261,13 @@
#define sReg2 LOCAL2_OFFSET(%ebp)
/*
+ * x86 JIT Helpers
+ */
+
+ .macro dumpSwitch _regData _regScratch1 _regScratch2
+ .endm
+
+ /*
* Hard coded helper values.
*/
diff --git a/vm/mterp/x86/zcmp.S b/vm/mterp/x86/zcmp.S
index cbda889..e9fc7d4 100644
--- a/vm/mterp/x86/zcmp.S
+++ b/vm/mterp/x86/zcmp.S
@@ -9,12 +9,17 @@
*/
/* if-cmp vAA, +BBBB */
cmpl $$0,(rFP,rINST,4) # compare (vA, 0)
+ movl rSELF,%ecx
movl $$2,%eax # assume branch not taken
j${revcmp} 1f
- movl rSELF,%ecx
movswl 2(rPC),%eax # fetch signed displacement
movl offThread_curHandlerTable(%ecx),rIBASE
1:
FETCH_INST_INDEXED %eax
ADVANCE_PC_INDEXED %eax
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE %ecx %eax
+ cmp $$0, %eax
+ jne common_updateProfile # set up %ebx & %edx & rPC
+#endif
GOTO_NEXT
diff --git a/vm/native/dalvik_system_Zygote.cpp b/vm/native/dalvik_system_Zygote.cpp
index 87655c6..28d8d2d 100644
--- a/vm/native/dalvik_system_Zygote.cpp
+++ b/vm/native/dalvik_system_Zygote.cpp
@@ -20,6 +20,10 @@
#include "Dalvik.h"
#include "native/InternalNativePriv.h"
+#ifdef HAVE_SELINUX
+#include <selinux/android.h>
+#endif
+
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -357,6 +361,23 @@
return 0;
}
+#ifdef HAVE_SELINUX
+/*
+ * Set SELinux security context.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int setSELinuxContext(uid_t uid, bool isSystemServer,
+ const char *seInfo, const char *niceName)
+{
+#ifdef HAVE_ANDROID_OS
+ return selinux_android_setcontext(uid, isSystemServer, seInfo, niceName);
+#else
+ return 0;
+#endif
+}
+#endif
+
/*
* Utility routine to fork zygote and specialize the child process.
*/
@@ -370,6 +391,10 @@
u4 debugFlags = args[3];
ArrayObject *rlimits = (ArrayObject *)args[4];
int64_t permittedCapabilities, effectiveCapabilities;
+#ifdef HAVE_SELINUX
+ char *seInfo = NULL;
+ char *niceName = NULL;
+#endif
if (isSystemServer) {
/*
@@ -383,6 +408,24 @@
effectiveCapabilities = args[7] | (int64_t) args[8] << 32;
} else {
permittedCapabilities = effectiveCapabilities = 0;
+#ifdef HAVE_SELINUX
+ StringObject* seInfoObj = (StringObject*)args[5];
+ if (seInfoObj) {
+ seInfo = dvmCreateCstrFromString(seInfoObj);
+ if (!seInfo) {
+ ALOGE("seInfo dvmCreateCstrFromString failed");
+ dvmAbort();
+ }
+ }
+ StringObject* niceNameObj = (StringObject*)args[6];
+ if (niceNameObj) {
+ niceName = dvmCreateCstrFromString(niceNameObj);
+ if (!niceName) {
+ ALOGE("niceName dvmCreateCstrFromString failed");
+ dvmAbort();
+ }
+ }
+#endif
}
if (!gDvm.zygote) {
@@ -467,6 +510,19 @@
dvmAbort();
}
+#ifdef HAVE_SELINUX
+ err = setSELinuxContext(uid, isSystemServer, seInfo, niceName);
+ if (err < 0) {
+ ALOGE("cannot set SELinux context: %s\n", strerror(errno));
+ dvmAbort();
+ }
+ // These free(3) calls are safe because we know we're only ever forking
+ // a single-threaded process, so we know no other thread held the heap
+ // lock when we forked.
+ free(seInfo);
+ free(niceName);
+#endif
+
/*
* Our system thread ID has changed. Get the new one.
*/
@@ -484,13 +540,17 @@
}
} else if (pid > 0) {
/* the parent process */
+#ifdef HAVE_SELINUX
+ free(seInfo);
+ free(niceName);
+#endif
}
return pid;
}
/* native public static int forkAndSpecialize(int uid, int gid,
- * int[] gids, int debugFlags);
+ * int[] gids, int debugFlags, String seInfo, String niceName);
*/
static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
JValue* pResult)
@@ -549,7 +609,7 @@
const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
{ "nativeFork", "()I",
Dalvik_dalvik_system_Zygote_fork },
- { "nativeForkAndSpecialize", "(II[II[[I)I",
+ { "nativeForkAndSpecialize", "(II[II[[ILjava/lang/String;Ljava/lang/String;)I",
Dalvik_dalvik_system_Zygote_forkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",
Dalvik_dalvik_system_Zygote_forkSystemServer },
diff --git a/vm/oo/Class.cpp b/vm/oo/Class.cpp
index 3a721b6..eb816b0 100644
--- a/vm/oo/Class.cpp
+++ b/vm/oo/Class.cpp
@@ -2913,20 +2913,26 @@
for (si = 0; si < clazz->super->vtableCount; si++) {
Method* superMeth = clazz->vtable[si];
- if (dvmCompareMethodNamesAndProtos(localMeth, superMeth) == 0)
- {
- /* verify */
- if (dvmIsFinalMethod(superMeth)) {
- ALOGW("Method %s.%s overrides final %s.%s",
- localMeth->clazz->descriptor, localMeth->name,
- superMeth->clazz->descriptor, superMeth->name);
- goto bail;
+ if (dvmCompareMethodNamesAndProtos(localMeth, superMeth) == 0) {
+ if (dvmCheckMethodAccess(clazz, superMeth)) {
+ /* verify */
+ if (dvmIsFinalMethod(superMeth)) {
+ ALOGW("Method %s.%s overrides final %s.%s",
+ localMeth->clazz->descriptor, localMeth->name,
+ superMeth->clazz->descriptor, superMeth->name);
+ goto bail;
+ }
+ clazz->vtable[si] = localMeth;
+ localMeth->methodIndex = (u2) si;
+ //ALOGV("+++ override %s.%s (slot %d)",
+ // clazz->descriptor, localMeth->name, si);
+ break;
+ } else {
+ ALOGW("in older versions of dalvik, method %s.%s would have incorrectly "
+ "overridden package-private method with same name in %s",
+ localMeth->clazz->descriptor, localMeth->name,
+ superMeth->clazz->descriptor);
}
- clazz->vtable[si] = localMeth;
- localMeth->methodIndex = (u2) si;
- //ALOGV("+++ override %s.%s (slot %d)",
- // clazz->descriptor, localMeth->name, si);
- break;
}
}
diff --git a/vm/reflect/Annotation.cpp b/vm/reflect/Annotation.cpp
index 233db08..453ddc5 100644
--- a/vm/reflect/Annotation.cpp
+++ b/vm/reflect/Annotation.cpp
@@ -2085,9 +2085,15 @@
const DexAnnotationSetRefItem* pItem;
const DexAnnotationSetItem* pAnnoSet;
Object *annoSet;
+ DexAnnotationSetItem emptySet;
+ emptySet.size = 0;
pItem = dexGetParameterAnnotationSetRef(pAnnoSetList, idx);
pAnnoSet = dexGetSetRefItemItem(pDexFile, pItem);
+ if (pAnnoSet == NULL) {
+ pAnnoSet = &emptySet;
+ }
+
annoSet = (Object *)processAnnotationSet(clazz,
pAnnoSet,
kDexVisibilityRuntime);
diff --git a/vm/reflect/Reflect.cpp b/vm/reflect/Reflect.cpp
index c5d7fbe..1d055c1 100644
--- a/vm/reflect/Reflect.cpp
+++ b/vm/reflect/Reflect.cpp
@@ -901,6 +901,9 @@
};
enum Conversion conv;
+#ifdef ARCH_HAVE_ALIGNED_DOUBLES
+ double ret;
+#endif
assert((srcType != PRIM_VOID) && (srcType != PRIM_NOT));
assert((dstType != PRIM_VOID) && (dstType != PRIM_NOT));
@@ -978,9 +981,15 @@
case OK4: *dstPtr = *srcPtr; return 1;
case OK8: *(s8*) dstPtr = *(s8*)srcPtr; return 2;
case ItoJ: *(s8*) dstPtr = (s8) (*(s4*) srcPtr); return 2;
+#ifndef ARCH_HAVE_ALIGNED_DOUBLES
case ItoD: *(double*) dstPtr = (double) (*(s4*) srcPtr); return 2;
case JtoD: *(double*) dstPtr = (double) (*(long long*) srcPtr); return 2;
case FtoD: *(double*) dstPtr = (double) (*(float*) srcPtr); return 2;
+#else
+ case ItoD: ret = (double) (*(s4*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
+ case JtoD: ret = (double) (*(long long*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
+ case FtoD: ret = (double) (*(float*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
+#endif
case ItoF: *(float*) dstPtr = (float) (*(int*) srcPtr); return 1;
case JtoF: *(float*) dstPtr = (float) (*(long long*) srcPtr); return 1;
case bad: {