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