| ... | ... | @@ -263,12 +263,12 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 263 | 263 | expression: []const u8, |
| 264 | 264 | allocator: std.mem.Allocator, |
| 265 | 265 | context: ExpressionContext, |
| 266 | | initial_value: usize, |
| 267 | | ) !Value { |
| 268 | | try self.stack.append(allocator, .{ .generic = initial_value }); |
| 266 | initial_value: ?usize, |
| 267 | ) !?Value { |
| 268 | if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i }); |
| 269 | 269 | var stream = std.io.fixedBufferStream(expression); |
| 270 | 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 | 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 | 412 | OP.xderef, |
| 413 | 413 | OP.xderef_size, |
| 414 | 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 | 420 | else => null, |
| 417 | 421 | }; |
| 418 | 422 | |
| ... | ... | @@ -424,7 +428,9 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 424 | 428 | |
| 425 | 429 | const operand = try readOperand(stream, opcode); |
| 426 | 430 | const size = switch (opcode) { |
| 427 | | OP.deref => @sizeOf(addr_type), |
| 431 | OP.deref, |
| 432 | OP.xderef, |
| 433 | => @sizeOf(addr_type), |
| 428 | 434 | OP.deref_size, |
| 429 | 435 | OP.xderef_size, |
| 430 | 436 | => operand.?.type_size, |
| ... | ... | @@ -442,16 +448,21 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 442 | 448 | else => return error.InvalidExpression, |
| 443 | 449 | })) orelse return error.InvalidExpression; |
| 444 | 450 | |
| 445 | | if (opcode == OP.deref_type) { |
| 446 | | self.stack.items[self.stack.items.len - 1] = .{ |
| 447 | | .regval_type = .{ |
| 448 | | .type_offset = operand.?.deref_type.type_offset, |
| 449 | | .type_size = operand.?.deref_type.size, |
| 450 | | .value = value, |
| 451 | | }, |
| 452 | | }; |
| 453 | | } else { |
| 454 | | self.stack.items[self.stack.items.len - 1] = .{ .generic = value }; |
| 451 | switch (opcode) { |
| 452 | OP.deref_type, |
| 453 | OP.xderef_type, |
| 454 | => { |
| 455 | self.stack.items[self.stack.items.len - 1] = .{ |
| 456 | .regval_type = .{ |
| 457 | .type_offset = operand.?.deref_type.type_offset, |
| 458 | .type_size = operand.?.deref_type.size, |
| 459 | .value = value, |
| 460 | }, |
| 461 | }; |
| 462 | }, |
| 463 | else => { |
| 464 | self.stack.items[self.stack.items.len - 1] = .{ .generic = value }; |
| 465 | }, |
| 455 | 466 | } |
| 456 | 467 | }, |
| 457 | 468 | OP.push_object_address, |
| ... | ... | @@ -759,7 +770,7 @@ pub fn Builder(comptime options: ExpressionOptions) type { |
| 759 | 770 | OP.ne, |
| 760 | 771 | OP.nop, |
| 761 | 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 | 847 | |
| 837 | 848 | pub fn writeBreg(writer: anytype, register: u8, offset: anytype) !void { |
| 838 | 849 | if (register > 31) return error.InvalidRegister; |
| 839 | | try writer.writeByte(OP.reg0 + register); |
| 850 | try writer.writeByte(OP.breg0 + register); |
| 840 | 851 | try leb.writeILEB128(writer, offset); |
| 841 | 852 | } |
| 842 | 853 | |
| ... | ... | @@ -848,7 +859,7 @@ pub fn Builder(comptime options: ExpressionOptions) type { |
| 848 | 859 | |
| 849 | 860 | pub fn writeRegvalType(writer: anytype, register: anytype, offset: anytype) !void { |
| 850 | 861 | if (options.call_frame_context) return error.InvalidCFAOpcode; |
| 851 | | try writer.writeByte(OP.bregx); |
| 862 | try writer.writeByte(OP.regval_type); |
| 852 | 863 | try leb.writeULEB128(writer, register); |
| 853 | 864 | try leb.writeULEB128(writer, offset); |
| 854 | 865 | } |
| ... | ... | @@ -996,35 +1007,36 @@ test "DWARF expressions" { |
| 996 | 1007 | |
| 997 | 1008 | // Constants |
| 998 | 1009 | { |
| 1010 | stack_machine.reset(); |
| 999 | 1011 | program.clearRetainingCapacity(); |
| 1000 | 1012 | |
| 1001 | | const expected = [_]comptime_int{ |
| 1013 | const input = [_]comptime_int{ |
| 1002 | 1014 | 1, |
| 1003 | 1015 | -1, |
| 1004 | | 0x0fff, |
| 1005 | | -0x0fff, |
| 1006 | | 0x0fffffff, |
| 1007 | | -0x0fffffff, |
| 1008 | | 0x0fffffffffffffff, |
| 1009 | | -0x0fffffffffffffff, |
| 1010 | | 0x8000000, |
| 1011 | | -0x8000000, |
| 1016 | @as(usize, @truncate(0x0fff)), |
| 1017 | @as(isize, @truncate(-0x0fff)), |
| 1018 | @as(usize, @truncate(0x0fffffff)), |
| 1019 | @as(isize, @truncate(-0x0fffffff)), |
| 1020 | @as(usize, @truncate(0x0fffffffffffffff)), |
| 1021 | @as(isize, @truncate(-0x0fffffffffffffff)), |
| 1022 | @as(usize, @truncate(0x8000000)), |
| 1023 | @as(isize, @truncate(-0x8000000)), |
| 1012 | 1024 | @as(usize, @truncate(0x12345678_12345678)), |
| 1013 | 1025 | @as(usize, @truncate(0xffffffff_ffffffff)), |
| 1014 | 1026 | @as(usize, @truncate(0xeeeeeeee_eeeeeeee)), |
| 1015 | 1027 | }; |
| 1016 | 1028 | |
| 1017 | | try b.writeConst(writer, u8, expected[0]); |
| 1018 | | try b.writeConst(writer, i8, expected[1]); |
| 1019 | | try b.writeConst(writer, u16, expected[2]); |
| 1020 | | try b.writeConst(writer, i16, expected[3]); |
| 1021 | | try b.writeConst(writer, u32, expected[4]); |
| 1022 | | try b.writeConst(writer, i32, expected[5]); |
| 1023 | | try b.writeConst(writer, u64, expected[6]); |
| 1024 | | try b.writeConst(writer, i64, expected[7]); |
| 1025 | | try b.writeConst(writer, u28, expected[8]); |
| 1026 | | try b.writeConst(writer, i28, expected[9]); |
| 1027 | | try b.writeAddr(writer, expected[10]); |
| 1029 | try b.writeConst(writer, u8, input[0]); |
| 1030 | try b.writeConst(writer, i8, input[1]); |
| 1031 | try b.writeConst(writer, u16, input[2]); |
| 1032 | try b.writeConst(writer, i16, input[3]); |
| 1033 | try b.writeConst(writer, u32, input[4]); |
| 1034 | try b.writeConst(writer, i32, input[5]); |
| 1035 | try b.writeConst(writer, u64, input[6]); |
| 1036 | try b.writeConst(writer, i64, input[7]); |
| 1037 | try b.writeConst(writer, u28, input[8]); |
| 1038 | try b.writeConst(writer, i28, input[9]); |
| 1039 | try b.writeAddr(writer, input[10]); |
| 1028 | 1040 | |
| 1029 | 1041 | var mock_compile_unit: dwarf.CompileUnit = undefined; |
| 1030 | 1042 | mock_compile_unit.addr_base = 1; |
| ... | ... | @@ -1033,8 +1045,8 @@ test "DWARF expressions" { |
| 1033 | 1045 | defer mock_debug_addr.deinit(); |
| 1034 | 1046 | |
| 1035 | 1047 | try mock_debug_addr.writer().writeIntNative(u16, 0); |
| 1036 | | try mock_debug_addr.writer().writeIntNative(usize, expected[11]); |
| 1037 | | try mock_debug_addr.writer().writeIntNative(usize, expected[12]); |
| 1048 | try mock_debug_addr.writer().writeIntNative(usize, input[11]); |
| 1049 | try mock_debug_addr.writer().writeIntNative(usize, input[12]); |
| 1038 | 1050 | |
| 1039 | 1051 | const context = ExpressionContext{ |
| 1040 | 1052 | .compile_unit = &mock_compile_unit, |
| ... | ... | @@ -1054,26 +1066,311 @@ test "DWARF expressions" { |
| 1054 | 1066 | try testing.expectEqual(die_offset, const_type.type_offset); |
| 1055 | 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))); |
| 1058 | | try testing.expectEqual(@as(usize, expected[11]), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1059 | | try testing.expectEqual(@as(usize, expected[10]), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1060 | | try testing.expectEqual(@as(isize, @truncate(expected[9])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1061 | | try testing.expectEqual(@as(usize, @truncate(expected[8])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1062 | | try testing.expectEqual(@as(isize, @truncate(expected[7])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1063 | | try testing.expectEqual(@as(usize, @truncate(expected[6])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1064 | | try testing.expectEqual(@as(isize, @truncate(expected[5])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1065 | | try testing.expectEqual(@as(usize, @truncate(expected[4])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1066 | | try testing.expectEqual(@as(isize, @truncate(expected[3])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1067 | | try testing.expectEqual(@as(usize, @truncate(expected[2])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1068 | | try testing.expectEqual(@as(isize, @truncate(expected[1])), @as(isize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1069 | | try testing.expectEqual(@as(usize, @truncate(expected[0])), @as(usize, @bitCast(stack_machine.stack.popOrNull().?.generic))); |
| 1069 | const expected = .{ |
| 1070 | .{ usize, input[12], usize }, |
| 1071 | .{ usize, input[11], usize }, |
| 1072 | .{ usize, input[10], usize }, |
| 1073 | .{ isize, input[9], isize }, |
| 1074 | .{ usize, input[8], usize }, |
| 1075 | .{ isize, input[7], isize }, |
| 1076 | .{ usize, input[6], usize }, |
| 1077 | .{ isize, input[5], isize }, |
| 1078 | .{ usize, input[4], usize }, |
| 1079 | .{ isize, input[3], isize }, |
| 1080 | .{ usize, input[2], usize }, |
| 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 | 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 | 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 | } |