2 * Internal definitions for the JavaScript interpreter.
3 * Copyright (c) 1998-1999 New Generation Software (NGS) Oy
5 * Author: Markku Rossi <mtr@ngs.fi>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/include/jsint.h,v $
33 /* We have always jsconfig.h */
38 /* #include <setjmp.h> */
39 /* #include <math.h> */
53 #else /* not STDC_HEADERS */
71 #endif /* not STDC_HEADERS */
73 /* Misc system headers. */
75 #include <sys/types.h>
78 * Protability kludges. If something is missing from the w32
79 * environment, please edit the micros/w32.{c,h} files and implement
84 /* Directory handling. */
87 #endif /* not WIN32 */
96 * Types and definitions.
99 /* Some portability features. */
102 #define JS_HOST_LINE_BREAK "\r\n"
103 #define JS_HOST_LINE_BREAK_LEN 2
105 #else /* not WIN32 */
107 #define JS_HOST_LINE_BREAK "\n"
108 #define JS_HOST_LINE_BREAK_LEN 1
110 #endif /* not WIN32 */
113 #define JS_BC_FILE_MAGIC 0xc0014a53
115 #define JS_GLOBAL_NAME ".global"
117 #define JS_SYMBOL_NULL ((JSSymbol) -1)
119 #define JS_IS_STR_WHITE_SPACE_CHAR(ch) \
120 ((ch) == '\t' || (ch) == ' ' || (ch) == '\f' || (ch) == '\v' \
121 || (ch) == '\r' || (ch) == '\n')
124 * Read macros for byte code files.
127 #define JS_BC_READ_INT32(cp, var) \
136 #define JS_BC_READ_INT16(cp, var) \
141 #define JS_BC_READ_INT8(cp, var) \
144 #define JS_BC_WRITE_INT32(cp, var) \
145 cp[3] = (unsigned char) ((var) & 0x000000ff); \
146 cp[2] = (unsigned char) (((var) >> 8) & 0x000000ff); \
147 cp[1] = (unsigned char) (((var) >> 16) & 0x000000ff); \
148 cp[0] = (unsigned char) (((var) >> 24) & 0x000000ff)
151 /* General VM macros. */
156 #define JS_SP1 (sp + 1)
157 #define JS_SP2 (sp + 2)
158 #define JS_SP(n) (sp + (n))
160 #define JS_LOCAL(n) (fp - 4 - (n))
161 #define JS_ARG(n) (fp + 1 + (n))
163 #define JS_WITHPTR (fp - 2)
164 #define JS_ARGS_FIXP (fp - 1)
166 #define JS_PUSH() sp--
167 #define JS_POP() sp++
168 #define JS_POP_N(n) sp += (n)
170 #define JS_COPY(to, from) \
172 (to)->type = (from)->type; \
173 (to)->u.copy.a = (from)->u.copy.a; \
174 (to)->u.copy.b = (from)->u.copy.b; \
177 #define JS_CONST(n) (&vm->consts[(n)])
178 #define JS_GLOBAL(n) (&vm->globals[(n)])
180 #define JS_SAVE_REGS() \
186 #define JS_CALL_HOOK(event) \
191 if ((hook_result = (*vm->hook) ((event), vm->hook_context)) != 0) \
194 sprintf (vm->error, "hook break %d", hook_result); \
200 #define JS_VM_ALLOCATE_FD(vm, where) \
202 if ((vm)->fd_count == 0) \
204 sprintf ((vm)->error, "%s: no more file descriptors allowed", \
211 #define JS_VM_FREE_FD(vm) \
216 #define JS_MAYBE_GC() \
218 if (vm->gc.bytes_allocated >= vm->gc.trigger) \
220 js_vm_garbage_collect (vm, fp, sp); \
221 JS_CALL_HOOK (JS_VM_EVENT_GARBAGE_COLLECT); \
225 #define JS_IS_TRUE(n) ((n)->type > JS_INTEGER \
226 || ((n)->type == JS_BOOLEAN && (n)->u.vboolean) \
227 || ((n)->type == JS_INTEGER && (n)->u.vinteger))
229 #define JS_IS_FALSE(n) ((n)->type < JS_BOOLEAN \
230 || ((n)->type == JS_BOOLEAN && !(n)->u.vboolean) \
231 || ((n)->type == JS_INTEGER && !(n)->u.vinteger))
233 #define JS_RESERVE_STACK_FOR_FUNCTION 10
235 #define JS_SUBROUTINE_CALL(function) \
237 /* Check that we have enought space in the stack. */ \
238 if (sp - JS_RESERVE_STACK_FOR_FUNCTION < vm->stack) \
239 ERROR ("stack overflow"); \
243 /* Save frame pointer. */ \
244 JS_SP0->type = JS_IPTR; \
245 JS_SP0->u.iptr = fp; \
251 /* Insert an empty args_fix. */ \
252 JS_SP0->type = JS_ARGS_FIX; \
253 JS_SP0->u.args_fix.argc = 0; \
254 JS_SP0->u.args_fix.delta = 0; \
257 /* Insert empty with pointer. */ \
258 JS_SP0->type = JS_IPTR; \
259 JS_SP0->u.iptr = NULL; \
262 /* Save return address. */ \
263 JS_SP0->type = JS_IPTR; \
264 JS_SP0->u.iptr = pc; \
267 /* And finally, jump to the method code. */ \
268 CALL_USER_FUNC ((function)); \
271 #define JS_OPERAND_CMP_REL(_OP_) \
273 if (JS_SP2->type == JS_STRING && JS_SP1->type == JS_STRING) \
276 = js_compare_strings (JS_SP2, JS_SP1) _OP_ 0; \
277 JS_SP2->type = JS_BOOLEAN; \
280 else if (JS_SP2->type == JS_INTEGER && JS_SP1->type == JS_INTEGER) \
283 = JS_SP2->u.vinteger _OP_ JS_SP1->u.vinteger; \
284 JS_SP2->type = JS_BOOLEAN; \
291 /* Do it the hard way. */ \
292 switch (JS_SP2->type) \
297 JS_COPY (&l, JS_SP2); \
301 js_vm_to_number (vm, JS_SP2, &l); \
305 switch (JS_SP1->type) \
310 JS_COPY (&r, JS_SP1); \
314 js_vm_to_number (vm, JS_SP1, &r); \
318 /* Do the comparison. */ \
321 if (l.type == JS_NAN || r.type == JS_NAN) \
322 JS_SP1->type = JS_UNDEFINED; \
323 else if (l.type == JS_INTEGER && r.type == JS_INTEGER) \
325 JS_SP1->type = JS_BOOLEAN; \
326 JS_SP1->u.vboolean = l.u.vinteger _OP_ r.u.vinteger; \
332 if (l.type == JS_FLOAT) \
335 ld = (double) l.u.vinteger; \
337 if (r.type == JS_FLOAT) \
340 rd = (double) r.u.vinteger; \
342 JS_SP1->type = JS_BOOLEAN; \
343 JS_SP1->u.vboolean = ld _OP_ rd; \
348 #define JS_OPERAND_CMP_EQ(_OP_, _VAL_) \
351 if (JS_SP2->type == JS_SP1->type) \
353 /* Comparsion between same types. */ \
354 switch (JS_SP2->type) \
357 res = JS_SP2->u.vinteger _OP_ JS_SP1->u.vinteger; \
361 res = js_compare_strings (JS_SP2, JS_SP1) _OP_ 0; \
365 res = JS_SP2->u.vfloat _OP_ JS_SP1->u.vfloat; \
369 /* 11.9.3: cases 5 and 6 */ \
374 res = JS_SP2->u.vboolean _OP_ JS_SP1->u.vboolean; \
378 res = JS_SP2->u.vobject _OP_ JS_SP1->u.vobject; \
382 res = ((JS_SP2->u.vbuiltin->info \
383 == JS_SP1->u.vbuiltin->info \
384 && (JS_SP2->u.vbuiltin->instance_context \
385 == JS_SP1->u.vbuiltin->instance_context)) \
390 res = JS_SP2->u.vfunction _OP_ JS_SP1->u.vfunction; \
394 res = JS_SP2->u.vsymbol _OP_ JS_SP1->u.vsymbol; \
398 res = JS_SP2->u.iptr _OP_ JS_SP1->u.iptr; \
408 /* Type conversions between different types. */ \
410 if ((JS_SP2->type == JS_UNDEFINED || JS_SP2->type == JS_NULL) \
411 && (JS_SP1->type == JS_UNDEFINED \
412 || JS_SP1->type == JS_NULL)) \
416 else if (JS_IS_NUMBER (JS_SP2) && JS_IS_NUMBER (JS_SP1)) \
418 if (JS_SP2->type == JS_NAN || JS_SP1->type == JS_NAN) \
419 /* 11.9.3: cases 5 and 6 */ \
421 else if (JS_SP2->type == JS_INTEGER) \
422 /* Integer-integer was already handled. */ \
423 res = (double) JS_SP2->u.vinteger _OP_ JS_SP1->u.vfloat; \
425 /* Integer-integer was already handled. */ \
426 res = JS_SP2->u.vfloat _OP_ (double) JS_SP1->u.vinteger; \
432 /* Must perform type casts. */ \
434 if ((JS_SP2->type == JS_STRING || JS_SP2->type == JS_BOOLEAN \
435 || JS_IS_NUMBER (JS_SP2)) \
436 && (JS_SP1->type == JS_STRING \
437 || JS_SP1->type == JS_BOOLEAN \
438 || JS_IS_NUMBER (JS_SP1))) \
440 js_vm_to_number (vm, JS_SP2, &l); \
441 js_vm_to_number (vm, JS_SP1, &r); \
443 if (l.type == JS_NAN || r.type == JS_NAN) \
445 else if (l.type == JS_INTEGER) \
447 if (r.type == JS_INTEGER) \
448 res = l.u.vinteger _OP_ r.u.vinteger; \
450 res = (double) l.u.vinteger _OP_ r.u.vfloat; \
454 if (r.type == JS_INTEGER) \
455 res = l.u.vfloat _OP_ (double) r.u.vinteger; \
457 res = l.u.vfloat _OP_ r.u.vfloat; \
460 else if (JS_SP2->type == JS_OBJECT \
461 && (JS_SP1->type == JS_STRING \
462 || JS_IS_NUMBER (JS_SP1))) \
466 /* ECMA 11.9.3 21. No preferred type specified. */ \
467 js_vm_to_primitive (vm, JS_SP2, &cvt, JS_UNDEFINED); \
468 JS_COPY (JS_SP2, &cvt); \
471 else if (JS_SP1->type == JS_OBJECT \
472 && (JS_SP2->type == JS_STRING \
473 || JS_IS_NUMBER (JS_SP2))) \
477 /* ECMA 11.9.3 20. No preferred type specified. */ \
478 js_vm_to_primitive (vm, JS_SP1, &cvt, JS_UNDEFINED); \
479 JS_COPY (JS_SP1, &cvt); \
487 JS_SP2->type = JS_BOOLEAN; \
488 JS_SP2->u.vboolean = res; \
493 #define JS_OPERAND_CMP_SEQ(_OP_, _VAL_) \
496 if (JS_SP2->type == JS_SP1->type) \
498 switch (JS_SP2->type) \
501 res = JS_SP2->u.vinteger _OP_ JS_SP1->u.vinteger; \
505 res = JS_SP2->u.vfloat _OP_ JS_SP1->u.vfloat; \
509 /* 11.9.6: cases 3 and 4 */ \
514 res = js_compare_strings (JS_SP2, JS_SP1) _OP_ 0; \
518 res = JS_SP2->u.vboolean _OP_ JS_SP1->u.vboolean; \
522 res = JS_SP2->u.vobject _OP_ JS_SP1->u.vobject; \
526 res = ((JS_SP2->u.vbuiltin->info \
527 == JS_SP1->u.vbuiltin->info \
528 && (JS_SP2->u.vbuiltin->instance_context \
529 == JS_SP1->u.vbuiltin->instance_context)) \
534 res = JS_SP2->u.vfunction _OP_ JS_SP1->u.vfunction; \
538 /* 11.9.6: case 12 */ \
545 /* Only numbers are allowed here. */ \
546 if (JS_IS_NUMBER (JS_SP2) && JS_IS_NUMBER (JS_SP1)) \
548 if (JS_SP2->type == JS_NAN || JS_SP1->type == JS_NAN) \
549 /* 11.9.6: cases 3 and 4 */ \
551 else if (JS_SP2->type == JS_INTEGER) \
552 res = (double) JS_SP2->u.vinteger _OP_ JS_SP1->u.vfloat; \
554 res = JS_SP2->u.vfloat _OP_ (double) JS_SP1->u.vinteger; \
560 JS_SP2->type = JS_BOOLEAN; \
561 JS_SP2->u.vboolean = res; \
566 #define JS_OPERAND_BINARY(_OP_) \
568 if (JS_SP2->type == JS_INTEGER && JS_SP1->type == JS_INTEGER) \
570 JS_SP2->u.vinteger = ((JSInt32) JS_SP2->u.vinteger \
571 _OP_ (JSInt32) JS_SP1->u.vinteger); \
578 l = js_vm_to_int32 (vm, JS_SP2); \
579 r = js_vm_to_int32 (vm, JS_SP1); \
581 JS_SP2->u.vinteger = (l _OP_ r); \
582 JS_SP2->type = JS_INTEGER; \
588 #define JS_IS_NUMBER(n) \
589 ((n)->type == JS_INTEGER || (n)->type == JS_FLOAT || (n)->type == JS_NAN)
591 /* Some math macros. */
593 #define JS_MAKE_POSITIVE_INFINITY(node) \
595 (node)->type = JS_FLOAT; \
596 (node)->u.vfloat = HUGE_VAL; \
599 #define JS_MAKE_NEGATIVE_INFINITY(node) \
601 (node)->type = JS_FLOAT; \
602 (node)->u.vfloat = -HUGE_VAL; \
605 #define JS_IS_POSITIVE_INFINITY(node) \
606 ((node)->type == JS_FLOAT && (node)->u.vfloat == HUGE_VAL)
608 #define JS_IS_NEGATIVE_INFINITY(node) \
609 ((node)->type == JS_FLOAT && (node)->u.vfloat == -HUGE_VAL)
611 #define JS_IS_FINITE(node) \
612 (!JS_IS_POSITIVE_INFINITY ((node)) \
613 && !JS_IS_NEGATIVE_INFINITY ((node)) \
614 && (node)->type != JS_NAN) \
616 #define JS_IS_PRIMITIVE_VALUE(node) \
617 ((node)->type == JS_UNDEFINED || (node)->type == JS_NULL \
618 || (node)->type == JS_BOOLEAN || JS_IS_NUMBER ((node)) \
619 || (node)->type == JS_STRING)
621 /* Macro to clear all flags from a heap memory block. */
622 #define JS_HEAP_MEMORY_BLOCK_CLEAR_FLAGS(mb) \
624 (mb)->flag_mark = 0; \
625 (mb)->flag_destroyable = 0; \
628 #define JS_NUM_HEAP_FREELISTS 20
631 * Virtual machine security flags. When these flags are enabled in
632 * the vm->security, the appropriate built-in modules don't implement
636 #define JS_VM_SECURE_FILE 0x01
637 #define JS_VM_SECURE_SYSTEM 0x02
640 * Noticeable virtual machine events. The `JS_VM_EVENT_OPERAND_COUNT'
641 * event is generated only if the interpreter was configured with the
642 * `--enable-operand-hooks' option.
645 #define JS_VM_EVENT_OPERAND_COUNT 1
646 #define JS_VM_EVENT_GARBAGE_COLLECT 2
652 typedef unsigned char JSUInt8
;
653 typedef signed char JSInt8
;
655 typedef unsigned short JSUInt16
;
656 typedef short JSInt16
;
660 typedef unsigned int JSUInt32
;
663 #else /* not SIZEOF_INT == 4 */
667 typedef unsigned long JSUInt32
;
668 typedef long JSInt32
;
670 #else /* not SIZEOF_LONG == 4 */
672 #error "do not know how to define a 32 bit long integer"
674 #endif /* not SIZEOF_LONG == 4 */
676 #endif /* not SIZEOF_INT == 4 */
679 * An unsigned interger number that can be used to align structures to
680 * correct byte boundaries. On 64 bit machines (Alpha) this should be
681 * 64 bits long, etc. For now one, we just assume that the mashine is
682 * a LP64 so the `unsigned long' is a correct type for it.
684 typedef unsigned long JSUIntAlign
;
688 /* Buffer filler or flusher function. */
689 typedef int (*JSIOStreamIOFunc
) (void *context
, unsigned char *buffer
,
690 unsigned int todo
, int *error_return
);
692 typedef int (*JSIOStreamSeek
) (void *context
, long offset
, int whence
);
694 typedef long (*JSIOStreamGetPosition
) (void *context
);
696 typedef long (*JSIOStreamGetLength
) (void *context
);
698 typedef void (*JSIOStreamClose
) (void *context
);
700 /* The I/O stream handle. */
701 struct js_io_stream_st
703 unsigned char *buffer
; /* Must be reallocatable with js_realloc(). */
705 unsigned int data_in_buf
;
709 unsigned int at_eof
: 1;
710 unsigned int autoflush
: 1;
711 unsigned int writep
: 1; /* Does the buffer contain write data? */
713 /* The system error code for the last operation that failed. */
716 /* Only one of the read and write is active. */
717 JSIOStreamIOFunc read
;
718 JSIOStreamIOFunc write
;
720 JSIOStreamGetPosition get_position
;
721 JSIOStreamGetLength get_length
;
723 JSIOStreamClose close
;
728 typedef struct js_io_stream_st JSIOStream
;
731 /* The destroy callback for the destroyable heap blocks. */
732 typedef void (*JSHeapDestroyableCB
) (void *ptr
);
735 * Each destroyable heap block must be castable to this structure e.g.
736 * the first item in the block must be pointer to the destroy function.
738 struct js_heap_destroyable_st
740 JSHeapDestroyableCB destroy
;
743 typedef struct js_heap_destroyable_st JSHeapDestroyable
;
746 /* Interned symbol. */
747 typedef unsigned int JSSymbol
;
749 /* JavaScript Types. */
756 JS_INTEGER
= 3, /* Integer, float and nan are `number' */
763 * The following ones are the internal types, used by this implementation.
777 struct js_builtin_info_st
;
779 /* Registry information for builtin objects. */
781 #define JS_PROPERTY_FOUND 1
782 #define JS_PROPERTY_UNKNOWN 0
784 typedef void (*JSBuiltinGlobalMethod
) (struct js_vm_st
*vm
,
785 struct js_builtin_info_st
*builtin_info
,
786 void *instance_context
,
787 struct js_node_st
*result_return
,
788 struct js_node_st
*args
);
791 * Function to call method <method> from the object. Function must return
792 * JS_PROPERTY_FOUND if the method was found or JS_PROPERTY_UNKNOWN
795 typedef int (*JSBuiltinMethod
) (struct js_vm_st
*vm
,
796 struct js_builtin_info_st
*builtin_info
,
797 void *instance_context
,
799 struct js_node_st
*result_return
,
800 struct js_node_st
*args
);
803 * Function to load and set property <property> of object. If <set>
804 * is true, property <property> should be set to value <node>. Otherwise
805 * function should return the value of property <property> in <node>.
806 * Function must return JS_PROPERTY_FOUND if the property was found or
807 * JS_PROPERTY_UNKNOWN otherwise.
809 typedef int (*JSBuiltinProperty
) (struct js_vm_st
*vm
,
810 struct js_builtin_info_st
*builtin_info
,
811 void *instance_context
,
812 JSSymbol property
, int set
,
813 struct js_node_st
*node
);
815 typedef void (*JSBuiltinNew
) (struct js_vm_st
*vm
,
816 struct js_builtin_info_st
*builtin_info
,
817 struct js_node_st
*args
,
818 struct js_node_st
*result_return
);
820 typedef void (*JSBuiltinDelete
) (struct js_builtin_info_st
*builtin_info
,
821 void *instance_context
);
823 typedef void (*JSBuiltinMark
) (struct js_builtin_info_st
*builtin_info
,
824 void *instance_context
);
826 typedef void (*JSBuiltinObjectCtxDelete
) (void *obj_context
);
828 struct js_builtin_info_st
830 JSHeapDestroyableCB destroy
;
832 JSBuiltinGlobalMethod global_method_proc
;
833 JSBuiltinMethod method_proc
;
834 JSBuiltinProperty property_proc
;
835 JSBuiltinNew new_proc
;
836 JSBuiltinDelete delete_proc
;
837 JSBuiltinMark mark_proc
;
840 JSBuiltinObjectCtxDelete obj_context_delete
;
842 struct js_object_st
*prototype
;
845 typedef struct js_builtin_info_st JSBuiltinInfo
;
847 /* Builtin object / class. */
850 JSHeapDestroyableCB destroy
;
853 void *instance_context
;
855 struct js_object_st
*prototype
;
858 typedef struct js_builtin_st JSBuiltin
;
864 unsigned int staticp
: 1;
869 struct js_object_st
*prototype
;
872 typedef struct js_string_st JSString
;
878 struct js_node_st
*data
;
880 struct js_object_st
*prototype
;
883 typedef struct js_array_st JSArray
;
886 struct js_function_st
888 void *implementation
;
889 struct js_object_st
*prototype
;
892 typedef struct js_function_st JSFunction
;
901 unsigned int vboolean
;
908 struct js_object_st
*vobject
;
912 /* Internal values. */
918 JSFunction
*vfunction
;
936 typedef struct js_node_st JSNode
;
941 /* Hash node for object's properties. */
942 struct js_object_prop_hash_bucket_st
944 struct js_object_prop_hash_bucket_st
*next
;
950 typedef struct js_object_prop_hash_bucket_st JSObjectPropHashBucket
;
952 /* The attribute flags for object's properties. */
953 #define JS_ATTRIB_READONLY 1
954 #define JS_ATTRIB_DONTENUM 2
955 #define JS_ATTRIB_DONTDELETE 4
956 #define JS_ATTRIB_Internal 8
958 /* Object's property. */
959 struct js_property_st
963 unsigned int attributes
;
966 typedef struct js_property_st JSProperty
;
970 JSObjectPropHashBucket
**hash
;
971 unsigned int *hash_lengths
;
972 unsigned int num_props
; /* Number of properties in this object. */
976 typedef struct js_object_st JSObject
;
984 JS_BCST_CONSTANTS
= 1,
991 JSBCSectionType type
;
993 void *data
; /* <length> bytes of data */
996 typedef struct js_bc_sect_st JSBCSect
;
1000 unsigned int num_sects
;
1004 typedef struct js_bc_st JSByteCode
;
1006 /* Debug information. */
1007 #define JS_DI_FILENAME 1
1008 #define JS_DI_LINENUMBER 2
1011 struct js_heap_block_st
1013 struct js_heap_block_st
*next
;
1015 /* <size> bytes of data follows the structure. */
1018 typedef struct js_heap_block_st JSHeapBlock
;
1020 /* Heap memory block. */
1022 #define JS_MEM_DEBUG 0
1024 /* All allocated blocks have this header. */
1025 struct js_heap_memory_block_st
1031 JSUIntAlign flag_mark
: 1;
1032 JSUIntAlign flag_destroyable
: 1;
1033 JSUIntAlign size
: (sizeof (JSUIntAlign
) * 8 - 2);
1034 /* <size> bytes of data follows this header. */
1037 typedef struct js_heap_memory_block_st JSHeapMemoryBlock
;
1040 * When the block is on the freelist, it has this header. The first
1041 * sizeof (void *) bytes of the block's data is used to hold the
1042 * freelist next pointer.
1044 struct js_heap_freelist_block_st
1046 JSHeapMemoryBlock block
;
1047 JSHeapMemoryBlock
*next
;
1050 typedef struct js_heap_freelist_block_st JSHeapFreelistBlock
;
1053 /* Parsed symbol table entry. */
1054 struct js_symtab_entry_st
1057 unsigned int offset
;
1060 typedef struct js_symtab_entry_st JSSymtabEntry
;
1064 * Entry points to different byte-code instruction dispatcher functions.
1065 * Each dispatcher must implement these.
1068 typedef int (*JSVMExecute
) (struct js_vm_st
*vm
, JSByteCode
*bc
,
1069 JSSymtabEntry
*symtab
,
1070 unsigned int num_symtab_entries
,
1071 unsigned int consts_offset
,
1072 unsigned int anonymous_function_offset
,
1073 unsigned char *debug_info
,
1074 unsigned int debug_info_len
,
1075 JSNode
*object
, JSNode
*func
,
1076 unsigned int argc
, JSNode
*argv
);
1078 typedef const char *(*JSVMFuncName
) (struct js_vm_st
*vm
, void *pc
);
1080 typedef const char *(*JSVMDebugPosition
) (struct js_vm_st
*vm
,
1081 unsigned int *linenum_return
);
1084 /* Virtual Machine. */
1086 #define JS_HASH_TABLE_SIZE 256
1088 struct js_hash_bucket_st
1090 struct js_hash_bucket_st
*next
;
1099 typedef struct js_hash_bucket_st JSHashBucket
;
1101 /* Error handler frame. */
1102 struct js_error_handler_frame_st
1104 struct js_error_handler_frame_st
*next
;
1107 /* The value thrown by the throw operand. */
1110 /* Saved state for the `try_push' operand. */
1117 typedef struct js_error_handler_frame_st JSErrorHandlerFrame
;
1121 /* Options for the virtual machine. */
1122 unsigned int verbose
; /* verbosity has different levels. */
1124 unsigned int stacktrace_on_error
: 1;
1125 unsigned int verbose_stacktrace
: 1;
1126 unsigned int warn_undef
: 1;
1128 /* Security flags. */
1129 unsigned long security
;
1131 /* The default system streams. */
1132 JSIOStream
*s_stdin
;
1133 JSIOStream
*s_stdout
;
1134 JSIOStream
*s_stderr
;
1136 /* The byte-code instruction dispatcher. */
1137 JSVMDispatchMethod dispatch_method
;
1138 const char *dispatch_method_name
;
1139 JSVMExecute dispatch_execute
;
1140 JSVMFuncName dispatch_func_name
;
1141 JSVMDebugPosition dispatch_debug_position
;
1143 /* Constants pool. */
1145 unsigned int num_consts
;
1146 unsigned int consts_alloc
;
1149 * Global symbols (both functions and variables). <globals_hash> is
1150 * a name-to-index mapping between symbol names and their positions
1153 JSHashBucket
*globals_hash
[JS_HASH_TABLE_SIZE
];
1155 unsigned int num_globals
;
1156 unsigned int globals_alloc
;
1158 /* The next anonymous function id. */
1159 unsigned int anonymous_function_next_id
;
1163 unsigned int stack_size
;
1164 JSNode
*sp
; /* Fuzzy stack pointer. */
1166 void *pc
; /* Fuzzy program counter. */
1168 /* Builtin objects for the primitive datatypes. */
1169 JSBuiltinInfo
*prim
[JS_IPTR
+ 1];
1171 /* Some commonly used symbols. */
1174 JSSymbol s___proto__
;
1175 JSSymbol s_prototype
;
1176 JSSymbol s_toSource
;
1177 JSSymbol s_toString
;
1184 JSHeapMemoryBlock
*heap_freelists
[JS_NUM_HEAP_FREELISTS
];
1185 unsigned long heap_size
;
1187 /* Information for the garbage collector. */
1190 unsigned long trigger
;
1191 unsigned long bytes_allocated
;
1192 unsigned long bytes_free
;
1193 unsigned long count
;
1196 /* Error handler frames. */
1197 JSErrorHandlerFrame
*error_handler
;
1199 /* Buffer for the error message. Sorry, we don't support long errors ;-) */
1203 * The result from the latest evaluation. This is set when the
1204 * js_vm_execute(), js_vm_apply(), or js_vm_call_method() functions
1205 * return to the caller.
1209 /* Event callback hook. */
1210 int (*hook
) (int event
, void *context
);
1212 unsigned int hook_operand_count
;
1213 unsigned int hook_operand_count_trigger
;
1215 /* How many file descriptors can be allocated. */
1216 unsigned long fd_count
;
1220 /* Byte-code operand profiling support. */
1222 unsigned int prof_count
[256];
1223 unsigned char prof_op
;
1225 #endif /* PROFILING */
1228 typedef struct js_vm_st JSVirtualMachine
;
1230 #include "kjs_structs.h"
1236 extern unsigned char js_latin1_tolower
[256];
1237 extern unsigned char js_latin1_toupper
[256];
1240 * Prototypes for global functions.
1244 * Memory allocation routines. If the allocation request fails, the
1245 * error recovery is performed according to the argument <vm>. If
1246 * <vm> is not NULL, an error message is formatted to vm->error and an
1247 * error is raise with js_vm_error(). If the <vm> is NULL, the
1248 * functions will return value NULL. It is an error to call these
1249 * functions with a non-NULL <vm> that has no error handler
1253 #ifndef JS_DEBUG_MEMORY_LEAKS
1254 #define JS_DEBUG_MEMORY_LEAKS 0
1255 #endif /* not JS_DEBUG_MEMORY_LEAKS */
1257 #if JS_DEBUG_MEMORY_LEAKS
1259 #define js_malloc(vm, size) js_malloc_i ((vm), (size), \
1261 #define js_calloc(vm, num, size) js_calloc_i ((vm), (num), (size), \
1263 #define js_realloc(vm, ptr, size) js_realloc_i ((vm), (ptr), (size), \
1265 #define js_strdup(vm, str) js_strdup_i ((vm), (str), \
1268 void *js_malloc_i (JSVirtualMachine
*vm
, size_t size
, char *, int);
1269 void *js_calloc_i (JSVirtualMachine
*vm
, size_t num
, size_t size
, char *, int);
1270 void *js_realloc_i (JSVirtualMachine
*vm
, void *ptr
, size_t size
, char *, int);
1271 void js_free (void *ptr
);
1272 char *js_strdup_i (JSVirtualMachine
*vm
, const char *str
, char *, int);
1274 #else /* not JS_DEBUG_MEMORY_LEAKS */
1276 void *js_malloc (JSVirtualMachine
*vm
, size_t size
);
1277 void *js_calloc (JSVirtualMachine
*vm
, size_t num
, size_t size
);
1278 void *js_realloc (JSVirtualMachine
*vm
, void *ptr
, size_t size
);
1279 void js_free (void *ptr
);
1280 char *js_strdup (JSVirtualMachine
*vm
, const char *str
);
1282 #endif /* not JS_DEBUG_MEMORY_LEAKS */
1287 JSByteCode
*js_bc_read_file (FILE *fp
);
1289 JSByteCode
*js_bc_read_data (unsigned char *data
, unsigned int datalen
);
1291 void js_bc_free (JSByteCode
*bc
);
1296 /* Allocate one I/O stream handle. */
1297 JSIOStream
*js_iostream_new ();
1299 JSIOStream
*js_iostream_file (FILE *fp
, int readp
, int writep
, int do_close
);
1301 JSIOStream
*js_iostream_pipe (FILE *fp
, int readp
);
1303 size_t js_iostream_read (JSIOStream
*stream
, void *ptr
, size_t size
);
1305 size_t js_iostream_write (JSIOStream
*stream
, void *ptr
, size_t size
);
1307 int js_iostream_flush (JSIOStream
*stream
);
1309 int js_iostream_unget (JSIOStream
*stream
, int byte
);
1311 int js_iostream_close (JSIOStream
*stream
);
1313 int js_iostream_seek (JSIOStream
*stream
, long offset
, int whence
);
1315 long js_iostream_get_position (JSIOStream
*stream
);
1317 long js_iostream_get_length (JSIOStream
*stream
);
1319 void js_iostream_fill_buffer (JSIOStream
*stream
);
1322 /* Virtual machine. */
1326 JSVirtualMachine
*js_vm_create (struct _KJS
*kjs
,
1327 unsigned int stack_size
,
1328 JSVMDispatchMethod dispatch_method
,
1329 unsigned int verbose
, int stacktrace_on_error
,
1330 JSIOStream
*s_stdin
, JSIOStream
*s_stdout
,
1331 JSIOStream
*s_stderr
);
1333 void js_vm_destroy (JSVirtualMachine
*vm
);
1336 * Execute byte code <bc>. Function returns 1 if the operation was
1337 * successful or 0 if any errors were encountered. In case of errors,
1338 * the error message is stored at vm->error.
1340 int js_vm_execute (JSVirtualMachine
*vm
, JSByteCode
*bc
);
1343 * Apply function <func_name> to arguments <argc, argv>. If
1344 * function's name <func_name> is NULL, then <func> must specify function
1345 * to which arguments are applied.
1347 int js_vm_apply (JSVirtualMachine
*vm
, char *func_name
, JSNode
*func
,
1348 unsigned int argc
, JSNode
*argv
);
1351 * Call method <method_name> from object <objet> with arguments <argc, argv>.
1353 int js_vm_call_method (JSVirtualMachine
*vm
, JSNode
*object
,
1354 const char *method_name
, unsigned int argc
,
1357 /* Map program counter to the source file line. */
1358 const char *js_vm_debug_position (JSVirtualMachine
*vm
,
1359 unsigned int *linenum_return
);
1361 /* Fetch the function name from the program counter value. */
1362 const char *js_vm_func_name (JSVirtualMachine
*vm
, void *pc
);
1364 /* Intern symbol <name, len> to virtual machine and return its JSSymbol id. */
1365 JSSymbol
js_vm_intern_with_len (JSVirtualMachine
*vm
, const char *name
,
1368 /* Intern symbol <name> to virtual machine and return its JSSymbol id. */
1369 static __inline JSSymbol
1370 js_vm_intern (JSVirtualMachine
*vm
, const char *name
)
1372 return js_vm_intern_with_len (vm
, name
, strlen (name
));
1375 /* Return the name of symbol <sym>. */
1376 const char *js_vm_symname (JSVirtualMachine
*vm
, JSSymbol sym
);
1379 * ToPrimitive(). Convert node <n> to its primitive value and return
1380 * the result in <result_return>.
1382 void js_vm_to_primitive (JSVirtualMachine
*vm
, const JSNode
*n
,
1383 JSNode
*result_return
, JSNodeType preferred_type
);
1386 * ToString(). Convert node <n> to its string presentations and
1387 * return the result in <result_return>.
1389 void js_vm_to_string (JSVirtualMachine
*vm
, const JSNode
*n
,
1390 JSNode
*result_return
);
1393 * ToNumber(). Convert node <n> to its number presentations and
1394 * return the result in <result_return>.
1396 void js_vm_to_number (JSVirtualMachine
*vm
, const JSNode
*n
,
1397 JSNode
*result_return
);
1399 /* ToObject(). Convert node <n> to object according to its type. */
1400 void js_vm_to_object (JSVirtualMachine
*vm
, const JSNode
*n
,
1401 JSNode
*result_return
);
1404 * ToInt32(). Convert node <n> to its signed 32 bit integer
1405 * presentation and return the result.
1407 JSInt32
js_vm_to_int32 (JSVirtualMachine
*vm
, JSNode
*n
);
1410 * ToBoolean(). Convert node <n> to a boolean value and return the
1413 int js_vm_to_boolean (JSVirtualMachine
*vm
, JSNode
*n
);
1417 * Raise an error. The error message must have been saved to vm->error
1418 * before this function is called. The function never returns.
1420 void js_vm_error (JSVirtualMachine
*vm
);
1423 * Count a hash value for <data_len> bytes of data <data>. The resulting
1424 * hash value should be re-mapped to the correct range, for example,
1425 * with the mod operand.
1427 static __inline
unsigned int
1428 js_count_hash (const char *data
, unsigned int data_len
)
1430 unsigned int val
= 0, i
;
1432 for (i
= 0; i
< data_len
; i
++)
1433 val
= (val
<< 5) ^ (unsigned char) data
[i
]
1434 ^ (val
>> 16) ^ (val
>> 7);
1440 /* Prototypes for the different instruction dispatcher implementations. */
1444 int js_vm_switch0_exec (JSVirtualMachine
*vm
, JSByteCode
*bc
,
1445 JSSymtabEntry
*symtab
,
1446 unsigned int num_symtab_entries
,
1447 unsigned int consts_offset
,
1448 unsigned int anonymous_function_offset
,
1449 unsigned char *debug_info
,
1450 unsigned int debug_info_len
,
1451 JSNode
*object
, JSNode
*func
,
1452 unsigned int argc
, JSNode
*argv
);
1454 const char *js_vm_switch0_func_name (JSVirtualMachine
*vm
, void *pc
);
1456 const char *js_vm_switch0_debug_position (JSVirtualMachine
*vm
,
1457 unsigned int *linenum_return
);
1459 #endif /* ALL_DISPATCHERS */
1461 int js_vm_switch_exec (JSVirtualMachine
*vm
, JSByteCode
*bc
,
1462 JSSymtabEntry
*symtab
,
1463 unsigned int num_symtab_entries
,
1464 unsigned int consts_offset
,
1465 unsigned int anonymous_function_offset
,
1466 unsigned char *debug_info
, unsigned int debug_info_len
,
1467 JSNode
*object
, JSNode
*func
,
1468 unsigned int argc
, JSNode
*argv
);
1470 const char *js_vm_switch_func_name (JSVirtualMachine
*vm
, void *pc
);
1472 const char *js_vm_switch_debug_position (JSVirtualMachine
*vm
,
1473 unsigned int *linenum_return
);
1475 int js_vm_jumps_exec (JSVirtualMachine
*vm
, JSByteCode
*bc
,
1476 JSSymtabEntry
*symtab
,
1477 unsigned int num_symtab_entries
,
1478 unsigned int consts_offset
,
1479 unsigned int anonymous_function_offset
,
1480 unsigned char *debug_info
, unsigned int debug_info_len
,
1481 JSNode
*object
, JSNode
*func
,
1482 unsigned int argc
, JSNode
*argv
);
1484 const char *js_vm_jumps_func_name (JSVirtualMachine
*vm
, void *pc
);
1486 const char *js_vm_jumps_debug_position (JSVirtualMachine
*vm
,
1487 unsigned int *linenum_return
);
1492 void *js_vm_alloc (JSVirtualMachine
*vm
, unsigned int size
);
1494 void *js_vm_alloc_destroyable (JSVirtualMachine
*vm
, unsigned int size
);
1496 void *js_vm_realloc (JSVirtualMachine
*vm
, void *ptr
, unsigned int new_size
);
1498 void js_vm_free (JSVirtualMachine
*vm
, void *ptr
);
1500 void js_vm_garbage_collect (JSVirtualMachine
*vm
, JSNode
*fp
, JSNode
*sp
);
1502 void js_vm_clear_heap (JSVirtualMachine
*vm
);
1504 void js_vm_mark (JSNode
*node
);
1506 int js_vm_mark_ptr (void *ptr
);
1508 int js_vm_is_marked_ptr (void *ptr
);
1512 static __inline JSFunction
*
1513 js_vm_make_function (JSVirtualMachine
*vm
, void *implementation
)
1515 JSFunction
*f
= (JSFunction
*) js_vm_alloc (vm
, sizeof (*f
));
1517 f
->implementation
= implementation
;
1518 f
->prototype
= (JSObject
*) NULL
;
1526 /* Create a new built-in info. */
1527 JSBuiltinInfo
*js_vm_builtin_info_create (JSVirtualMachine
*vm
);
1529 /* Create a new builtin object with <info, instance_context> to <result>. */
1530 void js_vm_builtin_create (JSVirtualMachine
*vm
, JSNode
*result
,
1531 JSBuiltinInfo
*info
, void *instance_context
);
1535 static __inline
void
1536 js_vm_make_array (JSVirtualMachine
*vm
, JSNode
*n
, unsigned int length
)
1541 n
->u
.varray
= (JSArray
*) js_vm_alloc (vm
, sizeof (*n
->u
.varray
));
1542 n
->u
.varray
->prototype
= NULL
;
1543 n
->u
.varray
->length
= length
;
1544 n
->u
.varray
->data
= (JSNode
*) js_vm_alloc (vm
, length
* sizeof (JSNode
));
1546 for (i
= 0; i
< length
; i
++)
1547 n
->u
.varray
->data
[i
].type
= JS_UNDEFINED
;
1550 static __inline
void
1551 js_vm_expand_array (JSVirtualMachine
*vm
, JSNode
*n
, unsigned int length
)
1553 if (n
->u
.varray
->length
< length
)
1555 n
->u
.varray
->data
= (JSNode
*) js_vm_realloc (vm
, n
->u
.varray
->data
,
1556 length
* sizeof (JSNode
));
1557 for (; n
->u
.varray
->length
< length
; n
->u
.varray
->length
++)
1558 n
->u
.varray
->data
[n
->u
.varray
->length
].type
= JS_UNDEFINED
;
1564 /* Enter file <fp> to the system. */
1565 void js_builtin_File_new (JSVirtualMachine
*vm
, JSNode
*result_return
,
1566 char *path
, JSIOStream
*stream
, int dont_close
);
1571 * Create a new regular expression node from <source, sourcelen> according
1572 * to <flags>. The argument <immutable> defines whether the created
1573 * regexp is immutable. The new regexp is returned in <result_return>.
1574 * If the <info> is NULL, the function will resolve it. Otherwise the given
1577 void js_builtin_RegExp_new (JSVirtualMachine
*vm
, char *source
,
1578 unsigned int source_len
, unsigned int flags
,
1579 int immutable
, JSBuiltinInfo
*info
,
1580 JSNode
*result_return
);
1583 * Do search-replace for the string <data, datalen> by replacing
1584 * matches of <regexp> with <repl, repl_len>. The resulting string is
1585 * returned in <result_return>
1587 void js_builtin_RegExp_replace (JSVirtualMachine
*vm
, char *data
,
1588 unsigned int datalen
, JSNode
*regexp
,
1589 char *repl
, unsigned int repl_len
,
1590 JSNode
*result_return
);
1593 * Do regexp match against <data, datalen>. Format the result array
1594 * to <result_return>.
1596 void js_builtin_RegExp_match (JSVirtualMachine
*vm
, char *data
,
1597 unsigned int datalen
, JSNode
*regexp
,
1598 JSNode
*result_return
);
1601 * Do regexp search against <data, datalen>. Return the start index of
1602 * the match in <result_return>.
1604 void js_builtin_RegExp_search (JSVirtualMachine
*vm
, char *data
,
1605 unsigned int datalen
, JSNode
*regexp
,
1606 JSNode
*result_return
);
1609 * Split the string <data, datalen> by regular expression <regexp>.
1610 * Function returns an array containing the substrings.
1612 void js_builtin_RegExp_split (JSVirtualMachine
*vm
, char *data
,
1613 unsigned int datalen
, JSNode
*regexp
,
1614 unsigned int limit
, JSNode
*result_return
);
1618 JSObject
*js_vm_object_new (JSVirtualMachine
*vm
);
1620 void js_vm_object_mark (JSObject
*obj
);
1622 int js_vm_object_load_property (JSVirtualMachine
*vm
, JSObject
*obj
,
1623 JSSymbol prop
, JSNode
*value_return
);
1625 void js_vm_object_store_property (JSVirtualMachine
*vm
, JSObject
*obj
,
1626 JSSymbol prop
, JSNode
*value
);
1628 void js_vm_object_delete_property (JSVirtualMachine
*vm
, JSObject
*obj
,
1631 void js_vm_object_load_array (JSVirtualMachine
*vm
, JSObject
*obj
, JSNode
*sel
,
1632 JSNode
*value_return
);
1634 void js_vm_object_store_array (JSVirtualMachine
*vm
, JSObject
*obj
,
1635 JSNode
*sel
, JSNode
*value
);
1637 void js_vm_object_delete_array (JSVirtualMachine
*vm
, JSObject
*obj
,
1640 int js_vm_object_nth (JSVirtualMachine
*vm
, JSObject
*obj
, int nth
,
1641 JSNode
*value_return
);
1646 void js_vm_stacktrace (JSVirtualMachine
*vm
, unsigned int num_frames
);
1651 static __inline
void
1652 js_vm_make_string (JSVirtualMachine
*vm
, JSNode
*n
, const char *data
,
1653 unsigned int data_len
)
1655 n
->type
= JS_STRING
;
1656 n
->u
.vstring
= (JSString
*) js_vm_alloc (vm
, sizeof (*n
->u
.vstring
));
1657 n
->u
.vstring
->staticp
= 0;
1658 n
->u
.vstring
->prototype
= NULL
;
1659 n
->u
.vstring
->len
= data_len
;
1660 n
->u
.vstring
->data
= (unsigned char *) js_vm_alloc (vm
, data_len
);
1662 memcpy (n
->u
.vstring
->data
, data
, data_len
);
1667 static __inline
void
1668 js_vm_make_static_string (JSVirtualMachine
*vm
, JSNode
*n
, const char *data
,
1669 unsigned int data_len
)
1671 n
->type
= JS_STRING
;
1672 n
->u
.vstring
= (JSString
*) js_vm_alloc (vm
, sizeof (*n
->u
.vstring
));
1673 n
->u
.vstring
->staticp
= 1;
1674 n
->u
.vstring
->prototype
= NULL
;
1675 n
->u
.vstring
->len
= data_len
;
1676 n
->u
.vstring
->data
= (unsigned char *) data
;
1681 js_compare_strings (JSNode
*a
, JSNode
*b
)
1685 for (i
= 0; i
< a
->u
.vstring
->len
&& i
< b
->u
.vstring
->len
; i
++)
1687 if (a
->u
.vstring
->data
[i
] < b
->u
.vstring
->data
[i
])
1689 if (a
->u
.vstring
->data
[i
] > b
->u
.vstring
->data
[i
])
1692 if (a
->u
.vstring
->len
< b
->u
.vstring
->len
)
1694 if (a
->u
.vstring
->len
> b
->u
.vstring
->len
)
1701 static __inline
char *
1702 js_string_to_c_string (JSVirtualMachine
*vm
, const JSNode
*a
)
1706 cp
= (char *) js_malloc (vm
, a
->u
.vstring
->len
+ 1);
1707 memcpy (cp
, a
->u
.vstring
->data
, a
->u
.vstring
->len
);
1708 cp
[a
->u
.vstring
->len
] = '\0';
1714 /* Dynamic loading. */
1717 * Try to open shared library <filename>. If the opening was
1718 * successful, a handle to the library is returned. Otherwise, the
1719 * function returns NULL, and an error message is returned in
1720 * <error_return>. The argument <error_return_len> specifies the
1721 * maximum length of the error message the function should return.
1723 void *js_dl_open (const char *filename
, char *error_return
,
1724 unsigned int error_return_len
);
1727 * Try to fetch the address of the symbol <symbol> from shared library
1730 void *js_dl_sym (void *library
, char *symbol
, char *error_return
,
1731 unsigned int error_return_len
);
1734 /* Misc helper functions. */
1736 unsigned long js_crc32 (const unsigned char *s
, unsigned int len
);
1740 * Definitions for the JavaScript part of the JavaScript interp.
1743 /* Flags for the compiler. See `jsc/entry.js'. */
1745 #define JSC_FLAG_VERBOSE 0x00000001
1746 #define JSC_FLAG_ANNOTATE_ASSEMBLER 0x00000002
1747 #define JSC_FLAG_GENERATE_DEBUG_INFO 0x00000004
1748 #define JSC_FLAG_GENERATE_EXECUTABLE_BC_FILES 0x00000008
1750 #define JSC_FLAG_OPTIMIZE_PEEPHOLE 0x00000020
1751 #define JSC_FLAG_OPTIMIZE_JUMPS 0x00000040
1752 #define JSC_FLAG_OPTIMIZE_BC_SIZE 0x00000080
1753 #define JSC_FLAG_OPTIMIZE_HEAVY 0x00000100
1755 #define JSC_FLAG_OPTIMIZE_MASK 0x0000fff0
1757 #define JSC_FLAG_WARN_UNUSED_ARGUMENT 0x00010000
1758 #define JSC_FLAG_WARN_UNUSED_VARIABLE 0x00020000
1759 #define JSC_FLAG_WARN_SHADOW 0x00040000
1760 #define JSC_FLAG_WARN_WITH_CLOBBER 0x00080000
1761 #define JSC_FLAG_WARN_MISSING_SEMICOLON 0x00100000
1762 #define JSC_FLAG_WARN_STRICT_ECMA 0x00200000
1763 #define JSC_FLAG_WARN_DEPRECATED 0x00400000
1765 #define JSC_FLAG_WARN_MASK 0xffff0000
1767 /* JavaScript interpreter handle. */
1770 JSInterpOptions options
;
1771 JSVirtualMachine
*vm
;
1774 /* Declaration for the JS compiler byte-code. */
1775 extern unsigned char js_compiler_bytecode
[];
1776 extern unsigned int js_compiler_bytecode_len
;
1782 #endif /* not JSINT_H */