15
Towards Array Bound Check Elimination in Java TM Virtual Machine Language * Hongwei Xi and Songtao Xia Oregon Graduate Institute {hongwei,sxia}@cse.ogi.edu Abstract In a standard Java implementation, a Java pro- gram is compiled into Java bytecode, which is then interpreted by Java virtual machine (JVM). We refer to the bytecode language as Java virtual machine language in this paper. For safety concerns, JVM performs run-time ar- ray bounds checking to detect out-of-bounds ar- ray access. Unfortunately, this practice can be prohibitively expensive in cases involving nu- merical computation. We propose a type-theoretic approach to eliminating run-time array bound checks in JVML and demonstrate that the property of safe array access can be readily captured with a restricted form of dependent type system and therefore enforced through type-checking. We focus on a language JVMLa, which is basically a subset of JVML with array access instructions, and prove that the execution of a well-typed JVMLa program can never cause memory vi- olations. 1 Introduction Java is an object-oriented programming lan- guage designed to support multiple host archi- tectures and allow secure delivery of software components [14]. One key step to achieving this objective is the introduction of Java virtual ma- chine (JVM). In a standard implementation of Java, a Java program is compiled into bytecode in Java Virtual Machine Language (JVML), which can then be interpreted by JVM. JVML bytecode is platform-independent and can be transferred across networks to a host * We acknowledge the support from the United States Air Force Materiel Command (F19 628-96-C-0161) and the Department of Defense. which may not trust the source of the bytecode. This makes it necessary to check for various potential safety violations in JVML bytecode. A significant concern in this context is mem- ory violations, including both run-time type er- rors and out-of-bounds array accesses. Clearly, we can insert run-time checks to prevent mem- ory violations from happening, but this practice can significantly slow down bytecode execution. The introduction of Java virtual machine ver- ifier can partially address the issue. The key point is that a great deal of type safety checking in JVML bytecode can be practically performed before execution, eliminating a vast number of type checks at run-time. Unfortunately, poten- tial out-of-bounds array accesses cannot be de- tected through JVM verifier and run-time array bound checks are needed. Array bounds checking can be expensive in practice. For instance, array bounds checking in an implementation of the matrix multiplica- tion algorithm can take up to 50% of the execu- tion time in our experiment. In general, tasks involving numerical computation such as anima- tion can suffer a great deal from run-time array bounds checking. This seems to be a significant reason for not disallowing out-of-bounds array access in many unsafe programming languages such as C and C++. As a consequence, it is common to encounter inscrutable crashes of C or C++ programs in practice. A traditional approach to eliminating run- time array bound checks is based on flow anal- ysis [3, 5, 6]. Although this is a fully automatic approach, it is also greatly limited and sensitive to program structures. For instance, it seems unlikely that such an approach can be adopted in practice to eliminate array bounds checking in an implementation of binary search on ar- rays. In addition, an approach based on flow

Towards Array Bound Check Elimination in JavaTM Virtual Machine

  • Upload
    others

  • View
    11

  • Download
    0

Embed Size (px)

Citation preview

Towards Array Bound Check Elimination in

JavaTM Virtual Machine Language∗

Hongwei Xi and Songtao Xia

Oregon Graduate Institute

{hongwei,sxia}@cse.ogi.edu

Abstract

In a standard Java implementation, a Java pro-gram is compiled into Java bytecode, whichis then interpreted by Java virtual machine(JVM). We refer to the bytecode language asJava virtual machine language in this paper.For safety concerns, JVM performs run-time ar-ray bounds checking to detect out-of-bounds ar-ray access. Unfortunately, this practice can beprohibitively expensive in cases involving nu-merical computation.

We propose a type-theoretic approach toeliminating run-time array bound checks inJVML and demonstrate that the property ofsafe array access can be readily captured witha restricted form of dependent type system andtherefore enforced through type-checking. Wefocus on a language JVMLa, which is basicallya subset of JVML with array access instructions,and prove that the execution of a well-typedJVMLa program can never cause memory vi-olations.

1 Introduction

Java is an object-oriented programming lan-guage designed to support multiple host archi-tectures and allow secure delivery of softwarecomponents [14]. One key step to achieving thisobjective is the introduction of Java virtual ma-chine (JVM). In a standard implementation ofJava, a Java program is compiled into bytecodein Java Virtual Machine Language (JVML),which can then be interpreted by JVM.

JVML bytecode is platform-independent andcan be transferred across networks to a host∗We acknowledge the support from the United States

Air Force Materiel Command (F19 628-96-C-0161) andthe Department of Defense.

which may not trust the source of the bytecode.This makes it necessary to check for variouspotential safety violations in JVML bytecode.A significant concern in this context is mem-ory violations, including both run-time type er-rors and out-of-bounds array accesses. Clearly,we can insert run-time checks to prevent mem-ory violations from happening, but this practicecan significantly slow down bytecode execution.The introduction of Java virtual machine ver-ifier can partially address the issue. The keypoint is that a great deal of type safety checkingin JVML bytecode can be practically performedbefore execution, eliminating a vast number oftype checks at run-time. Unfortunately, poten-tial out-of-bounds array accesses cannot be de-tected through JVM verifier and run-time arraybound checks are needed.

Array bounds checking can be expensive inpractice. For instance, array bounds checkingin an implementation of the matrix multiplica-tion algorithm can take up to 50% of the execu-tion time in our experiment. In general, tasksinvolving numerical computation such as anima-tion can suffer a great deal from run-time arraybounds checking. This seems to be a significantreason for not disallowing out-of-bounds arrayaccess in many unsafe programming languagessuch as C and C++. As a consequence, it iscommon to encounter inscrutable crashes of Cor C++ programs in practice.

A traditional approach to eliminating run-time array bound checks is based on flow anal-ysis [3, 5, 6]. Although this is a fully automaticapproach, it is also greatly limited and sensitiveto program structures. For instance, it seemsunlikely that such an approach can be adoptedin practice to eliminate array bounds checkingin an implementation of binary search on ar-rays. In addition, an approach based on flow

analysis often provides no or little feedback tothe programmer indicating why a particular ar-ray bound check in a program cannot be elimi-nated. Therefore, this approach offers little helpfor detecting program errors caused by potentialout-of-bounds array accesses.

High Performance Compiler for Java (HPCJ)compiles JVML bytecode into native code be-fore executing the bytecode, eliminating (some)array bound checks through flow analysis on thebytecode 1. This is a radically different ap-proach to implementing JVML, which is usu-ally done through interpretation. Also it seemssignificantly more difficult to eliminate arraybound checks in JVML bytecode than in Javasource programs since some structures in Javaprograms are destroyed when they are compiledinto bytecode. In general, a compiler like HPCJsacrifices binary portability but applies moresophisticated optimizations. Clearly, a limitedplatform coverage and increased maintenancecosts have to be traded against the performanceimprovements.

Just-in-time (JIT) compilers are another com-mon means to speeding up the execution ofJava bytecode [4]. In practice, the need forrapid compilation often limits the quality ofcode that a JIT compiler produces. Clearly,there is a trade-off in this context between thetime spent in compilation and the quality of gen-erated code.

A type-based approach is introduced in [16]for eliminating array bound checks. The keynotion behind this approach is the use of a re-stricted form of dependent types to capture theproperty of safe array access and then enforce itthrough type-checking. We briefly explain thisthrough the following code in de Caml, a dialectof DML [17].

let icopy src dst =for i = 0 to vect_length(src) - 1 do

dst..(i) <- src..(i)done

withtype {n:nat} ’a vect(n) ->’a vect(n) -> unit

;;

The icopy function copies an integer arrayinto another one. We use the double dot “..”notation for safe array access. The withtype

1At this moment, we know little about the algorithmused in HPCJ for array bound check elimination andthus unable to predict in which cases array bound checkscan be eliminated.

clause is a type annotation and the type{n:nat} ’a vect(n)-> ’a vect(n) -> unitstates that for every natural number n, the func-tion icopy takes two vectors of length n andreturns a value of type unit. It can be read-ily observed that both array accesses src..(i)and dst..(i) are safe since i is always withinthe bounds of src and dst 2. This property iscaptured by the type system of de Caml, andtherefore no run-time array bounds checking isneeded after the code passes type-checking inde Caml. Notice that it is impossible to de-termine whether dst..(i) is safe if the typeannotation is not supplied.

In this paper, we apply this idea to JVMLa,a subset of JVML, presenting an approach to-wards eliminating array bound checks in JVML.Inspired by [8, 11], we design a type system forJVMLa which is expressive enough to capturethe memory safety property of JVMLa byte-code, where memory safety consists of bothtype safety and safe array access. We are ableto enforce memory safety of bytecode throughtype-checking and thus eliminate run-time ar-ray bound checks. This approach is particularlysuitable for mobile code since the site which ex-ecutes the code may not trust the source of thecode. With such a type system, the verifica-tion of the memory safety of mobile code canbe performed through type-checking, regardlessthe origin of the code. We now present a shortJVMLa program before going into further de-tails. Notice that the simplicity of this exampleis solely for the sake of illustration purpose andshould not be interpreted as the limitation ofour approach.

The JVMLa program in Figure 1 roughly cor-responds to the above program in de Caml.Note that a double slash // starts a commentline. The formal representation of this programin JVMLa will be given in Section 4, and we nowinformally explain what the program means.For every integer i, the type int(i) is a single-ton type in which the only element is integer i.Also we use type intarray(n) for integer arraysof size n. Note that v0,v1,...,v4 are localvariables. Each label in the code is associatedwith a dependent type. For instance, the depen-dent type associated with the label icopy meansthat the top two elements of the current stackare of type intarray(n) for some natural num-ber n. We use @ for the rest of stack of which

2Note that all non-empty arrays in ML start at index0.

00. icopy: {n:nat} [sp: intarray(n) :: intarray(n) :: @]01. astore 0 // v0 <- src02. astore 1 // v1 <- dst03. aload 004. arraylength05. istore 2 // 03, 04, 05: store the array length into v206. push 007. istore 3 // 06, 07: initialize the loop count: v3 <- 0

08. loop: {n:nat, k:nat | k <= n}[v0: intarray(n), v1: intarray(n), v2: int(n), v3: int(k)]

09. iload 3 // load array index onto the stack10. iload 2 // load array size onto the stack11. isub // calculate the difference12. ifeq finish // difference equals zero: done13. aload 0 // push the src array pointer onto the stack14. iload 3 // push the index i onto the stack15. iaload // load the content in src[i]16. istore 4 // store the content into v417. aload 1 // push the dst array pointer onto the stack18. iload 3 // push the index i onto the stack19. iload 4 // push the content onto the stack20. iastore // store the content into dst[i]21. push 122. iload 323. iadd24. istore 3 // 20, 21, 22, 23: increment loop count by 125. goto loop // loop again

26. finish: []27. halt // program terminates

Figure 1: A copy function implemented in JVMLa

we have no knowledge. Also the dependent typeassociated with the label loop basically meansthat there exist natural numbers n and k satisfy-ing k ≤ n such that v0,v1,...,v4 are of typesintarray(n), intarray(n), int(n) and int(k), re-spectively. Clearly, the type of v0 depends onthe value of the integer in v2. The type systemof JVMLa guarantees that this property is sat-isfied when the code execution reaches the labelloop. The JVMLa code is well-typed. As a con-sequence (which we will explain later), this im-plies that the index is within the bounds of thearray when either the instruction on line 15 orline 20 is executed. In other words, it is unnec-essary to perform run-time array bound checkswhen these instructions are executed. We have

thus eliminated array bounds checking in thisprogram.

The main contribution of the paper is the de-sign of the type system of JVMLa and the for-malism which leads to the soundness proof ofthe type system. We feel that we have madean important step towards eliminating arraybounds checking in Java virtual machine, whichis a difficult question of significant practical rel-evance.

The organization of the paper is as follows.In Section 2, we introduce the language JVMLaand present both of its dynamic and static se-mantics. The type-checking in JVMLa involvesconstraint satisfaction, which is then explainedin Section 3. The type system of JVMLa is

involved, and we present an example in Sec-tion 4 to explain in details how type-checkingin JVMLa is performed. The soundness of thetype system of JVMLa is proven in Section 5.We mention in Section 6 and 7 some issues onimplementing JVMLa and generating JVMLa-like bytecode, and then list some important ex-tension to JVMLa in Section 8 that needs to bedone. The rest of the paper deals with relatedwork and concludes.

2 The language JVMLa

We find it instructive to concentrate on theessence of the approach to eliminating arraybound checks that we will introduce shortly.We form a language JVMLa for this purpose,which is basically a minimal subset of JVMLwith some array access instructions.

For the sake of simplicity, only integer ar-rays are allowed in JVMLa. Notice that theobject-oriented features in JVML have little todo with array bounds checking and are thus ex-cluded. We do not handle function calls, either.Nonetheless, we point out that the type system,like that of DML, is to guarantee arguments ofcorrect types are supplied when a function callis made. For instance, when the icopy func-tion in Figure 1 is called, it must be provable inthe type system that the top two elements onthe current stack are two integer arrays of thesame size; if this cannot be proven, a run-timecheck is needed to verify this. We point out thatmany details omitted in this paper for the sakeof space limitation can be found in [20].

Intuitively speaking, dependent types aretypes which depend on the values of languageexpressions. For instance, we may form a typeintarray(x) such that every array of this typeis an integer array of size x, which x is the ex-pression on which this type depends. We usethe name type index object for such an expres-sion. Also we can refine the type int into in-finitely many singleton types int(x), where xranges over all integers. The value of every ex-pression of type int(x) equals x. There are vari-ous compelling reasons for imposing restrictionson expressions which can be chosen as type in-dex objects. A novelty in DML [17] is to requirethat type index objects be drawn only from agiven constraint domain. This is crucial to ob-taining a practical type-checking algorithm. Forour purpose, we restrict type index objects tointegers.

The syntax for type index objects is presentedin Figure 2, where we use a for type index vari-ables, and i for fixed integers. Note that thelanguage for type index objects is typed. Weuse sorts for the types in this language in or-der to avoid potential confusion. We use · forthe empty index context and omit the stan-dard sorting rules for this language. We alsouse certain transparent abbreviations, such as0 ≤ x < y which stands for 0 ≤ x ∧ x < y. Thesubset sort {a : γ | P} stands for the sort forthose elements of sort γ satisfying the proposi-tion P . For example, we use nat as an abbrevi-ation for {a : int | a ≥ 0}.

The syntax of JVMLa is given in Figure 3and the meaning of JVMLa instructions is in-formally presented in Figure 4. A program isa pair (Λ, I), where I is a sequence of generalinstructions and Λ associates every label in Iwith a type τ . Note that a label is treated as ageneral instruction (its operational semantics issimply to increment the program count by 1). Inthe external language, we write a type followingeach label to mean that the label is associatedwith the type following it. Also we use length(I)for n if I is of form Lins0; . . . ; Linsn−1, and I(i)for Linsi if 0 ≤ i < length(I). We write I−1(L)for i if some Linsi is L. This is well-definedsince we require that all labels in a program bedistinct.

The following erasure function ‖ · ‖ erases allsyntax related to type index objects, transform-ing types into type erasures.

‖unit‖ = unit ‖int(x)‖ = int ‖σ‖ = unit‖intarray(x)‖ = intarray ‖∃a : γ.τ‖ = ‖τ‖

In the following presentation, we also write intfor ∃a : int.int(a) if int is treated as a type.

JVMLa is to be interpreted with a stack-based abstract machine. The execution of aJVMLa program is associated with a frame,which consists a set of local variables and astack. We assume there is a fixed number nv oflocal variables. We do not consider stack over-flow in this paper and therefore assume the ex-istence of a stack of unlimited depth.

2.1 Dynamic semantics

We use an abstract state machine for assign-ing operational semantics to JVMLa. This isa standard approach. A machine state M isa triple (H,V,S), where H and V are finitemappings standing for heap and the set of lo-cal variables, respectively, and S is a list stand-

index objects x, y ::= a | i | x+ y | x− y | x ∗ y | x÷ yindex propositions P ::= x < y | x ≤ y | x ≥ y | x > y | x = y | x 6= y |

> | ⊥ | P1 ∧ P2 | P1 ∨ P2

index sorts γ ::= int | {a : γ | P}index contexts φ ::= · | φ, a : γ | φ, P

Figure 2: The syntax for the index language

type τ ::= unit | int(x) | intarray(x) | σ | ∃a : γ.τtype erasure ε ::= unit | int | intarraystate type σ ::= state(λφ.F )frame F ::= (V, S)stack S ::= • | τ :: Sinstruction ins ::= aload n | astore n | iload n | iaload | iastore | istore n |

iadd | idiv | imul | isub | goto L | ifeq L | ifne L |pop | push i | newarray | arraylength | halt

general instr. seq. Lins ::= ins | Linstruction sequence P ::= halt | ins; I | L; Ilabel map Λ ::= {L1 : σ1, . . . , Ln : σn}program P ::= (Λ, I)

Figure 3: JVMLa syntax

ing for stack. The domain dom(H) of H is aset of heap addresses and the domain dom(V)is {0, 1, . . . , nv − 1}, where nv is the number oflocal variables. We do not specify how a heapaddress is represented, but the reader can sim-ply assume it to be a natural number. We useh for a heap address, i for an integer and hifor a value which is either a heap address oran integer. Given h ∈ dom(H), H(h) is a tuple(i0, . . . , in−1) such that every ik is an integer fork = 0, . . . , n − 1. Given k ∈ dom(V), V(k) iseither a heap address or an integer. Also we usehi1 :: . . . :: hin :: S for a stack where the topn elements are hi1, . . . , hin and the rest of thestack is represented by S.

Given a program P = (Λ, I), a P -snapshotQ is either HALT or a pair (pc,M) such that0 ≤ pc < length(I). The relation (pc,M) →(pc′,M′) means that the current machine stateM transforms into M′ after executing the in-struction I(pc) and the instruction count is setto pc′. We present some typical evaluation rulesfor JVMLa in Figure 5. We do not considergarbage collection in this abstract machine, andtherefore the heap can only be affected by thememory allocation instruction newarray.

Given a finite mapping f and an element x inthe domain of f , we use f(x) for the value towhich f maps x, and f [x 7→ v] for the mappingsuch that

f [x 7→ v](y) ={f(y) if y is not x;v if y is x.

Clearly, f [x 7→ v] is also meaningful when x isnot already in the domain of f . In this case, wesimply extend the domain of f with x.

We present some explanation on some of theevaluation rules. The rule (eval-iastore) is forevaluating the instruction iastore. This rule isapplicable only if the current stack is of formi :: j :: h :: S, that is, the top three elementsare an integer, an integer and a heap address,and H maps the heap address to an integer ar-ray (i0, . . . , in−1) of size n, and 0 ≤ j < nholds. If the required conditions do not hold,the execution stalls. We will form a type sys-tem for JVMLa so that the execution of a well-typed JVMLa program never stalls. Since out-of-bounds array access stalls execution, this im-plies that no out-of-bounds array access can oc-cur during the execution of well-typed JVMLaprograms.

aload n push the array pointer in variable n onto the stackastore n pop an array pointer from the stack and store it into variable niload n push the integer in variable n onto the stackistore n pop an integer from the stack and store it into variable niaload pop an index i and an array pointer a from the stack and store the content in

the ith cell of a onto the stackiastore pop an integer, an index i and an array pointer a from the stack and store the

integer into the ith cell of aiadd pop two integers i and j from the stack and store i+ j onto the stackisub pop two integers i and j from the stack and store i− j onto the stackimul pop two integers i and j from the stack and store i ∗ j onto the stackidiv pop two integers i and j from the stack and store i/j onto the stackgoto L jump to Lifeq L pop an integer from the stack and branch to L if zeroifne L pop an integer from the stack and branch to L if nonzeropop pop away the top element from the stackpush i push integer i onto the stacknewarray pop an integer i from the stack and allocate an integer array of size i on the

heap and push the array pointer onto the stackarraylength pop an array pointer from the stack and push the size of the array onto the

stackhalt terminate execution

Figure 4: A summary for instructions

The rule (eval-newarray) is for evaluatingthe instruction newarray. A fresh new heap ad-dress h is added into the domain of H after theinstruction is executed, and h is then mappedto an integer array initialized with zeros.

The interpretation of the rest of evaluationrules should now be clear to the reader. Thecomplete list of evaluation rules can be found in[20].

2.2 Static semantics

We present some typical typing rules for JVMLain this section. Constraints on integers are gen-erated during type-checking in JVMLa. Wepostpone the treatment of constraint satisfac-tion until Section 3 in order for a gentle pre-sentation. However, we informally explain theneed for constraints through the JVMLa codein Figure 1. Notice that the third local variablev3 is assumed to be of type int(k1) for somenatural number k1 when the execution reachesthe label loop. The type of v3 changes intoint(k1 +1) after the execution of the instructionon line 23. Then the execution jumps back tothe label loop. It must be verified (among many

other requirements) that v3 is of type int(k2) forsome natural number k2. Therefore, we mustprove that k1 + 1 is a natural number under thecondition that k1 is a natural number. This isa constraint, though it is trivial in this case. Ingeneral, type-checking in JVMLa involves solv-ing a great number of constraints of this form.

We have so far introduced various forms ofjudgments, some of which have yet to be definedlater. In Figure 7, we summarize the meaningof these judgments informally.

We present some explanation on some typ-ing rules. Generally speaking, an index vari-able context φ contains some assumption onindex variables declared in φ. For instance,n : nat, k : nat, k ≤ n is an index variable con-text which states that n and k are of sort natand k ≤ n holds, that is, n and k are naturalnumber satisfying k ≤ n.

The rule (type-iastore) states that in or-der to type an instruction sequence of formiastore; I, it is required that the current framebe of form (V, τ :: int(x) :: intarray(n) :: S)such that I is typable under φ; (V, S) and theerasure of τ is int and 0 ≤ x < n can be proven

P (pc) = iaload H(h) = (i0, . . . , in−1) 0 ≤ j < n

〈pc, (H,V, j :: h :: s)〉 →P 〈pc+ 1, (H,V, ij :: S)〉(eval-iaload)

P (pc) = iastore H(h) = (i0, . . . , in−1) 0 ≤ j < nH′ = H[h 7→ (i0, . . . , ij−1, i, ij+1, . . . , in−1)]

〈pc, (H,V, i :: j :: h :: S)〉 →P 〈pc+ 1, (H′,V,S)〉(eval-iastore)

P (pc) = iadd〈pc, (H,V, i :: j :: S)〉 →P 〈pc+ 1, (H,V, (i+ j) :: S)〉

(eval-iadd)

P (pc) = idiv j 6= 0〈pc, (H,V, i :: j :: S)〉 →P 〈pc+ 1, (H,V, (i/j) :: S)〉

(eval-idiv)

P (pc) = ifeq L〈pc, (H,V, 0 :: S)〉 →P 〈I−1(L) + 1, (H,V,S)〉

(eval-ifeq-t)

P (pc) = ifeq L i 6= 0〈pc, (H,V, i :: S)〉 →P 〈pc+ 1, (H,V,S)〉

(eval-ifeq-f)

P (pc) = goto L〈pc, (H,V,S)〉 →P 〈I−1(L) + 1, (H,V,S)〉

(eval-goto)

P (pc) = newarray i ≥ 0 h is new〈pc, (H,V, i :: S)〉 →P 〈pc+ 1, (H[h 7→ (0, . . . , 0)],V, h :: S)〉

(eval-newarray)

P (pc) = arraylength H(h) = (i0, . . . , in−1)〈pc, (H,V, h :: S)〉 →P 〈pc+ 1, (H,V, n :: S)〉

(eval-arraylength)

P (pc) = halt〈pc,M〉 →P HALT

(eval-halt)

Figure 5: Evaluation rules for JVMLa

under φ. This means that we must be able toverify that the value of index is within the ar-ray bounds when indexing an array. Obviously,a natural question at this moment is what todo if we cannot prove the index is within thebounds of the array. We give some explanationon the rule (type-ifeq) before answering thisquestion.

In order to type ifeq L; I, it is required thatthe stack type is of form int(x) :: S for some in-dex x. We first find the state type state(λφ.F )associated with L in the label map Λ, and thenverify that there exists a substitution θ for φsuch that F [θ] (the result from applying θ toF ) is satisfied under φ;x = 0; (V, S). It is im-portant to notice that x = 0 is in the indexvariable context since ifeq L branches only if xis zero. Also we need to verify that I is typableunder context φ;x 6= 0; (V, S), where x 6= 0 isassumed since I is executed only if ifeq L doesnot branch.

The typing rules for other conditional branch-

ing instructions should be straightforward. Sup-pose we cannot prove under context φ that anindex of type int(x) is less than the size of anarray of type intarray(n). We compute the ar-ray length and store the difference between theindex and the array length on top of that stack,which is of type int(i− n). We then do ifgte L,that is, jump to L if greater than or equal tozero, where L is the label of an entry to somecode handling array bounds violation. This al-lows us to assume that i − n < 0 when type-checking the rest of code. In other words, wecan readily prove that the index is less than thearray size after inserting a run-time check. Theimportant point is that we do not have to insertsuch checks if we have some other ways to provethat the index is within the array bounds in thetype system, which is often the case in practice.

The rule (type-goto) for typing goto L in-volves a judgment of form goto `Λ I, for which

φ, a : γ; (V [n 7→ τ ], S) ` Iφ; (V [n 7→ ∃a : γ.τ ], S) ` I

(type-open-var)

φ, a : γ; (V, τ :: S) ` Iφ; (V, ∃a : γ.τ :: S) ` I

(type-open-stack)

φ; (V, int :: S) `Λ I φ |= 0 ≤ x < n

φ; (V, int(x) :: intarray(n) :: S) `Λ iaload; I(type-iaload)

‖τ‖ = int φ |= 0 ≤ x < n φ; (V, S) `Λ I

φ; (V, τ :: int(x) :: intarray(n) :: S) `Λ iastore; I(type-iastore)

φ; (V, int(x+ y) :: S) `Λ I

φ; (V, int(x) :: int(y) :: S) `Λ iadd; I(type-iadd)

φ; (V, int(x/y) :: S) `Λ I φ |= y 6= 0φ; (V, int(x) :: int(y) :: S) `Λ idiv; I

(type-idiv)

goto `Λ I Λ(L) = state(λφ′.F ) φ ` θ : φ′ φ; (V, S) |= F [θ]φ; (V, S) `Λ goto L; I

(type-goto)

Λ(L) = state(λφ′.F ) φ ` θ : φ′ φ, x = 0; (V, S) |= F [θ] φ, x 6= 0; (V, S) ` Iφ; (V, int(x) :: S) `Λ ifeq L; I

(type-ifeq)

φ; (V, int(n) :: S) `Λ I

φ; (V, intarray(n) :: S) `Λ arraylength; I(type-arraylength)

φ |= n ≥ 0 φ; (V, intarray(n) :: S) `Λ I

φ; (V, int(n) :: S) `Λ newarray; I(type-newarray)

Λ(L) = state(λφ′.F ′) φ ` θ : φ′ φ;F |= F ′[θ] φ′;F ′ `Λ I

φ;F `Λ L; I(type-label)

goto `Λ I

φ;F `Λ halt; I(type-halt)

Figure 6: Some typing rules for JVMLa

Judgment form Judgement meaningφ |= P The proposition P holds under the context φ in the integer domain.

φ |= τ1 ≤ τ2 The type τ1 coerces into the type τ2 under the context φ modulo constraintsatisfaction.

φ;V |= V ′ The type of V (i) under the context φ coerces into V ′(i) for every 0 ≤ i < nvmodulo constraint satisfaction.

φ;S |= S′ The stack type S coerces into the stack type S′ under the context φφ; (V, S) |= (V ′, S′) This means both φ;V |= V ′ and φ;S |= S′ are derivable.

φ;F `Λ I The instruction sequence I is typable with respect to the label map Λ.goto `Λ I The instruction sequence I, which is after a goto , is typable.

` (Λ, I)[well-typed] The program P = (Λ, I) is well-typed.

Figure 7: A summary for various forms of judgments

we have the following typing rules.

goto `Λ haltgoto `Λ I

goto `Λ ins; IΛ(L) = state(λφ.F ) φ;F `Λ I

goto `Λ L; I

This basically means that instructions followinga goto are not accessible until a label appears.

The rest of the typing rule can be interpretedin a similar manner. The complete list of typingrules can be found in [20].

We use the judgment ` (Λ, I)[well-typed] tomean that the program P = (Λ, I) is well-typed.The following rule is for such a judgment, whereVempty maps n to unit for n = 0, . . . , nv − 1.

·; (Vempty, •) `Λ I

` (Λ, I)[well-typed]

3 Type coercion

We present the rules for type coercion in thissection, which clearly exhibit the involvement ofconstraint satisfaction in type-checking JVMLaprograms. In the presence of dependent types,it is no longer trivial to determine whether twotypes are equivalent. For instance, it is neces-sary to prove 1+1 = 2 in order to claim int(1+1)is equivalent to int(2). Similarly, type coercionalso involves constraint satisfaction. The needfor type coercion is mainly for typing condi-tional and unconditional jumps as shown in therules (type-goto) and (type-ifeq) (the deriva-tion of a judgment of form φ;F |= F ′ involvestype coercion).

We present the syntax for constraints as fol-lows, where P stands for index propositions.

index constraints Φ ::= P | P ⊃ Φ | ∀a : γ.Φ

We use φ |= Φ to mean that the constraint Φis satisfied under the index context φ, that is,the formula (φ)Φ is satisfiable in the domain ofintegers, where (φ)Φ is defined below.

(·)Φ = Φ (φ, a : int)Φ = (φ)∀a : int.Φ(φ, {a : γ | P})Φ = (φ, a : γ)(P ⊃ Φ)

(φ, P )Φ = (φ)(P ⊃ Φ)

For instance, the satisfiability relation a :nat, b : int, a + 1 = b |= b ≥ 0 holds since thefollowing formula is true in the integer domain.

∀a : int.a ≥ 0 ⊃ ∀b : int.a+ 1 = b ⊃ b ≥ 0

The coercion rule (coerce-state) deservessome explanation. Informally speaking, a statetype state(λφ.F ) is “stronger” if state(φ.F ) is“weaker”. The intuition is that a state typeroughly represents the notion of code continua-tion.

We define substitutions for index variables asfollows.

index substitutions θ ::= [] | θ[a 7→ x]

We omit the details on how substitution is per-formed, which is standard. Given an expressione such as a type or a state, we use e[θ] for theresult from applying θ to e. The following rulesare for typing substitutions.

φ ` [] : ·(subst-iempty)

φ ` θ : φ′ φ ` i : γφ ` θ[a 7→ i] : φ′, a : γ

(subst-ivar)

φ ` θ : φ′ φ |= P [θ]φ ` θ : φ′, P

(subst-prop)

4 An example

It is simply too overwhelming to formallydemonstrate how type-checking is performed inJVMLa because of the involvedness of the typesystem. Instead, we present some key ingredi-ents in type-checking the JVMLa program inFigure 1.

Let (Λ, I) represent the program, that is, wehave the notations in Figure 10 where insi isthe instruction on line i in the program fori = 1, . . . , 7, 9, . . . , 25, and Vloop is the map-ping {v0 : intarray(n), v1 : intarray(n), v2 :int(n), v3 : int(k)} as explained below. For i =0, . . . , 27, we write Ii for the suffix of I startingat Linsi, where I = Lins0,Lins1, . . . ,Lins27.

In the derivation D of goto `Λ I, thereare subderivations Di with conclusions of formφi; (Vi, Si) ` Ii for i = 0, . . . , 27. Some of theseφi, Vi, Si are listed in Figure 9. Recall thatVempty maps n to unit for n = 0, . . . , nv − 1.We write {vn1 : τ1, . . . , vnk : τk} for the V suchthat V (n) = τi if n = ni for some 1 ≤ i ≤ kand V (n) = unit otherwise. For instance, thederivation D15 is of the following form, wherethe last applied rule is (type-iaload).

D16 ‖int(k)‖ = int φ15 |= 0 ≤ k < n

φ15; (V15, S15) ` iaload; I16

Note φ15 = n : nat, k : nat, k ≤ n, k 6= n, andtherefore, the constraint φ15 |= 0 ≤ k < n holds

φ ` τ : ∗φ |= τ ≤ unit

(coerce-unit)φ |= x = y

φ |= int(x) ≤ int(y)(coerce-int)

φ |= x = y

φ |= intarray(x) ≤ intarray(y)(coerce-array)

φ, a : γ |= τ1 ≤ τ2φ |= ∃a : γ.τ1 ≤ τ2

(coerce-exi-ivar-l)

φ ` x : γ φ |= τ1 ≤ τ2[a 7→ x]φ |= τ1 ≤ ∃a : γ.τ2

(coerce-exi-ivar-r)

φ, φ2 ` θ : φ1 φ, φ2;F2 |= F1[θ]φ |= state(λφ1.F1) ≤ state(λφ2.F2)

(coerce-state)

φ;V |= V ′ φ;S |= S′

φ; (V, S) |= (V ′, S′)(coerce-frame)

φ |= V (i) ≤ V ′(i) for 0 ≤ i < nv

φ;V |= V ′(coerce-vars)

φ;S |= •(coerce-stack-1)

φ |= τ ≤ τ ′ φ;S |= S′

φ; τ :: S |= τ ′ :: S′(coerce-stack-2)

Figure 8: Type coercion rules for JVMLa

in the integer domain. This implies that theindex is within array bounds when iaload is ex-ecuted.

The derivation D25 is also interesting, whichis of the following form, where the last appliedrule is (type-goto).

φ25 |= n : nat φ25 |= k + 1 : natφ25 |= k + 1 ≤ n

φ25; (V25, S25) |= (Vloop[n, k 7→ n, k + 1], •)goto ` finish; halt

goto ` loop; finish; halt

The constraint φ25 |= k + 1 : nat is obviouslysatisfied. For φ25 |= k + 1 ≤ n, please noticethat k ≤ n and k 6= n are assumed in φ25 andthus k < n holds, which implies k + 1 ≤ n.

5 Soundness

We establish the soundness of the type systemof JVMLa in this section. Let us recall that amachine state M is a triple (H,V,S), where Hand V are finite mappings for the heap and localvariables, and S is a list for the stack.

Given a machine state M = (H,V,S) and aframe F = (V, S), the judgment H |= (V,S) :(V, S) means that M models the frame F . The

rules for deriving such a judgment is presentedin Figure 11. Also we write M |= φ;F if · `θ : φ is derivable for some substitution θ andMmodels F [θ].

Given a derivation D of ` P [well-typed] forprogram P = (Λ, I), we use Di for the greatestsubderivation of D with conclusion φi;Fi ` Iifor some φi, Fi, where Ii is the suffix of I startingat the ith instruction. Also we write D(i) forφi;Fi, that is, D(i) ` Ii is the conclusion of Di.

Lemma 5.1 (Main lemma) Assume that D isa derivation of ` P [well-typed] for program P =(Λ, I) and M |= D(pc) is derivable for somepc. Then (pc,M) →P HALT or (pc,M) →P

(pc′,M′) for some M′ and pc′ such that we canconstruct a derivation for M′ |= D(pc′).

Proof The lemma follows from a structural in-duction on the derivation D.

Theorem 5.2 (Progress) LetM0 be a machinestate and P = (Λ, I) be a program such that` P [well-typed] is derivable. If (0,M0) →∗P(pc,M) then either (pc,M) → HALT , or(pc,M)→P (pc′,M′) for some pc′ and M′. In

No. φ V S09 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), •

k ≤ n v2 : int(n), v3 : int(k)10 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), int(k) :: •

k ≤ n v2 : int(n), v3 : int(k)11 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), int(n) :: int(k) :: •

k ≤ n v2 : int(n), v3 : int(k)12 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), int(n− k) :: •

k ≤ n v2 : int(n), v3 : int(k)13 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), •

k ≤ n, k 6= n v2 : int(n), v3 : int(k)14 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), intarray(n) :: •

k ≤ n, k 6= n v2 : int(n), v3 : int(k)15 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), int(k) :: intarray(n) :: •

k ≤ n, k 6= n v2 : int(n), v3 : int(k)16 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), int :: •

k ≤ n, k 6= n v2 : int(n), v3 : int(k)17 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), •

k ≤ n, k 6= n v2 : int(n), v3 : int(k), v4 : int18 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), intarray(n) :: •

k ≤ n, k 6= n v2 : int(n), v3 : int(k), v4 : int19 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), int(k) :: intarray(n) :: •

k ≤ n, k 6= n v2 : int(n), v3 : int(k), v4 : int20 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), int :: int(k) :: intarray(n) :: •

k ≤ n, k 6= n v2 : int(n), v3 : int(k), v4 : int21 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), •

k ≤ n, k 6= n v2 : int(n), v3 : int(k), v4 : int22 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), int(1) :: •

k ≤ n, k 6= n v2 : int(n), v3 : int(k), v4 : int23 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), int(k) :: int(1) :: •

k ≤ n, k 6= n v2 : int(n), v3 : int(k), v4 : int24 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), int(k + 1) :: •

k ≤ n, k 6= n v2 : int(n), v3 : int(k), v4 : int25 n : nat, k : nat, v0 : intarray(n), v1 : intarray(n), •

k ≤ n, k 6= n v2 : int(n), v3 : int(k + 1), v4 : int

Figure 9: Contexts φn; (Vn, Sn) for n = 8, 8′, 9, . . . , 25

I = icopy; ins1; . . . ; ins7; loop; ins9; . . . ; ins25; finish;haltΛ(icopy) = state(λn : nat.(Vempty, intarray(n) :: intarray(n) :: •))Λ(loop) = state(λ{n : nat, k : nat, a ≤ n}.(Vloop, intarray(n) :: intarray(n) :: •))

Λ(finish) = state(Vempty, •)

Figure 10: Formal program representation

H |= i : int(i)(heap-int)

H(h) = (i0, . . . , in−1)H |= h : intarray(n)

(heap-intarray)

· ` x : γ H |= hi : τ [a 7→ x]H |= hi : ∃a : γ.τ

(heap-exists)

H |= S : •(heap-stack-1)

H |= hi : τ H |= S : SH |= hi :: S : τ :: S

(heap-stack-2)

H |= V(i) : V (i) for 0 ≤ i < nv

H |= V : V(heap-variables)

H |= V : V H |= S : SH |= (V,S) : (V, S)

(heap-frame)

Figure 11: Rules for modeling states

other words, the execution of a well-typed pro-gram in JVMLa either halts normally, or runsforever.

Proof The theorem immediately follows froman application of Lemma 5.1.

It is clear from the evaluation rules in Fig-ure 5 that out-of-bounds array access is dis-allowed in JVMLa. Therefore, Theorem 5.2guarantees that the execution of a well-typeJVMLa program cannot lead to run-time mem-ory violation. This implies that memory safetyof JVMLa programs can be enforced throughstatic type-checking.

6 Implementation

There is certain amount of nondeterminism inthe the typing rules of JVMLa. In the im-plementation, we impose some restriction toeliminating the nondeterminism. For instance,when both of the rules (coerce-exi-ivar-l) and(coerce-exi-ivar-r) are applicable, we choosethe former over the latter. For each of the rules(type-open-var) and (type-open-stack), weapply it whenever it is applicable. More detailscan be found in [20]. We have finished a pro-totype implementation for JVMLa and verifiedmany examples [19]. Several examples are ba-sically taken from the bytecode generated us-ing a compiler released by Sun. It seems un-likely, as indicated by these realistic examples,that an approach based on flow analysis canautomatically eliminate array bound checks inJVML bytecode highly effectively. This yields astrong support for studying the type-based ap-proach proposed in this paper. The current im-plementation, written in Objective Caml, cor-responds to the formal development of JVMLa

tightly. We are now trying to add more featuresof JVML into this implementation.

7 Type annotation

An immediate question regarding the applica-bility of the proposed approach is how to gen-erate the state types attached to the labels ina program. One possibility is to synthesize theinformation with some flow analysis. This, how-ever, seems to be a very limited approach. Weare currently exploring an alternative, requiringthe programmer to provide some annotations inprograms for eliminating array bounds check-ing. This is an effective approach as is arguedin [16]. With a dependently typed languageat bytecode level, the provided annotations canthen to be compiled into bytecode. Followingthe DML example [17], we have designed a de-pendently typed language Xanadu 3, which hasa Java-like syntax. The code in Figure 12 isan implementation of binary search on an inte-ger array. The state type following the keywordinvariant is a loop invariant which states thatthe values of low and high must equal i and j,respectively, for some integers i and j such thatboth 0 ≤ i ≤ n and 0 ≤ j + 1 ≤ n hold, wheren is the size of the searched vector. We haveprototyped a compiler for Xanadu, which trans-lates such invariants into state types at byte-code level. In the binary search example, theinvariant suffices to prove that the array accessvec[mid] is always safe, that is, the value ofmid is always within the bounds of the array.The important point is that the invariant is car-ried to the bytecode level so that the memory

3Xanadu is designed as an experiment language forstudying the integration of dependent types into realisticlanguages such as Java.

{n:nat}int bsearch(int key, int vec[n]) {

/* var is a key word indicating variable declaration */var: int low, mid, high, x;;

/* arraylength computes the length of an array */low = 0; high = arraylength(vec) - 1;

/* invariant: indicates a program invariant */invariant:

[i:int, j:int | 0 <= i <= n, 0 <= j+1 <= n] (low: int(i), high: int(j))while (low <= high) {

mid = (low + high) / 2; x = vec[mid];if (key == x) { return mid; }else if (key < x) { high = mid - 1; }

else { low = mid + 1; }}return -1;

}

Figure 12: An implementation of binary search in Xanadu

safety of the generated bytecode can be verifiedthrough type-checking at a site which may nottrust the source of the code. In other words, itis not enough to simply eliminate array boundchecks in a source program; we must provideevidence in the generated code that such checksare safely eliminated so that the correctness ofthe elimination can be verified independently.

Though it seems burdensome to write annota-tions, the programmer is not forced to do so. Inthe binary search example, the program can stillrun without the invariant annotation but somerun-time checking is then needed to enforce thesafety of the array access. However, we feel thatit is a good practice to write annotations sincethey can also serve as informative program doc-umentation facilitating program understandingand evolution. We point out that this examplealso demonstrates some limitation of automaticflow analysis since it seems highly unlikely thatthe invariant in this example can be effectivelysynthesized in practice. Such examples (e.g.quicksort, FFT, etc.) are abundant in practice.In general, it is heuristic at best to synthesizeloop invariants with flow analysis, and this oftenmakes it difficult to predict whether a particulararray access can be eliminated.

8 Extension

There are many potential issues lying aheadthat needs to be addressed. For instance, multi-dimensional arrays, which are not necessarilyrectangular, are allowed in Java. We use a sim-ple example to indicate an approach to handlingthis problem in the type system of Xanadu,though this has yet to be experimented. For2-dimensional integer array, it will be given thetype ∃m : nat.(∃n : nat.int array(n))array(m)if neither of its dimensions is known; or thetype (∃n : nat.int array(n))array(m) if it hasm rows; or the type (int array(n))array(m) ifit is of dimension m× n.

Another issue is on handling the jump-to-subroutine feature in JVML. We have listedrules in [20] for typing the instructions jsr andret. What is unclear at this moment is whetherthese rules can work satisfactorily since no ex-periment has been performed along this line.

In addition, the feature of method invocationclearly needs to be included into JVMLa. Thiswork, which requires some significant modifica-tion on the dynamic semantics of JVMLa, is cur-rently under study and will be reported in thefuture.

9 Related work

A typed assembly language (TAL) is first intro-duced in [8], and a stack-based typed assemblylanguage (STAL) is then introduced in [7]. Atype system similar to STAL is developed in[11] for JVML-0-C, which is basically a mini-mal subset of JVML capturing the feature ofjump-to-subroutine. The type systems of theselanguages suffice to guarantee type safety of pro-grams. Unfortunately, the property of safe ar-ray access cannot be captured in these type sys-tems. As a consequence, it is impossible to typeoptimized programs in which some array boundchecks are eliminated. This is a serious limita-tion.

A restricted form of dependent type system isdeveloped in [16] for eliminating array boundschecking in a functional programming language.This notion of types is carried further into anassembly language in [18], leading to a depen-dently type assembly language (DTAL), wherethe type system is adequate for capturing mem-ory safety of code. In this paper, we applythe approach developed in [18] to a bytecodelanguage JVMLa, which is basically a subsetof JVML with array access instructions. Webelieve that the type system of JVMLa is thefirst for a JVML-like language that can capturememory safety property of programs.

The notion of proof-carrying code (PCC) [10]is also suitable for eliminating array boundchecks. This is demonstrated by Touchstone,a compiler for the Safe C programming lan-guage [9]. Given TAL is already adequatefor this purpose, we feel that Touchstone’s ap-proach to handling type safety is too refined.Also we are not clear at this moment on howto use Touchstone’s approach for dealing withthe jump-to-subroutine feature in JVML. Onthe other hand, if one prefers, one may gener-ate proofs for certifying the well-typedness ofJVMLa programs. This opens an alternativeto Touchstone’s method for generating proof-carrying code.

As mentioned in the introduction, JVML ver-ifier [15] currently cannot detect potential out-of-bounds array accesses and every array accessin JVM is wrapped with array bound checks toenforce memory safety. This makes it impossi-ble to eliminate array bound checks in a stan-dard implementation of JVM since an array ac-cess instruction with bound checks is treated asan atomic instruction in this setting. Instead,we propose to separate array access instructions

from array bound checks and use a type systemto enforce memory safety. It is this separationthat allows us to eliminate array bound checksin the case where we can prove in the type sys-tem that they are redundant.

Recently, there has been a great deal of workon forming type systems for JVML-like lan-guages, such as [12, 13, 2] in addition to JVML-0-C. A key objective is to formalize the speci-fication for JVM verifier in contrast to its cur-rent prose description in English. In additionto advocating this, this paper also intends tostrengthen the JVM verifier so that more safetychecks can be performed statically. This cannot only produce more robust code but also en-hance the efficiency of code since many run-timechecks are saved.

We are currently extending JVMLa to includemore features of JVML. Like JVML-0-C, we seeno reasons why this approach is more difficultfor extension than other approaches. In particu-lar, we feel that this approach is largely orthogo-nal to the treatment of objects in Java, and thusexpect the integration of objects into JVMLa tobe smooth.

There are many potential applications for thetype system of JVMLa. For instance, we mayuse the type system to encode some informa-tion obtained from flow analysis and then ver-ify the information through type-checking. Aparticular interesting question at this momentis whether the type system can encode the re-sults generated by the algorithm in [6] for elim-inating array bound checks. Also we may usesome extension of JVMLa as the target languagefor compiling programs with annotations [17, 1],translating source-level annotations into the de-pendent types in JVMLa programs. This is es-pecially helpful in the case where it is difficultto eliminate array bound checks automatically.

Java is becoming a popular general-purposeprogramming language, but currently it seemssignificantly slower than C++, especially, in thefield of numerical computation. This makes ita highly relevant research topic to study arraybounds checking elimination in JVML if Java isto penetrate into this field. A similar problemalong this line is to eliminate pointer casts inJVML, which seems likely to be handled with asimilar type-based approach.

10 Acknowledgments

We gratefully acknowledge our discussion withJim Hook and Andrew Tolmach regarding thesubject of the paper, and thank PacSoft cen-ter at Oregon Graduate Institute for the sup-port we received and especially Jim Hook forhis encouragement. Also we thank the anony-mous referees for their constructive commentsand suggestions, which have undoubtedly raisedthe quality of the paper.

References

[1] David Detlefs. An overview of the extendedstatic checking system. In Workshop on FormalMethods in Software Practice, 1996.

[2] Stephen N. Freund and John C. Mitchell.A Type System for Object Initialization inthe JavaTM Bytecode Language. In Proceed-ings of ACM SIGPLAN Conference on Object-Oriented Programming, Systems, Languages &Application, pages 310{327, Vancouver, 1998.

[3] R. Gupta. Optimizing array bound checks us-ing ow analysis. ACM Letters on Program-ming Languages and Systems, 2(1{4):135{150,1994.

[4] Ishizaki et al. Design, Implementation andEvaluation of Optimizations in Just-in-timeCompiler. In Proceedings of ACM JavaGrande, 1999.

[5] Pryadarshan Kolte and Michael Wolfe. Elim-ination of redundant array subscript checks.In ACM SIGPLAN ’95 Conference on Pro-gramming Language Design and Implementa-tion. ACM Press, June 1995.

[6] S. P. Midki�, J. E. Moreira, and M. Snir. Op-timizing array reference checking in Java pro-grams, 1998. Available ashttp://www.almaden.ibm.com/journal/sj

/373/midkiff.txt

[7] Greg Morrisett, Karl Crary, Neal Glew, andDavid Walker. Stack-based typed assemblylanguage. In Proceedings of Workshop on Typesin Compilation, March 1998.

[8] Greg Morrisett, David Walker, Karl Crary, andNeal Glew. From system F to typed assem-bly language. In Proceedings of ACM Sympo-sium on Principles of Programming Languages,pages 85{97, January 1998.

[9] G. Necula and P. Lee. The design and imple-mentation of a certifying compiler. In ACM

SIGPLAN ’98 Conference on ProgrammingLanguage Design and Implementation, pages333{344. ACM press, June 1998.

[10] George Necula. Proof-carrying code. In Con-ference Record of 24th Annual ACM Sympo-sium on Principles of Programming Languages,pages 106{119. ACM press, 1997.

[11] Robert O’Callahan. A simple, comprehensivetype system for Java bytecode subroutines. InProceedings of ACM SIGPLAN Symposium onPrinciples of Programming Languages, pages70{78, San Antonio, January 1999.

[12] Zhenyu Qian. A formal speci�cation of JavaVirtual Machine instructions for objects, meth-ods and subroutines. In Jim Alves-Foss, ed-itor, Formal Syntax and Semantics of Java.Springer-Verlag, 1998.

[13] Raymie Stata and Mart��n Abadi. A type sys-tem for java bytecode subroutines. In Pro-ceedings of the 25th ACM Symposium on Prin-ciples of Programming Languages, pages 149{160, January 1998.

[14] Sun Microsystems. The Java language speci�-cation, 1995. Available asftp://ftp.javasoft.com/docs/

javaspec.ps.zip

[15] Tim Lindholm and Frank Yellin. The Javavirtual machine specification. Andison-Wesley,1996.

[16] Hongwei Xi and Frank Pfenning. Eliminat-ing array bound checking through dependenttypes. In Proceedings of ACM SIGPLANConference on Programming Language Designand Implementation, pages 249{257, Montreal,June 1998.

[17] Hongwei Xi and Frank Pfenning. Dependenttypes in practical programming. In Proceed-ings of ACM SIGPLAN Symposium on Prin-ciples of Programming Languages, pages 214{227, San Antonio, January 1999.

[18] Hongwei Xi and Robert Harper. A Depen-dently Typed Assembly Language. TechnicalReport CSE-99-008, Oregon Graduate Insti-tute, July 1999.

[19] Hongwei Xi and Songtao Xia. Some examplesin JVMLa, 1999. Available ashttp://www.cse.ogi.edu/~hongwei/JVMLa

[20] Hongwei Xi and Songtao Xia. Towards arraybound check elimination in JavaTM virtual ma-chine language, 1999. Available ashttp://www.cse.ogi.edu/~hongwei/

academic/papers/JVMLa.ps