Back to index

lightning-sunbird  0.9+nobinonly
jsopcode.h
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code, released
00017  * March 31, 1998.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #ifndef jsopcode_h___
00041 #define jsopcode_h___
00042 /*
00043  * JS bytecode definitions.
00044  */
00045 #include <stddef.h>
00046 #include "jsprvtd.h"
00047 #include "jspubtd.h"
00048 #include "jsutil.h"
00049 
00050 JS_BEGIN_EXTERN_C
00051 
00052 /*
00053  * JS operation bytecodes.
00054  */
00055 typedef enum JSOp {
00056 #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
00057     op = val,
00058 #include "jsopcode.tbl"
00059 #undef OPDEF
00060     JSOP_LIMIT
00061 } JSOp;
00062 
00063 typedef enum JSOpLength {
00064 #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
00065     op##_LENGTH = length,
00066 #include "jsopcode.tbl"
00067 #undef OPDEF
00068     JSOP_LIMIT_LENGTH
00069 } JSOpLength;
00070 
00071 /*
00072  * JS bytecode formats.
00073  */
00074 #define JOF_BYTE          0       /* single bytecode, no immediates */
00075 #define JOF_JUMP          1       /* signed 16-bit jump offset immediate */
00076 #define JOF_CONST         2       /* unsigned 16-bit constant pool index */
00077 #define JOF_UINT16        3       /* unsigned 16-bit immediate operand */
00078 #define JOF_TABLESWITCH   4       /* table switch */
00079 #define JOF_LOOKUPSWITCH  5       /* lookup switch */
00080 #define JOF_QARG          6       /* quickened get/set function argument ops */
00081 #define JOF_QVAR          7       /* quickened get/set local variable ops */
00082 #define JOF_INDEXCONST    8       /* uint16 slot index + constant pool index */
00083 #define JOF_JUMPX         9       /* signed 32-bit jump offset immediate */
00084 #define JOF_TABLESWITCHX  10      /* extended (32-bit offset) table switch */
00085 #define JOF_LOOKUPSWITCHX 11      /* extended (32-bit offset) lookup switch */
00086 #define JOF_UINT24        12      /* extended unsigned 24-bit literal (index) */
00087 #define JOF_LITOPX        13      /* JOF_UINT24 followed by op being extended,
00088                                      where op if JOF_CONST has no unsigned 16-
00089                                      bit immediate operand */
00090 #define JOF_LOCAL         14      /* block-local operand stack variable */
00091 #define JOF_TYPEMASK      0x000f  /* mask for above immediate types */
00092 #define JOF_NAME          0x0010  /* name operation */
00093 #define JOF_PROP          0x0020  /* obj.prop operation */
00094 #define JOF_ELEM          0x0030  /* obj[index] operation */
00095 #define JOF_MODEMASK      0x0030  /* mask for above addressing modes */
00096 #define JOF_SET           0x0040  /* set (i.e., assignment) operation */
00097 #define JOF_DEL           0x0080  /* delete operation */
00098 #define JOF_DEC           0x0100  /* decrement (--, not ++) opcode */
00099 #define JOF_INC           0x0200  /* increment (++, not --) opcode */
00100 #define JOF_INCDEC        0x0300  /* increment or decrement opcode */
00101 #define JOF_POST          0x0400  /* postorder increment or decrement */
00102 #define JOF_IMPORT        0x0800  /* import property op */
00103 #define JOF_FOR           0x1000  /* for-in property op */
00104 #define JOF_ASSIGNING     JOF_SET /* hint for JSClass.resolve, used for ops
00105                                      that do simplex assignment */
00106 #define JOF_DETECTING     0x2000  /* object detection flag for JSNewResolveOp */
00107 #define JOF_BACKPATCH     0x4000  /* backpatch placeholder during codegen */
00108 #define JOF_LEFTASSOC     0x8000  /* left-associative operator */
00109 #define JOF_DECLARING    0x10000  /* var, const, or function declaration op */
00110 #define JOF_XMLNAME      0x20000  /* XML name: *, a::b, @a, @a::b, etc. */
00111 
00112 #define JOF_TYPE_IS_EXTENDED_JUMP(t) \
00113     ((unsigned)((t) - JOF_JUMPX) <= (unsigned)(JOF_LOOKUPSWITCHX - JOF_JUMPX))
00114 
00115 /*
00116  * Immediate operand getters, setters, and bounds.
00117  */
00118 
00119 /* Short (2-byte signed offset) relative jump macros. */
00120 #define JUMP_OFFSET_LEN         2
00121 #define JUMP_OFFSET_HI(off)     ((jsbytecode)((off) >> 8))
00122 #define JUMP_OFFSET_LO(off)     ((jsbytecode)(off))
00123 #define GET_JUMP_OFFSET(pc)     ((int16)(((pc)[1] << 8) | (pc)[2]))
00124 #define SET_JUMP_OFFSET(pc,off) ((pc)[1] = JUMP_OFFSET_HI(off),               \
00125                                  (pc)[2] = JUMP_OFFSET_LO(off))
00126 #define JUMP_OFFSET_MIN         ((int16)0x8000)
00127 #define JUMP_OFFSET_MAX         ((int16)0x7fff)
00128 
00129 /*
00130  * When a short jump won't hold a relative offset, its 2-byte immediate offset
00131  * operand is an unsigned index of a span-dependency record, maintained until
00132  * code generation finishes -- after which some (but we hope not nearly all)
00133  * span-dependent jumps must be extended (see OptimizeSpanDeps in jsemit.c).
00134  *
00135  * If the span-dependency record index overflows SPANDEP_INDEX_MAX, the jump
00136  * offset will contain SPANDEP_INDEX_HUGE, indicating that the record must be
00137  * found (via binary search) by its "before span-dependency optimization" pc
00138  * offset (from script main entry point).
00139  */
00140 #define GET_SPANDEP_INDEX(pc)   ((uint16)(((pc)[1] << 8) | (pc)[2]))
00141 #define SET_SPANDEP_INDEX(pc,i) ((pc)[1] = JUMP_OFFSET_HI(i),                 \
00142                                  (pc)[2] = JUMP_OFFSET_LO(i))
00143 #define SPANDEP_INDEX_MAX       ((uint16)0xfffe)
00144 #define SPANDEP_INDEX_HUGE      ((uint16)0xffff)
00145 
00146 /* Ultimately, if short jumps won't do, emit long (4-byte signed) offsets. */
00147 #define JUMPX_OFFSET_LEN        4
00148 #define JUMPX_OFFSET_B3(off)    ((jsbytecode)((off) >> 24))
00149 #define JUMPX_OFFSET_B2(off)    ((jsbytecode)((off) >> 16))
00150 #define JUMPX_OFFSET_B1(off)    ((jsbytecode)((off) >> 8))
00151 #define JUMPX_OFFSET_B0(off)    ((jsbytecode)(off))
00152 #define GET_JUMPX_OFFSET(pc)    ((int32)(((pc)[1] << 24) | ((pc)[2] << 16)    \
00153                                          | ((pc)[3] << 8) | (pc)[4]))
00154 #define SET_JUMPX_OFFSET(pc,off)((pc)[1] = JUMPX_OFFSET_B3(off),              \
00155                                  (pc)[2] = JUMPX_OFFSET_B2(off),              \
00156                                  (pc)[3] = JUMPX_OFFSET_B1(off),              \
00157                                  (pc)[4] = JUMPX_OFFSET_B0(off))
00158 #define JUMPX_OFFSET_MIN        ((int32)0x80000000)
00159 #define JUMPX_OFFSET_MAX        ((int32)0x7fffffff)
00160 
00161 /*
00162  * A literal is indexed by a per-script atom map.  Most scripts have relatively
00163  * few literals, so the standard JOF_CONST format specifies a fixed 16 bits of
00164  * immediate operand index.  A script with more than 64K literals must push all
00165  * high-indexed literals on the stack using JSOP_LITERAL, then use JOF_ELEM ops
00166  * instead of JOF_PROP, etc.
00167  */
00168 #define ATOM_INDEX_LEN          2
00169 #define ATOM_INDEX_HI(i)        ((jsbytecode)((i) >> 8))
00170 #define ATOM_INDEX_LO(i)        ((jsbytecode)(i))
00171 #define GET_ATOM_INDEX(pc)      ((jsatomid)(((pc)[1] << 8) | (pc)[2]))
00172 #define SET_ATOM_INDEX(pc,i)    ((pc)[1] = ATOM_INDEX_HI(i),                  \
00173                                  (pc)[2] = ATOM_INDEX_LO(i))
00174 #define GET_ATOM(cx,script,pc)  js_GetAtom((cx), &(script)->atomMap,          \
00175                                            GET_ATOM_INDEX(pc))
00176 
00177 /* A full atom index for JSOP_UINT24 uses 24 bits of immediate operand. */
00178 #define UINT24_HI(i)            ((jsbytecode)((i) >> 16))
00179 #define UINT24_MID(i)           ((jsbytecode)((i) >> 8))
00180 #define UINT24_LO(i)            ((jsbytecode)(i))
00181 #define GET_UINT24(pc)          ((jsatomid)(((pc)[1] << 16) |                 \
00182                                             ((pc)[2] << 8) |                  \
00183                                             (pc)[3]))
00184 #define SET_UINT24(pc,i)        ((pc)[1] = UINT24_HI(i),                      \
00185                                  (pc)[2] = UINT24_MID(i),                     \
00186                                  (pc)[3] = UINT24_LO(i))
00187 
00188 /* Same format for JSOP_LITERAL, etc., but future-proof with different names. */
00189 #define LITERAL_INDEX_LEN       3
00190 #define LITERAL_INDEX_HI(i)     UINT24_HI(i)
00191 #define LITERAL_INDEX_MID(i)    UINT24_MID(i)
00192 #define LITERAL_INDEX_LO(i)     UINT24_LO(i)
00193 #define GET_LITERAL_INDEX(pc)   GET_UINT24(pc)
00194 #define SET_LITERAL_INDEX(pc,i) SET_UINT24(pc,i)
00195 
00196 /* Atom index limit is determined by SN_3BYTE_OFFSET_FLAG, see jsemit.h. */
00197 #define ATOM_INDEX_LIMIT_LOG2   23
00198 #define ATOM_INDEX_LIMIT        ((uint32)1 << ATOM_INDEX_LIMIT_LOG2)
00199 
00200 JS_STATIC_ASSERT(sizeof(jsatomid) * JS_BITS_PER_BYTE >=
00201                  ATOM_INDEX_LIMIT_LOG2 + 1);
00202 
00203 /* Common uint16 immediate format helpers. */
00204 #define UINT16_HI(i)            ((jsbytecode)((i) >> 8))
00205 #define UINT16_LO(i)            ((jsbytecode)(i))
00206 #define GET_UINT16(pc)          ((uintN)(((pc)[1] << 8) | (pc)[2]))
00207 #define SET_UINT16(pc,i)        ((pc)[1] = UINT16_HI(i), (pc)[2] = UINT16_LO(i))
00208 #define UINT16_LIMIT            ((uintN)1 << 16)
00209 
00210 /* Actual argument count operand format helpers. */
00211 #define ARGC_HI(argc)           UINT16_HI(argc)
00212 #define ARGC_LO(argc)           UINT16_LO(argc)
00213 #define GET_ARGC(pc)            GET_UINT16(pc)
00214 #define ARGC_LIMIT              UINT16_LIMIT
00215 
00216 /* Synonyms for quick JOF_QARG and JOF_QVAR bytecodes. */
00217 #define GET_ARGNO(pc)           GET_UINT16(pc)
00218 #define SET_ARGNO(pc,argno)     SET_UINT16(pc,argno)
00219 #define ARGNO_LEN               2
00220 #define ARGNO_LIMIT             UINT16_LIMIT
00221 
00222 #define GET_VARNO(pc)           GET_UINT16(pc)
00223 #define SET_VARNO(pc,varno)     SET_UINT16(pc,varno)
00224 #define VARNO_LEN               2
00225 #define VARNO_LIMIT             UINT16_LIMIT
00226 
00227 struct JSCodeSpec {
00228     const char          *name;          /* JS bytecode name */
00229     const char          *token;         /* JS source literal or null */
00230     int8                length;         /* length including opcode byte */
00231     int8                nuses;          /* arity, -1 if variadic */
00232     int8                ndefs;          /* number of stack results */
00233     uint8               prec;           /* operator precedence */
00234     uint32              format;         /* immediate operand format */
00235 };
00236 
00237 extern const JSCodeSpec js_CodeSpec[];
00238 extern uintN            js_NumCodeSpecs;
00239 extern const jschar     js_EscapeMap[];
00240 
00241 /*
00242  * Return a GC'ed string containing the chars in str, with any non-printing
00243  * chars or quotes (' or " as specified by the quote argument) escaped, and
00244  * with the quote character at the beginning and end of the result string.
00245  */
00246 extern JSString *
00247 js_QuoteString(JSContext *cx, JSString *str, jschar quote);
00248 
00249 /*
00250  * JSPrinter operations, for printf style message formatting.  The return
00251  * value from js_GetPrinterOutput() is the printer's cumulative output, in
00252  * a GC'ed string.
00253  */
00254 extern JSPrinter *
00255 js_NewPrinter(JSContext *cx, const char *name, uintN indent, JSBool pretty);
00256 
00257 extern void
00258 js_DestroyPrinter(JSPrinter *jp);
00259 
00260 extern JSString *
00261 js_GetPrinterOutput(JSPrinter *jp);
00262 
00263 extern int
00264 js_printf(JSPrinter *jp, const char *format, ...);
00265 
00266 extern JSBool
00267 js_puts(JSPrinter *jp, const char *s);
00268 
00269 #ifdef DEBUG
00270 /*
00271  * Disassemblers, for debugging only.
00272  */
00273 #include <stdio.h>
00274 
00275 extern JS_FRIEND_API(JSBool)
00276 js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp);
00277 
00278 extern JS_FRIEND_API(uintN)
00279 js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
00280                 JSBool lines, FILE *fp);
00281 #endif /* DEBUG */
00282 
00283 /*
00284  * Decompilers, for script, function, and expression pretty-printing.
00285  */
00286 extern JSBool
00287 js_DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len,
00288                  uintN pcdepth);
00289 
00290 extern JSBool
00291 js_DecompileScript(JSPrinter *jp, JSScript *script);
00292 
00293 extern JSBool
00294 js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun);
00295 
00296 extern JSBool
00297 js_DecompileFunction(JSPrinter *jp, JSFunction *fun);
00298 
00299 /*
00300  * Find the source expression that resulted in v, and return a new string
00301  * containing it.  Fall back on v's string conversion (fallback) if we can't
00302  * find the bytecode that generated and pushed v on the operand stack.
00303  *
00304  * Search the current stack frame if spindex is JSDVG_SEARCH_STACK.  Don't
00305  * look for v on the stack if spindex is JSDVG_IGNORE_STACK.  Otherwise,
00306  * spindex is the negative index of v, measured from cx->fp->sp, or from a
00307  * lower frame's sp if cx->fp is native.
00308  */
00309 extern JSString *
00310 js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
00311                            JSString *fallback);
00312 
00313 #define JSDVG_IGNORE_STACK      0
00314 #define JSDVG_SEARCH_STACK      1
00315 
00316 JS_END_EXTERN_C
00317 
00318 #endif /* jsopcode_h___ */