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 : * Nick Fitzgerald <nfitzgerald@mozilla.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either of the GNU General Public License Version 2 or later (the "GPL"),
30 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : /*
43 : * JS script operations.
44 : */
45 :
46 : #include <string.h>
47 : #include "jstypes.h"
48 : #include "jsutil.h"
49 : #include "jscrashreport.h"
50 : #include "jsprf.h"
51 : #include "jsapi.h"
52 : #include "jsatom.h"
53 : #include "jscntxt.h"
54 : #include "jsversion.h"
55 : #include "jsdbgapi.h"
56 : #include "jsfun.h"
57 : #include "jsgc.h"
58 : #include "jsgcmark.h"
59 : #include "jsinterp.h"
60 : #include "jslock.h"
61 : #include "jsnum.h"
62 : #include "jsopcode.h"
63 : #include "jsscope.h"
64 : #include "jsscript.h"
65 : #if JS_HAS_XDR
66 : #include "jsxdrapi.h"
67 : #endif
68 :
69 : #include "frontend/BytecodeEmitter.h"
70 : #include "frontend/Parser.h"
71 : #include "js/MemoryMetrics.h"
72 : #include "methodjit/MethodJIT.h"
73 : #include "methodjit/Retcon.h"
74 : #include "vm/Debugger.h"
75 :
76 : #include "jsinferinlines.h"
77 : #include "jsinterpinlines.h"
78 : #include "jsobjinlines.h"
79 : #include "jsscriptinlines.h"
80 :
81 : using namespace js;
82 : using namespace js::gc;
83 : using namespace js::frontend;
84 :
85 : namespace js {
86 :
87 : BindingKind
88 11472851 : Bindings::lookup(JSContext *cx, JSAtom *name, unsigned *indexp) const
89 : {
90 11472851 : if (!lastBinding)
91 93720 : return NONE;
92 :
93 : Shape **spp;
94 11379131 : Shape *shape = Shape::search(cx, lastBinding, ATOM_TO_JSID(name), &spp);
95 11379131 : if (!shape)
96 11302284 : return NONE;
97 :
98 76847 : if (indexp)
99 76837 : *indexp = shape->shortid();
100 :
101 76847 : if (shape->getter() == CallObject::getArgOp)
102 1870 : return ARGUMENT;
103 74977 : if (shape->getter() == CallObject::getUpvarOp)
104 0 : return UPVAR;
105 :
106 74977 : return shape->writable() ? VARIABLE : CONSTANT;
107 : }
108 :
109 : bool
110 2573514 : Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
111 : {
112 2573514 : if (!ensureShape(cx))
113 0 : return false;
114 :
115 : /*
116 : * We still follow 10.2.3 of ES3 and make argument and variable properties
117 : * of the Call objects enumerable. ES5 reformulated all of its Clause 10 to
118 : * avoid objects as activations, something we should do too.
119 : */
120 2573514 : unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
121 :
122 : uint16_t *indexp;
123 : PropertyOp getter;
124 : StrictPropertyOp setter;
125 2573514 : uint32_t slot = CallObject::RESERVED_SLOTS;
126 :
127 2573514 : if (kind == ARGUMENT) {
128 1419274 : JS_ASSERT(nvars == 0);
129 1419274 : JS_ASSERT(nupvars == 0);
130 1419274 : indexp = &nargs;
131 1419274 : getter = CallObject::getArgOp;
132 1419274 : setter = CallObject::setArgOp;
133 1419274 : slot += nargs;
134 1154240 : } else if (kind == UPVAR) {
135 148046 : indexp = &nupvars;
136 148046 : getter = CallObject::getUpvarOp;
137 148046 : setter = CallObject::setUpvarOp;
138 148046 : slot = lastBinding->maybeSlot();
139 148046 : attrs |= JSPROP_SHARED;
140 : } else {
141 1006194 : JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
142 1006194 : JS_ASSERT(nupvars == 0);
143 :
144 1006194 : indexp = &nvars;
145 1006194 : getter = CallObject::getVarOp;
146 1006194 : setter = CallObject::setVarOp;
147 1006194 : if (kind == CONSTANT)
148 18686 : attrs |= JSPROP_READONLY;
149 1006194 : slot += nargs + nvars;
150 : }
151 :
152 2573514 : if (*indexp == BINDING_COUNT_LIMIT) {
153 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
154 : (kind == ARGUMENT)
155 : ? JSMSG_TOO_MANY_FUN_ARGS
156 0 : : JSMSG_TOO_MANY_LOCALS);
157 0 : return false;
158 : }
159 :
160 : jsid id;
161 2573514 : if (!name) {
162 1556 : JS_ASSERT(kind == ARGUMENT); /* destructuring */
163 1556 : id = INT_TO_JSID(nargs);
164 : } else {
165 2571958 : id = ATOM_TO_JSID(name);
166 : }
167 :
168 2573514 : StackBaseShape base(&CallClass, NULL, BaseShape::VAROBJ);
169 2573514 : base.updateGetterSetter(attrs, getter, setter);
170 :
171 2573514 : UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base);
172 2573514 : if (!nbase)
173 0 : return NULL;
174 :
175 2573514 : StackShape child(nbase, id, slot, 0, attrs, Shape::HAS_SHORTID, *indexp);
176 :
177 : /* Shapes in bindings cannot be dictionaries. */
178 2573514 : Shape *shape = lastBinding->getChildBinding(cx, child);
179 2573514 : if (!shape)
180 0 : return false;
181 :
182 2573514 : lastBinding = shape;
183 2573514 : ++*indexp;
184 2573514 : return true;
185 : }
186 :
187 : Shape *
188 703452 : Bindings::callObjectShape(JSContext *cx) const
189 : {
190 703452 : if (!hasDup())
191 703443 : return lastShape();
192 :
193 : /*
194 : * Build a vector of non-duplicate properties in order from last added
195 : * to first (i.e., the order we normally have iterate over Shapes). Choose
196 : * the last added property in each set of dups.
197 : */
198 18 : Vector<const Shape *> shapes(cx);
199 18 : HashSet<jsid> seen(cx);
200 9 : if (!seen.init())
201 0 : return NULL;
202 :
203 27 : for (Shape::Range r = lastShape()->all(); !r.empty(); r.popFront()) {
204 18 : const Shape &s = r.front();
205 18 : HashSet<jsid>::AddPtr p = seen.lookupForAdd(s.propid());
206 18 : if (!p) {
207 9 : if (!seen.add(p, s.propid()))
208 0 : return NULL;
209 9 : if (!shapes.append(&s))
210 0 : return NULL;
211 : }
212 : }
213 :
214 : /*
215 : * Now build the Shape without duplicate properties.
216 : */
217 18 : RootedVarShape shape(cx);
218 9 : shape = initialShape(cx);
219 18 : for (int i = shapes.length() - 1; i >= 0; --i) {
220 9 : shape = shape->getChildBinding(cx, shapes[i]);
221 9 : if (!shape)
222 0 : return NULL;
223 : }
224 :
225 9 : return shape;
226 : }
227 :
228 : bool
229 380632 : Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
230 : {
231 380632 : JS_ASSERT(lastBinding);
232 380632 : JS_ASSERT(hasLocalNames());
233 :
234 380632 : Vector<JSAtom *> &names = *namesp;
235 380632 : JS_ASSERT(names.empty());
236 :
237 380632 : unsigned n = countLocalNames();
238 380632 : if (!names.growByUninitialized(n))
239 0 : return false;
240 :
241 : #ifdef DEBUG
242 380632 : JSAtom * const POISON = reinterpret_cast<JSAtom *>(0xdeadbeef);
243 1356381 : for (unsigned i = 0; i < n; i++)
244 975749 : names[i] = POISON;
245 : #endif
246 :
247 1356381 : for (Shape::Range r = lastBinding->all(); !r.empty(); r.popFront()) {
248 975749 : const Shape &shape = r.front();
249 975749 : unsigned index = uint16_t(shape.shortid());
250 :
251 975749 : if (shape.getter() == CallObject::getArgOp) {
252 510362 : JS_ASSERT(index < nargs);
253 465387 : } else if (shape.getter() == CallObject::getUpvarOp) {
254 69693 : JS_ASSERT(index < nupvars);
255 69693 : index += nargs + nvars;
256 : } else {
257 395694 : JS_ASSERT(index < nvars);
258 395694 : index += nargs;
259 : }
260 :
261 975749 : if (JSID_IS_ATOM(shape.propid())) {
262 975272 : names[index] = JSID_TO_ATOM(shape.propid());
263 : } else {
264 477 : JS_ASSERT(JSID_IS_INT(shape.propid()));
265 477 : JS_ASSERT(shape.getter() == CallObject::getArgOp);
266 477 : names[index] = NULL;
267 : }
268 : }
269 :
270 : #ifdef DEBUG
271 1356381 : for (unsigned i = 0; i < n; i++)
272 975749 : JS_ASSERT(names[i] != POISON);
273 : #endif
274 :
275 380632 : return true;
276 : }
277 :
278 : const Shape *
279 0 : Bindings::lastArgument() const
280 : {
281 0 : JS_ASSERT(lastBinding);
282 :
283 0 : const js::Shape *shape = lastVariable();
284 0 : if (nvars > 0) {
285 0 : while (shape->previous() && shape->getter() != CallObject::getArgOp)
286 0 : shape = shape->previous();
287 : }
288 0 : return shape;
289 : }
290 :
291 : const Shape *
292 420026 : Bindings::lastVariable() const
293 : {
294 420026 : JS_ASSERT(lastBinding);
295 :
296 420026 : const js::Shape *shape = lastUpvar();
297 420026 : if (nupvars > 0) {
298 0 : while (shape->getter() == CallObject::getUpvarOp)
299 0 : shape = shape->previous();
300 : }
301 420026 : return shape;
302 : }
303 :
304 : const Shape *
305 420026 : Bindings::lastUpvar() const
306 : {
307 420026 : JS_ASSERT(lastBinding);
308 420026 : return lastBinding;
309 : }
310 :
311 : void
312 1286213 : Bindings::makeImmutable()
313 : {
314 1286213 : JS_ASSERT(lastBinding);
315 1286213 : JS_ASSERT(!lastBinding->inDictionary());
316 1286213 : }
317 :
318 : void
319 6825145 : Bindings::trace(JSTracer *trc)
320 : {
321 6825145 : if (lastBinding)
322 6632047 : MarkShape(trc, &lastBinding, "shape");
323 6825145 : }
324 :
325 : #if JS_HAS_XDR
326 :
327 : static bool
328 27254 : XDRScriptConst(JSXDRState *xdr, HeapValue *vp)
329 : {
330 : /*
331 : * A script constant can be an arbitrary primitive value as they are used
332 : * to implement JSOP_LOOKUPSWITCH. But they cannot be objects, see
333 : * bug 407186.
334 : */
335 : enum ConstTag {
336 : SCRIPT_INT = 0,
337 : SCRIPT_DOUBLE = 1,
338 : SCRIPT_STRING = 2,
339 : SCRIPT_TRUE = 3,
340 : SCRIPT_FALSE = 4,
341 : SCRIPT_NULL = 5,
342 : SCRIPT_VOID = 6
343 : };
344 :
345 : uint32_t tag;
346 27254 : if (xdr->mode == JSXDR_ENCODE) {
347 25428 : if (vp->isInt32()) {
348 533 : tag = SCRIPT_INT;
349 24895 : } else if (vp->isDouble()) {
350 975 : tag = SCRIPT_DOUBLE;
351 23920 : } else if (vp->isString()) {
352 23920 : tag = SCRIPT_STRING;
353 0 : } else if (vp->isTrue()) {
354 0 : tag = SCRIPT_TRUE;
355 0 : } else if (vp->isFalse()) {
356 0 : tag = SCRIPT_FALSE;
357 0 : } else if (vp->isNull()) {
358 0 : tag = SCRIPT_NULL;
359 : } else {
360 0 : JS_ASSERT(vp->isUndefined());
361 0 : tag = SCRIPT_VOID;
362 : }
363 : }
364 :
365 27254 : if (!JS_XDRUint32(xdr, &tag))
366 0 : return false;
367 :
368 27254 : switch (tag) {
369 : case SCRIPT_INT: {
370 : uint32_t i;
371 533 : if (xdr->mode == JSXDR_ENCODE)
372 533 : i = uint32_t(vp->toInt32());
373 533 : if (!JS_XDRUint32(xdr, &i))
374 0 : return JS_FALSE;
375 533 : if (xdr->mode == JSXDR_DECODE)
376 0 : vp->init(Int32Value(int32_t(i)));
377 533 : break;
378 : }
379 : case SCRIPT_DOUBLE: {
380 : double d;
381 975 : if (xdr->mode == JSXDR_ENCODE)
382 975 : d = vp->toDouble();
383 975 : if (!JS_XDRDouble(xdr, &d))
384 0 : return false;
385 975 : if (xdr->mode == JSXDR_DECODE)
386 0 : vp->init(DoubleValue(d));
387 975 : break;
388 : }
389 : case SCRIPT_STRING: {
390 : JSString *str;
391 25746 : if (xdr->mode == JSXDR_ENCODE)
392 23920 : str = vp->toString();
393 25746 : if (!JS_XDRString(xdr, &str))
394 0 : return false;
395 25746 : if (xdr->mode == JSXDR_DECODE)
396 1826 : vp->init(StringValue(str));
397 25746 : break;
398 : }
399 : case SCRIPT_TRUE:
400 0 : if (xdr->mode == JSXDR_DECODE)
401 0 : vp->init(BooleanValue(true));
402 0 : break;
403 : case SCRIPT_FALSE:
404 0 : if (xdr->mode == JSXDR_DECODE)
405 0 : vp->init(BooleanValue(false));
406 0 : break;
407 : case SCRIPT_NULL:
408 0 : if (xdr->mode == JSXDR_DECODE)
409 0 : vp->init(NullValue());
410 0 : break;
411 : case SCRIPT_VOID:
412 0 : if (xdr->mode == JSXDR_DECODE)
413 0 : vp->init(UndefinedValue());
414 0 : break;
415 : }
416 27254 : return true;
417 : }
418 :
419 : static const char *
420 : SaveScriptFilename(JSContext *cx, const char *filename);
421 :
422 : JSBool
423 636231 : XDRScript(JSXDRState *xdr, JSScript **scriptp)
424 : {
425 : enum ScriptBits {
426 : NoScriptRval,
427 : SavedCallerFun,
428 : StrictModeCode,
429 : UsesEval,
430 : UsesArguments,
431 : OwnFilename,
432 : SharedFilename
433 : };
434 :
435 : uint32_t length, lineno, nslots;
436 : uint32_t natoms, nsrcnotes, ntrynotes, nobjects, nregexps, nconsts, i;
437 : uint32_t prologLength, version, encodedClosedCount;
438 636231 : uint16_t nClosedArgs = 0, nClosedVars = 0;
439 636231 : uint32_t nTypeSets = 0;
440 636231 : uint32_t scriptBits = 0;
441 :
442 636231 : JSContext *cx = xdr->cx;
443 : JSScript *script;
444 636231 : nsrcnotes = ntrynotes = natoms = nobjects = nregexps = nconsts = 0;
445 636231 : jssrcnote *notes = NULL;
446 :
447 : /* XDR arguments, local vars, and upvars. */
448 : uint16_t nargs, nvars, nupvars;
449 : #if defined(DEBUG) || defined(__GNUC__) /* quell GCC overwarning */
450 636231 : script = NULL;
451 636231 : nargs = nvars = nupvars = Bindings::BINDING_COUNT_LIMIT;
452 : #endif
453 : uint32_t argsVars, paddingUpvars;
454 636231 : if (xdr->mode == JSXDR_ENCODE) {
455 459139 : script = *scriptp;
456 :
457 : /* Should not XDR scripts optimized for a single global object. */
458 459139 : JS_ASSERT(!JSScript::isValidOffset(script->globalsOffset));
459 :
460 459139 : nargs = script->bindings.countArgs();
461 459139 : nvars = script->bindings.countVars();
462 459139 : nupvars = script->bindings.countUpvars();
463 459139 : argsVars = (nargs << 16) | nvars;
464 459139 : paddingUpvars = nupvars;
465 : }
466 636231 : if (!JS_XDRUint32(xdr, &argsVars) || !JS_XDRUint32(xdr, &paddingUpvars))
467 0 : return false;
468 636231 : if (xdr->mode == JSXDR_DECODE) {
469 177092 : nargs = argsVars >> 16;
470 177092 : nvars = argsVars & 0xFFFF;
471 177092 : JS_ASSERT((paddingUpvars >> 16) == 0);
472 177092 : nupvars = paddingUpvars & 0xFFFF;
473 : }
474 636231 : JS_ASSERT(nargs != Bindings::BINDING_COUNT_LIMIT);
475 636231 : JS_ASSERT(nvars != Bindings::BINDING_COUNT_LIMIT);
476 636231 : JS_ASSERT(nupvars != Bindings::BINDING_COUNT_LIMIT);
477 :
478 1272462 : Bindings bindings(cx);
479 636231 : uint32_t nameCount = nargs + nvars + nupvars;
480 636231 : if (nameCount > 0) {
481 1045084 : LifoAllocScope las(&cx->tempLifoAlloc());
482 :
483 : /*
484 : * To xdr the names we prefix the names with a bitmap descriptor and
485 : * then xdr the names as strings. For argument names (indexes below
486 : * nargs) the corresponding bit in the bitmap is unset when the name
487 : * is null. Such null names are not encoded or decoded. For variable
488 : * names (indexes starting from nargs) bitmap's bit is set when the
489 : * name is declared as const, not as ordinary var.
490 : * */
491 522542 : unsigned bitmapLength = JS_HOWMANY(nameCount, JS_BITS_PER_UINT32);
492 522542 : uint32_t *bitmap = cx->tempLifoAlloc().newArray<uint32_t>(bitmapLength);
493 522542 : if (!bitmap) {
494 0 : js_ReportOutOfMemory(cx);
495 0 : return false;
496 : }
497 :
498 1045084 : Vector<JSAtom *> names(cx);
499 522542 : if (xdr->mode == JSXDR_ENCODE) {
500 366634 : if (!script->bindings.getLocalNameArray(cx, &names))
501 0 : return false;
502 366634 : PodZero(bitmap, bitmapLength);
503 1321935 : for (unsigned i = 0; i < nameCount; i++) {
504 955301 : if (i < nargs && names[i])
505 495286 : bitmap[i >> JS_BITS_PER_UINT32_LOG2] |= JS_BIT(i & (JS_BITS_PER_UINT32 - 1));
506 : }
507 : }
508 1045084 : for (unsigned i = 0; i < bitmapLength; ++i) {
509 522542 : if (!JS_XDRUint32(xdr, &bitmap[i]))
510 0 : return false;
511 : }
512 :
513 1873584 : for (unsigned i = 0; i < nameCount; i++) {
514 2056035 : if (i < nargs &&
515 704993 : !(bitmap[i >> JS_BITS_PER_UINT32_LOG2] & JS_BIT(i & (JS_BITS_PER_UINT32 - 1))))
516 : {
517 432 : if (xdr->mode == JSXDR_DECODE) {
518 : uint16_t dummy;
519 0 : if (!bindings.addDestructuring(cx, &dummy))
520 0 : return false;
521 : } else {
522 432 : JS_ASSERT(!names[i]);
523 : }
524 432 : continue;
525 : }
526 :
527 : JSAtom *name;
528 1350610 : if (xdr->mode == JSXDR_ENCODE)
529 954869 : name = names[i];
530 1350610 : if (!js_XDRAtom(xdr, &name))
531 0 : return false;
532 1350610 : if (xdr->mode == JSXDR_DECODE) {
533 : BindingKind kind = (i < nargs)
534 : ? ARGUMENT
535 : : (i < unsigned(nargs + nvars))
536 151124 : ? (bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
537 : JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
538 : ? CONSTANT
539 : : VARIABLE)
540 546865 : : UPVAR;
541 395741 : if (!bindings.add(cx, name, kind))
542 0 : return false;
543 : }
544 : }
545 : }
546 :
547 636231 : if (xdr->mode == JSXDR_DECODE) {
548 177092 : if (!bindings.ensureShape(cx))
549 0 : return false;
550 177092 : bindings.makeImmutable();
551 : }
552 :
553 636231 : if (xdr->mode == JSXDR_ENCODE)
554 459139 : length = script->length;
555 636231 : if (!JS_XDRUint32(xdr, &length))
556 0 : return JS_FALSE;
557 :
558 636231 : if (xdr->mode == JSXDR_ENCODE) {
559 459139 : prologLength = script->mainOffset;
560 459139 : JS_ASSERT(script->getVersion() != JSVERSION_UNKNOWN);
561 459139 : version = (uint32_t)script->getVersion() | (script->nfixed << 16);
562 459139 : lineno = (uint32_t)script->lineno;
563 459139 : nslots = (uint32_t)script->nslots;
564 459139 : nslots = (uint32_t)((script->staticLevel << 16) | script->nslots);
565 459139 : natoms = script->natoms;
566 :
567 459139 : notes = script->notes();
568 459139 : nsrcnotes = script->numNotes();
569 :
570 459139 : if (JSScript::isValidOffset(script->objectsOffset))
571 186140 : nobjects = script->objects()->length;
572 459139 : if (JSScript::isValidOffset(script->upvarsOffset))
573 53645 : JS_ASSERT(script->bindings.countUpvars() == script->upvars()->length);
574 459139 : if (JSScript::isValidOffset(script->regexpsOffset))
575 6530 : nregexps = script->regexps()->length;
576 459139 : if (JSScript::isValidOffset(script->trynotesOffset))
577 90592 : ntrynotes = script->trynotes()->length;
578 459139 : if (JSScript::isValidOffset(script->constOffset))
579 5435 : nconsts = script->consts()->length;
580 :
581 459139 : nClosedArgs = script->nClosedArgs;
582 459139 : nClosedVars = script->nClosedVars;
583 459139 : encodedClosedCount = (nClosedArgs << 16) | nClosedVars;
584 :
585 459139 : nTypeSets = script->nTypeSets;
586 :
587 459139 : if (script->noScriptRval)
588 7244 : scriptBits |= (1 << NoScriptRval);
589 459139 : if (script->savedCallerFun)
590 0 : scriptBits |= (1 << SavedCallerFun);
591 459139 : if (script->strictModeCode)
592 275992 : scriptBits |= (1 << StrictModeCode);
593 459139 : if (script->usesEval)
594 1532 : scriptBits |= (1 << UsesEval);
595 459139 : if (script->usesArguments)
596 1779 : scriptBits |= (1 << UsesArguments);
597 459139 : if (script->filename) {
598 : scriptBits |= (script->filename != xdr->sharedFilename)
599 : ? (1 << OwnFilename)
600 459139 : : (1 << SharedFilename);
601 : }
602 :
603 459139 : JS_ASSERT(!script->compileAndGo);
604 459139 : JS_ASSERT(!script->hasSingletons);
605 : }
606 :
607 636231 : if (!JS_XDRUint32(xdr, &prologLength))
608 0 : return JS_FALSE;
609 636231 : if (!JS_XDRUint32(xdr, &version))
610 0 : return JS_FALSE;
611 :
612 : /*
613 : * To fuse allocations, we need srcnote, atom, objects, regexp, and trynote
614 : * counts early.
615 : */
616 636231 : if (!JS_XDRUint32(xdr, &natoms))
617 0 : return JS_FALSE;
618 636231 : if (!JS_XDRUint32(xdr, &nsrcnotes))
619 0 : return JS_FALSE;
620 636231 : if (!JS_XDRUint32(xdr, &ntrynotes))
621 0 : return JS_FALSE;
622 636231 : if (!JS_XDRUint32(xdr, &nobjects))
623 0 : return JS_FALSE;
624 636231 : if (!JS_XDRUint32(xdr, &nregexps))
625 0 : return JS_FALSE;
626 636231 : if (!JS_XDRUint32(xdr, &nconsts))
627 0 : return JS_FALSE;
628 636231 : if (!JS_XDRUint32(xdr, &encodedClosedCount))
629 0 : return JS_FALSE;
630 636231 : if (!JS_XDRUint32(xdr, &nTypeSets))
631 0 : return JS_FALSE;
632 636231 : if (!JS_XDRUint32(xdr, &scriptBits))
633 0 : return JS_FALSE;
634 :
635 636231 : if (xdr->mode == JSXDR_DECODE) {
636 177092 : nClosedArgs = encodedClosedCount >> 16;
637 177092 : nClosedVars = encodedClosedCount & 0xFFFF;
638 :
639 : /* Note: version is packed into the 32b space with another 16b value. */
640 177092 : JSVersion version_ = JSVersion(version & JS_BITMASK(16));
641 177092 : JS_ASSERT((version_ & VersionFlags::FULL_MASK) == unsigned(version_));
642 : script = JSScript::NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars,
643 : nregexps, ntrynotes, nconsts, 0, nClosedArgs,
644 177092 : nClosedVars, nTypeSets, version_);
645 177092 : if (!script)
646 0 : return JS_FALSE;
647 :
648 177092 : script->bindings.transfer(cx, &bindings);
649 177092 : JS_ASSERT(!script->mainOffset);
650 177092 : script->mainOffset = prologLength;
651 177092 : script->nfixed = uint16_t(version >> 16);
652 :
653 : /* If we know nsrcnotes, we allocated space for notes in script. */
654 177092 : notes = script->notes();
655 177092 : *scriptp = script;
656 :
657 177092 : if (scriptBits & (1 << NoScriptRval))
658 541 : script->noScriptRval = true;
659 177092 : if (scriptBits & (1 << SavedCallerFun))
660 0 : script->savedCallerFun = true;
661 177092 : if (scriptBits & (1 << StrictModeCode))
662 172371 : script->strictModeCode = true;
663 177092 : if (scriptBits & (1 << UsesEval))
664 506 : script->usesEval = true;
665 177092 : if (scriptBits & (1 << UsesArguments))
666 506 : script->usesArguments = true;
667 : }
668 :
669 636231 : if (!JS_XDRBytes(xdr, (char *)script->code, length * sizeof(jsbytecode)))
670 0 : return false;
671 :
672 1908693 : if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) ||
673 636231 : !JS_XDRUint32(xdr, &lineno) ||
674 636231 : !JS_XDRUint32(xdr, &nslots)) {
675 0 : return false;
676 : }
677 :
678 636231 : if (scriptBits & (1 << OwnFilename)) {
679 : char *filename;
680 636231 : if (xdr->mode == JSXDR_ENCODE)
681 459139 : filename = const_cast<char *>(script->filename);
682 636231 : if (!JS_XDRCString(xdr, &filename))
683 0 : return false;
684 636231 : if (xdr->mode == JSXDR_DECODE) {
685 177092 : script->filename = SaveScriptFilename(xdr->cx, filename);
686 177092 : Foreground::free_(filename);
687 177092 : if (!script->filename)
688 0 : return false;
689 177092 : if (!xdr->sharedFilename)
690 2942 : xdr->sharedFilename = script->filename;
691 : }
692 0 : } else if (scriptBits & (1 << SharedFilename)) {
693 0 : JS_ASSERT(xdr->sharedFilename);
694 0 : if (xdr->mode == JSXDR_DECODE)
695 0 : script->filename = xdr->sharedFilename;
696 : }
697 :
698 636231 : if (xdr->mode == JSXDR_DECODE) {
699 177092 : JS_ASSERT(!script->principals);
700 177092 : JS_ASSERT(!script->originPrincipals);
701 :
702 : /* The origin principals must be normalized at this point. */
703 177092 : JS_ASSERT_IF(script->principals, script->originPrincipals);
704 177092 : if (xdr->principals) {
705 174703 : script->principals = xdr->principals;
706 174703 : JS_HoldPrincipals(xdr->principals);
707 : }
708 177092 : if (xdr->originPrincipals) {
709 174708 : script->originPrincipals = xdr->originPrincipals;
710 174708 : JS_HoldPrincipals(xdr->originPrincipals);
711 : }
712 : }
713 :
714 636231 : if (xdr->mode == JSXDR_DECODE) {
715 177092 : script->lineno = (unsigned)lineno;
716 177092 : script->nslots = uint16_t(nslots);
717 177092 : script->staticLevel = uint16_t(nslots >> 16);
718 : }
719 :
720 9892487 : for (i = 0; i != natoms; ++i) {
721 9256256 : if (!js_XDRAtom(xdr, &script->atoms[i]))
722 0 : return false;
723 : }
724 :
725 : /*
726 : * Here looping from 0-to-length to xdr objects is essential. It ensures
727 : * that block objects from the script->objects array will be written and
728 : * restored in the outer-to-inner order. js_XDRBlockObject relies on this
729 : * to restore the parent chain.
730 : */
731 1619620 : for (i = 0; i != nobjects; ++i) {
732 983389 : HeapPtr<JSObject> *objp = &script->objects()->vector[i];
733 : uint32_t isBlock;
734 983389 : if (xdr->mode == JSXDR_ENCODE) {
735 695699 : JSObject *obj = *objp;
736 695699 : JS_ASSERT(obj->isFunction() || obj->isStaticBlock());
737 695699 : isBlock = obj->isBlock() ? 1 : 0;
738 : }
739 983389 : if (!JS_XDRUint32(xdr, &isBlock))
740 0 : return false;
741 983389 : if (isBlock == 0) {
742 623614 : JSObject *tmp = *objp;
743 623614 : if (!XDRFunctionObject(xdr, &tmp))
744 0 : return false;
745 623614 : *objp = tmp;
746 : } else {
747 359775 : JS_ASSERT(isBlock == 1);
748 359775 : StaticBlockObject *tmp = static_cast<StaticBlockObject *>(objp->get());
749 359775 : if (!XDRStaticBlockObject(xdr, script, &tmp))
750 0 : return false;
751 359775 : *objp = tmp;
752 : }
753 : }
754 741043 : for (i = 0; i != nupvars; ++i) {
755 104812 : if (!JS_XDRUint32(xdr, reinterpret_cast<uint32_t *>(&script->upvars()->vector[i])))
756 0 : return false;
757 : }
758 654759 : for (i = 0; i != nregexps; ++i) {
759 18528 : if (!XDRScriptRegExpObject(xdr, &script->regexps()->vector[i]))
760 0 : return false;
761 : }
762 738728 : for (i = 0; i != nClosedArgs; ++i) {
763 102497 : if (!JS_XDRUint32(xdr, &script->closedSlots[i]))
764 0 : return false;
765 : }
766 722351 : for (i = 0; i != nClosedVars; ++i) {
767 86120 : if (!JS_XDRUint32(xdr, &script->closedSlots[nClosedArgs + i]))
768 0 : return false;
769 : }
770 :
771 636231 : if (ntrynotes != 0) {
772 : /*
773 : * We combine tn->kind and tn->stackDepth when serializing as XDR is not
774 : * efficient when serializing small integer types.
775 : */
776 : JSTryNote *tn, *tnfirst;
777 : uint32_t kindAndDepth;
778 : JS_STATIC_ASSERT(sizeof(tn->kind) == sizeof(uint8_t));
779 : JS_STATIC_ASSERT(sizeof(tn->stackDepth) == sizeof(uint16_t));
780 :
781 130334 : tnfirst = script->trynotes()->vector;
782 130334 : JS_ASSERT(script->trynotes()->length == ntrynotes);
783 130334 : tn = tnfirst + ntrynotes;
784 213625 : do {
785 213625 : --tn;
786 213625 : if (xdr->mode == JSXDR_ENCODE) {
787 : kindAndDepth = (uint32_t(tn->kind) << 16)
788 145713 : | uint32_t(tn->stackDepth);
789 : }
790 640875 : if (!JS_XDRUint32(xdr, &kindAndDepth) ||
791 213625 : !JS_XDRUint32(xdr, &tn->start) ||
792 213625 : !JS_XDRUint32(xdr, &tn->length)) {
793 0 : return false;
794 : }
795 213625 : if (xdr->mode == JSXDR_DECODE) {
796 67912 : tn->kind = uint8_t(kindAndDepth >> 16);
797 67912 : tn->stackDepth = uint16_t(kindAndDepth);
798 : }
799 : } while (tn != tnfirst);
800 : }
801 :
802 636231 : if (nconsts) {
803 5985 : HeapValue *vector = script->consts()->vector;
804 33239 : for (i = 0; i != nconsts; ++i) {
805 27254 : if (!XDRScriptConst(xdr, &vector[i]))
806 0 : return false;
807 : }
808 : }
809 :
810 636231 : if (xdr->mode == JSXDR_DECODE) {
811 177092 : if (cx->hasRunOption(JSOPTION_PCCOUNT))
812 0 : (void) script->initCounts(cx);
813 177092 : *scriptp = script;
814 : }
815 :
816 636231 : return true;
817 : }
818 :
819 : #endif /* JS_HAS_XDR */
820 :
821 : } /* namespace js */
822 :
823 : bool
824 0 : JSScript::initCounts(JSContext *cx)
825 : {
826 0 : JS_ASSERT(!pcCounters);
827 :
828 0 : size_t count = 0;
829 :
830 : jsbytecode *pc, *next;
831 0 : for (pc = code; pc < code + length; pc = next) {
832 0 : count += OpcodeCounts::numCounts(JSOp(*pc));
833 0 : next = pc + GetBytecodeLength(pc);
834 : }
835 :
836 0 : size_t bytes = (length * sizeof(OpcodeCounts)) + (count * sizeof(double));
837 0 : char *cursor = (char *) cx->calloc_(bytes);
838 0 : if (!cursor)
839 0 : return false;
840 :
841 0 : DebugOnly<char *> base = cursor;
842 :
843 0 : pcCounters.counts = (OpcodeCounts *) cursor;
844 0 : cursor += length * sizeof(OpcodeCounts);
845 :
846 0 : for (pc = code; pc < code + length; pc = next) {
847 0 : pcCounters.counts[pc - code].counts = (double *) cursor;
848 0 : size_t capacity = OpcodeCounts::numCounts(JSOp(*pc));
849 : #ifdef DEBUG
850 0 : pcCounters.counts[pc - code].capacity = capacity;
851 : #endif
852 0 : cursor += capacity * sizeof(double);
853 0 : next = pc + GetBytecodeLength(pc);
854 : }
855 :
856 0 : JS_ASSERT(size_t(cursor - base) == bytes);
857 :
858 : /* Enable interrupts in any interpreter frames running on this script. */
859 : InterpreterFrames *frames;
860 0 : for (frames = cx->runtime->interpreterFrames; frames; frames = frames->older)
861 0 : frames->enableInterruptsIfRunning(this);
862 :
863 0 : return true;
864 : }
865 :
866 : void
867 1324353 : JSScript::destroyCounts(JSContext *cx)
868 : {
869 1324353 : if (pcCounters) {
870 0 : cx->free_(pcCounters.counts);
871 0 : pcCounters.counts = NULL;
872 : }
873 1324353 : }
874 :
875 : namespace js {
876 :
877 : /*
878 : * Shared script filename management.
879 : */
880 :
881 : static const char *
882 1286209 : SaveScriptFilename(JSContext *cx, const char *filename)
883 : {
884 1286209 : JSCompartment *comp = cx->compartment;
885 :
886 1286209 : ScriptFilenameTable::AddPtr p = comp->scriptFilenameTable.lookupForAdd(filename);
887 1286209 : if (!p) {
888 78536 : size_t size = offsetof(ScriptFilenameEntry, filename) + strlen(filename) + 1;
889 78536 : ScriptFilenameEntry *entry = (ScriptFilenameEntry *) cx->malloc_(size);
890 78536 : if (!entry)
891 0 : return NULL;
892 78536 : entry->marked = false;
893 78536 : strcpy(entry->filename, filename);
894 :
895 78536 : if (!comp->scriptFilenameTable.add(p, entry)) {
896 0 : Foreground::free_(entry);
897 0 : JS_ReportOutOfMemory(cx);
898 0 : return NULL;
899 : }
900 : }
901 :
902 1286209 : ScriptFilenameEntry *sfe = *p;
903 : #ifdef JSGC_INCREMENTAL
904 : /*
905 : * During the IGC we need to ensure that filename is marked whenever it is
906 : * accessed even if the name was already in the table. At this point old
907 : * scripts or exceptions pointing to the filename may no longer be
908 : * reachable.
909 : */
910 1286209 : if (comp->needsBarrier() && !sfe->marked)
911 55 : sfe->marked = true;
912 : #endif
913 :
914 1286209 : return sfe->filename;
915 : }
916 :
917 : } /* namespace js */
918 :
919 : /*
920 : * Back up from a saved filename by its offset within its hash table entry.
921 : */
922 : #define FILENAME_TO_SFE(fn) \
923 : ((ScriptFilenameEntry *) ((fn) - offsetof(ScriptFilenameEntry, filename)))
924 :
925 : void
926 6567533 : js_MarkScriptFilename(const char *filename)
927 : {
928 6567533 : ScriptFilenameEntry *sfe = FILENAME_TO_SFE(filename);
929 6567533 : sfe->marked = true;
930 6567533 : }
931 :
932 : void
933 122478 : js_SweepScriptFilenames(JSCompartment *comp)
934 : {
935 122478 : ScriptFilenameTable &table = comp->scriptFilenameTable;
936 388368 : for (ScriptFilenameTable::Enum e(table); !e.empty(); e.popFront()) {
937 265890 : ScriptFilenameEntry *entry = e.front();
938 265890 : if (entry->marked) {
939 187351 : entry->marked = false;
940 78539 : } else if (!comp->rt->gcKeepAtoms) {
941 78461 : Foreground::free_(entry);
942 78461 : e.removeFront();
943 : }
944 : }
945 122478 : }
946 :
947 : /*
948 : * JSScript data structures memory alignment:
949 : *
950 : * JSScript
951 : * JSObjectArray script objects' descriptor if JSScript.objectsOffset != 0,
952 : * use script->objects() to access it.
953 : * JSObjectArray script regexps' descriptor if JSScript.regexpsOffset != 0,
954 : * use script->regexps() to access it.
955 : * JSTryNoteArray script try notes' descriptor if JSScript.tryNotesOffset
956 : * != 0, use script->trynotes() to access it.
957 : * JSAtom *a[] array of JSScript.natoms atoms pointed by
958 : * JSScript.atoms if any.
959 : * JSObject *o[] array of script->objects()->length objects if any
960 : * pointed by script->objects()->vector.
961 : * JSObject *r[] array of script->regexps()->length regexps if any
962 : * pointed by script->regexps()->vector.
963 : * JSTryNote t[] array of script->trynotes()->length try notes if any
964 : * pointed by script->trynotes()->vector.
965 : * jsbytecode b[] script bytecode pointed by JSScript.code.
966 : * jssrcnote s[] script source notes, use script->notes() to access it
967 : *
968 : * The alignment avoids gaps between entries as alignment requirement for each
969 : * subsequent structure or array is the same or divides the alignment
970 : * requirement for the previous one.
971 : *
972 : * The followings asserts checks that assuming that the alignment requirement
973 : * for JSObjectArray and JSTryNoteArray are sizeof(void *) and for JSTryNote
974 : * it is sizeof(uint32_t) as the structure consists of 3 uint32_t fields.
975 : */
976 : JS_STATIC_ASSERT(sizeof(JSScript) % sizeof(void *) == 0);
977 : JS_STATIC_ASSERT(sizeof(JSObjectArray) % sizeof(void *) == 0);
978 : JS_STATIC_ASSERT(sizeof(JSTryNoteArray) == sizeof(JSObjectArray));
979 : JS_STATIC_ASSERT(sizeof(JSAtom *) == sizeof(JSObject *));
980 : JS_STATIC_ASSERT(sizeof(JSObject *) % sizeof(uint32_t) == 0);
981 : JS_STATIC_ASSERT(sizeof(JSTryNote) == 3 * sizeof(uint32_t));
982 : JS_STATIC_ASSERT(sizeof(uint32_t) % sizeof(jsbytecode) == 0);
983 : JS_STATIC_ASSERT(sizeof(jsbytecode) % sizeof(jssrcnote) == 0);
984 :
985 : /*
986 : * Check that uint8_t offsets is enough to reach any optional array allocated
987 : * after JSScript. For that we check that the maximum possible offset for
988 : * JSConstArray, that last optional array, still fits 1 byte and do not
989 : * coincide with INVALID_OFFSET.
990 : */
991 : JS_STATIC_ASSERT(sizeof(JSObjectArray) +
992 : sizeof(JSUpvarArray) +
993 : sizeof(JSObjectArray) +
994 : sizeof(JSTryNoteArray) +
995 : sizeof(js::GlobalSlotArray)
996 : < JSScript::INVALID_OFFSET);
997 : JS_STATIC_ASSERT(JSScript::INVALID_OFFSET <= 255);
998 :
999 : JSScript *
1000 1324850 : JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
1001 : uint32_t nobjects, uint32_t nupvars, uint32_t nregexps,
1002 : uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals,
1003 : uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets, JSVersion version)
1004 : {
1005 1324850 : size_t size = sizeof(JSAtom *) * natoms;
1006 1324850 : if (nobjects != 0)
1007 470954 : size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *);
1008 1324850 : if (nupvars != 0)
1009 112447 : size += sizeof(JSUpvarArray) + nupvars * sizeof(uint32_t);
1010 1324850 : if (nregexps != 0)
1011 18673 : size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *);
1012 1324850 : if (ntrynotes != 0)
1013 181686 : size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote);
1014 1324850 : if (nglobals != 0)
1015 12799 : size += sizeof(GlobalSlotArray) + nglobals * sizeof(GlobalSlotArray::Entry);
1016 1324850 : uint32_t totalClosed = nClosedArgs + nClosedVars;
1017 1324850 : if (totalClosed != 0)
1018 149939 : size += totalClosed * sizeof(uint32_t);
1019 :
1020 : /*
1021 : * To esnure jsval alignment for the const array we place it immediately
1022 : * after JSSomethingArray structs as their sizes all divide sizeof(jsval).
1023 : * This works as long as the data itself is allocated with proper
1024 : * alignment which we ensure below.
1025 : */
1026 : JS_STATIC_ASSERT(sizeof(JSObjectArray) % sizeof(jsval) == 0);
1027 : JS_STATIC_ASSERT(sizeof(JSUpvarArray) % sizeof(jsval) == 0);
1028 : JS_STATIC_ASSERT(sizeof(JSTryNoteArray) % sizeof(jsval) == 0);
1029 : JS_STATIC_ASSERT(sizeof(GlobalSlotArray) % sizeof(jsval) == 0);
1030 : JS_STATIC_ASSERT(sizeof(JSConstArray) % sizeof(jsval) == 0);
1031 1324850 : if (nconsts != 0)
1032 13348 : size += sizeof(JSConstArray) + nconsts * sizeof(Value);
1033 :
1034 1324850 : size += length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote);
1035 :
1036 1324850 : uint8_t *data = NULL;
1037 : #if JS_SCRIPT_INLINE_DATA_LIMIT
1038 : if (size <= JS_SCRIPT_INLINE_DATA_LIMIT) {
1039 : /*
1040 : * Check that if inlineData is big enough to store const values, we
1041 : * can do that without any special alignment requirements given that
1042 : * the script as a GC thing is always aligned on Cell::CellSize.
1043 : */
1044 : JS_STATIC_ASSERT(Cell::CellSize % sizeof(Value) == 0);
1045 : JS_STATIC_ASSERT(JS_SCRIPT_INLINE_DATA_LIMIT < sizeof(Value) ||
1046 : offsetof(JSScript, inlineData) % sizeof(Value) == 0);
1047 : } else
1048 : #endif
1049 : {
1050 : /*
1051 : * We assume that calloc aligns on sizeof(Value) if the size we ask to
1052 : * allocate divides sizeof(Value).
1053 : */
1054 : JS_STATIC_ASSERT(sizeof(Value) == sizeof(double));
1055 1324850 : data = static_cast<uint8_t *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value))));
1056 1324850 : if (!data)
1057 0 : return NULL;
1058 : }
1059 :
1060 1324850 : JSScript *script = js_NewGCScript(cx);
1061 1324850 : if (!script) {
1062 0 : Foreground::free_(data);
1063 0 : return NULL;
1064 : }
1065 :
1066 1324850 : PodZero(script);
1067 : #ifdef JS_CRASH_DIAGNOSTICS
1068 1324850 : script->cookie1[0] = script->cookie2[0] = JS_SCRIPT_COOKIE;
1069 : #endif
1070 : #if JS_SCRIPT_INLINE_DATA_LIMIT
1071 : if (!data)
1072 : data = script->inlineData;
1073 : #endif
1074 1324850 : script->data = data;
1075 1324850 : script->length = length;
1076 1324850 : script->version = version;
1077 1324850 : new (&script->bindings) Bindings(cx);
1078 :
1079 1324850 : uint8_t *cursor = data;
1080 1324850 : if (nobjects != 0) {
1081 470954 : script->objectsOffset = uint8_t(cursor - data);
1082 470954 : cursor += sizeof(JSObjectArray);
1083 : } else {
1084 853896 : script->objectsOffset = JSScript::INVALID_OFFSET;
1085 : }
1086 1324850 : if (nupvars != 0) {
1087 112447 : script->upvarsOffset = uint8_t(cursor - data);
1088 112447 : cursor += sizeof(JSUpvarArray);
1089 : } else {
1090 1212403 : script->upvarsOffset = JSScript::INVALID_OFFSET;
1091 : }
1092 1324850 : if (nregexps != 0) {
1093 18673 : script->regexpsOffset = uint8_t(cursor - data);
1094 18673 : cursor += sizeof(JSObjectArray);
1095 : } else {
1096 1306177 : script->regexpsOffset = JSScript::INVALID_OFFSET;
1097 : }
1098 1324850 : if (ntrynotes != 0) {
1099 181686 : script->trynotesOffset = uint8_t(cursor - data);
1100 181686 : cursor += sizeof(JSTryNoteArray);
1101 : } else {
1102 1143164 : script->trynotesOffset = JSScript::INVALID_OFFSET;
1103 : }
1104 1324850 : if (nglobals != 0) {
1105 12799 : script->globalsOffset = uint8_t(cursor - data);
1106 12799 : cursor += sizeof(GlobalSlotArray);
1107 : } else {
1108 1312051 : script->globalsOffset = JSScript::INVALID_OFFSET;
1109 : }
1110 1324850 : JS_ASSERT(cursor - data < 0xFF);
1111 1324850 : if (nconsts != 0) {
1112 13348 : script->constOffset = uint8_t(cursor - data);
1113 13348 : cursor += sizeof(JSConstArray);
1114 : } else {
1115 1311502 : script->constOffset = JSScript::INVALID_OFFSET;
1116 : }
1117 :
1118 : JS_STATIC_ASSERT(sizeof(JSObjectArray) +
1119 : sizeof(JSUpvarArray) +
1120 : sizeof(JSObjectArray) +
1121 : sizeof(JSTryNoteArray) +
1122 : sizeof(GlobalSlotArray) < 0xFF);
1123 :
1124 :
1125 1324850 : if (nconsts != 0) {
1126 13348 : JS_ASSERT(reinterpret_cast<uintptr_t>(cursor) % sizeof(jsval) == 0);
1127 13348 : script->consts()->length = nconsts;
1128 13348 : script->consts()->vector = (HeapValue *)cursor;
1129 13348 : cursor += nconsts * sizeof(script->consts()->vector[0]);
1130 : }
1131 :
1132 1324850 : if (natoms != 0) {
1133 1178782 : script->natoms = natoms;
1134 1178782 : script->atoms = reinterpret_cast<JSAtom **>(cursor);
1135 1178782 : cursor += natoms * sizeof(script->atoms[0]);
1136 : }
1137 :
1138 1324850 : if (nobjects != 0) {
1139 470954 : script->objects()->length = nobjects;
1140 470954 : script->objects()->vector = (HeapPtr<JSObject> *)cursor;
1141 470954 : cursor += nobjects * sizeof(script->objects()->vector[0]);
1142 : }
1143 :
1144 1324850 : if (nregexps != 0) {
1145 18673 : script->regexps()->length = nregexps;
1146 18673 : script->regexps()->vector = (HeapPtr<JSObject> *)cursor;
1147 18673 : cursor += nregexps * sizeof(script->regexps()->vector[0]);
1148 : }
1149 :
1150 1324850 : if (ntrynotes != 0) {
1151 181686 : script->trynotes()->length = ntrynotes;
1152 181686 : script->trynotes()->vector = reinterpret_cast<JSTryNote *>(cursor);
1153 181686 : size_t vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
1154 : #ifdef DEBUG
1155 181686 : memset(cursor, 0, vectorSize);
1156 : #endif
1157 181686 : cursor += vectorSize;
1158 : }
1159 :
1160 1324850 : if (nglobals != 0) {
1161 12799 : script->globals()->length = nglobals;
1162 12799 : script->globals()->vector = reinterpret_cast<GlobalSlotArray::Entry *>(cursor);
1163 12799 : cursor += nglobals * sizeof(script->globals()->vector[0]);
1164 : }
1165 :
1166 1324850 : if (totalClosed != 0) {
1167 149939 : script->nClosedArgs = nClosedArgs;
1168 149939 : script->nClosedVars = nClosedVars;
1169 149939 : script->closedSlots = reinterpret_cast<uint32_t *>(cursor);
1170 149939 : cursor += totalClosed * sizeof(uint32_t);
1171 : }
1172 :
1173 1324850 : JS_ASSERT(nTypeSets <= UINT16_MAX);
1174 1324850 : script->nTypeSets = uint16_t(nTypeSets);
1175 :
1176 : /*
1177 : * NB: We allocate the vector of uint32_t upvar cookies after all vectors of
1178 : * pointers, to avoid misalignment on 64-bit platforms. See bug 514645.
1179 : */
1180 1324850 : if (nupvars != 0) {
1181 112447 : script->upvars()->length = nupvars;
1182 112447 : script->upvars()->vector = reinterpret_cast<UpvarCookie *>(cursor);
1183 112447 : cursor += nupvars * sizeof(script->upvars()->vector[0]);
1184 : }
1185 :
1186 1324850 : script->code = (jsbytecode *)cursor;
1187 1324850 : JS_ASSERT(cursor + length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote) == data + size);
1188 :
1189 : #ifdef DEBUG
1190 1324850 : script->id_ = 0;
1191 : #endif
1192 :
1193 1324850 : JS_ASSERT(script->getVersion() == version);
1194 1324850 : return script;
1195 : }
1196 :
1197 : JSScript *
1198 1109121 : JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
1199 : {
1200 : uint32_t mainLength, prologLength, nfixed;
1201 : JSScript *script;
1202 : const char *filename;
1203 : JSFunction *fun;
1204 :
1205 : /* The counts of indexed things must be checked during code generation. */
1206 1109121 : JS_ASSERT(bce->atomIndices->count() <= INDEX_LIMIT);
1207 1109121 : JS_ASSERT(bce->objectList.length <= INDEX_LIMIT);
1208 1109121 : JS_ASSERT(bce->regexpList.length <= INDEX_LIMIT);
1209 :
1210 1109121 : mainLength = bce->offset();
1211 1109121 : prologLength = bce->prologOffset();
1212 :
1213 1109121 : if (!bce->bindings.ensureShape(cx))
1214 0 : return NULL;
1215 :
1216 1109121 : uint32_t nsrcnotes = uint32_t(bce->countFinalSourceNotes());
1217 1109121 : uint16_t nClosedArgs = uint16_t(bce->closedArgs.length());
1218 1109121 : JS_ASSERT(nClosedArgs == bce->closedArgs.length());
1219 1109121 : uint16_t nClosedVars = uint16_t(bce->closedVars.length());
1220 1109121 : JS_ASSERT(nClosedVars == bce->closedVars.length());
1221 1109121 : size_t upvarIndexCount = bce->upvarIndices.hasMap() ? bce->upvarIndices->count() : 0;
1222 : script = NewScript(cx, prologLength + mainLength, nsrcnotes,
1223 : bce->atomIndices->count(), bce->objectList.length,
1224 : upvarIndexCount, bce->regexpList.length,
1225 : bce->ntrynotes, bce->constList.length(),
1226 : bce->globalUses.length(), nClosedArgs, nClosedVars,
1227 1109121 : bce->typesetCount, bce->version());
1228 1109121 : if (!script)
1229 0 : return NULL;
1230 :
1231 1109121 : bce->bindings.makeImmutable();
1232 :
1233 1109121 : JS_ASSERT(script->mainOffset == 0);
1234 1109121 : script->mainOffset = prologLength;
1235 1109121 : PodCopy<jsbytecode>(script->code, bce->prologBase(), prologLength);
1236 1109121 : PodCopy<jsbytecode>(script->main(), bce->base(), mainLength);
1237 1109121 : nfixed = bce->inFunction() ? bce->bindings.countVars() : 0;
1238 1109121 : JS_ASSERT(nfixed < SLOTNO_LIMIT);
1239 1109121 : script->nfixed = uint16_t(nfixed);
1240 1109121 : js_InitAtomMap(cx, bce->atomIndices.getMap(), script->atoms);
1241 :
1242 1109121 : filename = bce->parser->tokenStream.getFilename();
1243 1109121 : if (filename) {
1244 1109117 : script->filename = SaveScriptFilename(cx, filename);
1245 1109117 : if (!script->filename)
1246 0 : return NULL;
1247 : }
1248 1109121 : script->lineno = bce->firstLine;
1249 1109121 : if (script->nfixed + bce->maxStackDepth >= JS_BIT(16)) {
1250 : ReportCompileErrorNumber(cx, bce->tokenStream(), NULL, JSREPORT_ERROR, JSMSG_NEED_DIET,
1251 0 : "script");
1252 0 : return NULL;
1253 : }
1254 1109121 : script->nslots = script->nfixed + bce->maxStackDepth;
1255 1109121 : script->staticLevel = uint16_t(bce->staticLevel);
1256 1109121 : script->principals = bce->parser->principals;
1257 :
1258 1109121 : if (script->principals)
1259 890705 : JS_HoldPrincipals(script->principals);
1260 :
1261 : /* Establish invariant: principals implies originPrincipals. */
1262 1109121 : script->originPrincipals = bce->parser->originPrincipals;
1263 1109121 : if (!script->originPrincipals)
1264 1108591 : script->originPrincipals = script->principals;
1265 1109121 : if (script->originPrincipals)
1266 890711 : JS_HoldPrincipals(script->originPrincipals);
1267 :
1268 1109121 : script->sourceMap = (jschar *) bce->parser->tokenStream.releaseSourceMap();
1269 :
1270 1109121 : if (!FinishTakingSrcNotes(cx, bce, script->notes()))
1271 0 : return NULL;
1272 1109121 : if (bce->ntrynotes != 0)
1273 141944 : FinishTakingTryNotes(bce, script->trynotes());
1274 1109121 : if (bce->objectList.length != 0)
1275 386133 : bce->objectList.finish(script->objects());
1276 1109121 : if (bce->regexpList.length != 0)
1277 16561 : bce->regexpList.finish(script->regexps());
1278 1109121 : if (bce->constList.length() != 0)
1279 12798 : bce->constList.finish(script->consts());
1280 1109121 : if (bce->flags & TCF_NO_SCRIPT_RVAL)
1281 48924 : script->noScriptRval = true;
1282 1109121 : if (bce->flags & TCF_STRICT_MODE_CODE)
1283 364963 : script->strictModeCode = true;
1284 1109121 : if (bce->flags & TCF_COMPILE_N_GO) {
1285 219176 : script->compileAndGo = true;
1286 219176 : const StackFrame *fp = bce->parser->callerFrame;
1287 219176 : if (fp && fp->isFunctionFrame())
1288 30760 : script->savedCallerFun = true;
1289 : }
1290 1109121 : if (bce->callsEval())
1291 8074 : script->usesEval = true;
1292 1109121 : if (bce->flags & TCF_FUN_USES_ARGUMENTS)
1293 11913 : script->usesArguments = true;
1294 1109121 : if (bce->flags & TCF_HAS_SINGLETONS)
1295 30620 : script->hasSingletons = true;
1296 :
1297 1109121 : if (bce->hasUpvarIndices()) {
1298 83617 : JS_ASSERT(bce->upvarIndices->count() <= bce->upvarMap.length());
1299 83617 : PodCopy<UpvarCookie>(script->upvars()->vector, bce->upvarMap.begin(),
1300 167234 : bce->upvarIndices->count());
1301 83617 : bce->upvarIndices->clear();
1302 83617 : bce->upvarMap.clear();
1303 : }
1304 :
1305 1109121 : if (bce->globalUses.length()) {
1306 12799 : PodCopy<GlobalSlotArray::Entry>(script->globals()->vector, &bce->globalUses[0],
1307 25598 : bce->globalUses.length());
1308 : }
1309 :
1310 1109121 : if (script->nClosedArgs)
1311 83956 : PodCopy<uint32_t>(script->closedSlots, &bce->closedArgs[0], script->nClosedArgs);
1312 1109121 : if (script->nClosedVars) {
1313 59105 : PodCopy<uint32_t>(&script->closedSlots[script->nClosedArgs], &bce->closedVars[0],
1314 118210 : script->nClosedVars);
1315 : }
1316 :
1317 1109121 : script->bindings.transfer(cx, &bce->bindings);
1318 :
1319 1109121 : fun = NULL;
1320 1109121 : if (bce->inFunction()) {
1321 : /*
1322 : * We initialize fun->script() to be the script constructed above
1323 : * so that the debugger has a valid fun->script().
1324 : */
1325 988449 : fun = bce->fun();
1326 988449 : JS_ASSERT(fun->isInterpreted());
1327 988449 : JS_ASSERT(!fun->script());
1328 : #ifdef DEBUG
1329 988449 : if (JSScript::isValidOffset(script->upvarsOffset))
1330 83617 : JS_ASSERT(script->upvars()->length == script->bindings.countUpvars());
1331 : else
1332 904832 : JS_ASSERT(script->bindings.countUpvars() == 0);
1333 : #endif
1334 988449 : if (bce->flags & TCF_FUN_HEAVYWEIGHT)
1335 70146 : fun->flags |= JSFUN_HEAVYWEIGHT;
1336 :
1337 : /*
1338 : * Mark functions which will only be executed once as singletons.
1339 : * Skip this for flat closures, which must be copied on executing.
1340 : */
1341 : bool singleton =
1342 988449 : cx->typeInferenceEnabled() &&
1343 : bce->parent &&
1344 64157 : bce->parent->compiling() &&
1345 64157 : bce->parent->asBytecodeEmitter()->checkSingletonContext() &&
1346 1116763 : !fun->isFlatClosure();
1347 :
1348 988449 : if (!script->typeSetFunction(cx, fun, singleton))
1349 0 : return NULL;
1350 :
1351 988449 : fun->setScript(script);
1352 988449 : script->globalObject = fun->getParent() ? &fun->getParent()->global() : NULL;
1353 : } else {
1354 : /*
1355 : * Initialize script->object, if necessary, so that the debugger has a
1356 : * valid holder object.
1357 : */
1358 120672 : if (bce->flags & TCF_NEED_SCRIPT_GLOBAL)
1359 86584 : script->globalObject = GetCurrentGlobal(cx);
1360 : }
1361 :
1362 : /* Tell the debugger about this compiled script. */
1363 1109121 : js_CallNewScriptHook(cx, script, fun);
1364 1109121 : if (!bce->parent) {
1365 130777 : GlobalObject *compileAndGoGlobal = NULL;
1366 130777 : if (script->compileAndGo) {
1367 104023 : compileAndGoGlobal = script->globalObject;
1368 104023 : if (!compileAndGoGlobal)
1369 34088 : compileAndGoGlobal = &bce->scopeChain()->global();
1370 : }
1371 130777 : Debugger::onNewScript(cx, script, compileAndGoGlobal);
1372 : }
1373 :
1374 1109121 : if (cx->hasRunOption(JSOPTION_PCCOUNT))
1375 0 : (void) script->initCounts(cx);
1376 :
1377 1109121 : return script;
1378 : }
1379 :
1380 : size_t
1381 1324353 : JSScript::computedSizeOfData()
1382 : {
1383 : #if JS_SCRIPT_INLINE_DATA_LIMIT
1384 : if (data == inlineData)
1385 : return 0;
1386 : #endif
1387 :
1388 1324353 : uint8_t *dataEnd = code + length * sizeof(jsbytecode) + numNotes() * sizeof(jssrcnote);
1389 1324353 : JS_ASSERT(dataEnd >= data);
1390 1324353 : return dataEnd - data;
1391 : }
1392 :
1393 : size_t
1394 3818 : JSScript::sizeOfData(JSMallocSizeOfFun mallocSizeOf)
1395 : {
1396 : #if JS_SCRIPT_INLINE_DATA_LIMIT
1397 : if (data == inlineData)
1398 : return 0;
1399 : #endif
1400 :
1401 3818 : return mallocSizeOf(data);
1402 : }
1403 :
1404 : /*
1405 : * Nb: srcnotes are variable-length. This function computes the number of
1406 : * srcnote *slots*, which may be greater than the number of srcnotes.
1407 : */
1408 : uint32_t
1409 1783492 : JSScript::numNotes()
1410 : {
1411 : jssrcnote *sn;
1412 1783492 : jssrcnote *notes_ = notes();
1413 83317355 : for (sn = notes_; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
1414 81533863 : continue;
1415 1783492 : return sn - notes_ + 1; /* +1 for the terminator */
1416 : }
1417 :
1418 : JS_FRIEND_API(void)
1419 1383636 : js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
1420 : {
1421 1383636 : JS_ASSERT(!script->callDestroyHook);
1422 1383636 : if (JSNewScriptHook hook = cx->runtime->debugHooks.newScriptHook) {
1423 420786 : AutoKeepAtoms keep(cx->runtime);
1424 : hook(cx, script->filename, script->lineno, script, fun,
1425 210393 : cx->runtime->debugHooks.newScriptHookData);
1426 : }
1427 1383636 : script->callDestroyHook = true;
1428 1383636 : }
1429 :
1430 : void
1431 1417227 : js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
1432 : {
1433 1417227 : if (!script->callDestroyHook)
1434 34088 : return;
1435 :
1436 1383139 : if (JSDestroyScriptHook hook = cx->runtime->debugHooks.destroyScriptHook)
1437 71086 : hook(cx, script, cx->runtime->debugHooks.destroyScriptHookData);
1438 1383139 : script->callDestroyHook = false;
1439 1383139 : JS_ClearScriptTraps(cx, script);
1440 : }
1441 :
1442 : #ifdef JS_CRASH_DIAGNOSTICS
1443 :
1444 : void
1445 8149498 : JSScript::CheckScript(JSScript *prev)
1446 : {
1447 8149498 : if (cookie1[0] != JS_SCRIPT_COOKIE || cookie2[0] != JS_SCRIPT_COOKIE) {
1448 0 : crash::StackBuffer<sizeof(JSScript), 0x87> buf1(this);
1449 0 : crash::StackBuffer<sizeof(JSScript), 0x88> buf2(prev);
1450 0 : JS_OPT_ASSERT(false);
1451 : }
1452 8149498 : }
1453 :
1454 : #endif /* JS_CRASH_DIAGNOSTICS */
1455 :
1456 : void
1457 1324353 : JSScript::finalize(JSContext *cx, bool background)
1458 : {
1459 1324353 : CheckScript(NULL);
1460 :
1461 1324353 : js_CallDestroyScriptHook(cx, this);
1462 :
1463 1324353 : JS_ASSERT_IF(principals, originPrincipals);
1464 1324353 : if (principals)
1465 1064927 : JS_DropPrincipals(cx->runtime, principals);
1466 1324353 : if (originPrincipals)
1467 1064938 : JS_DropPrincipals(cx->runtime, originPrincipals);
1468 :
1469 1324353 : if (types)
1470 470660 : types->destroy();
1471 :
1472 : #ifdef JS_METHODJIT
1473 1324353 : mjit::ReleaseScriptCode(cx, this);
1474 : #endif
1475 :
1476 1324353 : destroyCounts(cx);
1477 :
1478 1324353 : if (sourceMap)
1479 1 : cx->free_(sourceMap);
1480 :
1481 1324353 : if (debug) {
1482 1 : jsbytecode *end = code + length;
1483 67 : for (jsbytecode *pc = code; pc < end; pc++) {
1484 66 : if (BreakpointSite *site = getBreakpointSite(pc)) {
1485 : /* Breakpoints are swept before finalization. */
1486 0 : JS_ASSERT(site->firstBreakpoint() == NULL);
1487 0 : site->clearTrap(cx, NULL, NULL);
1488 0 : JS_ASSERT(getBreakpointSite(pc) == NULL);
1489 : }
1490 : }
1491 1 : cx->free_(debug);
1492 : }
1493 :
1494 : #if JS_SCRIPT_INLINE_DATA_LIMIT
1495 : if (data != inlineData)
1496 : #endif
1497 : {
1498 1324353 : JS_POISON(data, 0xdb, computedSizeOfData());
1499 1324353 : cx->free_(data);
1500 : }
1501 1324353 : }
1502 :
1503 : namespace js {
1504 :
1505 : static const uint32_t GSN_CACHE_THRESHOLD = 100;
1506 : static const uint32_t GSN_CACHE_MAP_INIT_SIZE = 20;
1507 :
1508 : void
1509 52591 : GSNCache::purge()
1510 : {
1511 52591 : code = NULL;
1512 52591 : if (map.initialized())
1513 4813 : map.finish();
1514 52591 : }
1515 :
1516 : } /* namespace js */
1517 :
1518 : jssrcnote *
1519 35139329 : js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
1520 : {
1521 35139329 : size_t target = pc - script->code;
1522 35139329 : if (target >= size_t(script->length))
1523 0 : return NULL;
1524 :
1525 35139329 : GSNCache *cache = GetGSNCache(cx);
1526 35139329 : if (cache->code == script->code) {
1527 6768717 : JS_ASSERT(cache->map.initialized());
1528 6768717 : GSNCache::Map::Ptr p = cache->map.lookup(pc);
1529 6768717 : return p ? p->value : NULL;
1530 : }
1531 :
1532 28370612 : size_t offset = 0;
1533 : jssrcnote *result;
1534 163120524 : for (jssrcnote *sn = script->notes(); ; sn = SN_NEXT(sn)) {
1535 163120524 : if (SN_IS_TERMINATOR(sn)) {
1536 26468047 : result = NULL;
1537 26468047 : break;
1538 : }
1539 136652477 : offset += SN_DELTA(sn);
1540 136652477 : if (offset == target && SN_IS_GETTABLE(sn)) {
1541 1902565 : result = sn;
1542 1902565 : break;
1543 : }
1544 : }
1545 :
1546 28370612 : if (cache->code != script->code && script->length >= GSN_CACHE_THRESHOLD) {
1547 27005 : unsigned nsrcnotes = 0;
1548 3765236 : for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn);
1549 3738231 : sn = SN_NEXT(sn)) {
1550 3738231 : if (SN_IS_GETTABLE(sn))
1551 1537312 : ++nsrcnotes;
1552 : }
1553 27005 : if (cache->code) {
1554 22192 : JS_ASSERT(cache->map.initialized());
1555 22192 : cache->map.finish();
1556 22192 : cache->code = NULL;
1557 : }
1558 27005 : if (cache->map.init(nsrcnotes)) {
1559 27005 : pc = script->code;
1560 3765236 : for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn);
1561 3738231 : sn = SN_NEXT(sn)) {
1562 3738231 : pc += SN_DELTA(sn);
1563 3738231 : if (SN_IS_GETTABLE(sn))
1564 1537312 : JS_ALWAYS_TRUE(cache->map.put(pc, sn));
1565 : }
1566 27005 : cache->code = script->code;
1567 : }
1568 : }
1569 :
1570 28370612 : return result;
1571 : }
1572 :
1573 : unsigned
1574 6564562 : js::PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc)
1575 : {
1576 6564562 : unsigned lineno = startLine;
1577 :
1578 : /*
1579 : * Walk through source notes accumulating their deltas, keeping track of
1580 : * line-number notes, until we pass the note for pc's offset within
1581 : * script->code.
1582 : */
1583 6564562 : ptrdiff_t offset = 0;
1584 6564562 : ptrdiff_t target = pc - code;
1585 136098171 : for (jssrcnote *sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
1586 133035066 : offset += SN_DELTA(sn);
1587 133035066 : SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
1588 133035066 : if (type == SRC_SETLINE) {
1589 4604761 : if (offset <= target)
1590 4388558 : lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
1591 128430305 : } else if (type == SRC_NEWLINE) {
1592 41037060 : if (offset <= target)
1593 40494405 : lineno++;
1594 : }
1595 133035066 : if (offset > target)
1596 3501457 : break;
1597 : }
1598 :
1599 6564562 : return lineno;
1600 : }
1601 :
1602 : unsigned
1603 6564562 : js::PCToLineNumber(JSScript *script, jsbytecode *pc)
1604 : {
1605 : /* Cope with StackFrame.pc value prior to entering js_Interpret. */
1606 6564562 : if (!pc)
1607 0 : return 0;
1608 :
1609 6564562 : return PCToLineNumber(script->lineno, script->notes(), script->code, pc);
1610 : }
1611 :
1612 : /* The line number limit is the same as the jssrcnote offset limit. */
1613 : #define SN_LINE_LIMIT (SN_3BYTE_OFFSET_FLAG << 16)
1614 :
1615 : jsbytecode *
1616 18 : js_LineNumberToPC(JSScript *script, unsigned target)
1617 : {
1618 18 : ptrdiff_t offset = 0;
1619 18 : ptrdiff_t best = -1;
1620 18 : unsigned lineno = script->lineno;
1621 18 : unsigned bestdiff = SN_LINE_LIMIT;
1622 150 : for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
1623 : /*
1624 : * Exact-match only if offset is not in the prolog; otherwise use
1625 : * nearest greater-or-equal line number match.
1626 : */
1627 135 : if (lineno == target && offset >= ptrdiff_t(script->mainOffset))
1628 3 : goto out;
1629 132 : if (lineno >= target) {
1630 65 : unsigned diff = lineno - target;
1631 65 : if (diff < bestdiff) {
1632 7 : bestdiff = diff;
1633 7 : best = offset;
1634 : }
1635 : }
1636 132 : offset += SN_DELTA(sn);
1637 132 : SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
1638 132 : if (type == SRC_SETLINE) {
1639 15 : lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
1640 117 : } else if (type == SRC_NEWLINE) {
1641 45 : lineno++;
1642 : }
1643 : }
1644 15 : if (best >= 0)
1645 6 : offset = best;
1646 : out:
1647 18 : return script->code + offset;
1648 : }
1649 :
1650 : JS_FRIEND_API(unsigned)
1651 1061 : js_GetScriptLineExtent(JSScript *script)
1652 : {
1653 1061 : unsigned lineno = script->lineno;
1654 1061 : unsigned maxLineNo = 0;
1655 1061 : bool counting = true;
1656 1728 : for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
1657 667 : SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
1658 667 : if (type == SRC_SETLINE) {
1659 92 : if (maxLineNo < lineno)
1660 50 : maxLineNo = lineno;
1661 92 : lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
1662 92 : counting = true;
1663 92 : if (maxLineNo < lineno)
1664 71 : maxLineNo = lineno;
1665 : else
1666 21 : counting = false;
1667 575 : } else if (type == SRC_NEWLINE) {
1668 117 : if (counting)
1669 92 : lineno++;
1670 : }
1671 : }
1672 :
1673 1061 : if (maxLineNo > lineno)
1674 4 : lineno = maxLineNo;
1675 :
1676 1061 : return 1 + lineno - script->lineno;
1677 : }
1678 :
1679 : namespace js {
1680 :
1681 : unsigned
1682 610651 : CurrentLine(JSContext *cx)
1683 : {
1684 610651 : return PCToLineNumber(cx->fp()->script(), cx->regs().pc);
1685 : }
1686 :
1687 : void
1688 24243 : CurrentScriptFileLineOriginSlow(JSContext *cx, const char **file, unsigned *linenop,
1689 : JSPrincipals **origin)
1690 : {
1691 24243 : FrameRegsIter iter(cx);
1692 48486 : while (!iter.done() && !iter.fp()->isScriptFrame())
1693 0 : ++iter;
1694 :
1695 24243 : if (iter.done()) {
1696 4 : *file = NULL;
1697 4 : *linenop = 0;
1698 4 : *origin = NULL;
1699 4 : return;
1700 : }
1701 :
1702 24239 : JSScript *script = iter.fp()->script();
1703 24239 : *file = script->filename;
1704 24239 : *linenop = PCToLineNumber(iter.fp()->script(), iter.pc());
1705 24239 : *origin = script->originPrincipals;
1706 : }
1707 :
1708 : class AutoJSXDRState {
1709 : public:
1710 4558 : AutoJSXDRState(JSXDRState *x
1711 : JS_GUARD_OBJECT_NOTIFIER_PARAM)
1712 4558 : : xdr(x)
1713 : {
1714 4558 : JS_GUARD_OBJECT_NOTIFIER_INIT;
1715 4558 : }
1716 4558 : ~AutoJSXDRState()
1717 4558 : {
1718 4558 : JS_XDRDestroy(xdr);
1719 4558 : }
1720 :
1721 15953 : operator JSXDRState*() const
1722 : {
1723 15953 : return xdr;
1724 : }
1725 :
1726 4558 : JSXDRState* operator->() const
1727 : {
1728 4558 : return xdr;
1729 : }
1730 :
1731 : private:
1732 : JSXDRState *const xdr;
1733 : JS_DECL_USE_GUARD_OBJECT_NOTIFIER
1734 : };
1735 :
1736 : JSScript *
1737 2279 : CloneScript(JSContext *cx, JSScript *script)
1738 : {
1739 2279 : JS_ASSERT(cx->compartment != script->compartment());
1740 :
1741 : /* Serialize script. */
1742 4558 : AutoJSXDRState w(JS_XDRNewMem(cx, JSXDR_ENCODE));
1743 2279 : if (!w)
1744 0 : return NULL;
1745 :
1746 2279 : if (!XDRScript(w, &script))
1747 0 : return NULL;
1748 :
1749 : uint32_t nbytes;
1750 2279 : void *p = JS_XDRMemGetData(w, &nbytes);
1751 2279 : if (!p)
1752 0 : return NULL;
1753 :
1754 : /* De-serialize script. */
1755 4558 : AutoJSXDRState r(JS_XDRNewMem(cx, JSXDR_DECODE));
1756 2279 : if (!r)
1757 0 : return NULL;
1758 :
1759 : /*
1760 : * Hand p off from w to r. Don't want them to share the data mem, lest
1761 : * they both try to free it in JS_XDRDestroy.
1762 : */
1763 2279 : JS_XDRMemSetData(r, p, nbytes);
1764 2279 : JS_XDRMemSetData(w, NULL, 0);
1765 :
1766 2279 : r->principals = cx->compartment->principals;
1767 2279 : r->originPrincipals = JSScript::normalizeOriginPrincipals(cx->compartment->principals,
1768 2279 : script->originPrincipals);
1769 2279 : JSScript *newScript = NULL;
1770 2279 : if (!XDRScript(r, &newScript))
1771 0 : return NULL;
1772 :
1773 2279 : return newScript;
1774 : }
1775 :
1776 : } /* namespace js */
1777 :
1778 : void
1779 0 : JSScript::copyClosedSlotsTo(JSScript *other)
1780 : {
1781 0 : js_memcpy(other->closedSlots, closedSlots, nClosedArgs + nClosedVars);
1782 0 : }
1783 :
1784 : bool
1785 2595 : JSScript::ensureHasDebug(JSContext *cx)
1786 : {
1787 2595 : if (debug)
1788 1246 : return true;
1789 :
1790 1349 : size_t nbytes = offsetof(DebugScript, breakpoints) + length * sizeof(BreakpointSite*);
1791 1349 : debug = (DebugScript *) cx->calloc_(nbytes);
1792 1349 : if (!debug)
1793 0 : return false;
1794 :
1795 : /*
1796 : * Ensure that any Interpret() instances running on this script have
1797 : * interrupts enabled. The interrupts must stay enabled until the
1798 : * debug state is destroyed.
1799 : */
1800 : InterpreterFrames *frames;
1801 3956 : for (frames = cx->runtime->interpreterFrames; frames; frames = frames->older)
1802 2607 : frames->enableInterruptsIfRunning(this);
1803 :
1804 1349 : return true;
1805 : }
1806 :
1807 : bool
1808 883 : JSScript::recompileForStepMode(JSContext *cx)
1809 : {
1810 : #ifdef JS_METHODJIT
1811 883 : if (jitNormal || jitCtor) {
1812 202 : mjit::Recompiler::clearStackReferences(cx, this);
1813 202 : mjit::ReleaseScriptCode(cx, this);
1814 : }
1815 : #endif
1816 883 : return true;
1817 : }
1818 :
1819 : bool
1820 937 : JSScript::tryNewStepMode(JSContext *cx, uint32_t newValue)
1821 : {
1822 937 : JS_ASSERT(debug);
1823 :
1824 937 : uint32_t prior = debug->stepMode;
1825 937 : debug->stepMode = newValue;
1826 :
1827 937 : if (!prior != !newValue) {
1828 : /* Step mode has been enabled or disabled. Alert the methodjit. */
1829 883 : if (!recompileForStepMode(cx)) {
1830 0 : debug->stepMode = prior;
1831 0 : return false;
1832 : }
1833 :
1834 883 : if (!stepModeEnabled() && !debug->numSites) {
1835 432 : cx->free_(debug);
1836 432 : debug = NULL;
1837 : }
1838 : }
1839 :
1840 937 : return true;
1841 : }
1842 :
1843 : bool
1844 1 : JSScript::setStepModeFlag(JSContext *cx, bool step)
1845 : {
1846 1 : if (!ensureHasDebug(cx))
1847 0 : return false;
1848 :
1849 1 : return tryNewStepMode(cx, (debug->stepMode & stepCountMask) | (step ? stepFlagMask : 0));
1850 : }
1851 :
1852 : bool
1853 936 : JSScript::changeStepModeCount(JSContext *cx, int delta)
1854 : {
1855 936 : if (!ensureHasDebug(cx))
1856 0 : return false;
1857 :
1858 936 : assertSameCompartment(cx, this);
1859 936 : JS_ASSERT_IF(delta > 0, cx->compartment->debugMode());
1860 :
1861 936 : uint32_t count = debug->stepMode & stepCountMask;
1862 936 : JS_ASSERT(((count + delta) & stepCountMask) == count + delta);
1863 : return tryNewStepMode(cx,
1864 : (debug->stepMode & stepFlagMask) |
1865 936 : ((count + delta) & stepCountMask));
1866 : }
1867 :
1868 : BreakpointSite *
1869 1658 : JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
1870 : GlobalObject *scriptGlobal)
1871 : {
1872 1658 : JS_ASSERT(size_t(pc - code) < length);
1873 :
1874 1658 : if (!ensureHasDebug(cx))
1875 0 : return NULL;
1876 :
1877 1658 : BreakpointSite *&site = debug->breakpoints[pc - code];
1878 :
1879 1658 : if (!site) {
1880 1190 : site = cx->runtime->new_<BreakpointSite>(this, pc);
1881 1190 : if (!site) {
1882 0 : js_ReportOutOfMemory(cx);
1883 0 : return NULL;
1884 : }
1885 1190 : debug->numSites++;
1886 : }
1887 :
1888 1658 : if (site->scriptGlobal)
1889 279 : JS_ASSERT_IF(scriptGlobal, site->scriptGlobal == scriptGlobal);
1890 : else
1891 1379 : site->scriptGlobal = scriptGlobal;
1892 :
1893 1658 : return site;
1894 : }
1895 :
1896 : void
1897 1190 : JSScript::destroyBreakpointSite(JSRuntime *rt, jsbytecode *pc)
1898 : {
1899 1190 : JS_ASSERT(unsigned(pc - code) < length);
1900 :
1901 1190 : BreakpointSite *&site = debug->breakpoints[pc - code];
1902 1190 : JS_ASSERT(site);
1903 :
1904 1190 : rt->delete_(site);
1905 1190 : site = NULL;
1906 :
1907 1190 : if (--debug->numSites == 0 && !stepModeEnabled()) {
1908 916 : rt->free_(debug);
1909 916 : debug = NULL;
1910 : }
1911 1190 : }
1912 :
1913 : void
1914 8814 : JSScript::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler)
1915 : {
1916 8814 : if (!hasAnyBreakpointsOrStepMode())
1917 8337 : return;
1918 :
1919 477 : jsbytecode *end = code + length;
1920 8886126 : for (jsbytecode *pc = code; pc < end; pc++) {
1921 8885649 : BreakpointSite *site = getBreakpointSite(pc);
1922 8885649 : if (site) {
1923 : Breakpoint *nextbp;
1924 1707 : for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
1925 1047 : nextbp = bp->nextInSite();
1926 1047 : if ((!dbg || bp->debugger == dbg) && (!handler || bp->getHandler() == handler))
1927 768 : bp->destroy(cx);
1928 : }
1929 : }
1930 : }
1931 : }
1932 :
1933 : void
1934 1741574 : JSScript::clearTraps(JSContext *cx)
1935 : {
1936 1741574 : if (!hasAnyBreakpointsOrStepMode())
1937 1741052 : return;
1938 :
1939 522 : jsbytecode *end = code + length;
1940 18081 : for (jsbytecode *pc = code; pc < end; pc++) {
1941 17559 : BreakpointSite *site = getBreakpointSite(pc);
1942 17559 : if (site)
1943 638 : site->clearTrap(cx);
1944 : }
1945 : }
1946 :
1947 : void
1948 6825145 : JSScript::markChildren(JSTracer *trc)
1949 : {
1950 6825145 : CheckScript(NULL);
1951 :
1952 470 : JS_ASSERT_IF(trc->runtime->gcCheckCompartment,
1953 6825615 : compartment() == trc->runtime->gcCheckCompartment);
1954 :
1955 69116789 : for (uint32_t i = 0; i < natoms; ++i) {
1956 62291644 : if (atoms[i])
1957 62291644 : MarkStringUnbarriered(trc, &atoms[i], "atom");
1958 : }
1959 :
1960 6825145 : if (JSScript::isValidOffset(objectsOffset)) {
1961 2173737 : JSObjectArray *objarray = objects();
1962 2173737 : MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
1963 : }
1964 :
1965 6825145 : if (JSScript::isValidOffset(regexpsOffset)) {
1966 87260 : JSObjectArray *objarray = regexps();
1967 87260 : MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
1968 : }
1969 :
1970 6825145 : if (JSScript::isValidOffset(constOffset)) {
1971 86824 : JSConstArray *constarray = consts();
1972 86824 : MarkValueRange(trc, constarray->length, constarray->vector, "consts");
1973 : }
1974 :
1975 6825145 : if (function())
1976 6778093 : MarkObject(trc, &function_, "function");
1977 :
1978 6825145 : if (!isCachedEval && globalObject)
1979 100743 : MarkObject(trc, &globalObject, "object");
1980 :
1981 6825145 : if (IS_GC_MARKING_TRACER(trc) && filename)
1982 6564228 : js_MarkScriptFilename(filename);
1983 :
1984 6825145 : bindings.trace(trc);
1985 :
1986 6825145 : if (types)
1987 1954054 : types->trace(trc);
1988 :
1989 6825145 : if (hasAnyBreakpointsOrStepMode()) {
1990 24457 : for (unsigned i = 0; i < length; i++) {
1991 23811 : BreakpointSite *site = debug->breakpoints[i];
1992 23811 : if (site && site->trapHandler)
1993 641 : MarkValue(trc, &site->trapClosure, "trap closure");
1994 : }
1995 : }
1996 6825145 : }
|