| ... | @@ -263,12 +263,12 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { | ... | @@ -263,12 +263,12 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 263 | expression: []const u8, | 263 | expression: []const u8, |
| 264 | allocator: std.mem.Allocator, | 264 | allocator: std.mem.Allocator, |
| 265 | context: ExpressionContext, | 265 | context: ExpressionContext, |
| 266 | initial_value: usize, | 266 | initial_value: ?usize, |
| 267 | ) !Value { | 267 | ) !?Value { |
| 268 | try self.stack.append(allocator, .{ .generic = initial_value }); | 268 | if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i }); |
| 269 | var stream = std.io.fixedBufferStream(expression); | 269 | var stream = std.io.fixedBufferStream(expression); |
| 270 | while (try self.step(&stream, allocator, context)) {} | 270 | while (try self.step(&stream, allocator, context)) {} |
| 271 | if (self.stack.items.len == 0) return error.InvalidExpression; | 271 | if (self.stack.items.len == 0) return null; |
| 272 | return self.stack.items[self.stack.items.len - 1]; | 272 | return self.stack.items[self.stack.items.len - 1]; |
| 273 | } | 273 | } |
| 274 | | 274 | |
| ... | @@ -412,7 +412,11 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { | ... | @@ -412,7 +412,11 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 412 | OP.xderef, | 412 | OP.xderef, |
| 413 | OP.xderef_size, | 413 | OP.xderef_size, |
| 414 | OP.xderef_type, | 414 | OP.xderef_type, |
| 415 | => try self.stack.pop().asIntegral(), | 415 | => blk: { |
| | 416 | _ = self.stack.pop(); |
| | 417 | if (self.stack.items.len == 0) return error.InvalidExpression; |
| | 418 | break :blk try self.stack.items[self.stack.items.len - 1].asIntegral(); |
| | 419 | }, |
| 416 | else => null, | 420 | else => null, |
| 417 | }; | 421 | }; |
| 418 | | 422 | |
| ... | @@ -424,7 +428,9 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { | ... | @@ -424,7 +428,9 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 424 | | 428 | |
| 425 | const operand = try readOperand(stream, opcode); | 429 | const operand = try readOperand(stream, opcode); |
| 426 | const size = switch (opcode) { | 430 | const size = switch (opcode) { |
| 427 | OP.deref => @sizeOf(addr_type), | 431 | OP.deref, |
| | 432 | OP.xderef, |
| | 433 | => @sizeOf(addr_type), |
| 428 | OP.deref_size, | 434 | OP.deref_size, |
| 429 | OP.xderef_size, | 435 | OP.xderef_size, |
| 430 | => operand.?.type_size, | 436 | => operand.?.type_size, |
| ... | @@ -442,16 +448,21 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { | ... | @@ -442,16 +448,21 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 442 | else => return error.InvalidExpression, | 448 | else => return error.InvalidExpression, |
| 443 | })) orelse return error.InvalidExpression; | 449 | })) orelse return error.InvalidExpression; |
| 444 | | 450 | |
| 445 | if (opcode == OP.deref_type) { | 451 | switch (opcode) { |
| 446 | self.stack.items[self.stack.items.len - 1] = .{ | 452 | OP.deref_type, |
| 447 | .regval_type = .{ | 453 | OP.xderef_type, |
| 448 | .type_offset = operand.?.deref_type.type_offset, | 454 | => { |
| 449 | .type_size = operand.?.deref_type.size, | 455 | self.stack.items[self.stack.items.len - 1] = .{ |
| 450 | .value = value, | 456 | .regval_type = .{ |
| 451 | }, | 457 | .type_offset = operand.?.deref_type.type_offset, |
| 452 | }; | 458 | .type_size = operand.?.deref_type.size, |
| 453 | } else { | 459 | .value = value, |
| 454 | self.stack.items[self.stack.items.len - 1] = .{ .generic = value }; | 460 | }, |
| | 461 | }; |
| | 462 | }, |
| | 463 | else => { |
| | 464 | self.stack.items[self.stack.items.len - 1] = .{ .generic = value }; |
| | 465 | }, |
| 455 | } | 466 | } |
| 456 | }, | 467 | }, |
| 457 | OP.push_object_address, | 468 | OP.push_object_address, |
| ... | @@ -759,7 +770,7 @@ pub fn Builder(comptime options: ExpressionOptions) type { | ... | @@ -759,7 +770,7 @@ pub fn Builder(comptime options: ExpressionOptions) type { |
| 759 | OP.ne, | 770 | OP.ne, |
| 760 | OP.nop, | 771 | OP.nop, |
| 761 | => try writer.writeByte(opcode), | 772 | => try writer.writeByte(opcode), |
| 762 | else => @compileError("This opcode requires operands, use write<Opcode>() instead"), | 773 | else => @compileError("This opcode requires operands, use `write<Opcode>()` instead"), |
| 763 | } | 774 | } |
| 764 | } | 775 | } |
| 765 | | 776 | |
| ... | @@ -836,7 +847,7 @@ pub fn Builder(comptime options: ExpressionOptions) type { | ... | @@ -836,7 +847,7 @@ pub fn Builder(comptime options: ExpressionOptions) type { |
| 836 | | 847 | |
| 837 | pub fn writeBreg(writer: anytype, register: u8, offset: anytype) !void { | 848 | pub fn writeBreg(writer: anytype, register: u8, offset: anytype) !void { |
| 838 | if (register > 31) return error.InvalidRegister; | 849 | if (register > 31) return error.InvalidRegister; |
| 839 | try writer.writeByte(OP.reg0 + register); | 850 | try writer.writeByte(OP.breg0 + register); |
| 840 | try leb.writeILEB128(writer, offset); | 851 | try leb.writeILEB128(writer, offset); |
| 841 | } | 852 | } |
| 842 | | 853 | |
| ... | @@ -848,7 +859,7 @@ pub fn Builder(comptime options: ExpressionOptions) type { | ... | @@ -848,7 +859,7 @@ pub fn Builder(comptime options: ExpressionOptions) type { |
| 848 | | 859 | |
| 849 | pub fn writeRegvalType(writer: anytype, register: anytype, offset: anytype) !void { | 860 | pub fn writeRegvalType(writer: anytype, register: anytype, offset: anytype) !void { |
| 850 | if (options.call_frame_context) return error.InvalidCFAOpcode; | 861 | if (options.call_frame_context) return error.InvalidCFAOpcode; |
| 851 | try writer.writeByte(OP.bregx); | 862 | try writer.writeByte(OP.regval_type); |
| 852 | try leb.writeULEB128(writer, register); | 863 | try leb.writeULEB128(writer, register); |
| 853 | try leb.writeULEB128(writer, offset); | 864 | try leb.writeULEB128(writer, offset); |
| 854 | } | 865 | } |
| ... | @@ -996,35 +1007,36 @@ test "DWARF expressions" { | ... | @@ -996,35 +1007,36 @@ test "DWARF expressions" { |
| 996 | | 1007 | |
| 997 | // Constants | 1008 | // Constants |
| 998 | { | 1009 | { |
| | 1010 | stack_machine.reset(); |
| 999 | program.clearRetainingCapacity(); | 1011 | program.clearRetainingCapacity(); |
| 1000 | | 1012 | |
| 1001 | const expected = [_]comptime_int{ | 1013 | const input = [_]comptime_int{ |
| 1002 | 1, | 1014 | 1, |
| 1003 | -1, | 1015 | -1, |
| 1004 | 0x0fff, | 1016 | @as(usize, @truncate(0x0fff)), |
| 1005 | -0x0fff, | 1017 | @as(isize, @truncate(-0x0fff)), |
| 1006 | 0x0fffffff, | 1018 | @as(usize, @truncate(0x0fffffff)), |
| 1007 | -0x0fffffff, | 1019 | @as(isize, @truncate(-0x0fffffff)), |
| 1008 | 0x0fffffffffffffff, | 1020 | @as(usize, @truncate(0x0fffffffffffffff)), |
| 1009 | -0x0fffffffffffffff, | 1021 | @as(isize, @truncate(-0x0fffffffffffffff)), |
| 1010 | 0x8000000, | 1022 | @as(usize, @truncate(0x8000000)), |
| 1011 | -0x8000000, | 1023 | @as(isize, @truncate(-0x8000000)), |
| 1012 | @as(usize, @truncate(0x12345678_12345678)), | 1024 | @as(usize, @truncate(0x12345678_12345678)), |
| 1013 | @as(usize, @truncate(0xffffffff_ffffffff)), | 1025 | @as(usize, @truncate(0xffffffff_ffffffff)), |
| 1014 | @as(usize, @truncate(0xeeeeeeee_eeeeeeee)), | 1026 | @as(usize, @truncate(0xeeeeeeee_eeeeeeee)), |
| 1015 | }; | 1027 | }; |
| 1016 | | 1028 | |
| 1017 | try b.writeConst(writer, u8, expected[0]); | 1029 | try b.writeConst(writer, u8, input[0]); |
| 1018 | try b.writeConst(writer, i8, expected[1]); | 1030 | try b.writeConst(writer, i8, input[1]); |
| 1019 | try b.writeConst(writer, u16, expected[2]); | 1031 | try b.writeConst(writer, u16, input[2]); |
| 1020 | try b.writeConst(writer, i16, expected[3]); | 1032 | try b.writeConst(writer, i16, input[3]); |
| 1021 | try b.writeConst(writer, u32, expected[4]); | 1033 | try b.writeConst(writer, u32, input[4]); |
| 1022 | try b.writeConst(writer, i32, expected[5]); | 1034 | try b.writeConst(writer, i32, input[5]); |
| 1023 | try b.writeConst(writer, u64, expected[6]); | 1035 | try b.writeConst(writer, u64, input[6]); |
| 1024 | try b.writeConst(writer, i64, expected[7]); | 1036 | try b.writeConst(writer, i64, input[7]); |
| 1025 | try b.writeConst(writer, u28, expected[8]); | 1037 | try b.writeConst(writer, u28, input[8]); |
| 1026 | try b.writeConst(writer, i28, expected[9]); | 1038 | try b.writeConst(writer, i28, input[9]); |
| 1027 | try b.writeAddr(writer, expected[10]); | 1039 | try b.writeAddr(writer, input[10]); |
| 1028 | | 1040 | |
| 1029 | var mock_compile_unit: dwarf.CompileUnit = undefined; | 1041 | var mock_compile_unit: dwarf.CompileUnit = undefined; |
| 1030 | mock_compile_unit.addr_base = 1; | 1042 | mock_compile_unit.addr_base = 1; |
| ... | @@ -1033,8 +1045,8 @@ test "DWARF expressions" { | ... | @@ -1033,8 +1045,8 @@ test "DWARF expressions" { |
| 1033 | defer mock_debug_addr.deinit(); | 1045 | defer mock_debug_addr.deinit(); |
| 1034 | | 1046 | |
| 1035 | try mock_debug_addr.writer().writeIntNative(u16, 0); | 1047 | try mock_debug_addr.writer().writeIntNative(u16, 0); |
| 1036 | try mock_debug_addr.writer().writeIntNative(usize, expected[11]); | 1048 | try mock_debug_addr.writer().writeIntNative(usize, input[11]); |
| 1037 | try mock_debug_addr.writer().writeIntNative(usize, expected[12]); | 1049 | try mock_debug_addr.writer().writeIntNative(usize, input[12]); |
| 1038 | | 1050 | |
| 1039 | const context = ExpressionContext{ | 1051 | const context = ExpressionContext{ |
| 1040 | .compile_unit = &mock_compile_unit, | 1052 | .compile_unit = &mock_compile_unit, |
| ... | @@ -1054,26 +1066,311 @@ test "DWARF expressions" { | ... | @@ -1054,26 +1066,311 @@ test "DWARF expressions" { |
| 1054 | try testing.expectEqual(die_offset, const_type.type_offset); | 1066 | try testing.expectEqual(die_offset, const_type.type_offset); |
| 1055 | try testing.expectEqualSlices(u8, type_bytes, const_type.value_bytes); | 1067 | try testing.expectEqualSlices(u8, type_bytes, const_type.value_bytes); |
| 1056 | | 1068 | |
| 1057 | try testing.expectEqual(@as(usize, expected[12]), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1069 | const expected = .{ |
| 1058 | try testing.expectEqual(@as(usize, expected[11]), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1070 | .{ usize, input[12], usize }, |
| 1059 | try testing.expectEqual(@as(usize, expected[10]), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1071 | .{ usize, input[11], usize }, |
| 1060 | try testing.expectEqual(@as(isize, @truncate(expected[9])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1072 | .{ usize, input[10], usize }, |
| 1061 | try testing.expectEqual(@as(usize, @truncate(expected[8])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1073 | .{ isize, input[9], isize }, |
| 1062 | try testing.expectEqual(@as(isize, @truncate(expected[7])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1074 | .{ usize, input[8], usize }, |
| 1063 | try testing.expectEqual(@as(usize, @truncate(expected[6])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1075 | .{ isize, input[7], isize }, |
| 1064 | try testing.expectEqual(@as(isize, @truncate(expected[5])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1076 | .{ usize, input[6], usize }, |
| 1065 | try testing.expectEqual(@as(usize, @truncate(expected[4])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1077 | .{ isize, input[5], isize }, |
| 1066 | try testing.expectEqual(@as(isize, @truncate(expected[3])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1078 | .{ usize, input[4], usize }, |
| 1067 | try testing.expectEqual(@as(usize, @truncate(expected[2])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1079 | .{ isize, input[3], isize }, |
| 1068 | try testing.expectEqual(@as(isize, @truncate(expected[1])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1080 | .{ usize, input[2], usize }, |
| 1069 | try testing.expectEqual(@as(usize, @truncate(expected[0])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); | 1081 | .{ isize, input[1], isize }, |
| | 1082 | .{ usize, input[0], usize }, |
| | 1083 | }; |
| | 1084 | |
| | 1085 | inline for (expected) |e| { |
| | 1086 | try testing.expectEqual(@as(e[0], e[1]), @as(e[2], @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| | 1087 | } |
| 1070 | } | 1088 | } |
| 1071 | | 1089 | |
| 1072 | // Register values | 1090 | // Register values |
| 1073 | if (@TypeOf(std.debug.ThreadContext) != void) { | 1091 | if (@sizeOf(std.debug.ThreadContext) != 0) { |
| | 1092 | stack_machine.reset(); |
| | 1093 | program.clearRetainingCapacity(); |
| | 1094 | |
| | 1095 | const reg_context = abi.RegisterContext{ |
| | 1096 | .eh_frame = true, |
| | 1097 | .is_macho = builtin.os.tag == .macos, |
| | 1098 | }; |
| 1074 | var thread_context: std.debug.ThreadContext = undefined; | 1099 | var thread_context: std.debug.ThreadContext = undefined; |
| 1075 | _ = thread_context; | 1100 | const context = ExpressionContext{ |
| | 1101 | .thread_context = &thread_context, |
| | 1102 | .reg_context = reg_context, |
| | 1103 | }; |
| | 1104 | |
| | 1105 | // TODO: Test fbreg (once implemented): mock a DIE and point compile_unit.frame_base at it |
| | 1106 | |
| | 1107 | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, 0, reg_context), 0xee); |
| | 1108 | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.fpRegNum(reg_context), reg_context), 1); |
| | 1109 | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.spRegNum(reg_context), reg_context), 2); |
| | 1110 | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.ipRegNum(), reg_context), 3); |
| 1076 | | 1111 | |
| 1077 | // TODO: Test fbreg, breg0..31, bregx, regval_type | 1112 | try b.writeBreg(writer, abi.fpRegNum(reg_context), @as(usize, 100)); |
| | 1113 | try b.writeBreg(writer, abi.spRegNum(reg_context), @as(usize, 200)); |
| | 1114 | try b.writeBregx(writer, abi.ipRegNum(), @as(usize, 300)); |
| | 1115 | try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400)); |
| | 1116 | |
| | 1117 | _ = try stack_machine.run(program.items, allocator, context, 0); |
| | 1118 | |
| | 1119 | const regval_type = stack_machine.stack.popOrNull().?.regval_type; |
| | 1120 | try testing.expectEqual(@as(usize, 400), regval_type.type_offset); |
| | 1121 | try testing.expectEqual(@as(u8, @sizeOf(usize)), regval_type.type_size); |
| | 1122 | try testing.expectEqual(@as(usize, 0xee), regval_type.value); |
| | 1123 | |
| | 1124 | try testing.expectEqual(@as(usize, 303), stack_machine.stack.popOrNull().?.generic); |
| | 1125 | try testing.expectEqual(@as(usize, 202), stack_machine.stack.popOrNull().?.generic); |
| | 1126 | try testing.expectEqual(@as(usize, 101), stack_machine.stack.popOrNull().?.generic); |
| | 1127 | } |
| | 1128 | |
| | 1129 | // Stack operations |
| | 1130 | { |
| | 1131 | var context = ExpressionContext{}; |
| | 1132 | |
| | 1133 | stack_machine.reset(); |
| | 1134 | program.clearRetainingCapacity(); |
| | 1135 | try b.writeConst(writer, u8, 1); |
| | 1136 | try b.writeOpcode(writer, OP.dup); |
| | 1137 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1138 | try testing.expectEqual(@as(usize, 1), stack_machine.stack.popOrNull().?.generic); |
| | 1139 | try testing.expectEqual(@as(usize, 1), stack_machine.stack.popOrNull().?.generic); |
| | 1140 | |
| | 1141 | stack_machine.reset(); |
| | 1142 | program.clearRetainingCapacity(); |
| | 1143 | try b.writeConst(writer, u8, 1); |
| | 1144 | try b.writeOpcode(writer, OP.drop); |
| | 1145 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1146 | try testing.expect(stack_machine.stack.popOrNull() == null); |
| | 1147 | |
| | 1148 | stack_machine.reset(); |
| | 1149 | program.clearRetainingCapacity(); |
| | 1150 | try b.writeConst(writer, u8, 4); |
| | 1151 | try b.writeConst(writer, u8, 5); |
| | 1152 | try b.writeConst(writer, u8, 6); |
| | 1153 | try b.writePick(writer, 2); |
| | 1154 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1155 | try testing.expectEqual(@as(usize, 4), stack_machine.stack.popOrNull().?.generic); |
| | 1156 | |
| | 1157 | stack_machine.reset(); |
| | 1158 | program.clearRetainingCapacity(); |
| | 1159 | try b.writeConst(writer, u8, 4); |
| | 1160 | try b.writeConst(writer, u8, 5); |
| | 1161 | try b.writeConst(writer, u8, 6); |
| | 1162 | try b.writeOpcode(writer, OP.over); |
| | 1163 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1164 | try testing.expectEqual(@as(usize, 5), stack_machine.stack.popOrNull().?.generic); |
| | 1165 | |
| | 1166 | stack_machine.reset(); |
| | 1167 | program.clearRetainingCapacity(); |
| | 1168 | try b.writeConst(writer, u8, 5); |
| | 1169 | try b.writeConst(writer, u8, 6); |
| | 1170 | try b.writeOpcode(writer, OP.swap); |
| | 1171 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1172 | try testing.expectEqual(@as(usize, 5), stack_machine.stack.popOrNull().?.generic); |
| | 1173 | try testing.expectEqual(@as(usize, 6), stack_machine.stack.popOrNull().?.generic); |
| | 1174 | |
| | 1175 | stack_machine.reset(); |
| | 1176 | program.clearRetainingCapacity(); |
| | 1177 | try b.writeConst(writer, u8, 4); |
| | 1178 | try b.writeConst(writer, u8, 5); |
| | 1179 | try b.writeConst(writer, u8, 6); |
| | 1180 | try b.writeOpcode(writer, OP.rot); |
| | 1181 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1182 | try testing.expectEqual(@as(usize, 5), stack_machine.stack.popOrNull().?.generic); |
| | 1183 | try testing.expectEqual(@as(usize, 4), stack_machine.stack.popOrNull().?.generic); |
| | 1184 | try testing.expectEqual(@as(usize, 6), stack_machine.stack.popOrNull().?.generic); |
| | 1185 | |
| | 1186 | const deref_target: usize = @truncate(0xffeeffee_ffeeffee); |
| | 1187 | |
| | 1188 | stack_machine.reset(); |
| | 1189 | program.clearRetainingCapacity(); |
| | 1190 | try b.writeAddr(writer, @intFromPtr(&deref_target)); |
| | 1191 | try b.writeOpcode(writer, OP.deref); |
| | 1192 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1193 | try testing.expectEqual(deref_target, stack_machine.stack.popOrNull().?.generic); |
| | 1194 | |
| | 1195 | stack_machine.reset(); |
| | 1196 | program.clearRetainingCapacity(); |
| | 1197 | try b.writeLiteral(writer, 0); |
| | 1198 | try b.writeAddr(writer, @intFromPtr(&deref_target)); |
| | 1199 | try b.writeOpcode(writer, OP.xderef); |
| | 1200 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1201 | try testing.expectEqual(deref_target, stack_machine.stack.popOrNull().?.generic); |
| | 1202 | |
| | 1203 | stack_machine.reset(); |
| | 1204 | program.clearRetainingCapacity(); |
| | 1205 | try b.writeAddr(writer, @intFromPtr(&deref_target)); |
| | 1206 | try b.writeDerefSize(writer, 1); |
| | 1207 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1208 | try testing.expectEqual(@as(usize, @as(*const u8, @ptrCast(&deref_target)).*), stack_machine.stack.popOrNull().?.generic); |
| | 1209 | |
| | 1210 | stack_machine.reset(); |
| | 1211 | program.clearRetainingCapacity(); |
| | 1212 | try b.writeLiteral(writer, 0); |
| | 1213 | try b.writeAddr(writer, @intFromPtr(&deref_target)); |
| | 1214 | try b.writeXDerefSize(writer, 1); |
| | 1215 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1216 | try testing.expectEqual(@as(usize, @as(*const u8, @ptrCast(&deref_target)).*), stack_machine.stack.popOrNull().?.generic); |
| | 1217 | |
| | 1218 | const type_offset: usize = @truncate(0xaabbaabb_aabbaabb); |
| | 1219 | |
| | 1220 | stack_machine.reset(); |
| | 1221 | program.clearRetainingCapacity(); |
| | 1222 | try b.writeAddr(writer, @intFromPtr(&deref_target)); |
| | 1223 | try b.writeDerefType(writer, 1, type_offset); |
| | 1224 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1225 | const deref_type = stack_machine.stack.popOrNull().?.regval_type; |
| | 1226 | try testing.expectEqual(type_offset, deref_type.type_offset); |
| | 1227 | try testing.expectEqual(@as(u8, 1), deref_type.type_size); |
| | 1228 | try testing.expectEqual(@as(usize, @as(*const u8, @ptrCast(&deref_target)).*), deref_type.value); |
| | 1229 | |
| | 1230 | stack_machine.reset(); |
| | 1231 | program.clearRetainingCapacity(); |
| | 1232 | try b.writeLiteral(writer, 0); |
| | 1233 | try b.writeAddr(writer, @intFromPtr(&deref_target)); |
| | 1234 | try b.writeXDerefType(writer, 1, type_offset); |
| | 1235 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1236 | const xderef_type = stack_machine.stack.popOrNull().?.regval_type; |
| | 1237 | try testing.expectEqual(type_offset, xderef_type.type_offset); |
| | 1238 | try testing.expectEqual(@as(u8, 1), xderef_type.type_size); |
| | 1239 | try testing.expectEqual(@as(usize, @as(*const u8, @ptrCast(&deref_target)).*), xderef_type.value); |
| | 1240 | |
| | 1241 | // TODO: Test OP.push_object_address |
| | 1242 | // TODO: Test OP.form_tls_address |
| | 1243 | |
| | 1244 | context.cfa = @truncate(0xccddccdd_ccddccdd); |
| | 1245 | |
| | 1246 | stack_machine.reset(); |
| | 1247 | program.clearRetainingCapacity(); |
| | 1248 | try b.writeOpcode(writer, OP.call_frame_cfa); |
| | 1249 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1250 | try testing.expectEqual(context.cfa.?, stack_machine.stack.popOrNull().?.generic); |
| | 1251 | } |
| | 1252 | |
| | 1253 | // Arithmetic and Logical Operations |
| | 1254 | { |
| | 1255 | var context = ExpressionContext{}; |
| | 1256 | |
| | 1257 | stack_machine.reset(); |
| | 1258 | program.clearRetainingCapacity(); |
| | 1259 | try b.writeConst(writer, i16, -4096); |
| | 1260 | try b.writeOpcode(writer, OP.abs); |
| | 1261 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1262 | try testing.expectEqual(@as(usize, 4096), stack_machine.stack.popOrNull().?.generic); |
| | 1263 | |
| | 1264 | stack_machine.reset(); |
| | 1265 | program.clearRetainingCapacity(); |
| | 1266 | try b.writeConst(writer, u16, 0xff0f); |
| | 1267 | try b.writeConst(writer, u16, 0xf0ff); |
| | 1268 | try b.writeOpcode(writer, OP.@"and"); |
| | 1269 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1270 | try testing.expectEqual(@as(usize, 0xf00f), stack_machine.stack.popOrNull().?.generic); |
| | 1271 | |
| | 1272 | stack_machine.reset(); |
| | 1273 | program.clearRetainingCapacity(); |
| | 1274 | try b.writeConst(writer, i16, -404); |
| | 1275 | try b.writeConst(writer, i16, 100); |
| | 1276 | try b.writeOpcode(writer, OP.div); |
| | 1277 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1278 | try testing.expectEqual(@as(isize, -404 / 100), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| | 1279 | |
| | 1280 | stack_machine.reset(); |
| | 1281 | program.clearRetainingCapacity(); |
| | 1282 | try b.writeConst(writer, u16, 200); |
| | 1283 | try b.writeConst(writer, u16, 50); |
| | 1284 | try b.writeOpcode(writer, OP.minus); |
| | 1285 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1286 | try testing.expectEqual(@as(usize, 150), stack_machine.stack.popOrNull().?.generic); |
| | 1287 | |
| | 1288 | stack_machine.reset(); |
| | 1289 | program.clearRetainingCapacity(); |
| | 1290 | try b.writeConst(writer, u16, 123); |
| | 1291 | try b.writeConst(writer, u16, 100); |
| | 1292 | try b.writeOpcode(writer, OP.mod); |
| | 1293 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1294 | try testing.expectEqual(@as(usize, 23), stack_machine.stack.popOrNull().?.generic); |
| | 1295 | |
| | 1296 | stack_machine.reset(); |
| | 1297 | program.clearRetainingCapacity(); |
| | 1298 | try b.writeConst(writer, u16, 0xff); |
| | 1299 | try b.writeConst(writer, u16, 0xee); |
| | 1300 | try b.writeOpcode(writer, OP.mul); |
| | 1301 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1302 | try testing.expectEqual(@as(usize, 0xed12), stack_machine.stack.popOrNull().?.generic); |
| | 1303 | |
| | 1304 | stack_machine.reset(); |
| | 1305 | program.clearRetainingCapacity(); |
| | 1306 | try b.writeConst(writer, u16, 5); |
| | 1307 | try b.writeOpcode(writer, OP.neg); |
| | 1308 | try b.writeConst(writer, i16, -6); |
| | 1309 | try b.writeOpcode(writer, OP.neg); |
| | 1310 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1311 | try testing.expectEqual(@as(usize, 6), stack_machine.stack.popOrNull().?.generic); |
| | 1312 | try testing.expectEqual(@as(isize, -5), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| | 1313 | |
| | 1314 | stack_machine.reset(); |
| | 1315 | program.clearRetainingCapacity(); |
| | 1316 | try b.writeConst(writer, u16, 0xff0f); |
| | 1317 | try b.writeOpcode(writer, OP.not); |
| | 1318 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1319 | try testing.expectEqual(~@as(usize, 0xff0f), stack_machine.stack.popOrNull().?.generic); |
| | 1320 | |
| | 1321 | stack_machine.reset(); |
| | 1322 | program.clearRetainingCapacity(); |
| | 1323 | try b.writeConst(writer, u16, 0xff0f); |
| | 1324 | try b.writeConst(writer, u16, 0xf0ff); |
| | 1325 | try b.writeOpcode(writer, OP.@"or"); |
| | 1326 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1327 | try testing.expectEqual(@as(usize, 0xffff), stack_machine.stack.popOrNull().?.generic); |
| | 1328 | |
| | 1329 | stack_machine.reset(); |
| | 1330 | program.clearRetainingCapacity(); |
| | 1331 | try b.writeConst(writer, i16, 402); |
| | 1332 | try b.writeConst(writer, i16, 100); |
| | 1333 | try b.writeOpcode(writer, OP.plus); |
| | 1334 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1335 | try testing.expectEqual(@as(usize, 502), stack_machine.stack.popOrNull().?.generic); |
| | 1336 | |
| | 1337 | stack_machine.reset(); |
| | 1338 | program.clearRetainingCapacity(); |
| | 1339 | try b.writeConst(writer, u16, 4096); |
| | 1340 | try b.writePlusUconst(writer, @as(usize, 8192)); |
| | 1341 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1342 | try testing.expectEqual(@as(usize, 4096 + 8192), stack_machine.stack.popOrNull().?.generic); |
| | 1343 | |
| | 1344 | stack_machine.reset(); |
| | 1345 | program.clearRetainingCapacity(); |
| | 1346 | try b.writeConst(writer, u16, 0xfff); |
| | 1347 | try b.writeConst(writer, u16, 1); |
| | 1348 | try b.writeOpcode(writer, OP.shl); |
| | 1349 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1350 | try testing.expectEqual(@as(usize, 0xfff << 1), stack_machine.stack.popOrNull().?.generic); |
| | 1351 | |
| | 1352 | stack_machine.reset(); |
| | 1353 | program.clearRetainingCapacity(); |
| | 1354 | try b.writeConst(writer, u16, 0xfff); |
| | 1355 | try b.writeConst(writer, u16, 1); |
| | 1356 | try b.writeOpcode(writer, OP.shr); |
| | 1357 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1358 | try testing.expectEqual(@as(usize, 0xfff >> 1), stack_machine.stack.popOrNull().?.generic); |
| | 1359 | |
| | 1360 | stack_machine.reset(); |
| | 1361 | program.clearRetainingCapacity(); |
| | 1362 | try b.writeConst(writer, u16, 0xfff); |
| | 1363 | try b.writeConst(writer, u16, 1); |
| | 1364 | try b.writeOpcode(writer, OP.shr); |
| | 1365 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1366 | try testing.expectEqual(@as(usize, @bitCast(@as(isize, 0xfff) >> 1)), stack_machine.stack.popOrNull().?.generic); |
| | 1367 | |
| | 1368 | stack_machine.reset(); |
| | 1369 | program.clearRetainingCapacity(); |
| | 1370 | try b.writeConst(writer, u16, 0xf0ff); |
| | 1371 | try b.writeConst(writer, u16, 0xff0f); |
| | 1372 | try b.writeOpcode(writer, OP.xor); |
| | 1373 | _ = try stack_machine.run(program.items, allocator, context, null); |
| | 1374 | try testing.expectEqual(@as(usize, 0x0ff0), stack_machine.stack.popOrNull().?.generic); |
| 1078 | } | 1375 | } |
| 1079 | } | 1376 | } |