|
|
1.1 ! root 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 ! 4: * License Version 1.1 (the "License"); you may not use this file ! 5: * except in compliance with the License. You may obtain a copy of ! 6: * the License at http://www.mozilla.org/NPL/ ! 7: * ! 8: * Software distributed under the License is distributed on an "AS ! 9: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ! 10: * implied. See the License for the specific language governing ! 11: * rights and limitations under the License. ! 12: * ! 13: * The Original Code is Mozilla Communicator client code, released ! 14: * March 31, 1998. ! 15: * ! 16: * The Initial Developer of the Original Code is Netscape ! 17: * Communications Corporation. Portions created by Netscape are ! 18: * Copyright (C) 1998 Netscape Communications Corporation. All ! 19: * Rights Reserved. ! 20: * ! 21: * Contributor(s): ! 22: * ! 23: * Alternatively, the contents of this file may be used under the ! 24: * terms of the GNU Public License (the "GPL"), in which case the ! 25: * provisions of the GPL are applicable instead of those above. ! 26: * If you wish to allow use of your version of this file only ! 27: * under the terms of the GPL and not to allow others to use your ! 28: * version of this file under the NPL, indicate your decision by ! 29: * deleting the provisions above and replace them with the notice ! 30: * and other provisions required by the GPL. If you do not delete ! 31: * the provisions above, a recipient may use your version of this ! 32: * file under either the NPL or the GPL. ! 33: */ ! 34: ! 35: #ifndef jsemit_h___ ! 36: #define jsemit_h___ ! 37: /* ! 38: * JS bytecode generation. ! 39: */ ! 40: ! 41: #include "jsstddef.h" ! 42: #include "jstypes.h" ! 43: #include "jsatom.h" ! 44: #include "jsopcode.h" ! 45: #include "jsprvtd.h" ! 46: #include "jspubtd.h" ! 47: ! 48: JS_BEGIN_EXTERN_C ! 49: ! 50: /* ! 51: * NB: If you add non-loop STMT_* enumerators, do so before STMT_DO_LOOP or ! 52: * you will break the STMT_IS_LOOP macro, just below this enum. ! 53: */ ! 54: typedef enum JSStmtType { ! 55: STMT_BLOCK = 0, /* compound statement: { s1[;... sN] } */ ! 56: STMT_LABEL = 1, /* labeled statement: L: s */ ! 57: STMT_IF = 2, /* if (then) statement */ ! 58: STMT_ELSE = 3, /* else clause of if statement */ ! 59: STMT_SWITCH = 4, /* switch statement */ ! 60: STMT_WITH = 5, /* with statement */ ! 61: STMT_TRY = 6, /* try statement */ ! 62: STMT_CATCH = 7, /* catch block */ ! 63: STMT_FINALLY = 8, /* finally statement */ ! 64: STMT_SUBROUTINE = 9, /* gosub-target subroutine body */ ! 65: STMT_DO_LOOP = 10, /* do/while loop statement */ ! 66: STMT_FOR_LOOP = 11, /* for loop statement */ ! 67: STMT_FOR_IN_LOOP = 12, /* for/in loop statement */ ! 68: STMT_WHILE_LOOP = 13 /* while loop statement */ ! 69: } JSStmtType; ! 70: ! 71: #define STMT_IS_LOOP(stmt) ((stmt)->type >= STMT_DO_LOOP) ! 72: ! 73: typedef struct JSStmtInfo JSStmtInfo; ! 74: ! 75: struct JSStmtInfo { ! 76: JSStmtType type; /* statement type */ ! 77: ptrdiff_t update; /* loop update offset (top if none) */ ! 78: ptrdiff_t breaks; /* offset of last break in loop */ ! 79: ptrdiff_t continues; /* offset of last continue in loop */ ! 80: ptrdiff_t gosub; /* offset of last GOSUB for this finally */ ! 81: ptrdiff_t catchJump; /* offset of last end-of-catch jump */ ! 82: JSAtom *label; /* name of LABEL or CATCH var */ ! 83: JSStmtInfo *down; /* info for enclosing statement */ ! 84: }; ! 85: ! 86: #define SET_STATEMENT_TOP(stmt, top) \ ! 87: ((stmt)->update = (top), (stmt)->breaks = \ ! 88: (stmt)->continues = (stmt)->catchJump = (stmt)->gosub = (-1)) ! 89: ! 90: struct JSTreeContext { /* tree context for semantic checks */ ! 91: uint32 flags; /* statement state flags, see below */ ! 92: uint32 tryCount; /* total count of try statements parsed */ ! 93: JSStmtInfo *topStmt; /* top of statement info stack */ ! 94: JSAtomList decls; /* function, const, and var declarations */ ! 95: JSParseNode *nodeList; /* list of recyclable parse-node structs */ ! 96: }; ! 97: ! 98: #define TCF_COMPILING 0x01 /* generating bytecode; this tc is a cg */ ! 99: #define TCF_IN_FUNCTION 0x02 /* parsing inside function body */ ! 100: #define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */ ! 101: #define TCF_RETURN_VOID 0x08 /* function has 'return;' */ ! 102: #define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */ ! 103: #define TCF_FUN_CLOSURE_VS_VAR 0x20 /* function and var with same name */ ! 104: #define TCF_FUN_USES_NONLOCALS 0x40 /* function refers to non-local names */ ! 105: #define TCF_FUN_HEAVYWEIGHT 0x80 /* function needs Call object per call */ ! 106: #define TCF_FUN_FLAGS 0xE0 /* flags to propagate from FunctionBody */ ! 107: ! 108: #define TREE_CONTEXT_INIT(tc) \ ! 109: ((tc)->flags = 0, (tc)->tryCount = 0, (tc)->topStmt = NULL, \ ! 110: ATOM_LIST_INIT(&(tc)->decls), (tc)->nodeList = NULL) ! 111: ! 112: #define TREE_CONTEXT_FINISH(tc) \ ! 113: ((void)0) ! 114: ! 115: /* ! 116: * Span-dependent instructions are jumps whose span (from the jump bytecode to ! 117: * the jump target) may require 2 or 4 bytes of immediate operand. ! 118: */ ! 119: typedef struct JSSpanDep JSSpanDep; ! 120: typedef struct JSJumpTarget JSJumpTarget; ! 121: ! 122: struct JSSpanDep { ! 123: ptrdiff_t top; /* offset of first bytecode in an opcode */ ! 124: ptrdiff_t offset; /* offset - 1 within opcode of jump operand */ ! 125: ptrdiff_t before; /* original offset - 1 of jump operand */ ! 126: JSJumpTarget *target; /* tagged target pointer or backpatch delta */ ! 127: }; ! 128: ! 129: /* ! 130: * Jump targets are stored in an AVL tree, for O(log(n)) lookup with targets ! 131: * sorted by offset from left to right, so that targets above a span-dependent ! 132: * instruction whose jump offset operand must be extended can be found quickly ! 133: * and adjusted upward (toward higher offsets). ! 134: */ ! 135: struct JSJumpTarget { ! 136: ptrdiff_t offset; /* offset of span-dependent jump target */ ! 137: int balance; /* AVL tree balance number */ ! 138: JSJumpTarget *kids[2]; /* left and right AVL tree child pointers */ ! 139: }; ! 140: ! 141: #define JT_LEFT 0 ! 142: #define JT_RIGHT 1 ! 143: #define JT_OTHER_DIR(dir) (1 - (dir)) ! 144: #define JT_IMBALANCE(dir) (((dir) << 1) - 1) ! 145: #define JT_DIR(imbalance) (((imbalance) + 1) >> 1) ! 146: ! 147: /* ! 148: * Backpatch deltas are encoded in JSSpanDep.target if JT_TAG_BIT is clear, ! 149: * so we can maintain backpatch chains when using span dependency records to ! 150: * hold jump offsets that overflow 16 bits. ! 151: */ ! 152: #define JT_TAG_BIT ((jsword) 1) ! 153: #define JT_UNTAG_SHIFT 1 ! 154: #define JT_SET_TAG(jt) ((JSJumpTarget *)((jsword)(jt) | JT_TAG_BIT)) ! 155: #define JT_CLR_TAG(jt) ((JSJumpTarget *)((jsword)(jt) & ~JT_TAG_BIT)) ! 156: #define JT_HAS_TAG(jt) ((jsword)(jt) & JT_TAG_BIT) ! 157: ! 158: #define BITS_PER_PTRDIFF (sizeof(ptrdiff_t) * JS_BITS_PER_BYTE) ! 159: #define BITS_PER_BPDELTA (BITS_PER_PTRDIFF - 1 - JT_UNTAG_SHIFT) ! 160: #define BPDELTA_MAX (((ptrdiff_t)1 << BITS_PER_BPDELTA) - 1) ! 161: #define BPDELTA_TO_JT(bp) ((JSJumpTarget *)((bp) << JT_UNTAG_SHIFT)) ! 162: #define JT_TO_BPDELTA(jt) ((ptrdiff_t)((jsword)(jt) >> JT_UNTAG_SHIFT)) ! 163: ! 164: #define SD_SET_TARGET(sd,jt) ((sd)->target = JT_SET_TAG(jt)) ! 165: #define SD_SET_BPDELTA(sd,bp) ((sd)->target = BPDELTA_TO_JT(bp)) ! 166: #define SD_GET_BPDELTA(sd) (JS_ASSERT(!JT_HAS_TAG((sd)->target)), \ ! 167: JT_TO_BPDELTA((sd)->target)) ! 168: #define SD_TARGET_OFFSET(sd) (JS_ASSERT(JT_HAS_TAG((sd)->target)), \ ! 169: JT_CLR_TAG((sd)->target)->offset) ! 170: ! 171: struct JSCodeGenerator { ! 172: JSTreeContext treeContext; /* base state: statement info stack, etc. */ ! 173: void *codeMark; /* low watermark in cx->codePool */ ! 174: void *noteMark; /* low watermark in cx->notePool */ ! 175: void *tempMark; /* low watermark in cx->tempPool */ ! 176: struct { ! 177: jsbytecode *base; /* base of JS bytecode vector */ ! 178: jsbytecode *limit; /* one byte beyond end of bytecode */ ! 179: jsbytecode *next; /* pointer to next free bytecode */ ! 180: jssrcnote *notes; /* source notes, see below */ ! 181: uintN noteCount; /* number of source notes so far */ ! 182: uintN noteMask; /* growth increment for notes */ ! 183: ptrdiff_t lastNoteOffset; /* code offset for last source note */ ! 184: uintN currentLine; /* line number for tree-based srcnote gen */ ! 185: } prolog, main, *current; ! 186: const char *filename; /* null or weak link to source filename */ ! 187: uintN firstLine; /* first line, for js_NewScriptFromCG */ ! 188: JSPrincipals *principals; /* principals for constant folding eval */ ! 189: JSAtomList atomList; /* literals indexed for mapping */ ! 190: intN stackDepth; /* current stack depth in script frame */ ! 191: uintN maxStackDepth; /* maximum stack depth so far */ ! 192: JSTryNote *tryBase; /* first exception handling note */ ! 193: JSTryNote *tryNext; /* next available note */ ! 194: size_t tryNoteSpace; /* # of bytes allocated at tryBase */ ! 195: JSSpanDep *spanDeps; /* span dependent instruction records */ ! 196: JSJumpTarget *jumpTargets; /* AVL tree of jump target offsets */ ! 197: JSJumpTarget *jtFreeList; /* JT_LEFT-linked list of free structs */ ! 198: uintN numSpanDeps; /* number of span dependencies */ ! 199: uintN numJumpTargets; /* number of jump targets */ ! 200: uintN emitLevel; /* js_EmitTree recursion level */ ! 201: }; ! 202: ! 203: #define CG_BASE(cg) ((cg)->current->base) ! 204: #define CG_LIMIT(cg) ((cg)->current->limit) ! 205: #define CG_NEXT(cg) ((cg)->current->next) ! 206: #define CG_CODE(cg,offset) (CG_BASE(cg) + (offset)) ! 207: #define CG_OFFSET(cg) PTRDIFF(CG_NEXT(cg), CG_BASE(cg), jsbytecode) ! 208: ! 209: #define CG_NOTES(cg) ((cg)->current->notes) ! 210: #define CG_NOTE_COUNT(cg) ((cg)->current->noteCount) ! 211: #define CG_NOTE_MASK(cg) ((cg)->current->noteMask) ! 212: #define CG_LAST_NOTE_OFFSET(cg) ((cg)->current->lastNoteOffset) ! 213: #define CG_CURRENT_LINE(cg) ((cg)->current->currentLine) ! 214: ! 215: #define CG_PROLOG_BASE(cg) ((cg)->prolog.base) ! 216: #define CG_PROLOG_LIMIT(cg) ((cg)->prolog.limit) ! 217: #define CG_PROLOG_NEXT(cg) ((cg)->prolog.next) ! 218: #define CG_PROLOG_CODE(cg,poff) (CG_PROLOG_BASE(cg) + (poff)) ! 219: #define CG_PROLOG_OFFSET(cg) PTRDIFF(CG_PROLOG_NEXT(cg), CG_PROLOG_BASE(cg),\ ! 220: jsbytecode) ! 221: ! 222: #define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main) ! 223: #define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog) ! 224: ! 225: /* ! 226: * Initialize cg to allocate bytecode space from cx->codePool, source note ! 227: * space from cx->notePool, and all other arena-allocated temporaries from ! 228: * cx->tempPool. Return true on success. Report an error and return false ! 229: * if the initial code segment can't be allocated. ! 230: */ ! 231: extern JS_FRIEND_API(JSBool) ! 232: js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, ! 233: const char *filename, uintN lineno, ! 234: JSPrincipals *principals); ! 235: ! 236: /* ! 237: * Release cx->codePool, cx->notePool, and cx->tempPool to marks set by ! 238: * js_InitCodeGenerator. Note that cgs are magic: they own the arena pool ! 239: * "tops-of-stack" space above their codeMark, noteMark, and tempMark points. ! 240: * This means you cannot alloc from tempPool and save the pointer beyond the ! 241: * next JS_FinishCodeGenerator. ! 242: */ ! 243: extern JS_FRIEND_API(void) ! 244: js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg); ! 245: ! 246: /* ! 247: * Emit one bytecode. ! 248: */ ! 249: extern ptrdiff_t ! 250: js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op); ! 251: ! 252: /* ! 253: * Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1). ! 254: */ ! 255: extern ptrdiff_t ! 256: js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1); ! 257: ! 258: /* ! 259: * Emit three bytecodes, an opcode with two bytes of immediate operands. ! 260: */ ! 261: extern ptrdiff_t ! 262: js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1, ! 263: jsbytecode op2); ! 264: ! 265: /* ! 266: * Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand. ! 267: */ ! 268: extern ptrdiff_t ! 269: js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra); ! 270: ! 271: /* ! 272: * Unsafe macro to call js_SetJumpOffset and return false if it does. ! 273: */ ! 274: #define CHECK_AND_SET_JUMP_OFFSET(cx,cg,pc,off) \ ! 275: JS_BEGIN_MACRO \ ! 276: if (!js_SetJumpOffset(cx, cg, pc, off)) \ ! 277: return JS_FALSE; \ ! 278: JS_END_MACRO ! 279: ! 280: #define CHECK_AND_SET_JUMP_OFFSET_AT(cx,cg,off) \ ! 281: CHECK_AND_SET_JUMP_OFFSET(cx, cg, CG_CODE(cg,off), CG_OFFSET(cg) - (off)) ! 282: ! 283: extern JSBool ! 284: js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, ! 285: ptrdiff_t off); ! 286: ! 287: /* Test whether we're in a with statement. */ ! 288: extern JSBool ! 289: js_InWithStatement(JSTreeContext *tc); ! 290: ! 291: /* Test whether we're in a catch block with exception named by atom. */ ! 292: extern JSBool ! 293: js_InCatchBlock(JSTreeContext *tc, JSAtom *atom); ! 294: ! 295: /* ! 296: * Push the C-stack-allocated struct at stmt onto the stmtInfo stack. ! 297: */ ! 298: extern void ! 299: js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, ! 300: ptrdiff_t top); ! 301: ! 302: /* ! 303: * Pop tc->topStmt. If the top JSStmtInfo struct is not stack-allocated, it ! 304: * is up to the caller to free it. ! 305: */ ! 306: extern void ! 307: js_PopStatement(JSTreeContext *tc); ! 308: ! 309: /* ! 310: * Like js_PopStatement(&cg->treeContext), also patch breaks and continues. ! 311: * May fail if a jump offset overflows. ! 312: */ ! 313: extern JSBool ! 314: js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg); ! 315: ! 316: /* ! 317: * Emit code into cg for the tree rooted at pn. ! 318: */ ! 319: extern JSBool ! 320: js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn); ! 321: ! 322: /* ! 323: * Emit code into cg for the tree rooted at body, then create a persistent ! 324: * script for fun from cg. ! 325: */ ! 326: extern JSBool ! 327: js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body, ! 328: JSFunction *fun); ! 329: ! 330: /* ! 331: * Source notes generated along with bytecode for decompiling and debugging. ! 332: * A source note is a uint8 with 5 bits of type and 3 of offset from the pc of ! 333: * the previous note. If 3 bits of offset aren't enough, extended delta notes ! 334: * (SRC_XDELTA) consisting of 2 set high order bits followed by 6 offset bits ! 335: * are emitted before the next note. Some notes have operand offsets encoded ! 336: * immediately after them, in note bytes or byte-triples. ! 337: * ! 338: * Source Note Extended Delta ! 339: * +7-6-5-4-3+2-1-0+ +7-6-5+4-3-2-1-0+ ! 340: * |note-type|delta| |1 1| ext-delta | ! 341: * +---------+-----+ +---+-----------+ ! 342: * ! 343: * At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE, ! 344: * SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode. ! 345: * ! 346: * NB: the js_SrcNoteSpec array in jsemit.c is indexed by this enum, so its ! 347: * initializers need to match the order here. ! 348: */ ! 349: typedef enum JSSrcNoteType { ! 350: SRC_NULL = 0, /* terminates a note vector */ ! 351: SRC_IF = 1, /* JSOP_IFEQ bytecode is from an if-then */ ! 352: SRC_IF_ELSE = 2, /* JSOP_IFEQ bytecode is from an if-then-else */ ! 353: SRC_WHILE = 3, /* JSOP_IFEQ is from a while loop */ ! 354: SRC_FOR = 4, /* JSOP_NOP or JSOP_POP in for loop head */ ! 355: SRC_CONTINUE = 5, /* JSOP_GOTO is a continue, not a break; ! 356: also used on JSOP_ENDINIT if extra comma ! 357: at end of array literal: [1,2,,] */ ! 358: SRC_VAR = 6, /* JSOP_NAME/SETNAME/FORNAME in a var decl */ ! 359: SRC_PCDELTA = 7, /* offset from comma-operator to next POP, ! 360: or from CONDSWITCH to first CASE opcode */ ! 361: SRC_ASSIGNOP = 8, /* += or another assign-op follows */ ! 362: SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */ ! 363: SRC_RESERVED0 = 10, /* reserved for future use */ ! 364: SRC_HIDDEN = 11, /* opcode shouldn't be decompiled */ ! 365: SRC_PCBASE = 12, /* offset of first obj.prop.subprop bytecode */ ! 366: SRC_LABEL = 13, /* JSOP_NOP for label: with atomid immediate */ ! 367: SRC_LABELBRACE = 14, /* JSOP_NOP for label: {...} begin brace */ ! 368: SRC_ENDBRACE = 15, /* JSOP_NOP for label: {...} end brace */ ! 369: SRC_BREAK2LABEL = 16, /* JSOP_GOTO for 'break label' with atomid */ ! 370: SRC_CONT2LABEL = 17, /* JSOP_GOTO for 'continue label' with atomid */ ! 371: SRC_SWITCH = 18, /* JSOP_*SWITCH with offset to end of switch, ! 372: 2nd off to first JSOP_CASE if condswitch */ ! 373: SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */ ! 374: SRC_CATCH = 20, /* catch block has guard */ ! 375: SRC_CONST = 21, /* JSOP_SETCONST in a const decl */ ! 376: SRC_NEWLINE = 22, /* bytecode follows a source newline */ ! 377: SRC_SETLINE = 23, /* a file-absolute source line number note */ ! 378: SRC_XDELTA = 24 /* 24-31 are for extended delta notes */ ! 379: } JSSrcNoteType; ! 380: ! 381: #define SN_TYPE_BITS 5 ! 382: #define SN_DELTA_BITS 3 ! 383: #define SN_XDELTA_BITS 6 ! 384: #define SN_TYPE_MASK (JS_BITMASK(SN_TYPE_BITS) << SN_DELTA_BITS) ! 385: #define SN_DELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_DELTA_BITS)) ! 386: #define SN_XDELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_XDELTA_BITS)) ! 387: ! 388: #define SN_MAKE_NOTE(sn,t,d) (*(sn) = (jssrcnote) \ ! 389: (((t) << SN_DELTA_BITS) \ ! 390: | ((d) & SN_DELTA_MASK))) ! 391: #define SN_MAKE_XDELTA(sn,d) (*(sn) = (jssrcnote) \ ! 392: ((SRC_XDELTA << SN_DELTA_BITS) \ ! 393: | ((d) & SN_XDELTA_MASK))) ! 394: ! 395: #define SN_IS_XDELTA(sn) ((*(sn) >> SN_DELTA_BITS) >= SRC_XDELTA) ! 396: #define SN_TYPE(sn) (SN_IS_XDELTA(sn) ? SRC_XDELTA \ ! 397: : *(sn) >> SN_DELTA_BITS) ! 398: #define SN_SET_TYPE(sn,type) SN_MAKE_NOTE(sn, type, SN_DELTA(sn)) ! 399: #define SN_IS_GETTABLE(sn) (SN_TYPE(sn) < SRC_NEWLINE) ! 400: ! 401: #define SN_DELTA(sn) ((ptrdiff_t)(SN_IS_XDELTA(sn) \ ! 402: ? *(sn) & SN_XDELTA_MASK \ ! 403: : *(sn) & SN_DELTA_MASK)) ! 404: #define SN_SET_DELTA(sn,delta) (SN_IS_XDELTA(sn) \ ! 405: ? SN_MAKE_XDELTA(sn, delta) \ ! 406: : SN_MAKE_NOTE(sn, SN_TYPE(sn), delta)) ! 407: ! 408: #define SN_DELTA_LIMIT ((ptrdiff_t)JS_BIT(SN_DELTA_BITS)) ! 409: #define SN_XDELTA_LIMIT ((ptrdiff_t)JS_BIT(SN_XDELTA_BITS)) ! 410: ! 411: /* ! 412: * Offset fields follow certain notes and are frequency-encoded: an offset in ! 413: * [0,0x7f] consumes one byte, an offset in [0x80,0x7fffff] takes three, and ! 414: * the high bit of the first byte is set. ! 415: */ ! 416: #define SN_3BYTE_OFFSET_FLAG 0x80 ! 417: #define SN_3BYTE_OFFSET_MASK 0x7f ! 418: ! 419: typedef struct JSSrcNoteSpec { ! 420: const char *name; /* name for disassembly/debugging output */ ! 421: uint8 arity; /* number of offset operands */ ! 422: uint8 offsetBias; /* bias of offset(s) from annotated pc */ ! 423: int8 isSpanDep; /* 1 or -1 if offsets could span extended ops, ! 424: 0 otherwise; sign tells span direction */ ! 425: } JSSrcNoteSpec; ! 426: ! 427: extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[]; ! 428: extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn); ! 429: ! 430: #define SN_LENGTH(sn) ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \ ! 431: : js_SrcNoteLength(sn)) ! 432: #define SN_NEXT(sn) ((sn) + SN_LENGTH(sn)) ! 433: ! 434: /* A source note array is terminated by an all-zero element. */ ! 435: #define SN_MAKE_TERMINATOR(sn) (*(sn) = SRC_NULL) ! 436: #define SN_IS_TERMINATOR(sn) (*(sn) == SRC_NULL) ! 437: ! 438: /* ! 439: * Append a new source note of the given type (and therefore size) to cg's ! 440: * notes dynamic array, updating cg->noteCount. Return the new note's index ! 441: * within the array pointed at by cg->current->notes. Return -1 if out of ! 442: * memory. ! 443: */ ! 444: extern intN ! 445: js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type); ! 446: ! 447: extern intN ! 448: js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, ! 449: ptrdiff_t offset); ! 450: ! 451: extern intN ! 452: js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, ! 453: ptrdiff_t offset1, ptrdiff_t offset2); ! 454: ! 455: /* ! 456: * NB: this function can add at most one extra extended delta note. ! 457: */ ! 458: extern jssrcnote * ! 459: js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn, ! 460: ptrdiff_t delta); ! 461: ! 462: /* ! 463: * Get and set the offset operand identified by which (0 for the first, etc.). ! 464: */ ! 465: extern JS_FRIEND_API(ptrdiff_t) ! 466: js_GetSrcNoteOffset(jssrcnote *sn, uintN which); ! 467: ! 468: extern JSBool ! 469: js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, ! 470: uintN which, ptrdiff_t offset); ! 471: ! 472: /* ! 473: * Finish taking source notes in cx's notePool, copying final notes to the new ! 474: * stable store allocated by the caller and passed in via notes. Return false ! 475: * on malloc failure, which means this function reported an error. ! 476: * ! 477: * To compute the number of jssrcnotes to allocate and pass in via notes, use ! 478: * the CG_COUNT_FINAL_SRCNOTES macro. This macro knows a lot about details of ! 479: * js_FinishTakingSrcNotes, SO DON'T CHANGE jsemit.c's js_FinishTakingSrcNotes ! 480: * FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES! ! 481: */ ! 482: #define CG_COUNT_FINAL_SRCNOTES(cg, cnt) \ ! 483: JS_BEGIN_MACRO \ ! 484: ptrdiff_t diff_ = CG_PROLOG_OFFSET(cg) - (cg)->prolog.lastNoteOffset; \ ! 485: cnt = (cg)->prolog.noteCount + (cg)->main.noteCount + 1; \ ! 486: if ((cg)->prolog.noteCount && \ ! 487: (cg)->prolog.currentLine != (cg)->firstLine) { \ ! 488: if (diff_ > SN_DELTA_MASK) \ ! 489: cnt += JS_HOWMANY(diff_ - SN_DELTA_MASK, SN_XDELTA_MASK); \ ! 490: cnt += 2 + (((cg)->firstLine > SN_3BYTE_OFFSET_MASK) << 1); \ ! 491: } else if (diff_ > 0) { \ ! 492: if (cg->main.noteCount) { \ ! 493: jssrcnote *sn_ = (cg)->main.notes; \ ! 494: diff_ -= SN_IS_XDELTA(sn_) \ ! 495: ? SN_XDELTA_MASK - (*sn_ & SN_XDELTA_MASK) \ ! 496: : SN_DELTA_MASK - (*sn_ & SN_DELTA_MASK); \ ! 497: } \ ! 498: if (diff_ > 0) \ ! 499: cnt += JS_HOWMANY(diff_, SN_XDELTA_MASK); \ ! 500: } \ ! 501: JS_END_MACRO ! 502: ! 503: extern JSBool ! 504: js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes); ! 505: ! 506: /* ! 507: * Allocate cg->treeContext.tryCount notes (plus one for the end sentinel) ! 508: * from cx->tempPool and set up cg->tryBase/tryNext for exactly tryCount ! 509: * js_NewTryNote calls. The storage is freed by js_FinishCodeGenerator. ! 510: */ ! 511: extern JSBool ! 512: js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg); ! 513: ! 514: /* ! 515: * Grab the next trynote slot in cg, filling it in appropriately. ! 516: */ ! 517: extern JSTryNote * ! 518: js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start, ! 519: ptrdiff_t end, ptrdiff_t catchStart); ! 520: ! 521: /* ! 522: * Finish generating exception information into the space at notes. As with ! 523: * js_FinishTakingSrcNotes, the caller must use CG_COUNT_FINAL_TRYNOTES(cg) to ! 524: * preallocate enough space in a JSTryNote[] to pass as the notes parameter of ! 525: * js_FinishTakingTryNotes. ! 526: */ ! 527: #define CG_COUNT_FINAL_TRYNOTES(cg, cnt) \ ! 528: JS_BEGIN_MACRO \ ! 529: cnt = ((cg)->tryNext > (cg)->tryBase) \ ! 530: ? PTRDIFF(cg->tryNext, cg->tryBase, JSTryNote) + 1 \ ! 531: : 0; \ ! 532: JS_END_MACRO ! 533: ! 534: extern void ! 535: js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg, JSTryNote *notes); ! 536: ! 537: JS_END_EXTERN_C ! 538: ! 539: #endif /* jsemit_h___ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.