1
/* $Header: d:/cvsroot/tads/tads3/VMTYPE.H,v 1.3 1999/05/17 02:52:29 MJRoberts Exp $ */
4
* Copyright (c) 1998, 2002 Michael J. Roberts. All Rights Reserved.
6
* Please see the accompanying license file, LICENSE.TXT, for information
7
* on using and copying this software.
17
10/21/98 MJRoberts - Creation
33
* Constant pool/code offset. This is an address of an object in the
34
* pool. Pool offsets are 32-bit values.
36
typedef uint32 pool_ofs_t;
39
* Savepoint ID's are stored in a single byte; since we store many
40
* copies of savepoint ID's (since they need to be stored with each undo
41
* list head), we want to save some space on this type. This limits us
42
* to 256 simultaneous savepoints, but this should be more than we
43
* actually want to keep around anyway, because of the amount of memory
44
* it would consume to try to keep more than that around.
46
typedef uchar vm_savept_t;
47
const vm_savept_t VM_SAVEPT_MAX = 255;
50
* Object ID type. VM_INVALID_OBJ is a distinguished value that serves
51
* as an invalid object ID (a null pointer, effectively); no object can
54
typedef uint32 vm_obj_id_t;
55
const vm_obj_id_t VM_INVALID_OBJ = 0;
58
* Property ID. Property ID's are 16-bit values. VM_INVALID_PROP is a
59
* distinguished value that serves as an invalid property ID, which can
60
* be used to indicate the absence of a property value.
62
typedef uint16 vm_prop_id_t;
63
const vm_prop_id_t VM_INVALID_PROP = 0;
66
* Maximum recursion depth for recursive equality tests and hash
69
* When we're comparing or hashing a tree of references by value, such as
70
* when we're comparing two vectors or hashing a vector, we'll keep track
71
* of the recursion depth of our tree traversal. If we reach this depth,
72
* we'll throw an error on the assumption that the tree contains cycles and
73
* thus cannot be hashed or compared by value. This depth is chosen to be
74
* large enough that it's unlikely we'll exceed it with acyclical trees,
75
* but small enough that we probably won't blow the C++ stack before we
78
const int VM_MAX_TREE_DEPTH_EQ = 256;
85
/* nil - doubles as a null pointer and a boolean false */
88
/* true - boolean true */
92
* Stack pointer (this is used to store a pointer to the enclosing
93
* frame in a stack frame). This is a native machine pointer.
98
* Code pointer (this is used to store a pointer to the return
99
* address in a stack frame, for example). This is a native machine
100
* pointer. This differs from VM_CODEOFS in that this is a native
105
/* object reference */
111
/* 32-bit signed integer */
115
* string constant value - the value is an offset into the constant
116
* pool of the string descriptor
121
* self-printing string value - the value is an offset into the
122
* constant pool of the string descriptor
127
* list constant - the value is an offset into the constant pool of
128
* the list descriptor
133
* byte-code constant offset - this is an offset into the byte-code
134
* pool. This differs from VM_CODEPTR in that this is an offset in
135
* the byte-code constant pool rather than a native machine pointer.
141
* function pointer - this is represented as an offset into the
142
* byte-code pool. This differs from VM_CODEOFS in that the code
143
* referenced by a VM_CODEOFS value is generally invoked directly
144
* whenever the value is evaluated, whereas VM_FUNCPTR values are
145
* used to convey function pointers, so the underlying code is not
146
* executed implicitly on evaluation of such a value but must be
147
* explicitly invoked.
152
* This is a special pseudo-type used to indicate that a value is
153
* not present. This differs from nil, in that nil is a null
154
* reference or false value, whereas this indicates that there's no
155
* specified value at all. This is used, for example, to indicate
156
* in an undo record that a property did not previously exist.
161
* This is a special pseudo-type used to indicate that evaluating an
162
* expression requires executing system code. The value stored is a
163
* pointer to a constant CVmNativeCodeDesc object, which describes a
164
* native code method.
169
* Enumerated constant
174
* First invalid type ID. Tools (such as compilers and debuggers)
175
* can use this ID and any higher ID values to flag their own
178
VM_FIRST_INVALID_TYPE
181
/* macro to create a private type constant for internal use in a tool */
182
#define VM_MAKE_INTERNAL_TYPE(idx) \
183
((vm_datatype_t)(((int)VM_FIRST_INVALID_TYPE) + (idx)))
186
* Value container. Local variables, stack locations, and other value
187
* holders use this structure to store a value and its type.
194
/* stack/code pointer */
197
/* object reference */
206
/* enumerated constant */
209
/* sstring/dstring/list constant pool offset/pcode pool offset */
212
/* native code descriptor */
213
const class CVmNativeCodeDesc *native_desc;
216
/* set various types of values */
217
void set_empty() { typ = VM_EMPTY; }
218
void set_nil() { typ = VM_NIL; }
219
void set_true() { typ = VM_TRUE; }
220
void set_stack(void *ptr) { typ = VM_STACK; val.ptr = ptr; }
221
void set_codeptr(void *ptr) { typ = VM_CODEPTR; val.ptr = ptr; }
222
void set_obj(vm_obj_id_t obj) { typ = VM_OBJ; val.obj = obj; }
223
void set_nil_obj() { typ = VM_NIL; val.obj = VM_INVALID_OBJ; }
224
void set_propid(vm_prop_id_t prop) { typ = VM_PROP; val.prop = prop; }
225
void set_int(int32 intval) { typ = VM_INT; val.intval = intval; }
226
void set_enum(uint32 enumval) { typ = VM_ENUM; val.enumval = enumval; }
227
void set_sstring(pool_ofs_t ofs) { typ = VM_SSTRING; val.ofs = ofs; }
228
void set_dstring(pool_ofs_t ofs) { typ = VM_DSTRING; val.ofs = ofs; }
229
void set_list(pool_ofs_t ofs) { typ = VM_LIST; val.ofs = ofs; }
230
void set_codeofs(pool_ofs_t ofs) { typ = VM_CODEOFS; val.ofs = ofs; }
231
void set_fnptr(pool_ofs_t ofs) { typ = VM_FUNCPTR; val.ofs = ofs; }
232
void set_native(const class CVmNativeCodeDesc *desc)
233
{ typ = VM_NATIVE_CODE; val.native_desc = desc; }
236
* set an object or nil value: if the object ID is VM_INVALID_OBJ,
237
* we'll set the type to nil
239
void set_obj_or_nil(vm_obj_id_t obj)
241
/* set the object value initially */
245
/* if the object is invalid, set the type to nil */
246
if (obj == VM_INVALID_OBJ)
250
/* set to an integer giving the datatype of the given value */
251
void set_datatype(VMG_ const vm_val_t *val);
253
/* set to nil if 'val' is zero, true if 'val' is non-zero */
254
void set_logical(int v) { typ = (v != 0 ? VM_TRUE : VM_NIL); }
256
/* determine if the value is logical (nil or true) */
257
int is_logical() const { return (typ == VM_NIL || typ == VM_TRUE); }
260
* Get a logical as numeric TRUE or FALSE. This does not perform
261
* any type checking; the caller must ensure that the value is
262
* either true or nil, or this may return meaningless results.
264
int get_logical() const { return (typ == VM_TRUE); }
267
* Get the underlying string constant value. If the value does not
268
* have an underlying string constant (because it is of a type that
269
* does not store a string value), this will return null.
271
const char *get_as_string(VMG0_) const;
274
* Get the underlying list constant value. If the value does not
275
* have an underlying list constant (because it is of a type that
276
* does not store list data), this returns null.
278
const char *get_as_list(VMG0_) const;
281
* Get the effective number of elements from this value when the
282
* value is used as the right-hand side of a '+' or '-' operator
283
* whose left-hand side implies that the operation involved is a set
284
* operation (this is the case is the left-hand side is of certain
285
* collection types, such as list, array, or vector); and get the
286
* nth element in that context. Most types of values contribute
287
* only one element to these operations, but some collection types
288
* supply their elements individually, rather than the collection
289
* itself, for these operations. 'idx' is the 1-based index of the
290
* element to retrieve.
292
size_t get_coll_addsub_rhs_ele_cnt(VMG0_) const;
293
void get_coll_addsub_rhs_ele(VMG_ size_t idx, vm_val_t *result) const;
296
* Convert a numeric value to an integer value. If the value isn't
297
* numeric, throws an error.
299
void num_to_logical()
304
/* it's an integer - treat 0 as nil, all else as true */
305
typ = (val.intval == 0 ? VM_NIL : VM_TRUE);
309
/* it's not a number - throw an error */
310
err_throw(VMERR_NO_LOG_CONV);
314
/* determine if the value is some kind of number */
315
int is_numeric() const { return (typ == VM_INT); }
318
* Convert a numeric value to an integer. If the value is not
319
* numeric, we'll throw an error.
321
int32 num_to_int() const
326
/* it's an integer already - return the value directly */
332
* other types are not numeric and can't be directly
333
* converted to integer by arithmetic conversion
335
err_throw(VMERR_NUM_VAL_REQD);
337
/* the compiler might not know we'll never get here */
338
AFTER_ERR_THROW(return 0;)
343
* determine if the numeric value is zero; throws an error if the
344
* value is not numeric
346
int num_is_zero() const
351
/* check the integer value to see if it's zero */
352
return (val.intval == 0);
356
/* it's not a number */
357
err_throw(VMERR_NUM_VAL_REQD);
359
/* in case the compiler doesn't know we'll never get here */
360
AFTER_ERR_THROW(return 0;)
365
* Determine if this value equals a given value. The nature of the
366
* match depends on the type of this value:
368
* integers, property ID's, code offsets: the types and values must
371
* string and list constants: the other value must either be the same
372
* type of constant, or an object that has an underlying value of the
373
* same type; and the contents of the strings or lists must match.
375
* objects: the match depends on the type of the object. We invoke the
376
* object's virtual equals() routine to make this determination.
378
* 'depth' has the same meaning as in calc_hash().
380
int equals(VMG_ const vm_val_t *v) const { return equals(vmg_ v, 0); }
381
int equals(VMG_ const vm_val_t *val, int depth) const;
384
* Calculate a hash for the value. The meaning of the hash varies by
385
* type, but is stable for a given value. 'depth' is a recursion depth
386
* counter, with the same meaning as in CVmObject::calc_hash().
388
uint calc_hash(VMG0_) const { return calc_hash(vmg_ 0); }
389
uint calc_hash(VMG_ int depth) const;
392
* Compare this value to the given value. Returns a value greater than
393
* zero if this value is greater than 'val', a value less than zero if
394
* this value is less than 'val', or 0 if the two values are equal.
395
* Throws an error if the two values are not comparable.
397
* By far the most common type of comparison is between integers, so we
398
* test in-line to see if we have two integer values, and if so, use a
399
* fast in-line comparison. If we don't have two integers, we'll use
400
* our full out-of-line test, which will look at other more interesting
403
int compare_to(VMG_ const vm_val_t *b) const
405
if (typ == VM_INT && b->typ == VM_INT)
406
return (val.intval > b->val.intval
407
? 1 : val.intval < b->val.intval ? -1 : 0);
409
return gen_compare_to(vmg_ b);
413
* relative value comparisons
417
int is_gt(VMG_ const vm_val_t *b) const
419
if (typ == VM_INT && b->typ == VM_INT)
420
return val.intval > b->val.intval;
422
return gen_compare_to(vmg_ b) > 0;
426
int is_ge(VMG_ const vm_val_t *b) const
428
if (typ == VM_INT && b->typ == VM_INT)
429
return val.intval >= b->val.intval;
431
return gen_compare_to(vmg_ b) >= 0;
435
int is_lt(VMG_ const vm_val_t *b) const
437
if (typ == VM_INT && b->typ == VM_INT)
438
return val.intval < b->val.intval;
440
return gen_compare_to(vmg_ b) < 0;
444
int is_le(VMG_ const vm_val_t *b) const
446
if (typ == VM_INT && b->typ == VM_INT)
447
return val.intval <= b->val.intval;
449
return gen_compare_to(vmg_ b) <= 0;
453
/* out-of-line comparison, used when we don't have two integers */
454
int gen_compare_to(VMG_ const vm_val_t *val) const;
457
/* ------------------------------------------------------------------------ */
459
* Native code descriptor. This describes a native method call of an
460
* intrinsic class object.
462
class CVmNativeCodeDesc
465
/* create a descriptor with an exact number of arguments */
466
CVmNativeCodeDesc(int argc)
468
/* remember the parameters - there are no optional arguments */
474
/* create a descriptor with optional arguments (but not varargs) */
475
CVmNativeCodeDesc(int min_argc, int opt_argc)
477
/* remember the parameters */
478
min_argc_ = min_argc;
479
opt_argc_ = opt_argc;
483
/* create a descriptor with optional arguments and/or varargs */
484
CVmNativeCodeDesc(int min_argc, int opt_argc, int varargs)
486
/* remember the parameters */
487
min_argc_ = min_argc;
488
opt_argc_ = opt_argc;
492
/* check the given number of arguments for validity */
493
int args_ok(int argc) const
496
* the actual parameters must number at least the minimum, and
497
* cannot exceed the maximum (i.e., the minimum plus the
498
* optionals) unless we have varargs, in which case there is no
501
return (argc >= min_argc_
502
&& (varargs_ || argc <= min_argc_ + opt_argc_));
505
/* minimum argument count */
508
/* number of optional named arguments beyond the minimum */
512
* true -> varargs: any number of arguments greater than or equal to
513
* min_argc_ are valid
518
/* ------------------------------------------------------------------------ */
520
* String handling - these routines are provided as covers to allow for
521
* easier adjustment for Unicode or other encodings. Don't include these
522
* if we're compiling interface routines for the HTML TADS environment,
523
* since HTML TADS has its own similar definitions for these, and we don't
524
* need these for interface code.
526
* NOTE: The purpose of this macro is to indicate that we're being
527
* #included by an HTML TADS source file - that is, the current compile run
528
* is for an htmltads/xxx.cpp file. Do NOT #define this macro when
529
* compiling tads3/xxx.cpp files. The tads3/xxx.cpp files have absolutely
530
* no explicit dependencies on the htmltads subsystem and thus don't
531
* #include the htmltads headers that would provide the conflicting
532
* interface definitions for these functions. The conflict is in the other
533
* direction: some of the htmltads source files explicitly depend on tads3
534
* headers, so they indirectly #include this header. So, this macro needs
535
* to be defined only when compiling htmltads/xxx.cpp files.
537
#ifdef T3_COMPILING_FOR_HTML
538
#include "tadshtml.h"
541
inline size_t get_strlen(const textchar_t *str) { return strlen(str); }
542
inline void do_strcpy(textchar_t *dst, const textchar_t *src)
543
{ strcpy(dst, src); }
545
#endif /* T3_COMPILING_FOR_HTML */
547
/* ------------------------------------------------------------------------ */
549
* Portable Binary Representations. When we store certain types of
550
* information in memory, we store it in a format that is identical to
551
* the format we use in portable binary files; using this format allows
552
* us to read and write binary files as byte images, without any
553
* interpretation, which greatly improves I/O performance in many cases.
557
* Portable binary LENGTH indicator. This is used to store length
558
* prefixes for strings, lists, and similar objects. We use a UINT2
559
* (16-bit unsigned integer) for this type of value.
561
const size_t VMB_LEN = 2;
562
inline void vmb_put_len(char *buf, size_t len) { oswp2(buf, len); }
563
inline size_t vmb_get_len(const char *buf) { return osrp2(buf); }
566
* Portable binary unsigned 2-byte integer
568
const size_t VMB_UINT2 = 2;
569
inline void vmb_put_uint2(char *buf, uint16 i) { oswp2(buf, i); }
570
inline uint16 vmb_get_uint2(const char *buf) { return osrp2(buf); }
573
* Portable binary object ID.
575
const size_t VMB_OBJECT_ID = 4;
576
inline void vmb_put_objid(char *buf, vm_obj_id_t obj) { oswp4(buf, obj); }
577
inline vm_obj_id_t vmb_get_objid(const char *buf) { return t3rp4u(buf); }
580
* Portable binary property ID
582
const size_t VMB_PROP_ID = 2;
583
inline void vmb_put_propid(char *buf, vm_obj_id_t prop) { oswp2(buf, prop); }
584
inline vm_prop_id_t vmb_get_propid(const char *buf) { return osrp2(buf); }
587
* Portable data holder. This is used to store varying-type data items;
588
* for example, this is used to store an element in a list, or the value
589
* of a property in an object. This type of value stores a one-byte
590
* prefix indicating the type of the value, and a four-byte area in
591
* which the value is stored. The actual use of the four-byte value
592
* area depends on the type.
594
const size_t VMB_DATAHOLDER = 5;
596
/* offset from a portable data holder pointer to the data value */
597
const size_t VMB_DH_DATAOFS = 1;
599
/* store a portable dataholder from a vm_val_t */
600
void vmb_put_dh(char *buf, const vm_val_t *val);
602
/* store a nil value in a portable dataholder */
603
inline void vmb_put_dh_nil(char *buf) { buf[0] = VM_NIL; }
605
/* store an object value in a portable dataholder */
606
inline void vmb_put_dh_obj(char *buf, vm_obj_id_t obj)
607
{ buf[0] = VM_OBJ; vmb_put_objid(buf + 1, obj); }
609
/* store a property value in a portable dataholder */
610
inline void vmb_put_dh_prop(char *buf, vm_prop_id_t prop)
611
{ buf[0] = VM_PROP; vmb_put_propid(buf + 1, prop); }
613
/* get the value portion of a vm_val_t from a portable dataholder */
614
void vmb_get_dh_val(const char *buf, vm_val_t *val);
616
/* get the type from a portable dataholder */
617
inline vm_datatype_t vmb_get_dh_type(const char *buf)
618
{ return (vm_datatype_t)buf[0]; }
620
/* get a vm_val_t from a portable dataholder */
621
inline void vmb_get_dh(const char *buf, vm_val_t *val)
622
{ val->typ = vmb_get_dh_type(buf); vmb_get_dh_val(buf, val); }
624
/* get an object value from a portable dataholder */
625
inline vm_obj_id_t vmb_get_dh_obj(const char *buf)
626
{ return (vm_obj_id_t)t3rp4u(buf+1); }
628
/* get an integer value from a portable dataholder */
629
inline int32 vmb_get_dh_int(const char *buf)
630
{ return (int32)osrp4(buf+1); }
632
/* get a property ID value from a portable dataholder */
633
inline vm_prop_id_t vmb_get_dh_prop(const char *buf)
634
{ return (vm_prop_id_t)osrp2(buf+1); }
636
/* get a constant offset value from a portable dataholder */
637
inline pool_ofs_t vmb_get_dh_ofs(const char *buf)
638
{ return (pool_ofs_t)t3rp4u(buf+1); }
641
#endif /* VMTYPE_H */