summaryrefslogtreecommitdiff
path: root/vm/mterp/x86/footer.S
diff options
context:
space:
mode:
Diffstat (limited to 'vm/mterp/x86/footer.S')
-rw-r--r--vm/mterp/x86/footer.S535
1 files changed, 535 insertions, 0 deletions
diff --git a/vm/mterp/x86/footer.S b/vm/mterp/x86/footer.S
new file mode 100644
index 0000000..d43a662
--- /dev/null
+++ b/vm/mterp/x86/footer.S
@@ -0,0 +1,535 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Common subroutines and data.
+ */
+
+/*
+ * Common code when a backwards branch is taken
+ *
+ * On entry:
+ * ebx (a.k.a. rINST_FULL) -> PC adjustment in 16-bit words
+ */
+common_backwardBranch:
+ GET_GLUE(%ecx)
+ call common_periodicChecks # Note: expects rPC to be preserved
+ ADVANCE_PC_INDEXED(rINST_FULL)
+ FETCH_INST()
+ GOTO_NEXT
+
+
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ * eax = Method* methodToCall
+ * rINST trashed, must reload
+ */
+
+common_invokeMethodRange:
+.LinvokeNewRange:
+
+ /*
+ * prepare to copy args to "outs" area of current frame
+ */
+
+ movzbl 1(rPC),rINST_FULL # rINST_FULL<- AA
+ movzwl 4(rPC), %ecx # %ecx<- CCCC
+ SPILL(rPC)
+ SAVEAREA_FROM_FP(%edx,rFP) # %edx<- &StackSaveArea
+ test rINST_FULL, rINST_FULL
+ movl rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
+ jz .LinvokeArgsDone # no args; jump to args done
+
+
+ /*
+ * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count, %edx=&outs (&stackSaveArea)
+ * (very few methods have > 10 args; could unroll for common cases)
+ */
+
+ movl %ebx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- save %ebx
+ lea (rFP, %ecx, 4), %ecx # %ecx<- &vCCCC
+ shll $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
+ subl LOCAL0_OFFSET(%ebp), %edx # %edx<- update &outs
+ shrl $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
+1:
+ movl (%ecx), %ebx # %ebx<- vCCCC
+ lea 4(%ecx), %ecx # %ecx<- &vCCCC++
+ subl $$1, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- LOCAL0_OFFSET--
+ movl %ebx, (%edx) # *outs<- vCCCC
+ lea 4(%edx), %edx # outs++
+ jne 1b # loop if count (LOCAL0_OFFSET(%ebp)) not zero
+ movl LOCAL1_OFFSET(%ebp), %ebx # %ebx<- restore %ebx
+ jmp .LinvokeArgsDone # continue
+
+ /*
+ * %eax is "Method* methodToCall", the method we're trying to call
+ * prepare to copy args to "outs" area of current frame
+ */
+
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+ movzbl 1(rPC),rINST_FULL # rINST_FULL<- BA
+ SPILL(rPC)
+ movl rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
+ shrl $$4, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- B
+ je .LinvokeArgsDone # no args; jump to args done
+ movzwl 4(rPC), %ecx # %ecx<- GFED
+ SAVEAREA_FROM_FP(%edx,rFP) # %edx<- &StackSaveArea
+
+ /*
+ * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
+ */
+
+.LinvokeNonRange:
+ cmp $$2, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 2
+ movl %ecx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- GFED
+ jl 1f # handle 1 arg
+ je 2f # handle 2 args
+ cmp $$4, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 4
+ jl 3f # handle 3 args
+ je 4f # handle 4 args
+5:
+ andl $$15, rINST_FULL # rINST<- A
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, rINST_FULL, 4), %ecx # %ecx<- vA
+ movl %ecx, (%edx) # *outs<- vA
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+4:
+ shr $$12, %ecx # %ecx<- G
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vG
+ movl %ecx, (%edx) # *outs<- vG
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+3:
+ and $$0x0f00, %ecx # %ecx<- 0F00
+ shr $$8, %ecx # %ecx<- F
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vF
+ movl %ecx, (%edx) # *outs<- vF
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+2:
+ and $$0x00f0, %ecx # %ecx<- 00E0
+ shr $$4, %ecx # %ecx<- E
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vE
+ movl %ecx, (%edx) # *outs<- vE
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+1:
+ and $$0x000f, %ecx # %ecx<- 000D
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vD
+ movl %ecx, -4(%edx) # *--outs<- vD
+0:
+
+ /*
+ * %eax is "Method* methodToCall", the method we're trying to call
+ * find space for the new stack frame, check for overflow
+ */
+
+.LinvokeArgsDone:
+ movzwl offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
+ movzwl offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
+ movl %eax, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- methodToCall
+ shl $$2, %edx # %edx<- update offset
+ SAVEAREA_FROM_FP(%eax,rFP) # %eax<- &StackSaveArea
+ subl %edx, %eax # %eax<- newFP; (old savearea - regsSize)
+ GET_GLUE(%edx) # %edx<- pMterpGlue
+ movl %eax, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- &outs
+ subl $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
+ movl offGlue_interpStackEnd(%edx), %edx # %edx<- glue->interpStackEnd
+ movl %edx, LOCAL2_OFFSET(%ebp) # LOCAL2_OFFSET<- glue->interpStackEnd
+ shl $$2, %ecx # %ecx<- update offset for outsSize
+ movl %eax, %edx # %edx<- newSaveArea
+ sub %ecx, %eax # %eax<- bottom; (newSaveArea - outsSize)
+ cmp LOCAL2_OFFSET(%ebp), %eax # compare interpStackEnd and bottom
+ movl LOCAL0_OFFSET(%ebp), %eax # %eax<- restore methodToCall
+ jl .LstackOverflow # handle frame overflow
+
+ /*
+ * set up newSaveArea
+ */
+
+#ifdef EASY_GDB
+ SAVEAREA_FROM_FP(%ecx,rFP) # %ecx<- &StackSaveArea
+ movl %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
+#endif
+ movl rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
+ movl rPC_SPILL(%ebp), %ecx
+ movl %ecx, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
+ testl $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
+ movl %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
+ jne .LinvokeNative # handle native call
+
+ /*
+ * Update "glue" values for the new method
+ * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
+ */
+
+ movl offMethod_clazz(%eax), %edx # %edx<- method->clazz
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+ movl %eax, offGlue_method(%ecx) # glue->method<- methodToCall
+ movl %edx, offGlue_methodClassDex(%ecx) # glue->methodClassDex<- method->clazz->pDvmDex
+ movl offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
+ movl offGlue_self(%ecx), %eax # %eax<- glue->self
+ movl LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- newFP
+ FETCH_INST()
+ GOTO_NEXT # jump to methodToCall->insns
+
+ /*
+ * Prep for the native call
+ * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea
+ */
+
+.LinvokeNative:
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl %eax, OUT_ARG1(%esp) # push parameter methodToCall
+ movl offGlue_self(%ecx), %ecx # %ecx<- glue->self
+ movl offThread_jniLocal_topCookie(%ecx), %eax # %eax<- self->localRef->...
+ movl %eax, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
+ movl %edx, OUT_ARG4(%esp) # save newSaveArea
+ movl LOCAL1_OFFSET(%ebp), %edx # %edx<- newFP
+ movl %edx, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
+ movl %ecx, OUT_ARG3(%esp) # save glue->self
+ movl %ecx, OUT_ARG2(%esp) # push parameter glue->self
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl OUT_ARG1(%esp), %eax # %eax<- methodToCall
+ lea offGlue_retval(%ecx), %ecx # %ecx<- &retval
+ movl %ecx, OUT_ARG0(%esp) # push parameter pMterpGlue
+ push %edx # push parameter newFP
+
+ call *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
+ lea 4(%esp), %esp
+ movl OUT_ARG4(%esp), %ecx # %ecx<- newSaveArea
+ movl OUT_ARG3(%esp), %eax # %eax<- glue->self
+ movl offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
+ cmp $$0, offThread_exception(%eax) # check for exception
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
+ movl %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
+ UNSPILL(rPC)
+ jne common_exceptionThrown # handle exception
+ FETCH_INST_WORD(3)
+ ADVANCE_PC(3)
+ GOTO_NEXT # jump to next instruction
+
+.LstackOverflow: # eax=methodToCall
+ movl %eax, OUT_ARG1(%esp) # push parameter methodToCall
+ GET_GLUE(%eax) # %eax<- pMterpGlue
+ movl offGlue_self(%eax), %eax # %eax<- glue->self
+ movl %eax, OUT_ARG0(%esp) # push parameter self
+ call dvmHandleStackOverflow # call: (Thread* self, Method* meth)
+ UNSPILL(rPC) # return: void
+ jmp common_exceptionThrown # handle exception
+
+
+/*
+ * Common invoke code (old-style).
+ * TUNING: Rewrite along lines of new armv5 code?
+ *
+ * On entry:
+ * eax = Method* methodToCall
+ * ecx = bool methodCallRange
+ * rINST trashed, must reload
+ */
+common_invokeOld:
+ movl %ecx,OUT_ARG1(%esp) # arg1<- methodCallRange
+ GET_GLUE(%ecx)
+ movzwl (rPC),rINST_FULL # recover rINST
+ movl %eax,OUT_ARG2(%esp) # arg2<- method
+ movzwl 4(rPC),%eax # eax<- GFED or CCCC
+ SAVE_PC_TO_GLUE(%ecx)
+ SAVE_FP_TO_GLUE(%ecx)
+ movzbl rINST_HI,rINST_FULL
+ movl rINST_FULL,OUT_ARG3(%esp)# arg3<- AA
+ movl %ecx,OUT_ARG0(%esp) # arg0<- GLUE
+ movl %eax,OUT_ARG4(%esp) # arg4<- GFED/CCCC
+ call dvmMterp_invokeMethod
+ jmp common_resumeAfterGlueCall
+
+
+/*
+ * Do we need the thread to be suspended or have debugger/profiling activity?
+ *
+ * On entry:
+ * ebx -> PC adjustment in 16-bit words (must be preserved)
+ * ecx -> GLUE pointer
+ * reentry type, e.g. kInterpEntryInstr stored in rGLUE->entryPoint
+ *
+ * Note: A call will normally kill %eax, rPC/%edx and %ecx. To
+ * streamline the normal case, this routine will preserve rPC and
+ * %ecx in addition to the normal caller save regs. The save/restore
+ * is a bit ugly, but will happen in the relatively uncommon path.
+ * TODO: Basic-block style Jit will need a hook here as well. Fold it into
+ * the suspendCount check so we can get both in 1 shot.
+ */
+common_periodicChecks:
+ movl offGlue_pSelfSuspendCount(%ecx),%eax # eax <- &suspendCount
+ cmpl $$0,(%eax)
+ jne 1f
+
+6:
+ movl offGlue_pDebuggerActive(%ecx),%eax # eax <- &DebuggerActive
+ movl offGlue_pActiveProfilers(%ecx),%ecx # ecx <- &ActiveProfilers
+ testl %eax,%eax # debugger enabled?
+ je 2f
+ movzbl (%eax),%eax # get active count
+2:
+ orl (%ecx),%eax # eax <- debuggerActive | activeProfilers
+ GET_GLUE(%ecx) # restore rGLUE
+ jne 3f # one or both active - switch interp
+
+5:
+ ret
+
+ /* Check for suspend */
+1:
+ /* At this point, the return pointer to the caller of
+ * common_periodicChecks is on the top of stack. We need to preserve
+ * rPC(edx) and GLUE(ecx). We'll spill rPC, and reload GLUE.
+ * The outgoing profile is:
+ * bool dvmCheckSuspendPending(Thread* self)
+ * Because we reached here via a call, go ahead and build a new frame.
+ */
+ EXPORT_PC() # need for precise GC
+ movl offGlue_self(%ecx),%eax # eax<- glue->self
+ SPILL(rPC) # save edx
+ push %ebp
+ movl %esp,%ebp
+ subl $$24,%esp
+ movl %eax,OUT_ARG0(%esp)
+ call dvmCheckSuspendPending
+ addl $$24,%esp
+ pop %ebp
+ UNSPILL(rPC)
+ GET_GLUE(%ecx)
+
+ /*
+ * Need to check to see if debugger or profiler flags got set
+ * while we were suspended.
+ */
+ jmp 6b
+
+ /* Switch interpreters */
+ /* Note: %ebx contains the 16-bit word offset to be applied to rPC to
+ * "complete" the interpretation of backwards branches. In effect, we
+ * are completing the interpretation of the branch instruction here,
+ * and the new interpreter will resume interpretation at the branch
+ * target. However, a switch request recognized during the handling
+ * of a return from method instruction results in an immediate abort,
+ * and the new interpreter will resume by re-interpreting the return
+ * instruction.
+ */
+3:
+ leal (rPC,%ebx,2),rPC # adjust pc to show target
+ GET_GLUE(%ecx) # bail expect GLUE already loaded
+ movl $$1,rINST_FULL # set changeInterp to true
+ jmp common_gotoBail
+
+
+/*
+ * Common code for handling a return instruction
+ */
+common_returnFromMethod:
+ GET_GLUE(%ecx)
+ /* Set entry mode in case we bail */
+ movb $$kInterpEntryReturn,offGlue_entryPoint(%ecx)
+ xorl rINST_FULL,rINST_FULL # zero offset in case we switch interps
+ call common_periodicChecks # Note: expects %ecx to be preserved
+
+ SAVEAREA_FROM_FP(%eax,rFP) # eax<- saveArea (old)
+ movl offStackSaveArea_prevFrame(%eax),rFP # rFP<- prevFrame
+ movl (offStackSaveArea_method-sizeofStackSaveArea)(rFP),rINST_FULL
+ cmpl $$0,rINST_FULL # break?
+ je common_gotoBail # break frame, bail out completely
+
+ movl offStackSaveArea_savedPc(%eax),rPC # pc<- saveArea->savedPC
+ movl offGlue_self(%ecx),%eax # eax<- self
+ movl rINST_FULL,offGlue_method(%ecx) # glue->method = newSave->meethod
+ movl rFP,offThread_curFrame(%eax) # self->curFrame = fp
+ movl offMethod_clazz(rINST_FULL),%eax # eax<- method->clazz
+ FETCH_INST_WORD(3)
+ movl offClassObject_pDvmDex(%eax),%eax # eax<- method->clazz->pDvmDex
+ ADVANCE_PC(3)
+ movl %eax,offGlue_methodClassDex(%ecx)
+ /* not bailing - restore entry mode to default */
+ movb $$kInterpEntryInstr,offGlue_entryPoint(%ecx)
+ GOTO_NEXT
+
+/*
+ * Prepare to strip the current frame and "longjump" back to caller of
+ * dvmMterpStdRun.
+ *
+ * on entry:
+ * rINST_FULL holds changeInterp
+ * ecx holds glue pointer
+ *
+ * expected profile: dvmMterpStdBail(MterpGlue *glue, bool changeInterp)
+ */
+common_gotoBail:
+ SAVE_PC_TO_GLUE(%ecx) # export state to glue
+ SAVE_FP_TO_GLUE(%ecx)
+ movl %ecx,OUT_ARG0(%esp) # glue in arg0
+ movl rINST_FULL,OUT_ARG1(%esp) # changeInterp in arg1
+ call dvmMterpStdBail # bail out....
+
+
+/*
+ * After returning from a "glued" function, pull out the updated values
+ * and start executing at the next instruction.
+ */
+ common_resumeAfterGlueCall:
+ GET_GLUE(%ecx)
+ LOAD_PC_FROM_GLUE(%ecx)
+ LOAD_FP_FROM_GLUE(%ecx)
+ FETCH_INST()
+ GOTO_NEXT
+
+/*
+ * Integer divide or mod by zero
+ */
+common_errDivideByZero:
+ EXPORT_PC()
+ movl $$.LstrArithmeticException,%eax
+ movl %eax,OUT_ARG0(%esp)
+ movl $$.LstrDivideByZero,%eax
+ movl %eax,OUT_ARG1(%esp)
+ SPILL(rPC)
+ call dvmThrowException
+ UNSPILL(rPC)
+ jmp common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ */
+common_errNegativeArraySize:
+ EXPORT_PC()
+ movl $$.LstrNegativeArraySizeException,%eax
+ movl %eax,OUT_ARG0(%esp)
+ xorl %eax,%eax
+ movl %eax,OUT_ARG1(%esp)
+ SPILL(rPC)
+ call dvmThrowException
+ UNSPILL(rPC)
+ jmp common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ */
+common_errNoSuchMethod:
+
+ EXPORT_PC()
+ movl $$.LstrNoSuchMethodError,%eax
+ movl %eax,OUT_ARG0(%esp)
+ xorl %eax,%eax
+ movl %eax,OUT_ARG1(%esp)
+ SPILL(rPC)
+ call dvmThrowException
+ UNSPILL(rPC)
+ jmp common_exceptionThrown
+
+/*
+ * Hit a null object when we weren't expecting one. Export the PC, throw a
+ * NullPointerException and goto the exception processing code.
+ */
+common_errNullObject:
+ EXPORT_PC()
+ movl $$.LstrNullPointerException,%eax
+ movl %eax,OUT_ARG0(%esp)
+ xorl %eax,%eax
+ movl %eax,OUT_ARG1(%esp)
+ SPILL(rPC)
+ call dvmThrowException
+ UNSPILL(rPC)
+ jmp common_exceptionThrown
+
+/*
+ * Array index exceeds max.
+ */
+common_errArrayIndex:
+ EXPORT_PC()
+ movl $$.LstrArrayIndexException,%eax
+ movl %eax,OUT_ARG0(%esp)
+ xorl %eax,%eax
+ movl %eax,OUT_ARG1(%esp)
+ SPILL(rPC)
+ call dvmThrowException
+ UNSPILL(rPC)
+ jmp common_exceptionThrown
+/*
+ * Invalid array value.
+ */
+common_errArrayStore:
+ EXPORT_PC()
+ movl $$.LstrArrayStoreException,%eax
+ movl %eax,OUT_ARG0(%esp)
+ xorl %eax,%eax
+ movl %eax,OUT_ARG1(%esp)
+ SPILL(rPC)
+ call dvmThrowException
+ UNSPILL(rPC)
+ jmp common_exceptionThrown
+
+/*
+ * Somebody has thrown an exception. Handle it.
+ *
+ * If the exception processing code returns to us (instead of falling
+ * out of the interpreter), continue with whatever the next instruction
+ * now happens to be.
+ *
+ * This does not return.
+ */
+common_exceptionThrown:
+ GET_GLUE(%ecx)
+ SAVE_PC_TO_GLUE(%ecx)
+ SAVE_FP_TO_GLUE(%ecx)
+ movl %ecx,OUT_ARG0(%esp)
+ call dvmMterp_exceptionThrown
+ jmp common_resumeAfterGlueCall
+
+common_abort:
+ movl $$0xdeadf00d,%eax
+ call *%eax
+
+
+/*
+ * Strings
+ */
+
+ .section .rodata
+.LstrNullPointerException:
+ .asciz "Ljava/lang/NullPointerException;"
+.LstrArithmeticException:
+ .asciz "Ljava/lang/ArithmeticException;"
+.LstrDivideByZero:
+ .asciz "divide by zero"
+.LstrArrayIndexException:
+ .asciz "Ljava/lang/ArrayIndexOutOfBoundsException;"
+.LstrArrayStoreException:
+ .asciz "Ljava/lang/ArrayStoreException;"
+.LstrNegativeArraySizeException:
+ .asciz "Ljava/lang/NegativeArraySizeException;"
+.LstrInstantiationError:
+ .asciz "Ljava/lang/InstantiationError;"
+.LstrClassCastException:
+ .asciz "Ljava/lang/ClassCastException;"
+.LstrNoSuchMethodError:
+ .asciz "Ljava/lang/NoSuchMethodError;"
+.LstrInternalError:
+ .asciz "Ljava/lang/InternalError;"
+.LstrFilledNewArrayNotImpl:
+ .asciz "filled-new-array only implemented for 'int'"