summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-01-20 14:03:55 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-01-20 14:03:55 -0800
commit4c1a2915e40eceeb68dbc323d28b8bf8763af83b (patch)
treeb6df7a910dfb981a44919eb33fc29aaaca02b7b2
parent066bed5fb19102e4f560f242b0cee645f1ed8b31 (diff)
downloadandroid_dalvik-4c1a2915e40eceeb68dbc323d28b8bf8763af83b.tar.gz
android_dalvik-4c1a2915e40eceeb68dbc323d28b8bf8763af83b.tar.bz2
android_dalvik-4c1a2915e40eceeb68dbc323d28b8bf8763af83b.zip
auto import from //branches/cupcake/...@127101
-rw-r--r--docs/verifier.html6
-rw-r--r--dx/tests/042-dex-ignore-result/expected.txt1
-rw-r--r--dx/tests/043-dex-two-classes/expected.txt1
-rw-r--r--dx/tests/044-dex-math-ops/expected.txt1
-rw-r--r--dx/tests/045-dex-switch-ops/expected.txt1
-rw-r--r--dx/tests/046-dex-exceptions/expected.txt1
-rw-r--r--dx/tests/047-dex-wide-args/expected.txt1
-rw-r--r--dx/tests/048-dex-new-array/expected.txt1
-rw-r--r--dx/tests/049-dex-instanceof/expected.txt1
-rw-r--r--dx/tests/050-dex-checkcast/expected.txt1
-rw-r--r--dx/tests/051-dex-explicit-null/expected.txt1
-rw-r--r--dx/tests/052-dex-static-var-access/expected.txt1
-rw-r--r--dx/tests/053-dex-instance-var-access/expected.txt1
-rw-r--r--dx/tests/054-dex-high16/expected.txt1
-rw-r--r--dx/tests/055-dex-explicit-throw/expected.txt1
-rw-r--r--dx/tests/056-dex-call-interface/expected.txt1
-rw-r--r--dx/tests/057-dex-call-virtual/expected.txt1
-rw-r--r--dx/tests/058-dex-call-direct/expected.txt1
-rw-r--r--dx/tests/059-dex-call-super/expected.txt1
-rw-r--r--dx/tests/060-dex-call-static/expected.txt1
-rw-r--r--dx/tests/061-dex-try-catch/expected.txt1
-rw-r--r--dx/tests/062-dex-synch-method/expected.txt1
-rw-r--r--dx/tests/063-dex-empty-switch/expected.txt1
-rw-r--r--dx/tests/064-dex-array-access/expected.txt1
-rw-r--r--dx/tests/065-dex-new-array/expected.txt1
-rw-r--r--dx/tests/066-dex-try-catch-rethrow/expected.txt1
-rw-r--r--dx/tests/067-dex-switch-and-try/expected.txt1
-rw-r--r--dx/tests/068-dex-infinite-loop/expected.txt1
-rw-r--r--dx/tests/069-dex-source-position/expected.txt1
-rw-r--r--dx/tests/070-dex-multianewarray/expected.txt1
-rw-r--r--dx/tests/072-dex-switch-edge-cases/expected.txt1
-rw-r--r--dx/tests/073-dex-null-array-refs/expected.txt1
-rw-r--r--dx/tests/074-dex-form35c-edge-case/expected.txt1
-rw-r--r--dx/tests/075-dex-cat2-value-merge/expected.txt1
-rw-r--r--dx/tests/076-dex-synch-and-stack/expected.txt1
-rw-r--r--dx/tests/077-dex-code-alignment/expected.txt1
-rw-r--r--dx/tests/078-dex-local-variable-table/expected.txt1
-rw-r--r--dx/tests/079-dex-local-variable-renumbering/expected.txt1
-rw-r--r--dx/tests/080-dex-exception-tables/expected.txt1
-rw-r--r--dx/tests/081-dex-throws-list/expected.txt1
-rw-r--r--dx/tests/082-dex-throws-list-sharing/expected.txt1
-rw-r--r--dx/tests/083-ssa-phi-placement/expected.txt1
-rw-r--r--dx/tests/084-dex-high-register-moves/expected.txt1
-rw-r--r--dx/tests/086-ssa-edge-split/expected.txt1
-rw-r--r--dx/tests/087-ssa-local-vars/expected.txt1
-rw-r--r--dx/tests/088-ssa-combine-blocks/expected.txt1
-rw-r--r--dx/tests/089-dex-define-object/expected.txt1
-rw-r--r--dx/tests/090-dex-unify-arrays/expected.txt1
-rw-r--r--dx/tests/091-ssa-const-collector/expected.txt1
-rw-r--r--dx/tests/092-ssa-cfg-edge-cases/expected.txt1
-rw-r--r--dx/tests/093-ssa-invoke-range/expected.txt1
-rw-r--r--dx/tests/095-dex-const-string-jumbo/expected.txt1
-rw-r--r--dx/tests/096-dex-giant-catch/expected.txt1
-rw-r--r--dx/tests/097-dex-branch-offset-zero/expected.txt1
-rw-r--r--dx/tests/099-dex-core-library-error/expected.txt1
-rw-r--r--dx/tests/108-string-annotation/expected.txt1
-rwxr-xr-xdx/tests/run-test5
-rw-r--r--libcore/annotation/src/main/java/java/lang/annotation/Retention.java13
-rw-r--r--libcore/luni/src/main/java/java/util/HashMap.java29
-rw-r--r--libcore/luni/src/main/java/java/util/LinkedHashMap.java35
-rwxr-xr-xlibcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp48
-rw-r--r--libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionContextImpl.java59
-rw-r--r--libdex/DexSwapVerify.c1
-rw-r--r--tests/024-illegal-access/expected.txt5
-rw-r--r--tests/024-illegal-access/info.txt3
-rw-r--r--tests/024-illegal-access/src/CheckInstanceof.java27
-rw-r--r--tests/024-illegal-access/src/Main.java38
-rw-r--r--tests/024-illegal-access/src/otherpkg/Package.java24
-rw-r--r--tests/024-illegal-access/src2/otherpkg/Package.java24
-rwxr-xr-xtests/etc/local-run-test-jar10
-rwxr-xr-xtests/run-test1
-rw-r--r--vm/analysis/CodeVerify.c184
-rw-r--r--vm/analysis/DexOptimize.c2
-rw-r--r--vm/analysis/DexVerify.c25
-rw-r--r--vm/analysis/RegisterMap.c695
-rw-r--r--vm/analysis/RegisterMap.h10
-rw-r--r--vm/analysis/VerifySubs.c38
-rw-r--r--vm/analysis/VerifySubs.h3
-rw-r--r--vm/mterp/NOTES.txt35
-rw-r--r--vm/mterp/c/OP_NOT_LONG.c2
-rw-r--r--vm/mterp/out/InterpAsm-x86.S73
-rw-r--r--vm/mterp/out/InterpC-allstubs.c2
-rw-r--r--vm/mterp/out/InterpC-portdbg.c2
-rw-r--r--vm/mterp/out/InterpC-portstd.c2
-rw-r--r--vm/mterp/x86/OP_FILLED_NEW_ARRAY.S6
-rw-r--r--vm/mterp/x86/OP_NEW_INSTANCE.S4
-rw-r--r--vm/mterp/x86/OP_NOT_INT.S2
-rw-r--r--vm/mterp/x86/OP_NOT_LONG.S7
-rw-r--r--vm/mterp/x86/OP_REM_DOUBLE.S2
-rw-r--r--vm/mterp/x86/OP_REM_DOUBLE_2ADDR.S2
-rw-r--r--vm/mterp/x86/OP_REM_FLOAT.S2
-rw-r--r--vm/mterp/x86/OP_REM_FLOAT_2ADDR.S2
-rw-r--r--vm/mterp/x86/OP_RSUB_INT.S2
-rw-r--r--vm/mterp/x86/binopLit16.S6
-rw-r--r--vm/oo/Array.c5
-rw-r--r--vm/oo/Class.c83
96 files changed, 1284 insertions, 295 deletions
diff --git a/docs/verifier.html b/docs/verifier.html
index 42abc9202..656b83273 100644
--- a/docs/verifier.html
+++ b/docs/verifier.html
@@ -139,6 +139,12 @@ some amount of additional memory or spending additional cycles
on non-DEX-optimized instructions. We don't want to throw an
IllegalAccessError at verification time, since that would indicate that
access to the class being verified was illegal.
+<p>
+One approach that might be worth pursuing: for situations like illegal
+accesses, the verifier makes an in-RAM private copy of the method, and
+alters the instructions there. The class object is altered to point at
+the new copy of the instructions. This requires minimal memory overhead
+and provides a better experience for developers.
<p>
The VerifyError is accompanied by detailed, if somewhat cryptic,
diff --git a/dx/tests/042-dex-ignore-result/expected.txt b/dx/tests/042-dex-ignore-result/expected.txt
index 8ba83ea8e..a1db6a475 100644
--- a/dx/tests/042-dex-ignore-result/expected.txt
+++ b/dx/tests/042-dex-ignore-result/expected.txt
@@ -1,2 +1 @@
-javac 1.7.0-internal_bootstrap
Good!
diff --git a/dx/tests/043-dex-two-classes/expected.txt b/dx/tests/043-dex-two-classes/expected.txt
index 82ec25d38..e88eb13a0 100644
--- a/dx/tests/043-dex-two-classes/expected.txt
+++ b/dx/tests/043-dex-two-classes/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
processing Blort.class...
processing Zorch.class...
Good!
diff --git a/dx/tests/044-dex-math-ops/expected.txt b/dx/tests/044-dex-math-ops/expected.txt
index 7fe180571..f6f8b7996 100644
--- a/dx/tests/044-dex-math-ops/expected.txt
+++ b/dx/tests/044-dex-math-ops/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.blort:(DD)V:
regs: 000f; ins: 0005; outs: 0000
0000: move-object v0, v10
diff --git a/dx/tests/045-dex-switch-ops/expected.txt b/dx/tests/045-dex-switch-ops/expected.txt
index 72c571bab..46476ea83 100644
--- a/dx/tests/045-dex-switch-ops/expected.txt
+++ b/dx/tests/045-dex-switch-ops/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.switchTest1:(I)I:
regs: 0005; ins: 0002; outs: 0000
0000: move-object v0, v3
diff --git a/dx/tests/046-dex-exceptions/expected.txt b/dx/tests/046-dex-exceptions/expected.txt
index 5eddfcb7e..933a54764 100644
--- a/dx/tests/046-dex-exceptions/expected.txt
+++ b/dx/tests/046-dex-exceptions/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.exTest1:(I)I:
regs: 0004; ins: 0001; outs: 0001
0000: move v0, v3
diff --git a/dx/tests/047-dex-wide-args/expected.txt b/dx/tests/047-dex-wide-args/expected.txt
index a6badfde8..cc353fc51 100644
--- a/dx/tests/047-dex-wide-args/expected.txt
+++ b/dx/tests/047-dex-wide-args/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:(IJIJ)J:
regs: 0010; ins: 0006; outs: 0000
0000: move v0, v10
diff --git a/dx/tests/048-dex-new-array/expected.txt b/dx/tests/048-dex-new-array/expected.txt
index 6866d1f61..15332ca5b 100644
--- a/dx/tests/048-dex-new-array/expected.txt
+++ b/dx/tests/048-dex-new-array/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:()V:
regs: 0002; ins: 0000; outs: 0001
0000: const/4 v1, #int 0 // #0
diff --git a/dx/tests/049-dex-instanceof/expected.txt b/dx/tests/049-dex-instanceof/expected.txt
index c8fa6052d..77f903c03 100644
--- a/dx/tests/049-dex-instanceof/expected.txt
+++ b/dx/tests/049-dex-instanceof/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:(Ljava/lang/Object;)Z:
regs: 0003; ins: 0001; outs: 0000
0000: move-object v0, v2
diff --git a/dx/tests/050-dex-checkcast/expected.txt b/dx/tests/050-dex-checkcast/expected.txt
index 270b03a8a..96f7f201b 100644
--- a/dx/tests/050-dex-checkcast/expected.txt
+++ b/dx/tests/050-dex-checkcast/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:(Ljava/lang/Object;)LBlort;:
regs: 0003; ins: 0001; outs: 0000
0000: move-object v0, v2
diff --git a/dx/tests/051-dex-explicit-null/expected.txt b/dx/tests/051-dex-explicit-null/expected.txt
index 8fb700cc2..18ce09259 100644
--- a/dx/tests/051-dex-explicit-null/expected.txt
+++ b/dx/tests/051-dex-explicit-null/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()Ljava/lang/Object;:
regs: 0001; ins: 0000; outs: 0000
0000: const/4 v0, #null // #0
diff --git a/dx/tests/052-dex-static-var-access/expected.txt b/dx/tests/052-dex-static-var-access/expected.txt
index bfa91965e..239f98492 100644
--- a/dx/tests/052-dex-static-var-access/expected.txt
+++ b/dx/tests/052-dex-static-var-access/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()Ljava/lang/Object;:
regs: 0004; ins: 0000; outs: 0000
0000: sget-byte v1, Blort.staticByte:B
diff --git a/dx/tests/053-dex-instance-var-access/expected.txt b/dx/tests/053-dex-instance-var-access/expected.txt
index a0c0acaff..b73f617be 100644
--- a/dx/tests/053-dex-instance-var-access/expected.txt
+++ b/dx/tests/053-dex-instance-var-access/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()Ljava/lang/Object;:
regs: 0006; ins: 0001; outs: 0000
0000: move-object v0, v5
diff --git a/dx/tests/054-dex-high16/expected.txt b/dx/tests/054-dex-high16/expected.txt
index 42902bc47..b9d6cf304 100644
--- a/dx/tests/054-dex-high16/expected.txt
+++ b/dx/tests/054-dex-high16/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.testDouble:()V:
regs: 0002; ins: 0000; outs: 0002
0000: const-wide/high16 v0, #double -Infinity // #fff0000000000000
diff --git a/dx/tests/055-dex-explicit-throw/expected.txt b/dx/tests/055-dex-explicit-throw/expected.txt
index 1c6243176..b7e4c334a 100644
--- a/dx/tests/055-dex-explicit-throw/expected.txt
+++ b/dx/tests/055-dex-explicit-throw/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()V:
regs: 0001; ins: 0000; outs: 0000
0000: sget-object v0, Blort.theException:Ljava/lang/RuntimeException;
diff --git a/dx/tests/056-dex-call-interface/expected.txt b/dx/tests/056-dex-call-interface/expected.txt
index d3e7451d5..faf18c42e 100644
--- a/dx/tests/056-dex-call-interface/expected.txt
+++ b/dx/tests/056-dex-call-interface/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:(LZorch;D)I:
regs: 000b; ins: 0003; outs: 0003
0000: move-object v0, v8
diff --git a/dx/tests/057-dex-call-virtual/expected.txt b/dx/tests/057-dex-call-virtual/expected.txt
index d4932ccd5..ea50d354d 100644
--- a/dx/tests/057-dex-call-virtual/expected.txt
+++ b/dx/tests/057-dex-call-virtual/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:(LZorch;)I:
regs: 0004; ins: 0001; outs: 0002
0000: move-object v0, v3
diff --git a/dx/tests/058-dex-call-direct/expected.txt b/dx/tests/058-dex-call-direct/expected.txt
index cac99b10e..11820a3d4 100644
--- a/dx/tests/058-dex-call-direct/expected.txt
+++ b/dx/tests/058-dex-call-direct/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:(LBlort;)I:
regs: 0004; ins: 0001; outs: 0002
0000: move-object v0, v3
diff --git a/dx/tests/059-dex-call-super/expected.txt b/dx/tests/059-dex-call-super/expected.txt
index e18c9df06..8bb3bdebe 100644
--- a/dx/tests/059-dex-call-super/expected.txt
+++ b/dx/tests/059-dex-call-super/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()I:
regs: 0004; ins: 0001; outs: 0002
0000: move-object v0, v3
diff --git a/dx/tests/060-dex-call-static/expected.txt b/dx/tests/060-dex-call-static/expected.txt
index f451938b2..94329898a 100644
--- a/dx/tests/060-dex-call-static/expected.txt
+++ b/dx/tests/060-dex-call-static/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:()I:
regs: 0001; ins: 0000; outs: 0001
0000: invoke-static {}, Zorch.zorch1:()V
diff --git a/dx/tests/061-dex-try-catch/expected.txt b/dx/tests/061-dex-try-catch/expected.txt
index dc8e6a7f5..d66f40468 100644
--- a/dx/tests/061-dex-try-catch/expected.txt
+++ b/dx/tests/061-dex-try-catch/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:(I)V:
regs: 0004; ins: 0001; outs: 0000
0000: move v0, v3
diff --git a/dx/tests/062-dex-synch-method/expected.txt b/dx/tests/062-dex-synch-method/expected.txt
index 9492aa1e8..68bdebe76 100644
--- a/dx/tests/062-dex-synch-method/expected.txt
+++ b/dx/tests/062-dex-synch-method/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.testInstance1:()V:
regs: 0003; ins: 0001; outs: 0000
0000: move-object v0, v2
diff --git a/dx/tests/063-dex-empty-switch/expected.txt b/dx/tests/063-dex-empty-switch/expected.txt
index 4e0f6ba85..e4d1a469e 100644
--- a/dx/tests/063-dex-empty-switch/expected.txt
+++ b/dx/tests/063-dex-empty-switch/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:(I)I:
regs: 0005; ins: 0002; outs: 0000
0000: move-object v0, v3
diff --git a/dx/tests/064-dex-array-access/expected.txt b/dx/tests/064-dex-array-access/expected.txt
index d1912f81d..ae251e780 100644
--- a/dx/tests/064-dex-array-access/expected.txt
+++ b/dx/tests/064-dex-array-access/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test01:([Z)Z:
regs: 0007; ins: 0002; outs: 0000
0000: move-object v0, v5
diff --git a/dx/tests/065-dex-new-array/expected.txt b/dx/tests/065-dex-new-array/expected.txt
index a16ebe979..0b26182be 100644
--- a/dx/tests/065-dex-new-array/expected.txt
+++ b/dx/tests/065-dex-new-array/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()[Z:
regs: 0003; ins: 0001; outs: 0000
0000: move-object v0, v2
diff --git a/dx/tests/066-dex-try-catch-rethrow/expected.txt b/dx/tests/066-dex-try-catch-rethrow/expected.txt
index 371146313..13af56c09 100644
--- a/dx/tests/066-dex-try-catch-rethrow/expected.txt
+++ b/dx/tests/066-dex-try-catch-rethrow/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()V:
regs: 0005; ins: 0000; outs: 0002
0000: const-string v1, "x"
diff --git a/dx/tests/067-dex-switch-and-try/expected.txt b/dx/tests/067-dex-switch-and-try/expected.txt
index 43817109d..5e55bf41b 100644
--- a/dx/tests/067-dex-switch-and-try/expected.txt
+++ b/dx/tests/067-dex-switch-and-try/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:(I)I:
regs: 0006; ins: 0002; outs: 0000
0000: move-object v0, v4
diff --git a/dx/tests/068-dex-infinite-loop/expected.txt b/dx/tests/068-dex-infinite-loop/expected.txt
index 6f3064da3..1a84bd9be 100644
--- a/dx/tests/068-dex-infinite-loop/expected.txt
+++ b/dx/tests/068-dex-infinite-loop/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()V:
regs: 0000; ins: 0000; outs: 0000
0000: goto/32 0000 // +0000
diff --git a/dx/tests/069-dex-source-position/expected.txt b/dx/tests/069-dex-source-position/expected.txt
index b769055dd..853ee6581 100644
--- a/dx/tests/069-dex-source-position/expected.txt
+++ b/dx/tests/069-dex-source-position/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:(I)I:
regs: 0006; ins: 0001; outs: 0001
0000: move v0, v5
diff --git a/dx/tests/070-dex-multianewarray/expected.txt b/dx/tests/070-dex-multianewarray/expected.txt
index e9fac8ff9..9ddbabe9b 100644
--- a/dx/tests/070-dex-multianewarray/expected.txt
+++ b/dx/tests/070-dex-multianewarray/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test01:()Ljava/lang/Object;:
regs: 0003; ins: 0000; outs: 0002
0000: const/4 v1, #int 2 // #2
diff --git a/dx/tests/072-dex-switch-edge-cases/expected.txt b/dx/tests/072-dex-switch-edge-cases/expected.txt
index 8be71dab2..665928422 100644
--- a/dx/tests/072-dex-switch-edge-cases/expected.txt
+++ b/dx/tests/072-dex-switch-edge-cases/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:(I)I:
regs: 0005; ins: 0002; outs: 0000
0000: move-object v0, v3
diff --git a/dx/tests/073-dex-null-array-refs/expected.txt b/dx/tests/073-dex-null-array-refs/expected.txt
index 3acb6b265..7f3ee21b0 100644
--- a/dx/tests/073-dex-null-array-refs/expected.txt
+++ b/dx/tests/073-dex-null-array-refs/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()Ljava/lang/Object;:
regs: 0002; ins: 0000; outs: 0000
0000: const/4 v0, #null // #0
diff --git a/dx/tests/074-dex-form35c-edge-case/expected.txt b/dx/tests/074-dex-form35c-edge-case/expected.txt
index bc4f2da29..6afdcd773 100644
--- a/dx/tests/074-dex-form35c-edge-case/expected.txt
+++ b/dx/tests/074-dex-form35c-edge-case/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:()V:
regs: 0012; ins: 0001; outs: 0003
0000: move-object/from16 v0, v17
diff --git a/dx/tests/075-dex-cat2-value-merge/expected.txt b/dx/tests/075-dex-cat2-value-merge/expected.txt
index 9bb8e3324..e1b9b1b3b 100644
--- a/dx/tests/075-dex-cat2-value-merge/expected.txt
+++ b/dx/tests/075-dex-cat2-value-merge/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:([J)V:
regs: 0008; ins: 0001; outs: 0000
0000: move-object v0, v7
diff --git a/dx/tests/076-dex-synch-and-stack/expected.txt b/dx/tests/076-dex-synch-and-stack/expected.txt
index c8c017887..eba839ed2 100644
--- a/dx/tests/076-dex-synch-and-stack/expected.txt
+++ b/dx/tests/076-dex-synch-and-stack/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:()V:
regs: 0006; ins: 0001; outs: 0001
0000: move-object v0, v5
diff --git a/dx/tests/077-dex-code-alignment/expected.txt b/dx/tests/077-dex-code-alignment/expected.txt
index 8f6db7de2..e69de29bb 100644
--- a/dx/tests/077-dex-code-alignment/expected.txt
+++ b/dx/tests/077-dex-code-alignment/expected.txt
@@ -1 +0,0 @@
-javac 1.7.0-internal_bootstrap
diff --git a/dx/tests/078-dex-local-variable-table/expected.txt b/dx/tests/078-dex-local-variable-table/expected.txt
index d55333b98..3e5cd69d0 100644
--- a/dx/tests/078-dex-local-variable-table/expected.txt
+++ b/dx/tests/078-dex-local-variable-table/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test01:(Ljava/lang/Object;)V:
regs: 0003; ins: 0001; outs: 0001
0000: move-object v0, v2
diff --git a/dx/tests/079-dex-local-variable-renumbering/expected.txt b/dx/tests/079-dex-local-variable-renumbering/expected.txt
index f8f15c86c..94ba113e3 100644
--- a/dx/tests/079-dex-local-variable-renumbering/expected.txt
+++ b/dx/tests/079-dex-local-variable-renumbering/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:(I)I:
regs: 0015; ins: 0001; outs: 0000
0000: move/from16 v1, v20
diff --git a/dx/tests/080-dex-exception-tables/expected.txt b/dx/tests/080-dex-exception-tables/expected.txt
index 9337e7307..4cf43f186 100644
--- a/dx/tests/080-dex-exception-tables/expected.txt
+++ b/dx/tests/080-dex-exception-tables/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()I:
regs: 0002; ins: 0000; outs: 0000
0000: invoke-static {}, Blort.call1:()V
diff --git a/dx/tests/081-dex-throws-list/expected.txt b/dx/tests/081-dex-throws-list/expected.txt
index 502f724b8..1350edfab 100644
--- a/dx/tests/081-dex-throws-list/expected.txt
+++ b/dx/tests/081-dex-throws-list/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:()I:
system-annotation dalvik.annotation.Throws {value: {java.lang.RuntimeException}}
Blort.test2:()I:
diff --git a/dx/tests/082-dex-throws-list-sharing/expected.txt b/dx/tests/082-dex-throws-list-sharing/expected.txt
index 016b41f66..0f3392494 100644
--- a/dx/tests/082-dex-throws-list-sharing/expected.txt
+++ b/dx/tests/082-dex-throws-list-sharing/expected.txt
@@ -1,3 +1,2 @@
-javac 1.7.0-internal_bootstrap
java.lang.RuntimeException
java.lang.Error, java.lang.UnsupportedOperationException
diff --git a/dx/tests/083-ssa-phi-placement/expected.txt b/dx/tests/083-ssa-phi-placement/expected.txt
index c02e4393e..9a0cb0b65 100644
--- a/dx/tests/083-ssa-phi-placement/expected.txt
+++ b/dx/tests/083-ssa-phi-placement/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
reading Blort.class...
method <init> ()V
first 000c
diff --git a/dx/tests/084-dex-high-register-moves/expected.txt b/dx/tests/084-dex-high-register-moves/expected.txt
index e24cde0e6..33466c4e2 100644
--- a/dx/tests/084-dex-high-register-moves/expected.txt
+++ b/dx/tests/084-dex-high-register-moves/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:()V:
regs: 0018; ins: 0000; outs: 0000
0000: const/16 v22, #int 0 // #0000
diff --git a/dx/tests/086-ssa-edge-split/expected.txt b/dx/tests/086-ssa-edge-split/expected.txt
index bc29b2076..e59af312c 100644
--- a/dx/tests/086-ssa-edge-split/expected.txt
+++ b/dx/tests/086-ssa-edge-split/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
reading Blort.class...
method <init> ()V
first 000c
diff --git a/dx/tests/087-ssa-local-vars/expected.txt b/dx/tests/087-ssa-local-vars/expected.txt
index 9d8f81f02..6c0a6f78b 100644
--- a/dx/tests/087-ssa-local-vars/expected.txt
+++ b/dx/tests/087-ssa-local-vars/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
reading Blort.class...
method <init> ()V
first 000c
diff --git a/dx/tests/088-ssa-combine-blocks/expected.txt b/dx/tests/088-ssa-combine-blocks/expected.txt
index fef77e3c4..7bf445dfe 100644
--- a/dx/tests/088-ssa-combine-blocks/expected.txt
+++ b/dx/tests/088-ssa-combine-blocks/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
reading Blort.class...
method <init> ()V
first 000c
diff --git a/dx/tests/089-dex-define-object/expected.txt b/dx/tests/089-dex-define-object/expected.txt
index 8ba83ea8e..a1db6a475 100644
--- a/dx/tests/089-dex-define-object/expected.txt
+++ b/dx/tests/089-dex-define-object/expected.txt
@@ -1,2 +1 @@
-javac 1.7.0-internal_bootstrap
Good!
diff --git a/dx/tests/090-dex-unify-arrays/expected.txt b/dx/tests/090-dex-unify-arrays/expected.txt
index 818e985e5..7a4125f95 100644
--- a/dx/tests/090-dex-unify-arrays/expected.txt
+++ b/dx/tests/090-dex-unify-arrays/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test1:(Z)Ljava/lang/Object;:
regs: 0004; ins: 0001; outs: 0000
0000: move v0, v3
diff --git a/dx/tests/091-ssa-const-collector/expected.txt b/dx/tests/091-ssa-const-collector/expected.txt
index ef82e8ddf..0edb6e8e8 100644
--- a/dx/tests/091-ssa-const-collector/expected.txt
+++ b/dx/tests/091-ssa-const-collector/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
reading Blort.class...
method <init> ()V
first 000c
diff --git a/dx/tests/092-ssa-cfg-edge-cases/expected.txt b/dx/tests/092-ssa-cfg-edge-cases/expected.txt
index 394550a37..41fefc48a 100644
--- a/dx/tests/092-ssa-cfg-edge-cases/expected.txt
+++ b/dx/tests/092-ssa-cfg-edge-cases/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
reading Blort.class...
method <init> ()V
first 000c
diff --git a/dx/tests/093-ssa-invoke-range/expected.txt b/dx/tests/093-ssa-invoke-range/expected.txt
index 2fad8d6b1..bb383c0de 100644
--- a/dx/tests/093-ssa-invoke-range/expected.txt
+++ b/dx/tests/093-ssa-invoke-range/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
reading Blort.class...
method <init> ()V
first 000c
diff --git a/dx/tests/095-dex-const-string-jumbo/expected.txt b/dx/tests/095-dex-const-string-jumbo/expected.txt
index 1dbcc35b8..a4014d914 100644
--- a/dx/tests/095-dex-const-string-jumbo/expected.txt
+++ b/dx/tests/095-dex-const-string-jumbo/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
Blort.test:()V:
regs: 0003; ins: 0001; outs: 0001
0000: move-object v0, v2
diff --git a/dx/tests/096-dex-giant-catch/expected.txt b/dx/tests/096-dex-giant-catch/expected.txt
index 5c1b6d465..e71992eef 100644
--- a/dx/tests/096-dex-giant-catch/expected.txt
+++ b/dx/tests/096-dex-giant-catch/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
catches
try 0024..00010017
catch java.lang.RuntimeException -> 00011260
diff --git a/dx/tests/097-dex-branch-offset-zero/expected.txt b/dx/tests/097-dex-branch-offset-zero/expected.txt
index a57ea8838..2b021a566 100644
--- a/dx/tests/097-dex-branch-offset-zero/expected.txt
+++ b/dx/tests/097-dex-branch-offset-zero/expected.txt
@@ -1,2 +1 @@
-javac 1.7.0-internal_bootstrap
No bad branches found.
diff --git a/dx/tests/099-dex-core-library-error/expected.txt b/dx/tests/099-dex-core-library-error/expected.txt
index 022871a82..d9c405bc2 100644
--- a/dx/tests/099-dex-core-library-error/expected.txt
+++ b/dx/tests/099-dex-core-library-error/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
exit code: 1
exit code: 1
exit code: 0
diff --git a/dx/tests/108-string-annotation/expected.txt b/dx/tests/108-string-annotation/expected.txt
index befa6908d..57da807fe 100644
--- a/dx/tests/108-string-annotation/expected.txt
+++ b/dx/tests/108-string-annotation/expected.txt
@@ -1,4 +1,3 @@
-javac 1.7.0-internal_bootstrap
elements[0]:
name
diff --git a/dx/tests/run-test b/dx/tests/run-test
index 84eadb962..a9221de1d 100755
--- a/dx/tests/run-test
+++ b/dx/tests/run-test
@@ -33,7 +33,10 @@ cd "${progdir}"
progdir=`pwd`
prog="${progdir}"/`basename "${prog}"`
-export JAVAC="${progdir}/../../../prebuilt/common/openjdk/bin/javac -version"
+export JAVAC="${progdir}/../../../prebuilt/common/openjdk/bin/javac"
+if [ "!" -e "$JAVAC" ]; then
+ JAVAC="javac"
+fi
info="info.txt"
run="run"
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/Retention.java b/libcore/annotation/src/main/java/java/lang/annotation/Retention.java
index 1c440ae92..198fccc15 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/Retention.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/Retention.java
@@ -17,14 +17,10 @@
package java.lang.annotation;
-// BEGIN android-note
-// Un-linked RetentionPolicy#RUNTIME due to clearjavadoc problem (it doesn't
-// yet deal with links to enums).
-// END android-note
-
/**
* Defines a meta-annotation for determining the scope of retention for an
- * annotation. The default value is {@code RetentionPolicy.RUNTIME}.
+ * annotation. If the retention annotation is not set {@code
+ * RetentionPolicy.CLASS} is used as default retention.
*
* @since Android 1.0
*/
@@ -32,5 +28,8 @@ package java.lang.annotation;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
- RetentionPolicy value() default RetentionPolicy.CLASS;
+ // BEGIN android-changed
+ // copied from newer version of harmony
+ RetentionPolicy value();
+ // END android-changed
}
diff --git a/libcore/luni/src/main/java/java/util/HashMap.java b/libcore/luni/src/main/java/java/util/HashMap.java
index 056c113d7..594e8a801 100644
--- a/libcore/luni/src/main/java/java/util/HashMap.java
+++ b/libcore/luni/src/main/java/java/util/HashMap.java
@@ -299,6 +299,7 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>,
putAllImpl(map);
}
+ // BEGIN android-changed
/**
* Removes all mappings from this hash map, leaving it empty.
*
@@ -308,12 +309,17 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>,
*/
@Override
public void clear() {
+ internalClear();
+ }
+
+ void internalClear() {
if (elementCount > 0) {
elementCount = 0;
Arrays.fill(elementData, null);
modCount++;
}
}
+ // END android-changed
/**
* Returns a shallow copy of this map.
@@ -326,9 +332,10 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>,
public Object clone() {
try {
// BEGIN android-changed
+ // copied from newer version of harmony
HashMap<K, V> map = (HashMap<K, V>) super.clone();
- map.elementCount = 0;
map.elementData = newElementArray(elementData.length);
+ map.internalClear();
Entry<K, V> entry;
for (int i = 0; i < elementData.length; i++) {
if ((entry = elementData[i]) != null){
@@ -448,20 +455,26 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>,
final Entry<K,V> findNonNullKeyEntry(Object key, int index, int keyHash) {
Entry<K,V> m = elementData[index];
// BEGIN android-changed
- while (m != null) {
- if (m.origKeyHash == keyHash) {
- if (key instanceof String) {
- // The VM can optimize String.equals but not Object.equals
- if (((String) key).equals(m.key)) {
+ // The VM can optimize String.equals but not Object.equals
+ if (key instanceof String) {
+ String keyString = (String) key;
+ while (m != null) {
+ if (m.origKeyHash == keyHash) {
+ if (keyString.equals(m.key)) {
return m;
}
- } else {
+ }
+ m = m.next;
+ }
+ } else {
+ while (m != null) {
+ if (m.origKeyHash == keyHash) {
if (key.equals(m.key)) {
return m;
}
}
+ m = m.next;
}
- m = m.next;
}
return null;
// END android-changed
diff --git a/libcore/luni/src/main/java/java/util/LinkedHashMap.java b/libcore/luni/src/main/java/java/util/LinkedHashMap.java
index 1a613458f..a32a28b12 100644
--- a/libcore/luni/src/main/java/java/util/LinkedHashMap.java
+++ b/libcore/luni/src/main/java/java/util/LinkedHashMap.java
@@ -19,9 +19,10 @@ package java.util;
/**
- * LinkedHashMap is a variant on HashMap. Its entries are kept in a
+ * LinkedHashMap is a variant of HashMap. Its entries are kept in a
* doubly-linked list. The iteration order is, by default, the order in which
- * keys were inserted.
+ * keys were inserted. Reinserting an already existing key doesn't change the
+ * order. A key is existing if a call to {@code containsKey} would return true.
* <p>
* If the three argument constructor is used, and {@code order} is specified as
* {@code true}, the iteration will be in the order that entries were accessed.
@@ -30,6 +31,21 @@ package java.util;
* <p>
* Null elements are allowed, and all the optional map operations are supported.
* <p>
+ * <b>Note:</b> The implementation of {@code LinkedHashMap} is not synchronized.
+ * If one thread of several threads accessing an instance modifies the map
+ * structurally, access to the map needs to be synchronized. For
+ * insertion-ordered instances a structural modification is an operation that
+ * removes or adds an entry. Access-ordered instances also are structurally
+ * modified by put(), get() and putAll() since these methods change the order of
+ * the entries. Changes in the value of an entry are not structural changes.
+ * <p>
+ * The Iterator that can be created by calling the {@code iterator} method
+ * throws a {@code ConcurrentModificationException} if the map is structurally
+ * changed while an iterator is used to iterate over the elements. Only the
+ * {@code remove} method that is provided by the iterator allows for removal of
+ * elements during iteration. It is not possible to guarantee that this
+ * mechanism works in all cases of unsynchronized concurrent modification. It
+ * should only be used for debugging purposes.
*
* @since Android 1.0
*/
@@ -115,7 +131,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
/**
* Constructs a new {@code LinkedHashMap} instance containing the mappings
- * from the specified map.
+ * from the specified map. The order of the elements is preserved.
*
* @param m
* the mappings to add.
@@ -314,6 +330,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
}
// BEGIN android-changed
+ // copied from newer version of harmony
/**
* Maps the specified key to the specified value.
*
@@ -352,7 +369,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
if (++elementCount > threshold) {
rehash();
}
- m = (LinkedHashMapEntry<K, V>) createHashedEntry(key, 0, 0);
+ m = (LinkedHashMapEntry<K, V>) createHashedEntry(null, 0, 0);
} else {
linkEntry(m);
}
@@ -595,6 +612,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
return false;
}
+ // BEGIN android-changed
/**
* Removes all elements from this map, leaving it empty.
*
@@ -604,11 +622,18 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
*/
@Override
public void clear() {
- super.clear();
+ internalClear();
+ }
+
+ @Override
+ void internalClear() {
+ super.internalClear();
head = tail = null;
}
+ // END android-changed
// BEGIN android-removed
+ // copied from newer version of harmony
// /**
// * Answers a new HashMap with the same mappings and size as this HashMap.
// *
diff --git a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index 7afb54e52..de0129588 100755
--- a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -1469,18 +1469,48 @@ static jint osNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
return 0;
}
- while (sent < count) {
- result = send(handle, (jbyte *) message + sent, (int) count - sent, SOCKET_NOFLAGS);
- if (result == -1) {
- int err = convertError(errno);
- log_socket_close(handle, err);
- throwSocketException(env, err);
+ result = send(handle, (jbyte *) message, (int) count, SOCKET_NOFLAGS);
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+
+ if (SOCKERR_WOULDBLOCK == err){
+ jclass socketExClass,errorCodeExClass;
+ jmethodID errorCodeExConstructor, socketExConstructor,socketExCauseMethod;
+ jobject errorCodeEx, socketEx;
+ const char* errorMessage = netLookupErrorString(err);
+ jstring errorMessageString = env->NewStringUTF(errorMessage);
+
+ errorCodeExClass = env->FindClass("org/apache/harmony/luni/util/ErrorCodeException");
+ if (!errorCodeExClass){
+ return 0;
+ }
+ errorCodeExConstructor = env->GetMethodID(errorCodeExClass,"<init>","(I)V");
+ if (!errorCodeExConstructor){
+ return 0;
+ }
+ errorCodeEx = env->NewObject(errorCodeExClass,errorCodeExConstructor,err);
+
+ socketExClass = env->FindClass("java/net/SocketException");
+ if (!socketExClass) {
+ return 0;
+ }
+ socketExConstructor = env->GetMethodID(socketExClass,"<init>","(Ljava/lang/String;)V");
+ if (!socketExConstructor) {
+ return 0;
+ }
+ socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString);
+ socketExCauseMethod = env->GetMethodID(socketExClass,"initCause","(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
+ env->CallObjectMethod(socketEx,socketExCauseMethod,errorCodeEx);
+ env->Throw((jthrowable)socketEx);
return 0;
}
- sent += result;
+ throwSocketException(env, err);
+ return 0;
}
- add_send_stats(handle, sent);
- return sent;
+
+ add_send_stats(handle, result);
+ return result;
}
static jint osNetworkSystem_writeSocketImpl(JNIEnv* env, jclass clazz,
diff --git a/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionContextImpl.java b/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionContextImpl.java
index 3c6a3b8df..6882aa139 100644
--- a/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionContextImpl.java
+++ b/libcore/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionContextImpl.java
@@ -36,6 +36,7 @@
*/
package org.apache.harmony.xnet.provider.jsse;
+import java.nio.ByteBuffer;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -54,25 +55,28 @@ public class SSLSessionContextImpl implements SSLSessionContext {
private int cacheSize = 20;
private long timeout = 0;
- private final LinkedHashMap<byte[], SSLSession> sessions =
- new LinkedHashMap<byte[],SSLSession>(cacheSize, 0.75f, true) {
- public boolean removeEldestEntry(Map.Entry eldest) {
+ private final LinkedHashMap<ByteBuffer, SSLSession> sessions =
+ new LinkedHashMap<ByteBuffer, SSLSession>(cacheSize, 0.75f, true) {
+ @Override
+ public boolean removeEldestEntry(
+ Map.Entry<ByteBuffer, SSLSession> eldest) {
return cacheSize > 0 && this.size() > cacheSize;
}
};
- private volatile LinkedHashMap<byte[], SSLSession> clone = new LinkedHashMap<byte[], SSLSession>();
+ private volatile LinkedHashMap<ByteBuffer, SSLSession> clone =
+ new LinkedHashMap<ByteBuffer, SSLSession>();
/**
* @see javax.net.ssl.SSLSessionContext#getIds()
*/
public Enumeration<byte[]> getIds() {
return new Enumeration<byte[]>() {
- Iterator<byte[]> iterator = clone.keySet().iterator();
+ Iterator<ByteBuffer> iterator = clone.keySet().iterator();
public boolean hasMoreElements() {
return iterator.hasNext();
}
public byte[] nextElement() {
- return iterator.next();
+ return iterator.next().array();
}
};
}
@@ -82,7 +86,7 @@ public class SSLSessionContextImpl implements SSLSessionContext {
*/
public SSLSession getSession(byte[] sessionId) {
synchronized (sessions) {
- return (SSLSession) sessions.get(sessionId);
+ return sessions.get(ByteBuffer.wrap(sessionId));
}
}
@@ -90,14 +94,18 @@ public class SSLSessionContextImpl implements SSLSessionContext {
* @see javax.net.ssl.SSLSessionContext#getSessionCacheSize()
*/
public int getSessionCacheSize() {
- return cacheSize;
+ synchronized (sessions) {
+ return cacheSize;
+ }
}
/**
* @see javax.net.ssl.SSLSessionContext#getSessionTimeout()
*/
public int getSessionTimeout() {
- return (int) (timeout/1000);
+ synchronized (sessions) {
+ return (int) (timeout/1000);
+ }
}
/**
@@ -109,18 +117,16 @@ public class SSLSessionContextImpl implements SSLSessionContext {
}
synchronized (sessions) {
cacheSize = size;
- Set<byte[]> set = sessions.keySet();
- if (cacheSize > 0 && cacheSize < set.size()) {
- // Resize the cache to the maximum
- Iterator<byte[]> iterator = set.iterator();
- for (int i = 0; iterator.hasNext(); i++) {
+ if (cacheSize > 0 && cacheSize < sessions.size()) {
+ int removals = sessions.size() - cacheSize;
+ Iterator<ByteBuffer> iterator = sessions.keySet().iterator();
+ while (removals-- > 0) {
iterator.next();
- if (i >= cacheSize) {
- iterator.remove();
- }
+ iterator.remove();
}
+ clone = (LinkedHashMap<ByteBuffer, SSLSession>)
+ sessions.clone();
}
- clone = (LinkedHashMap<byte[], SSLSession>) sessions.clone();
}
}
@@ -131,18 +137,21 @@ public class SSLSessionContextImpl implements SSLSessionContext {
if (seconds < 0) {
throw new IllegalArgumentException("seconds < 0");
}
-
synchronized (sessions) {
timeout = seconds*1000;
// Check timeouts and remove expired sessions
SSLSession ses;
- for (Iterator<byte[]> iterator = sessions.keySet().iterator(); iterator.hasNext();) {
- ses = (SSLSession)(sessions.get(iterator.next()));
- if (!ses.isValid()) {
+ Iterator<Map.Entry<ByteBuffer, SSLSession>> iterator =
+ sessions.entrySet().iterator();
+ while (iterator.hasNext()) {
+ SSLSession session = iterator.next().getValue();
+ if (!session.isValid()) {
+ // safe to remove with this special method since it doesn't
+ // make the iterator throw a ConcurrentModificationException
iterator.remove();
}
}
- clone = (LinkedHashMap<byte[], SSLSession>) sessions.clone();
+ clone = (LinkedHashMap<ByteBuffer, SSLSession>) sessions.clone();
}
}
@@ -152,8 +161,8 @@ public class SSLSessionContextImpl implements SSLSessionContext {
*/
void putSession(SSLSession ses) {
synchronized (sessions) {
- sessions.put(ses.getId(), ses);
- clone = (LinkedHashMap<byte[], SSLSession>) sessions.clone();
+ sessions.put(ByteBuffer.wrap(ses.getId()), ses);
+ clone = (LinkedHashMap<ByteBuffer, SSLSession>) sessions.clone();
}
}
}
diff --git a/libdex/DexSwapVerify.c b/libdex/DexSwapVerify.c
index 86c0d402f..6ccd82001 100644
--- a/libdex/DexSwapVerify.c
+++ b/libdex/DexSwapVerify.c
@@ -2726,6 +2726,7 @@ int dexFixByteOrdering(u1* addr, int len)
CheckState state;
bool okay = true;
+ memset(&state, 0, sizeof(state));
LOGV("+++ swapping and verifying\n");
/*
diff --git a/tests/024-illegal-access/expected.txt b/tests/024-illegal-access/expected.txt
index 453812ddc..5f951f493 100644
--- a/tests/024-illegal-access/expected.txt
+++ b/tests/024-illegal-access/expected.txt
@@ -1,3 +1,2 @@
-java.lang.VerifyError: PublicAccess
- at Main.main(Main.java:3)
- at dalvik.system.NativeStart.main(Native Method)
+Got expected failure 1
+Got expected failure 2
diff --git a/tests/024-illegal-access/info.txt b/tests/024-illegal-access/info.txt
index 6c17ca726..16a284dac 100644
--- a/tests/024-illegal-access/info.txt
+++ b/tests/024-illegal-access/info.txt
@@ -1,2 +1,3 @@
Test that an attempt to access a private field results in a verification
-error.
+error. Also try to access a non-public class in a different package with
+"instanceof".
diff --git a/tests/024-illegal-access/src/CheckInstanceof.java b/tests/024-illegal-access/src/CheckInstanceof.java
new file mode 100644
index 000000000..de48cd2d2
--- /dev/null
+++ b/tests/024-illegal-access/src/CheckInstanceof.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/**
+ * Make sure we're performing access checks on classes used in "instanceof".
+ */
+public class CheckInstanceof {
+ public static void main(Object obj) {
+ if (obj instanceof otherpkg.Package)
+ System.out.println("yes!");
+ else
+ System.out.println("no!");
+ }
+}
diff --git a/tests/024-illegal-access/src/Main.java b/tests/024-illegal-access/src/Main.java
index 97fc55f5a..bde73e945 100644
--- a/tests/024-illegal-access/src/Main.java
+++ b/tests/024-illegal-access/src/Main.java
@@ -1,5 +1,41 @@
+/*
+ * 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.
+ */
+
public class Main {
static public void main(String[] args) {
- PublicAccess.main();
+ try {
+ PublicAccess.main();
+ System.err.println("ERROR: call 1 not expected to succeed");
+ } catch (VerifyError ve) {
+ // dalvik
+ System.out.println("Got expected failure 1");
+ } catch (IllegalAccessError iae) {
+ // reference
+ System.out.println("Got expected failure 1");
+ }
+
+ try {
+ CheckInstanceof.main(new Object());
+ System.err.println("ERROR: call 2 not expected to succeed");
+ } catch (VerifyError ve) {
+ // dalvik
+ System.out.println("Got expected failure 2");
+ } catch (IllegalAccessError iae) {
+ // reference
+ System.out.println("Got expected failure 2");
+ }
}
}
diff --git a/tests/024-illegal-access/src/otherpkg/Package.java b/tests/024-illegal-access/src/otherpkg/Package.java
new file mode 100644
index 000000000..a82b32149
--- /dev/null
+++ b/tests/024-illegal-access/src/otherpkg/Package.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package otherpkg;
+
+/*
+ * Package-scope class (public here).
+ */
+public class Package {
+}
+
diff --git a/tests/024-illegal-access/src2/otherpkg/Package.java b/tests/024-illegal-access/src2/otherpkg/Package.java
new file mode 100644
index 000000000..7f740d4c5
--- /dev/null
+++ b/tests/024-illegal-access/src2/otherpkg/Package.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package otherpkg;
+
+/*
+ * Package-scope class.
+ */
+class Package {
+}
+
diff --git a/tests/etc/local-run-test-jar b/tests/etc/local-run-test-jar
index 66ca06233..0c802ba37 100755
--- a/tests/etc/local-run-test-jar
+++ b/tests/etc/local-run-test-jar
@@ -24,6 +24,7 @@ GDB="n"
VERIFY="y"
OPTIMIZE="y"
VALGRIND="n"
+DEV_MODE="n"
QUIET="n"
while true; do
@@ -47,6 +48,9 @@ while true; do
elif [ "x$1" = "x--valgrind" ]; then
VALGRIND="y"
shift
+ elif [ "x$1" = "x--dev" ]; then
+ DEV_MODE="y"
+ shift
elif [ "x$1" = "x--no-verify" ]; then
VERIFY="n"
shift
@@ -104,7 +108,11 @@ DATA_DIR=/tmp
DEBUG_OPTS="-Xcheck:jni -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"
export ANDROID_PRINTF_LOG=brief
-export ANDROID_LOG_TAGS='*:s'
+if [ "$DEV_MODE" = "y" ]; then
+ export ANDROID_LOG_TAGS='*:d'
+else
+ export ANDROID_LOG_TAGS='*:s'
+fi
export ANDROID_DATA="$DATA_DIR"
export ANDROID_ROOT="${BASE}/system"
export LD_LIBRARY_PATH="${BASE}/system/lib"
diff --git a/tests/run-test b/tests/run-test
index 82f9721d6..b50390561 100755
--- a/tests/run-test
+++ b/tests/run-test
@@ -83,6 +83,7 @@ while true; do
run_args="${run_args} --valgrind"
shift
elif [ "x$1" = "x--dev" ]; then
+ run_args="${run_args} --dev"
dev_mode="yes"
shift
elif [ "x$1" = "x--update" ]; then
diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c
index 0b8a94d98..2c5e74945 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -327,32 +327,6 @@ static bool isTypeWidthEqual1nr(RegType type1, RegType type2)
}
/*
- * Given a 32-bit constant, return the most-restricted RegType that can hold
- * the value.
- */
-static RegType determineCat1Const(s4 value)
-{
- if (value < -32768)
- return kRegTypeInteger;
- else if (value < -128)
- return kRegTypeShort;
- else if (value < 0)
- return kRegTypeByte;
- else if (value == 0)
- return kRegTypeZero;
- else if (value == 1)
- return kRegTypeOne;
- else if (value < 128)
- return kRegTypePosByte;
- else if (value < 32768)
- return kRegTypePosShort;
- else if (value < 65536)
- return kRegTypeChar;
- else
- return kRegTypeInteger;
-}
-
-/*
* Convert a VM PrimitiveType enum value to the equivalent RegType value.
*/
static RegType primitiveTypeToRegType(PrimitiveType primType)
@@ -923,7 +897,6 @@ bad_sig:
static RegType getMethodReturnType(const Method* meth)
{
RegType type;
- bool okay = true;
const char* descriptor = dexProtoGetReturnType(&meth->prototype);
switch (*descriptor) {
@@ -957,6 +930,7 @@ static RegType getMethodReturnType(const Method* meth)
case 'L':
case '[':
{
+ bool okay = true;
ClassObject* clazz =
lookupClassByDescriptor(meth, descriptor, &okay);
assert(okay);
@@ -2455,7 +2429,7 @@ static void checkFinalFieldAccess(const Method* meth, const Field* field,
/* make sure we're in the same class */
if (meth->clazz != field->clazz) {
- LOG_VFY_METH(meth, "VFY: can't modify final field %s.%\n",
+ LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
field->clazz->descriptor, field->name);
*pOkay = false;
return;
@@ -2716,6 +2690,54 @@ static bool initRegisterTable(const Method* meth, const InsnFlags* insnFlags,
/*
+ * Verify that the arguments in a filled-new-array instruction are valid.
+ *
+ * "resClass" is the class refered to by pDecInsn->vB.
+ */
+static void verifyFilledNewArrayRegs(const Method* meth,
+ const RegType* insnRegs, const int insnRegCount,
+ const DecodedInstruction* pDecInsn, ClassObject* resClass, bool isRange,
+ bool* pOkay)
+{
+ u4 argCount = pDecInsn->vA;
+ RegType expectedType;
+ PrimitiveType elemType;
+ unsigned int ui;
+
+ assert(dvmIsArrayClass(resClass));
+ elemType = resClass->elementClass->primitiveType;
+ if (elemType == PRIM_NOT) {
+ LOG_VFY("VFY: filled-new-array not yet supported on reference types\n");
+ *pOkay = false;
+ return;
+ }
+
+ expectedType = primitiveTypeToRegType(elemType);
+ //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
+
+ /*
+ * Verify each register. If "argCount" is bad, verifyRegisterType()
+ * will run off the end of the list and fail. It's legal, if silly,
+ * for argCount to be zero.
+ */
+ for (ui = 0; ui < argCount; ui++) {
+ u4 getReg;
+
+ if (isRange)
+ getReg = pDecInsn->vC + ui;
+ else
+ getReg = pDecInsn->arg[ui];
+
+ verifyRegisterType(insnRegs, insnRegCount, getReg, expectedType, pOkay);
+ if (!*pOkay) {
+ LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
+ return;
+ }
+ }
+}
+
+
+/*
* ===========================================================================
* Entry point and driver loop
* ===========================================================================
@@ -3309,12 +3331,12 @@ static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
case OP_CONST:
/* could be boolean, int, float, or a null reference */
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- determineCat1Const((s4)decInsn.vB), &okay);
+ dvmDetermineCat1Const((s4)decInsn.vB), &okay);
break;
case OP_CONST_HIGH16:
/* could be boolean, int, float, or a null reference */
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- determineCat1Const((s4) decInsn.vB << 16), &okay);
+ dvmDetermineCat1Const((s4) decInsn.vB << 16), &okay);
break;
case OP_CONST_WIDE_16:
case OP_CONST_WIDE_32:
@@ -3332,8 +3354,18 @@ static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
break;
case OP_CONST_CLASS:
assert(gDvm.classJavaLangClass != NULL);
- setRegisterType(workRegs, insnRegCount, decInsn.vA,
- regTypeFromClass(gDvm.classJavaLangClass), &okay);
+ /* make sure we can resolve the class; access check is important */
+ resClass = dvmOptResolveClass(meth->clazz, decInsn.vB);
+ if (resClass == NULL) {
+ const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
+ dvmLogUnableToResolveClass(badClassDesc, meth);
+ LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
+ decInsn.vB, badClassDesc, meth->clazz->descriptor);
+ okay = false;
+ } else {
+ setRegisterType(workRegs, insnRegCount, decInsn.vA,
+ regTypeFromClass(gDvm.classJavaLangClass), &okay);
+ }
break;
case OP_MONITOR_ENTER:
@@ -3378,17 +3410,29 @@ static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
}
break;
case OP_INSTANCE_OF:
+ /* make sure we're checking a reference type */
tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &okay);
if (!okay)
break;
if (!regTypeIsReference(tmpType)) {
- LOG_VFY("VFY: vB not a reference\n");
+ LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
okay = false;
break;
}
- /* result is boolean */
- setRegisterType(workRegs, insnRegCount, decInsn.vA,
- kRegTypeBoolean, &okay);
+
+ /* make sure we can resolve the class; access check is important */
+ resClass = dvmOptResolveClass(meth->clazz, decInsn.vC);
+ if (resClass == NULL) {
+ const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
+ dvmLogUnableToResolveClass(badClassDesc, meth);
+ LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
+ decInsn.vC, badClassDesc, meth->clazz->descriptor);
+ okay = false;
+ } else {
+ /* result is boolean */
+ setRegisterType(workRegs, insnRegCount, decInsn.vA,
+ kRegTypeBoolean, &okay);
+ }
break;
case OP_ARRAY_LENGTH:
@@ -3442,7 +3486,7 @@ static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
case OP_NEW_ARRAY:
resClass = dvmOptResolveClass(meth->clazz, decInsn.vC);
if (resClass == NULL) {
- const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
+ const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
dvmLogUnableToResolveClass(badClassDesc, meth);
LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
decInsn.vC, badClassDesc, meth->clazz->descriptor);
@@ -3451,6 +3495,9 @@ static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
LOG_VFY("VFY: new-array on non-array class\n");
okay = false;
} else {
+ /* make sure "size" register is valid type */
+ verifyRegisterType(workRegs, insnRegCount, decInsn.vB,
+ kRegTypeInteger, &okay);
/* set register type to array class */
setRegisterType(workRegs, insnRegCount, decInsn.vA,
regTypeFromClass(resClass), &okay);
@@ -3458,7 +3505,6 @@ static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
break;
case OP_FILLED_NEW_ARRAY:
case OP_FILLED_NEW_ARRAY_RANGE:
- /* (decInsn.vA == 0) is silly, but not illegal */
resClass = dvmOptResolveClass(meth->clazz, decInsn.vB);
if (resClass == NULL) {
const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
@@ -3470,13 +3516,11 @@ static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
LOG_VFY("VFY: filled-new-array on non-array class\n");
okay = false;
} else {
- /*
- * TODO: verify decInsn.vA range
- * TODO: if resClass is array of references, verify the registers
- * in the argument list against the array type.
- * TODO: if resClass is array of primitives, verify that the
- * contents of the registers are appropriate.
- */
+ bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
+
+ /* check the arguments to the instruction */
+ verifyFilledNewArrayRegs(meth, workRegs, insnRegCount, &decInsn,
+ resClass, isRange, &okay);
/* filled-array result goes into "result" register */
setResultRegisterType(workRegs, insnRegCount,
regTypeFromClass(resClass), &okay);
@@ -3802,6 +3846,7 @@ aget_1nr_common:
if (!okay)
break;
+ /* get the class of the array we're pulling an object from */
resClass = getClassFromRegister(workRegs, insnRegCount,
decInsn.vB, &okay);
if (!okay)
@@ -3811,7 +3856,7 @@ aget_1nr_common:
assert(resClass != NULL);
if (!dvmIsArrayClass(resClass)) {
- LOG_VFY("VFY: aget-object on non-ref array class\n");
+ LOG_VFY("VFY: aget-object on non-array class\n");
okay = false;
break;
}
@@ -3826,9 +3871,14 @@ aget_1nr_common:
assert(resClass->arrayDim > 1);
elementClass = dvmFindArrayClass(&resClass->descriptor[1],
resClass->classLoader);
- } else {
+ } else if (resClass->descriptor[1] == 'L') {
assert(resClass->arrayDim == 1);
elementClass = resClass->elementClass;
+ } else {
+ LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
+ resClass->descriptor);
+ okay = false;
+ break;
}
dstType = regTypeFromClass(elementClass);
@@ -4655,7 +4705,7 @@ sput_1nr_common:
case OP_INVOKE_INTERFACE:
case OP_INVOKE_INTERFACE_RANGE:
{
- RegType thisType, returnType;
+ RegType /*thisType,*/ returnType;
Method* absMethod;
bool isRange;
@@ -4666,6 +4716,7 @@ sput_1nr_common:
if (!okay)
break;
+#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
/*
* Get the type of the "this" arg, which should always be an
* interface class. Because we don't do a full merge on
@@ -4676,7 +4727,6 @@ sput_1nr_common:
if (!okay)
break;
-#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
if (thisType == kRegTypeZero) {
/* null pointer always passes (and always fails at runtime) */
} else {
@@ -4934,10 +4984,40 @@ sput_1nr_common:
break;
+ /*
+ * Verifying "quickened" instructions is tricky, because we have
+ * discarded the original field/method information. The byte offsets
+ * and vtable indices only have meaning in the context of an object
+ * instance.
+ *
+ * If a piece of code declares a local reference variable, assigns
+ * null to it, and then issues a virtual method call on it, we
+ * cannot evaluate the method call during verification. This situation
+ * isn't hard to handle, since we know the call will always result in an
+ * NPE, and the arguments and return value don't matter. Any code that
+ * depends on the result of the method call is inaccessible, so the
+ * fact that we can't fully verify anything that comes after the bad
+ * call is not a problem.
+ *
+ * We must also consider the case of multiple code paths, only some of
+ * which involve a null reference. We can completely verify the method
+ * if we sidestep the results of executing with a null reference.
+ * For example, if on the first pass through the code we try to do a
+ * virtual method invocation through a null ref, we have to skip the
+ * method checks and have the method return a "wildcard" type (which
+ * merges with anything to become that other thing). The move-result
+ * will tell us if it's a reference, single-word numeric, or double-word
+ * value. We continue to perform the verification, and at the end of
+ * the function any invocations that were never fully exercised are
+ * marked as null-only.
+ *
+ * We would do something similar for the field accesses. The field's
+ * type, once known, can be used to recover the width of short integers.
+ * If the object reference was null, the field-get returns the "wildcard"
+ * type, which is acceptable for any operation.
+ */
case OP_EXECUTE_INLINE:
case OP_INVOKE_DIRECT_EMPTY:
- okay = false; // TODO - implement optimized opcodes
- break;
case OP_IGET_QUICK:
case OP_IGET_WIDE_QUICK:
case OP_IGET_OBJECT_QUICK:
@@ -4948,7 +5028,7 @@ sput_1nr_common:
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_SUPER_QUICK:
case OP_INVOKE_SUPER_QUICK_RANGE:
- okay = false; // TODO - implement optimized opcodes
+ okay = false;
break;
/* these should never appear */
diff --git a/vm/analysis/DexOptimize.c b/vm/analysis/DexOptimize.c
index 90e4c6feb..09199dbab 100644
--- a/vm/analysis/DexOptimize.c
+++ b/vm/analysis/DexOptimize.c
@@ -1657,7 +1657,7 @@ ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx)
bool allowed = dvmCheckClassAccess(referrer, resClass);
untweakLoader(referrer, resClass);
if (!allowed) {
- LOGI("DexOpt: resolve class illegal access: %s -> %s\n",
+ LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
referrer->descriptor, resClass->descriptor);
return NULL;
}
diff --git a/vm/analysis/DexVerify.c b/vm/analysis/DexVerify.c
index f78133bb3..5a3e8bdad 100644
--- a/vm/analysis/DexVerify.c
+++ b/vm/analysis/DexVerify.c
@@ -331,13 +331,20 @@ static void decodeInstruction(const Method* meth, int insnIdx,
*/
static bool checkNewInstance(const Method* meth, int insnIdx)
{
- DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
+ DvmDex* pDvmDex = meth->clazz->pDvmDex;
DecodedInstruction decInsn;
const char* classDescriptor;
+ u4 idx;
decodeInstruction(meth, insnIdx, &decInsn);
- classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vB); // 2nd item
+ idx = decInsn.vB; // 2nd item
+ if (idx >= pDvmDex->pHeader->typeIdsSize) {
+ LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
+ idx, pDvmDex->pHeader->typeIdsSize);
+ return false;
+ }
+ classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
if (classDescriptor[0] != 'L') {
LOG_VFY_METH(meth, "VFY: can't call new-instance on type '%s'\n",
classDescriptor);
@@ -354,12 +361,20 @@ static bool checkNewInstance(const Method* meth, int insnIdx)
*/
static bool checkNewArray(const Method* meth, int insnIdx)
{
- DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
+ DvmDex* pDvmDex = meth->clazz->pDvmDex;
DecodedInstruction decInsn;
const char* classDescriptor;
+ u4 idx;
decodeInstruction(meth, insnIdx, &decInsn);
- classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vC); // 3rd item
+ idx = decInsn.vC; // 3rd item
+ if (idx >= pDvmDex->pHeader->typeIdsSize) {
+ LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
+ idx, pDvmDex->pHeader->typeIdsSize);
+ return false;
+ }
+
+ classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
int bracketCount = 0;
const char* cp = classDescriptor;
@@ -589,7 +604,7 @@ static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
break;
case OP_FILLED_NEW_ARRAY:
- if (!checkTypeIndex(meth, i, false))
+ if (!checkTypeIndex(meth, i, true))
return false;
break;
case OP_FILLED_NEW_ARRAY_RANGE:
diff --git a/vm/analysis/RegisterMap.c b/vm/analysis/RegisterMap.c
index 8e0054ebf..eb243af2a 100644
--- a/vm/analysis/RegisterMap.c
+++ b/vm/analysis/RegisterMap.c
@@ -14,11 +14,13 @@
* limitations under the License.
*/
+// ** UNDER CONSTRUCTION **
+
/*
* This code generate "register maps" for Dalvik bytecode. In a stack-based
- * VM we would call these "stack maps". They are used to increase the
- * precision in the garbage collector when finding references in the
- * interpreter call stack.
+ * VM we might call these "stack maps". They are used to increase the
+ * precision in the garbage collector when scanning references in the
+ * interpreter thread stacks.
*/
#include "Dalvik.h"
#include "analysis/CodeVerify.h"
@@ -36,6 +38,11 @@ results in the optimized DEX file, which increases their size by about 25%
unless we use compression, and for performance reasons we don't want to
just re-run the verifier.
+On the plus side, we know that verification has completed successfully --
+or at least are allowed to assume that it would -- so we skip a lot of
+the checks (like verifying that the register indices in instructions
+are reasonable).
+
Both type-precise and live-precise information can be generated knowing
only whether or not a register holds a reference. We don't need to
know what kind of reference or whether the object has been initialized.
@@ -64,7 +71,7 @@ typedef u1 SRegType;
* can be category 1 or 2, so we need two slots.
*/
#define kExtraRegs 2
-#define RESULT_REGISTER(_insnRegCount) (_insnRegCount)
+#define RESULT_REGISTER(_insnRegCountPlus) (_insnRegCountPlus - kExtraRegs)
/*
* Working state.
@@ -84,7 +91,7 @@ typedef struct WorkState {
* Number of registers we track for each instruction. This is equal
* to the method's declared "registersSize" plus kExtraRegs.
*/
- int insnRegCount;
+ int insnRegCountPlus;
/*
* Instruction widths and flags, one entry per code unit.
@@ -197,7 +204,7 @@ RegisterMap* dvmGenerateRegisterMap(const Method* meth)
pState->method = meth;
pState->insnsSize = dvmGetMethodInsnsSize(meth);
- pState->insnRegCount = meth->registersSize + kExtraRegs;
+ pState->insnRegCountPlus = meth->registersSize + kExtraRegs;
pState->insnFlags = calloc(sizeof(InsnFlags), pState->insnsSize);
pState->addrRegs = calloc(sizeof(SRegType*), pState->insnsSize);
@@ -228,7 +235,7 @@ RegisterMap* dvmGenerateRegisterMap(const Method* meth)
for (offset = 0; offset < pState->insnsSize; offset++) {
if (dvmInsnIsGcPoint(pState->insnFlags, offset)) {
pState->addrRegs[offset] = regPtr;
- regPtr += pState->insnRegCount;
+ regPtr += pState->insnRegCountPlus;
}
}
assert(regPtr - pState->regAlloc == pState->insnsSize * gcPointCount);
@@ -313,7 +320,7 @@ static bool setTypesFromSignature(WorkState* pState)
while (*ccp != 0) {
switch (*ccp) {
case 'L':
- case '[':
+ //case '[':
*pCurReg++ = kRegTypeReference;
break;
case 'Z':
@@ -386,7 +393,7 @@ static inline int compareRegisters(const SRegType* src1, const SRegType* src2,
static bool analyzeMethod(WorkState* pState)
{
const Method* meth = pState->method;
- SRegType workRegs[pState->insnRegCount];
+ SRegType workRegs[pState->insnRegCountPlus];
InsnFlags* insnFlags = pState->insnFlags;
int insnsSize = pState->insnsSize;
int insnIdx, startGuess;
@@ -454,7 +461,7 @@ static bool analyzeMethod(WorkState* pState)
if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
SRegType* insnRegs = getRegisterLine(pState, insnIdx);
assert(insnRegs != NULL);
- copyRegisters(workRegs, insnRegs, pState->insnRegCount);
+ copyRegisters(workRegs, insnRegs, pState->insnRegCountPlus);
} else {
#ifndef NDEBUG
@@ -464,7 +471,8 @@ static bool analyzeMethod(WorkState* pState)
*/
SRegType* insnRegs = getRegisterLine(pState, insnIdx);
if (insnRegs != NULL &&
- compareRegisters(workRegs, insnRegs, pState->insnRegCount) != 0)
+ compareRegisters(workRegs, insnRegs,
+ pState->insnRegCountPlus) != 0)
{
char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
LOG_VFY("HUH? workRegs diverged in %s.%s %s\n",
@@ -494,6 +502,129 @@ bail:
}
/*
+ * Get a pointer to the method being invoked.
+ *
+ * Returns NULL on failure.
+ */
+static Method* getInvokedMethod(const Method* meth,
+ const DecodedInstruction* pDecInsn, MethodType methodType)
+{
+ Method* resMethod;
+ char* sigOriginal = NULL;
+
+ /*
+ * Resolve the method. This could be an abstract or concrete method
+ * depending on what sort of call we're making.
+ */
+ if (methodType == METHOD_INTERFACE) {
+ resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
+ } else {
+ resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType);
+ }
+ if (resMethod == NULL) {
+ /* failed; print a meaningful failure message */
+ DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
+ const DexMethodId* pMethodId;
+ const char* methodName;
+ char* methodDesc;
+ const char* classDescriptor;
+
+ pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
+ methodName = dexStringById(pDexFile, pMethodId->nameIdx);
+ methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
+ classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+ LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n",
+ dvmMethodTypeStr(methodType), pDecInsn->vB,
+ classDescriptor, methodName, methodDesc);
+ free(methodDesc);
+ return NULL;
+ }
+
+ return resMethod;
+}
+
+/*
+ * Return the register type for the method. Since we don't care about
+ * the actual type, we can just look at the "shorty" signature.
+ *
+ * Returns kRegTypeUnknown for "void".
+ */
+static SRegType getMethodReturnType(const Method* meth)
+{
+ SRegType type;
+
+ switch (meth->shorty[0]) {
+ case 'I':
+ type = kRegTypeInteger;
+ break;
+ case 'C':
+ type = kRegTypeChar;
+ break;
+ case 'S':
+ type = kRegTypeShort;
+ break;
+ case 'B':
+ type = kRegTypeByte;
+ break;
+ case 'Z':
+ type = kRegTypeBoolean;
+ break;
+ case 'V':
+ type = kRegTypeUnknown;
+ break;
+ case 'F':
+ type = kRegTypeFloat;
+ break;
+ case 'D':
+ type = kRegTypeDoubleLo;
+ break;
+ case 'J':
+ type = kRegTypeLongLo;
+ break;
+ case 'L':
+ //case '[':
+ type = kRegTypeReference;
+ break;
+ default:
+ /* we verified signature return type earlier, so this is impossible */
+ assert(false);
+ type = kRegTypeConflict;
+ break;
+ }
+
+ return type;
+}
+
+/*
+ * Copy a category 1 register.
+ */
+static inline void copyRegister1(SRegType* insnRegs, u4 vdst, u4 vsrc)
+{
+ insnRegs[vdst] = insnRegs[vsrc];
+}
+
+/*
+ * Copy a category 2 register. Note the source and destination may overlap.
+ */
+static inline void copyRegister2(SRegType* insnRegs, u4 vdst, u4 vsrc)
+{
+ //memmove(&insnRegs[vdst], &insnRegs[vsrc], sizeof(SRegType) * 2);
+ SRegType r1 = insnRegs[vsrc];
+ SRegType r2 = insnRegs[vsrc+1];
+ insnRegs[vdst] = r1;
+ insnRegs[vdst+1] = r2;
+}
+
+/*
+ * Set the type of a category 1 register.
+ */
+static inline void setRegisterType(SRegType* insnRegs, u4 vdst, SRegType type)
+{
+ insnRegs[vdst] = type;
+}
+
+/*
* Decode the specified instruction and update the register info.
*/
static bool handleInstruction(WorkState* pState, SRegType* workRegs,
@@ -524,14 +655,15 @@ static bool handleInstruction(WorkState* pState, SRegType* workRegs,
* The behavior can be determined from the InstrFlags.
*/
DecodedInstruction decInsn;
- SRegType entryRegs[pState->insnRegCount];
+ SRegType entryRegs[pState->insnRegCountPlus];
+ const int insnRegCountPlus = pState->insnRegCountPlus;
bool justSetResult = false;
int branchTarget = 0;
+ SRegType tmpType;
dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn);
const int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
-
/*
* Make a copy of the previous register state. If the instruction
* throws an exception, we merge *this* into the destination rather
@@ -541,14 +673,537 @@ static bool handleInstruction(WorkState* pState, SRegType* workRegs,
*/
if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
{
- copyRegisters(entryRegs, workRegs, pState->insnRegCount);
+ copyRegisters(entryRegs, workRegs, insnRegCountPlus);
}
switch (decInsn.opCode) {
case OP_NOP:
break;
- default: break; // TODO: fill this in
+ case OP_MOVE:
+ case OP_MOVE_FROM16:
+ case OP_MOVE_16:
+ case OP_MOVE_OBJECT:
+ case OP_MOVE_OBJECT_FROM16:
+ case OP_MOVE_OBJECT_16:
+ copyRegister1(workRegs, decInsn.vA, decInsn.vB);
+ break;
+ case OP_MOVE_WIDE:
+ case OP_MOVE_WIDE_FROM16:
+ case OP_MOVE_WIDE_16:
+ copyRegister2(workRegs, decInsn.vA, decInsn.vB);
+ break;
+
+ /*
+ * The move-result instructions copy data out of a "pseudo-register"
+ * with the results from the last method invocation. In practice we
+ * might want to hold the result in an actual CPU register, so the
+ * Dalvik spec requires that these only appear immediately after an
+ * invoke or filled-new-array.
+ *
+ * These calls invalidate the "result" register. (This is now
+ * redundant with the reset done below, but it can make the debug info
+ * easier to read in some cases.)
+ */
+ case OP_MOVE_RESULT:
+ case OP_MOVE_RESULT_OBJECT:
+ copyRegister1(workRegs, decInsn.vA, RESULT_REGISTER(insnRegCountPlus));
+ break;
+ case OP_MOVE_RESULT_WIDE:
+ copyRegister2(workRegs, decInsn.vA, RESULT_REGISTER(insnRegCountPlus));
+ break;
+
+ case OP_MOVE_EXCEPTION:
+ /*
+ * This statement can only appear as the first instruction in an
+ * exception handler (though not all exception handlers need to
+ * have one of these). We verify that as part of extracting the
+ * exception type from the catch block list.
+ */
+ setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
+ break;
+
+ case OP_RETURN_VOID:
+ case OP_RETURN:
+ case OP_RETURN_WIDE:
+ case OP_RETURN_OBJECT:
+ break;
+
+ case OP_CONST_4:
+ case OP_CONST_16:
+ case OP_CONST:
+ /* could be boolean, int, float, or a null reference */
+ setRegisterType(workRegs, decInsn.vA,
+ dvmDetermineCat1Const((s4)decInsn.vB));
+ break;
+ case OP_CONST_HIGH16:
+ /* could be boolean, int, float, or a null reference */
+ setRegisterType(workRegs, decInsn.vA,
+ dvmDetermineCat1Const((s4) decInsn.vB << 16));
+ break;
+ case OP_CONST_WIDE_16:
+ case OP_CONST_WIDE_32:
+ case OP_CONST_WIDE:
+ case OP_CONST_WIDE_HIGH16:
+ /* could be long or double; default to long and allow conversion */
+ setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
+ break;
+ case OP_CONST_STRING:
+ case OP_CONST_STRING_JUMBO:
+ case OP_CONST_CLASS:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
+ break;
+
+ case OP_MONITOR_ENTER:
+ case OP_MONITOR_EXIT:
+ break;
+
+ case OP_CHECK_CAST:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
+ break;
+ case OP_INSTANCE_OF:
+ /* result is boolean */
+ setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
+ break;
+
+ case OP_ARRAY_LENGTH:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
+ break;
+
+ case OP_NEW_INSTANCE:
+ case OP_NEW_ARRAY:
+ /* add the new uninitialized reference to the register ste */
+ setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
+ break;
+ case OP_FILLED_NEW_ARRAY:
+ case OP_FILLED_NEW_ARRAY_RANGE:
+ setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus),
+ kRegTypeReference);
+ justSetResult = true;
+ break;
+
+ case OP_CMPL_FLOAT:
+ case OP_CMPG_FLOAT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
+ break;
+ case OP_CMPL_DOUBLE:
+ case OP_CMPG_DOUBLE:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
+ break;
+ case OP_CMP_LONG:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
+ break;
+
+ case OP_THROW:
+ case OP_GOTO:
+ case OP_GOTO_16:
+ case OP_GOTO_32:
+ case OP_PACKED_SWITCH:
+ case OP_SPARSE_SWITCH:
+ break;
+
+ case OP_FILL_ARRAY_DATA:
+ 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:
+ case OP_IF_EQZ:
+ case OP_IF_NEZ:
+ case OP_IF_LTZ:
+ case OP_IF_GEZ:
+ case OP_IF_GTZ:
+ case OP_IF_LEZ:
+ break;
+
+ case OP_AGET:
+ tmpType = kRegTypeInteger;
+ goto aget_1nr_common;
+ case OP_AGET_BOOLEAN:
+ tmpType = kRegTypeBoolean;
+ goto aget_1nr_common;
+ case OP_AGET_BYTE:
+ tmpType = kRegTypeByte;
+ goto aget_1nr_common;
+ case OP_AGET_CHAR:
+ tmpType = kRegTypeChar;
+ goto aget_1nr_common;
+ case OP_AGET_SHORT:
+ tmpType = kRegTypeShort;
+ goto aget_1nr_common;
+aget_1nr_common:
+ setRegisterType(workRegs, decInsn.vA, tmpType);
+ break;
+
+ case OP_AGET_WIDE:
+ /*
+ * We know this is either long or double, and we don't really
+ * discriminate between those during verification, so we
+ * call it a long.
+ */
+ setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
+ break;
+
+ case OP_AGET_OBJECT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
+ break;
+
+ case OP_APUT:
+ case OP_APUT_BOOLEAN:
+ case OP_APUT_BYTE:
+ case OP_APUT_CHAR:
+ case OP_APUT_SHORT:
+ case OP_APUT_WIDE:
+ case OP_APUT_OBJECT:
+ break;
+
+ case OP_IGET:
+ tmpType = kRegTypeInteger;
+ goto iget_1nr_common;
+ case OP_IGET_BOOLEAN:
+ tmpType = kRegTypeBoolean;
+ goto iget_1nr_common;
+ case OP_IGET_BYTE:
+ tmpType = kRegTypeByte;
+ goto iget_1nr_common;
+ case OP_IGET_CHAR:
+ tmpType = kRegTypeChar;
+ goto iget_1nr_common;
+ case OP_IGET_SHORT:
+ tmpType = kRegTypeShort;
+ goto iget_1nr_common;
+iget_1nr_common:
+ setRegisterType(workRegs, decInsn.vA, tmpType);
+ break;
+
+ case OP_IGET_WIDE:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
+ break;
+
+ case OP_IGET_OBJECT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
+ break;
+
+ case OP_IPUT:
+ case OP_IPUT_BOOLEAN:
+ case OP_IPUT_BYTE:
+ case OP_IPUT_CHAR:
+ case OP_IPUT_SHORT:
+ case OP_IPUT_WIDE:
+ case OP_IPUT_OBJECT:
+ break;
+
+ case OP_SGET:
+ tmpType = kRegTypeInteger;
+ goto sget_1nr_common;
+ case OP_SGET_BOOLEAN:
+ tmpType = kRegTypeBoolean;
+ goto sget_1nr_common;
+ case OP_SGET_BYTE:
+ tmpType = kRegTypeByte;
+ goto sget_1nr_common;
+ case OP_SGET_CHAR:
+ tmpType = kRegTypeChar;
+ goto sget_1nr_common;
+ case OP_SGET_SHORT:
+ tmpType = kRegTypeShort;
+ goto sget_1nr_common;
+sget_1nr_common:
+ setRegisterType(workRegs, decInsn.vA, tmpType);
+ break;
+
+ case OP_SGET_WIDE:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
+ break;
+
+ case OP_SGET_OBJECT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
+ break;
+
+ case OP_SPUT:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_SHORT:
+ case OP_SPUT_WIDE:
+ case OP_SPUT_OBJECT:
+ break;
+
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_VIRTUAL_RANGE:
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_SUPER_RANGE:
+ {
+ Method* calledMethod;
+
+ calledMethod = getInvokedMethod(meth, &decInsn, METHOD_VIRTUAL);
+ if (calledMethod == NULL)
+ goto bail;
+ setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus),
+ getMethodReturnType(calledMethod));
+ justSetResult = true;
+ }
+ break;
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_DIRECT_RANGE:
+ {
+ Method* calledMethod;
+
+ calledMethod = getInvokedMethod(meth, &decInsn, METHOD_DIRECT);
+ if (calledMethod == NULL)
+ goto bail;
+ setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus),
+ getMethodReturnType(calledMethod));
+ justSetResult = true;
+ }
+ break;
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_STATIC_RANGE:
+ {
+ Method* calledMethod;
+
+ calledMethod = getInvokedMethod(meth, &decInsn, METHOD_STATIC);
+ if (calledMethod == NULL)
+ goto bail;
+ setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus),
+ getMethodReturnType(calledMethod));
+ justSetResult = true;
+ }
+ break;
+ case OP_INVOKE_INTERFACE:
+ case OP_INVOKE_INTERFACE_RANGE:
+ {
+ Method* absMethod;
+
+ absMethod = getInvokedMethod(meth, &decInsn, METHOD_INTERFACE);
+ if (absMethod == NULL)
+ goto bail;
+ setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus),
+ getMethodReturnType(absMethod));
+ justSetResult = true;
+ }
+ break;
+
+ case OP_NEG_INT:
+ case OP_NOT_INT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
+ break;
+ case OP_NEG_LONG:
+ case OP_NOT_LONG:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
+ break;
+ case OP_NEG_FLOAT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
+ break;
+ case OP_NEG_DOUBLE:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
+ break;
+ case OP_INT_TO_LONG:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
+ break;
+ case OP_INT_TO_FLOAT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
+ break;
+ case OP_INT_TO_DOUBLE:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
+ break;
+ case OP_LONG_TO_INT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
+ break;
+ case OP_LONG_TO_FLOAT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
+ break;
+ case OP_LONG_TO_DOUBLE:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
+ break;
+ case OP_FLOAT_TO_INT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
+ break;
+ case OP_FLOAT_TO_LONG:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
+ break;
+ case OP_FLOAT_TO_DOUBLE:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
+ break;
+ case OP_DOUBLE_TO_INT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
+ break;
+ case OP_DOUBLE_TO_LONG:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
+ break;
+ case OP_DOUBLE_TO_FLOAT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
+ break;
+ case OP_INT_TO_BYTE:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeByte);
+ break;
+ case OP_INT_TO_CHAR:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeChar);
+ break;
+ case OP_INT_TO_SHORT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeShort);
+ break;
+
+ case OP_ADD_INT:
+ case OP_SUB_INT:
+ case OP_MUL_INT:
+ case OP_REM_INT:
+ case OP_DIV_INT:
+ case OP_SHL_INT:
+ case OP_SHR_INT:
+ case OP_USHR_INT:
+ case OP_AND_INT:
+ case OP_OR_INT:
+ case OP_XOR_INT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
+ break;
+ 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:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
+ break;
+ case OP_ADD_FLOAT:
+ case OP_SUB_FLOAT:
+ case OP_MUL_FLOAT:
+ case OP_DIV_FLOAT:
+ case OP_REM_FLOAT:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
+ break;
+ case OP_ADD_DOUBLE:
+ case OP_SUB_DOUBLE:
+ case OP_MUL_DOUBLE:
+ case OP_DIV_DOUBLE:
+ case OP_REM_DOUBLE:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
+ break;
+ case OP_ADD_INT_2ADDR:
+ case OP_SUB_INT_2ADDR:
+ case OP_MUL_INT_2ADDR:
+ case OP_REM_INT_2ADDR:
+ case OP_SHL_INT_2ADDR:
+ case OP_SHR_INT_2ADDR:
+ case OP_USHR_INT_2ADDR:
+ case OP_AND_INT_2ADDR:
+ case OP_OR_INT_2ADDR:
+ case OP_XOR_INT_2ADDR:
+ case OP_DIV_INT_2ADDR:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
+ break;
+ 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:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
+ break;
+ 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:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
+ break;
+ 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:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
+ break;
+ 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:
+ 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_SHL_INT_LIT8:
+ case OP_SHR_INT_LIT8:
+ case OP_USHR_INT_LIT8:
+ case OP_AND_INT_LIT8:
+ case OP_OR_INT_LIT8:
+ case OP_XOR_INT_LIT8:
+ setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
+ break;
+
+
+ /*
+ * See comments in analysis/CodeVerify.c re: why some of these are
+ * annoying to deal with. In here, "annoying" turns into "impossible",
+ * since we make no effort to keep reference type info.
+ *
+ * Handling most of these would require retaining the field/method
+ * reference info that we discarded when the instructions were
+ * quickened.
+ */
+ case OP_EXECUTE_INLINE:
+ case OP_INVOKE_DIRECT_EMPTY:
+ 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:
+ case OP_INVOKE_VIRTUAL_QUICK:
+ case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+ case OP_INVOKE_SUPER_QUICK:
+ case OP_INVOKE_SUPER_QUICK_RANGE:
+ dvmAbort(); // can't work
+ break;
+
+
+ /* these should never appear */
+ case OP_UNUSED_3E:
+ case OP_UNUSED_3F:
+ case OP_UNUSED_40:
+ case OP_UNUSED_41:
+ case OP_UNUSED_42:
+ case OP_UNUSED_43:
+ case OP_UNUSED_73:
+ case OP_UNUSED_79:
+ case OP_UNUSED_7A:
+ case OP_UNUSED_E3:
+ case OP_UNUSED_E4:
+ case OP_UNUSED_E5:
+ case OP_UNUSED_E6:
+ case OP_UNUSED_E7:
+ case OP_UNUSED_E8:
+ case OP_UNUSED_E9:
+ case OP_UNUSED_EA:
+ case OP_UNUSED_EB:
+ case OP_UNUSED_EC:
+ case OP_UNUSED_ED:
+ case OP_UNUSED_EF:
+ case OP_UNUSED_F1:
+ case OP_UNUSED_FC:
+ case OP_UNUSED_FD:
+ case OP_UNUSED_FE:
+ case OP_UNUSED_FF:
+ dvmAbort();
+ break;
/*
* DO NOT add a "default" clause here. Without it the compiler will
@@ -563,7 +1218,7 @@ static bool handleInstruction(WorkState* pState, SRegType* workRegs,
* the verifier.
*/
if (!justSetResult) {
- int reg = RESULT_REGISTER(pState->insnRegCount);
+ int reg = RESULT_REGISTER(pState->insnRegCountPlus);
workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown;
}
@@ -585,7 +1240,7 @@ static bool handleInstruction(WorkState* pState, SRegType* workRegs,
/* if not yet visited, or regs were updated, set "changed" */
if (!dvmInsnIsVisited(insnFlags, insnIdx+insnWidth) ||
compareRegisters(workRegs, entryRegs,
- pState->insnRegCount) != 0)
+ pState->insnRegCountPlus) != 0)
{
dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
}
@@ -747,7 +1402,7 @@ static void updateRegisters(WorkState* pState, int nextInsn,
{
const Method* meth = pState->method;
InsnFlags* insnFlags = pState->insnFlags;
- const int insnRegCount = pState->insnRegCount;
+ const int insnRegCountPlus = pState->insnRegCountPlus;
SRegType* targetRegs = getRegisterLine(pState, nextInsn);
if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
@@ -759,7 +1414,7 @@ static void updateRegisters(WorkState* pState, int nextInsn,
* just an optimization.)
*/
LOGVV("COPY into 0x%04x\n", nextInsn);
- copyRegisters(targetRegs, workRegs, insnRegCount);
+ copyRegisters(targetRegs, workRegs, insnRegCountPlus);
dvmInsnSetChanged(insnFlags, nextInsn, true);
} else {
/* merge registers, set Changed only if different */
@@ -767,7 +1422,7 @@ static void updateRegisters(WorkState* pState, int nextInsn,
bool changed = false;
int i;
- for (i = 0; i < insnRegCount; i++) {
+ for (i = 0; i < insnRegCountPlus; i++) {
targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed);
}
diff --git a/vm/analysis/RegisterMap.h b/vm/analysis/RegisterMap.h
index d431aa7ce..07071d2d4 100644
--- a/vm/analysis/RegisterMap.h
+++ b/vm/analysis/RegisterMap.h
@@ -15,17 +15,21 @@
*/
/*
- * Register map declaration.
+ * Declaration of register map data structure and related functions.
*/
#ifndef _DALVIK_REGISTERMAP
#define _DALVIK_REGISTERMAP
+/*
+ * This is a single variable-size structure. It may be allocated on the
+ * heap or mapped out of a DEX file.
+ */
typedef struct RegisterMap {
/* header */
char addrWidth; /* bytes per address, 1 or 2 */
char regWidth; /* bytes per register line, 1+ */
- char pad0;
- char pad1;
+
+ /* char pad0, pad1; */
/* entries start here; 32-bit align guaranteed */
u4 entries[1];
diff --git a/vm/analysis/VerifySubs.c b/vm/analysis/VerifySubs.c
index 77134a733..8dcc6f8dc 100644
--- a/vm/analysis/VerifySubs.c
+++ b/vm/analysis/VerifySubs.c
@@ -195,6 +195,7 @@ bool dvmCheckSwitchTargets(const Method* meth, InsnFlags* insnFlags,
const int insnCount = dvmGetMethodInsnsSize(meth);
const u2* insns = meth->insns + curOffset;
const u2* switchInsns;
+ u2 expectedSignature;
int switchCount, tableSize;
int offsetToSwitch, offsetToKeys, offsetToTargets, targ;
int offset, absOffset;
@@ -229,13 +230,22 @@ bool dvmCheckSwitchTargets(const Method* meth, InsnFlags* insnFlags,
/* 0=sig, 1=count, 2/3=firstKey */
offsetToTargets = 4;
offsetToKeys = -1;
+ expectedSignature = kPackedSwitchSignature;
} else {
/* 0=sig, 1=count, 2..count*2 = keys */
offsetToKeys = 2;
offsetToTargets = 2 + 2*switchCount;
+ expectedSignature = kSparseSwitchSignature;
}
tableSize = offsetToTargets + switchCount*2;
+ if (switchInsns[0] != expectedSignature) {
+ LOG_VFY_METH(meth,
+ "VFY: wrong signature for switch table (0x%04x, wanted 0x%04x)\n",
+ switchInsns[0], expectedSignature);
+ return false;
+ }
+
/* make sure the end of the switch is in range */
if (curOffset + offsetToSwitch + tableSize > insnCount) {
LOG_VFY_METH(meth,
@@ -368,6 +378,9 @@ void dvmLogVerifyFailure(const Method* meth, const char* format, ...)
/*
* Show a relatively human-readable message describing the failure to
* resolve a class.
+ *
+ * TODO: this is somewhat misleading when resolution fails because of
+ * illegal access rather than nonexistent class.
*/
void dvmLogUnableToResolveClass(const char* missingClassDescr,
const Method* meth)
@@ -434,4 +447,29 @@ bool dvmGetBranchTarget(const Method* meth, InsnFlags* insnFlags,
return true;
}
+/*
+ * Given a 32-bit constant, return the most-restricted RegType enum entry
+ * that can hold the value.
+ */
+char dvmDetermineCat1Const(s4 value)
+{
+ if (value < -32768)
+ return kRegTypeInteger;
+ else if (value < -128)
+ return kRegTypeShort;
+ else if (value < 0)
+ return kRegTypeByte;
+ else if (value == 0)
+ return kRegTypeZero;
+ else if (value == 1)
+ return kRegTypeOne;
+ else if (value < 128)
+ return kRegTypePosByte;
+ else if (value < 32768)
+ return kRegTypePosShort;
+ else if (value < 65536)
+ return kRegTypeChar;
+ else
+ return kRegTypeInteger;
+}
diff --git a/vm/analysis/VerifySubs.h b/vm/analysis/VerifySubs.h
index 4a317d4ee..4d5b57ce8 100644
--- a/vm/analysis/VerifySubs.h
+++ b/vm/analysis/VerifySubs.h
@@ -67,4 +67,7 @@ void dvmLogUnableToResolveClass(const char* missingClassDescr,
bool dvmGetBranchTarget(const Method* meth, InsnFlags* insnFlags,
int curOffset, int* pOffset, bool* pConditional);
+/* return a RegType enumeration value that "value" just fits into */
+char dvmDetermineCat1Const(s4 value);
+
#endif /*_DALVIK_VERIFYSUBS*/
diff --git a/vm/mterp/NOTES.txt b/vm/mterp/NOTES.txt
index b7b9bc0ed..e348934e8 100644
--- a/vm/mterp/NOTES.txt
+++ b/vm/mterp/NOTES.txt
@@ -35,3 +35,38 @@ result into the specified destination register. Using a virtual register
to hold a partial or temporary result is not allowed. Virtual registers
must not be modified if we abort the instruction with an exception.
+
+==== Method results and GC ====
+
+The return value from a method is held in local storage (on the native
+stack for the portable interpreter, and in glue->retval for asm). It's not
+accessible to a GC. In practice this isn't a problem, because if the
+following instruction is not a "move-result" then the result is ignored,
+and none of the move-result* instructions are GC points.
+
+(This is potentially an issue when debugging, since we can theoretically
+single-step by individual bytecodes, but in practice we always step by
+source lines and move-result is grouped with the method invoke.)
+
+This suggests a rule:
+
+ * Don't do anything that can cause a GC in the invoke-* handler after
+ a method returns successfully.
+
+Unsuccessful returns, such as a native method call that returns with an
+exception pending, are not interesting because the return value is ignored.
+
+If it's not possible to obey this rule, then we need to track the value
+used in a return-object instruction for a brief period. The easiest way
+to accomplish this is to store it in the interpreted stack where the GC
+can find it, and use a live-precise GC to ignore the value.
+
+The "trackref" functions can also be used, but they add overhead to method
+calls returning objects, and ensuring that we stop tracking the reference
+when it's no longer needed can be awkward.
+
+Any solution must work correctly when returning into or returning from native
+code. JNI handles returns from interp->native by adding the value to the
+local references table, but returns from native->interp are simply stored
+in the usual "retval".
+
diff --git a/vm/mterp/c/OP_NOT_LONG.c b/vm/mterp/c/OP_NOT_LONG.c
index 4aafe8c58..4fb393ae4 100644
--- a/vm/mterp/c/OP_NOT_LONG.c
+++ b/vm/mterp/c/OP_NOT_LONG.c
@@ -1,2 +1,2 @@
-HANDLE_UNOP(OP_NOT_LONG, "not-long", , & 0xffffffffffffffffULL, _WIDE)
+HANDLE_UNOP(OP_NOT_LONG, "not-long", , ^ 0xffffffffffffffffULL, _WIDE)
OP_END
diff --git a/vm/mterp/out/InterpAsm-x86.S b/vm/mterp/out/InterpAsm-x86.S
index e75fac4a8..857168239 100644
--- a/vm/mterp/out/InterpAsm-x86.S
+++ b/vm/mterp/out/InterpAsm-x86.S
@@ -3146,9 +3146,9 @@ dvmAsmInstructionStart = .L_OP_NOP
andb $0xf,%cl # ecx<- A
FETCH_INST_WORD(1)
ADVANCE_PC(1)
- testl %eax,%eax
- sete %al
- movzbl %al,%eax
+
+
+ notl %eax
SET_VREG(%eax,%ecx)
GOTO_NEXT
@@ -3184,11 +3184,8 @@ dvmAsmInstructionStart = .L_OP_NOP
andb $0xf,rINST_LO # rINST_FULL<- A
GET_VREG_WORD(%eax,%ecx,0) # eax<- v[B+0]
GET_VREG_WORD(%ecx,%ecx,1) # ecx<- v[B+1]
- orl %ecx,%eax
- testl %eax,%eax # any bits set?
- sete %cl
- movzbl %cl,%eax
- movl $0,%ecx
+ notl %eax
+ notl %ecx
SET_VREG_WORD(%eax,rINST_FULL,0) # v[A+0]<- eax
SET_VREG_WORD(%ecx,rINST_FULL,1) # v[A+1]<- ecx
FETCH_INST_WORD(1)
@@ -4306,7 +4303,7 @@ dvmAsmInstructionStart = .L_OP_NOP
movzbl rINST_HI,%ecx # ecx<- AA
FETCH_INST_WORD(2)
1:
- fprem1
+ fprem
fstsw %ax
sahf
jp 1b
@@ -4419,7 +4416,7 @@ dvmAsmInstructionStart = .L_OP_NOP
movzbl rINST_HI,%ecx # ecx<- AA
FETCH_INST_WORD(2)
1:
- fprem1
+ fprem
fstsw %ax
sahf
jp 1b
@@ -5108,7 +5105,7 @@ dvmAsmInstructionStart = .L_OP_NOP
flds (rFP,%ecx,4) # vAA to fp stack
FETCH_INST_WORD(1)
1:
- fprem1
+ fprem
fstsw %ax
sahf
jp 1b
@@ -5221,7 +5218,7 @@ dvmAsmInstructionStart = .L_OP_NOP
fldl (rFP,%ecx,4) # vAA to fp stack
FETCH_INST_WORD(1)
1:
- fprem1
+ fprem
fstsw %ax
sahf
jp 1b
@@ -5251,7 +5248,7 @@ dvmAsmInstructionStart = .L_OP_NOP
movswl 2(rPC),%ecx # ecx<- ssssCCCC
movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
andb $0xf,rINST_LO # rINST_FULL<- A
- addl %ecx,%eax # ex: addl %ecx, %eax
+ addl %ecx,%eax # for example: addl %ecx, %eax
SET_VREG(%eax,rINST_FULL)
FETCH_INST_WORD(2)
ADVANCE_PC(2)
@@ -5262,21 +5259,27 @@ dvmAsmInstructionStart = .L_OP_NOP
.balign 64
.L_OP_RSUB_INT: /* 0xd1 */
/* File: x86/OP_RSUB_INT.S */
-/* File: x86/binop1.S */
+/* File: x86/binopLit16.S */
/*
- * Generic 32-bit binary operation in which both operands loaded to
- * registers (op0 in eax, op1 in ecx).
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = eax op ecx".
+ * This could be an x86 instruction or a function call. (If the result
+ * comes back in a register other than eax, you can override "result".)
+ *
+ * For: add-int/lit16, rsub-int,
+ * and-int/lit16, or-int/lit16, xor-int/lit16
*/
- /* binop vAA, vBB, vCC */
- movzbl 2(rPC),%eax # eax<- BB
- movzbl 3(rPC),%ecx # ecx<- CC
- GET_VREG(%eax,%eax) # eax<- vBB
- GET_VREG(%ecx,%ecx) # eax<- vBB
- subl %eax,%ecx # ex: addl %ecx,%eax
- movzbl rINST_HI,%eax # tmp<- AA
+ /* binop/lit16 vA, vB, #+CCCC */
+ movzbl rINST_HI,%eax # eax<- 000000BA
+ sarl $4,%eax # eax<- B
+ GET_VREG(%eax,%eax) # eax<- vB
+ movswl 2(rPC),%ecx # ecx<- ssssCCCC
+ movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
+ andb $0xf,rINST_LO # rINST_FULL<- A
+ subl %eax,%ecx # for example: addl %ecx, %eax
+ SET_VREG(%ecx,rINST_FULL)
FETCH_INST_WORD(2)
ADVANCE_PC(2)
- SET_VREG(%ecx,%eax)
GOTO_NEXT
@@ -5379,7 +5382,7 @@ dvmAsmInstructionStart = .L_OP_NOP
movswl 2(rPC),%ecx # ecx<- ssssCCCC
movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
andb $0xf,rINST_LO # rINST_FULL<- A
- andl %ecx,%eax # ex: addl %ecx, %eax
+ andl %ecx,%eax # for example: addl %ecx, %eax
SET_VREG(%eax,rINST_FULL)
FETCH_INST_WORD(2)
ADVANCE_PC(2)
@@ -5407,7 +5410,7 @@ dvmAsmInstructionStart = .L_OP_NOP
movswl 2(rPC),%ecx # ecx<- ssssCCCC
movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
andb $0xf,rINST_LO # rINST_FULL<- A
- orl %ecx,%eax # ex: addl %ecx, %eax
+ orl %ecx,%eax # for example: addl %ecx, %eax
SET_VREG(%eax,rINST_FULL)
FETCH_INST_WORD(2)
ADVANCE_PC(2)
@@ -5436,7 +5439,7 @@ dvmAsmInstructionStart = .L_OP_NOP
movswl 2(rPC),%ecx # ecx<- ssssCCCC
movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
andb $0xf,rINST_LO # rINST_FULL<- A
- xor %ecx,%eax # ex: addl %ecx, %eax
+ xor %ecx,%eax # for example: addl %ecx, %eax
SET_VREG(%eax,rINST_FULL)
FETCH_INST_WORD(2)
ADVANCE_PC(2)
@@ -6461,8 +6464,8 @@ dvmAsmSisterStart:
*/
.LOP_NEW_INSTANCE_abstract:
movl offClassObject_descriptor(%ecx),%eax
- movl $.LstrInstantiationError,OUT_ARG1(%esp)
- movl %eax,OUT_ARG0(%esp)
+ movl $.LstrInstantiationError,OUT_ARG0(%esp)
+ movl %eax,OUT_ARG1(%esp)
call dvmThrowExceptionWithClassMessage
UNSPILL(rPC)
jmp common_exceptionThrown
@@ -6582,9 +6585,9 @@ dvmAsmSisterStart:
testl rINST_FULL,rINST_FULL
je 4f
UNSPILL_TMP(rPC)
- andl $0xf0,rPC # rPC<- 000000B0
- sall $12,rPC # rPC<- 000B0000
- orl %ecx,rPC # rpc<- 000BFEDC
+ andl $0x0f,rPC # rPC<- 0000000A
+ sall $16,rPC # rPC<- 000A0000
+ orl %ecx,rPC # rpc<- 000AFEDC
3:
movl $0xf,%ecx
andl rPC,%ecx # ecx<- next reg to load
@@ -6682,9 +6685,9 @@ dvmAsmSisterStart:
testl rINST_FULL,rINST_FULL
je 4f
UNSPILL_TMP(rPC)
- andl $0xf0,rPC # rPC<- 000000B0
- sall $12,rPC # rPC<- 000B0000
- orl %ecx,rPC # rpc<- 000BFEDC
+ andl $0x0f,rPC # rPC<- 0000000A
+ sall $16,rPC # rPC<- 000A0000
+ orl %ecx,rPC # rpc<- 000AFEDC
3:
movl $0xf,%ecx
andl rPC,%ecx # ecx<- next reg to load
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 65b7e1ea2..02592bdff 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -2285,7 +2285,7 @@ HANDLE_UNOP(OP_NEG_LONG, "neg-long", -, , _WIDE)
OP_END
/* File: c/OP_NOT_LONG.c */
-HANDLE_UNOP(OP_NOT_LONG, "not-long", , & 0xffffffffffffffffULL, _WIDE)
+HANDLE_UNOP(OP_NOT_LONG, "not-long", , ^ 0xffffffffffffffffULL, _WIDE)
OP_END
/* File: c/OP_NEG_FLOAT.c */
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index 450490398..cc23d33f3 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -2629,7 +2629,7 @@ HANDLE_UNOP(OP_NEG_LONG, "neg-long", -, , _WIDE)
OP_END
/* File: c/OP_NOT_LONG.c */
-HANDLE_UNOP(OP_NOT_LONG, "not-long", , & 0xffffffffffffffffULL, _WIDE)
+HANDLE_UNOP(OP_NOT_LONG, "not-long", , ^ 0xffffffffffffffffULL, _WIDE)
OP_END
/* File: c/OP_NEG_FLOAT.c */
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index 02a81d87c..78722361b 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -2349,7 +2349,7 @@ HANDLE_UNOP(OP_NEG_LONG, "neg-long", -, , _WIDE)
OP_END
/* File: c/OP_NOT_LONG.c */
-HANDLE_UNOP(OP_NOT_LONG, "not-long", , & 0xffffffffffffffffULL, _WIDE)
+HANDLE_UNOP(OP_NOT_LONG, "not-long", , ^ 0xffffffffffffffffULL, _WIDE)
OP_END
/* File: c/OP_NEG_FLOAT.c */
diff --git a/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S b/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S
index 107717ee2..85b468d78 100644
--- a/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S
+++ b/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S
@@ -89,9 +89,9 @@
testl rINST_FULL,rINST_FULL
je 4f
UNSPILL_TMP(rPC)
- andl $$0xf0,rPC # rPC<- 000000B0
- sall $$12,rPC # rPC<- 000B0000
- orl %ecx,rPC # rpc<- 000BFEDC
+ andl $$0x0f,rPC # rPC<- 0000000A
+ sall $$16,rPC # rPC<- 000A0000
+ orl %ecx,rPC # rpc<- 000AFEDC
3:
movl $$0xf,%ecx
andl rPC,%ecx # ecx<- next reg to load
diff --git a/vm/mterp/x86/OP_NEW_INSTANCE.S b/vm/mterp/x86/OP_NEW_INSTANCE.S
index 299e249f3..da951f746 100644
--- a/vm/mterp/x86/OP_NEW_INSTANCE.S
+++ b/vm/mterp/x86/OP_NEW_INSTANCE.S
@@ -84,8 +84,8 @@
*/
.L${opcode}_abstract:
movl offClassObject_descriptor(%ecx),%eax
- movl $$.LstrInstantiationError,OUT_ARG1(%esp)
- movl %eax,OUT_ARG0(%esp)
+ movl $$.LstrInstantiationError,OUT_ARG0(%esp)
+ movl %eax,OUT_ARG1(%esp)
call dvmThrowExceptionWithClassMessage
UNSPILL(rPC)
jmp common_exceptionThrown
diff --git a/vm/mterp/x86/OP_NOT_INT.S b/vm/mterp/x86/OP_NOT_INT.S
index ba37ca426..c910716d9 100644
--- a/vm/mterp/x86/OP_NOT_INT.S
+++ b/vm/mterp/x86/OP_NOT_INT.S
@@ -1,2 +1,2 @@
%verify "executed"
-%include "x86/unop.S" {"pre0":"testl %eax,%eax","pre1":"sete %al","instr":"movzbl %al,%eax"}
+%include "x86/unop.S" {"instr":"notl %eax"}
diff --git a/vm/mterp/x86/OP_NOT_LONG.S b/vm/mterp/x86/OP_NOT_LONG.S
index b080d23cc..3eca12046 100644
--- a/vm/mterp/x86/OP_NOT_LONG.S
+++ b/vm/mterp/x86/OP_NOT_LONG.S
@@ -6,11 +6,8 @@
andb $$0xf,rINST_LO # rINST_FULL<- A
GET_VREG_WORD(%eax,%ecx,0) # eax<- v[B+0]
GET_VREG_WORD(%ecx,%ecx,1) # ecx<- v[B+1]
- orl %ecx,%eax
- testl %eax,%eax # any bits set?
- sete %cl
- movzbl %cl,%eax
- movl $$0,%ecx
+ notl %eax
+ notl %ecx
SET_VREG_WORD(%eax,rINST_FULL,0) # v[A+0]<- eax
SET_VREG_WORD(%ecx,rINST_FULL,1) # v[A+1]<- ecx
FETCH_INST_WORD(1)
diff --git a/vm/mterp/x86/OP_REM_DOUBLE.S b/vm/mterp/x86/OP_REM_DOUBLE.S
index f28a22432..809ac0a83 100644
--- a/vm/mterp/x86/OP_REM_DOUBLE.S
+++ b/vm/mterp/x86/OP_REM_DOUBLE.S
@@ -7,7 +7,7 @@
movzbl rINST_HI,%ecx # ecx<- AA
FETCH_INST_WORD(2)
1:
- fprem1
+ fprem
fstsw %ax
sahf
jp 1b
diff --git a/vm/mterp/x86/OP_REM_DOUBLE_2ADDR.S b/vm/mterp/x86/OP_REM_DOUBLE_2ADDR.S
index f1131b024..b199e6e52 100644
--- a/vm/mterp/x86/OP_REM_DOUBLE_2ADDR.S
+++ b/vm/mterp/x86/OP_REM_DOUBLE_2ADDR.S
@@ -7,7 +7,7 @@
fldl (rFP,%ecx,4) # vAA to fp stack
FETCH_INST_WORD(1)
1:
- fprem1
+ fprem
fstsw %ax
sahf
jp 1b
diff --git a/vm/mterp/x86/OP_REM_FLOAT.S b/vm/mterp/x86/OP_REM_FLOAT.S
index 1e013684c..d78bc9a2c 100644
--- a/vm/mterp/x86/OP_REM_FLOAT.S
+++ b/vm/mterp/x86/OP_REM_FLOAT.S
@@ -7,7 +7,7 @@
movzbl rINST_HI,%ecx # ecx<- AA
FETCH_INST_WORD(2)
1:
- fprem1
+ fprem
fstsw %ax
sahf
jp 1b
diff --git a/vm/mterp/x86/OP_REM_FLOAT_2ADDR.S b/vm/mterp/x86/OP_REM_FLOAT_2ADDR.S
index 17d3e4eb3..fd1742bfd 100644
--- a/vm/mterp/x86/OP_REM_FLOAT_2ADDR.S
+++ b/vm/mterp/x86/OP_REM_FLOAT_2ADDR.S
@@ -7,7 +7,7 @@
flds (rFP,%ecx,4) # vAA to fp stack
FETCH_INST_WORD(1)
1:
- fprem1
+ fprem
fstsw %ax
sahf
jp 1b
diff --git a/vm/mterp/x86/OP_RSUB_INT.S b/vm/mterp/x86/OP_RSUB_INT.S
index 442ab326d..fa9b410ac 100644
--- a/vm/mterp/x86/OP_RSUB_INT.S
+++ b/vm/mterp/x86/OP_RSUB_INT.S
@@ -1,2 +1,2 @@
%verify "executed"
-%include "x86/binop1.S" {"instr":"subl %eax,%ecx","result":"%ecx","tmp":"%eax"}
+%include "x86/binopLit16.S" {"instr":"subl %eax,%ecx","result":"%ecx"}
diff --git a/vm/mterp/x86/binopLit16.S b/vm/mterp/x86/binopLit16.S
index 9ac8146ca..762068f9e 100644
--- a/vm/mterp/x86/binopLit16.S
+++ b/vm/mterp/x86/binopLit16.S
@@ -1,4 +1,4 @@
-%default {"result":"eax"}
+%default {"result":"%eax"}
/*
* Generic 32-bit "lit16" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = eax op ecx".
@@ -15,8 +15,8 @@
movswl 2(rPC),%ecx # ecx<- ssssCCCC
movzbl rINST_HI,rINST_FULL # rINST_FULL<- BA
andb $$0xf,rINST_LO # rINST_FULL<- A
- $instr # ex: addl %ecx, %eax
- SET_VREG(%eax,rINST_FULL)
+ $instr # for example: addl %ecx, %eax
+ SET_VREG($result,rINST_FULL)
FETCH_INST_WORD(2)
ADVANCE_PC(2)
GOTO_NEXT
diff --git a/vm/oo/Array.c b/vm/oo/Array.c
index cfe2456db..ebddca1ee 100644
--- a/vm/oo/Array.c
+++ b/vm/oo/Array.c
@@ -559,6 +559,8 @@ static ClassObject* createArrayClass(const char* descriptor, Object* loader)
* class in arrays of primitives.
*
* "type" should be 'I', 'J', 'Z', etc.
+ *
+ * Returns NULL if the type doesn't correspond to a known primitive type.
*/
ClassObject* dvmFindPrimitiveClass(char type)
{
@@ -593,8 +595,7 @@ ClassObject* dvmFindPrimitiveClass(char type)
idx = PRIM_VOID;
break;
default:
- LOGE("Unknown primitive type '%c'\n", type);
- assert(false);
+ LOGW("Unknown primitive type '%c'\n", type);
return NULL;
}
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index 7773066cb..ca2870a32 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -2799,48 +2799,48 @@ static bool createIftable(ClassObject* clazz)
assert(idx == ifCount);
- /*
- * Remove anything redundant from our recent additions. Note we have
- * to traverse the recent adds when looking for duplicates, because
- * it's possible the recent additions are self-redundant. This
- * reduces the memory footprint of classes with lots of inherited
- * interfaces.
- *
- * (I don't know if this will cause problems later on when we're trying
- * to find a static field. It looks like the proper search order is
- * (1) current class, (2) interfaces implemented by current class,
- * (3) repeat with superclass. A field implemented by an interface
- * and by a superclass might come out wrong if the superclass also
- * implements the interface. The javac compiler will reject the
- * situation as ambiguous, so the concern is somewhat artificial.)
- *
- * UPDATE: this makes ReferenceType.Interfaces difficult to implement,
- * because it wants to return just the interfaces declared to be
- * implemented directly by the class. I'm excluding this code for now.
- */
if (false) {
- for (i = superIfCount; i < ifCount; i++) {
- int j;
+ /*
+ * Remove anything redundant from our recent additions. Note we have
+ * to traverse the recent adds when looking for duplicates, because
+ * it's possible the recent additions are self-redundant. This
+ * reduces the memory footprint of classes with lots of inherited
+ * interfaces.
+ *
+ * (I don't know if this will cause problems later on when we're trying
+ * to find a static field. It looks like the proper search order is
+ * (1) current class, (2) interfaces implemented by current class,
+ * (3) repeat with superclass. A field implemented by an interface
+ * and by a superclass might come out wrong if the superclass also
+ * implements the interface. The javac compiler will reject the
+ * situation as ambiguous, so the concern is somewhat artificial.)
+ *
+ * UPDATE: this makes ReferenceType.Interfaces difficult to implement,
+ * because it wants to return just the interfaces declared to be
+ * implemented directly by the class. I'm excluding this code for now.
+ */
+ for (i = superIfCount; i < ifCount; i++) {
+ int j;
- for (j = 0; j < ifCount; j++) {
- if (i == j)
- continue;
- if (clazz->iftable[i].clazz == clazz->iftable[j].clazz) {
- LOGVV("INTF: redundant interface %s in %s\n",
- clazz->iftable[i].clazz->descriptor,
- clazz->descriptor);
-
- if (i != ifCount-1)
- memmove(&clazz->iftable[i], &clazz->iftable[i+1],
- (ifCount - i -1) * sizeof(InterfaceEntry));
- ifCount--;
- i--; // adjust for i++ above
- break;
+ for (j = 0; j < ifCount; j++) {
+ if (i == j)
+ continue;
+ if (clazz->iftable[i].clazz == clazz->iftable[j].clazz) {
+ LOGVV("INTF: redundant interface %s in %s\n",
+ clazz->iftable[i].clazz->descriptor,
+ clazz->descriptor);
+
+ if (i != ifCount-1)
+ memmove(&clazz->iftable[i], &clazz->iftable[i+1],
+ (ifCount - i -1) * sizeof(InterfaceEntry));
+ ifCount--;
+ i--; // adjust for i++ above
+ break;
+ }
}
}
- }
- LOGVV("INTF: class '%s' nodupes=%d\n", clazz->descriptor, ifCount);
- } // if (false)
+ LOGVV("INTF: class '%s' nodupes=%d\n", clazz->descriptor, ifCount);
+ } // if (false)
clazz->iftableCount = ifCount;
@@ -2956,6 +2956,13 @@ static bool createIftable(ClassObject* clazz)
== 0)
{
LOGVV("INTF: matched at %d\n", j);
+ if (!dvmIsPublicMethod(clazz->vtable[j])) {
+ LOGW("Implementation of %s.%s is not public\n",
+ clazz->descriptor, clazz->vtable[j]->name);
+ dvmThrowException("Ljava/lang/IllegalAccessError;",
+ "interface implementation not public");
+ goto bail;
+ }
clazz->iftable[i].methodIndexArray[methIdx] = j;
break;
}