#include "../tdkpin_dispatch.h" #include #include static jmp_buf g_error_jump; static uint16_t g_error_code; static Win16FarPtr g_dispatched_procedure; static Win16FarPtr g_receiver; static Win16FarPtr g_argument; _Noreturn void borland_runtime_error(uint16_t code) { g_error_code = code; longjmp(g_error_jump, 1); } void win16_call_dynamic_method(Win16FarPtr procedure) { g_dispatched_procedure = procedure; } void win16_call_dynamic_method_two_far( Win16FarPtr procedure, Win16FarPtr receiver, Win16FarPtr argument) { g_dispatched_procedure = procedure; g_receiver = receiver; g_argument = argument; } static void write_far(uint16_t offset, Win16FarPtr pointer) { win16_write_u16( win16_dgroup_pointer(offset), 0, win16_far_offset(pointer)); win16_write_u16( win16_dgroup_pointer((uint16_t)(offset + 2)), 0, win16_far_selector(pointer)); } int main(void) { static uint8_t dgroup[0x1000]; static uint8_t object[32]; win16_reset_segment_bindings(); win16_bind_segment(0x5000, dgroup, sizeof(dgroup), true); win16_set_dgroup_selector(0x5000); win16_bind_segment(0x6000, object, sizeof(object), true); /* VMT 0x0100 -> derived dynamic table 0x0200. */ win16_write_u16(win16_dgroup_pointer(0x0104), 0, 0x0200); win16_write_u16(win16_dgroup_pointer(0x0200), 0, 0x0300); win16_write_u16(win16_dgroup_pointer(0x0202), 0, 0xffff); win16_write_u16(win16_dgroup_pointer(0x0204), 0, 0xffff); win16_write_u16(win16_dgroup_pointer(0x0206), 0, 2); win16_write_u16(win16_dgroup_pointer(0x0208), 0, 10); win16_write_u16(win16_dgroup_pointer(0x020a), 0, 20); write_far(0x020c, win16_make_far_pointer(0x7000, 0x1111)); write_far(0x0210, win16_make_far_pointer(0x7000, 0x2222)); win16_write_u16(win16_dgroup_pointer(0x0300), 0, 0); win16_write_u16(win16_dgroup_pointer(0x0302), 0, 0xffff); win16_write_u16(win16_dgroup_pointer(0x0304), 0, 0xffff); win16_write_u16(win16_dgroup_pointer(0x0306), 0, 1); win16_write_u16(win16_dgroup_pointer(0x0308), 0, 30); write_far(0x030a, win16_make_far_pointer(0x7100, 0x3333)); Win16FarPtr slot = borland_resolve_dynamic_method_slot(0x0100, 20); assert(slot == win16_dgroup_pointer(0x0210)); assert(win16_read_u16(win16_dgroup_pointer(0x0202)) == 20); assert(win16_read_u16(win16_dgroup_pointer(0x0204)) == 0x0210); /* The cache bypasses the now-corrupted method-count word. */ win16_write_u16(win16_dgroup_pointer(0x0206), 0, 0xffff); assert(borland_find_dynamic_method(0x0100, 20) == slot); win16_write_u16(win16_dgroup_pointer(0x0206), 0, 2); slot = borland_resolve_dynamic_method_slot(0x0100, 30); assert(slot == win16_dgroup_pointer(0x030a)); assert(win16_read_u16(win16_dgroup_pointer(0x0302)) == 30); assert(win16_read_u16(win16_dgroup_pointer(0x0304)) == 0x030a); g_dispatched_procedure = 0; borland_dispatch_dynamic_method(0x0100, 10); assert(g_dispatched_procedure == win16_make_far_pointer(0x7000, 0x1111)); /* Generated callers use the receiver VMT and preserve both far args. */ win16_write_u16(win16_dgroup_pointer(0x0404), 0, 0x0500); win16_write_u16(win16_dgroup_pointer(0x0500), 0, 0); win16_write_u16(win16_dgroup_pointer(0x0502), 0, 0xffff); win16_write_u16(win16_dgroup_pointer(0x0504), 0, 0xffff); win16_write_u16(win16_dgroup_pointer(0x0506), 0, 2); win16_write_u16(win16_dgroup_pointer(0x0508), 0, 0x8002); win16_write_u16(win16_dgroup_pointer(0x050a), 0, 0x0006); write_far(0x050c, win16_make_far_pointer(0x7200, 0x4444)); write_far(0x0510, win16_make_far_pointer(0x7300, 0x5555)); Win16FarPtr receiver = win16_make_far_pointer(0x6000, 4); Win16FarPtr argument = win16_make_far_pointer(0x6100, 0x1234); win16_write_u16(receiver, 0, 0x0400); borland_dispatch_method_8002(receiver, argument); assert(g_dispatched_procedure == win16_make_far_pointer(0x7200, 0x4444)); assert(g_receiver == receiver && g_argument == argument); borland_dispatch_method_0006(receiver, argument); assert(g_dispatched_procedure == win16_make_far_pointer(0x7300, 0x5555)); assert(g_receiver == receiver && g_argument == argument); if (setjmp(g_error_jump) == 0) { (void)borland_resolve_dynamic_method_slot(0x0100, 99); assert(false); } assert(g_error_code == 210); return 0; }