⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jsemit.c

📁 java script test programing source code
💻 C
📖 第 1 页 / 共 5 页
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sw=4 et tw=78: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * JS bytecode generation. */#include "jsstddef.h"#ifdef HAVE_MEMORY_H#include <memory.h>#endif#include <string.h>#include "jstypes.h"#include "jsarena.h" /* Added by JSIFY */#include "jsutil.h" /* Added by JSIFY */#include "jsbit.h"#include "jsprf.h"#include "jsapi.h"#include "jsatom.h"#include "jscntxt.h"#include "jsconfig.h"#include "jsemit.h"#include "jsfun.h"#include "jsnum.h"#include "jsopcode.h"#include "jsparse.h"#include "jsregexp.h"#include "jsscan.h"#include "jsscope.h"#include "jsscript.h"/* Allocation chunk counts, must be powers of two in general. */#define BYTECODE_CHUNK  256     /* code allocation increment */#define SRCNOTE_CHUNK   64      /* initial srcnote allocation increment */#define TRYNOTE_CHUNK   64      /* trynote allocation increment *//* Macros to compute byte sizes from typed element counts. */#define BYTECODE_SIZE(n)        ((n) * sizeof(jsbytecode))#define SRCNOTE_SIZE(n)         ((n) * sizeof(jssrcnote))#define TRYNOTE_SIZE(n)         ((n) * sizeof(JSTryNote))JS_FRIEND_API(JSBool)js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg,                     JSArenaPool *codePool, JSArenaPool *notePool,                     const char *filename, uintN lineno,                     JSPrincipals *principals){    memset(cg, 0, sizeof *cg);    TREE_CONTEXT_INIT(&cg->treeContext);    cg->treeContext.flags |= TCF_COMPILING;    cg->codePool = codePool;    cg->notePool = notePool;    cg->codeMark = JS_ARENA_MARK(codePool);    cg->noteMark = JS_ARENA_MARK(notePool);    cg->tempMark = JS_ARENA_MARK(&cx->tempPool);    cg->current = &cg->main;    cg->filename = filename;    cg->firstLine = cg->prolog.currentLine = cg->main.currentLine = lineno;    cg->principals = principals;    ATOM_LIST_INIT(&cg->atomList);    cg->prolog.noteMask = cg->main.noteMask = SRCNOTE_CHUNK - 1;    ATOM_LIST_INIT(&cg->constList);    return JS_TRUE;}JS_FRIEND_API(void)js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg){    TREE_CONTEXT_FINISH(&cg->treeContext);    JS_ARENA_RELEASE(cg->codePool, cg->codeMark);    JS_ARENA_RELEASE(cg->notePool, cg->noteMark);    JS_ARENA_RELEASE(&cx->tempPool, cg->tempMark);}static ptrdiff_tEmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta){    jsbytecode *base, *limit, *next;    ptrdiff_t offset, length;    size_t incr, size;    base = CG_BASE(cg);    next = CG_NEXT(cg);    limit = CG_LIMIT(cg);    offset = PTRDIFF(next, base, jsbytecode);    if (next + delta > limit) {        length = offset + delta;        length = (length <= BYTECODE_CHUNK)                 ? BYTECODE_CHUNK                 : JS_BIT(JS_CeilingLog2(length));        incr = BYTECODE_SIZE(length);        if (!base) {            JS_ARENA_ALLOCATE_CAST(base, jsbytecode *, cg->codePool, incr);        } else {            size = BYTECODE_SIZE(PTRDIFF(limit, base, jsbytecode));            incr -= size;            JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);        }        if (!base) {            JS_ReportOutOfMemory(cx);            return -1;        }        CG_BASE(cg) = base;        CG_LIMIT(cg) = base + length;        CG_NEXT(cg) = base + offset;    }    return offset;}static voidUpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target){    jsbytecode *pc;    const JSCodeSpec *cs;    intN nuses;    pc = CG_CODE(cg, target);    cs = &js_CodeSpec[pc[0]];    nuses = cs->nuses;    if (nuses < 0)        nuses = 2 + GET_ARGC(pc);       /* stack: fun, this, [argc arguments] */    cg->stackDepth -= nuses;    JS_ASSERT(cg->stackDepth >= 0);    if (cg->stackDepth < 0) {        char numBuf[12];        JS_snprintf(numBuf, sizeof numBuf, "%d", target);        JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING,                                     js_GetErrorMessage, NULL,                                     JSMSG_STACK_UNDERFLOW,                                     cg->filename ? cg->filename : "stdin",                                     numBuf);    }    cg->stackDepth += cs->ndefs;    if ((uintN)cg->stackDepth > cg->maxStackDepth)        cg->maxStackDepth = cg->stackDepth;}ptrdiff_tjs_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op){    ptrdiff_t offset = EmitCheck(cx, cg, op, 1);    if (offset >= 0) {        *CG_NEXT(cg)++ = (jsbytecode)op;        UpdateDepth(cx, cg, offset);    }    return offset;}ptrdiff_tjs_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1){    ptrdiff_t offset = EmitCheck(cx, cg, op, 2);    if (offset >= 0) {        jsbytecode *next = CG_NEXT(cg);        next[0] = (jsbytecode)op;        next[1] = op1;        CG_NEXT(cg) = next + 2;        UpdateDepth(cx, cg, offset);    }    return offset;}ptrdiff_tjs_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1,         jsbytecode op2){    ptrdiff_t offset = EmitCheck(cx, cg, op, 3);    if (offset >= 0) {        jsbytecode *next = CG_NEXT(cg);        next[0] = (jsbytecode)op;        next[1] = op1;        next[2] = op2;        CG_NEXT(cg) = next + 3;        UpdateDepth(cx, cg, offset);    }    return offset;}ptrdiff_tjs_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra){    ptrdiff_t length = 1 + (ptrdiff_t)extra;    ptrdiff_t offset = EmitCheck(cx, cg, op, length);    if (offset >= 0) {        jsbytecode *next = CG_NEXT(cg);        *next = (jsbytecode)op;        memset(next + 1, 0, BYTECODE_SIZE(extra));        CG_NEXT(cg) = next + length;        UpdateDepth(cx, cg, offset);    }    return offset;}/* XXX too many "... statement" L10N gaffes below -- fix via js.msg! */const char js_with_statement_str[] = "with statement";const char js_finally_block_str[]  = "finally block";const char js_script_str[]         = "script";static const char *statementName[] = {    "label statement",       /* LABEL */    "if statement",          /* IF */    "else statement",        /* ELSE */    "switch statement",      /* SWITCH */    "block",                 /* BLOCK */    js_with_statement_str,   /* WITH */    "catch block",           /* CATCH */    "try block",             /* TRY */    js_finally_block_str,    /* FINALLY */    js_finally_block_str,    /* SUBROUTINE */    "do loop",               /* DO_LOOP */    "for loop",              /* FOR_LOOP */    "for/in loop",           /* FOR_IN_LOOP */    "while loop",            /* WHILE_LOOP */};static const char *StatementName(JSCodeGenerator *cg){    if (!cg->treeContext.topStmt)        return js_script_str;    return statementName[cg->treeContext.topStmt->type];}static voidReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg){    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET,                         StatementName(cg));}/**  Span-dependent instructions in JS bytecode consist of the jump (JOF_JUMP)  and switch (JOF_LOOKUPSWITCH, JOF_TABLESWITCH) format opcodes, subdivided  into unconditional (gotos and gosubs), and conditional jumps or branches  (which pop a value, test it, and jump depending on its value).  Most jumps  have just one immediate operand, a signed offset from the jump opcode's pc  to the target bytecode.  The lookup and table switch opcodes may contain  many jump offsets.  Mozilla bug #80981 (http://bugzilla.mozilla.org/show_bug.cgi?id=80981) was  fixed by adding extended "X" counterparts to the opcodes/formats (NB: X is  suffixed to prefer JSOP_ORX thereby avoiding a JSOP_XOR name collision for  the extended form of the JSOP_OR branch opcode).  The unextended or short  formats have 16-bit signed immediate offset operands, the extended or long  formats have 32-bit signed immediates.  The span-dependency problem consists  of selecting as few long instructions as possible, or about as few -- since  jumps can span other jumps, extending one jump may cause another to need to  be extended.  Most JS scripts are short, so need no extended jumps.  We optimize for this  case by generating short jumps until we know a long jump is needed.  After  that point, we keep generating short jumps, but each jump's 16-bit immediate  offset operand is actually an unsigned index into cg->spanDeps, an array of  JSSpanDep structs.  Each struct tells the top offset in the script of the  opcode, the "before" offset of the jump (which will be the same as top for  simplex jumps, but which will index further into the bytecode array for a  non-initial jump offset in a lookup or table switch), the after "offset"  adjusted during span-dependent instruction selection (initially the same  value as the "before" offset), and the jump target (more below).  Since we generate cg->spanDeps lazily, from within js_SetJumpOffset, we must  ensure that all bytecode generated so far can be inspected to discover where  the jump offset immediate operands lie within CG_CODE(cg).  But the bonus is  that we generate span-dependency records sorted by their offsets, so we can  binary-search when trying to find a JSSpanDep for a given bytecode offset,  or the nearest JSSpanDep at or above a given pc.  To avoid limiting scripts to 64K jumps, if the cg->spanDeps index overflows  65534, we store SPANDEP_INDEX_HUGE in the jump's immediate operand.  This  tells us that we need to binary-search for the cg->spanDeps entry by the  jump opcode's bytecode offset (sd->before).  Jump targets need to be maintained in a data structure that lets us look  up an already-known target by its address (jumps may have a common target),  and that also lets us update the addresses (script-relative, a.k.a. absolute  offsets) of targets that come after a jump target (for when a jump below  that target needs to be extended).  We use an AVL tree, implemented using  recursion, but with some tricky optimizations to its height-balancing code  (see http://www.cmcrossroads.com/bradapp/ftp/src/libs/C++/AvlTrees.html).  A final wrinkle: backpatch chains are linked by jump-to-jump offsets with  positive sign, even though they link "backward" (i.e., toward lower bytecode  address).  We don't want to waste space and search time in the AVL tree for  such temporary backpatch deltas, so we use a single-bit wildcard scheme to  tag true JSJumpTarget pointers and encode untagged, signed (positive) deltas  in JSSpanDep.target pointers, depending on whether the JSSpanDep has a known  target, or is still awaiting backpatching.  Note that backpatch chains would present a problem for BuildSpanDepTable,  which inspects bytecode to build cg->spanDeps on demand, when the first  short jump offset overflows.  To solve this temporary problem, we emit a  proxy bytecode (JSOP_BACKPATCH; JSOP_BACKPATCH_POP for branch ops) whose  nuses/ndefs counts help keep the stack balanced, but whose opcode format  distinguishes its backpatch delta immediate operand from a normal jump  offset. */static intBalanceJumpTargets(JSJumpTarget **jtp){    JSJumpTarget *jt, *jt2, *root;    int dir, otherDir, heightChanged;    JSBool doubleRotate;    jt = *jtp;    JS_ASSERT(jt->balance != 0);    if (jt->balance < -1) {        dir = JT_RIGHT;        doubleRotate = (jt->kids[JT_LEFT]->balance > 0);    } else if (jt->balance > 1) {        dir = JT_LEFT;        doubleRotate = (jt->kids[JT_RIGHT]->balance < 0);    } else {        return 0;    }    otherDir = JT_OTHER_DIR(dir);    if (doubleRotate) {        jt2 = jt->kids[otherDir];        *jtp = root = jt2->kids[dir];        jt->kids[otherDir] = root->kids[dir];        root->kids[dir] = jt;        jt2->kids[dir] = root->kids[otherDir];        root->kids[otherDir] = jt2;        heightChanged = 1;        root->kids[JT_LEFT]->balance = -JS_MAX(root->balance, 0);        root->kids[JT_RIGHT]->balance = -JS_MIN(root->balance, 0);        root->balance = 0;    } else {        *jtp = root = jt->kids[otherDir];        jt->kids[otherDir] = root->kids[dir];        root->kids[dir] = jt;        heightChanged = (root->balance != 0);        jt->balance = -((dir == JT_LEFT) ? --root->balance : ++root->balance);    }    return heightChanged;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -