home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / js / src / jsemit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  20.4 KB  |  783 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. /*
  20.  * JS bytecode generation.
  21.  */
  22. #include <memory.h>
  23. #include <stddef.h>
  24. #include <string.h>
  25. #include "prtypes.h"
  26. #ifndef NSPR20
  27. #include "prarena.h"
  28. #else
  29. #include "plarena.h"
  30. #endif
  31. #include "prlog.h"
  32. #include "jsapi.h"
  33. #include "jscntxt.h"
  34. #include "jsemit.h"
  35. #include "jsopcode.h"
  36.  
  37. #define CGINCR  256     /* code generation bytecode allocation increment */
  38. #define SNINCR  64      /* source note allocation increment */
  39.  
  40. JS_FRIEND_API(JSBool)
  41. js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, PRArenaPool *pool)
  42. {
  43.     cg->pool = pool;
  44.     PR_ARENA_ALLOCATE(cg->base, pool, CGINCR);
  45.     if (!cg->base) {
  46.     JS_ReportOutOfMemory(cx);
  47.     return JS_FALSE;
  48.     }
  49.     cg->limit = CG_CODE(cg, CGINCR);
  50.     CG_RESET(cg);
  51.     return JS_TRUE;
  52. }
  53.  
  54. static ptrdiff_t
  55. EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, intN delta)
  56. {
  57.     ptrdiff_t offset, length;
  58.     size_t cgsize;
  59.  
  60.     PR_ASSERT(delta < CGINCR);
  61.     offset = CG_OFFSET(cg);
  62.     if (op != JSOP_NOP)
  63.     cg->lastCodeOffset = offset;
  64.     if ((pruword)cg->ptr + delta >= (pruword)cg->limit) {
  65.         length = cg->limit - cg->base;
  66.     cgsize = length * sizeof(jsbytecode);
  67.         PR_ARENA_GROW(cg->base, cg->pool, cgsize, CGINCR);
  68.     if (!cg->base) {
  69.         JS_ReportOutOfMemory(cx);
  70.         return -1;
  71.     }
  72.         cg->limit = CG_CODE(cg, length + CGINCR);
  73.         cg->ptr = CG_CODE(cg, offset);
  74.     }
  75.     return offset;
  76. }
  77.  
  78. /*
  79.  * Cancel the last instruction.  This can't be called more than once between
  80.  * bytecode generations using cg.  Most of the work involves finding and then
  81.  * cancelling any related source notes.
  82.  */
  83. void
  84. js_CancelLastOpcode(JSContext *cx, JSCodeGenerator *cg, uint16 *newlinesp)
  85. {
  86.     ptrdiff_t offset, lastCodeOffset;
  87.     ptrdiff_t shrink, delta;
  88.     JSCodeSpec *cs;
  89.     jssrcnote *sn, *last, *next;
  90.  
  91.     lastCodeOffset = cg->lastCodeOffset;
  92.     shrink = CG_OFFSET(cg) - lastCodeOffset;
  93.     if (shrink <= 0)
  94.     return;
  95.  
  96.     cg->ptr = CG_CODE(cg, lastCodeOffset);
  97.     cs = &js_CodeSpec[*cg->ptr];
  98.     PR_ASSERT(cs->nuses >= 0);
  99.     cg->stackDepth += cs->nuses;
  100.     cg->stackDepth -= cs->ndefs;
  101.  
  102.     if (cg->noteCount) {
  103.     offset = cg->saveNoteOffset;
  104.     last = &cg->notes[cg->lastNoteCount];
  105.     for (sn = &cg->notes[cg->saveNoteCount]; sn <= last; sn = next) {
  106.         next = SN_NEXT(sn);
  107.         delta = SN_DELTA(sn);
  108.         offset += delta;
  109.         if (offset == lastCodeOffset) {
  110.         /* The canceled op may not have any non-newline note. */
  111.         if (SN_IS_GETTABLE(sn)) {
  112.             SN_MAKE_TERMINATOR(sn);
  113.             cg->noteCount = cg->saveNoteCount;
  114.             cg->lastNoteOffset = cg->saveNoteOffset;
  115.  
  116.             /* Clear so we'll know to increment *newlinesp below. */
  117.             shrink = 0;
  118.         }
  119.         } else if (offset > lastCodeOffset) {
  120.         /* Notes after the canceled op are newlines or xdeltas. */
  121.         if (shrink == 0) {
  122.             if (SN_TYPE(sn) == SRC_NEWLINE) {
  123.             /* Newlines after the canceled op are pushed back. */
  124.             (*newlinesp)++;
  125.             }
  126.         } else if (delta >= shrink) {
  127.             /* If there's enough delta to take away shrink, do it. */
  128.             delta -= shrink;
  129.             SN_SET_DELTA(sn, delta);
  130.         }
  131.         }
  132.     }
  133.     }
  134. }
  135.  
  136. void
  137. js_UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target)
  138. {
  139.     jsbytecode *pc;
  140.     jssrcnote *sn, *last;
  141.     ptrdiff_t offset;
  142.     JSCodeSpec *cs;
  143.     intN nuses;
  144.  
  145.     pc = CG_CODE(cg, target);
  146.  
  147.     /*
  148.      * If there are source notes, check for hidden JSOP_LEAVEWITH created when
  149.      * breaking or continuing out of a with statement, or a JSOP_POP generated
  150.      * when breaking or continuing out of a for/in loop.  The compiler ensures
  151.      * stack balance for such bytecodes, but if we account for their popping
  152.      * here, we'll misreport an underflow.
  153.      */
  154.     if (cg->noteCount) {
  155.     sn = cg->notes;
  156.     last = &sn[cg->saveNoteCount];
  157.     if (SN_TYPE(last) == SRC_HIDDEN) {
  158.         /* We must ensure that this source note applies to target. */
  159.         for (offset = 0; sn <= last; sn = SN_NEXT(sn)) {
  160.         offset += SN_DELTA(sn);
  161.         if (offset == target && sn == last)
  162.             return;
  163.         }
  164.     }
  165.     }
  166.  
  167.     cs = &js_CodeSpec[pc[0]];
  168.     nuses = cs->nuses;
  169.     if (nuses < 0)
  170.         nuses = 2 + GET_ARGC(pc);    /* stack: fun, this, [argc arguments] */
  171.     cg->stackDepth -= nuses;
  172.     if (cg->stackDepth < 0)
  173.         JS_ReportError(cx, "internal error: stack underflow at pc %d", target);
  174.     cg->stackDepth += cs->ndefs;
  175.     if ((uintN)cg->stackDepth > cg->maxStackDepth)
  176.         cg->maxStackDepth = cg->stackDepth;
  177. }
  178.  
  179. ptrdiff_t
  180. js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op)
  181. {
  182.     ptrdiff_t offset = EmitCheck(cx, cg, op, 1);
  183.  
  184.     if (offset >= 0) {
  185.     *cg->ptr++ = (jsbytecode)op;
  186.     js_UpdateDepth(cx, cg, offset);
  187.     }
  188.     return offset;
  189. }
  190.  
  191. ptrdiff_t
  192. js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1)
  193. {
  194.     ptrdiff_t offset = EmitCheck(cx, cg, op, 2);
  195.  
  196.     if (offset >= 0) {
  197.     cg->ptr[0] = (jsbytecode)op;
  198.     cg->ptr[1] = op1;
  199.     cg->ptr += 2;
  200.     js_UpdateDepth(cx, cg, offset);
  201.     }
  202.     return offset;
  203. }
  204.  
  205. ptrdiff_t
  206. js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1,
  207.      jsbytecode op2)
  208. {
  209.     ptrdiff_t offset = EmitCheck(cx, cg, op, 3);
  210.  
  211.     if (offset >= 0) {
  212.     cg->ptr[0] = (jsbytecode)op;
  213.     cg->ptr[1] = op1;
  214.     cg->ptr[2] = op2;
  215.     cg->ptr += 3;
  216.     js_UpdateDepth(cx, cg, offset);
  217.     }
  218.     return offset;
  219. }
  220.  
  221. static const char *statementName[] = {
  222.     "block",            /* BLOCK */
  223.     "label statement",  /* LABEL */
  224.     "if statement",     /* IF */
  225.     "else statement",   /* ELSE */
  226.     "switch statement", /* SWITCH */
  227.     "with statement",   /* WITH */
  228.     "do loop",          /* DO_LOOP */
  229.     "for loop",         /* FOR_LOOP */
  230.     "for/in loop",      /* FOR_IN_LOOP */
  231.     "while loop",       /* WHILE_LOOP */
  232. };
  233.  
  234. static const char *
  235. StatementName(JSCodeGenerator *cg)
  236. {
  237.     if (!cg || !cg->stmtInfo)
  238.     return "script";
  239.     return statementName[cg->stmtInfo->type];
  240. }
  241.  
  242. static void
  243. ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg)
  244. {
  245.     JS_ReportError(cx, "%s too large", StatementName(cg));
  246. }
  247.  
  248. JSBool
  249. js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
  250.          ptrdiff_t off)
  251. {
  252.     if (off < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < off) {
  253.     ReportStatementTooLarge(cx, cg);
  254.     return JS_FALSE;
  255.     }
  256.     SET_JUMP_OFFSET(pc, off);
  257.     return JS_TRUE;
  258. }
  259.  
  260. /* Forward declaration to keep MoveGotos after PatchGotos. */
  261. static void
  262. MoveGotos(JSCodeGenerator *cg, StmtInfo *stmt, ptrdiff_t last, ptrdiff_t first,
  263.       ptrdiff_t growth);
  264.  
  265. ptrdiff_t
  266. js_MoveCode(JSContext *cx,
  267.         JSCodeGenerator *from, ptrdiff_t fromOffset,
  268.         JSCodeGenerator *to, ptrdiff_t toOffset)
  269. {
  270.     ptrdiff_t length, growth, offset, saveOffset;
  271.     StmtInfo *stmt;
  272.  
  273.     length = CG_OFFSET(from) - fromOffset;
  274.     growth = (toOffset + length) - CG_OFFSET(to);
  275.     saveOffset = to->lastCodeOffset;
  276.     offset = EmitCheck(cx, to, *CG_CODE(from, from->lastCodeOffset), growth);
  277.     if (offset >= 0) {
  278.     memmove(CG_CODE(to, toOffset), CG_CODE(from, fromOffset), length);
  279.     to->ptr += growth;
  280.     if (to == from) {
  281.         growth = toOffset - fromOffset;
  282.         for (stmt = to->stmtInfo; stmt; stmt = stmt->down) {
  283.         if (stmt->top >= fromOffset)
  284.             stmt->top += growth;
  285.         if (stmt->update >= fromOffset)
  286.             stmt->update += growth;
  287.         if (stmt->breaks >= fromOffset) {
  288.             stmt->breaks += growth;
  289.             MoveGotos(to, stmt, stmt->breaks, toOffset, growth);
  290.         }
  291.         if (stmt->continues >= fromOffset) {
  292.             stmt->continues += growth;
  293.             MoveGotos(to, stmt, stmt->continues, toOffset, growth);
  294.         }
  295.         }
  296.         to->lastCodeOffset = saveOffset + growth;
  297.     } else {
  298.         /* For now, we handle expressions only, not statements. */
  299.         PR_ASSERT(!from->stmtInfo);
  300.         to->lastCodeOffset += from->lastCodeOffset - fromOffset;
  301.         if (from->maxStackDepth > to->maxStackDepth)
  302.         to->maxStackDepth = from->maxStackDepth;
  303.     }
  304.     }
  305.     return offset;
  306. }
  307.  
  308. void
  309. js_PushStatement(JSCodeGenerator *cg, StmtInfo *stmt, StmtType type,
  310.          ptrdiff_t top)
  311. {
  312.     stmt->type = type;
  313.     SET_STATEMENT_TOP(stmt, top);
  314.     stmt->label = NULL;
  315.     stmt->down = cg->stmtInfo;
  316.     cg->stmtInfo = stmt;
  317. }
  318.  
  319. static ptrdiff_t
  320. EmitGoto(JSContext *cx, JSCodeGenerator *cg, StmtInfo *toStmt,
  321.      ptrdiff_t *last, JSAtom *label, JSSrcNoteType noteType)
  322. {
  323.     StmtInfo *stmt;
  324.     intN index;
  325.     ptrdiff_t offset, delta;
  326.  
  327.     for (stmt = cg->stmtInfo; stmt != toStmt; stmt = stmt->down) {
  328.     switch (stmt->type) {
  329.       case STMT_WITH:
  330.         if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
  331.         js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) {
  332.         return -1;
  333.         }
  334.         break;
  335.       case STMT_FOR_IN_LOOP:
  336.         if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
  337.         js_Emit1(cx, cg, JSOP_POP) < 0) {
  338.         return -1;
  339.         }
  340.         break;
  341.       default:;
  342.     }
  343.     }
  344.  
  345.     if (label) {
  346.     index = js_NewSrcNote(cx, cg, noteType);
  347.     if (index < 0)
  348.         return -1;
  349.     if (!js_SetSrcNoteOffset(cx, cg, (uintN)index, 0,
  350.                  (ptrdiff_t)label->index)) {
  351.         return -1;
  352.     }
  353.     }
  354.  
  355.     offset = CG_OFFSET(cg);
  356.     delta = offset - *last;
  357.     *last = offset;
  358.     return js_Emit3(cx, cg, JSOP_GOTO,
  359.             JUMP_OFFSET_HI(delta), JUMP_OFFSET_LO(delta));
  360. }
  361.  
  362. static JSBool
  363. PatchGotos(JSContext *cx, JSCodeGenerator *cg, StmtInfo *stmt, ptrdiff_t last,
  364.        jsbytecode *target)
  365. {
  366.     jsbytecode *pc, *top;
  367.     ptrdiff_t delta, jumpOffset;
  368.  
  369.     pc = CG_CODE(cg, last);
  370.     top = CG_CODE(cg, stmt->top);
  371.     while (pc > top) {
  372.     PR_ASSERT(*pc == JSOP_GOTO);
  373.         delta = GET_JUMP_OFFSET(pc);
  374.         jumpOffset = target - pc;
  375.         CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, jumpOffset);
  376.         pc -= delta;
  377.     }
  378.     return JS_TRUE;
  379. }
  380.  
  381. static void
  382. MoveGotos(JSCodeGenerator *cg, StmtInfo *stmt, ptrdiff_t last, ptrdiff_t first,
  383.       ptrdiff_t growth)
  384. {
  385.     jsbytecode *pc, *top, *stop, *prev;
  386.     ptrdiff_t delta;
  387.  
  388.     pc = CG_CODE(cg, last);
  389.     top = CG_CODE(cg, stmt->top);
  390.     stop = CG_CODE(cg, first);
  391.     while (pc > top) {
  392.     PR_ASSERT(*pc == JSOP_GOTO);
  393.         delta = GET_JUMP_OFFSET(pc);
  394.     prev = pc - delta;
  395.     if (prev < stop) {
  396.         delta += growth;
  397.         SET_JUMP_OFFSET(pc, delta);
  398.         return;
  399.     }
  400.         pc = prev;
  401.     }
  402. }
  403.  
  404. ptrdiff_t
  405. js_EmitBreak(JSContext *cx, JSCodeGenerator *cg, StmtInfo *stmt,
  406.          JSAtom *label)
  407. {
  408.     return EmitGoto(cx, cg, stmt, &stmt->breaks, label, SRC_BREAK2LABEL);
  409. }
  410.  
  411. ptrdiff_t
  412. js_EmitContinue(JSContext *cx, JSCodeGenerator *cg, StmtInfo *stmt,
  413.         JSAtom *label)
  414. {
  415.     return EmitGoto(cx, cg, stmt, &stmt->continues, label, SRC_CONT2LABEL);
  416. }
  417.  
  418. JSBool
  419. js_PopStatement(JSContext *cx, JSCodeGenerator *cg)
  420. {
  421.     StmtInfo *stmt;
  422.  
  423.     stmt = cg->stmtInfo;
  424.     if (!PatchGotos(cx, cg, stmt, stmt->breaks, cg->ptr))
  425.     return JS_FALSE;
  426.     if (!PatchGotos(cx, cg, stmt, stmt->continues, CG_CODE(cg, stmt->update)))
  427.     return JS_FALSE;
  428.     cg->stmtInfo = stmt->down;
  429.     return JS_TRUE;
  430. }
  431.  
  432. const char *js_SrcNoteName[] = {
  433.     "null",
  434.     "if",
  435.     "if-else",
  436.     "while",
  437.     "for",
  438.     "continue",
  439.     "var",
  440.     "comma",
  441.     "assignop",
  442.     "cond",
  443.     "paren",
  444.     "hidden",
  445.     "pcbase",
  446.     "label",
  447.     "labelbrace",
  448.     "endbrace",
  449.     "break2label",
  450.     "cont2label",
  451.     "switch",
  452.     "unused19",
  453.     "unused20",
  454.     "unused21",
  455.     "newline",
  456.     "setline",
  457.     "xdelta"
  458. };
  459.  
  460. uint8 js_SrcNoteArity[] = {
  461.     0,  /* SRC_NULL */
  462.     0,  /* SRC_IF */
  463.     0,  /* SRC_IF_ELSE */
  464.     0,  /* SRC_WHILE */
  465.     3,  /* SRC_FOR */
  466.     0,  /* SRC_CONTINUE */
  467.     0,  /* SRC_VAR */
  468.     1,  /* SRC_COMMA */
  469.     0,  /* SRC_ASSIGNOP */
  470.     0,  /* SRC_COND */
  471.     0,  /* SRC_PAREN */
  472.     0,  /* SRC_HIDDEN */
  473.     1,  /* SRC_PCBASE */
  474.     1,  /* SRC_LABEL */
  475.     1,  /* SRC_LABELBRACE */
  476.     0,  /* SRC_ENDBRACE */
  477.     1,  /* SRC_BREAK2LABEL */
  478.     1,  /* SRC_CONT2LABEL */
  479.     1,  /* SRC_SWITCH */
  480.     0,  /* SRC_UNUSED19 */
  481.     0,  /* SRC_UNUSED20 */
  482.     0,  /* SRC_UNUSED21 */
  483.     0,  /* SRC_NEWLINE */
  484.     1,  /* SRC_SETLINE */
  485.     0   /* SRC_XDELTA */
  486. };
  487.  
  488. intN
  489. AllocSrcNote(JSContext *cx, JSCodeGenerator *cg)
  490. {
  491.     intN index;
  492.     PRArenaPool *pool;
  493.     size_t incr, size;
  494.  
  495.     index = cg->noteCount;
  496.     if (index % SNINCR == 0) {
  497.         pool = &cx->tempPool;
  498.     incr = SNINCR * sizeof(jssrcnote);
  499.         if (!cg->notes) {
  500.             PR_ARENA_ALLOCATE(cg->notes, pool, incr);
  501.         } else {
  502.         size = cg->noteCount * sizeof(jssrcnote);
  503.             PR_ARENA_GROW(cg->notes, pool, size, incr);
  504.         }
  505.     if (!cg->notes) {
  506.         JS_ReportOutOfMemory(cx);
  507.         return -1;
  508.     }
  509.     }
  510.  
  511.     cg->noteCount = index + 1;
  512.     return index;
  513. }
  514.  
  515. intN
  516. js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type)
  517. {
  518.     intN index, n;
  519.     jssrcnote *sn;
  520.     ptrdiff_t offset, saveOffset, delta, xdelta;
  521.  
  522.     /*
  523.      * Claim a note slot in cg->notes by growing it if necessary and then
  524.      * incrementing cg->noteCount.
  525.      */
  526.     index = AllocSrcNote(cx, cg);
  527.     sn = &cg->notes[index];
  528.  
  529.     /*
  530.      * Compute delta from the last annotated bytecode's offset.  If it's too
  531.      * big to fit in sn, allocate one or more xdelta notes and reset sn.
  532.      */
  533.     offset = CG_OFFSET(cg);
  534.     saveOffset = cg->lastNoteOffset;
  535.     delta = offset - saveOffset;
  536.     cg->lastNoteOffset = offset;
  537.     if (delta >= SN_DELTA_LIMIT) {
  538.     do {
  539.         xdelta = PR_MIN(delta, SN_XDELTA_MASK);
  540.         SN_MAKE_XDELTA(sn, xdelta);
  541.         delta -= xdelta;
  542.         index = js_NewSrcNote(cx, cg, SRC_NULL);
  543.         if (index < 0)
  544.         return -1;
  545.         sn = &cg->notes[index];
  546.     } while (delta >= SN_DELTA_LIMIT);
  547.     }
  548.  
  549.     /*
  550.      * Initialize type and delta, then allocate the minimum number of notes
  551.      * needed for type's arity.  Usually, we won't need more, but if an offset
  552.      * does take two bytes, js_SetSrcNoteOffset will grow cg->notes.
  553.      */
  554.     SN_MAKE_NOTE(sn, type, delta);
  555.     for (n = (intN)js_SrcNoteArity[type]; n > 0; n--) {
  556.         if (js_NewSrcNote(cx, cg, SRC_NULL) < 0)
  557.         return -1;
  558.     }
  559.  
  560.     /*
  561.      * Set lastNoteCount here, after any recursion, so it has the lowest
  562.      * index value among all note bytes allocated by the non-recursive call
  563.      * that claimed the first byte.
  564.      */
  565.     cg->lastNoteCount = index;
  566.     if (type != SRC_NULL && type < SRC_NEWLINE) {
  567.     cg->saveNoteCount = index;
  568.     cg->saveNoteOffset = saveOffset;
  569.     }
  570.     return index;
  571. }
  572.  
  573. intN
  574. js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
  575.            ptrdiff_t offset)
  576. {
  577.     intN index;
  578.  
  579.     index = js_NewSrcNote(cx, cg, type);
  580.     if (index >= 0) {
  581.     if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset))
  582.         return -1;
  583.     }
  584.     return index;
  585. }
  586.  
  587. intN
  588. js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
  589.            ptrdiff_t offset1, ptrdiff_t offset2)
  590. {
  591.     intN index;
  592.  
  593.     index = js_NewSrcNote(cx, cg, type);
  594.     if (index >= 0) {
  595.     if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset1))
  596.         return -1;
  597.     if (!js_SetSrcNoteOffset(cx, cg, index, 1, offset2))
  598.         return -1;
  599.     }
  600.     return index;
  601. }
  602.  
  603. static JSBool
  604. GrowSrcNotes(JSContext *cx, JSCodeGenerator *cg)
  605. {
  606.     PRArenaPool *pool;
  607.     size_t incr, size;
  608.  
  609.     pool = &cx->tempPool;
  610.     incr = SNINCR * sizeof(jssrcnote);
  611.     size = cg->noteCount * sizeof(jssrcnote);
  612.     PR_ARENA_GROW(cg->notes, pool, size, incr);
  613.     if (!cg->notes) {
  614.     JS_ReportOutOfMemory(cx);
  615.     return JS_FALSE;
  616.     }
  617.     return JS_TRUE;
  618. }
  619.  
  620. JSBool
  621. js_BumpSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, uintN index,
  622.             ptrdiff_t incr)
  623. {
  624.     jssrcnote *sn;
  625.     ptrdiff_t delta, limit, xdelta;
  626.     uintN length;
  627.  
  628.     sn = &cg->notes[index];
  629.     delta = SN_DELTA(sn) + incr;
  630.     limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
  631.     while (delta >= limit) {
  632.     length = cg->noteCount - index;
  633.     if (AllocSrcNote(cx, cg) < 0)
  634.         return JS_FALSE;
  635.     sn = &cg->notes[index];
  636.     memmove(sn + 1, sn, length * sizeof(jssrcnote));
  637.     xdelta = PR_MIN(delta, SN_XDELTA_LIMIT - 1);
  638.     SN_MAKE_XDELTA(sn, xdelta);
  639.     sn++;
  640.     delta -= xdelta;
  641.     }
  642.     SN_SET_DELTA(sn, delta);
  643.     cg->lastNoteOffset += incr;
  644.     if (index < cg->saveNoteCount)
  645.     cg->saveNoteOffset += incr;
  646.     return JS_TRUE;
  647. }
  648.  
  649. uintN
  650. js_SrcNoteLength(jssrcnote *sn)
  651. {
  652.     intN arity;
  653.     jssrcnote *base;
  654.  
  655.     arity = (intN)js_SrcNoteArity[SN_TYPE(sn)];
  656.     if (!arity)
  657.     return 1;
  658.     for (base = sn++; --arity >= 0; sn++) {
  659.     if (*sn & SN_2BYTE_OFFSET_FLAG)
  660.         sn++;
  661.     }
  662.     return sn - base;
  663. }
  664.  
  665. ptrdiff_t
  666. js_GetSrcNoteOffset(jssrcnote *sn, uintN which)
  667. {
  668.     /* Find the offset numbered which (i.e., skip exactly which offsets). */
  669.     PR_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
  670.     PR_ASSERT(which < js_SrcNoteArity[SN_TYPE(sn)]);
  671.     for (sn++; which; sn++, which--) {
  672.     if (*sn & SN_2BYTE_OFFSET_FLAG)
  673.         sn++;
  674.     }
  675.     if (*sn & SN_2BYTE_OFFSET_FLAG)
  676.     return (ptrdiff_t)((*sn & SN_2BYTE_OFFSET_MASK) << 8) | sn[1];
  677.     return (ptrdiff_t)*sn;
  678. }
  679.  
  680. JSBool
  681. js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
  682.             uintN which, ptrdiff_t offset)
  683. {
  684.     jssrcnote *sn;
  685.     ptrdiff_t diff;
  686.  
  687.     if ((size_t)offset >= (size_t)(SN_2BYTE_OFFSET_FLAG << 8)) {
  688.     ReportStatementTooLarge(cx, cg);
  689.     return JS_FALSE;
  690.     }
  691.  
  692.     /* Find the offset numbered which (i.e., skip exactly which offsets). */
  693.     sn = &cg->notes[index];
  694.     PR_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
  695.     PR_ASSERT(which < js_SrcNoteArity[SN_TYPE(sn)]);
  696.     for (sn++; which; sn++, which--) {
  697.     if (*sn & SN_2BYTE_OFFSET_FLAG)
  698.         sn++;
  699.     }
  700.  
  701.     /* See if the new offset requires two bytes. */
  702.     if ((uintN)offset > (uintN)SN_2BYTE_OFFSET_MASK) {
  703.     /* Maybe this offset was already set to a two-byte value. */
  704.     if (!(*sn & SN_2BYTE_OFFSET_FLAG)) {
  705.         /* Losing, need to insert another byte for this offset. */
  706.         index = sn - cg->notes;
  707.         if (cg->noteCount++ % SNINCR == 0) {
  708.         if (!GrowSrcNotes(cx, cg))
  709.             return JS_FALSE;
  710.         sn = cg->notes + index;
  711.         }
  712.         diff = cg->noteCount - (index + 2);
  713.         if (diff > 0)
  714.         memmove(sn + 2, sn + 1, diff * sizeof(jssrcnote));
  715.     }
  716.     *sn++ = (jssrcnote)(SN_2BYTE_OFFSET_FLAG | (offset >> 8));
  717.     }
  718.     *sn = (jssrcnote)offset;
  719.     return JS_TRUE;
  720. }
  721.  
  722. JSBool
  723. js_MoveSrcNotes(JSContext *cx, JSCodeGenerator *from, JSCodeGenerator *to)
  724. {
  725.     intN i, j, length, index;
  726.     jssrcnote *sn;
  727.     JSSrcNoteType type;
  728.     ptrdiff_t delta, limit, xdelta;
  729.  
  730.     PR_ASSERT(from != to);
  731.     for (i = 0; (uintN)i < from->noteCount; i += length) {
  732.     length = SN_LENGTH(&from->notes[i]);
  733.     type = SN_TYPE(&from->notes[i]);
  734.     index = js_NewSrcNote(cx, to, type);
  735.     if (index < 0)
  736.         return JS_FALSE;
  737.     for (j = (intN)js_SrcNoteArity[type]; --j >= 0; ) {
  738.         if (!js_SetSrcNoteOffset(cx, to, index, j,
  739.                      js_GetSrcNoteOffset(&from->notes[i], j))) {
  740.         return JS_FALSE;
  741.         }
  742.     }
  743.     delta = SN_DELTA(&from->notes[i]);
  744.     to->lastNoteOffset += delta;
  745.     sn = &to->notes[index];
  746.     if (i == 0) {
  747.         /* First note's delta must count bytecodes from last note in to. */
  748.         delta += SN_DELTA(sn);
  749.         limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
  750.         if (delta >= limit) {
  751.         do {
  752.             xdelta = PR_MIN(delta, SN_XDELTA_MASK);
  753.             SN_MAKE_XDELTA(sn, xdelta);
  754.             delta -= xdelta;
  755.             index = js_NewSrcNote(cx, to, SRC_NULL);
  756.             if (index < 0)
  757.             return JS_FALSE;
  758.             sn = &to->notes[index];
  759.         } while (delta >= limit);
  760.         }
  761.     }
  762.     SN_SET_DELTA(sn, delta);
  763.     }
  764.     return JS_TRUE;
  765. }
  766.  
  767. JS_FRIEND_API(jssrcnote *)
  768. js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg)
  769. {
  770.     uintN count;
  771.     jssrcnote *tmp, *final;
  772.  
  773.     count = cg->noteCount;
  774.     tmp   = cg->notes;
  775.     final = JS_malloc(cx, (count + 1) * sizeof(jssrcnote));
  776.     if (!final)
  777.     return NULL;
  778.     memcpy(final, tmp, count * sizeof(jssrcnote));
  779.     SN_MAKE_TERMINATOR(&final[count]);
  780.     CG_RESET_NOTES(cg);
  781.     return final;
  782. }
  783.