1 |
/* -*- 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 |
jsbytecode *imacpc; /* null or interpreter macro call pc */ |
72 |
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 |
|
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 |
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 |
script->staticLevel */ |
132 |
|
133 |
#ifdef __cplusplus /* Aargh, LiveConnect, bug 442399. */ |
134 |
inline void assertValidStackDepth(uintN depth); |
135 |
#endif |
136 |
}; |
137 |
|
138 |
#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 |
static JS_INLINE jsval * |
147 |
StackBase(JSStackFrame *fp) |
148 |
{ |
149 |
return fp->slots + fp->script->nfixed; |
150 |
} |
151 |
|
152 |
#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 |
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 |
#define PCVCAP_MAKE(t,s,p) ((uint32(t) << PCVCAP_TAGBITS) | \ |
239 |
((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 |
#ifndef JS_THREADSAFE |
246 |
# define js_GenerateShape(cx, gcLocked) js_GenerateShape (cx) |
247 |
#endif |
248 |
|
249 |
extern uint32 |
250 |
js_GenerateShape(JSContext *cx, JSBool gcLocked); |
251 |
|
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 |
/* |
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 |
#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 |
JSPropCacheEntry *pctestentry; /* entry of the last PC-based test */ |
274 |
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 |
* |
348 |
* Return the filled cache entry or JS_NO_PROP_CACHE_FILL if caching was not |
349 |
* possible. |
350 |
*/ |
351 |
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 |
|
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 |
PCMETER(cache_->pctestentry = entry); \ |
378 |
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 |
extern JS_REQUIRES_STACK JSAtom * |
407 |
js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, |
408 |
JSObject **objp, JSObject **pobjp, |
409 |
JSPropCacheEntry **entryp); |
410 |
|
411 |
/* The property cache does not need a destructor. */ |
412 |
#define js_FinishPropertyCache(cache) ((void) 0) |
413 |
|
414 |
extern void |
415 |
js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache); |
416 |
|
417 |
extern void |
418 |
js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script); |
419 |
|
420 |
/* |
421 |
* Interpreter stack arena-pool alloc and free functions. |
422 |
*/ |
423 |
extern JS_REQUIRES_STACK JS_FRIEND_API(jsval *) |
424 |
js_AllocStack(JSContext *cx, uintN nslots, void **markp); |
425 |
|
426 |
extern JS_REQUIRES_STACK JS_FRIEND_API(void) |
427 |
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 |
#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 |
/* |
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 |
extern JS_REQUIRES_STACK JS_FRIEND_API(JSBool) |
494 |
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 |
extern JS_FORCES_STACK JSBool |
536 |
js_Execute(JSContext *cx, JSObject *chain, JSScript *script, |
537 |
JSStackFrame *down, uintN flags, jsval *result); |
538 |
|
539 |
extern JS_REQUIRES_STACK JSBool |
540 |
js_InvokeConstructor(JSContext *cx, uintN argc, JSBool clampReturn, jsval *vp); |
541 |
|
542 |
extern JS_REQUIRES_STACK JSBool |
543 |
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 |
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 |
/* |
561 |
* 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 |
* 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 |
extern JS_REQUIRES_STACK jsval * |
594 |
js_AllocRawStack(JSContext *cx, uintN nslots, void **markp); |
595 |
|
596 |
extern JS_REQUIRES_STACK void |
597 |
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 |
extern JS_REQUIRES_STACK JSBool |
618 |
js_EnterWith(JSContext *cx, jsint stackIndex); |
619 |
|
620 |
extern JS_REQUIRES_STACK void |
621 |
js_LeaveWith(JSContext *cx); |
622 |
|
623 |
extern JS_REQUIRES_STACK JSClass * |
624 |
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 |
extern JS_REQUIRES_STACK JSBool |
631 |
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 |
extern JS_REQUIRES_STACK void |
651 |
js_TraceOpcode(JSContext *cx); |
652 |
|
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___ */ |