/* Borland Pascal object construction and destruction protocol. */ #include "tdkpin_borland_objects.h" /* * 1020:03ef — constructor entry helper. * * The VMT is a near DGROUP pointer. Its first word is the instance size, and * DI in the register ABI supplies the offset of the object's VMT field. For an * already allocated object the helper clears the caller's hidden VMT argument; * compiler-generated failure cleanup uses that mutation to avoid freeing an * object which it did not allocate. */ bool borland_enter_object_constructor( BorlandObjectCallFrame *frame, uint16_t vmt_field_offset) { uint16_t vmt = frame->vmt_argument; if (vmt == 0) { return true; } if (frame->object != 0) { frame->vmt_argument = 0; } else { uint16_t object_size = win16_read_u16(win16_dgroup_pointer(vmt)); BorlandAllocationAttempt allocation = borland_try_get_mem(object_size); if (allocation.failed) { borland_runtime_error(203); } if (allocation.block == 0) { return false; } frame->object = allocation.block; } win16_write_u16( frame->object, vmt_field_offset, vmt); return true; } /* * 1020:0439 — destructor exit helper. A nonzero hidden VMT argument says that * this destructor invocation owns the allocation. The size is recovered from * the VMT currently installed in the object, then the caller's object pointer * is cleared after a successful release. */ void borland_finish_object_destructor( BorlandObjectCallFrame *frame, uint16_t vmt_field_offset) { if (frame->vmt_argument == 0) { return; } uint16_t vmt = win16_read_u16(win16_far_add_offset( frame->object, vmt_field_offset)); uint16_t object_size = win16_read_u16(win16_dgroup_pointer(vmt)); if (borland_try_free_mem(frame->object, object_size)) { borland_runtime_error(204); } frame->object = 0; } /* 1008:2d99 — the root object's constructor has its VMT field at offset zero. */ Win16FarPtr borland_default_object_constructor( Win16FarPtr object, uint16_t vmt) { BorlandObjectCallFrame frame = {object, vmt}; borland_enter_object_constructor(&frame, 0); return frame.object; } /* 1008:2dcd — root destructor cleanup with the VMT field at offset zero. */ void borland_default_object_destructor(Win16FarPtr object, uint16_t vmt) { BorlandObjectCallFrame frame = {object, vmt}; borland_finish_object_destructor(&frame, 0); } /* * 1008:2db3 — Pascal Dispose: call VMT slot +8 with hidden dispose mode 1. * The virtual destructor itself ultimately reaches 1020:0439 and frees the * allocation according to the VMT size. */ void borland_dispose_object(Win16FarPtr object) { uint16_t vmt = win16_read_u16(object); Win16FarPtr destructor = win16_read_far_pointer(win16_dgroup_pointer(vmt), 8); win16_call_object_destructor(destructor, object, 1); } /* 1008:2d87 — Borland's abstract virtual-method trap. */ _Noreturn void borland_abstract_method_error(void) { borland_runtime_error(211); } /* 1018:0d8a — ObjectWindows abstract slot forwarding to the Borland trap. */ _Noreturn void object_windows_abstract_method(void) { borland_abstract_method_error(); }