home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / js / src / jsemit.h < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  14.0 KB  |  346 lines

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #ifndef jsemit_h___
  20. #define jsemit_h___
  21. /*
  22.  * JS bytecode generation.
  23.  */
  24. #include <stddef.h>
  25. #include "prtypes.h"
  26. #include "jsatom.h"
  27. #include "jsopcode.h"
  28. #include "jsprvtd.h"
  29. #include "jspubtd.h"
  30.  
  31. PR_BEGIN_EXTERN_C
  32.  
  33. typedef enum StmtType {
  34.     STMT_BLOCK        = 0,      /* compound statement: { s1[;... sN] } */
  35.     STMT_LABEL        = 1,      /* labeled statement:  l: s */
  36.     STMT_IF           = 2,      /* if (then) statement */
  37.     STMT_ELSE         = 3,      /* else statement */
  38.     STMT_SWITCH       = 4,      /* switch statement */
  39.     STMT_WITH         = 5,      /* with statement */
  40.     STMT_DO_LOOP      = 6,      /* do/while loop statement */
  41.     STMT_FOR_LOOP     = 7,      /* for loop statement */
  42.     STMT_FOR_IN_LOOP  = 8,      /* for/in loop statement */
  43.     STMT_WHILE_LOOP   = 9       /* while loop statement */
  44. } StmtType;
  45.  
  46. #define STMT_IS_LOOP(stmt)      ((stmt)->type >= STMT_DO_LOOP)
  47.  
  48. typedef struct SwitchCase SwitchCase;
  49. typedef struct StmtInfo   StmtInfo;
  50.  
  51. struct StmtInfo {
  52.     StmtType    type;           /* statement type */
  53.     ptrdiff_t   top;            /* offset of loop top from cg base */
  54.     ptrdiff_t   update;         /* loop update offset (top if none) */
  55.     ptrdiff_t   breaks;         /* offset of last break in loop */
  56.     ptrdiff_t   continues;      /* offset of last continue in loop */
  57.     JSAtom      *label;         /* label name if type is STMT_LABEL */
  58.     StmtInfo    *down;          /* info for enclosing statement */
  59. };
  60.  
  61. struct SwitchCase {
  62.     jsval       value;
  63.     ptrdiff_t   offset;
  64.     SwitchCase  *next;
  65. };
  66.  
  67. #define SET_STATEMENT_TOP(stmt, top) \
  68.     ((stmt)->top = (stmt)->update = (stmt)->breaks = (stmt)->continues = (top))
  69.  
  70. struct JSCodeGenerator {
  71.     PRArenaPool *pool;          /* pool in which to allocate code */
  72.     jsbytecode  *base;          /* base of JS bytecode vector */
  73.     jsbytecode  *limit;         /* one byte beyond end of bytecode */
  74.     jsbytecode  *ptr;           /* pointer to next free bytecode */
  75.     JSAtomList  atomList;       /* literals indexed for mapping */
  76.     JSSymbol    *args;          /* list of formal argument symbols */
  77.     JSSymbol    *vars;          /* list of local variable symbols */
  78.     ptrdiff_t   lastCodeOffset; /* offset of last non-nop opcode */
  79.     StmtInfo    *stmtInfo;      /* statement stack for break/continue */
  80.     intN        stackDepth;     /* current stack depth in basic block */
  81.     uintN       maxStackDepth;  /* maximum stack depth so far */
  82.     jssrcnote   *notes;         /* source notes, see below */
  83.     uintN       noteCount;      /* number of source notes so far */
  84.     uintN       lastNoteCount;  /* index of last emitted source note */
  85.     uintN       saveNoteCount;  /* saved index for source note cancellation */
  86.     ptrdiff_t   lastNoteOffset; /* code offset of last emitted source note */
  87.     ptrdiff_t   saveNoteOffset; /* saved offset before last cancellable note */
  88. };
  89.  
  90. #define CG_CODE(cg,offset)      ((cg)->base + (offset))
  91. #define CG_OFFSET(cg)           ((cg)->ptr - (cg)->base)
  92. #define CG_RESET(cg)            ((cg)->ptr = (cg)->base,                      \
  93.                  INIT_ATOM_LIST(&(cg)->atomList),             \
  94.                  (cg)->args = (cg)->vars = NULL,              \
  95.                                  (cg)->lastCodeOffset = 0,                    \
  96.                  (cg)->stmtInfo = NULL,                       \
  97.                                  (cg)->stackDepth = (cg)->maxStackDepth = 0,  \
  98.                                  CG_RESET_NOTES(cg))
  99. #define CG_RESET_NOTES(cg)      ((cg)->notes = NULL, (cg)->noteCount = 0,     \
  100.                                  (cg)->lastNoteCount = 0,                     \
  101.                  (cg)->saveNoteCount = 0,                     \
  102.                                  (cg)->lastNoteOffset = 0,                    \
  103.                                  (cg)->saveNoteOffset = 0)
  104. #define CG_PUSH(cg, newcg)      ((newcg)->atomList = (cg)->atomList)
  105. #define CG_POP(cg, newcg)       ((cg)->atomList = (newcg)->atomList)
  106.  
  107. /*
  108.  * Initialize cg to allocate from an arena pool.  Return true on success.
  109.  * Report an exception and return false if the initial code segment can't
  110.  * be allocated.
  111.  */
  112. extern JS_FRIEND_API(JSBool)
  113. js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, PRArenaPool *pool);
  114.  
  115. /*
  116.  * Emit one bytecode.
  117.  */
  118. extern ptrdiff_t
  119. js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op);
  120.  
  121. /*
  122.  * Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1).
  123.  */
  124. extern ptrdiff_t
  125. js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1);
  126.  
  127. /*
  128.  * Emit three bytecodes, an opcode with two bytes of immediate operands.
  129.  */
  130. extern ptrdiff_t
  131. js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1,
  132.      jsbytecode op2);
  133.  
  134. /*
  135.  * Unsafe macro to call js_SetJumpOffset and return false if it does.
  136.  */
  137. #define CHECK_AND_SET_JUMP_OFFSET(cx,cg,pc,off)                               \
  138.     PR_BEGIN_MACRO                                                            \
  139.     if (!js_SetJumpOffset(cx, cg, pc, off))                               \
  140.         return JS_FALSE;                                                  \
  141.     PR_END_MACRO
  142.  
  143. #define CHECK_AND_SET_JUMP_OFFSET_AT(cx,cg,off)                               \
  144.     CHECK_AND_SET_JUMP_OFFSET(cx, cg, CG_CODE(cg,off), CG_OFFSET(cg) - (off))
  145.  
  146. extern JSBool
  147. js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
  148.          ptrdiff_t off);
  149.  
  150. /*
  151.  * Cancel the last bytecode and any immediate operands emitted via cg.
  152.  * You can't Cancel more than once between Emit calls.
  153.  */
  154. extern void
  155. js_CancelLastOpcode(JSContext *cx, JSCodeGenerator *cg, uint16 *newlinesp);
  156.  
  157. /*
  158.  * Update cg's stack depth budget for the opcode located at offset in cg.
  159.  */
  160. extern void
  161. js_UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t offset);
  162.  
  163. /*
  164.  * Copy code from code generator from starting at fromOffset and running to
  165.  * CG_OFFSET(from) into code generator to, starting at toOffset.
  166.  *
  167.  * NB: this function does not move source notes; the caller must do that.
  168.  */
  169. extern ptrdiff_t
  170. js_MoveCode(JSContext *cx,
  171.             JSCodeGenerator *from, ptrdiff_t fromOffset,
  172.             JSCodeGenerator *to, ptrdiff_t toOffset);
  173.  
  174. /*
  175.  * Push the stack-allocated struct at stmt onto the cg->stmtInfo stack.
  176.  */
  177. extern void
  178. js_PushStatement(JSCodeGenerator *cg, StmtInfo *stmt, StmtType type,
  179.          ptrdiff_t top);
  180.  
  181. /*
  182.  * Emit a break instruction, recording it for backpatching.
  183.  */
  184. extern ptrdiff_t
  185. js_EmitBreak(JSContext *cx, JSCodeGenerator *cg, StmtInfo *stmt,
  186.          JSAtom *label);
  187.  
  188. /*
  189.  * Emit a continue instruction, recording it for backpatching.
  190.  */
  191. extern ptrdiff_t
  192. js_EmitContinue(JSContext *cx, JSCodeGenerator *cg, StmtInfo *stmt,
  193.         JSAtom *label);
  194.  
  195. /*
  196.  * Pop cg->stmtInfo.  If the top StmtInfo struct is not stack-allocated, it
  197.  * is up to the caller to free it.
  198.  */
  199. extern JSBool
  200. js_PopStatement(JSContext *cx, JSCodeGenerator *cg);
  201.  
  202. /*
  203.  * Source notes generated along with bytecode for decompiling and debugging.
  204.  * A source note is a uint8 with 5 bits of type and 3 of offset from the pc of
  205.  * the previous note.  If 3 bits of offset aren't enough, extended delta notes
  206.  * (SRC_XDELTA) consisting of 2 set high order bits followed by 6 offset bits
  207.  * are emitted before the next note.  Some notes have operand offsets encoded
  208.  * in note bytes or byte-pairs.
  209.  *
  210.  * At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE,
  211.  * SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode.
  212.  *
  213.  * NB: the js_SrcNoteName and js_SrcNoteArity arrays in jsemit.c are indexed
  214.  * by this enum, so their initializers need to match the order here.
  215.  */
  216. typedef enum JSSrcNoteType {
  217.     SRC_NULL        = 0,        /* terminates a note vector */
  218.     SRC_IF          = 1,        /* JSOP_IFEQ bytecode is from an if-then */
  219.     SRC_IF_ELSE     = 2,        /* JSOP_IFEQ bytecode is from an if-then-else */
  220.     SRC_WHILE       = 3,        /* JSOP_IFEQ is from a while loop */
  221.     SRC_FOR         = 4,        /* JSOP_NOP or JSOP_POP in for loop head */
  222.     SRC_CONTINUE    = 5,        /* JSOP_GOTO is a continue, not a break */
  223.     SRC_VAR         = 6,        /* JSOP_NAME/FORNAME with a var declaration */
  224.     SRC_COMMA       = 7,        /* JSOP_POP representing a comma operator */
  225.     SRC_ASSIGNOP    = 8,        /* += or another assign-op follows */
  226.     SRC_COND        = 9,        /* JSOP_IFEQ is from conditional ?: operator */
  227.     SRC_PAREN       = 10,       /* JSOP_NOP generated to mark user parens */
  228.     SRC_HIDDEN      = 11,       /* JSOP_LEAVEWITH for break/continue in with */
  229.     SRC_PCBASE      = 12,       /* offset of first obj.prop.subprop bytecode */
  230.     SRC_LABEL       = 13,       /* JSOP_NOP for label: with atomid immediate */
  231.     SRC_LABELBRACE  = 14,       /* JSOP_NOP for label: {...} begin brace */
  232.     SRC_ENDBRACE    = 15,       /* JSOP_NOP for label: {...} end brace */
  233.     SRC_BREAK2LABEL = 16,       /* JSOP_GOTO for 'break label' with atomid */
  234.     SRC_CONT2LABEL  = 17,       /* JSOP_GOTO for 'continue label' with atomid */
  235.     SRC_SWITCH      = 18,       /* JSOP_*SWITCH with offset to end of switch */
  236.     SRC_UNUSED19    = 19,       /* unused */
  237.     SRC_UNUSED20    = 20,       /* unused */
  238.     SRC_UNUSED21    = 21,       /* unused */
  239.     SRC_NEWLINE     = 22,       /* bytecode follows a source newline */
  240.     SRC_SETLINE     = 23,       /* a file-absolute source line number note */
  241.     SRC_XDELTA      = 24        /* 24-31 are for extended delta notes */
  242. } JSSrcNoteType;
  243.  
  244. #define SN_TYPE_BITS            5
  245. #define SN_DELTA_BITS           3
  246. #define SN_XDELTA_BITS          6
  247. #define SN_TYPE_MASK            (PR_BITMASK(SN_TYPE_BITS) << SN_DELTA_BITS)
  248. #define SN_DELTA_MASK           ((ptrdiff_t)PR_BITMASK(SN_DELTA_BITS))
  249. #define SN_XDELTA_MASK          ((ptrdiff_t)PR_BITMASK(SN_XDELTA_BITS))
  250.  
  251. #define SN_MAKE_NOTE(sn,t,d)    (*(sn) = (jssrcnote)                          \
  252.                       (((t) << SN_DELTA_BITS)             \
  253.                        | ((d) & SN_DELTA_MASK)))
  254. #define SN_MAKE_XDELTA(sn,d)    (*(sn) = (jssrcnote)                          \
  255.                       ((SRC_XDELTA << SN_DELTA_BITS)      \
  256.                        | ((d) & SN_XDELTA_MASK)))
  257.  
  258. #define SN_IS_XDELTA(sn)        ((*(sn) >> SN_DELTA_BITS) >= SRC_XDELTA)
  259. #define SN_TYPE(sn)             (SN_IS_XDELTA(sn) ? SRC_XDELTA                \
  260.                           : *(sn) >> SN_DELTA_BITS)
  261. #define SN_SET_TYPE(sn,type)    SN_MAKE_NOTE(sn, type, SN_DELTA(sn))
  262. #define SN_IS_GETTABLE(sn)      (SN_TYPE(sn) < SRC_NEWLINE)
  263.  
  264. #define SN_DELTA(sn)            ((ptrdiff_t)(SN_IS_XDELTA(sn)                 \
  265.                          ? *(sn) & SN_XDELTA_MASK         \
  266.                          : *(sn) & SN_DELTA_MASK))
  267. #define SN_SET_DELTA(sn,delta)  (SN_IS_XDELTA(sn)                             \
  268.                  ? SN_MAKE_XDELTA(sn, delta)                  \
  269.                  : SN_MAKE_NOTE(sn, SN_TYPE(sn), delta))
  270.  
  271. #define SN_DELTA_LIMIT          ((ptrdiff_t)PR_BIT(SN_DELTA_BITS))
  272. #define SN_XDELTA_LIMIT         ((ptrdiff_t)PR_BIT(SN_XDELTA_BITS))
  273.  
  274. /*
  275.  * Offset fields follow certain notes and are frequency-encoded: an offset in
  276.  * [0,127] consumes one byte, an offset in [128,32767] takes two, and the high
  277.  * bit of the first byte is set.
  278.  */
  279. #define SN_2BYTE_OFFSET_FLAG    0x80
  280. #define SN_2BYTE_OFFSET_MASK    0x7f
  281.  
  282. extern const char *js_SrcNoteName[];
  283. extern uint8 js_SrcNoteArity[];
  284. extern uintN js_SrcNoteLength(jssrcnote *sn);
  285.  
  286. #define SN_LENGTH(sn)           ((js_SrcNoteArity[SN_TYPE(sn)] == 0) ? 1      \
  287.                  : js_SrcNoteLength(sn))
  288. #define SN_NEXT(sn)             ((sn) + SN_LENGTH(sn))
  289.  
  290. /* A source note array is terminated by an all-zero element. */
  291. #define SN_MAKE_TERMINATOR(sn)  (*(sn) = SRC_NULL)
  292. #define SN_IS_TERMINATOR(sn)    (*(sn) == SRC_NULL)
  293.  
  294. /*
  295.  * Append a new source note of the given type (and therefore size) to cg's
  296.  * notes dynamic array, updating cg->noteCount.  Return the new note's index
  297.  * within the array pointed at by cg->notes.  Return -1 if out of memory.
  298.  */
  299. extern intN
  300. js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type);
  301.  
  302. extern intN
  303. js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
  304.            ptrdiff_t offset);
  305.  
  306. extern intN
  307. js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
  308.            ptrdiff_t offset1, ptrdiff_t offset2);
  309.  
  310. /*
  311.  * Increment the delta of the note at cg->notes[index], overflowing into one
  312.  * or more xdelta notes if necessary.
  313.  */
  314. extern JSBool
  315. js_BumpSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, uintN index,
  316.             ptrdiff_t incr);
  317.  
  318. /*
  319.  * Get and set the offset operand identified by which (0 for the first, etc.).
  320.  */
  321. extern ptrdiff_t
  322. js_GetSrcNoteOffset(jssrcnote *sn, uintN which);
  323.  
  324. extern JSBool
  325. js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
  326.             uintN which, ptrdiff_t offset);
  327.  
  328. /*
  329.  * Copy source notes from one code generator to another.  The code annotated
  330.  * by the copied notes must be moved *after* the notes are moved.
  331.  */
  332. extern JSBool
  333. js_MoveSrcNotes(JSContext *cx, JSCodeGenerator *from, JSCodeGenerator *to);
  334.  
  335. /*
  336.  * Finish taking source notes in cx's tempPool by copying them to new stable
  337.  * store allocated via JS_malloc.  Return null on malloc failure, which means
  338.  * this function reported an error.
  339.  */
  340. extern JS_FRIEND_API(jssrcnote *)
  341. js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg);
  342.  
  343. PR_END_EXTERN_C
  344.  
  345. #endif /* jsemit_h___ */
  346.