Here I list a bunch of things that can be done with Z-machine, not specific to any programming language (although some may only be possible in some programming languages).
Global variables overlapping the extension table
The global variable table can overlap the extension table, so that the mouse and joystick state can be accessed directly as variables.
Global variables overlapping the object table
If the object table is placed right after the global variables table, the first object header might fit in the global variables table. If the first object is the player, then you can read their location easily as a global variable.
You can make multiple objects sharing property tables if it would help. Such objects will then share their name and property values, although they will still have their individual locations and attributes.
It might help if the properties are read-only for those class of objects. An example might be if many rooms contain an identical magical portal all leading to the same location.
Truncated default property table
If you don't need 63 default properties, you can truncate the default property table to only the default properties you need. Number the properties that need defaults with the highest numbers, 63 and down. The header to specify where the object table is, it is then deducted the unused default properties so that the address of the default properties will be correct. (Frolg automatically does this.)
Very long object names
Object names have to be in core (which is limited to 64K) and are limited to 765 Z-characters. If you have very long names, you can make them fit by storing them in the fwords table. (The Z-machine port of Wry Humor does this.)