1 |
siliconforks |
332 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 |
|
|
* vim: set ts=8 sw=4 et tw=78: |
3 |
|
|
* |
4 |
|
|
* ***** BEGIN LICENSE BLOCK ***** |
5 |
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
6 |
|
|
* |
7 |
|
|
* The contents of this file are subject to the Mozilla Public License Version |
8 |
|
|
* 1.1 (the "License"); you may not use this file except in compliance with |
9 |
|
|
* the License. You may obtain a copy of the License at |
10 |
|
|
* http://www.mozilla.org/MPL/ |
11 |
|
|
* |
12 |
|
|
* Software distributed under the License is distributed on an "AS IS" basis, |
13 |
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
14 |
|
|
* for the specific language governing rights and limitations under the |
15 |
|
|
* License. |
16 |
|
|
* |
17 |
|
|
* The Original Code is Mozilla Communicator client code, released |
18 |
|
|
* March 31, 1998. |
19 |
|
|
* |
20 |
|
|
* The Initial Developer of the Original Code is |
21 |
|
|
* Netscape Communications Corporation. |
22 |
|
|
* Portions created by the Initial Developer are Copyright (C) 1998 |
23 |
|
|
* the Initial Developer. All Rights Reserved. |
24 |
|
|
* |
25 |
|
|
* Contributor(s): |
26 |
|
|
* |
27 |
|
|
* Alternatively, the contents of this file may be used under the terms of |
28 |
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"), |
29 |
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
30 |
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead |
31 |
|
|
* of those above. If you wish to allow use of your version of this file only |
32 |
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to |
33 |
|
|
* use your version of this file under the terms of the MPL, indicate your |
34 |
|
|
* decision by deleting the provisions above and replace them with the notice |
35 |
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete |
36 |
|
|
* the provisions above, a recipient may use your version of this file under |
37 |
|
|
* the terms of any one of the MPL, the GPL or the LGPL. |
38 |
|
|
* |
39 |
|
|
* ***** END LICENSE BLOCK ***** */ |
40 |
|
|
|
41 |
|
|
#ifndef jsinterp_h___ |
42 |
|
|
#define jsinterp_h___ |
43 |
|
|
/* |
44 |
|
|
* JS interpreter interface. |
45 |
|
|
*/ |
46 |
|
|
#include "jsprvtd.h" |
47 |
|
|
#include "jspubtd.h" |
48 |
|
|
#include "jsfun.h" |
49 |
|
|
#include "jsopcode.h" |
50 |
|
|
#include "jsscript.h" |
51 |
|
|
|
52 |
|
|
JS_BEGIN_EXTERN_C |
53 |
|
|
|
54 |
|
|
typedef struct JSFrameRegs { |
55 |
|
|
jsbytecode *pc; /* program counter */ |
56 |
|
|
jsval *sp; /* stack pointer */ |
57 |
|
|
} JSFrameRegs; |
58 |
|
|
|
59 |
|
|
/* |
60 |
|
|
* JS stack frame, may be allocated on the C stack by native callers. Always |
61 |
|
|
* allocated on cx->stackPool for calls from the interpreter to an interpreted |
62 |
|
|
* function. |
63 |
|
|
* |
64 |
|
|
* NB: This struct is manually initialized in jsinterp.c and jsiter.c. If you |
65 |
|
|
* add new members, update both files. But first, try to remove members. The |
66 |
|
|
* sharp* and xml* members should be moved onto the stack as local variables |
67 |
|
|
* with well-known slots, if possible. |
68 |
|
|
*/ |
69 |
|
|
struct JSStackFrame { |
70 |
|
|
JSFrameRegs *regs; |
71 |
siliconforks |
399 |
jsbytecode *imacpc; /* null or interpreter macro call pc */ |
72 |
siliconforks |
332 |
jsval *slots; /* variables, locals and operand stack */ |
73 |
|
|
JSObject *callobj; /* lazily created Call object */ |
74 |
|
|
JSObject *argsobj; /* lazily created arguments object */ |
75 |
|
|
JSObject *varobj; /* variables object, where vars go */ |
76 |
|
|
JSObject *callee; /* function or script object */ |
77 |
|
|
JSScript *script; /* script being interpreted */ |
78 |
|
|
JSFunction *fun; /* function being called or null */ |
79 |
|
|
JSObject *thisp; /* "this" pointer if in method */ |
80 |
|
|
uintN argc; /* actual argument count */ |
81 |
|
|
jsval *argv; /* base of argument stack slots */ |
82 |
|
|
jsval rval; /* function return value */ |
83 |
|
|
JSStackFrame *down; /* previous frame */ |
84 |
|
|
void *annotation; /* used by Java security */ |
85 |
siliconforks |
460 |
|
86 |
|
|
/* |
87 |
|
|
* We can't determine in advance which local variables can live on |
88 |
|
|
* the stack and be freed when their dynamic scope ends, and which |
89 |
|
|
* will be closed over and need to live in the heap. So we place |
90 |
|
|
* variables on the stack initially, note when they are closed |
91 |
|
|
* over, and copy those that are out to the heap when we leave |
92 |
|
|
* their dynamic scope. |
93 |
|
|
* |
94 |
|
|
* The bytecode compiler produces a tree of block objects |
95 |
|
|
* accompanying each JSScript representing those lexical blocks in |
96 |
|
|
* the script that have let-bound variables associated with them. |
97 |
|
|
* These block objects are never modified, and never become part |
98 |
|
|
* of any function's scope chain. Their parent slots point to the |
99 |
|
|
* innermost block that encloses them, or are NULL in the |
100 |
|
|
* outermost blocks within a function or in eval or global code. |
101 |
|
|
* |
102 |
|
|
* When we are in the static scope of such a block, blockChain |
103 |
|
|
* points to its compiler-allocated block object; otherwise, it is |
104 |
|
|
* NULL. |
105 |
|
|
* |
106 |
|
|
* scopeChain is the current scope chain, including 'call' and |
107 |
|
|
* 'block' objects for those function calls and lexical blocks |
108 |
|
|
* whose static scope we are currently executing in, and 'with' |
109 |
|
|
* objects for with statements; the chain is typically terminated |
110 |
|
|
* by a global object. However, as an optimization, the young end |
111 |
|
|
* of the chain omits block objects we have not yet cloned. To |
112 |
|
|
* create a closure, we clone the missing blocks from blockChain |
113 |
|
|
* (which is always current), place them at the head of |
114 |
|
|
* scopeChain, and use that for the closure's scope chain. If we |
115 |
|
|
* never close over a lexical block, we never place a mutable |
116 |
|
|
* clone of it on scopeChain. |
117 |
|
|
* |
118 |
|
|
* This lazy cloning is implemented in js_GetScopeChain, which is |
119 |
|
|
* also used in some other cases --- entering 'with' blocks, for |
120 |
|
|
* example. |
121 |
|
|
*/ |
122 |
|
|
JSObject *scopeChain; |
123 |
|
|
JSObject *blockChain; |
124 |
|
|
|
125 |
siliconforks |
332 |
uintN sharpDepth; /* array/object initializer depth */ |
126 |
|
|
JSObject *sharpArray; /* scope for #n= initializer vars */ |
127 |
|
|
uint32 flags; /* frame flags -- see below */ |
128 |
|
|
JSStackFrame *dormantNext; /* next dormant frame chain */ |
129 |
|
|
JSObject *xmlNamespace; /* null or default xml namespace in E4X */ |
130 |
|
|
JSStackFrame *displaySave; /* previous value of display entry for |
131 |
siliconforks |
460 |
script->staticLevel */ |
132 |
|
|
|
133 |
|
|
#ifdef __cplusplus /* Aargh, LiveConnect, bug 442399. */ |
134 |
|
|
inline void assertValidStackDepth(uintN depth); |
135 |
siliconforks |
332 |
#endif |
136 |
|
|
}; |
137 |
|
|
|
138 |
siliconforks |
399 |
#ifdef __cplusplus |
139 |
|
|
static JS_INLINE uintN |
140 |
|
|
FramePCOffset(JSStackFrame* fp) |
141 |
|
|
{ |
142 |
|
|
return uintN((fp->imacpc ? fp->imacpc : fp->regs->pc) - fp->script->code); |
143 |
|
|
} |
144 |
|
|
#endif |
145 |
|
|
|
146 |
siliconforks |
332 |
static JS_INLINE jsval * |
147 |
|
|
StackBase(JSStackFrame *fp) |
148 |
|
|
{ |
149 |
|
|
return fp->slots + fp->script->nfixed; |
150 |
|
|
} |
151 |
|
|
|
152 |
siliconforks |
460 |
#ifdef __cplusplus /* Aargh, LiveConnect, bug 442399. */ |
153 |
|
|
void |
154 |
|
|
JSStackFrame::assertValidStackDepth(uintN depth) |
155 |
|
|
{ |
156 |
|
|
JS_ASSERT(0 <= regs->sp - StackBase(this)); |
157 |
|
|
JS_ASSERT(depth <= uintptr_t(regs->sp - StackBase(this))); |
158 |
|
|
} |
159 |
|
|
#endif |
160 |
|
|
|
161 |
siliconforks |
332 |
static JS_INLINE uintN |
162 |
|
|
GlobalVarCount(JSStackFrame *fp) |
163 |
|
|
{ |
164 |
|
|
uintN n; |
165 |
|
|
|
166 |
|
|
JS_ASSERT(!fp->fun); |
167 |
|
|
n = fp->script->nfixed; |
168 |
|
|
if (fp->script->regexpsOffset != 0) |
169 |
|
|
n -= JS_SCRIPT_REGEXPS(fp->script)->length; |
170 |
|
|
return n; |
171 |
|
|
} |
172 |
|
|
|
173 |
|
|
typedef struct JSInlineFrame { |
174 |
|
|
JSStackFrame frame; /* base struct */ |
175 |
|
|
JSFrameRegs callerRegs; /* parent's frame registers */ |
176 |
|
|
void *mark; /* mark before inline frame */ |
177 |
|
|
void *hookData; /* debugger call hook data */ |
178 |
|
|
JSVersion callerVersion; /* dynamic version of calling script */ |
179 |
|
|
} JSInlineFrame; |
180 |
|
|
|
181 |
|
|
/* JS stack frame flags. */ |
182 |
|
|
#define JSFRAME_CONSTRUCTING 0x01 /* frame is for a constructor invocation */ |
183 |
|
|
#define JSFRAME_COMPUTED_THIS 0x02 /* frame.thisp was computed already */ |
184 |
|
|
#define JSFRAME_ASSIGNING 0x04 /* a complex (not simplex JOF_ASSIGNING) op |
185 |
|
|
is currently assigning to a property */ |
186 |
|
|
#define JSFRAME_DEBUGGER 0x08 /* frame for JS_EvaluateInStackFrame */ |
187 |
|
|
#define JSFRAME_EVAL 0x10 /* frame for obj_eval */ |
188 |
|
|
#define JSFRAME_ROOTED_ARGV 0x20 /* frame.argv is rooted by the caller */ |
189 |
|
|
#define JSFRAME_YIELDING 0x40 /* js_Interpret dispatched JSOP_YIELD */ |
190 |
|
|
#define JSFRAME_ITERATOR 0x80 /* trying to get an iterator for for-in */ |
191 |
|
|
#define JSFRAME_GENERATOR 0x200 /* frame belongs to generator-iterator */ |
192 |
|
|
|
193 |
|
|
#define JSFRAME_OVERRIDE_SHIFT 24 /* override bit-set params; see jsfun.c */ |
194 |
|
|
#define JSFRAME_OVERRIDE_BITS 8 |
195 |
|
|
|
196 |
|
|
#define JSFRAME_SPECIAL (JSFRAME_DEBUGGER | JSFRAME_EVAL) |
197 |
|
|
|
198 |
|
|
/* |
199 |
|
|
* Property cache with structurally typed capabilities for invalidation, for |
200 |
|
|
* polymorphic callsite method/get/set speedups. |
201 |
|
|
* |
202 |
|
|
* See bug https://bugzilla.mozilla.org/show_bug.cgi?id=365851. |
203 |
|
|
*/ |
204 |
|
|
#define PROPERTY_CACHE_LOG2 12 |
205 |
|
|
#define PROPERTY_CACHE_SIZE JS_BIT(PROPERTY_CACHE_LOG2) |
206 |
|
|
#define PROPERTY_CACHE_MASK JS_BITMASK(PROPERTY_CACHE_LOG2) |
207 |
|
|
|
208 |
|
|
/* |
209 |
|
|
* Add kshape rather than xor it to avoid collisions between nearby bytecode |
210 |
|
|
* that are evolving an object by setting successive properties, incrementing |
211 |
|
|
* the object's scope->shape on each set. |
212 |
|
|
*/ |
213 |
|
|
#define PROPERTY_CACHE_HASH(pc,kshape) \ |
214 |
|
|
(((((jsuword)(pc) >> PROPERTY_CACHE_LOG2) ^ (jsuword)(pc)) + (kshape)) & \ |
215 |
|
|
PROPERTY_CACHE_MASK) |
216 |
|
|
|
217 |
|
|
#define PROPERTY_CACHE_HASH_PC(pc,kshape) \ |
218 |
|
|
PROPERTY_CACHE_HASH(pc, kshape) |
219 |
|
|
|
220 |
|
|
#define PROPERTY_CACHE_HASH_ATOM(atom,obj,pobj) \ |
221 |
|
|
PROPERTY_CACHE_HASH((jsuword)(atom) >> 2, OBJ_SHAPE(obj)) |
222 |
|
|
|
223 |
|
|
/* |
224 |
|
|
* Property cache value capability macros. |
225 |
|
|
*/ |
226 |
|
|
#define PCVCAP_PROTOBITS 4 |
227 |
|
|
#define PCVCAP_PROTOSIZE JS_BIT(PCVCAP_PROTOBITS) |
228 |
|
|
#define PCVCAP_PROTOMASK JS_BITMASK(PCVCAP_PROTOBITS) |
229 |
|
|
|
230 |
|
|
#define PCVCAP_SCOPEBITS 4 |
231 |
|
|
#define PCVCAP_SCOPESIZE JS_BIT(PCVCAP_SCOPEBITS) |
232 |
|
|
#define PCVCAP_SCOPEMASK JS_BITMASK(PCVCAP_SCOPEBITS) |
233 |
|
|
|
234 |
|
|
#define PCVCAP_TAGBITS (PCVCAP_PROTOBITS + PCVCAP_SCOPEBITS) |
235 |
|
|
#define PCVCAP_TAGMASK JS_BITMASK(PCVCAP_TAGBITS) |
236 |
|
|
#define PCVCAP_TAG(t) ((t) & PCVCAP_TAGMASK) |
237 |
|
|
|
238 |
siliconforks |
460 |
#define PCVCAP_MAKE(t,s,p) ((uint32(t) << PCVCAP_TAGBITS) | \ |
239 |
siliconforks |
332 |
((s) << PCVCAP_PROTOBITS) | \ |
240 |
|
|
(p)) |
241 |
|
|
#define PCVCAP_SHAPE(t) ((t) >> PCVCAP_TAGBITS) |
242 |
|
|
|
243 |
|
|
#define SHAPE_OVERFLOW_BIT JS_BIT(32 - PCVCAP_TAGBITS) |
244 |
|
|
|
245 |
siliconforks |
460 |
#ifndef JS_THREADSAFE |
246 |
|
|
# define js_GenerateShape(cx, gcLocked) js_GenerateShape (cx) |
247 |
|
|
#endif |
248 |
|
|
|
249 |
siliconforks |
332 |
extern uint32 |
250 |
siliconforks |
460 |
js_GenerateShape(JSContext *cx, JSBool gcLocked); |
251 |
siliconforks |
332 |
|
252 |
|
|
struct JSPropCacheEntry { |
253 |
|
|
jsbytecode *kpc; /* pc if vcap tag is <= 1, else atom */ |
254 |
|
|
jsuword kshape; /* key shape if pc, else obj for atom */ |
255 |
|
|
jsuword vcap; /* value capability, see above */ |
256 |
|
|
jsuword vword; /* value word, see PCVAL_* below */ |
257 |
|
|
}; |
258 |
|
|
|
259 |
siliconforks |
460 |
/* |
260 |
|
|
* Special value for functions returning JSPropCacheEntry * to distinguish |
261 |
|
|
* between failure and no no-cache-fill cases. |
262 |
|
|
*/ |
263 |
|
|
#define JS_NO_PROP_CACHE_FILL ((JSPropCacheEntry *) NULL + 1) |
264 |
|
|
|
265 |
siliconforks |
332 |
#if defined DEBUG_brendan || defined DEBUG_brendaneich |
266 |
|
|
#define JS_PROPERTY_CACHE_METERING 1 |
267 |
|
|
#endif |
268 |
|
|
|
269 |
|
|
typedef struct JSPropertyCache { |
270 |
|
|
JSPropCacheEntry table[PROPERTY_CACHE_SIZE]; |
271 |
|
|
JSBool empty; |
272 |
|
|
#ifdef JS_PROPERTY_CACHE_METERING |
273 |
siliconforks |
460 |
JSPropCacheEntry *pctestentry; /* entry of the last PC-based test */ |
274 |
siliconforks |
332 |
uint32 fills; /* number of cache entry fills */ |
275 |
|
|
uint32 nofills; /* couldn't fill (e.g. default get) */ |
276 |
|
|
uint32 rofills; /* set on read-only prop can't fill */ |
277 |
|
|
uint32 disfills; /* fill attempts on disabled cache */ |
278 |
|
|
uint32 oddfills; /* fill attempt after setter deleted */ |
279 |
|
|
uint32 modfills; /* fill that rehashed to a new entry */ |
280 |
|
|
uint32 brandfills; /* scope brandings to type structural |
281 |
|
|
method fills */ |
282 |
|
|
uint32 noprotos; /* resolve-returned non-proto pobj */ |
283 |
|
|
uint32 longchains; /* overlong scope and/or proto chain */ |
284 |
|
|
uint32 recycles; /* cache entries recycled by fills */ |
285 |
|
|
uint32 pcrecycles; /* pc-keyed entries recycled by atom- |
286 |
|
|
keyed fills */ |
287 |
|
|
uint32 tests; /* cache probes */ |
288 |
|
|
uint32 pchits; /* fast-path polymorphic op hits */ |
289 |
|
|
uint32 protopchits; /* pchits hitting immediate prototype */ |
290 |
|
|
uint32 initests; /* cache probes from JSOP_INITPROP */ |
291 |
|
|
uint32 inipchits; /* init'ing next property pchit case */ |
292 |
|
|
uint32 inipcmisses; /* init'ing next property pc misses */ |
293 |
|
|
uint32 settests; /* cache probes from JOF_SET opcodes */ |
294 |
|
|
uint32 addpchits; /* adding next property pchit case */ |
295 |
|
|
uint32 setpchits; /* setting existing property pchit */ |
296 |
|
|
uint32 setpcmisses; /* setting/adding property pc misses */ |
297 |
|
|
uint32 slotchanges; /* clasp->reserveSlots result variance- |
298 |
|
|
induced slot changes */ |
299 |
|
|
uint32 setmisses; /* JSOP_SET{NAME,PROP} total misses */ |
300 |
|
|
uint32 idmisses; /* slow-path key id == atom misses */ |
301 |
|
|
uint32 komisses; /* slow-path key object misses */ |
302 |
|
|
uint32 vcmisses; /* value capability misses */ |
303 |
|
|
uint32 misses; /* cache misses */ |
304 |
|
|
uint32 flushes; /* cache flushes */ |
305 |
|
|
uint32 pcpurges; /* shadowing purges on proto chain */ |
306 |
|
|
# define PCMETER(x) x |
307 |
|
|
#else |
308 |
|
|
# define PCMETER(x) ((void)0) |
309 |
|
|
#endif |
310 |
|
|
} JSPropertyCache; |
311 |
|
|
|
312 |
|
|
/* |
313 |
|
|
* Property cache value tagging/untagging macros. |
314 |
|
|
*/ |
315 |
|
|
#define PCVAL_OBJECT 0 |
316 |
|
|
#define PCVAL_SLOT 1 |
317 |
|
|
#define PCVAL_SPROP 2 |
318 |
|
|
|
319 |
|
|
#define PCVAL_TAGBITS 2 |
320 |
|
|
#define PCVAL_TAGMASK JS_BITMASK(PCVAL_TAGBITS) |
321 |
|
|
#define PCVAL_TAG(v) ((v) & PCVAL_TAGMASK) |
322 |
|
|
#define PCVAL_CLRTAG(v) ((v) & ~(jsuword)PCVAL_TAGMASK) |
323 |
|
|
#define PCVAL_SETTAG(v,t) ((jsuword)(v) | (t)) |
324 |
|
|
|
325 |
|
|
#define PCVAL_NULL 0 |
326 |
|
|
#define PCVAL_IS_NULL(v) ((v) == PCVAL_NULL) |
327 |
|
|
|
328 |
|
|
#define PCVAL_IS_OBJECT(v) (PCVAL_TAG(v) == PCVAL_OBJECT) |
329 |
|
|
#define PCVAL_TO_OBJECT(v) ((JSObject *) (v)) |
330 |
|
|
#define OBJECT_TO_PCVAL(obj) ((jsuword) (obj)) |
331 |
|
|
|
332 |
|
|
#define PCVAL_OBJECT_TO_JSVAL(v) OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v)) |
333 |
|
|
#define JSVAL_OBJECT_TO_PCVAL(v) OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v)) |
334 |
|
|
|
335 |
|
|
#define PCVAL_IS_SLOT(v) ((v) & PCVAL_SLOT) |
336 |
|
|
#define PCVAL_TO_SLOT(v) ((jsuint)(v) >> 1) |
337 |
|
|
#define SLOT_TO_PCVAL(i) (((jsuword)(i) << 1) | PCVAL_SLOT) |
338 |
|
|
|
339 |
|
|
#define PCVAL_IS_SPROP(v) (PCVAL_TAG(v) == PCVAL_SPROP) |
340 |
|
|
#define PCVAL_TO_SPROP(v) ((JSScopeProperty *) PCVAL_CLRTAG(v)) |
341 |
|
|
#define SPROP_TO_PCVAL(sprop) PCVAL_SETTAG(sprop, PCVAL_SPROP) |
342 |
|
|
|
343 |
|
|
/* |
344 |
|
|
* Fill property cache entry for key cx->fp->pc, optimized value word computed |
345 |
|
|
* from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj), |
346 |
|
|
* 4-bit scopeIndex, and 4-bit protoIndex. |
347 |
siliconforks |
460 |
* |
348 |
|
|
* Return the filled cache entry or JS_NO_PROP_CACHE_FILL if caching was not |
349 |
|
|
* possible. |
350 |
siliconforks |
332 |
*/ |
351 |
siliconforks |
460 |
extern JS_REQUIRES_STACK JSPropCacheEntry * |
352 |
|
|
js_FillPropertyCache(JSContext *cx, JSObject *obj, |
353 |
|
|
uintN scopeIndex, uintN protoIndex, JSObject *pobj, |
354 |
|
|
JSScopeProperty *sprop, JSBool adding); |
355 |
siliconforks |
332 |
|
356 |
|
|
/* |
357 |
|
|
* Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the |
358 |
|
|
* fast path in js_Interpret, so it makes "just-so" restrictions on parameters, |
359 |
|
|
* e.g. pobj and obj should not be the same variable, since for JOF_PROP-mode |
360 |
|
|
* opcodes, obj must not be changed because of a cache miss. |
361 |
|
|
* |
362 |
|
|
* On return from PROPERTY_CACHE_TEST, if atom is null then obj points to the |
363 |
|
|
* scope chain element in which the property was found, pobj is locked, and |
364 |
|
|
* entry is valid. If atom is non-null then no object is locked but entry is |
365 |
|
|
* still set correctly for use, e.g., by js_FillPropertyCache and atom should |
366 |
|
|
* be used as the id to find. |
367 |
|
|
* |
368 |
|
|
* We must lock pobj on a hit in order to close races with threads that might |
369 |
|
|
* be deleting a property from its scope, or otherwise invalidating property |
370 |
|
|
* caches (on all threads) by re-generating scope->shape. |
371 |
|
|
*/ |
372 |
|
|
#define PROPERTY_CACHE_TEST(cx, pc, obj, pobj, entry, atom) \ |
373 |
|
|
do { \ |
374 |
|
|
JSPropertyCache *cache_ = &JS_PROPERTY_CACHE(cx); \ |
375 |
|
|
uint32 kshape_ = (JS_ASSERT(OBJ_IS_NATIVE(obj)), OBJ_SHAPE(obj)); \ |
376 |
|
|
entry = &cache_->table[PROPERTY_CACHE_HASH_PC(pc, kshape_)]; \ |
377 |
siliconforks |
460 |
PCMETER(cache_->pctestentry = entry); \ |
378 |
siliconforks |
332 |
PCMETER(cache_->tests++); \ |
379 |
|
|
JS_ASSERT(&obj != &pobj); \ |
380 |
|
|
if (entry->kpc == pc && entry->kshape == kshape_) { \ |
381 |
|
|
JSObject *tmp_; \ |
382 |
|
|
pobj = obj; \ |
383 |
|
|
JS_LOCK_OBJ(cx, pobj); \ |
384 |
|
|
JS_ASSERT(PCVCAP_TAG(entry->vcap) <= 1); \ |
385 |
|
|
if (PCVCAP_TAG(entry->vcap) == 1 && \ |
386 |
|
|
(tmp_ = LOCKED_OBJ_GET_PROTO(pobj)) != NULL && \ |
387 |
|
|
OBJ_IS_NATIVE(tmp_)) { \ |
388 |
|
|
JS_UNLOCK_OBJ(cx, pobj); \ |
389 |
|
|
pobj = tmp_; \ |
390 |
|
|
JS_LOCK_OBJ(cx, pobj); \ |
391 |
|
|
} \ |
392 |
|
|
if (PCVCAP_SHAPE(entry->vcap) == OBJ_SHAPE(pobj)) { \ |
393 |
|
|
PCMETER(cache_->pchits++); \ |
394 |
|
|
PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \ |
395 |
|
|
pobj = OBJ_SCOPE(pobj)->object; \ |
396 |
|
|
atom = NULL; \ |
397 |
|
|
break; \ |
398 |
|
|
} \ |
399 |
|
|
JS_UNLOCK_OBJ(cx, pobj); \ |
400 |
|
|
} \ |
401 |
|
|
atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, &entry); \ |
402 |
|
|
if (atom) \ |
403 |
|
|
PCMETER(cache_->misses++); \ |
404 |
|
|
} while (0) |
405 |
|
|
|
406 |
siliconforks |
460 |
extern JS_REQUIRES_STACK JSAtom * |
407 |
siliconforks |
332 |
js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, |
408 |
|
|
JSObject **objp, JSObject **pobjp, |
409 |
|
|
JSPropCacheEntry **entryp); |
410 |
|
|
|
411 |
siliconforks |
460 |
/* The property cache does not need a destructor. */ |
412 |
|
|
#define js_FinishPropertyCache(cache) ((void) 0) |
413 |
siliconforks |
332 |
|
414 |
|
|
extern void |
415 |
siliconforks |
460 |
js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache); |
416 |
siliconforks |
332 |
|
417 |
|
|
extern void |
418 |
siliconforks |
460 |
js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script); |
419 |
siliconforks |
332 |
|
420 |
|
|
/* |
421 |
|
|
* Interpreter stack arena-pool alloc and free functions. |
422 |
|
|
*/ |
423 |
siliconforks |
460 |
extern JS_REQUIRES_STACK JS_FRIEND_API(jsval *) |
424 |
siliconforks |
332 |
js_AllocStack(JSContext *cx, uintN nslots, void **markp); |
425 |
|
|
|
426 |
siliconforks |
460 |
extern JS_REQUIRES_STACK JS_FRIEND_API(void) |
427 |
siliconforks |
332 |
js_FreeStack(JSContext *cx, void *mark); |
428 |
|
|
|
429 |
|
|
/* |
430 |
|
|
* Refresh and return fp->scopeChain. It may be stale if block scopes are |
431 |
|
|
* active but not yet reflected by objects in the scope chain. If a block |
432 |
|
|
* scope contains a with, eval, XML filtering predicate, or similar such |
433 |
|
|
* dynamically scoped construct, then compile-time block scope at fp->blocks |
434 |
|
|
* must reflect at runtime. |
435 |
|
|
*/ |
436 |
|
|
extern JSObject * |
437 |
|
|
js_GetScopeChain(JSContext *cx, JSStackFrame *fp); |
438 |
|
|
|
439 |
|
|
/* |
440 |
|
|
* Given a context and a vector of [callee, this, args...] for a function that |
441 |
|
|
* was specified with a JSFUN_THISP_PRIMITIVE flag, get the primitive value of |
442 |
|
|
* |this| into *thisvp. In doing so, if |this| is an object, insist it is an |
443 |
|
|
* instance of clasp and extract its private slot value to return via *thisvp. |
444 |
|
|
* |
445 |
|
|
* NB: this function loads and uses *vp before storing *thisvp, so the two may |
446 |
|
|
* alias the same jsval. |
447 |
|
|
*/ |
448 |
|
|
extern JSBool |
449 |
|
|
js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp); |
450 |
|
|
|
451 |
|
|
/* |
452 |
|
|
* For a call with arguments argv including argv[-1] (nominal |this|) and |
453 |
|
|
* argv[-2] (callee) replace null |this| with callee's parent, replace |
454 |
|
|
* primitive values with the equivalent wrapper objects and censor activation |
455 |
|
|
* objects as, per ECMA-262, they may not be referred to by |this|. argv[-1] |
456 |
|
|
* must not be a JSVAL_VOID. |
457 |
|
|
*/ |
458 |
|
|
extern JSObject * |
459 |
|
|
js_ComputeThis(JSContext *cx, JSBool lazy, jsval *argv); |
460 |
|
|
|
461 |
|
|
extern const uint16 js_PrimitiveTestFlags[]; |
462 |
|
|
|
463 |
|
|
#define PRIMITIVE_THIS_TEST(fun,thisv) \ |
464 |
|
|
(JS_ASSERT(!JSVAL_IS_VOID(thisv)), \ |
465 |
|
|
JSFUN_THISP_TEST(JSFUN_THISP_FLAGS((fun)->flags), \ |
466 |
|
|
js_PrimitiveTestFlags[JSVAL_TAG(thisv) - 1])) |
467 |
|
|
|
468 |
siliconforks |
460 |
#ifdef __cplusplus /* Aargh, libgjs, bug 492720. */ |
469 |
|
|
static JS_INLINE JSObject * |
470 |
|
|
js_ComputeThisForFrame(JSContext *cx, JSStackFrame *fp) |
471 |
|
|
{ |
472 |
|
|
JSObject* obj; |
473 |
|
|
if (fp->flags & JSFRAME_COMPUTED_THIS) |
474 |
|
|
return fp->thisp; |
475 |
|
|
obj = js_ComputeThis(cx, JS_TRUE, fp->argv); |
476 |
|
|
if (!obj) |
477 |
|
|
return NULL; |
478 |
|
|
fp->thisp = obj; |
479 |
|
|
fp->flags |= JSFRAME_COMPUTED_THIS; |
480 |
|
|
return obj; |
481 |
|
|
} |
482 |
|
|
#endif |
483 |
|
|
|
484 |
siliconforks |
332 |
/* |
485 |
|
|
* NB: js_Invoke requires that cx is currently running JS (i.e., that cx->fp |
486 |
|
|
* is non-null), and that vp points to the callee, |this| parameter, and |
487 |
|
|
* actual arguments of the call. [vp .. vp + 2 + argc) must belong to the last |
488 |
|
|
* JS stack segment that js_AllocStack allocated. The function may use the |
489 |
|
|
* space available after vp + 2 + argc in the stack segment for temporaries, |
490 |
|
|
* so the caller should not use that space for values that must be preserved |
491 |
|
|
* across the call. |
492 |
|
|
*/ |
493 |
siliconforks |
460 |
extern JS_REQUIRES_STACK JS_FRIEND_API(JSBool) |
494 |
siliconforks |
332 |
js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags); |
495 |
|
|
|
496 |
|
|
/* |
497 |
|
|
* Consolidated js_Invoke flags simply rename certain JSFRAME_* flags, so that |
498 |
|
|
* we can share bits stored in JSStackFrame.flags and passed to: |
499 |
|
|
* |
500 |
|
|
* js_Invoke |
501 |
|
|
* js_InternalInvoke |
502 |
|
|
* js_ValueToFunction |
503 |
|
|
* js_ValueToFunctionObject |
504 |
|
|
* js_ValueToCallableObject |
505 |
|
|
* js_ReportIsNotFunction |
506 |
|
|
* |
507 |
|
|
* See jsfun.h for the latter four and flag renaming macros. |
508 |
|
|
*/ |
509 |
|
|
#define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING |
510 |
|
|
#define JSINVOKE_ITERATOR JSFRAME_ITERATOR |
511 |
|
|
|
512 |
|
|
/* |
513 |
|
|
* Mask to isolate construct and iterator flags for use with jsfun.h functions. |
514 |
|
|
*/ |
515 |
|
|
#define JSINVOKE_FUNFLAGS (JSINVOKE_CONSTRUCT | JSINVOKE_ITERATOR) |
516 |
|
|
|
517 |
|
|
/* |
518 |
|
|
* "Internal" calls may come from C or C++ code using a JSContext on which no |
519 |
|
|
* JS is running (!cx->fp), so they may need to push a dummy JSStackFrame. |
520 |
|
|
*/ |
521 |
|
|
#define js_InternalCall(cx,obj,fval,argc,argv,rval) \ |
522 |
|
|
js_InternalInvoke(cx, obj, fval, 0, argc, argv, rval) |
523 |
|
|
|
524 |
|
|
#define js_InternalConstruct(cx,obj,fval,argc,argv,rval) \ |
525 |
|
|
js_InternalInvoke(cx, obj, fval, JSINVOKE_CONSTRUCT, argc, argv, rval) |
526 |
|
|
|
527 |
|
|
extern JSBool |
528 |
|
|
js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags, |
529 |
|
|
uintN argc, jsval *argv, jsval *rval); |
530 |
|
|
|
531 |
|
|
extern JSBool |
532 |
|
|
js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval, |
533 |
|
|
JSAccessMode mode, uintN argc, jsval *argv, jsval *rval); |
534 |
|
|
|
535 |
siliconforks |
460 |
extern JS_FORCES_STACK JSBool |
536 |
siliconforks |
332 |
js_Execute(JSContext *cx, JSObject *chain, JSScript *script, |
537 |
|
|
JSStackFrame *down, uintN flags, jsval *result); |
538 |
|
|
|
539 |
siliconforks |
460 |
extern JS_REQUIRES_STACK JSBool |
540 |
siliconforks |
332 |
js_InvokeConstructor(JSContext *cx, uintN argc, JSBool clampReturn, jsval *vp); |
541 |
|
|
|
542 |
siliconforks |
460 |
extern JS_REQUIRES_STACK JSBool |
543 |
siliconforks |
332 |
js_Interpret(JSContext *cx); |
544 |
|
|
|
545 |
|
|
#define JSPROP_INITIALIZER 0x100 /* NB: Not a valid property attribute. */ |
546 |
|
|
|
547 |
|
|
extern JSBool |
548 |
|
|
js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, |
549 |
|
|
JSObject **objp, JSProperty **propp); |
550 |
|
|
|
551 |
|
|
extern JSBool |
552 |
|
|
js_StrictlyEqual(JSContext *cx, jsval lval, jsval rval); |
553 |
|
|
|
554 |
siliconforks |
460 |
extern JSBool |
555 |
|
|
js_InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp); |
556 |
|
|
|
557 |
|
|
/* Work around liveconnect building this file as C on 1.9.1 branch */ |
558 |
|
|
#ifdef __cplusplus |
559 |
|
|
|
560 |
siliconforks |
332 |
/* |
561 |
siliconforks |
460 |
* Given an active context, a static scope level, and an upvar cookie, return |
562 |
|
|
* the value of the upvar. |
563 |
|
|
*/ |
564 |
|
|
extern jsval& |
565 |
|
|
js_GetUpvar(JSContext *cx, uintN level, uintN cookie); |
566 |
|
|
|
567 |
|
|
#endif |
568 |
|
|
|
569 |
|
|
/* |
570 |
siliconforks |
332 |
* JS_LONE_INTERPRET indicates that the compiler should see just the code for |
571 |
|
|
* the js_Interpret function when compiling jsinterp.cpp. The rest of the code |
572 |
|
|
* from the file should be visible only when compiling jsinvoke.cpp. It allows |
573 |
|
|
* platform builds to optimize selectively js_Interpret when the granularity |
574 |
|
|
* of the optimizations with the given compiler is a compilation unit. |
575 |
|
|
* |
576 |
|
|
* JS_STATIC_INTERPRET is the modifier for functions defined in jsinterp.cpp |
577 |
|
|
* that only js_Interpret calls. When JS_LONE_INTERPRET is true all such |
578 |
|
|
* functions are declared below. |
579 |
|
|
*/ |
580 |
|
|
#ifndef JS_LONE_INTERPRET |
581 |
|
|
# ifdef _MSC_VER |
582 |
|
|
# define JS_LONE_INTERPRET 0 |
583 |
|
|
# else |
584 |
|
|
# define JS_LONE_INTERPRET 1 |
585 |
|
|
# endif |
586 |
|
|
#endif |
587 |
|
|
|
588 |
|
|
#if !JS_LONE_INTERPRET |
589 |
|
|
# define JS_STATIC_INTERPRET static |
590 |
|
|
#else |
591 |
|
|
# define JS_STATIC_INTERPRET |
592 |
|
|
|
593 |
siliconforks |
460 |
extern JS_REQUIRES_STACK jsval * |
594 |
siliconforks |
332 |
js_AllocRawStack(JSContext *cx, uintN nslots, void **markp); |
595 |
|
|
|
596 |
siliconforks |
460 |
extern JS_REQUIRES_STACK void |
597 |
siliconforks |
332 |
js_FreeRawStack(JSContext *cx, void *mark); |
598 |
|
|
|
599 |
|
|
/* |
600 |
|
|
* ECMA requires "the global object", but in embeddings such as the browser, |
601 |
|
|
* which have multiple top-level objects (windows, frames, etc. in the DOM), |
602 |
|
|
* we prefer fun's parent. An example that causes this code to run: |
603 |
|
|
* |
604 |
|
|
* // in window w1 |
605 |
|
|
* function f() { return this } |
606 |
|
|
* function g() { return f } |
607 |
|
|
* |
608 |
|
|
* // in window w2 |
609 |
|
|
* var h = w1.g() |
610 |
|
|
* alert(h() == w1) |
611 |
|
|
* |
612 |
|
|
* The alert should display "true". |
613 |
|
|
*/ |
614 |
|
|
extern JSObject * |
615 |
|
|
js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv); |
616 |
|
|
|
617 |
siliconforks |
460 |
extern JS_REQUIRES_STACK JSBool |
618 |
siliconforks |
332 |
js_EnterWith(JSContext *cx, jsint stackIndex); |
619 |
|
|
|
620 |
siliconforks |
460 |
extern JS_REQUIRES_STACK void |
621 |
siliconforks |
332 |
js_LeaveWith(JSContext *cx); |
622 |
|
|
|
623 |
siliconforks |
460 |
extern JS_REQUIRES_STACK JSClass * |
624 |
siliconforks |
332 |
js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth); |
625 |
|
|
|
626 |
|
|
/* |
627 |
|
|
* Unwind block and scope chains to match the given depth. The function sets |
628 |
|
|
* fp->sp on return to stackDepth. |
629 |
|
|
*/ |
630 |
siliconforks |
460 |
extern JS_REQUIRES_STACK JSBool |
631 |
siliconforks |
332 |
js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth, |
632 |
|
|
JSBool normalUnwind); |
633 |
|
|
|
634 |
|
|
extern JSBool |
635 |
|
|
js_OnUnknownMethod(JSContext *cx, jsval *vp); |
636 |
|
|
|
637 |
|
|
/* |
638 |
|
|
* Find the results of incrementing or decrementing *vp. For pre-increments, |
639 |
|
|
* both *vp and *vp2 will contain the result on return. For post-increments, |
640 |
|
|
* vp will contain the original value converted to a number and vp2 will get |
641 |
|
|
* the result. Both vp and vp2 must be roots. |
642 |
|
|
*/ |
643 |
|
|
extern JSBool |
644 |
|
|
js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2); |
645 |
|
|
|
646 |
|
|
/* |
647 |
|
|
* Opcode tracing helper. When len is not 0, cx->fp->regs->pc[-len] gives the |
648 |
|
|
* previous opcode. |
649 |
|
|
*/ |
650 |
siliconforks |
460 |
extern JS_REQUIRES_STACK void |
651 |
|
|
js_TraceOpcode(JSContext *cx); |
652 |
siliconforks |
332 |
|
653 |
|
|
/* |
654 |
|
|
* JS_OPMETER helper functions. |
655 |
|
|
*/ |
656 |
|
|
extern void |
657 |
|
|
js_MeterOpcodePair(JSOp op1, JSOp op2); |
658 |
|
|
|
659 |
|
|
extern void |
660 |
|
|
js_MeterSlotOpcode(JSOp op, uint32 slot); |
661 |
|
|
|
662 |
|
|
#endif /* JS_LONE_INTERPRET */ |
663 |
|
|
|
664 |
|
|
JS_END_EXTERN_C |
665 |
|
|
|
666 |
|
|
#endif /* jsinterp_h___ */ |