Arquitectura de Computadores II 3º Ano Máquinas Virtuais João Luís Ferreira Sobral Departamento do Informática Universidade do Minho Março 2003 Máquinas Virtuais Questões que levaram à introdução de máquinas virtuais 1. Como possibilitar a execução de programas em arquitecturas de computadores com conjuntos de instruções diferentes, sem efectuar a recompilação do código fonte? 2. Como garantir que código executável que é descarregado é seguro? 3. Como produzir código compacto, por forma a que seja descarregado rapidamente? 1. Obtenção de código executável portável (sem recompilação das fontes) • O código fonte é compilado para um ISA virtual (ISA da máquina virtual), que durante a execução é traduzido para um ISA real • As E/S são efectuadas através de chamadas a rotinas pré-definidas (i.é., não existem instruções específicas para E/S) • A abordagem tradicional obriga ao desenvolvimento de nº Linguagens x nº de arquitecturas compiladores. Com uma máquina virtual não apenas necessários nº Linguagens compiladores + nº de arq. máquinas virtuais 2. Segurança do código executável • O código executável é validado durante a execução ou quando carregado • Cada operando tem um tipo associado possibilitando validações adicionais 3. Código compacto • Utilizar um ISA que origine instruções com um número reduzido de bits Exemplos de Máquinas Virtuais • Smalltalk – Digitalk (década de 80) • JVM (Java Virtual Machine) – SUN (meados de 90) • CLR (Common Language Runtime) – Microsoft (finais de 90) Arquitectura de Computadores II 2 © João Luís Sobral 2003 Java Virtual Machine Visão global • Máquina de stack (todos os cálculos são efectuados numa pilha) • Opcodes de 8 bits (201 definidos, 25 quick, 3 reservados). • Grande parte das instruções ocupa apenas 8 bits. • Cada instrução identifica o tipo de dados dos operandos, o que melhora a segurança do código • Instruções para acesso a elementos de arrays • Zona dedicada ao armazenamento de constantes e símbolos • Não existem instruções para manipulação directa de endereços de memória (segurança do código!) Tipos de dados • • • • • • • • byte – 8 bits em complemento para 2 short - 16 bits em complemento para 2 int - 32 bits em complemento para 2 long – 64 bits em complemento para 2 char – 16 bits inteiros sem sinal representando caracteres Unicode float – 32 bits IEEE 754 em vírgula flutuante double – 64 bits IEEE 754 em vírgula flutuante reference – referência para um array ou objecto Zonas de dados • PC – registo que aponta para a instrução em execução • Java stack – equivalente à pilha nas linguagens convencionais, contém os parâmetros dos métodos, as variáveis locais e os resultados intermédios • Heap – contém objectos e arrays • Área de métodos – contém código dos métodos • Área de constantes – contém as constantes utilizadas em cada classe e as referências a símbolos externos (semelhante a uma tabela de símbolos, mas com um âmbito alargado) Arquitectura de Computadores II 3 © João Luís Sobral 2003 Java Virtual Machine Conjunto de Instruções • Cada instrução é constituída por um opcode de 8 bits seguido de um ou mais operandos • O conjunto de instruções não é ortogonal: algumas instruções operam apenas em operandos específicos • Cada instrução é precedida da indicação dos tipos dos operandos • A stack frame de cada método contém: • • • As instruções máquina podem-se referir aos seguintes operandos: 1. 2. 3. 4. 5. • Grupo Transferência de informação Aritméticas Lógicas e Deslocamento Comparação e salto Outras Variáveis locais, numeradas de 0, 1, 2, ... Uma pilha para manipular os dados, que se encontra vazia quando um método inicia valor imediato (imm) variável local (#loc) a pilha a zona de constantes (#cons) endereço de salto (end) Quadro resumo das instruções: Tipos de Operandos Instrução bipush imm8 sipush imm16 Tconst_n ldc #cons8 pop, dup, swap Tload, Tstore #loc8 Tload_<n>, Tstore_<n> Taload, Tastore getfield, putfield #cons16 Tadd, Tsub, Tmult, Tdiv, Trem, Tneg Tinc #loc8 Imm8 Tand, Tor, Txor Tshl, Tshr, Tushr ifcond end16 if_icmp<cond> end16 goto end16 goto_w end32 invokestatic #cons16 Treturn return wide new #cons16 newarray type8 Arquitectura de Computadores II i, l, f, d, a i, l, f, d, a i, l, f, d, a b, s, i, l, f, d, c, a i, l, f, d i i, l i, l cond = eq | ne | lt | le | gt | ge i, l, f, d, a 4 # Comentário 2 3 1 2 1 2 1 1 3 1 push immediate push immediate push constant 0 or 1 push item from constant pool direct operand stack manipulation load/store type T local variable #loc load/store type T local variable n (0..3) load/store array element of type T load/store object field addition, subtract, multiply, divide, remainder, NEG increment local var. by Imm8 AND, OR, XOR shift left logical., right logical, right arth. branch to PC + end16 if condz is true branch to PC + end16 if cond is true branch to PC + end16 branch to PC + end32 invoke static method #cons16 return value of type T from method return from void method gain access to more local variables create new object create new array of type 3 1 1 3 3 3 5 3 1 1 3 3 2 © João Luís Sobral 2003 Java Virtual Machine Conjunto de Instruções (exemplos) • int x = 2 iconst_2 istore_0 • int y = 6 bipush 6 istore_1 • push byte 6 store into local var #1 (y) int u = x + y iload_0 iload_1 iadd istore_2 • push 2 store into local var #0 (x) push x push y add local #2 (v) u = add(x,y,-1) iload_0 iload_1 iconst_m1 invokestatic #1 istore_2 • push push x >= push x x 2 2 ? 0 int w[] = new int[3]; iconst_3 newarray int astore_0 • push a push b a + b push c (a + b) + c return integer on stack if ( x < 2 ) x=0; iload_0 iconst_2 if_icmpge fim iconst_0 istore_0 • push x push y push -1 constant #1 = referência método add get result from stack static add(int a, int b,int c) { return(a+b+c); } iload_0 iload_1 iadd iload_2 iadd ireturn • // static add(int,int,int) push 3 w= int[3] w[2] = 4; aload_0 iconst_2 iconst_4 iastore Arquitectura de Computadores II push w push 2 push 4 5 © João Luís Sobral 2003 Java Virtual Machine Exercícios Para cada uma das alíneas seguintes, verifique qual o código gerado pelo compilador 1. Expressões aritméticas a. constantes public class Main { public static void main(String[] str) { int x = 2; int y = 6; int z = 200; int u = 2000000; } b. cálculos z = x + y; z = 3*((x/y) - 2/(z+u)); x++; y <<= 3 2. Invocações de métodos e passagem de parâmetros a. codificação de invocações de métodos static add(int a, int b,int c) { return(a + b + c); } public static void main(String[] str) { .... add(x,y,-1); } b. codificação de métodos interprete a informação apresentada com a assinatura do método add 3. Controlo de fluxo if ( x < 2 ) x=0; boolean flag = ( x < y); for (int i=0; i<10; i++) x++; 4. Arrays int w[] = new int[3]; w[2] = 4; w[0]=w[2]; Arquitectura de Computadores II 6 © João Luís Sobral 2003