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 |
jsval argsobj; /* lazily created arguments object, must be |
75 |
JSVAL_OBJECT */ |
76 |
JSObject *varobj; /* variables object, where vars go */ |
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 |
JSStackFrame *displaySave; /* previous value of display entry for |
130 |
script->staticLevel */ |
131 |
|
132 |
#ifdef __cplusplus /* Allow inclusion from LiveConnect C files. */ |
133 |
|
134 |
inline void assertValidStackDepth(uintN depth); |
135 |
|
136 |
void putActivationObjects(JSContext *cx) { |
137 |
/* |
138 |
* The order of calls here is important as js_PutCallObject needs to |
139 |
* access argsobj. |
140 |
*/ |
141 |
if (callobj) { |
142 |
js_PutCallObject(cx, this); |
143 |
JS_ASSERT(!argsobj); |
144 |
} else if (argsobj) { |
145 |
js_PutArgsObject(cx, this); |
146 |
} |
147 |
} |
148 |
|
149 |
JSObject *callee() { |
150 |
return argv ? JSVAL_TO_OBJECT(argv[-2]) : NULL; |
151 |
} |
152 |
|
153 |
#endif /* __cplusplus */ |
154 |
}; |
155 |
|
156 |
#ifdef __cplusplus |
157 |
|
158 |
static JS_INLINE uintN |
159 |
FramePCOffset(JSStackFrame* fp) |
160 |
{ |
161 |
return uintN((fp->imacpc ? fp->imacpc : fp->regs->pc) - fp->script->code); |
162 |
} |
163 |
|
164 |
static JS_INLINE jsval * |
165 |
StackBase(JSStackFrame *fp) |
166 |
{ |
167 |
return fp->slots + fp->script->nfixed; |
168 |
} |
169 |
|
170 |
void |
171 |
JSStackFrame::assertValidStackDepth(uintN depth) |
172 |
{ |
173 |
JS_ASSERT(0 <= regs->sp - StackBase(this)); |
174 |
JS_ASSERT(depth <= uintptr_t(regs->sp - StackBase(this))); |
175 |
} |
176 |
|
177 |
static JS_INLINE uintN |
178 |
GlobalVarCount(JSStackFrame *fp) |
179 |
{ |
180 |
uintN n; |
181 |
|
182 |
JS_ASSERT(!fp->fun); |
183 |
n = fp->script->nfixed; |
184 |
if (fp->script->regexpsOffset != 0) |
185 |
n -= fp->script->regexps()->length; |
186 |
return n; |
187 |
} |
188 |
|
189 |
#endif /* __cplusplus */ |
190 |
|
191 |
typedef struct JSInlineFrame { |
192 |
JSStackFrame frame; /* base struct */ |
193 |
JSFrameRegs callerRegs; /* parent's frame registers */ |
194 |
void *mark; /* mark before inline frame */ |
195 |
void *hookData; /* debugger call hook data */ |
196 |
JSVersion callerVersion; /* dynamic version of calling script */ |
197 |
} JSInlineFrame; |
198 |
|
199 |
/* JS stack frame flags. */ |
200 |
#define JSFRAME_CONSTRUCTING 0x01 /* frame is for a constructor invocation */ |
201 |
#define JSFRAME_COMPUTED_THIS 0x02 /* frame.thisp was computed already */ |
202 |
#define JSFRAME_ASSIGNING 0x04 /* a complex (not simplex JOF_ASSIGNING) op |
203 |
is currently assigning to a property */ |
204 |
#define JSFRAME_DEBUGGER 0x08 /* frame for JS_EvaluateInStackFrame */ |
205 |
#define JSFRAME_EVAL 0x10 /* frame for obj_eval */ |
206 |
#define JSFRAME_ROOTED_ARGV 0x20 /* frame.argv is rooted by the caller */ |
207 |
#define JSFRAME_YIELDING 0x40 /* js_Interpret dispatched JSOP_YIELD */ |
208 |
#define JSFRAME_ITERATOR 0x80 /* trying to get an iterator for for-in */ |
209 |
#define JSFRAME_GENERATOR 0x200 /* frame belongs to generator-iterator */ |
210 |
#define JSFRAME_OVERRIDE_ARGS 0x400 /* overridden arguments local variable */ |
211 |
|
212 |
#define JSFRAME_SPECIAL (JSFRAME_DEBUGGER | JSFRAME_EVAL) |
213 |
|
214 |
/* |
215 |
* Property cache with structurally typed capabilities for invalidation, for |
216 |
* polymorphic callsite method/get/set speedups. For details, see |
217 |
* <https://developer.mozilla.org/en/SpiderMonkey/Internals/Property_cache>. |
218 |
*/ |
219 |
#define PROPERTY_CACHE_LOG2 12 |
220 |
#define PROPERTY_CACHE_SIZE JS_BIT(PROPERTY_CACHE_LOG2) |
221 |
#define PROPERTY_CACHE_MASK JS_BITMASK(PROPERTY_CACHE_LOG2) |
222 |
|
223 |
/* |
224 |
* Add kshape rather than xor it to avoid collisions between nearby bytecode |
225 |
* that are evolving an object by setting successive properties, incrementing |
226 |
* the object's scope->shape on each set. |
227 |
*/ |
228 |
#define PROPERTY_CACHE_HASH(pc,kshape) \ |
229 |
(((((jsuword)(pc) >> PROPERTY_CACHE_LOG2) ^ (jsuword)(pc)) + (kshape)) & \ |
230 |
PROPERTY_CACHE_MASK) |
231 |
|
232 |
#define PROPERTY_CACHE_HASH_PC(pc,kshape) \ |
233 |
PROPERTY_CACHE_HASH(pc, kshape) |
234 |
|
235 |
#define PROPERTY_CACHE_HASH_ATOM(atom,obj) \ |
236 |
PROPERTY_CACHE_HASH((jsuword)(atom) >> 2, OBJ_SHAPE(obj)) |
237 |
|
238 |
/* |
239 |
* Property cache value capability macros. |
240 |
*/ |
241 |
#define PCVCAP_PROTOBITS 4 |
242 |
#define PCVCAP_PROTOSIZE JS_BIT(PCVCAP_PROTOBITS) |
243 |
#define PCVCAP_PROTOMASK JS_BITMASK(PCVCAP_PROTOBITS) |
244 |
|
245 |
#define PCVCAP_SCOPEBITS 4 |
246 |
#define PCVCAP_SCOPESIZE JS_BIT(PCVCAP_SCOPEBITS) |
247 |
#define PCVCAP_SCOPEMASK JS_BITMASK(PCVCAP_SCOPEBITS) |
248 |
|
249 |
#define PCVCAP_TAGBITS (PCVCAP_PROTOBITS + PCVCAP_SCOPEBITS) |
250 |
#define PCVCAP_TAGMASK JS_BITMASK(PCVCAP_TAGBITS) |
251 |
#define PCVCAP_TAG(t) ((t) & PCVCAP_TAGMASK) |
252 |
|
253 |
#define PCVCAP_MAKE(t,s,p) ((uint32(t) << PCVCAP_TAGBITS) | \ |
254 |
((s) << PCVCAP_PROTOBITS) | \ |
255 |
(p)) |
256 |
#define PCVCAP_SHAPE(t) ((t) >> PCVCAP_TAGBITS) |
257 |
|
258 |
#define SHAPE_OVERFLOW_BIT JS_BIT(32 - PCVCAP_TAGBITS) |
259 |
|
260 |
struct JSPropCacheEntry { |
261 |
jsbytecode *kpc; /* pc if vcap tag is <= 1, else atom */ |
262 |
jsuword kshape; /* key shape if pc, else obj for atom */ |
263 |
jsuword vcap; /* value capability, see above */ |
264 |
jsuword vword; /* value word, see PCVAL_* below */ |
265 |
|
266 |
#ifdef __cplusplus /* Allow inclusion from LiveConnect C files. */ |
267 |
bool adding() const { |
268 |
return PCVCAP_TAG(vcap) == 0 && kshape != PCVCAP_SHAPE(vcap); |
269 |
} |
270 |
#endif |
271 |
}; |
272 |
|
273 |
/* |
274 |
* Special value for functions returning JSPropCacheEntry * to distinguish |
275 |
* between failure and no no-cache-fill cases. |
276 |
*/ |
277 |
#define JS_NO_PROP_CACHE_FILL ((JSPropCacheEntry *) NULL + 1) |
278 |
|
279 |
#if defined DEBUG_brendan || defined DEBUG_brendaneich |
280 |
#define JS_PROPERTY_CACHE_METERING 1 |
281 |
#endif |
282 |
|
283 |
typedef struct JSPropertyCache { |
284 |
JSPropCacheEntry table[PROPERTY_CACHE_SIZE]; |
285 |
JSBool empty; |
286 |
#ifdef JS_PROPERTY_CACHE_METERING |
287 |
JSPropCacheEntry *pctestentry; /* entry of the last PC-based test */ |
288 |
uint32 fills; /* number of cache entry fills */ |
289 |
uint32 nofills; /* couldn't fill (e.g. default get) */ |
290 |
uint32 rofills; /* set on read-only prop can't fill */ |
291 |
uint32 disfills; /* fill attempts on disabled cache */ |
292 |
uint32 oddfills; /* fill attempt after setter deleted */ |
293 |
uint32 modfills; /* fill that rehashed to a new entry */ |
294 |
uint32 brandfills; /* scope brandings to type structural |
295 |
method fills */ |
296 |
uint32 noprotos; /* resolve-returned non-proto pobj */ |
297 |
uint32 longchains; /* overlong scope and/or proto chain */ |
298 |
uint32 recycles; /* cache entries recycled by fills */ |
299 |
uint32 pcrecycles; /* pc-keyed entries recycled by atom- |
300 |
keyed fills */ |
301 |
uint32 tests; /* cache probes */ |
302 |
uint32 pchits; /* fast-path polymorphic op hits */ |
303 |
uint32 protopchits; /* pchits hitting immediate prototype */ |
304 |
uint32 initests; /* cache probes from JSOP_INITPROP */ |
305 |
uint32 inipchits; /* init'ing next property pchit case */ |
306 |
uint32 inipcmisses; /* init'ing next property pc misses */ |
307 |
uint32 settests; /* cache probes from JOF_SET opcodes */ |
308 |
uint32 addpchits; /* adding next property pchit case */ |
309 |
uint32 setpchits; /* setting existing property pchit */ |
310 |
uint32 setpcmisses; /* setting/adding property pc misses */ |
311 |
uint32 slotchanges; /* clasp->reserveSlots result variance- |
312 |
induced slot changes */ |
313 |
uint32 setmisses; /* JSOP_SET{NAME,PROP} total misses */ |
314 |
uint32 idmisses; /* slow-path key id == atom misses */ |
315 |
uint32 komisses; /* slow-path key object misses */ |
316 |
uint32 vcmisses; /* value capability misses */ |
317 |
uint32 misses; /* cache misses */ |
318 |
uint32 flushes; /* cache flushes */ |
319 |
uint32 pcpurges; /* shadowing purges on proto chain */ |
320 |
# define PCMETER(x) x |
321 |
#else |
322 |
# define PCMETER(x) ((void)0) |
323 |
#endif |
324 |
} JSPropertyCache; |
325 |
|
326 |
/* |
327 |
* Property cache value tagging/untagging macros. |
328 |
*/ |
329 |
#define PCVAL_OBJECT 0 |
330 |
#define PCVAL_SLOT 1 |
331 |
#define PCVAL_SPROP 2 |
332 |
|
333 |
#define PCVAL_TAGBITS 2 |
334 |
#define PCVAL_TAGMASK JS_BITMASK(PCVAL_TAGBITS) |
335 |
#define PCVAL_TAG(v) ((v) & PCVAL_TAGMASK) |
336 |
#define PCVAL_CLRTAG(v) ((v) & ~(jsuword)PCVAL_TAGMASK) |
337 |
#define PCVAL_SETTAG(v,t) ((jsuword)(v) | (t)) |
338 |
|
339 |
#define PCVAL_NULL 0 |
340 |
#define PCVAL_IS_NULL(v) ((v) == PCVAL_NULL) |
341 |
|
342 |
#define PCVAL_IS_OBJECT(v) (PCVAL_TAG(v) == PCVAL_OBJECT) |
343 |
#define PCVAL_TO_OBJECT(v) ((JSObject *) (v)) |
344 |
#define OBJECT_TO_PCVAL(obj) ((jsuword) (obj)) |
345 |
|
346 |
#define PCVAL_OBJECT_TO_JSVAL(v) OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v)) |
347 |
#define JSVAL_OBJECT_TO_PCVAL(v) OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v)) |
348 |
|
349 |
#define PCVAL_IS_SLOT(v) ((v) & PCVAL_SLOT) |
350 |
#define PCVAL_TO_SLOT(v) ((jsuint)(v) >> 1) |
351 |
#define SLOT_TO_PCVAL(i) (((jsuword)(i) << 1) | PCVAL_SLOT) |
352 |
|
353 |
#define PCVAL_IS_SPROP(v) (PCVAL_TAG(v) == PCVAL_SPROP) |
354 |
#define PCVAL_TO_SPROP(v) ((JSScopeProperty *) PCVAL_CLRTAG(v)) |
355 |
#define SPROP_TO_PCVAL(sprop) PCVAL_SETTAG(sprop, PCVAL_SPROP) |
356 |
|
357 |
/* |
358 |
* Fill property cache entry for key cx->fp->pc, optimized value word computed |
359 |
* from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj), |
360 |
* 4-bit scopeIndex, and 4-bit protoIndex. |
361 |
* |
362 |
* Return the filled cache entry or JS_NO_PROP_CACHE_FILL if caching was not |
363 |
* possible. |
364 |
*/ |
365 |
extern JS_REQUIRES_STACK JSPropCacheEntry * |
366 |
js_FillPropertyCache(JSContext *cx, JSObject *obj, |
367 |
uintN scopeIndex, uintN protoIndex, JSObject *pobj, |
368 |
JSScopeProperty *sprop, JSBool adding); |
369 |
|
370 |
/* |
371 |
* Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the |
372 |
* fast path in js_Interpret, so it makes "just-so" restrictions on parameters, |
373 |
* e.g. pobj and obj should not be the same variable, since for JOF_PROP-mode |
374 |
* opcodes, obj must not be changed because of a cache miss. |
375 |
* |
376 |
* On return from PROPERTY_CACHE_TEST, if atom is null then obj points to the |
377 |
* scope chain element in which the property was found, pobj is locked, and |
378 |
* entry is valid. If atom is non-null then no object is locked but entry is |
379 |
* still set correctly for use, e.g., by js_FillPropertyCache and atom should |
380 |
* be used as the id to find. |
381 |
* |
382 |
* We must lock pobj on a hit in order to close races with threads that might |
383 |
* be deleting a property from its scope, or otherwise invalidating property |
384 |
* caches (on all threads) by re-generating scope->shape. |
385 |
*/ |
386 |
#define PROPERTY_CACHE_TEST(cx, pc, obj, pobj, entry, atom) \ |
387 |
do { \ |
388 |
JSPropertyCache *cache_ = &JS_PROPERTY_CACHE(cx); \ |
389 |
uint32 kshape_ = (JS_ASSERT(OBJ_IS_NATIVE(obj)), OBJ_SHAPE(obj)); \ |
390 |
entry = &cache_->table[PROPERTY_CACHE_HASH_PC(pc, kshape_)]; \ |
391 |
PCMETER(cache_->pctestentry = entry); \ |
392 |
PCMETER(cache_->tests++); \ |
393 |
JS_ASSERT(&obj != &pobj); \ |
394 |
if (entry->kpc == pc && entry->kshape == kshape_) { \ |
395 |
JSObject *tmp_; \ |
396 |
pobj = obj; \ |
397 |
JS_ASSERT(PCVCAP_TAG(entry->vcap) <= 1); \ |
398 |
if (PCVCAP_TAG(entry->vcap) == 1 && \ |
399 |
(tmp_ = OBJ_GET_PROTO(cx, pobj)) != NULL) { \ |
400 |
pobj = tmp_; \ |
401 |
} \ |
402 |
\ |
403 |
if (JS_LOCK_OBJ_IF_SHAPE(cx, pobj, PCVCAP_SHAPE(entry->vcap))) { \ |
404 |
PCMETER(cache_->pchits++); \ |
405 |
PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \ |
406 |
atom = NULL; \ |
407 |
break; \ |
408 |
} \ |
409 |
} \ |
410 |
atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, &entry); \ |
411 |
if (atom) \ |
412 |
PCMETER(cache_->misses++); \ |
413 |
} while (0) |
414 |
|
415 |
extern JS_REQUIRES_STACK JSAtom * |
416 |
js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc, |
417 |
JSObject **objp, JSObject **pobjp, |
418 |
JSPropCacheEntry **entryp); |
419 |
|
420 |
/* The property cache does not need a destructor. */ |
421 |
#define js_FinishPropertyCache(cache) ((void) 0) |
422 |
|
423 |
extern void |
424 |
js_PurgePropertyCache(JSContext *cx, JSPropertyCache *cache); |
425 |
|
426 |
extern void |
427 |
js_PurgePropertyCacheForScript(JSContext *cx, JSScript *script); |
428 |
|
429 |
/* |
430 |
* Interpreter stack arena-pool alloc and free functions. |
431 |
*/ |
432 |
extern JS_REQUIRES_STACK JS_FRIEND_API(jsval *) |
433 |
js_AllocStack(JSContext *cx, uintN nslots, void **markp); |
434 |
|
435 |
extern JS_REQUIRES_STACK JS_FRIEND_API(void) |
436 |
js_FreeStack(JSContext *cx, void *mark); |
437 |
|
438 |
/* |
439 |
* Refresh and return fp->scopeChain. It may be stale if block scopes are |
440 |
* active but not yet reflected by objects in the scope chain. If a block |
441 |
* scope contains a with, eval, XML filtering predicate, or similar such |
442 |
* dynamically scoped construct, then compile-time block scope at fp->blocks |
443 |
* must reflect at runtime. |
444 |
*/ |
445 |
extern JSObject * |
446 |
js_GetScopeChain(JSContext *cx, JSStackFrame *fp); |
447 |
|
448 |
/* |
449 |
* Given a context and a vector of [callee, this, args...] for a function that |
450 |
* was specified with a JSFUN_THISP_PRIMITIVE flag, get the primitive value of |
451 |
* |this| into *thisvp. In doing so, if |this| is an object, insist it is an |
452 |
* instance of clasp and extract its private slot value to return via *thisvp. |
453 |
* |
454 |
* NB: this function loads and uses *vp before storing *thisvp, so the two may |
455 |
* alias the same jsval. |
456 |
*/ |
457 |
extern JSBool |
458 |
js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp); |
459 |
|
460 |
/* |
461 |
* For a call with arguments argv including argv[-1] (nominal |this|) and |
462 |
* argv[-2] (callee) replace null |this| with callee's parent, replace |
463 |
* primitive values with the equivalent wrapper objects and censor activation |
464 |
* objects as, per ECMA-262, they may not be referred to by |this|. argv[-1] |
465 |
* must not be a JSVAL_VOID. |
466 |
*/ |
467 |
extern JSObject * |
468 |
js_ComputeThis(JSContext *cx, JSBool lazy, jsval *argv); |
469 |
|
470 |
extern const uint16 js_PrimitiveTestFlags[]; |
471 |
|
472 |
#define PRIMITIVE_THIS_TEST(fun,thisv) \ |
473 |
(JS_ASSERT(!JSVAL_IS_VOID(thisv)), \ |
474 |
JSFUN_THISP_TEST(JSFUN_THISP_FLAGS((fun)->flags), \ |
475 |
js_PrimitiveTestFlags[JSVAL_TAG(thisv) - 1])) |
476 |
|
477 |
#ifdef __cplusplus /* Aargh, libgjs, bug 492720. */ |
478 |
static JS_INLINE JSObject * |
479 |
js_ComputeThisForFrame(JSContext *cx, JSStackFrame *fp) |
480 |
{ |
481 |
if (fp->flags & JSFRAME_COMPUTED_THIS) |
482 |
return fp->thisp; |
483 |
JSObject* obj = js_ComputeThis(cx, JS_TRUE, fp->argv); |
484 |
if (!obj) |
485 |
return NULL; |
486 |
fp->thisp = obj; |
487 |
fp->flags |= JSFRAME_COMPUTED_THIS; |
488 |
return obj; |
489 |
} |
490 |
#endif |
491 |
|
492 |
/* |
493 |
* NB: js_Invoke requires that cx is currently running JS (i.e., that cx->fp |
494 |
* is non-null), and that vp points to the callee, |this| parameter, and |
495 |
* actual arguments of the call. [vp .. vp + 2 + argc) must belong to the last |
496 |
* JS stack segment that js_AllocStack allocated. The function may use the |
497 |
* space available after vp + 2 + argc in the stack segment for temporaries, |
498 |
* so the caller should not use that space for values that must be preserved |
499 |
* across the call. |
500 |
*/ |
501 |
extern JS_REQUIRES_STACK JS_FRIEND_API(JSBool) |
502 |
js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags); |
503 |
|
504 |
/* |
505 |
* Consolidated js_Invoke flags simply rename certain JSFRAME_* flags, so that |
506 |
* we can share bits stored in JSStackFrame.flags and passed to: |
507 |
* |
508 |
* js_Invoke |
509 |
* js_InternalInvoke |
510 |
* js_ValueToFunction |
511 |
* js_ValueToFunctionObject |
512 |
* js_ValueToCallableObject |
513 |
* js_ReportIsNotFunction |
514 |
* |
515 |
* See jsfun.h for the latter four and flag renaming macros. |
516 |
*/ |
517 |
#define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING |
518 |
#define JSINVOKE_ITERATOR JSFRAME_ITERATOR |
519 |
|
520 |
/* |
521 |
* Mask to isolate construct and iterator flags for use with jsfun.h functions. |
522 |
*/ |
523 |
#define JSINVOKE_FUNFLAGS (JSINVOKE_CONSTRUCT | JSINVOKE_ITERATOR) |
524 |
|
525 |
/* |
526 |
* "Internal" calls may come from C or C++ code using a JSContext on which no |
527 |
* JS is running (!cx->fp), so they may need to push a dummy JSStackFrame. |
528 |
*/ |
529 |
#define js_InternalCall(cx,obj,fval,argc,argv,rval) \ |
530 |
js_InternalInvoke(cx, obj, fval, 0, argc, argv, rval) |
531 |
|
532 |
#define js_InternalConstruct(cx,obj,fval,argc,argv,rval) \ |
533 |
js_InternalInvoke(cx, obj, fval, JSINVOKE_CONSTRUCT, argc, argv, rval) |
534 |
|
535 |
extern JSBool |
536 |
js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags, |
537 |
uintN argc, jsval *argv, jsval *rval); |
538 |
|
539 |
extern JSBool |
540 |
js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval, |
541 |
JSAccessMode mode, uintN argc, jsval *argv, jsval *rval); |
542 |
|
543 |
extern JS_FORCES_STACK JSBool |
544 |
js_Execute(JSContext *cx, JSObject *chain, JSScript *script, |
545 |
JSStackFrame *down, uintN flags, jsval *result); |
546 |
|
547 |
extern JS_REQUIRES_STACK JSBool |
548 |
js_InvokeConstructor(JSContext *cx, uintN argc, JSBool clampReturn, jsval *vp); |
549 |
|
550 |
extern JS_REQUIRES_STACK JSBool |
551 |
js_Interpret(JSContext *cx); |
552 |
|
553 |
#define JSPROP_INITIALIZER 0x100 /* NB: Not a valid property attribute. */ |
554 |
|
555 |
extern JSBool |
556 |
js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, |
557 |
JSObject **objp, JSProperty **propp); |
558 |
|
559 |
extern JSBool |
560 |
js_StrictlyEqual(JSContext *cx, jsval lval, jsval rval); |
561 |
|
562 |
/* === except that NaN is the same as NaN and -0 is not the same as +0. */ |
563 |
extern JSBool |
564 |
js_SameValue(jsval v1, jsval v2, JSContext *cx); |
565 |
|
566 |
extern JSBool |
567 |
js_InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp); |
568 |
|
569 |
#ifdef __cplusplus /* Allow inclusion from LiveConnect C files. */ |
570 |
|
571 |
/* |
572 |
* Given an active context, a static scope level, and an upvar cookie, return |
573 |
* the value of the upvar. |
574 |
*/ |
575 |
extern jsval& |
576 |
js_GetUpvar(JSContext *cx, uintN level, uintN cookie); |
577 |
|
578 |
#endif /* __cplusplus */ |
579 |
|
580 |
/* |
581 |
* JS_LONE_INTERPRET indicates that the compiler should see just the code for |
582 |
* the js_Interpret function when compiling jsinterp.cpp. The rest of the code |
583 |
* from the file should be visible only when compiling jsinvoke.cpp. It allows |
584 |
* platform builds to optimize selectively js_Interpret when the granularity |
585 |
* of the optimizations with the given compiler is a compilation unit. |
586 |
* |
587 |
* JS_STATIC_INTERPRET is the modifier for functions defined in jsinterp.cpp |
588 |
* that only js_Interpret calls. When JS_LONE_INTERPRET is true all such |
589 |
* functions are declared below. |
590 |
*/ |
591 |
#ifndef JS_LONE_INTERPRET |
592 |
# ifdef _MSC_VER |
593 |
# define JS_LONE_INTERPRET 0 |
594 |
# else |
595 |
# define JS_LONE_INTERPRET 1 |
596 |
# endif |
597 |
#endif |
598 |
|
599 |
#if !JS_LONE_INTERPRET |
600 |
# define JS_STATIC_INTERPRET static |
601 |
#else |
602 |
# define JS_STATIC_INTERPRET |
603 |
|
604 |
extern JS_REQUIRES_STACK jsval * |
605 |
js_AllocRawStack(JSContext *cx, uintN nslots, void **markp); |
606 |
|
607 |
extern JS_REQUIRES_STACK void |
608 |
js_FreeRawStack(JSContext *cx, void *mark); |
609 |
|
610 |
/* |
611 |
* ECMA requires "the global object", but in embeddings such as the browser, |
612 |
* which have multiple top-level objects (windows, frames, etc. in the DOM), |
613 |
* we prefer fun's parent. An example that causes this code to run: |
614 |
* |
615 |
* // in window w1 |
616 |
* function f() { return this } |
617 |
* function g() { return f } |
618 |
* |
619 |
* // in window w2 |
620 |
* var h = w1.g() |
621 |
* alert(h() == w1) |
622 |
* |
623 |
* The alert should display "true". |
624 |
*/ |
625 |
extern JSObject * |
626 |
js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv); |
627 |
|
628 |
extern JS_REQUIRES_STACK JSBool |
629 |
js_EnterWith(JSContext *cx, jsint stackIndex); |
630 |
|
631 |
extern JS_REQUIRES_STACK void |
632 |
js_LeaveWith(JSContext *cx); |
633 |
|
634 |
extern JS_REQUIRES_STACK JSClass * |
635 |
js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth); |
636 |
|
637 |
/* |
638 |
* Unwind block and scope chains to match the given depth. The function sets |
639 |
* fp->sp on return to stackDepth. |
640 |
*/ |
641 |
extern JS_REQUIRES_STACK JSBool |
642 |
js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth, |
643 |
JSBool normalUnwind); |
644 |
|
645 |
extern JSBool |
646 |
js_OnUnknownMethod(JSContext *cx, jsval *vp); |
647 |
|
648 |
/* |
649 |
* Find the results of incrementing or decrementing *vp. For pre-increments, |
650 |
* both *vp and *vp2 will contain the result on return. For post-increments, |
651 |
* vp will contain the original value converted to a number and vp2 will get |
652 |
* the result. Both vp and vp2 must be roots. |
653 |
*/ |
654 |
extern JSBool |
655 |
js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2); |
656 |
|
657 |
/* |
658 |
* Opcode tracing helper. When len is not 0, cx->fp->regs->pc[-len] gives the |
659 |
* previous opcode. |
660 |
*/ |
661 |
extern JS_REQUIRES_STACK void |
662 |
js_TraceOpcode(JSContext *cx); |
663 |
|
664 |
/* |
665 |
* JS_OPMETER helper functions. |
666 |
*/ |
667 |
extern void |
668 |
js_MeterOpcodePair(JSOp op1, JSOp op2); |
669 |
|
670 |
extern void |
671 |
js_MeterSlotOpcode(JSOp op, uint32 slot); |
672 |
|
673 |
#endif /* JS_LONE_INTERPRET */ |
674 |
|
675 |
JS_END_EXTERN_C |
676 |
|
677 |
#endif /* jsinterp_h___ */ |