summaryrefslogtreecommitdiffstats
path: root/vm/mterp/mips/OP_CHECK_CAST.S
diff options
context:
space:
mode:
Diffstat (limited to 'vm/mterp/mips/OP_CHECK_CAST.S')
-rw-r--r--vm/mterp/mips/OP_CHECK_CAST.S71
1 files changed, 71 insertions, 0 deletions
diff --git a/vm/mterp/mips/OP_CHECK_CAST.S b/vm/mterp/mips/OP_CHECK_CAST.S
new file mode 100644
index 000000000..f29a51f1e
--- /dev/null
+++ b/vm/mterp/mips/OP_CHECK_CAST.S
@@ -0,0 +1,71 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+ /*
+ * Check to see if a cast from one class to another is allowed.
+ */
+ # check-cast vAA, class /* BBBB */
+ GET_OPA(a3) # a3 <- AA
+ FETCH(a2, 1) # a2 <- BBBB
+ GET_VREG(rOBJ, a3) # rOBJ <- object
+ LOAD_rSELF_methodClassDex(a0) # a0 <- pDvmDex
+ LOAD_base_offDvmDex_pResClasses(a0, a0) # a0 <- pDvmDex->pResClasses
+ # is object null?
+ beqz rOBJ, .L${opcode}_okay # null obj, cast always succeeds
+ LOAD_eas2(a1, a0, a2) # a1 <- resolved class
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- obj->clazz
+ # have we resolved this before?
+ beqz a1, .L${opcode}_resolve # not resolved, do it now
+.L${opcode}_resolved:
+ # same class (trivial success)?
+ bne a0, a1, .L${opcode}_fullcheck # no, do full check
+.L${opcode}_okay:
+ FETCH_ADVANCE_INST(2) # advance rPC, load rINST
+ GET_INST_OPCODE(t0) # extract opcode from rINST
+ GOTO_OPCODE(t0) # jump to next instruction
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * a0 holds obj->clazz
+ * a1 holds class resolved from BBBB
+ * rOBJ holds object
+ */
+.L${opcode}_fullcheck:
+ move rBIX,a1 # avoid ClassObject getting clobbered
+ JAL(dvmInstanceofNonTrivial) # v0 <- boolean result
+ # failed?
+ bnez v0, .L${opcode}_okay # no, success
+ b .L${opcode}_castfailure
+%break
+
+.L${opcode}_castfailure:
+ # A cast has failed. We need to throw a ClassCastException with the
+ # class of the object that failed to be cast.
+ EXPORT_PC() # about to throw
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- obj->clazz
+ move a1,rBIX # r1<- desired class
+ JAL(dvmThrowClassCastException)
+ b common_exceptionThrown
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * a2 holds BBBB
+ * rOBJ holds object
+ */
+.L${opcode}_resolve:
+ EXPORT_PC() # resolve() could throw
+ LOAD_rSELF_method(a3) # a3 <- self->method
+ move a1, a2 # a1 <- BBBB
+ li a2, 0 # a2 <- false
+ LOAD_base_offMethod_clazz(a0, a3) # a0 <- method->clazz
+ JAL(dvmResolveClass) # v0 <- resolved ClassObject ptr
+ # got null?
+ beqz v0, common_exceptionThrown # yes, handle exception
+ move a1, v0 # a1 <- class resolved from BBB
+ LOAD_base_offObject_clazz(a0, rOBJ) # a0 <- obj->clazz
+ b .L${opcode}_resolved # pick up where we left off