• No se han encontrado resultados

Evaluación del proceso de enseñanza y de la práctica docente

7. EVALUACIÓN

7.3. Evaluación del proceso de enseñanza y de la práctica docente

Current AO language implementations as well as some of the prototypes developed in this thesis perform weaving at the bytecode level. Thus, the Java bytecode format [LY99] has some implications on the design of weavers. The bytecode for each class is stored in a separate file, and each file has several sections—as shown in Figure 2.2—that reflect the different entities in the class’s source code of which only the relevant ones are discussed here.

First, a class file stores the so-called constant pool which contains the symbolic names of methods, fields, and types as well as literals used within the class. Subsequently, those values are only referred to by means of their index within the constant pool. Next, type information for the class is stored, comprising the class’s modifiers and the fully qualified names of the class, its super class and its interfaces. This is followed by two sections holding the definition of all declared fields, respectively methods. Finally, each entity can have an arbitrary number of bytecode attributes which can be used by the compiler to store additional information for that entity, e.g., debugging information like a mapping from bytecode instructions to lines in the source code.

Background Header Constant Pool Type Information Fields Methods Attributes

Modifiers, Name, Signature Attributes

Figure 2.2: The Java Virtual Machine class file format.

A method definition consists of structural information: modifiers, the method’s name, and the fully qualified names of the argument types and of the result type. If the method does not have the abstractornative modifier, it also has a body. In the bytecode format the body is represented by an array of bytecode instructions stored as a special attribute.

Each instruction has a so-called opcode—one byte that encodes the kind of instruction. For each opcode there is also a symbolic name, or mnemonic, which is used throughout this thesis to denote instructions. Following the opcode, an instruction can have a number of immediate values as parameters. An example for an immediate value is the constant pool index of a method reference for an invocation.

The Java Virtual Machine (JVM) instruction set is stack-based. That means, instructions which produce values, e.g., constants or the result value of a method call, push them onto the so-called operand stack —also called just stack where this is unambiguous. Required values likewise are read from the stack. For example, in order to call a method, the argument values have to be the top values on the stack when the method call instruction is executed. Thereby these values are popped from the stack and after the called method has completed its execution the result value is pushed onto the stack. Listing 2.4 shows an example of bytecode instructions that execute the statementClazz.method(1 + 2).

Background

1 sipush 1 2 sipush 2 3 iadd

4 invokestatic #1// void Clazz. method(int)

Listing 2.4: Bytecode instructions calling a method.

Thesipush instructions each push a constant value on the stack, i.e., after the second instruction, the operand stack has the value 2 on its top and the value 1 is below. The iadd instruction pops two values from the stack, adds them and pushes the result back on the top. Thus, if the stack was empty before executing the instruction from the example, the stack contains only the value 3 afterwards. Finally, the instruction invokestatic calls a static

method. The target method is specified in terms of a constant pool index— in the example #1—the method’s symbolic name is written as a comment. Execution of this instruction pops the value (3) from the stack and passes it toClazz.method.

Besides the operand stack, bytecode instructions can also use an arbitrary number of so-called locals. These are storage locations which can be randomly accessed by means of an index. Besides temporary variables, the arguments passed to a method are also stored as locals as shown in Listing 2.5. The listing shows the bytecode for the method Clazz.methodwhich just passes its single argument (line 2) to the method Console.print.

1 void Clazz. method(int):

2 iload 0

3 invokestatic #2//void Console.print (int )

Listing 2.5: Bytecode instructions accessing the method’s arguments.

The instructions of a method are usually executed sequentially, but there are also instructions to alter the control flow. These instructions have as immediate value the offset of the target instruction relative to the jumping instruction’s offset. The jump can either be unconditional as for the goto

instruction or conditional. Conditionally jumping instructions are also called branch instructions. They pop at least one value from the stack and jump to the target instruction only if this value satisfies some condition. Otherwise, execution is continued with the instruction following the branch instruction; this is called the fall-through case. There are several different branch instruc- tions, one example is ifne which pops one value from the stack and jumps if this is unequal to 0. Since the Java Virtual Machine represents the boolean values trueand falseas the numbers1and 0, theifne instruction is also used to jump if a boolean value is true.

Binding of Join Points

In addition to the control flow instructions, other parts of Java bytecode refer to instructions by their offset. Most importantly, this is the exception handler map. Similar to the try-catch structure in the source code, this map specifies the range of bytecode instructions—in terms of a start and an end offset—which may cause an exception and the offset of the instruction where to continue execution in the case of an exception—i.e., thecatch block.

Documento similar