diff --git a/lib/pinc_bytecode/bytecode.ml b/lib/pinc_bytecode/bytecode.ml index 2800615..385207b 100644 --- a/lib/pinc_bytecode/bytecode.ml +++ b/lib/pinc_bytecode/bytecode.ml @@ -1,20 +1,18 @@ type t = { - instructions : Bytes.t; + instructions : Instruction.t Array.t; constants : Value.t Int32.Map.t; } let make ~instructions ~constants = { instructions; constants } -let pp_instructions fmt instructions = +let pp_instructions fmt = let offset = ref 0 in - while !offset < Bytes.length instructions do - let new_offset, t = Instruction.decode instructions !offset in - if !offset = 0 then - Format.fprintf fmt "%0.4i %a" !offset Instruction.pp t - else - Format.fprintf fmt "@;%0.4i %a" !offset Instruction.pp t; - offset := new_offset - done + Array.iter @@ fun instruction -> + if !offset = 0 then + Format.fprintf fmt "%0.4i %a" !offset Instruction.pp instruction + else + Format.fprintf fmt "@;%0.4i %a" !offset Instruction.pp instruction; + offset := !offset + Instruction.length instruction ;; let rec pp_value fmt = function @@ -53,7 +51,7 @@ let pp fmt t = pp_constants fmt t.constants; Format.fprintf Format.std_formatter "@."); - if Bytes.length t.instructions > 0 then ( + if Array.length t.instructions > 0 then ( Format.fprintf Format.std_formatter "[INSTRUCTIONS]@."; Format.fprintf fmt "@[%a@]" pp_instructions t.instructions) ;; @@ -69,8 +67,14 @@ let serialize t = Buffer.add_int32_be buf key; Value.serialize buf value) in - let () = Buffer.add_int32_be buf @@ Int32.of_int (Bytes.length t.instructions) in - let () = Buffer.add_bytes buf t.instructions in + let () = Buffer.add_int32_be buf @@ Int32.of_int (Array.length t.instructions) in + let () = + Array.iter + (fun instruction -> + let serialized = Instruction.to_bytes instruction in + Buffer.add_bytes buf serialized) + t.instructions + in Buffer.contents buf ;; @@ -89,8 +93,12 @@ let deserialize str = in let instructions_length = Int32.to_int @@ Bytes.get_int32_be bytes !offset in offset := !offset + 4; - let instructions = Bytes.sub bytes !offset instructions_length in - offset := !offset + instructions_length; + let instructions = + Array.init instructions_length (fun _ -> + let new_offset, res = Instruction.decode bytes !offset in + offset := new_offset; + res) + in assert (!offset = Bytes.length bytes); make ~instructions ~constants ;; diff --git a/lib/pinc_bytecode/instruction.ml b/lib/pinc_bytecode/instruction.ml index 46bbabc..6aade5b 100644 --- a/lib/pinc_bytecode/instruction.ml +++ b/lib/pinc_bytecode/instruction.ml @@ -135,6 +135,8 @@ let operands_length = function | I_Debug_Print_Stack -> 0 ;; +let length t = 1 + operands_length t + let decode bytes offset = let instruction = Bytes.get_uint8 bytes offset in let offset = offset + 1 in diff --git a/lib/pinc_bytecode/value.ml b/lib/pinc_bytecode/value.ml index ce0d21f..317aac0 100644 --- a/lib/pinc_bytecode/value.ml +++ b/lib/pinc_bytecode/value.ml @@ -19,7 +19,7 @@ and builtin_function = { and compiled_function = { num_locals : int; num_parameters : int; - instructions : Bytes.t; + instructions : Instruction.t Array.t; } and closure = { @@ -110,11 +110,7 @@ let rec equal a b = Int.equal a.num_parameters b.num_parameters && Int.equal a.fn_index b.fn_index | _ -> false -and equal_function a b = - Int.equal a.num_locals b.num_locals - && Int.equal a.num_parameters b.num_parameters - && Bytes.equal a.instructions b.instructions -;; +and equal_function a b = a == b let compare a b = match (a, b) with @@ -185,8 +181,12 @@ and serialize_function buf f = Buffer.add_int8 buf 0x09; Buffer.add_int32_be buf @@ Int32.of_int num_locals; Buffer.add_int32_be buf @@ Int32.of_int num_parameters; - Buffer.add_int32_be buf @@ Int32.of_int (Bytes.length instructions); - Buffer.add_bytes buf instructions + Buffer.add_int32_be buf @@ Int32.of_int (Array.length instructions); + Array.iter + (fun instruction -> + let serialized = Instruction.to_bytes instruction in + Buffer.add_bytes buf serialized) + instructions and serialize_builtin_function buf f = let num_parameters = f.num_parameters in @@ -265,8 +265,12 @@ and deserialize_function bytes offset = offset := !offset + 4; let instructions_length = Int32.to_int @@ Bytes.get_int32_be bytes !offset in offset := !offset + 4; - let instructions = Bytes.sub bytes !offset instructions_length in - offset := !offset + instructions_length; + let instructions = + Array.init instructions_length (fun _ -> + let new_offset, res = Instruction.decode bytes !offset in + offset := new_offset; + res) + in { num_locals; num_parameters; instructions } and deserialize_builtin_function bytes offset = diff --git a/lib/pinc_compiler/compiler.ml b/lib/pinc_compiler/compiler.ml index e0b5a35..a84b6d7 100644 --- a/lib/pinc_compiler/compiler.ml +++ b/lib/pinc_compiler/compiler.ml @@ -6,7 +6,7 @@ type emitted_instruction = { } type scope = { - instructions : Buffer.t; + instructions : Pinc_Bytecode.Instruction.t Dynarray.t; last_instruction : emitted_instruction; previous_instruction : emitted_instruction; } @@ -58,13 +58,7 @@ let replace_instruction t offset instruction = match t.scopes with | [] -> assert false | scope :: _ -> - let current_instructions = Buffer.to_bytes scope.instructions in - let src = Pinc_Bytecode.Instruction.to_bytes instruction in - let srcoff = 0 in - let len = Bytes.length src in - Bytes.blit src srcoff current_instructions offset len; - Buffer.truncate scope.instructions 0; - Buffer.add_bytes scope.instructions current_instructions; + Dynarray.set scope.instructions offset instruction; t ;; @@ -72,7 +66,7 @@ let remove_last_instruction t = match t.scopes with | [] -> assert false | scope :: scopes -> - Buffer.truncate scope.instructions scope.last_instruction.offset; + Dynarray.remove_last scope.instructions; let scope' = { scope with last_instruction = scope.previous_instruction } in { t with scopes = scope' :: scopes } ;; @@ -85,7 +79,7 @@ let match_last_instruction t check = let add_scope t = let scope = { - instructions = Buffer.create 8; + instructions = Dynarray.create (); previous_instruction = empty_instruction; last_instruction = empty_instruction; } @@ -119,8 +113,8 @@ let add_constant = let emit t opcode = let scope = current_scope t in - let offset = Buffer.length scope.instructions in - Buffer.add_bytes scope.instructions @@ Pinc_Bytecode.Instruction.to_bytes @@ opcode; + let offset = Dynarray.length scope.instructions in + Dynarray.add_last scope.instructions opcode; let t = set_last_instruction t offset opcode in t ;; @@ -289,7 +283,7 @@ let rec compile_expr t (expr : Pinc_Types.Ast.expression) = let num_free_variables = List.length free_variables in let num_parameters = List.length parameters in - let instructions = Buffer.to_bytes scope.instructions in + let instructions = Dynarray.to_array @@ scope.instructions in let fn_addr, t = add_constant t @@ Pinc_Bytecode.Value.Function { num_locals; num_parameters; instructions } @@ -429,7 +423,7 @@ and compile_conditional_expression t ~condition ~consequent ~alternate = (* Alternate *) let t = emit t (Pinc_Bytecode.Instruction.I_Jump 0xFFFFFFFl) in let jump_alternate_offset = last_instruction_offset t in - let jump_address = Int32.of_int (Buffer.length @@ current_instructions t) in + let jump_address = Int32.of_int (Dynarray.length @@ current_instructions t) in let t = replace_instruction t jump_consequent_offset @@ Pinc_Bytecode.Instruction.I_Jump_If_False jump_address @@ -447,7 +441,7 @@ and compile_conditional_expression t ~condition ~consequent ~alternate = in t in - let jump_address = Int32.of_int (Buffer.length @@ current_instructions t) in + let jump_address = Int32.of_int (Dynarray.length @@ current_instructions t) in let t = replace_instruction t jump_alternate_offset @@ Pinc_Bytecode.Instruction.I_Jump jump_address @@ -476,7 +470,7 @@ and compile_loop_expression t ~index ~iterator ~reverse:_ ~iterable ~body = let t = emit t @@ Pinc_Bytecode.Instruction.I_Length in let t = emit_set_symbol t length_symbol in (* Set Iterator *) - let jump_address = Int32.of_int (Buffer.length @@ current_instructions t) in + let jump_address = Int32.of_int (Dynarray.length @@ current_instructions t) in let t = emit_get_symbol t iterable_symbol in let t = emit_get_symbol t index_symbol in let t = emit t @@ Pinc_Bytecode.Instruction.I_Index in @@ -536,7 +530,7 @@ let compile_declaration (decl : Pinc_Types.Ast.declaration) t = let compile (ast : Pinc_Types.Ast.t) = let scope = { - instructions = Buffer.create 8; + instructions = Dynarray.create (); previous_instruction = empty_instruction; last_instruction = empty_instruction; } @@ -552,6 +546,6 @@ let compile (ast : Pinc_Types.Ast.t) = Pinc_Bytecode.Bytecode.serialize @@ Pinc_Bytecode.Bytecode.make - ~instructions:(Buffer.to_bytes @@ current_instructions t) + ~instructions:(Dynarray.to_array @@ current_instructions t) ~constants:t.constants ;; diff --git a/lib/pinc_vm/vm.ml b/lib/pinc_vm/vm.ml index ee92e6b..4502c2f 100644 --- a/lib/pinc_vm/vm.ml +++ b/lib/pinc_vm/vm.ml @@ -498,13 +498,11 @@ let execute_return t = let run t = while (current_frame t).instruction_pointer - < Bytes.length @@ Frame.instructions (current_frame t) + < Array.length @@ Frame.instructions (current_frame t) do let frame = current_frame t in - let new_ip, op = - Instruction.decode (Frame.instructions frame) frame.instruction_pointer - in - Frame.set_instruction_pointer frame new_ip; + let op = Array.get (Frame.instructions frame) frame.instruction_pointer in + Frame.set_instruction_pointer frame @@ succ frame.instruction_pointer; match op with | Instruction.I_Debug_Print_Stack -> execute_debug_print_stack t | Instruction.I_Pop -> execute_pop t diff --git a/lib/pinc_vm/vm_frame.ml b/lib/pinc_vm/vm_frame.ml index 108954e..044d36d 100644 --- a/lib/pinc_vm/vm_frame.ml +++ b/lib/pinc_vm/vm_frame.ml @@ -1,10 +1,19 @@ type t = { base_pointer : int; - closure : Pinc_Bytecode.Value.closure; mutable instruction_pointer : int; + instructions : Pinc_Bytecode.Instruction.t Array.t; + closure : Pinc_Bytecode.Value.closure; } -let make ~base_pointer ~closure = { base_pointer; closure; instruction_pointer = 0 } -let instructions t = t.closure.fn.instructions +let make ~base_pointer ~closure = + { + base_pointer; + closure; + instructions = closure.Pinc_Bytecode.Value.fn.instructions; + instruction_pointer = 0; + } +;; + +let instructions t = t.instructions let free_variables t = t.closure.free_variables let set_instruction_pointer t i = t.instruction_pointer <- i diff --git a/lib/pinc_vm/vm_stack.ml b/lib/pinc_vm/vm_stack.ml index fe2bcb2..f337a16 100644 --- a/lib/pinc_vm/vm_stack.ml +++ b/lib/pinc_vm/vm_stack.ml @@ -25,32 +25,24 @@ let push t value = if t.stack_pointer > t.stack_size then raise_notrace Pinc_stack_overflow else ( - t.stack.(t.stack_pointer) <- value; + Array.unsafe_set t.stack t.stack_pointer value; t.stack_pointer <- succ t.stack_pointer) ;; let pop t = - if t.stack_pointer == 0 then - assert false - else ( - let value = t.stack.(t.stack_pointer - 1) in - t.stack_pointer <- pred t.stack_pointer; - value) + t.stack_pointer <- t.stack_pointer - 1; + Array.unsafe_get t.stack t.stack_pointer ;; let pop_n t n = - if t.stack_pointer < n then - assert false - else ( - let elements = List.init n (fun index -> t.stack.(t.stack_pointer - n + index)) in - t.stack_pointer <- t.stack_pointer - n; - elements) + t.stack_pointer <- t.stack_pointer - n; + List.init n (fun index -> Array.unsafe_get t.stack (t.stack_pointer + index)) ;; let nth t n = match t.stack_pointer - n with | 0 -> Pinc_Bytecode.Value.Null - | n -> t.stack.(n - 1) + | n -> Array.unsafe_get t.stack (n - 1) ;; let top t = nth t 0 diff --git a/test/vm/conditionals_instructions.t b/test/vm/conditionals_instructions.t index e560241..e4a9bfa 100644 --- a/test/vm/conditionals_instructions.t +++ b/test/vm/conditionals_instructions.t @@ -1,9 +1,9 @@ $ NO_COLOR="1" print_instructions . IfTrue [INSTRUCTIONS] 0000 I_True - 0001 I_Jump_If_False 0x0000000C (00000012) + 0001 I_Jump_If_False 0x00000004 (00000004) 0006 I_True - 0007 I_Jump 0x0000000D (00000013) + 0007 I_Jump 0x00000005 (00000005) 0012 I_Null 0013 I_Pop @@ -11,9 +11,9 @@ $ NO_COLOR="1" print_instructions . IfTrueElse [INSTRUCTIONS] 0000 I_True - 0001 I_Jump_If_False 0x0000000C (00000012) + 0001 I_Jump_If_False 0x00000004 (00000004) 0006 I_True - 0007 I_Jump 0x0000000D (00000013) + 0007 I_Jump 0x00000005 (00000005) 0012 I_False 0013 I_Pop @@ -21,9 +21,9 @@ $ NO_COLOR="1" print_instructions . IfFalse [INSTRUCTIONS] 0000 I_False - 0001 I_Jump_If_False 0x0000000C (00000012) + 0001 I_Jump_If_False 0x00000004 (00000004) 0006 I_True - 0007 I_Jump 0x0000000D (00000013) + 0007 I_Jump 0x00000005 (00000005) 0012 I_Null 0013 I_Pop @@ -31,8 +31,8 @@ $ NO_COLOR="1" print_instructions . IfFalseElse [INSTRUCTIONS] 0000 I_False - 0001 I_Jump_If_False 0x0000000C (00000012) + 0001 I_Jump_If_False 0x00000004 (00000004) 0006 I_True - 0007 I_Jump 0x0000000D (00000013) + 0007 I_Jump 0x00000005 (00000005) 0012 I_False 0013 I_Pop diff --git a/test/vm/functions_instructions.t b/test/vm/functions_instructions.t index 3cd4925..0c185bf 100644 --- a/test/vm/functions_instructions.t +++ b/test/vm/functions_instructions.t @@ -50,9 +50,9 @@ 0x00000001 (00000001) : 2 0x00000002 (00000002) : [ 0000 I_True - 0001 I_Jump_If_False 0x00000010 (00000016) + 0001 I_Jump_If_False 0x00000004 (00000004) 0006 I_Constant 0x00000000 (00000000) - 0011 I_Jump 0x00000015 (00000021) + 0011 I_Jump 0x00000005 (00000005) 0016 I_Constant 0x00000001 (00000001) 0021 I_Return ] @@ -248,9 +248,9 @@ 0000 I_Get_Local 0x00000000 (00000000) 0005 I_Constant 0x00000000 (00000000) 0010 I_Less_Equal - 0011 I_Jump_If_False 0x0000001A (00000026) + 0011 I_Jump_If_False 0x00000006 (00000006) 0016 I_Get_Local 0x00000000 (00000000) - 0021 I_Jump 0x0000003D (00000061) + 0021 I_Jump 0x00000011 (00000017) 0026 I_Current_Closure 0027 I_Get_Local 0x00000000 (00000000) 0032 I_Constant 0x00000001 (00000001) @@ -271,9 +271,9 @@ 0000 I_Get_Local 0x00000000 (00000000) 0005 I_Constant 0x00000004 (00000004) 0010 I_Less_Equal - 0011 I_Jump_If_False 0x0000001A (00000026) + 0011 I_Jump_If_False 0x00000006 (00000006) 0016 I_Constant 0x00000005 (00000005) - 0021 I_Jump 0x00000031 (00000049) + 0021 I_Jump 0x0000000D (00000013) 0026 I_Get_Local 0x00000000 (00000000) 0031 I_Current_Closure 0032 I_Get_Local 0x00000000 (00000000) diff --git a/test/vm/loop_instructions.t b/test/vm/loop_instructions.t index 2a9c6ad..70fc33f 100644 --- a/test/vm/loop_instructions.t +++ b/test/vm/loop_instructions.t @@ -39,7 +39,7 @@ 0111 I_Get_Global 0x00000003 (00000003) 0116 I_Get_Global 0x00000002 (00000002) 0121 I_Greater_Equal - 0122 I_Jump_If_False 0x00000044 (00000068) + 0122 I_Jump_If_False 0x00000010 (00000016) 0127 I_Get_Global 0x00000002 (00000002) 0132 I_Dynamic_Array 0133 I_Pop