js/src/jsscript.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jsscript.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3869 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/*
    1.11 + * JS script operations.
    1.12 + */
    1.13 +
    1.14 +#include "jsscriptinlines.h"
    1.15 +
    1.16 +#include "mozilla/DebugOnly.h"
    1.17 +#include "mozilla/MathAlgorithms.h"
    1.18 +#include "mozilla/MemoryReporting.h"
    1.19 +#include "mozilla/PodOperations.h"
    1.20 +
    1.21 +#include <string.h>
    1.22 +
    1.23 +#include "jsapi.h"
    1.24 +#include "jsatom.h"
    1.25 +#include "jscntxt.h"
    1.26 +#include "jsfun.h"
    1.27 +#include "jsgc.h"
    1.28 +#include "jsobj.h"
    1.29 +#include "jsopcode.h"
    1.30 +#include "jsprf.h"
    1.31 +#include "jstypes.h"
    1.32 +#include "jsutil.h"
    1.33 +#include "jswrapper.h"
    1.34 +
    1.35 +#include "frontend/BytecodeCompiler.h"
    1.36 +#include "frontend/BytecodeEmitter.h"
    1.37 +#include "frontend/SharedContext.h"
    1.38 +#include "gc/Marking.h"
    1.39 +#include "jit/BaselineJIT.h"
    1.40 +#include "jit/IonCode.h"
    1.41 +#include "js/MemoryMetrics.h"
    1.42 +#include "js/OldDebugAPI.h"
    1.43 +#include "js/Utility.h"
    1.44 +#include "vm/ArgumentsObject.h"
    1.45 +#include "vm/Compression.h"
    1.46 +#include "vm/Debugger.h"
    1.47 +#include "vm/Opcodes.h"
    1.48 +#include "vm/SelfHosting.h"
    1.49 +#include "vm/Shape.h"
    1.50 +#include "vm/Xdr.h"
    1.51 +
    1.52 +#include "jsfuninlines.h"
    1.53 +#include "jsinferinlines.h"
    1.54 +#include "jsobjinlines.h"
    1.55 +
    1.56 +#include "vm/ScopeObject-inl.h"
    1.57 +#include "vm/Stack-inl.h"
    1.58 +
    1.59 +using namespace js;
    1.60 +using namespace js::gc;
    1.61 +using namespace js::frontend;
    1.62 +
    1.63 +using mozilla::PodCopy;
    1.64 +using mozilla::PodZero;
    1.65 +using mozilla::RotateLeft;
    1.66 +
    1.67 +typedef Rooted<GlobalObject *> RootedGlobalObject;
    1.68 +
    1.69 +/* static */ uint32_t
    1.70 +Bindings::argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle bindings)
    1.71 +{
    1.72 +    HandlePropertyName arguments = cx->names().arguments;
    1.73 +    BindingIter bi(bindings);
    1.74 +    while (bi->name() != arguments)
    1.75 +        bi++;
    1.76 +    return bi.frameIndex();
    1.77 +}
    1.78 +
    1.79 +bool
    1.80 +Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
    1.81 +                                   unsigned numArgs, uint32_t numVars,
    1.82 +                                   Binding *bindingArray, uint32_t numBlockScoped)
    1.83 +{
    1.84 +    JS_ASSERT(!self->callObjShape_);
    1.85 +    JS_ASSERT(self->bindingArrayAndFlag_ == TEMPORARY_STORAGE_BIT);
    1.86 +    JS_ASSERT(!(uintptr_t(bindingArray) & TEMPORARY_STORAGE_BIT));
    1.87 +    JS_ASSERT(numArgs <= ARGC_LIMIT);
    1.88 +    JS_ASSERT(numVars <= LOCALNO_LIMIT);
    1.89 +    JS_ASSERT(numBlockScoped <= LOCALNO_LIMIT);
    1.90 +    JS_ASSERT(numVars <= LOCALNO_LIMIT - numBlockScoped);
    1.91 +    JS_ASSERT(UINT32_MAX - numArgs >= numVars + numBlockScoped);
    1.92 +
    1.93 +    self->bindingArrayAndFlag_ = uintptr_t(bindingArray) | TEMPORARY_STORAGE_BIT;
    1.94 +    self->numArgs_ = numArgs;
    1.95 +    self->numVars_ = numVars;
    1.96 +    self->numBlockScoped_ = numBlockScoped;
    1.97 +
    1.98 +    // Get the initial shape to use when creating CallObjects for this script.
    1.99 +    // After creation, a CallObject's shape may change completely (via direct eval() or
   1.100 +    // other operations that mutate the lexical scope). However, since the
   1.101 +    // lexical bindings added to the initial shape are permanent and the
   1.102 +    // allocKind/nfixed of a CallObject cannot change, one may assume that the
   1.103 +    // slot location (whether in the fixed or dynamic slots) of a variable is
   1.104 +    // the same as in the initial shape. (This is assumed by the interpreter and
   1.105 +    // JITs when interpreting/compiling aliasedvar ops.)
   1.106 +
   1.107 +    // Since unaliased variables are, by definition, only accessed by local
   1.108 +    // operations and never through the scope chain, only give shapes to
   1.109 +    // aliased variables. While the debugger may observe any scope object at
   1.110 +    // any time, such accesses are mediated by DebugScopeProxy (see
   1.111 +    // DebugScopeProxy::handleUnaliasedAccess).
   1.112 +    uint32_t nslots = CallObject::RESERVED_SLOTS;
   1.113 +    for (BindingIter bi(self); bi; bi++) {
   1.114 +        if (bi->aliased())
   1.115 +            nslots++;
   1.116 +    }
   1.117 +
   1.118 +    // Put as many of nslots inline into the object header as possible.
   1.119 +    uint32_t nfixed = gc::GetGCKindSlots(gc::GetGCObjectKind(nslots));
   1.120 +
   1.121 +    // Start with the empty shape and then append one shape per aliased binding.
   1.122 +    RootedShape shape(cx,
   1.123 +        EmptyShape::getInitialShape(cx, &CallObject::class_, nullptr, nullptr, nullptr,
   1.124 +                                    nfixed, BaseShape::VAROBJ | BaseShape::DELEGATE));
   1.125 +    if (!shape)
   1.126 +        return false;
   1.127 +
   1.128 +#ifdef DEBUG
   1.129 +    HashSet<PropertyName *> added(cx);
   1.130 +    if (!added.init())
   1.131 +        return false;
   1.132 +#endif
   1.133 +
   1.134 +    uint32_t slot = CallObject::RESERVED_SLOTS;
   1.135 +    for (BindingIter bi(self); bi; bi++) {
   1.136 +        if (!bi->aliased())
   1.137 +            continue;
   1.138 +
   1.139 +#ifdef DEBUG
   1.140 +        // The caller ensures no duplicate aliased names.
   1.141 +        JS_ASSERT(!added.has(bi->name()));
   1.142 +        if (!added.put(bi->name()))
   1.143 +            return false;
   1.144 +#endif
   1.145 +
   1.146 +        StackBaseShape stackBase(cx, &CallObject::class_, nullptr, nullptr,
   1.147 +                                 BaseShape::VAROBJ | BaseShape::DELEGATE);
   1.148 +
   1.149 +        UnownedBaseShape *base = BaseShape::getUnowned(cx, stackBase);
   1.150 +        if (!base)
   1.151 +            return false;
   1.152 +
   1.153 +        unsigned attrs = JSPROP_PERMANENT |
   1.154 +                         JSPROP_ENUMERATE |
   1.155 +                         (bi->kind() == Binding::CONSTANT ? JSPROP_READONLY : 0);
   1.156 +        StackShape child(base, NameToId(bi->name()), slot, attrs, 0);
   1.157 +
   1.158 +        shape = cx->compartment()->propertyTree.getChild(cx, shape, child);
   1.159 +        if (!shape)
   1.160 +            return false;
   1.161 +
   1.162 +        JS_ASSERT(slot < nslots);
   1.163 +        slot++;
   1.164 +    }
   1.165 +    JS_ASSERT(slot == nslots);
   1.166 +
   1.167 +    JS_ASSERT(!shape->inDictionary());
   1.168 +    self->callObjShape_.init(shape);
   1.169 +    return true;
   1.170 +}
   1.171 +
   1.172 +uint8_t *
   1.173 +Bindings::switchToScriptStorage(Binding *newBindingArray)
   1.174 +{
   1.175 +    JS_ASSERT(bindingArrayUsingTemporaryStorage());
   1.176 +    JS_ASSERT(!(uintptr_t(newBindingArray) & TEMPORARY_STORAGE_BIT));
   1.177 +
   1.178 +    if (count() > 0)
   1.179 +        PodCopy(newBindingArray, bindingArray(), count());
   1.180 +    bindingArrayAndFlag_ = uintptr_t(newBindingArray);
   1.181 +    return reinterpret_cast<uint8_t *>(newBindingArray + count());
   1.182 +}
   1.183 +
   1.184 +bool
   1.185 +Bindings::clone(JSContext *cx, InternalBindingsHandle self,
   1.186 +                uint8_t *dstScriptData, HandleScript srcScript)
   1.187 +{
   1.188 +    /* The clone has the same bindingArray_ offset as 'src'. */
   1.189 +    Bindings &src = srcScript->bindings;
   1.190 +    ptrdiff_t off = (uint8_t *)src.bindingArray() - srcScript->data;
   1.191 +    JS_ASSERT(off >= 0);
   1.192 +    JS_ASSERT(size_t(off) <= srcScript->dataSize());
   1.193 +    Binding *dstPackedBindings = (Binding *)(dstScriptData + off);
   1.194 +
   1.195 +    /*
   1.196 +     * Since atoms are shareable throughout the runtime, we can simply copy
   1.197 +     * the source's bindingArray directly.
   1.198 +     */
   1.199 +    if (!initWithTemporaryStorage(cx, self, src.numArgs(), src.numVars(), src.bindingArray(),
   1.200 +                                  src.numBlockScoped()))
   1.201 +        return false;
   1.202 +    self->switchToScriptStorage(dstPackedBindings);
   1.203 +    return true;
   1.204 +}
   1.205 +
   1.206 +/* static */ Bindings
   1.207 +GCMethods<Bindings>::initial()
   1.208 +{
   1.209 +    return Bindings();
   1.210 +}
   1.211 +
   1.212 +template<XDRMode mode>
   1.213 +static bool
   1.214 +XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, uint32_t numVars,
   1.215 +                  HandleScript script, unsigned numBlockScoped)
   1.216 +{
   1.217 +    JSContext *cx = xdr->cx();
   1.218 +
   1.219 +    if (mode == XDR_ENCODE) {
   1.220 +        for (BindingIter bi(script); bi; bi++) {
   1.221 +            RootedAtom atom(cx, bi->name());
   1.222 +            if (!XDRAtom(xdr, &atom))
   1.223 +                return false;
   1.224 +        }
   1.225 +
   1.226 +        for (BindingIter bi(script); bi; bi++) {
   1.227 +            uint8_t u8 = (uint8_t(bi->kind()) << 1) | uint8_t(bi->aliased());
   1.228 +            if (!xdr->codeUint8(&u8))
   1.229 +                return false;
   1.230 +        }
   1.231 +    } else {
   1.232 +        uint32_t nameCount = numArgs + numVars;
   1.233 +
   1.234 +        AutoValueVector atoms(cx);
   1.235 +        if (!atoms.resize(nameCount))
   1.236 +            return false;
   1.237 +        for (uint32_t i = 0; i < nameCount; i++) {
   1.238 +            RootedAtom atom(cx);
   1.239 +            if (!XDRAtom(xdr, &atom))
   1.240 +                return false;
   1.241 +            atoms[i] = StringValue(atom);
   1.242 +        }
   1.243 +
   1.244 +        Binding *bindingArray = las.alloc().newArrayUninitialized<Binding>(nameCount);
   1.245 +        if (!bindingArray)
   1.246 +            return false;
   1.247 +        for (uint32_t i = 0; i < nameCount; i++) {
   1.248 +            uint8_t u8;
   1.249 +            if (!xdr->codeUint8(&u8))
   1.250 +                return false;
   1.251 +
   1.252 +            PropertyName *name = atoms[i].toString()->asAtom().asPropertyName();
   1.253 +            Binding::Kind kind = Binding::Kind(u8 >> 1);
   1.254 +            bool aliased = bool(u8 & 1);
   1.255 +
   1.256 +            bindingArray[i] = Binding(name, kind, aliased);
   1.257 +        }
   1.258 +
   1.259 +        InternalBindingsHandle bindings(script, &script->bindings);
   1.260 +        if (!Bindings::initWithTemporaryStorage(cx, bindings, numArgs, numVars, bindingArray,
   1.261 +                                                numBlockScoped))
   1.262 +            return false;
   1.263 +    }
   1.264 +
   1.265 +    return true;
   1.266 +}
   1.267 +
   1.268 +bool
   1.269 +Bindings::bindingIsAliased(uint32_t bindingIndex)
   1.270 +{
   1.271 +    JS_ASSERT(bindingIndex < count());
   1.272 +    return bindingArray()[bindingIndex].aliased();
   1.273 +}
   1.274 +
   1.275 +void
   1.276 +Bindings::trace(JSTracer *trc)
   1.277 +{
   1.278 +    if (callObjShape_)
   1.279 +        MarkShape(trc, &callObjShape_, "callObjShape");
   1.280 +
   1.281 +    /*
   1.282 +     * As the comment in Bindings explains, bindingsArray may point into freed
   1.283 +     * storage when bindingArrayUsingTemporaryStorage so we don't mark it.
   1.284 +     * Note: during compilation, atoms are already kept alive by gcKeepAtoms.
   1.285 +     */
   1.286 +    if (bindingArrayUsingTemporaryStorage())
   1.287 +        return;
   1.288 +
   1.289 +    for (Binding *b = bindingArray(), *end = b + count(); b != end; b++) {
   1.290 +        PropertyName *name = b->name();
   1.291 +        MarkStringUnbarriered(trc, &name, "bindingArray");
   1.292 +    }
   1.293 +}
   1.294 +
   1.295 +bool
   1.296 +js::FillBindingVector(HandleScript fromScript, BindingVector *vec)
   1.297 +{
   1.298 +    for (BindingIter bi(fromScript); bi; bi++) {
   1.299 +        if (!vec->append(*bi))
   1.300 +            return false;
   1.301 +    }
   1.302 +
   1.303 +    return true;
   1.304 +}
   1.305 +
   1.306 +template<XDRMode mode>
   1.307 +bool
   1.308 +js::XDRScriptConst(XDRState<mode> *xdr, MutableHandleValue vp)
   1.309 +{
   1.310 +    JSContext *cx = xdr->cx();
   1.311 +
   1.312 +    /*
   1.313 +     * A script constant can be an arbitrary primitive value as they are used
   1.314 +     * to implement JSOP_LOOKUPSWITCH. But they cannot be objects, see
   1.315 +     * bug 407186.
   1.316 +     */
   1.317 +    enum ConstTag {
   1.318 +        SCRIPT_INT     = 0,
   1.319 +        SCRIPT_DOUBLE  = 1,
   1.320 +        SCRIPT_ATOM    = 2,
   1.321 +        SCRIPT_TRUE    = 3,
   1.322 +        SCRIPT_FALSE   = 4,
   1.323 +        SCRIPT_NULL    = 5,
   1.324 +        SCRIPT_OBJECT  = 6,
   1.325 +        SCRIPT_VOID    = 7,
   1.326 +        SCRIPT_HOLE    = 8
   1.327 +    };
   1.328 +
   1.329 +    uint32_t tag;
   1.330 +    if (mode == XDR_ENCODE) {
   1.331 +        if (vp.isInt32()) {
   1.332 +            tag = SCRIPT_INT;
   1.333 +        } else if (vp.isDouble()) {
   1.334 +            tag = SCRIPT_DOUBLE;
   1.335 +        } else if (vp.isString()) {
   1.336 +            tag = SCRIPT_ATOM;
   1.337 +        } else if (vp.isTrue()) {
   1.338 +            tag = SCRIPT_TRUE;
   1.339 +        } else if (vp.isFalse()) {
   1.340 +            tag = SCRIPT_FALSE;
   1.341 +        } else if (vp.isNull()) {
   1.342 +            tag = SCRIPT_NULL;
   1.343 +        } else if (vp.isObject()) {
   1.344 +            tag = SCRIPT_OBJECT;
   1.345 +        } else if (vp.isMagic(JS_ELEMENTS_HOLE)) {
   1.346 +            tag = SCRIPT_HOLE;
   1.347 +        } else {
   1.348 +            JS_ASSERT(vp.isUndefined());
   1.349 +            tag = SCRIPT_VOID;
   1.350 +        }
   1.351 +    }
   1.352 +
   1.353 +    if (!xdr->codeUint32(&tag))
   1.354 +        return false;
   1.355 +
   1.356 +    switch (tag) {
   1.357 +      case SCRIPT_INT: {
   1.358 +        uint32_t i;
   1.359 +        if (mode == XDR_ENCODE)
   1.360 +            i = uint32_t(vp.toInt32());
   1.361 +        if (!xdr->codeUint32(&i))
   1.362 +            return false;
   1.363 +        if (mode == XDR_DECODE)
   1.364 +            vp.set(Int32Value(int32_t(i)));
   1.365 +        break;
   1.366 +      }
   1.367 +      case SCRIPT_DOUBLE: {
   1.368 +        double d;
   1.369 +        if (mode == XDR_ENCODE)
   1.370 +            d = vp.toDouble();
   1.371 +        if (!xdr->codeDouble(&d))
   1.372 +            return false;
   1.373 +        if (mode == XDR_DECODE)
   1.374 +            vp.set(DoubleValue(d));
   1.375 +        break;
   1.376 +      }
   1.377 +      case SCRIPT_ATOM: {
   1.378 +        RootedAtom atom(cx);
   1.379 +        if (mode == XDR_ENCODE)
   1.380 +            atom = &vp.toString()->asAtom();
   1.381 +        if (!XDRAtom(xdr, &atom))
   1.382 +            return false;
   1.383 +        if (mode == XDR_DECODE)
   1.384 +            vp.set(StringValue(atom));
   1.385 +        break;
   1.386 +      }
   1.387 +      case SCRIPT_TRUE:
   1.388 +        if (mode == XDR_DECODE)
   1.389 +            vp.set(BooleanValue(true));
   1.390 +        break;
   1.391 +      case SCRIPT_FALSE:
   1.392 +        if (mode == XDR_DECODE)
   1.393 +            vp.set(BooleanValue(false));
   1.394 +        break;
   1.395 +      case SCRIPT_NULL:
   1.396 +        if (mode == XDR_DECODE)
   1.397 +            vp.set(NullValue());
   1.398 +        break;
   1.399 +      case SCRIPT_OBJECT: {
   1.400 +        RootedObject obj(cx);
   1.401 +        if (mode == XDR_ENCODE)
   1.402 +            obj = &vp.toObject();
   1.403 +
   1.404 +        if (!XDRObjectLiteral(xdr, &obj))
   1.405 +            return false;
   1.406 +
   1.407 +        if (mode == XDR_DECODE)
   1.408 +            vp.setObject(*obj);
   1.409 +        break;
   1.410 +      }
   1.411 +      case SCRIPT_VOID:
   1.412 +        if (mode == XDR_DECODE)
   1.413 +            vp.set(UndefinedValue());
   1.414 +        break;
   1.415 +      case SCRIPT_HOLE:
   1.416 +        if (mode == XDR_DECODE)
   1.417 +            vp.setMagic(JS_ELEMENTS_HOLE);
   1.418 +        break;
   1.419 +    }
   1.420 +    return true;
   1.421 +}
   1.422 +
   1.423 +template bool
   1.424 +js::XDRScriptConst(XDRState<XDR_ENCODE> *, MutableHandleValue);
   1.425 +
   1.426 +template bool
   1.427 +js::XDRScriptConst(XDRState<XDR_DECODE> *, MutableHandleValue);
   1.428 +
   1.429 +// Code LazyScript's free variables.
   1.430 +template<XDRMode mode>
   1.431 +static bool
   1.432 +XDRLazyFreeVariables(XDRState<mode> *xdr, MutableHandle<LazyScript *> lazy)
   1.433 +{
   1.434 +    JSContext *cx = xdr->cx();
   1.435 +    RootedAtom atom(cx);
   1.436 +    HeapPtrAtom *freeVariables = lazy->freeVariables();
   1.437 +    size_t numFreeVariables = lazy->numFreeVariables();
   1.438 +    for (size_t i = 0; i < numFreeVariables; i++) {
   1.439 +        if (mode == XDR_ENCODE)
   1.440 +            atom = freeVariables[i];
   1.441 +
   1.442 +        if (!XDRAtom(xdr, &atom))
   1.443 +            return false;
   1.444 +
   1.445 +        if (mode == XDR_DECODE)
   1.446 +            freeVariables[i] = atom;
   1.447 +    }
   1.448 +
   1.449 +    return true;
   1.450 +}
   1.451 +
   1.452 +// Code the missing part needed to re-create a LazyScript from a JSScript.
   1.453 +template<XDRMode mode>
   1.454 +static bool
   1.455 +XDRRelazificationInfo(XDRState<mode> *xdr, HandleFunction fun, HandleScript script,
   1.456 +                      MutableHandle<LazyScript *> lazy)
   1.457 +{
   1.458 +    MOZ_ASSERT_IF(mode == XDR_ENCODE, script->isRelazifiable() && script->maybeLazyScript());
   1.459 +    MOZ_ASSERT_IF(mode == XDR_ENCODE, !lazy->numInnerFunctions());
   1.460 +
   1.461 +    JSContext *cx = xdr->cx();
   1.462 +
   1.463 +    uint64_t packedFields;
   1.464 +    {
   1.465 +        uint32_t begin = script->sourceStart();
   1.466 +        uint32_t end = script->sourceEnd();
   1.467 +        uint32_t lineno = script->lineno();
   1.468 +        uint32_t column = script->column();
   1.469 +
   1.470 +        if (mode == XDR_ENCODE) {
   1.471 +            packedFields = lazy->packedFields();
   1.472 +            MOZ_ASSERT(begin == lazy->begin());
   1.473 +            MOZ_ASSERT(end == lazy->end());
   1.474 +            MOZ_ASSERT(lineno == lazy->lineno());
   1.475 +            MOZ_ASSERT(column == lazy->column());
   1.476 +        }
   1.477 +
   1.478 +        if (!xdr->codeUint64(&packedFields))
   1.479 +            return false;
   1.480 +
   1.481 +        if (mode == XDR_DECODE) {
   1.482 +            lazy.set(LazyScript::Create(cx, fun, packedFields, begin, end, lineno, column));
   1.483 +
   1.484 +            // As opposed to XDRLazyScript, we need to restore the runtime bits
   1.485 +            // of the script, as we are trying to match the fact this function
   1.486 +            // has already been parsed and that it would need to be re-lazified.
   1.487 +            lazy->initRuntimeFields(packedFields);
   1.488 +        }
   1.489 +    }
   1.490 +
   1.491 +    // Code free variables.
   1.492 +    if (!XDRLazyFreeVariables(xdr, lazy))
   1.493 +        return false;
   1.494 +
   1.495 +    return true;
   1.496 +}
   1.497 +
   1.498 +static inline uint32_t
   1.499 +FindScopeObjectIndex(JSScript *script, NestedScopeObject &scope)
   1.500 +{
   1.501 +    ObjectArray *objects = script->objects();
   1.502 +    HeapPtrObject *vector = objects->vector;
   1.503 +    unsigned length = objects->length;
   1.504 +    for (unsigned i = 0; i < length; ++i) {
   1.505 +        if (vector[i] == &scope)
   1.506 +            return i;
   1.507 +    }
   1.508 +
   1.509 +    MOZ_ASSUME_UNREACHABLE("Scope not found");
   1.510 +}
   1.511 +
   1.512 +static bool
   1.513 +SaveSharedScriptData(ExclusiveContext *, Handle<JSScript *>, SharedScriptData *, uint32_t);
   1.514 +
   1.515 +enum XDRClassKind {
   1.516 +    CK_BlockObject = 0,
   1.517 +    CK_WithObject  = 1,
   1.518 +    CK_JSFunction  = 2,
   1.519 +    CK_JSObject    = 3
   1.520 +};
   1.521 +
   1.522 +template<XDRMode mode>
   1.523 +bool
   1.524 +js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
   1.525 +              HandleFunction fun, MutableHandleScript scriptp)
   1.526 +{
   1.527 +    /* NB: Keep this in sync with CloneScript. */
   1.528 +
   1.529 +    enum ScriptBits {
   1.530 +        NoScriptRval,
   1.531 +        SavedCallerFun,
   1.532 +        Strict,
   1.533 +        ContainsDynamicNameAccess,
   1.534 +        FunHasExtensibleScope,
   1.535 +        FunNeedsDeclEnvObject,
   1.536 +        FunHasAnyAliasedFormal,
   1.537 +        ArgumentsHasVarBinding,
   1.538 +        NeedsArgsObj,
   1.539 +        IsGeneratorExp,
   1.540 +        IsLegacyGenerator,
   1.541 +        IsStarGenerator,
   1.542 +        OwnSource,
   1.543 +        ExplicitUseStrict,
   1.544 +        SelfHosted,
   1.545 +        IsCompileAndGo,
   1.546 +        HasSingleton,
   1.547 +        TreatAsRunOnce,
   1.548 +        HasLazyScript
   1.549 +    };
   1.550 +
   1.551 +    uint32_t length, lineno, column, nslots, staticLevel;
   1.552 +    uint32_t natoms, nsrcnotes, i;
   1.553 +    uint32_t nconsts, nobjects, nregexps, ntrynotes, nblockscopes;
   1.554 +    uint32_t prologLength, version;
   1.555 +    uint32_t funLength = 0;
   1.556 +    uint32_t nTypeSets = 0;
   1.557 +    uint32_t scriptBits = 0;
   1.558 +
   1.559 +    JSContext *cx = xdr->cx();
   1.560 +    RootedScript script(cx);
   1.561 +    natoms = nsrcnotes = 0;
   1.562 +    nconsts = nobjects = nregexps = ntrynotes = nblockscopes = 0;
   1.563 +
   1.564 +    /* XDR arguments and vars. */
   1.565 +    uint16_t nargs = 0;
   1.566 +    uint16_t nblocklocals = 0;
   1.567 +    uint32_t nvars = 0;
   1.568 +    if (mode == XDR_ENCODE) {
   1.569 +        script = scriptp.get();
   1.570 +        JS_ASSERT_IF(enclosingScript, enclosingScript->compartment() == script->compartment());
   1.571 +
   1.572 +        nargs = script->bindings.numArgs();
   1.573 +        nblocklocals = script->bindings.numBlockScoped();
   1.574 +        nvars = script->bindings.numVars();
   1.575 +    }
   1.576 +    if (!xdr->codeUint16(&nargs))
   1.577 +        return false;
   1.578 +    if (!xdr->codeUint16(&nblocklocals))
   1.579 +        return false;
   1.580 +    if (!xdr->codeUint32(&nvars))
   1.581 +        return false;
   1.582 +
   1.583 +    if (mode == XDR_ENCODE)
   1.584 +        length = script->length();
   1.585 +    if (!xdr->codeUint32(&length))
   1.586 +        return false;
   1.587 +
   1.588 +    if (mode == XDR_ENCODE) {
   1.589 +        prologLength = script->mainOffset();
   1.590 +        JS_ASSERT(script->getVersion() != JSVERSION_UNKNOWN);
   1.591 +        version = script->getVersion();
   1.592 +        lineno = script->lineno();
   1.593 +        column = script->column();
   1.594 +        nslots = script->nslots();
   1.595 +        staticLevel = script->staticLevel();
   1.596 +        natoms = script->natoms();
   1.597 +
   1.598 +        nsrcnotes = script->numNotes();
   1.599 +
   1.600 +        if (script->hasConsts())
   1.601 +            nconsts = script->consts()->length;
   1.602 +        if (script->hasObjects())
   1.603 +            nobjects = script->objects()->length;
   1.604 +        if (script->hasRegexps())
   1.605 +            nregexps = script->regexps()->length;
   1.606 +        if (script->hasTrynotes())
   1.607 +            ntrynotes = script->trynotes()->length;
   1.608 +        if (script->hasBlockScopes())
   1.609 +            nblockscopes = script->blockScopes()->length;
   1.610 +
   1.611 +        nTypeSets = script->nTypeSets();
   1.612 +        funLength = script->funLength();
   1.613 +
   1.614 +        if (script->noScriptRval())
   1.615 +            scriptBits |= (1 << NoScriptRval);
   1.616 +        if (script->savedCallerFun())
   1.617 +            scriptBits |= (1 << SavedCallerFun);
   1.618 +        if (script->strict())
   1.619 +            scriptBits |= (1 << Strict);
   1.620 +        if (script->explicitUseStrict())
   1.621 +            scriptBits |= (1 << ExplicitUseStrict);
   1.622 +        if (script->selfHosted())
   1.623 +            scriptBits |= (1 << SelfHosted);
   1.624 +        if (script->bindingsAccessedDynamically())
   1.625 +            scriptBits |= (1 << ContainsDynamicNameAccess);
   1.626 +        if (script->funHasExtensibleScope())
   1.627 +            scriptBits |= (1 << FunHasExtensibleScope);
   1.628 +        if (script->funNeedsDeclEnvObject())
   1.629 +            scriptBits |= (1 << FunNeedsDeclEnvObject);
   1.630 +        if (script->funHasAnyAliasedFormal())
   1.631 +            scriptBits |= (1 << FunHasAnyAliasedFormal);
   1.632 +        if (script->argumentsHasVarBinding())
   1.633 +            scriptBits |= (1 << ArgumentsHasVarBinding);
   1.634 +        if (script->analyzedArgsUsage() && script->needsArgsObj())
   1.635 +            scriptBits |= (1 << NeedsArgsObj);
   1.636 +        if (!enclosingScript || enclosingScript->scriptSource() != script->scriptSource())
   1.637 +            scriptBits |= (1 << OwnSource);
   1.638 +        if (script->isGeneratorExp())
   1.639 +            scriptBits |= (1 << IsGeneratorExp);
   1.640 +        if (script->isLegacyGenerator())
   1.641 +            scriptBits |= (1 << IsLegacyGenerator);
   1.642 +        if (script->isStarGenerator())
   1.643 +            scriptBits |= (1 << IsStarGenerator);
   1.644 +        if (script->compileAndGo())
   1.645 +            scriptBits |= (1 << IsCompileAndGo);
   1.646 +        if (script->hasSingletons())
   1.647 +            scriptBits |= (1 << HasSingleton);
   1.648 +        if (script->treatAsRunOnce())
   1.649 +            scriptBits |= (1 << TreatAsRunOnce);
   1.650 +        if (script->isRelazifiable())
   1.651 +            scriptBits |= (1 << HasLazyScript);
   1.652 +    }
   1.653 +
   1.654 +    if (!xdr->codeUint32(&prologLength))
   1.655 +        return false;
   1.656 +    if (!xdr->codeUint32(&version))
   1.657 +        return false;
   1.658 +
   1.659 +    // To fuse allocations, we need lengths of all embedded arrays early.
   1.660 +    if (!xdr->codeUint32(&natoms))
   1.661 +        return false;
   1.662 +    if (!xdr->codeUint32(&nsrcnotes))
   1.663 +        return false;
   1.664 +    if (!xdr->codeUint32(&nconsts))
   1.665 +        return false;
   1.666 +    if (!xdr->codeUint32(&nobjects))
   1.667 +        return false;
   1.668 +    if (!xdr->codeUint32(&nregexps))
   1.669 +        return false;
   1.670 +    if (!xdr->codeUint32(&ntrynotes))
   1.671 +        return false;
   1.672 +    if (!xdr->codeUint32(&nblockscopes))
   1.673 +        return false;
   1.674 +    if (!xdr->codeUint32(&nTypeSets))
   1.675 +        return false;
   1.676 +    if (!xdr->codeUint32(&funLength))
   1.677 +        return false;
   1.678 +    if (!xdr->codeUint32(&scriptBits))
   1.679 +        return false;
   1.680 +
   1.681 +    if (mode == XDR_DECODE) {
   1.682 +        JSVersion version_ = JSVersion(version);
   1.683 +        JS_ASSERT((version_ & VersionFlags::MASK) == unsigned(version_));
   1.684 +
   1.685 +        // staticLevel is set below.
   1.686 +        CompileOptions options(cx);
   1.687 +        options.setVersion(version_)
   1.688 +               .setNoScriptRval(!!(scriptBits & (1 << NoScriptRval)))
   1.689 +               .setSelfHostingMode(!!(scriptBits & (1 << SelfHosted)));
   1.690 +        RootedScriptSource sourceObject(cx);
   1.691 +        if (scriptBits & (1 << OwnSource)) {
   1.692 +            ScriptSource *ss = cx->new_<ScriptSource>();
   1.693 +            if (!ss)
   1.694 +                return false;
   1.695 +            ScriptSourceHolder ssHolder(ss);
   1.696 +
   1.697 +            /*
   1.698 +             * We use this CompileOptions only to initialize the
   1.699 +             * ScriptSourceObject. Most CompileOptions fields aren't used by
   1.700 +             * ScriptSourceObject, and those that are (element; elementAttributeName)
   1.701 +             * aren't preserved by XDR. So this can be simple.
   1.702 +             */
   1.703 +            CompileOptions options(cx);
   1.704 +            options.setOriginPrincipals(xdr->originPrincipals());
   1.705 +            ss->initFromOptions(cx, options);
   1.706 +            sourceObject = ScriptSourceObject::create(cx, ss, options);
   1.707 +            if (!sourceObject)
   1.708 +                return false;
   1.709 +        } else {
   1.710 +            JS_ASSERT(enclosingScript);
   1.711 +            // When decoding, all the scripts and the script source object
   1.712 +            // are in the same compartment, so the script's source object
   1.713 +            // should never be a cross-compartment wrapper.
   1.714 +            JS_ASSERT(enclosingScript->sourceObject()->is<ScriptSourceObject>());
   1.715 +            sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>();
   1.716 +        }
   1.717 +        script = JSScript::Create(cx, enclosingScope, !!(scriptBits & (1 << SavedCallerFun)),
   1.718 +                                  options, /* staticLevel = */ 0, sourceObject, 0, 0);
   1.719 +        if (!script)
   1.720 +            return false;
   1.721 +    }
   1.722 +
   1.723 +    /* JSScript::partiallyInit assumes script->bindings is fully initialized. */
   1.724 +    LifoAllocScope las(&cx->tempLifoAlloc());
   1.725 +    if (!XDRScriptBindings(xdr, las, nargs, nvars, script, nblocklocals))
   1.726 +        return false;
   1.727 +
   1.728 +    if (mode == XDR_DECODE) {
   1.729 +        if (!JSScript::partiallyInit(cx, script, nconsts, nobjects, nregexps, ntrynotes,
   1.730 +                                     nblockscopes, nTypeSets))
   1.731 +        {
   1.732 +            return false;
   1.733 +        }
   1.734 +
   1.735 +        JS_ASSERT(!script->mainOffset());
   1.736 +        script->mainOffset_ = prologLength;
   1.737 +        script->setLength(length);
   1.738 +        script->funLength_ = funLength;
   1.739 +
   1.740 +        scriptp.set(script);
   1.741 +
   1.742 +        if (scriptBits & (1 << Strict))
   1.743 +            script->strict_ = true;
   1.744 +        if (scriptBits & (1 << ExplicitUseStrict))
   1.745 +            script->explicitUseStrict_ = true;
   1.746 +        if (scriptBits & (1 << ContainsDynamicNameAccess))
   1.747 +            script->bindingsAccessedDynamically_ = true;
   1.748 +        if (scriptBits & (1 << FunHasExtensibleScope))
   1.749 +            script->funHasExtensibleScope_ = true;
   1.750 +        if (scriptBits & (1 << FunNeedsDeclEnvObject))
   1.751 +            script->funNeedsDeclEnvObject_ = true;
   1.752 +        if (scriptBits & (1 << FunHasAnyAliasedFormal))
   1.753 +            script->funHasAnyAliasedFormal_ = true;
   1.754 +        if (scriptBits & (1 << ArgumentsHasVarBinding))
   1.755 +            script->setArgumentsHasVarBinding();
   1.756 +        if (scriptBits & (1 << NeedsArgsObj))
   1.757 +            script->setNeedsArgsObj(true);
   1.758 +        if (scriptBits & (1 << IsGeneratorExp))
   1.759 +            script->isGeneratorExp_ = true;
   1.760 +        if (scriptBits & (1 << IsCompileAndGo))
   1.761 +            script->compileAndGo_ = true;
   1.762 +        if (scriptBits & (1 << HasSingleton))
   1.763 +            script->hasSingletons_ = true;
   1.764 +        if (scriptBits & (1 << TreatAsRunOnce))
   1.765 +            script->treatAsRunOnce_ = true;
   1.766 +
   1.767 +        if (scriptBits & (1 << IsLegacyGenerator)) {
   1.768 +            JS_ASSERT(!(scriptBits & (1 << IsStarGenerator)));
   1.769 +            script->setGeneratorKind(LegacyGenerator);
   1.770 +        } else if (scriptBits & (1 << IsStarGenerator))
   1.771 +            script->setGeneratorKind(StarGenerator);
   1.772 +    }
   1.773 +
   1.774 +    JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
   1.775 +    JS_STATIC_ASSERT(sizeof(jssrcnote) == 1);
   1.776 +
   1.777 +    if (scriptBits & (1 << OwnSource)) {
   1.778 +        if (!script->scriptSource()->performXDR<mode>(xdr))
   1.779 +            return false;
   1.780 +    }
   1.781 +    if (!xdr->codeUint32(&script->sourceStart_))
   1.782 +        return false;
   1.783 +    if (!xdr->codeUint32(&script->sourceEnd_))
   1.784 +        return false;
   1.785 +
   1.786 +    if (!xdr->codeUint32(&lineno) ||
   1.787 +        !xdr->codeUint32(&column) ||
   1.788 +        !xdr->codeUint32(&nslots) ||
   1.789 +        !xdr->codeUint32(&staticLevel))
   1.790 +    {
   1.791 +        return false;
   1.792 +    }
   1.793 +
   1.794 +    if (mode == XDR_DECODE) {
   1.795 +        script->lineno_ = lineno;
   1.796 +        script->column_ = column;
   1.797 +        script->nslots_ = nslots;
   1.798 +        script->staticLevel_ = staticLevel;
   1.799 +    }
   1.800 +
   1.801 +    jsbytecode *code = script->code();
   1.802 +    SharedScriptData *ssd;
   1.803 +    if (mode == XDR_DECODE) {
   1.804 +        ssd = SharedScriptData::new_(cx, length, nsrcnotes, natoms);
   1.805 +        if (!ssd)
   1.806 +            return false;
   1.807 +        code = ssd->data;
   1.808 +        if (natoms != 0) {
   1.809 +            script->natoms_ = natoms;
   1.810 +            script->atoms = ssd->atoms();
   1.811 +        }
   1.812 +    }
   1.813 +
   1.814 +    if (!xdr->codeBytes(code, length) || !xdr->codeBytes(code + length, nsrcnotes)) {
   1.815 +        if (mode == XDR_DECODE)
   1.816 +            js_free(ssd);
   1.817 +        return false;
   1.818 +    }
   1.819 +
   1.820 +    for (i = 0; i != natoms; ++i) {
   1.821 +        if (mode == XDR_DECODE) {
   1.822 +            RootedAtom tmp(cx);
   1.823 +            if (!XDRAtom(xdr, &tmp))
   1.824 +                return false;
   1.825 +            script->atoms[i].init(tmp);
   1.826 +        } else {
   1.827 +            RootedAtom tmp(cx, script->atoms[i]);
   1.828 +            if (!XDRAtom(xdr, &tmp))
   1.829 +                return false;
   1.830 +        }
   1.831 +    }
   1.832 +
   1.833 +    if (mode == XDR_DECODE) {
   1.834 +        if (!SaveSharedScriptData(cx, script, ssd, nsrcnotes))
   1.835 +            return false;
   1.836 +    }
   1.837 +
   1.838 +    if (nconsts) {
   1.839 +        HeapValue *vector = script->consts()->vector;
   1.840 +        RootedValue val(cx);
   1.841 +        for (i = 0; i != nconsts; ++i) {
   1.842 +            if (mode == XDR_ENCODE)
   1.843 +                val = vector[i];
   1.844 +            if (!XDRScriptConst(xdr, &val))
   1.845 +                return false;
   1.846 +            if (mode == XDR_DECODE)
   1.847 +                vector[i].init(val);
   1.848 +        }
   1.849 +    }
   1.850 +
   1.851 +    /*
   1.852 +     * Here looping from 0-to-length to xdr objects is essential to ensure that
   1.853 +     * all references to enclosing blocks (via FindScopeObjectIndex below) happen
   1.854 +     * after the enclosing block has been XDR'd.
   1.855 +     */
   1.856 +    for (i = 0; i != nobjects; ++i) {
   1.857 +        HeapPtr<JSObject> *objp = &script->objects()->vector[i];
   1.858 +        XDRClassKind classk;
   1.859 +
   1.860 +        if (mode == XDR_ENCODE) {
   1.861 +            JSObject *obj = *objp;
   1.862 +            if (obj->is<BlockObject>())
   1.863 +                classk = CK_BlockObject;
   1.864 +            else if (obj->is<StaticWithObject>())
   1.865 +                classk = CK_WithObject;
   1.866 +            else if (obj->is<JSFunction>())
   1.867 +                classk = CK_JSFunction;
   1.868 +            else if (obj->is<JSObject>() || obj->is<ArrayObject>())
   1.869 +                classk = CK_JSObject;
   1.870 +            else
   1.871 +                MOZ_ASSUME_UNREACHABLE("Cannot encode this class of object.");
   1.872 +        }
   1.873 +
   1.874 +        if (!xdr->codeEnum32(&classk))
   1.875 +            return false;
   1.876 +
   1.877 +        switch (classk) {
   1.878 +          case CK_BlockObject:
   1.879 +          case CK_WithObject: {
   1.880 +            /* Code the nested block's enclosing scope. */
   1.881 +            uint32_t enclosingStaticScopeIndex = 0;
   1.882 +            if (mode == XDR_ENCODE) {
   1.883 +                NestedScopeObject &scope = (*objp)->as<NestedScopeObject>();
   1.884 +                if (NestedScopeObject *enclosing = scope.enclosingNestedScope())
   1.885 +                    enclosingStaticScopeIndex = FindScopeObjectIndex(script, *enclosing);
   1.886 +                else
   1.887 +                    enclosingStaticScopeIndex = UINT32_MAX;
   1.888 +            }
   1.889 +            if (!xdr->codeUint32(&enclosingStaticScopeIndex))
   1.890 +                return false;
   1.891 +            Rooted<JSObject*> enclosingStaticScope(cx);
   1.892 +            if (mode == XDR_DECODE) {
   1.893 +                if (enclosingStaticScopeIndex != UINT32_MAX) {
   1.894 +                    JS_ASSERT(enclosingStaticScopeIndex < i);
   1.895 +                    enclosingStaticScope = script->objects()->vector[enclosingStaticScopeIndex];
   1.896 +                } else {
   1.897 +                    enclosingStaticScope = fun;
   1.898 +                }
   1.899 +            }
   1.900 +
   1.901 +            if (classk == CK_BlockObject) {
   1.902 +                Rooted<StaticBlockObject*> tmp(cx, static_cast<StaticBlockObject *>(objp->get()));
   1.903 +                if (!XDRStaticBlockObject(xdr, enclosingStaticScope, tmp.address()))
   1.904 +                    return false;
   1.905 +                *objp = tmp;
   1.906 +            } else {
   1.907 +                Rooted<StaticWithObject*> tmp(cx, static_cast<StaticWithObject *>(objp->get()));
   1.908 +                if (!XDRStaticWithObject(xdr, enclosingStaticScope, tmp.address()))
   1.909 +                    return false;
   1.910 +                *objp = tmp;
   1.911 +            }
   1.912 +            break;
   1.913 +          }
   1.914 +
   1.915 +          case CK_JSFunction: {
   1.916 +            /* Code the nested function's enclosing scope. */
   1.917 +            uint32_t funEnclosingScopeIndex = 0;
   1.918 +            RootedObject funEnclosingScope(cx);
   1.919 +            if (mode == XDR_ENCODE) {
   1.920 +                RootedFunction function(cx, &(*objp)->as<JSFunction>());
   1.921 +
   1.922 +                if (function->isInterpretedLazy())
   1.923 +                    funEnclosingScope = function->lazyScript()->enclosingScope();
   1.924 +                else
   1.925 +                    funEnclosingScope = function->nonLazyScript()->enclosingStaticScope();
   1.926 +
   1.927 +                StaticScopeIter<NoGC> ssi(funEnclosingScope);
   1.928 +                if (ssi.done() || ssi.type() == StaticScopeIter<NoGC>::FUNCTION) {
   1.929 +                    JS_ASSERT(ssi.done() == !fun);
   1.930 +                    funEnclosingScopeIndex = UINT32_MAX;
   1.931 +                } else if (ssi.type() == StaticScopeIter<NoGC>::BLOCK) {
   1.932 +                    funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block());
   1.933 +                    JS_ASSERT(funEnclosingScopeIndex < i);
   1.934 +                } else {
   1.935 +                    funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.staticWith());
   1.936 +                    JS_ASSERT(funEnclosingScopeIndex < i);
   1.937 +                }
   1.938 +            }
   1.939 +
   1.940 +            if (!xdr->codeUint32(&funEnclosingScopeIndex))
   1.941 +                return false;
   1.942 +
   1.943 +            if (mode == XDR_DECODE) {
   1.944 +                if (funEnclosingScopeIndex == UINT32_MAX) {
   1.945 +                    funEnclosingScope = fun;
   1.946 +                } else {
   1.947 +                    JS_ASSERT(funEnclosingScopeIndex < i);
   1.948 +                    funEnclosingScope = script->objects()->vector[funEnclosingScopeIndex];
   1.949 +                }
   1.950 +            }
   1.951 +
   1.952 +            // Code nested function and script.
   1.953 +            RootedObject tmp(cx, *objp);
   1.954 +            if (!XDRInterpretedFunction(xdr, funEnclosingScope, script, &tmp))
   1.955 +                return false;
   1.956 +            *objp = tmp;
   1.957 +            break;
   1.958 +          }
   1.959 +
   1.960 +          case CK_JSObject: {
   1.961 +            /* Code object literal. */
   1.962 +            RootedObject tmp(cx, *objp);
   1.963 +            if (!XDRObjectLiteral(xdr, &tmp))
   1.964 +                return false;
   1.965 +            *objp = tmp;
   1.966 +            break;
   1.967 +          }
   1.968 +
   1.969 +          default: {
   1.970 +            MOZ_ASSERT(false, "Unknown class kind.");
   1.971 +            return false;
   1.972 +          }
   1.973 +        }
   1.974 +    }
   1.975 +
   1.976 +    for (i = 0; i != nregexps; ++i) {
   1.977 +        if (!XDRScriptRegExpObject(xdr, &script->regexps()->vector[i]))
   1.978 +            return false;
   1.979 +    }
   1.980 +
   1.981 +    if (ntrynotes != 0) {
   1.982 +        JSTryNote *tnfirst = script->trynotes()->vector;
   1.983 +        JS_ASSERT(script->trynotes()->length == ntrynotes);
   1.984 +        JSTryNote *tn = tnfirst + ntrynotes;
   1.985 +        do {
   1.986 +            --tn;
   1.987 +            if (!xdr->codeUint8(&tn->kind) ||
   1.988 +                !xdr->codeUint32(&tn->stackDepth) ||
   1.989 +                !xdr->codeUint32(&tn->start) ||
   1.990 +                !xdr->codeUint32(&tn->length)) {
   1.991 +                return false;
   1.992 +            }
   1.993 +        } while (tn != tnfirst);
   1.994 +    }
   1.995 +
   1.996 +    for (i = 0; i < nblockscopes; ++i) {
   1.997 +        BlockScopeNote *note = &script->blockScopes()->vector[i];
   1.998 +        if (!xdr->codeUint32(&note->index) ||
   1.999 +            !xdr->codeUint32(&note->start) ||
  1.1000 +            !xdr->codeUint32(&note->length) ||
  1.1001 +            !xdr->codeUint32(&note->parent))
  1.1002 +        {
  1.1003 +            return false;
  1.1004 +        }
  1.1005 +    }
  1.1006 +
  1.1007 +    if (scriptBits & (1 << HasLazyScript)) {
  1.1008 +        Rooted<LazyScript *> lazy(cx);
  1.1009 +        if (mode == XDR_ENCODE)
  1.1010 +            lazy = script->maybeLazyScript();
  1.1011 +
  1.1012 +        if (!XDRRelazificationInfo(xdr, fun, script, &lazy))
  1.1013 +            return false;
  1.1014 +
  1.1015 +        if (mode == XDR_DECODE)
  1.1016 +            script->setLazyScript(lazy);
  1.1017 +    }
  1.1018 +
  1.1019 +    if (mode == XDR_DECODE) {
  1.1020 +        scriptp.set(script);
  1.1021 +
  1.1022 +        /* see BytecodeEmitter::tellDebuggerAboutCompiledScript */
  1.1023 +        CallNewScriptHook(cx, script, fun);
  1.1024 +        if (!fun) {
  1.1025 +            RootedGlobalObject global(cx, script->compileAndGo() ? &script->global() : nullptr);
  1.1026 +            Debugger::onNewScript(cx, script, global);
  1.1027 +        }
  1.1028 +    }
  1.1029 +
  1.1030 +    return true;
  1.1031 +}
  1.1032 +
  1.1033 +template bool
  1.1034 +js::XDRScript(XDRState<XDR_ENCODE> *, HandleObject, HandleScript, HandleFunction,
  1.1035 +              MutableHandleScript);
  1.1036 +
  1.1037 +template bool
  1.1038 +js::XDRScript(XDRState<XDR_DECODE> *, HandleObject, HandleScript, HandleFunction,
  1.1039 +              MutableHandleScript);
  1.1040 +
  1.1041 +template<XDRMode mode>
  1.1042 +bool
  1.1043 +js::XDRLazyScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
  1.1044 +                  HandleFunction fun, MutableHandle<LazyScript *> lazy)
  1.1045 +{
  1.1046 +    JSContext *cx = xdr->cx();
  1.1047 +
  1.1048 +    {
  1.1049 +        uint32_t begin;
  1.1050 +        uint32_t end;
  1.1051 +        uint32_t lineno;
  1.1052 +        uint32_t column;
  1.1053 +        uint64_t packedFields;
  1.1054 +
  1.1055 +        if (mode == XDR_ENCODE) {
  1.1056 +            MOZ_ASSERT(!lazy->maybeScript());
  1.1057 +            MOZ_ASSERT(fun == lazy->functionNonDelazifying());
  1.1058 +
  1.1059 +            begin = lazy->begin();
  1.1060 +            end = lazy->end();
  1.1061 +            lineno = lazy->lineno();
  1.1062 +            column = lazy->column();
  1.1063 +            packedFields = lazy->packedFields();
  1.1064 +        }
  1.1065 +
  1.1066 +        if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
  1.1067 +            !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
  1.1068 +            !xdr->codeUint64(&packedFields))
  1.1069 +        {
  1.1070 +            return false;
  1.1071 +        }
  1.1072 +
  1.1073 +        if (mode == XDR_DECODE)
  1.1074 +            lazy.set(LazyScript::Create(cx, fun, packedFields, begin, end, lineno, column));
  1.1075 +    }
  1.1076 +
  1.1077 +    // Code free variables.
  1.1078 +    if (!XDRLazyFreeVariables(xdr, lazy))
  1.1079 +        return false;
  1.1080 +
  1.1081 +    // Code inner functions.
  1.1082 +    {
  1.1083 +        RootedObject func(cx);
  1.1084 +        HeapPtrFunction *innerFunctions = lazy->innerFunctions();
  1.1085 +        size_t numInnerFunctions = lazy->numInnerFunctions();
  1.1086 +        for (size_t i = 0; i < numInnerFunctions; i++) {
  1.1087 +            if (mode == XDR_ENCODE)
  1.1088 +                func = innerFunctions[i];
  1.1089 +
  1.1090 +            if (!XDRInterpretedFunction(xdr, fun, enclosingScript, &func))
  1.1091 +                return false;
  1.1092 +
  1.1093 +            if (mode == XDR_DECODE)
  1.1094 +                innerFunctions[i] = &func->as<JSFunction>();
  1.1095 +        }
  1.1096 +    }
  1.1097 +
  1.1098 +    if (mode == XDR_DECODE) {
  1.1099 +        JS_ASSERT(!lazy->sourceObject());
  1.1100 +        ScriptSourceObject *sourceObject = &enclosingScript->scriptSourceUnwrap();
  1.1101 +
  1.1102 +        // Set the enclosing scope of the lazy function, this would later be
  1.1103 +        // used to define the environment when the function would be used.
  1.1104 +        lazy->setParent(enclosingScope, sourceObject);
  1.1105 +    }
  1.1106 +
  1.1107 +    return true;
  1.1108 +}
  1.1109 +
  1.1110 +template bool
  1.1111 +js::XDRLazyScript(XDRState<XDR_ENCODE> *, HandleObject, HandleScript,
  1.1112 +                  HandleFunction, MutableHandle<LazyScript *>);
  1.1113 +
  1.1114 +template bool
  1.1115 +js::XDRLazyScript(XDRState<XDR_DECODE> *, HandleObject, HandleScript,
  1.1116 +                  HandleFunction, MutableHandle<LazyScript *>);
  1.1117 +
  1.1118 +void
  1.1119 +JSScript::setSourceObject(JSObject *object)
  1.1120 +{
  1.1121 +    JS_ASSERT(compartment() == object->compartment());
  1.1122 +    sourceObject_ = object;
  1.1123 +}
  1.1124 +
  1.1125 +js::ScriptSourceObject &
  1.1126 +JSScript::scriptSourceUnwrap() const {
  1.1127 +    return UncheckedUnwrap(sourceObject())->as<ScriptSourceObject>();
  1.1128 +}
  1.1129 +
  1.1130 +js::ScriptSource *
  1.1131 +JSScript::scriptSource() const {
  1.1132 +    return scriptSourceUnwrap().source();
  1.1133 +}
  1.1134 +
  1.1135 +bool
  1.1136 +JSScript::initScriptCounts(JSContext *cx)
  1.1137 +{
  1.1138 +    JS_ASSERT(!hasScriptCounts());
  1.1139 +
  1.1140 +    size_t n = 0;
  1.1141 +
  1.1142 +    for (jsbytecode *pc = code(); pc < codeEnd(); pc += GetBytecodeLength(pc))
  1.1143 +        n += PCCounts::numCounts(JSOp(*pc));
  1.1144 +
  1.1145 +    size_t bytes = (length() * sizeof(PCCounts)) + (n * sizeof(double));
  1.1146 +    char *base = (char *) cx->calloc_(bytes);
  1.1147 +    if (!base)
  1.1148 +        return false;
  1.1149 +
  1.1150 +    /* Create compartment's scriptCountsMap if necessary. */
  1.1151 +    ScriptCountsMap *map = compartment()->scriptCountsMap;
  1.1152 +    if (!map) {
  1.1153 +        map = cx->new_<ScriptCountsMap>();
  1.1154 +        if (!map || !map->init()) {
  1.1155 +            js_free(base);
  1.1156 +            js_delete(map);
  1.1157 +            return false;
  1.1158 +        }
  1.1159 +        compartment()->scriptCountsMap = map;
  1.1160 +    }
  1.1161 +
  1.1162 +    char *cursor = base;
  1.1163 +
  1.1164 +    ScriptCounts scriptCounts;
  1.1165 +    scriptCounts.pcCountsVector = (PCCounts *) cursor;
  1.1166 +    cursor += length() * sizeof(PCCounts);
  1.1167 +
  1.1168 +    for (jsbytecode *pc = code(); pc < codeEnd(); pc += GetBytecodeLength(pc)) {
  1.1169 +        JS_ASSERT(uintptr_t(cursor) % sizeof(double) == 0);
  1.1170 +        scriptCounts.pcCountsVector[pcToOffset(pc)].counts = (double *) cursor;
  1.1171 +        size_t capacity = PCCounts::numCounts(JSOp(*pc));
  1.1172 +#ifdef DEBUG
  1.1173 +        scriptCounts.pcCountsVector[pcToOffset(pc)].capacity = capacity;
  1.1174 +#endif
  1.1175 +        cursor += capacity * sizeof(double);
  1.1176 +    }
  1.1177 +
  1.1178 +    if (!map->putNew(this, scriptCounts)) {
  1.1179 +        js_free(base);
  1.1180 +        return false;
  1.1181 +    }
  1.1182 +    hasScriptCounts_ = true; // safe to set this;  we can't fail after this point
  1.1183 +
  1.1184 +    JS_ASSERT(size_t(cursor - base) == bytes);
  1.1185 +
  1.1186 +    /* Enable interrupts in any interpreter frames running on this script. */
  1.1187 +    for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
  1.1188 +        if (iter->isInterpreter())
  1.1189 +            iter->asInterpreter()->enableInterruptsIfRunning(this);
  1.1190 +    }
  1.1191 +
  1.1192 +    return true;
  1.1193 +}
  1.1194 +
  1.1195 +static inline ScriptCountsMap::Ptr GetScriptCountsMapEntry(JSScript *script)
  1.1196 +{
  1.1197 +    JS_ASSERT(script->hasScriptCounts());
  1.1198 +    ScriptCountsMap *map = script->compartment()->scriptCountsMap;
  1.1199 +    ScriptCountsMap::Ptr p = map->lookup(script);
  1.1200 +    JS_ASSERT(p);
  1.1201 +    return p;
  1.1202 +}
  1.1203 +
  1.1204 +js::PCCounts
  1.1205 +JSScript::getPCCounts(jsbytecode *pc) {
  1.1206 +    JS_ASSERT(containsPC(pc));
  1.1207 +    ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
  1.1208 +    return p->value().pcCountsVector[pcToOffset(pc)];
  1.1209 +}
  1.1210 +
  1.1211 +void
  1.1212 +JSScript::addIonCounts(jit::IonScriptCounts *ionCounts)
  1.1213 +{
  1.1214 +    ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
  1.1215 +    if (p->value().ionCounts)
  1.1216 +        ionCounts->setPrevious(p->value().ionCounts);
  1.1217 +    p->value().ionCounts = ionCounts;
  1.1218 +}
  1.1219 +
  1.1220 +jit::IonScriptCounts *
  1.1221 +JSScript::getIonCounts()
  1.1222 +{
  1.1223 +    ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
  1.1224 +    return p->value().ionCounts;
  1.1225 +}
  1.1226 +
  1.1227 +ScriptCounts
  1.1228 +JSScript::releaseScriptCounts()
  1.1229 +{
  1.1230 +    ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
  1.1231 +    ScriptCounts counts = p->value();
  1.1232 +    compartment()->scriptCountsMap->remove(p);
  1.1233 +    hasScriptCounts_ = false;
  1.1234 +    return counts;
  1.1235 +}
  1.1236 +
  1.1237 +void
  1.1238 +JSScript::destroyScriptCounts(FreeOp *fop)
  1.1239 +{
  1.1240 +    if (hasScriptCounts()) {
  1.1241 +        ScriptCounts scriptCounts = releaseScriptCounts();
  1.1242 +        scriptCounts.destroy(fop);
  1.1243 +    }
  1.1244 +}
  1.1245 +
  1.1246 +void
  1.1247 +ScriptSourceObject::setSource(ScriptSource *source)
  1.1248 +{
  1.1249 +    if (source)
  1.1250 +        source->incref();
  1.1251 +    if (this->source())
  1.1252 +        this->source()->decref();
  1.1253 +    setReservedSlot(SOURCE_SLOT, PrivateValue(source));
  1.1254 +}
  1.1255 +
  1.1256 +JSObject *
  1.1257 +ScriptSourceObject::element() const
  1.1258 +{
  1.1259 +    return getReservedSlot(ELEMENT_SLOT).toObjectOrNull();
  1.1260 +}
  1.1261 +
  1.1262 +void
  1.1263 +ScriptSourceObject::initElement(HandleObject element)
  1.1264 +{
  1.1265 +    JS_ASSERT(getReservedSlot(ELEMENT_SLOT).isNull());
  1.1266 +    setReservedSlot(ELEMENT_SLOT, ObjectOrNullValue(element));
  1.1267 +}
  1.1268 +
  1.1269 +const Value &
  1.1270 +ScriptSourceObject::elementAttributeName() const
  1.1271 +{
  1.1272 +    const Value &prop = getReservedSlot(ELEMENT_PROPERTY_SLOT);
  1.1273 +    JS_ASSERT(prop.isUndefined() || prop.isString());
  1.1274 +    return prop;
  1.1275 +}
  1.1276 +
  1.1277 +void
  1.1278 +ScriptSourceObject::initIntroductionScript(JSScript *script)
  1.1279 +{
  1.1280 +    JS_ASSERT(!getReservedSlot(INTRODUCTION_SCRIPT_SLOT).toPrivate());
  1.1281 +
  1.1282 +    // There is no equivalent of cross-compartment wrappers for scripts. If
  1.1283 +    // the introduction script would be in a different compartment from the
  1.1284 +    // compiled code, we would be creating a cross-compartment script
  1.1285 +    // reference, which would be bogus. In that case, just don't bother to
  1.1286 +    // retain the introduction script.
  1.1287 +    if (script && script->compartment() == compartment())
  1.1288 +        setReservedSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(script));
  1.1289 +}
  1.1290 +
  1.1291 +void
  1.1292 +ScriptSourceObject::trace(JSTracer *trc, JSObject *obj)
  1.1293 +{
  1.1294 +    ScriptSourceObject *sso = static_cast<ScriptSourceObject *>(obj);
  1.1295 +
  1.1296 +    if (JSScript *script = sso->introductionScript()) {
  1.1297 +        MarkScriptUnbarriered(trc, &script, "ScriptSourceObject introductionScript");
  1.1298 +        sso->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(script));
  1.1299 +    }
  1.1300 +}
  1.1301 +
  1.1302 +void
  1.1303 +ScriptSourceObject::finalize(FreeOp *fop, JSObject *obj)
  1.1304 +{
  1.1305 +    // ScriptSource::setSource automatically takes care of the refcount
  1.1306 +    obj->as<ScriptSourceObject>().setSource(nullptr);
  1.1307 +}
  1.1308 +
  1.1309 +const Class ScriptSourceObject::class_ = {
  1.1310 +    "ScriptSource",
  1.1311 +    JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
  1.1312 +    JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_IS_ANONYMOUS,
  1.1313 +    JS_PropertyStub,        /* addProperty */
  1.1314 +    JS_DeletePropertyStub,  /* delProperty */
  1.1315 +    JS_PropertyStub,        /* getProperty */
  1.1316 +    JS_StrictPropertyStub,  /* setProperty */
  1.1317 +    JS_EnumerateStub,
  1.1318 +    JS_ResolveStub,
  1.1319 +    JS_ConvertStub,
  1.1320 +    finalize,
  1.1321 +    nullptr,                /* call        */
  1.1322 +    nullptr,                /* hasInstance */
  1.1323 +    nullptr,                /* construct   */
  1.1324 +    trace
  1.1325 +};
  1.1326 +
  1.1327 +ScriptSourceObject *
  1.1328 +ScriptSourceObject::create(ExclusiveContext *cx, ScriptSource *source,
  1.1329 +                           const ReadOnlyCompileOptions &options)
  1.1330 +{
  1.1331 +    RootedObject object(cx, NewObjectWithGivenProto(cx, &class_, nullptr, cx->global()));
  1.1332 +    if (!object)
  1.1333 +        return nullptr;
  1.1334 +    RootedScriptSource sourceObject(cx, &object->as<ScriptSourceObject>());
  1.1335 +
  1.1336 +    source->incref();
  1.1337 +    sourceObject->initSlot(SOURCE_SLOT, PrivateValue(source));
  1.1338 +    sourceObject->initSlot(ELEMENT_SLOT, ObjectOrNullValue(options.element()));
  1.1339 +    if (options.elementAttributeName())
  1.1340 +        sourceObject->initSlot(ELEMENT_PROPERTY_SLOT, StringValue(options.elementAttributeName()));
  1.1341 +    else
  1.1342 +        sourceObject->initSlot(ELEMENT_PROPERTY_SLOT, UndefinedValue());
  1.1343 +
  1.1344 +    sourceObject->initSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(nullptr));
  1.1345 +    sourceObject->initIntroductionScript(options.introductionScript());
  1.1346 +
  1.1347 +    return sourceObject;
  1.1348 +}
  1.1349 +
  1.1350 +static const unsigned char emptySource[] = "";
  1.1351 +
  1.1352 +/* Adjust the amount of memory this script source uses for source data,
  1.1353 +   reallocating if needed. */
  1.1354 +bool
  1.1355 +ScriptSource::adjustDataSize(size_t nbytes)
  1.1356 +{
  1.1357 +    // Allocating 0 bytes has undefined behavior, so special-case it.
  1.1358 +    if (nbytes == 0) {
  1.1359 +        if (data.compressed != emptySource)
  1.1360 +            js_free(data.compressed);
  1.1361 +        data.compressed = const_cast<unsigned char *>(emptySource);
  1.1362 +        return true;
  1.1363 +    }
  1.1364 +
  1.1365 +    // |data.compressed| can be nullptr.
  1.1366 +    void *buf = js_realloc(data.compressed, nbytes);
  1.1367 +    if (!buf && data.compressed != emptySource)
  1.1368 +        js_free(data.compressed);
  1.1369 +    data.compressed = static_cast<unsigned char *>(buf);
  1.1370 +    return !!data.compressed;
  1.1371 +}
  1.1372 +
  1.1373 +/* static */ bool
  1.1374 +JSScript::loadSource(JSContext *cx, ScriptSource *ss, bool *worked)
  1.1375 +{
  1.1376 +    JS_ASSERT(!ss->hasSourceData());
  1.1377 +    *worked = false;
  1.1378 +    if (!cx->runtime()->sourceHook || !ss->sourceRetrievable())
  1.1379 +        return true;
  1.1380 +    jschar *src = nullptr;
  1.1381 +    size_t length;
  1.1382 +    if (!cx->runtime()->sourceHook->load(cx, ss->filename(), &src, &length))
  1.1383 +        return false;
  1.1384 +    if (!src)
  1.1385 +        return true;
  1.1386 +    ss->setSource(src, length);
  1.1387 +    *worked = true;
  1.1388 +    return true;
  1.1389 +}
  1.1390 +
  1.1391 +JSFlatString *
  1.1392 +JSScript::sourceData(JSContext *cx)
  1.1393 +{
  1.1394 +    JS_ASSERT(scriptSource()->hasSourceData());
  1.1395 +    return scriptSource()->substring(cx, sourceStart(), sourceEnd());
  1.1396 +}
  1.1397 +
  1.1398 +SourceDataCache::AutoHoldEntry::AutoHoldEntry()
  1.1399 +  : cache_(nullptr), source_(nullptr), charsToFree_(nullptr)
  1.1400 +{
  1.1401 +}
  1.1402 +
  1.1403 +void
  1.1404 +SourceDataCache::AutoHoldEntry::holdEntry(SourceDataCache *cache, ScriptSource *source)
  1.1405 +{
  1.1406 +    // Initialise the holder for a specific cache and script source. This will
  1.1407 +    // hold on to the cached source chars in the event that the cache is purged.
  1.1408 +    JS_ASSERT(!cache_ && !source_ && !charsToFree_);
  1.1409 +    cache_ = cache;
  1.1410 +    source_ = source;
  1.1411 +}
  1.1412 +
  1.1413 +void
  1.1414 +SourceDataCache::AutoHoldEntry::deferDelete(const jschar *chars)
  1.1415 +{
  1.1416 +    // Take ownership of source chars now the cache is being purged. Remove our
  1.1417 +    // reference to the ScriptSource which might soon be destroyed.
  1.1418 +    JS_ASSERT(cache_ && source_ && !charsToFree_);
  1.1419 +    cache_ = nullptr;
  1.1420 +    source_ = nullptr;
  1.1421 +    charsToFree_ = chars;
  1.1422 +}
  1.1423 +
  1.1424 +SourceDataCache::AutoHoldEntry::~AutoHoldEntry()
  1.1425 +{
  1.1426 +    // The holder is going out of scope. If it has taken ownership of cached
  1.1427 +    // chars then delete them, otherwise unregister ourself with the cache.
  1.1428 +    if (charsToFree_) {
  1.1429 +        JS_ASSERT(!cache_ && !source_);
  1.1430 +        js_free(const_cast<jschar *>(charsToFree_));
  1.1431 +    } else if (cache_) {
  1.1432 +        JS_ASSERT(source_);
  1.1433 +        cache_->releaseEntry(*this);
  1.1434 +    }
  1.1435 +}
  1.1436 +
  1.1437 +void
  1.1438 +SourceDataCache::holdEntry(AutoHoldEntry &holder, ScriptSource *ss)
  1.1439 +{
  1.1440 +    JS_ASSERT(!holder_);
  1.1441 +    holder.holdEntry(this, ss);
  1.1442 +    holder_ = &holder;
  1.1443 +}
  1.1444 +
  1.1445 +void
  1.1446 +SourceDataCache::releaseEntry(AutoHoldEntry &holder)
  1.1447 +{
  1.1448 +    JS_ASSERT(holder_ == &holder);
  1.1449 +    holder_ = nullptr;
  1.1450 +}
  1.1451 +
  1.1452 +const jschar *
  1.1453 +SourceDataCache::lookup(ScriptSource *ss, AutoHoldEntry &holder)
  1.1454 +{
  1.1455 +    JS_ASSERT(!holder_);
  1.1456 +    if (!map_)
  1.1457 +        return nullptr;
  1.1458 +    if (Map::Ptr p = map_->lookup(ss)) {
  1.1459 +        holdEntry(holder, ss);
  1.1460 +        return p->value();
  1.1461 +    }
  1.1462 +    return nullptr;
  1.1463 +}
  1.1464 +
  1.1465 +bool
  1.1466 +SourceDataCache::put(ScriptSource *ss, const jschar *str, AutoHoldEntry &holder)
  1.1467 +{
  1.1468 +    JS_ASSERT(!holder_);
  1.1469 +
  1.1470 +    if (!map_) {
  1.1471 +        map_ = js_new<Map>();
  1.1472 +        if (!map_)
  1.1473 +            return false;
  1.1474 +
  1.1475 +        if (!map_->init()) {
  1.1476 +            js_delete(map_);
  1.1477 +            map_ = nullptr;
  1.1478 +            return false;
  1.1479 +        }
  1.1480 +    }
  1.1481 +
  1.1482 +    if (!map_->put(ss, str))
  1.1483 +        return false;
  1.1484 +
  1.1485 +    holdEntry(holder, ss);
  1.1486 +    return true;
  1.1487 +}
  1.1488 +
  1.1489 +void
  1.1490 +SourceDataCache::purge()
  1.1491 +{
  1.1492 +    if (!map_)
  1.1493 +        return;
  1.1494 +
  1.1495 +    for (Map::Range r = map_->all(); !r.empty(); r.popFront()) {
  1.1496 +        const jschar *chars = r.front().value();
  1.1497 +        if (holder_ && r.front().key() == holder_->source()) {
  1.1498 +            holder_->deferDelete(chars);
  1.1499 +            holder_ = nullptr;
  1.1500 +        } else {
  1.1501 +            js_free(const_cast<jschar*>(chars));
  1.1502 +        }
  1.1503 +    }
  1.1504 +
  1.1505 +    js_delete(map_);
  1.1506 +    map_ = nullptr;
  1.1507 +}
  1.1508 +
  1.1509 +size_t
  1.1510 +SourceDataCache::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
  1.1511 +{
  1.1512 +    size_t n = 0;
  1.1513 +    if (map_ && !map_->empty()) {
  1.1514 +        n += map_->sizeOfIncludingThis(mallocSizeOf);
  1.1515 +        for (Map::Range r = map_->all(); !r.empty(); r.popFront()) {
  1.1516 +            const jschar *v = r.front().value();
  1.1517 +            n += mallocSizeOf(v);
  1.1518 +        }
  1.1519 +    }
  1.1520 +    return n;
  1.1521 +}
  1.1522 +
  1.1523 +const jschar *
  1.1524 +ScriptSource::chars(JSContext *cx, SourceDataCache::AutoHoldEntry &holder)
  1.1525 +{
  1.1526 +    if (const jschar *chars = getOffThreadCompressionChars(cx))
  1.1527 +        return chars;
  1.1528 +    JS_ASSERT(ready());
  1.1529 +
  1.1530 +#ifdef USE_ZLIB
  1.1531 +    if (compressed()) {
  1.1532 +        if (const jschar *decompressed = cx->runtime()->sourceDataCache.lookup(this, holder))
  1.1533 +            return decompressed;
  1.1534 +
  1.1535 +        const size_t nbytes = sizeof(jschar) * (length_ + 1);
  1.1536 +        jschar *decompressed = static_cast<jschar *>(js_malloc(nbytes));
  1.1537 +        if (!decompressed)
  1.1538 +            return nullptr;
  1.1539 +
  1.1540 +        if (!DecompressString(data.compressed, compressedLength_,
  1.1541 +                              reinterpret_cast<unsigned char *>(decompressed), nbytes)) {
  1.1542 +            JS_ReportOutOfMemory(cx);
  1.1543 +            js_free(decompressed);
  1.1544 +            return nullptr;
  1.1545 +        }
  1.1546 +
  1.1547 +        decompressed[length_] = 0;
  1.1548 +
  1.1549 +        if (!cx->runtime()->sourceDataCache.put(this, decompressed, holder)) {
  1.1550 +            JS_ReportOutOfMemory(cx);
  1.1551 +            js_free(decompressed);
  1.1552 +            return nullptr;
  1.1553 +        }
  1.1554 +
  1.1555 +        return decompressed;
  1.1556 +    }
  1.1557 +#endif
  1.1558 +    return data.source;
  1.1559 +}
  1.1560 +
  1.1561 +JSFlatString *
  1.1562 +ScriptSource::substring(JSContext *cx, uint32_t start, uint32_t stop)
  1.1563 +{
  1.1564 +    JS_ASSERT(start <= stop);
  1.1565 +    SourceDataCache::AutoHoldEntry holder;
  1.1566 +    const jschar *chars = this->chars(cx, holder);
  1.1567 +    if (!chars)
  1.1568 +        return nullptr;
  1.1569 +    return js_NewStringCopyN<CanGC>(cx, chars + start, stop - start);
  1.1570 +}
  1.1571 +
  1.1572 +bool
  1.1573 +ScriptSource::setSourceCopy(ExclusiveContext *cx, SourceBufferHolder &srcBuf,
  1.1574 +                            bool argumentsNotIncluded, SourceCompressionTask *task)
  1.1575 +{
  1.1576 +    JS_ASSERT(!hasSourceData());
  1.1577 +    length_ = srcBuf.length();
  1.1578 +    argumentsNotIncluded_ = argumentsNotIncluded;
  1.1579 +
  1.1580 +    // There are several cases where source compression is not a good idea:
  1.1581 +    //  - If the script is tiny, then compression will save little or no space.
  1.1582 +    //  - If the script is enormous, then decompression can take seconds. With
  1.1583 +    //    lazy parsing, decompression is not uncommon, so this can significantly
  1.1584 +    //    increase latency.
  1.1585 +    //  - If there is only one core, then compression will contend with JS
  1.1586 +    //    execution (which hurts benchmarketing).
  1.1587 +    //  - If the source contains a giant string, then parsing will finish much
  1.1588 +    //    faster than compression which increases latency (this case is handled
  1.1589 +    //    in Parser::stringLiteral).
  1.1590 +    //
  1.1591 +    // Lastly, since the parsing thread will eventually perform a blocking wait
  1.1592 +    // on the compresion task's worker thread, require that there are at least 2
  1.1593 +    // worker threads:
  1.1594 +    //  - If we are on a worker thread, there must be another worker thread to
  1.1595 +    //    execute our compression task.
  1.1596 +    //  - If we are on the main thread, there must be at least two worker
  1.1597 +    //    threads since at most one worker thread can be blocking on the main
  1.1598 +    //    thread (see WorkerThreadState::canStartParseTask) which would cause a
  1.1599 +    //    deadlock if there wasn't a second worker thread that could make
  1.1600 +    //    progress on our compression task.
  1.1601 +#ifdef JS_THREADSAFE
  1.1602 +    bool canCompressOffThread =
  1.1603 +        WorkerThreadState().cpuCount > 1 &&
  1.1604 +        WorkerThreadState().threadCount >= 2;
  1.1605 +#else
  1.1606 +    bool canCompressOffThread = false;
  1.1607 +#endif
  1.1608 +    const size_t TINY_SCRIPT = 256;
  1.1609 +    const size_t HUGE_SCRIPT = 5 * 1024 * 1024;
  1.1610 +    if (TINY_SCRIPT <= srcBuf.length() && srcBuf.length() < HUGE_SCRIPT && canCompressOffThread) {
  1.1611 +        task->ss = this;
  1.1612 +        task->chars = srcBuf.get();
  1.1613 +        ready_ = false;
  1.1614 +        if (!StartOffThreadCompression(cx, task))
  1.1615 +            return false;
  1.1616 +    } else if (srcBuf.ownsChars()) {
  1.1617 +        data.source = srcBuf.take();
  1.1618 +    } else {
  1.1619 +        if (!adjustDataSize(sizeof(jschar) * srcBuf.length()))
  1.1620 +            return false;
  1.1621 +        PodCopy(data.source, srcBuf.get(), length_);
  1.1622 +    }
  1.1623 +
  1.1624 +    return true;
  1.1625 +}
  1.1626 +
  1.1627 +void
  1.1628 +ScriptSource::setSource(const jschar *src, size_t length)
  1.1629 +{
  1.1630 +    JS_ASSERT(!hasSourceData());
  1.1631 +    length_ = length;
  1.1632 +    JS_ASSERT(!argumentsNotIncluded_);
  1.1633 +    data.source = const_cast<jschar *>(src);
  1.1634 +}
  1.1635 +
  1.1636 +bool
  1.1637 +SourceCompressionTask::work()
  1.1638 +{
  1.1639 +    // A given compression token can be compressed on any thread, and the ss
  1.1640 +    // not being ready indicates to other threads that its fields might change
  1.1641 +    // with no lock held.
  1.1642 +    JS_ASSERT(!ss->ready());
  1.1643 +
  1.1644 +    size_t compressedLength = 0;
  1.1645 +    size_t nbytes = sizeof(jschar) * ss->length_;
  1.1646 +
  1.1647 +    // Memory allocation functions on JSRuntime and JSContext are not
  1.1648 +    // threadsafe. We have to use the js_* variants.
  1.1649 +
  1.1650 +#ifdef USE_ZLIB
  1.1651 +    // Try to keep the maximum memory usage down by only allocating half the
  1.1652 +    // size of the string, first.
  1.1653 +    size_t firstSize = nbytes / 2;
  1.1654 +    if (!ss->adjustDataSize(firstSize))
  1.1655 +        return false;
  1.1656 +    Compressor comp(reinterpret_cast<const unsigned char *>(chars), nbytes);
  1.1657 +    if (!comp.init())
  1.1658 +        return false;
  1.1659 +    comp.setOutput(ss->data.compressed, firstSize);
  1.1660 +    bool cont = !abort_;
  1.1661 +    while (cont) {
  1.1662 +        switch (comp.compressMore()) {
  1.1663 +          case Compressor::CONTINUE:
  1.1664 +            break;
  1.1665 +          case Compressor::MOREOUTPUT: {
  1.1666 +            if (comp.outWritten() == nbytes) {
  1.1667 +                cont = false;
  1.1668 +                break;
  1.1669 +            }
  1.1670 +
  1.1671 +            // The compressed output is greater than half the size of the
  1.1672 +            // original string. Reallocate to the full size.
  1.1673 +            if (!ss->adjustDataSize(nbytes))
  1.1674 +                return false;
  1.1675 +            comp.setOutput(ss->data.compressed, nbytes);
  1.1676 +            break;
  1.1677 +          }
  1.1678 +          case Compressor::DONE:
  1.1679 +            cont = false;
  1.1680 +            break;
  1.1681 +          case Compressor::OOM:
  1.1682 +            return false;
  1.1683 +        }
  1.1684 +        cont = cont && !abort_;
  1.1685 +    }
  1.1686 +    compressedLength = comp.outWritten();
  1.1687 +    if (abort_ || compressedLength == nbytes)
  1.1688 +        compressedLength = 0;
  1.1689 +#endif
  1.1690 +
  1.1691 +    if (compressedLength == 0) {
  1.1692 +        if (!ss->adjustDataSize(nbytes))
  1.1693 +            return false;
  1.1694 +        PodCopy(ss->data.source, chars, ss->length());
  1.1695 +    } else {
  1.1696 +        // Shrink the buffer to the size of the compressed data. Shouldn't fail.
  1.1697 +        JS_ALWAYS_TRUE(ss->adjustDataSize(compressedLength));
  1.1698 +    }
  1.1699 +    ss->compressedLength_ = compressedLength;
  1.1700 +    return true;
  1.1701 +}
  1.1702 +
  1.1703 +void
  1.1704 +ScriptSource::destroy()
  1.1705 +{
  1.1706 +    JS_ASSERT(ready());
  1.1707 +    adjustDataSize(0);
  1.1708 +    if (introducerFilename_ != filename_)
  1.1709 +        js_free(introducerFilename_);
  1.1710 +    js_free(filename_);
  1.1711 +    js_free(displayURL_);
  1.1712 +    js_free(sourceMapURL_);
  1.1713 +    if (originPrincipals_)
  1.1714 +        JS_DropPrincipals(TlsPerThreadData.get()->runtimeFromMainThread(), originPrincipals_);
  1.1715 +    ready_ = false;
  1.1716 +    js_free(this);
  1.1717 +}
  1.1718 +
  1.1719 +void
  1.1720 +ScriptSource::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
  1.1721 +                                     JS::ScriptSourceInfo *info) const
  1.1722 +{
  1.1723 +    if (ready() && data.compressed != emptySource) {
  1.1724 +        if (compressed())
  1.1725 +            info->compressed += mallocSizeOf(data.compressed);
  1.1726 +        else
  1.1727 +            info->uncompressed += mallocSizeOf(data.source);
  1.1728 +    }
  1.1729 +    info->misc += mallocSizeOf(this) + mallocSizeOf(filename_);
  1.1730 +    info->numScripts++;
  1.1731 +}
  1.1732 +
  1.1733 +template<XDRMode mode>
  1.1734 +bool
  1.1735 +ScriptSource::performXDR(XDRState<mode> *xdr)
  1.1736 +{
  1.1737 +    uint8_t hasSource = hasSourceData();
  1.1738 +    if (!xdr->codeUint8(&hasSource))
  1.1739 +        return false;
  1.1740 +
  1.1741 +    uint8_t retrievable = sourceRetrievable_;
  1.1742 +    if (!xdr->codeUint8(&retrievable))
  1.1743 +        return false;
  1.1744 +    sourceRetrievable_ = retrievable;
  1.1745 +
  1.1746 +    if (hasSource && !sourceRetrievable_) {
  1.1747 +        // Only set members when we know decoding cannot fail. This prevents the
  1.1748 +        // script source from being partially initialized.
  1.1749 +        uint32_t length = length_;
  1.1750 +        if (!xdr->codeUint32(&length))
  1.1751 +            return false;
  1.1752 +
  1.1753 +        uint32_t compressedLength = compressedLength_;
  1.1754 +        if (!xdr->codeUint32(&compressedLength))
  1.1755 +            return false;
  1.1756 +
  1.1757 +        uint8_t argumentsNotIncluded = argumentsNotIncluded_;
  1.1758 +        if (!xdr->codeUint8(&argumentsNotIncluded))
  1.1759 +            return false;
  1.1760 +
  1.1761 +        size_t byteLen = compressedLength ? compressedLength : (length * sizeof(jschar));
  1.1762 +        if (mode == XDR_DECODE) {
  1.1763 +            if (!adjustDataSize(byteLen))
  1.1764 +                return false;
  1.1765 +        }
  1.1766 +        if (!xdr->codeBytes(data.compressed, byteLen)) {
  1.1767 +            if (mode == XDR_DECODE) {
  1.1768 +                js_free(data.compressed);
  1.1769 +                data.compressed = nullptr;
  1.1770 +            }
  1.1771 +            return false;
  1.1772 +        }
  1.1773 +        length_ = length;
  1.1774 +        compressedLength_ = compressedLength;
  1.1775 +        argumentsNotIncluded_ = argumentsNotIncluded;
  1.1776 +    }
  1.1777 +
  1.1778 +    uint8_t haveSourceMap = hasSourceMapURL();
  1.1779 +    if (!xdr->codeUint8(&haveSourceMap))
  1.1780 +        return false;
  1.1781 +
  1.1782 +    if (haveSourceMap) {
  1.1783 +        uint32_t sourceMapURLLen = (mode == XDR_DECODE) ? 0 : js_strlen(sourceMapURL_);
  1.1784 +        if (!xdr->codeUint32(&sourceMapURLLen))
  1.1785 +            return false;
  1.1786 +
  1.1787 +        if (mode == XDR_DECODE) {
  1.1788 +            size_t byteLen = (sourceMapURLLen + 1) * sizeof(jschar);
  1.1789 +            sourceMapURL_ = static_cast<jschar *>(xdr->cx()->malloc_(byteLen));
  1.1790 +            if (!sourceMapURL_)
  1.1791 +                return false;
  1.1792 +        }
  1.1793 +        if (!xdr->codeChars(sourceMapURL_, sourceMapURLLen)) {
  1.1794 +            if (mode == XDR_DECODE) {
  1.1795 +                js_free(sourceMapURL_);
  1.1796 +                sourceMapURL_ = nullptr;
  1.1797 +            }
  1.1798 +            return false;
  1.1799 +        }
  1.1800 +        sourceMapURL_[sourceMapURLLen] = '\0';
  1.1801 +    }
  1.1802 +
  1.1803 +    uint8_t haveDisplayURL = hasDisplayURL();
  1.1804 +    if (!xdr->codeUint8(&haveDisplayURL))
  1.1805 +        return false;
  1.1806 +
  1.1807 +    if (haveDisplayURL) {
  1.1808 +        uint32_t displayURLLen = (mode == XDR_DECODE) ? 0 : js_strlen(displayURL_);
  1.1809 +        if (!xdr->codeUint32(&displayURLLen))
  1.1810 +            return false;
  1.1811 +
  1.1812 +        if (mode == XDR_DECODE) {
  1.1813 +            size_t byteLen = (displayURLLen + 1) * sizeof(jschar);
  1.1814 +            displayURL_ = static_cast<jschar *>(xdr->cx()->malloc_(byteLen));
  1.1815 +            if (!displayURL_)
  1.1816 +                return false;
  1.1817 +        }
  1.1818 +        if (!xdr->codeChars(displayURL_, displayURLLen)) {
  1.1819 +            if (mode == XDR_DECODE) {
  1.1820 +                js_free(displayURL_);
  1.1821 +                displayURL_ = nullptr;
  1.1822 +            }
  1.1823 +            return false;
  1.1824 +        }
  1.1825 +        displayURL_[displayURLLen] = '\0';
  1.1826 +    }
  1.1827 +
  1.1828 +    uint8_t haveFilename = !!filename_;
  1.1829 +    if (!xdr->codeUint8(&haveFilename))
  1.1830 +        return false;
  1.1831 +
  1.1832 +    if (haveFilename) {
  1.1833 +        const char *fn = filename();
  1.1834 +        if (!xdr->codeCString(&fn))
  1.1835 +            return false;
  1.1836 +        if (mode == XDR_DECODE && !setFilename(xdr->cx(), fn))
  1.1837 +            return false;
  1.1838 +    }
  1.1839 +
  1.1840 +    if (mode == XDR_DECODE)
  1.1841 +        ready_ = true;
  1.1842 +
  1.1843 +    return true;
  1.1844 +}
  1.1845 +
  1.1846 +// Format and return a cx->malloc_'ed URL for a generated script like:
  1.1847 +//   {filename} line {lineno} > {introducer}
  1.1848 +// For example:
  1.1849 +//   foo.js line 7 > eval
  1.1850 +// indicating code compiled by the call to 'eval' on line 7 of foo.js.
  1.1851 +static char *
  1.1852 +FormatIntroducedFilename(ExclusiveContext *cx, const char *filename, unsigned lineno,
  1.1853 +                         const char *introducer)
  1.1854 +{
  1.1855 +    // Compute the length of the string in advance, so we can allocate a
  1.1856 +    // buffer of the right size on the first shot.
  1.1857 +    //
  1.1858 +    // (JS_smprintf would be perfect, as that allocates the result
  1.1859 +    // dynamically as it formats the string, but it won't allocate from cx,
  1.1860 +    // and wants us to use a special free function.)
  1.1861 +    char linenoBuf[15];
  1.1862 +    size_t filenameLen = strlen(filename);
  1.1863 +    size_t linenoLen = JS_snprintf(linenoBuf, 15, "%u", lineno);
  1.1864 +    size_t introducerLen = strlen(introducer);
  1.1865 +    size_t len = filenameLen                    +
  1.1866 +                 6 /* == strlen(" line ") */    +
  1.1867 +                 linenoLen                      +
  1.1868 +                 3 /* == strlen(" > ") */       +
  1.1869 +                 introducerLen                  +
  1.1870 +                 1 /* \0 */;
  1.1871 +    char *formatted = cx->pod_malloc<char>(len);
  1.1872 +    if (!formatted)
  1.1873 +        return nullptr;
  1.1874 +    mozilla::DebugOnly<size_t> checkLen = JS_snprintf(formatted, len, "%s line %s > %s",
  1.1875 +                                                      filename, linenoBuf, introducer);
  1.1876 +    JS_ASSERT(checkLen == len - 1);
  1.1877 +
  1.1878 +    return formatted;
  1.1879 +}
  1.1880 +
  1.1881 +bool
  1.1882 +ScriptSource::initFromOptions(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
  1.1883 +{
  1.1884 +    JS_ASSERT(!filename_);
  1.1885 +    JS_ASSERT(!introducerFilename_);
  1.1886 +
  1.1887 +    originPrincipals_ = options.originPrincipals(cx);
  1.1888 +    if (originPrincipals_)
  1.1889 +        JS_HoldPrincipals(originPrincipals_);
  1.1890 +
  1.1891 +    introductionType_ = options.introductionType;
  1.1892 +    setIntroductionOffset(options.introductionOffset);
  1.1893 +
  1.1894 +    if (options.hasIntroductionInfo) {
  1.1895 +        JS_ASSERT(options.introductionType != nullptr);
  1.1896 +        const char *filename = options.filename() ? options.filename() : "<unknown>";
  1.1897 +        char *formatted = FormatIntroducedFilename(cx, filename, options.introductionLineno,
  1.1898 +                                                   options.introductionType);
  1.1899 +        if (!formatted)
  1.1900 +            return false;
  1.1901 +        filename_ = formatted;
  1.1902 +    } else if (options.filename()) {
  1.1903 +        if (!setFilename(cx, options.filename()))
  1.1904 +            return false;
  1.1905 +    }
  1.1906 +
  1.1907 +    if (options.introducerFilename()) {
  1.1908 +        introducerFilename_ = js_strdup(cx, options.introducerFilename());
  1.1909 +        if (!introducerFilename_)
  1.1910 +            return false;
  1.1911 +    } else {
  1.1912 +        introducerFilename_ = filename_;
  1.1913 +    }
  1.1914 +
  1.1915 +    return true;
  1.1916 +}
  1.1917 +
  1.1918 +bool
  1.1919 +ScriptSource::setFilename(ExclusiveContext *cx, const char *filename)
  1.1920 +{
  1.1921 +    JS_ASSERT(!filename_);
  1.1922 +    filename_ = js_strdup(cx, filename);
  1.1923 +    if (!filename_)
  1.1924 +        return false;
  1.1925 +    return true;
  1.1926 +}
  1.1927 +
  1.1928 +bool
  1.1929 +ScriptSource::setDisplayURL(ExclusiveContext *cx, const jschar *displayURL)
  1.1930 +{
  1.1931 +    JS_ASSERT(displayURL);
  1.1932 +    if (hasDisplayURL()) {
  1.1933 +        if (cx->isJSContext() &&
  1.1934 +            !JS_ReportErrorFlagsAndNumber(cx->asJSContext(), JSREPORT_WARNING,
  1.1935 +                                          js_GetErrorMessage, nullptr,
  1.1936 +                                          JSMSG_ALREADY_HAS_PRAGMA, filename_,
  1.1937 +                                          "//# sourceURL"))
  1.1938 +        {
  1.1939 +            return false;
  1.1940 +        }
  1.1941 +    }
  1.1942 +    size_t len = js_strlen(displayURL) + 1;
  1.1943 +    if (len == 1)
  1.1944 +        return true;
  1.1945 +    displayURL_ = js_strdup(cx, displayURL);
  1.1946 +    if (!displayURL_)
  1.1947 +        return false;
  1.1948 +    return true;
  1.1949 +}
  1.1950 +
  1.1951 +const jschar *
  1.1952 +ScriptSource::displayURL()
  1.1953 +{
  1.1954 +    JS_ASSERT(hasDisplayURL());
  1.1955 +    return displayURL_;
  1.1956 +}
  1.1957 +
  1.1958 +bool
  1.1959 +ScriptSource::setSourceMapURL(ExclusiveContext *cx, const jschar *sourceMapURL)
  1.1960 +{
  1.1961 +    JS_ASSERT(sourceMapURL);
  1.1962 +    if (hasSourceMapURL()) {
  1.1963 +        if (cx->isJSContext() &&
  1.1964 +            !JS_ReportErrorFlagsAndNumber(cx->asJSContext(), JSREPORT_WARNING,
  1.1965 +                                          js_GetErrorMessage, nullptr,
  1.1966 +                                          JSMSG_ALREADY_HAS_PRAGMA, filename_,
  1.1967 +                                          "//# sourceMappingURL"))
  1.1968 +        {
  1.1969 +            return false;
  1.1970 +        }
  1.1971 +    }
  1.1972 +
  1.1973 +    size_t len = js_strlen(sourceMapURL) + 1;
  1.1974 +    if (len == 1)
  1.1975 +        return true;
  1.1976 +    sourceMapURL_ = js_strdup(cx, sourceMapURL);
  1.1977 +    if (!sourceMapURL_)
  1.1978 +        return false;
  1.1979 +    return true;
  1.1980 +}
  1.1981 +
  1.1982 +const jschar *
  1.1983 +ScriptSource::sourceMapURL()
  1.1984 +{
  1.1985 +    JS_ASSERT(hasSourceMapURL());
  1.1986 +    return sourceMapURL_;
  1.1987 +}
  1.1988 +
  1.1989 +/*
  1.1990 + * Shared script data management.
  1.1991 + */
  1.1992 +
  1.1993 +SharedScriptData *
  1.1994 +js::SharedScriptData::new_(ExclusiveContext *cx, uint32_t codeLength,
  1.1995 +                           uint32_t srcnotesLength, uint32_t natoms)
  1.1996 +{
  1.1997 +    /*
  1.1998 +     * Ensure the atoms are aligned, as some architectures don't allow unaligned
  1.1999 +     * access.
  1.2000 +     */
  1.2001 +    const uint32_t pointerSize = sizeof(JSAtom *);
  1.2002 +    const uint32_t pointerMask = pointerSize - 1;
  1.2003 +    const uint32_t dataOffset = offsetof(SharedScriptData, data);
  1.2004 +    uint32_t baseLength = codeLength + srcnotesLength;
  1.2005 +    uint32_t padding = (pointerSize - ((baseLength + dataOffset) & pointerMask)) & pointerMask;
  1.2006 +    uint32_t length = baseLength + padding + pointerSize * natoms;
  1.2007 +
  1.2008 +    SharedScriptData *entry = (SharedScriptData *)cx->malloc_(length + dataOffset);
  1.2009 +    if (!entry)
  1.2010 +        return nullptr;
  1.2011 +
  1.2012 +    entry->length = length;
  1.2013 +    entry->natoms = natoms;
  1.2014 +    entry->marked = false;
  1.2015 +    memset(entry->data + baseLength, 0, padding);
  1.2016 +
  1.2017 +    /*
  1.2018 +     * Call constructors to initialize the storage that will be accessed as a
  1.2019 +     * HeapPtrAtom array via atoms().
  1.2020 +     */
  1.2021 +    HeapPtrAtom *atoms = entry->atoms();
  1.2022 +    JS_ASSERT(reinterpret_cast<uintptr_t>(atoms) % sizeof(JSAtom *) == 0);
  1.2023 +    for (unsigned i = 0; i < natoms; ++i)
  1.2024 +        new (&atoms[i]) HeapPtrAtom();
  1.2025 +
  1.2026 +    return entry;
  1.2027 +}
  1.2028 +
  1.2029 +/*
  1.2030 + * Takes ownership of its *ssd parameter and either adds it into the runtime's
  1.2031 + * ScriptDataTable or frees it if a matching entry already exists.
  1.2032 + *
  1.2033 + * Sets the |code| and |atoms| fields on the given JSScript.
  1.2034 + */
  1.2035 +static bool
  1.2036 +SaveSharedScriptData(ExclusiveContext *cx, Handle<JSScript *> script, SharedScriptData *ssd,
  1.2037 +                     uint32_t nsrcnotes)
  1.2038 +{
  1.2039 +    ASSERT(script != nullptr);
  1.2040 +    ASSERT(ssd != nullptr);
  1.2041 +
  1.2042 +    AutoLockForExclusiveAccess lock(cx);
  1.2043 +
  1.2044 +    ScriptBytecodeHasher::Lookup l(ssd);
  1.2045 +
  1.2046 +    ScriptDataTable::AddPtr p = cx->scriptDataTable().lookupForAdd(l);
  1.2047 +    if (p) {
  1.2048 +        js_free(ssd);
  1.2049 +        ssd = *p;
  1.2050 +    } else {
  1.2051 +        if (!cx->scriptDataTable().add(p, ssd)) {
  1.2052 +            script->setCode(nullptr);
  1.2053 +            script->atoms = nullptr;
  1.2054 +            js_free(ssd);
  1.2055 +            js_ReportOutOfMemory(cx);
  1.2056 +            return false;
  1.2057 +        }
  1.2058 +    }
  1.2059 +
  1.2060 +#ifdef JSGC_INCREMENTAL
  1.2061 +    /*
  1.2062 +     * During the IGC we need to ensure that bytecode is marked whenever it is
  1.2063 +     * accessed even if the bytecode was already in the table: at this point
  1.2064 +     * old scripts or exceptions pointing to the bytecode may no longer be
  1.2065 +     * reachable. This is effectively a read barrier.
  1.2066 +     */
  1.2067 +    if (cx->isJSContext()) {
  1.2068 +        JSRuntime *rt = cx->asJSContext()->runtime();
  1.2069 +        if (JS::IsIncrementalGCInProgress(rt) && rt->gcIsFull)
  1.2070 +            ssd->marked = true;
  1.2071 +    }
  1.2072 +#endif
  1.2073 +
  1.2074 +    script->setCode(ssd->data);
  1.2075 +    script->atoms = ssd->atoms();
  1.2076 +    return true;
  1.2077 +}
  1.2078 +
  1.2079 +static inline void
  1.2080 +MarkScriptData(JSRuntime *rt, const jsbytecode *bytecode)
  1.2081 +{
  1.2082 +    /*
  1.2083 +     * As an invariant, a ScriptBytecodeEntry should not be 'marked' outside of
  1.2084 +     * a GC. Since SweepScriptBytecodes is only called during a full gc,
  1.2085 +     * to preserve this invariant, only mark during a full gc.
  1.2086 +     */
  1.2087 +    if (rt->gcIsFull)
  1.2088 +        SharedScriptData::fromBytecode(bytecode)->marked = true;
  1.2089 +}
  1.2090 +
  1.2091 +void
  1.2092 +js::UnmarkScriptData(JSRuntime *rt)
  1.2093 +{
  1.2094 +    JS_ASSERT(rt->gcIsFull);
  1.2095 +    ScriptDataTable &table = rt->scriptDataTable();
  1.2096 +    for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront()) {
  1.2097 +        SharedScriptData *entry = e.front();
  1.2098 +        entry->marked = false;
  1.2099 +    }
  1.2100 +}
  1.2101 +
  1.2102 +void
  1.2103 +js::SweepScriptData(JSRuntime *rt)
  1.2104 +{
  1.2105 +    JS_ASSERT(rt->gcIsFull);
  1.2106 +    ScriptDataTable &table = rt->scriptDataTable();
  1.2107 +
  1.2108 +    if (rt->keepAtoms())
  1.2109 +        return;
  1.2110 +
  1.2111 +    for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront()) {
  1.2112 +        SharedScriptData *entry = e.front();
  1.2113 +        if (!entry->marked) {
  1.2114 +            js_free(entry);
  1.2115 +            e.removeFront();
  1.2116 +        }
  1.2117 +    }
  1.2118 +}
  1.2119 +
  1.2120 +void
  1.2121 +js::FreeScriptData(JSRuntime *rt)
  1.2122 +{
  1.2123 +    ScriptDataTable &table = rt->scriptDataTable();
  1.2124 +    if (!table.initialized())
  1.2125 +        return;
  1.2126 +
  1.2127 +    for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront())
  1.2128 +        js_free(e.front());
  1.2129 +
  1.2130 +    table.clear();
  1.2131 +}
  1.2132 +
  1.2133 +/*
  1.2134 + * JSScript::data and SharedScriptData::data have complex,
  1.2135 + * manually-controlled, memory layouts.
  1.2136 + *
  1.2137 + * JSScript::data begins with some optional array headers. They are optional
  1.2138 + * because they often aren't needed, i.e. the corresponding arrays often have
  1.2139 + * zero elements. Each header has a bit in JSScript::hasArrayBits that
  1.2140 + * indicates if it's present within |data|; from this the offset of each
  1.2141 + * present array header can be computed. Each header has an accessor function
  1.2142 + * in JSScript that encapsulates this offset computation.
  1.2143 + *
  1.2144 + * Array type       Array elements  Accessor
  1.2145 + * ----------       --------------  --------
  1.2146 + * ConstArray       Consts          consts()
  1.2147 + * ObjectArray      Objects         objects()
  1.2148 + * ObjectArray      Regexps         regexps()
  1.2149 + * TryNoteArray     Try notes       trynotes()
  1.2150 + * BlockScopeArray  Scope notes     blockScopes()
  1.2151 + *
  1.2152 + * Then are the elements of several arrays.
  1.2153 + * - Most of these arrays have headers listed above (if present). For each of
  1.2154 + *   these, the array pointer and the array length is stored in the header.
  1.2155 + * - The remaining arrays have pointers and lengths that are stored directly in
  1.2156 + *   JSScript. This is because, unlike the others, they are nearly always
  1.2157 + *   non-zero length and so the optional-header space optimization isn't
  1.2158 + *   worthwhile.
  1.2159 + *
  1.2160 + * Array elements   Pointed to by         Length
  1.2161 + * --------------   -------------         ------
  1.2162 + * Consts           consts()->vector      consts()->length
  1.2163 + * Objects          objects()->vector     objects()->length
  1.2164 + * Regexps          regexps()->vector     regexps()->length
  1.2165 + * Try notes        trynotes()->vector    trynotes()->length
  1.2166 + * Scope notes      blockScopes()->vector blockScopes()->length
  1.2167 + *
  1.2168 + * IMPORTANT: This layout has two key properties.
  1.2169 + * - It ensures that everything has sufficient alignment; in particular, the
  1.2170 + *   consts() elements need jsval alignment.
  1.2171 + * - It ensures there are no gaps between elements, which saves space and makes
  1.2172 + *   manual layout easy. In particular, in the second part, arrays with larger
  1.2173 + *   elements precede arrays with smaller elements.
  1.2174 + *
  1.2175 + * SharedScriptData::data contains data that can be shared within a
  1.2176 + * runtime. These items' layout is manually controlled to make it easier to
  1.2177 + * manage both during (temporary) allocation and during matching against
  1.2178 + * existing entries in the runtime. As the jsbytecode has to come first to
  1.2179 + * enable lookup by bytecode identity, SharedScriptData::data, the atoms part
  1.2180 + * has to manually be aligned sufficiently by adding padding after the notes
  1.2181 + * part.
  1.2182 + *
  1.2183 + * Array elements   Pointed to by         Length
  1.2184 + * --------------   -------------         ------
  1.2185 + * jsbytecode       code                  length
  1.2186 + * jsscrnote        notes()               numNotes()
  1.2187 + * Atoms            atoms                 natoms
  1.2188 + *
  1.2189 + * The following static assertions check JSScript::data's alignment properties.
  1.2190 + */
  1.2191 +
  1.2192 +#define KEEPS_JSVAL_ALIGNMENT(T) \
  1.2193 +    (JS_ALIGNMENT_OF(jsval) % JS_ALIGNMENT_OF(T) == 0 && \
  1.2194 +     sizeof(T) % sizeof(jsval) == 0)
  1.2195 +
  1.2196 +#define HAS_JSVAL_ALIGNMENT(T) \
  1.2197 +    (JS_ALIGNMENT_OF(jsval) == JS_ALIGNMENT_OF(T) && \
  1.2198 +     sizeof(T) == sizeof(jsval))
  1.2199 +
  1.2200 +#define NO_PADDING_BETWEEN_ENTRIES(T1, T2) \
  1.2201 +    (JS_ALIGNMENT_OF(T1) % JS_ALIGNMENT_OF(T2) == 0)
  1.2202 +
  1.2203 +/*
  1.2204 + * These assertions ensure that there is no padding between the array headers,
  1.2205 + * and also that the consts() elements (which follow immediately afterward) are
  1.2206 + * jsval-aligned.  (There is an assumption that |data| itself is jsval-aligned;
  1.2207 + * we check this below).
  1.2208 + */
  1.2209 +JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ConstArray));
  1.2210 +JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ObjectArray));       /* there are two of these */
  1.2211 +JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(TryNoteArray));
  1.2212 +JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(BlockScopeArray));
  1.2213 +
  1.2214 +/* These assertions ensure there is no padding required between array elements. */
  1.2215 +JS_STATIC_ASSERT(HAS_JSVAL_ALIGNMENT(HeapValue));
  1.2216 +JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapValue, HeapPtrObject));
  1.2217 +JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, HeapPtrObject));
  1.2218 +JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, JSTryNote));
  1.2219 +JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(JSTryNote, uint32_t));
  1.2220 +JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(uint32_t, uint32_t));
  1.2221 +
  1.2222 +JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapValue, BlockScopeNote));
  1.2223 +JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(BlockScopeNote, BlockScopeNote));
  1.2224 +JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(JSTryNote, BlockScopeNote));
  1.2225 +JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, BlockScopeNote));
  1.2226 +JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(BlockScopeNote, uint32_t));
  1.2227 +
  1.2228 +static inline size_t
  1.2229 +ScriptDataSize(uint32_t nbindings, uint32_t nconsts, uint32_t nobjects, uint32_t nregexps,
  1.2230 +               uint32_t ntrynotes, uint32_t nblockscopes)
  1.2231 +{
  1.2232 +    size_t size = 0;
  1.2233 +
  1.2234 +    if (nconsts != 0)
  1.2235 +        size += sizeof(ConstArray) + nconsts * sizeof(Value);
  1.2236 +    if (nobjects != 0)
  1.2237 +        size += sizeof(ObjectArray) + nobjects * sizeof(JSObject *);
  1.2238 +    if (nregexps != 0)
  1.2239 +        size += sizeof(ObjectArray) + nregexps * sizeof(JSObject *);
  1.2240 +    if (ntrynotes != 0)
  1.2241 +        size += sizeof(TryNoteArray) + ntrynotes * sizeof(JSTryNote);
  1.2242 +    if (nblockscopes != 0)
  1.2243 +        size += sizeof(BlockScopeArray) + nblockscopes * sizeof(BlockScopeNote);
  1.2244 +
  1.2245 +    if (nbindings != 0) {
  1.2246 +	// Make sure bindings are sufficiently aligned.
  1.2247 +        size = JS_ROUNDUP(size, JS_ALIGNMENT_OF(Binding)) + nbindings * sizeof(Binding);
  1.2248 +    }
  1.2249 +
  1.2250 +    return size;
  1.2251 +}
  1.2252 +
  1.2253 +void
  1.2254 +JSScript::initCompartment(ExclusiveContext *cx)
  1.2255 +{
  1.2256 +    compartment_ = cx->compartment_;
  1.2257 +}
  1.2258 +
  1.2259 +JSScript *
  1.2260 +JSScript::Create(ExclusiveContext *cx, HandleObject enclosingScope, bool savedCallerFun,
  1.2261 +                 const ReadOnlyCompileOptions &options, unsigned staticLevel,
  1.2262 +                 HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd)
  1.2263 +{
  1.2264 +    JS_ASSERT(bufStart <= bufEnd);
  1.2265 +
  1.2266 +    RootedScript script(cx, js_NewGCScript(cx));
  1.2267 +    if (!script)
  1.2268 +        return nullptr;
  1.2269 +
  1.2270 +    PodZero(script.get());
  1.2271 +    new (&script->bindings) Bindings;
  1.2272 +
  1.2273 +    script->enclosingScopeOrOriginalFunction_ = enclosingScope;
  1.2274 +    script->savedCallerFun_ = savedCallerFun;
  1.2275 +    script->initCompartment(cx);
  1.2276 +
  1.2277 +    script->compileAndGo_ = options.compileAndGo;
  1.2278 +    script->selfHosted_ = options.selfHostingMode;
  1.2279 +    script->noScriptRval_ = options.noScriptRval;
  1.2280 +
  1.2281 +    script->version = options.version;
  1.2282 +    JS_ASSERT(script->getVersion() == options.version);     // assert that no overflow occurred
  1.2283 +
  1.2284 +    // This is an unsigned-to-uint16_t conversion, test for too-high values.
  1.2285 +    // In practice, recursion in Parser and/or BytecodeEmitter will blow the
  1.2286 +    // stack if we nest functions more than a few hundred deep, so this will
  1.2287 +    // never trigger.  Oh well.
  1.2288 +    if (staticLevel > UINT16_MAX) {
  1.2289 +        if (cx->isJSContext()) {
  1.2290 +            JS_ReportErrorNumber(cx->asJSContext(),
  1.2291 +                                 js_GetErrorMessage, nullptr, JSMSG_TOO_DEEP, js_function_str);
  1.2292 +        }
  1.2293 +        return nullptr;
  1.2294 +    }
  1.2295 +    script->staticLevel_ = uint16_t(staticLevel);
  1.2296 +
  1.2297 +    script->setSourceObject(sourceObject);
  1.2298 +    script->sourceStart_ = bufStart;
  1.2299 +    script->sourceEnd_ = bufEnd;
  1.2300 +
  1.2301 +    return script;
  1.2302 +}
  1.2303 +
  1.2304 +static inline uint8_t *
  1.2305 +AllocScriptData(ExclusiveContext *cx, size_t size)
  1.2306 +{
  1.2307 +    uint8_t *data = static_cast<uint8_t *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value))));
  1.2308 +    if (!data)
  1.2309 +        return nullptr;
  1.2310 +
  1.2311 +    // All script data is optional, so size might be 0. In that case, we don't care about alignment.
  1.2312 +    JS_ASSERT(size == 0 || size_t(data) % sizeof(Value) == 0);
  1.2313 +    return data;
  1.2314 +}
  1.2315 +
  1.2316 +/* static */ bool
  1.2317 +JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nconsts,
  1.2318 +                        uint32_t nobjects, uint32_t nregexps, uint32_t ntrynotes,
  1.2319 +                        uint32_t nblockscopes, uint32_t nTypeSets)
  1.2320 +{
  1.2321 +    size_t size = ScriptDataSize(script->bindings.count(), nconsts, nobjects, nregexps, ntrynotes,
  1.2322 +                                 nblockscopes);
  1.2323 +    if (size > 0) {
  1.2324 +        script->data = AllocScriptData(cx, size);
  1.2325 +        if (!script->data)
  1.2326 +            return false;
  1.2327 +    } else {
  1.2328 +        script->data = nullptr;
  1.2329 +    }
  1.2330 +    script->dataSize_ = size;
  1.2331 +
  1.2332 +    JS_ASSERT(nTypeSets <= UINT16_MAX);
  1.2333 +    script->nTypeSets_ = uint16_t(nTypeSets);
  1.2334 +
  1.2335 +    uint8_t *cursor = script->data;
  1.2336 +    if (nconsts != 0) {
  1.2337 +        script->setHasArray(CONSTS);
  1.2338 +        cursor += sizeof(ConstArray);
  1.2339 +    }
  1.2340 +    if (nobjects != 0) {
  1.2341 +        script->setHasArray(OBJECTS);
  1.2342 +        cursor += sizeof(ObjectArray);
  1.2343 +    }
  1.2344 +    if (nregexps != 0) {
  1.2345 +        script->setHasArray(REGEXPS);
  1.2346 +        cursor += sizeof(ObjectArray);
  1.2347 +    }
  1.2348 +    if (ntrynotes != 0) {
  1.2349 +        script->setHasArray(TRYNOTES);
  1.2350 +        cursor += sizeof(TryNoteArray);
  1.2351 +    }
  1.2352 +    if (nblockscopes != 0) {
  1.2353 +        script->setHasArray(BLOCK_SCOPES);
  1.2354 +        cursor += sizeof(BlockScopeArray);
  1.2355 +    }
  1.2356 +
  1.2357 +    if (nconsts != 0) {
  1.2358 +        JS_ASSERT(reinterpret_cast<uintptr_t>(cursor) % sizeof(jsval) == 0);
  1.2359 +        script->consts()->length = nconsts;
  1.2360 +        script->consts()->vector = (HeapValue *)cursor;
  1.2361 +        cursor += nconsts * sizeof(script->consts()->vector[0]);
  1.2362 +    }
  1.2363 +
  1.2364 +    if (nobjects != 0) {
  1.2365 +        script->objects()->length = nobjects;
  1.2366 +        script->objects()->vector = (HeapPtr<JSObject> *)cursor;
  1.2367 +        cursor += nobjects * sizeof(script->objects()->vector[0]);
  1.2368 +    }
  1.2369 +
  1.2370 +    if (nregexps != 0) {
  1.2371 +        script->regexps()->length = nregexps;
  1.2372 +        script->regexps()->vector = (HeapPtr<JSObject> *)cursor;
  1.2373 +        cursor += nregexps * sizeof(script->regexps()->vector[0]);
  1.2374 +    }
  1.2375 +
  1.2376 +    if (ntrynotes != 0) {
  1.2377 +        script->trynotes()->length = ntrynotes;
  1.2378 +        script->trynotes()->vector = reinterpret_cast<JSTryNote *>(cursor);
  1.2379 +        size_t vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
  1.2380 +#ifdef DEBUG
  1.2381 +        memset(cursor, 0, vectorSize);
  1.2382 +#endif
  1.2383 +        cursor += vectorSize;
  1.2384 +    }
  1.2385 +
  1.2386 +    if (nblockscopes != 0) {
  1.2387 +        script->blockScopes()->length = nblockscopes;
  1.2388 +        script->blockScopes()->vector = reinterpret_cast<BlockScopeNote *>(cursor);
  1.2389 +        size_t vectorSize = nblockscopes * sizeof(script->blockScopes()->vector[0]);
  1.2390 +#ifdef DEBUG
  1.2391 +        memset(cursor, 0, vectorSize);
  1.2392 +#endif
  1.2393 +        cursor += vectorSize;
  1.2394 +    }
  1.2395 +
  1.2396 +    if (script->bindings.count() != 0) {
  1.2397 +	// Make sure bindings are sufficiently aligned.
  1.2398 +	cursor = reinterpret_cast<uint8_t*>
  1.2399 +	    (JS_ROUNDUP(reinterpret_cast<uintptr_t>(cursor), JS_ALIGNMENT_OF(Binding)));
  1.2400 +    }
  1.2401 +    cursor = script->bindings.switchToScriptStorage(reinterpret_cast<Binding *>(cursor));
  1.2402 +
  1.2403 +    JS_ASSERT(cursor == script->data + size);
  1.2404 +    return true;
  1.2405 +}
  1.2406 +
  1.2407 +/* static */ bool
  1.2408 +JSScript::fullyInitTrivial(ExclusiveContext *cx, Handle<JSScript*> script)
  1.2409 +{
  1.2410 +    if (!partiallyInit(cx, script, 0, 0, 0, 0, 0, 0))
  1.2411 +        return false;
  1.2412 +
  1.2413 +    SharedScriptData *ssd = SharedScriptData::new_(cx, 1, 1, 0);
  1.2414 +    if (!ssd)
  1.2415 +        return false;
  1.2416 +
  1.2417 +    ssd->data[0] = JSOP_RETRVAL;
  1.2418 +    ssd->data[1] = SRC_NULL;
  1.2419 +    script->setLength(1);
  1.2420 +    return SaveSharedScriptData(cx, script, ssd, 1);
  1.2421 +}
  1.2422 +
  1.2423 +/* static */ bool
  1.2424 +JSScript::fullyInitFromEmitter(ExclusiveContext *cx, HandleScript script, BytecodeEmitter *bce)
  1.2425 +{
  1.2426 +    /* The counts of indexed things must be checked during code generation. */
  1.2427 +    JS_ASSERT(bce->atomIndices->count() <= INDEX_LIMIT);
  1.2428 +    JS_ASSERT(bce->objectList.length <= INDEX_LIMIT);
  1.2429 +    JS_ASSERT(bce->regexpList.length <= INDEX_LIMIT);
  1.2430 +
  1.2431 +    uint32_t mainLength = bce->offset();
  1.2432 +    uint32_t prologLength = bce->prologOffset();
  1.2433 +    uint32_t nsrcnotes;
  1.2434 +    if (!FinishTakingSrcNotes(cx, bce, &nsrcnotes))
  1.2435 +        return false;
  1.2436 +    uint32_t natoms = bce->atomIndices->count();
  1.2437 +    if (!partiallyInit(cx, script,
  1.2438 +                       bce->constList.length(), bce->objectList.length, bce->regexpList.length,
  1.2439 +                       bce->tryNoteList.length(), bce->blockScopeList.length(), bce->typesetCount))
  1.2440 +    {
  1.2441 +        return false;
  1.2442 +    }
  1.2443 +
  1.2444 +    JS_ASSERT(script->mainOffset() == 0);
  1.2445 +    script->mainOffset_ = prologLength;
  1.2446 +
  1.2447 +    script->lineno_ = bce->firstLine;
  1.2448 +
  1.2449 +    script->setLength(prologLength + mainLength);
  1.2450 +    script->natoms_ = natoms;
  1.2451 +    SharedScriptData *ssd = SharedScriptData::new_(cx, script->length(), nsrcnotes, natoms);
  1.2452 +    if (!ssd)
  1.2453 +        return false;
  1.2454 +
  1.2455 +    jsbytecode *code = ssd->data;
  1.2456 +    PodCopy<jsbytecode>(code, bce->prolog.code.begin(), prologLength);
  1.2457 +    PodCopy<jsbytecode>(code + prologLength, bce->code().begin(), mainLength);
  1.2458 +    CopySrcNotes(bce, (jssrcnote *)(code + script->length()), nsrcnotes);
  1.2459 +    InitAtomMap(bce->atomIndices.getMap(), ssd->atoms());
  1.2460 +
  1.2461 +    if (!SaveSharedScriptData(cx, script, ssd, nsrcnotes))
  1.2462 +        return false;
  1.2463 +
  1.2464 +    FunctionBox *funbox = bce->sc->isFunctionBox() ? bce->sc->asFunctionBox() : nullptr;
  1.2465 +
  1.2466 +    if (bce->constList.length() != 0)
  1.2467 +        bce->constList.finish(script->consts());
  1.2468 +    if (bce->objectList.length != 0)
  1.2469 +        bce->objectList.finish(script->objects());
  1.2470 +    if (bce->regexpList.length != 0)
  1.2471 +        bce->regexpList.finish(script->regexps());
  1.2472 +    if (bce->tryNoteList.length() != 0)
  1.2473 +        bce->tryNoteList.finish(script->trynotes());
  1.2474 +    if (bce->blockScopeList.length() != 0)
  1.2475 +        bce->blockScopeList.finish(script->blockScopes());
  1.2476 +    script->strict_ = bce->sc->strict;
  1.2477 +    script->explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
  1.2478 +    script->bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
  1.2479 +    script->funHasExtensibleScope_ = funbox ? funbox->hasExtensibleScope() : false;
  1.2480 +    script->funNeedsDeclEnvObject_ = funbox ? funbox->needsDeclEnvObject() : false;
  1.2481 +    script->hasSingletons_ = bce->hasSingletons;
  1.2482 +
  1.2483 +    if (funbox) {
  1.2484 +        if (funbox->argumentsHasLocalBinding()) {
  1.2485 +            // This must precede the script->bindings.transfer() call below
  1.2486 +            script->setArgumentsHasVarBinding();
  1.2487 +            if (funbox->definitelyNeedsArgsObj())
  1.2488 +                script->setNeedsArgsObj(true);
  1.2489 +        } else {
  1.2490 +            JS_ASSERT(!funbox->definitelyNeedsArgsObj());
  1.2491 +        }
  1.2492 +
  1.2493 +        script->funLength_ = funbox->length;
  1.2494 +    }
  1.2495 +
  1.2496 +    RootedFunction fun(cx, nullptr);
  1.2497 +    if (funbox) {
  1.2498 +        JS_ASSERT(!bce->script->noScriptRval());
  1.2499 +        script->isGeneratorExp_ = funbox->inGenexpLambda;
  1.2500 +        script->setGeneratorKind(funbox->generatorKind());
  1.2501 +        script->setFunction(funbox->function());
  1.2502 +    }
  1.2503 +
  1.2504 +    // The call to nfixed() depends on the above setFunction() call.
  1.2505 +    if (UINT32_MAX - script->nfixed() < bce->maxStackDepth) {
  1.2506 +        bce->reportError(nullptr, JSMSG_NEED_DIET, "script");
  1.2507 +        return false;
  1.2508 +    }
  1.2509 +    script->nslots_ = script->nfixed() + bce->maxStackDepth;
  1.2510 +
  1.2511 +    for (unsigned i = 0, n = script->bindings.numArgs(); i < n; ++i) {
  1.2512 +        if (script->formalIsAliased(i)) {
  1.2513 +            script->funHasAnyAliasedFormal_ = true;
  1.2514 +            break;
  1.2515 +        }
  1.2516 +    }
  1.2517 +
  1.2518 +    return true;
  1.2519 +}
  1.2520 +
  1.2521 +size_t
  1.2522 +JSScript::computedSizeOfData() const
  1.2523 +{
  1.2524 +    return dataSize();
  1.2525 +}
  1.2526 +
  1.2527 +size_t
  1.2528 +JSScript::sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const
  1.2529 +{
  1.2530 +    return mallocSizeOf(data);
  1.2531 +}
  1.2532 +
  1.2533 +size_t
  1.2534 +JSScript::sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const
  1.2535 +{
  1.2536 +    return types->sizeOfIncludingThis(mallocSizeOf);
  1.2537 +}
  1.2538 +
  1.2539 +/*
  1.2540 + * Nb: srcnotes are variable-length.  This function computes the number of
  1.2541 + * srcnote *slots*, which may be greater than the number of srcnotes.
  1.2542 + */
  1.2543 +uint32_t
  1.2544 +JSScript::numNotes()
  1.2545 +{
  1.2546 +    jssrcnote *sn;
  1.2547 +    jssrcnote *notes_ = notes();
  1.2548 +    for (sn = notes_; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
  1.2549 +        continue;
  1.2550 +    return sn - notes_ + 1;    /* +1 for the terminator */
  1.2551 +}
  1.2552 +
  1.2553 +js::GlobalObject&
  1.2554 +JSScript::uninlinedGlobal() const
  1.2555 +{
  1.2556 +    return global();
  1.2557 +}
  1.2558 +
  1.2559 +void
  1.2560 +js::CallNewScriptHook(JSContext *cx, HandleScript script, HandleFunction fun)
  1.2561 +{
  1.2562 +    if (script->selfHosted())
  1.2563 +        return;
  1.2564 +
  1.2565 +    JS_ASSERT(!script->isActiveEval());
  1.2566 +    if (JSNewScriptHook hook = cx->runtime()->debugHooks.newScriptHook) {
  1.2567 +        AutoKeepAtoms keepAtoms(cx->perThreadData);
  1.2568 +        hook(cx, script->filename(), script->lineno(), script, fun,
  1.2569 +             cx->runtime()->debugHooks.newScriptHookData);
  1.2570 +    }
  1.2571 +}
  1.2572 +
  1.2573 +void
  1.2574 +js::CallDestroyScriptHook(FreeOp *fop, JSScript *script)
  1.2575 +{
  1.2576 +    if (script->selfHosted())
  1.2577 +        return;
  1.2578 +
  1.2579 +    // The hook will only call into JS if a GC is not running.
  1.2580 +    if (JSDestroyScriptHook hook = fop->runtime()->debugHooks.destroyScriptHook)
  1.2581 +        hook(fop, script, fop->runtime()->debugHooks.destroyScriptHookData);
  1.2582 +    script->clearTraps(fop);
  1.2583 +}
  1.2584 +
  1.2585 +void
  1.2586 +JSScript::finalize(FreeOp *fop)
  1.2587 +{
  1.2588 +    // NOTE: this JSScript may be partially initialized at this point.  E.g. we
  1.2589 +    // may have created it and partially initialized it with
  1.2590 +    // JSScript::Create(), but not yet finished initializing it with
  1.2591 +    // fullyInitFromEmitter() or fullyInitTrivial().
  1.2592 +
  1.2593 +    CallDestroyScriptHook(fop, this);
  1.2594 +    fop->runtime()->spsProfiler.onScriptFinalized(this);
  1.2595 +
  1.2596 +    if (types)
  1.2597 +        types->destroy();
  1.2598 +
  1.2599 +#ifdef JS_ION
  1.2600 +    jit::DestroyIonScripts(fop, this);
  1.2601 +#endif
  1.2602 +
  1.2603 +    destroyScriptCounts(fop);
  1.2604 +    destroyDebugScript(fop);
  1.2605 +
  1.2606 +    if (data) {
  1.2607 +        JS_POISON(data, 0xdb, computedSizeOfData());
  1.2608 +        fop->free_(data);
  1.2609 +    }
  1.2610 +
  1.2611 +    fop->runtime()->lazyScriptCache.remove(this);
  1.2612 +}
  1.2613 +
  1.2614 +static const uint32_t GSN_CACHE_THRESHOLD = 100;
  1.2615 +
  1.2616 +void
  1.2617 +GSNCache::purge()
  1.2618 +{
  1.2619 +    code = nullptr;
  1.2620 +    if (map.initialized())
  1.2621 +        map.finish();
  1.2622 +}
  1.2623 +
  1.2624 +jssrcnote *
  1.2625 +js::GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc)
  1.2626 +{
  1.2627 +    size_t target = pc - script->code();
  1.2628 +    if (target >= script->length())
  1.2629 +        return nullptr;
  1.2630 +
  1.2631 +    if (cache.code == script->code()) {
  1.2632 +        JS_ASSERT(cache.map.initialized());
  1.2633 +        GSNCache::Map::Ptr p = cache.map.lookup(pc);
  1.2634 +        return p ? p->value() : nullptr;
  1.2635 +    }
  1.2636 +
  1.2637 +    size_t offset = 0;
  1.2638 +    jssrcnote *result;
  1.2639 +    for (jssrcnote *sn = script->notes(); ; sn = SN_NEXT(sn)) {
  1.2640 +        if (SN_IS_TERMINATOR(sn)) {
  1.2641 +            result = nullptr;
  1.2642 +            break;
  1.2643 +        }
  1.2644 +        offset += SN_DELTA(sn);
  1.2645 +        if (offset == target && SN_IS_GETTABLE(sn)) {
  1.2646 +            result = sn;
  1.2647 +            break;
  1.2648 +        }
  1.2649 +    }
  1.2650 +
  1.2651 +    if (cache.code != script->code() && script->length() >= GSN_CACHE_THRESHOLD) {
  1.2652 +        unsigned nsrcnotes = 0;
  1.2653 +        for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn);
  1.2654 +             sn = SN_NEXT(sn)) {
  1.2655 +            if (SN_IS_GETTABLE(sn))
  1.2656 +                ++nsrcnotes;
  1.2657 +        }
  1.2658 +        if (cache.code) {
  1.2659 +            JS_ASSERT(cache.map.initialized());
  1.2660 +            cache.map.finish();
  1.2661 +            cache.code = nullptr;
  1.2662 +        }
  1.2663 +        if (cache.map.init(nsrcnotes)) {
  1.2664 +            pc = script->code();
  1.2665 +            for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn);
  1.2666 +                 sn = SN_NEXT(sn)) {
  1.2667 +                pc += SN_DELTA(sn);
  1.2668 +                if (SN_IS_GETTABLE(sn))
  1.2669 +                    JS_ALWAYS_TRUE(cache.map.put(pc, sn));
  1.2670 +            }
  1.2671 +            cache.code = script->code();
  1.2672 +        }
  1.2673 +    }
  1.2674 +
  1.2675 +    return result;
  1.2676 +}
  1.2677 +
  1.2678 +jssrcnote *
  1.2679 +js_GetSrcNote(JSContext *cx, JSScript *script, jsbytecode *pc)
  1.2680 +{
  1.2681 +    return GetSrcNote(cx->runtime()->gsnCache, script, pc);
  1.2682 +}
  1.2683 +
  1.2684 +unsigned
  1.2685 +js::PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc,
  1.2686 +                   unsigned *columnp)
  1.2687 +{
  1.2688 +    unsigned lineno = startLine;
  1.2689 +    unsigned column = 0;
  1.2690 +
  1.2691 +    /*
  1.2692 +     * Walk through source notes accumulating their deltas, keeping track of
  1.2693 +     * line-number notes, until we pass the note for pc's offset within
  1.2694 +     * script->code.
  1.2695 +     */
  1.2696 +    ptrdiff_t offset = 0;
  1.2697 +    ptrdiff_t target = pc - code;
  1.2698 +    for (jssrcnote *sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
  1.2699 +        offset += SN_DELTA(sn);
  1.2700 +        SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
  1.2701 +        if (type == SRC_SETLINE) {
  1.2702 +            if (offset <= target)
  1.2703 +                lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
  1.2704 +            column = 0;
  1.2705 +        } else if (type == SRC_NEWLINE) {
  1.2706 +            if (offset <= target)
  1.2707 +                lineno++;
  1.2708 +            column = 0;
  1.2709 +        }
  1.2710 +
  1.2711 +        if (offset > target)
  1.2712 +            break;
  1.2713 +
  1.2714 +        if (type == SRC_COLSPAN) {
  1.2715 +            ptrdiff_t colspan = js_GetSrcNoteOffset(sn, 0);
  1.2716 +
  1.2717 +            if (colspan >= SN_COLSPAN_DOMAIN / 2)
  1.2718 +                colspan -= SN_COLSPAN_DOMAIN;
  1.2719 +            JS_ASSERT(ptrdiff_t(column) + colspan >= 0);
  1.2720 +            column += colspan;
  1.2721 +        }
  1.2722 +    }
  1.2723 +
  1.2724 +    if (columnp)
  1.2725 +        *columnp = column;
  1.2726 +
  1.2727 +    return lineno;
  1.2728 +}
  1.2729 +
  1.2730 +unsigned
  1.2731 +js::PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp)
  1.2732 +{
  1.2733 +    /* Cope with InterpreterFrame.pc value prior to entering Interpret. */
  1.2734 +    if (!pc)
  1.2735 +        return 0;
  1.2736 +
  1.2737 +    return PCToLineNumber(script->lineno(), script->notes(), script->code(), pc, columnp);
  1.2738 +}
  1.2739 +
  1.2740 +jsbytecode *
  1.2741 +js_LineNumberToPC(JSScript *script, unsigned target)
  1.2742 +{
  1.2743 +    ptrdiff_t offset = 0;
  1.2744 +    ptrdiff_t best = -1;
  1.2745 +    unsigned lineno = script->lineno();
  1.2746 +    unsigned bestdiff = SN_MAX_OFFSET;
  1.2747 +    for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
  1.2748 +        /*
  1.2749 +         * Exact-match only if offset is not in the prolog; otherwise use
  1.2750 +         * nearest greater-or-equal line number match.
  1.2751 +         */
  1.2752 +        if (lineno == target && offset >= ptrdiff_t(script->mainOffset()))
  1.2753 +            goto out;
  1.2754 +        if (lineno >= target) {
  1.2755 +            unsigned diff = lineno - target;
  1.2756 +            if (diff < bestdiff) {
  1.2757 +                bestdiff = diff;
  1.2758 +                best = offset;
  1.2759 +            }
  1.2760 +        }
  1.2761 +        offset += SN_DELTA(sn);
  1.2762 +        SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
  1.2763 +        if (type == SRC_SETLINE) {
  1.2764 +            lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
  1.2765 +        } else if (type == SRC_NEWLINE) {
  1.2766 +            lineno++;
  1.2767 +        }
  1.2768 +    }
  1.2769 +    if (best >= 0)
  1.2770 +        offset = best;
  1.2771 +out:
  1.2772 +    return script->offsetToPC(offset);
  1.2773 +}
  1.2774 +
  1.2775 +JS_FRIEND_API(unsigned)
  1.2776 +js_GetScriptLineExtent(JSScript *script)
  1.2777 +{
  1.2778 +    unsigned lineno = script->lineno();
  1.2779 +    unsigned maxLineNo = lineno;
  1.2780 +    for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
  1.2781 +        SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
  1.2782 +        if (type == SRC_SETLINE)
  1.2783 +            lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
  1.2784 +        else if (type == SRC_NEWLINE)
  1.2785 +            lineno++;
  1.2786 +
  1.2787 +        if (maxLineNo < lineno)
  1.2788 +            maxLineNo = lineno;
  1.2789 +    }
  1.2790 +
  1.2791 +    return 1 + maxLineNo - script->lineno();
  1.2792 +}
  1.2793 +
  1.2794 +void
  1.2795 +js::DescribeScriptedCallerForCompilation(JSContext *cx, MutableHandleScript maybeScript,
  1.2796 +                                         const char **file, unsigned *linenop,
  1.2797 +                                         uint32_t *pcOffset, JSPrincipals **origin,
  1.2798 +                                         LineOption opt)
  1.2799 +{
  1.2800 +    if (opt == CALLED_FROM_JSOP_EVAL) {
  1.2801 +        jsbytecode *pc = nullptr;
  1.2802 +        maybeScript.set(cx->currentScript(&pc));
  1.2803 +        JS_ASSERT(JSOp(*pc) == JSOP_EVAL || JSOp(*pc) == JSOP_SPREADEVAL);
  1.2804 +        JS_ASSERT(*(pc + (JSOp(*pc) == JSOP_EVAL ? JSOP_EVAL_LENGTH
  1.2805 +                                                 : JSOP_SPREADEVAL_LENGTH)) == JSOP_LINENO);
  1.2806 +        *file = maybeScript->filename();
  1.2807 +        *linenop = GET_UINT16(pc + (JSOp(*pc) == JSOP_EVAL ? JSOP_EVAL_LENGTH
  1.2808 +                                                           : JSOP_SPREADEVAL_LENGTH));
  1.2809 +        *pcOffset = pc - maybeScript->code();
  1.2810 +        *origin = maybeScript->originPrincipals();
  1.2811 +        return;
  1.2812 +    }
  1.2813 +
  1.2814 +    NonBuiltinFrameIter iter(cx);
  1.2815 +
  1.2816 +    if (iter.done()) {
  1.2817 +        maybeScript.set(nullptr);
  1.2818 +        *file = nullptr;
  1.2819 +        *linenop = 0;
  1.2820 +        *pcOffset = 0;
  1.2821 +        *origin = cx->compartment()->principals;
  1.2822 +        return;
  1.2823 +    }
  1.2824 +
  1.2825 +    *file = iter.scriptFilename();
  1.2826 +    *linenop = iter.computeLine();
  1.2827 +    *origin = iter.originPrincipals();
  1.2828 +
  1.2829 +    // These values are only used for introducer fields which are debugging
  1.2830 +    // information and can be safely left null for asm.js frames.
  1.2831 +    if (iter.hasScript()) {
  1.2832 +        maybeScript.set(iter.script());
  1.2833 +        *pcOffset = iter.pc() - maybeScript->code();
  1.2834 +    } else {
  1.2835 +        maybeScript.set(nullptr);
  1.2836 +        *pcOffset = 0;
  1.2837 +    }
  1.2838 +}
  1.2839 +
  1.2840 +template <class T>
  1.2841 +static inline T *
  1.2842 +Rebase(JSScript *dst, JSScript *src, T *srcp)
  1.2843 +{
  1.2844 +    size_t off = reinterpret_cast<uint8_t *>(srcp) - src->data;
  1.2845 +    return reinterpret_cast<T *>(dst->data + off);
  1.2846 +}
  1.2847 +
  1.2848 +JSScript *
  1.2849 +js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, HandleScript src,
  1.2850 +                NewObjectKind newKind /* = GenericObject */)
  1.2851 +{
  1.2852 +    /* NB: Keep this in sync with XDRScript. */
  1.2853 +
  1.2854 +    /* Some embeddings are not careful to use ExposeObjectToActiveJS as needed. */
  1.2855 +    JS_ASSERT(!src->sourceObject()->isMarked(gc::GRAY));
  1.2856 +
  1.2857 +    uint32_t nconsts   = src->hasConsts()   ? src->consts()->length   : 0;
  1.2858 +    uint32_t nobjects  = src->hasObjects()  ? src->objects()->length  : 0;
  1.2859 +    uint32_t nregexps  = src->hasRegexps()  ? src->regexps()->length  : 0;
  1.2860 +    uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
  1.2861 +    uint32_t nblockscopes = src->hasBlockScopes() ? src->blockScopes()->length : 0;
  1.2862 +
  1.2863 +    /* Script data */
  1.2864 +
  1.2865 +    size_t size = src->dataSize();
  1.2866 +    uint8_t *data = AllocScriptData(cx, size);
  1.2867 +    if (!data)
  1.2868 +        return nullptr;
  1.2869 +
  1.2870 +    /* Bindings */
  1.2871 +
  1.2872 +    Rooted<Bindings> bindings(cx);
  1.2873 +    InternalHandle<Bindings*> bindingsHandle =
  1.2874 +        InternalHandle<Bindings*>::fromMarkedLocation(bindings.address());
  1.2875 +    if (!Bindings::clone(cx, bindingsHandle, data, src))
  1.2876 +        return nullptr;
  1.2877 +
  1.2878 +    /* Objects */
  1.2879 +
  1.2880 +    AutoObjectVector objects(cx);
  1.2881 +    if (nobjects != 0) {
  1.2882 +        HeapPtrObject *vector = src->objects()->vector;
  1.2883 +        for (unsigned i = 0; i < nobjects; i++) {
  1.2884 +            RootedObject obj(cx, vector[i]);
  1.2885 +            RootedObject clone(cx);
  1.2886 +            if (obj->is<NestedScopeObject>()) {
  1.2887 +                Rooted<NestedScopeObject*> innerBlock(cx, &obj->as<NestedScopeObject>());
  1.2888 +
  1.2889 +                RootedObject enclosingScope(cx);
  1.2890 +                if (NestedScopeObject *enclosingBlock = innerBlock->enclosingNestedScope())
  1.2891 +                    enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)];
  1.2892 +                else
  1.2893 +                    enclosingScope = fun;
  1.2894 +
  1.2895 +                clone = CloneNestedScopeObject(cx, enclosingScope, innerBlock);
  1.2896 +            } else if (obj->is<JSFunction>()) {
  1.2897 +                RootedFunction innerFun(cx, &obj->as<JSFunction>());
  1.2898 +                if (innerFun->isNative()) {
  1.2899 +                    assertSameCompartment(cx, innerFun);
  1.2900 +                    clone = innerFun;
  1.2901 +                } else {
  1.2902 +                    if (innerFun->isInterpretedLazy()) {
  1.2903 +                        AutoCompartment ac(cx, innerFun);
  1.2904 +                        if (!innerFun->getOrCreateScript(cx))
  1.2905 +                            return nullptr;
  1.2906 +                    }
  1.2907 +                    RootedObject staticScope(cx, innerFun->nonLazyScript()->enclosingStaticScope());
  1.2908 +                    StaticScopeIter<CanGC> ssi(cx, staticScope);
  1.2909 +                    RootedObject enclosingScope(cx);
  1.2910 +                    if (ssi.done() || ssi.type() == StaticScopeIter<CanGC>::FUNCTION)
  1.2911 +                        enclosingScope = fun;
  1.2912 +                    else if (ssi.type() == StaticScopeIter<CanGC>::BLOCK)
  1.2913 +                        enclosingScope = objects[FindScopeObjectIndex(src, ssi.block())];
  1.2914 +                    else
  1.2915 +                        enclosingScope = objects[FindScopeObjectIndex(src, ssi.staticWith())];
  1.2916 +
  1.2917 +                    clone = CloneFunctionAndScript(cx, enclosingScope, innerFun);
  1.2918 +                }
  1.2919 +            } else {
  1.2920 +                /*
  1.2921 +                 * Clone object literals emitted for the JSOP_NEWOBJECT opcode. We only emit that
  1.2922 +                 * instead of the less-optimized JSOP_NEWINIT for self-hosted code or code compiled
  1.2923 +                 * with JSOPTION_COMPILE_N_GO set. As we don't clone the latter type of code, this
  1.2924 +                 * case should only ever be hit when cloning objects from self-hosted code.
  1.2925 +                 */
  1.2926 +                clone = CloneObjectLiteral(cx, cx->global(), obj);
  1.2927 +            }
  1.2928 +            if (!clone || !objects.append(clone))
  1.2929 +                return nullptr;
  1.2930 +        }
  1.2931 +    }
  1.2932 +
  1.2933 +    /* RegExps */
  1.2934 +
  1.2935 +    AutoObjectVector regexps(cx);
  1.2936 +    for (unsigned i = 0; i < nregexps; i++) {
  1.2937 +        HeapPtrObject *vector = src->regexps()->vector;
  1.2938 +        for (unsigned i = 0; i < nregexps; i++) {
  1.2939 +            JSObject *clone = CloneScriptRegExpObject(cx, vector[i]->as<RegExpObject>());
  1.2940 +            if (!clone || !regexps.append(clone))
  1.2941 +                return nullptr;
  1.2942 +        }
  1.2943 +    }
  1.2944 +
  1.2945 +    /*
  1.2946 +     * Wrap the script source object as needed. Self-hosted scripts may be
  1.2947 +     * in another runtime, so lazily create a new script source object to
  1.2948 +     * use for them.
  1.2949 +     */
  1.2950 +    RootedObject sourceObject(cx);
  1.2951 +    if (cx->runtime()->isSelfHostingCompartment(src->compartment())) {
  1.2952 +        if (!cx->compartment()->selfHostingScriptSource) {
  1.2953 +            CompileOptions options(cx);
  1.2954 +            FillSelfHostingCompileOptions(options);
  1.2955 +
  1.2956 +            ScriptSourceObject *obj = frontend::CreateScriptSourceObject(cx, options);
  1.2957 +            if (!obj)
  1.2958 +                return nullptr;
  1.2959 +            cx->compartment()->selfHostingScriptSource = obj;
  1.2960 +        }
  1.2961 +        sourceObject = cx->compartment()->selfHostingScriptSource;
  1.2962 +    } else {
  1.2963 +        sourceObject = src->sourceObject();
  1.2964 +        if (!cx->compartment()->wrap(cx, &sourceObject))
  1.2965 +            return nullptr;
  1.2966 +    }
  1.2967 +
  1.2968 +    /* Now that all fallible allocation is complete, create the GC thing. */
  1.2969 +
  1.2970 +    CompileOptions options(cx);
  1.2971 +    options.setOriginPrincipals(src->originPrincipals())
  1.2972 +           .setCompileAndGo(src->compileAndGo())
  1.2973 +           .setSelfHostingMode(src->selfHosted())
  1.2974 +           .setNoScriptRval(src->noScriptRval())
  1.2975 +           .setVersion(src->getVersion());
  1.2976 +
  1.2977 +    RootedScript dst(cx, JSScript::Create(cx, enclosingScope, src->savedCallerFun(),
  1.2978 +                                          options, src->staticLevel(),
  1.2979 +                                          sourceObject, src->sourceStart(), src->sourceEnd()));
  1.2980 +    if (!dst) {
  1.2981 +        js_free(data);
  1.2982 +        return nullptr;
  1.2983 +    }
  1.2984 +
  1.2985 +    dst->bindings = bindings;
  1.2986 +
  1.2987 +    /* This assignment must occur before all the Rebase calls. */
  1.2988 +    dst->data = data;
  1.2989 +    dst->dataSize_ = size;
  1.2990 +    memcpy(data, src->data, size);
  1.2991 +
  1.2992 +    /* Script filenames, bytecodes and atoms are runtime-wide. */
  1.2993 +    dst->setCode(src->code());
  1.2994 +    dst->atoms = src->atoms;
  1.2995 +
  1.2996 +    dst->setLength(src->length());
  1.2997 +    dst->lineno_ = src->lineno();
  1.2998 +    dst->mainOffset_ = src->mainOffset();
  1.2999 +    dst->natoms_ = src->natoms();
  1.3000 +    dst->funLength_ = src->funLength();
  1.3001 +    dst->nTypeSets_ = src->nTypeSets();
  1.3002 +    dst->nslots_ = src->nslots();
  1.3003 +    if (src->argumentsHasVarBinding()) {
  1.3004 +        dst->setArgumentsHasVarBinding();
  1.3005 +        if (src->analyzedArgsUsage())
  1.3006 +            dst->setNeedsArgsObj(src->needsArgsObj());
  1.3007 +    }
  1.3008 +    dst->cloneHasArray(src);
  1.3009 +    dst->strict_ = src->strict();
  1.3010 +    dst->explicitUseStrict_ = src->explicitUseStrict();
  1.3011 +    dst->bindingsAccessedDynamically_ = src->bindingsAccessedDynamically();
  1.3012 +    dst->funHasExtensibleScope_ = src->funHasExtensibleScope();
  1.3013 +    dst->funNeedsDeclEnvObject_ = src->funNeedsDeclEnvObject();
  1.3014 +    dst->funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
  1.3015 +    dst->hasSingletons_ = src->hasSingletons();
  1.3016 +    dst->treatAsRunOnce_ = src->treatAsRunOnce();
  1.3017 +    dst->isGeneratorExp_ = src->isGeneratorExp();
  1.3018 +    dst->setGeneratorKind(src->generatorKind());
  1.3019 +
  1.3020 +    /* Copy over hints. */
  1.3021 +    dst->shouldInline_ = src->shouldInline();
  1.3022 +    dst->shouldCloneAtCallsite_ = src->shouldCloneAtCallsite();
  1.3023 +    dst->isCallsiteClone_ = src->isCallsiteClone();
  1.3024 +
  1.3025 +    if (nconsts != 0) {
  1.3026 +        HeapValue *vector = Rebase<HeapValue>(dst, src, src->consts()->vector);
  1.3027 +        dst->consts()->vector = vector;
  1.3028 +        for (unsigned i = 0; i < nconsts; ++i)
  1.3029 +            JS_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom());
  1.3030 +    }
  1.3031 +    if (nobjects != 0) {
  1.3032 +        HeapPtrObject *vector = Rebase<HeapPtr<JSObject> >(dst, src, src->objects()->vector);
  1.3033 +        dst->objects()->vector = vector;
  1.3034 +        for (unsigned i = 0; i < nobjects; ++i)
  1.3035 +            vector[i].init(objects[i]);
  1.3036 +    }
  1.3037 +    if (nregexps != 0) {
  1.3038 +        HeapPtrObject *vector = Rebase<HeapPtr<JSObject> >(dst, src, src->regexps()->vector);
  1.3039 +        dst->regexps()->vector = vector;
  1.3040 +        for (unsigned i = 0; i < nregexps; ++i)
  1.3041 +            vector[i].init(regexps[i]);
  1.3042 +    }
  1.3043 +    if (ntrynotes != 0)
  1.3044 +        dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
  1.3045 +    if (nblockscopes != 0)
  1.3046 +        dst->blockScopes()->vector = Rebase<BlockScopeNote>(dst, src, src->blockScopes()->vector);
  1.3047 +
  1.3048 +    return dst;
  1.3049 +}
  1.3050 +
  1.3051 +bool
  1.3052 +js::CloneFunctionScript(JSContext *cx, HandleFunction original, HandleFunction clone,
  1.3053 +                        NewObjectKind newKind /* = GenericObject */)
  1.3054 +{
  1.3055 +    JS_ASSERT(clone->isInterpreted());
  1.3056 +
  1.3057 +    RootedScript script(cx, clone->nonLazyScript());
  1.3058 +    JS_ASSERT(script);
  1.3059 +    JS_ASSERT(script->compartment() == original->compartment());
  1.3060 +    JS_ASSERT_IF(script->compartment() != cx->compartment(),
  1.3061 +                 !script->enclosingStaticScope());
  1.3062 +
  1.3063 +    RootedObject scope(cx, script->enclosingStaticScope());
  1.3064 +
  1.3065 +    clone->mutableScript().init(nullptr);
  1.3066 +
  1.3067 +    JSScript *cscript = CloneScript(cx, scope, clone, script, newKind);
  1.3068 +    if (!cscript)
  1.3069 +        return false;
  1.3070 +
  1.3071 +    clone->setScript(cscript);
  1.3072 +    cscript->setFunction(clone);
  1.3073 +
  1.3074 +    script = clone->nonLazyScript();
  1.3075 +    CallNewScriptHook(cx, script, clone);
  1.3076 +    RootedGlobalObject global(cx, script->compileAndGo() ? &script->global() : nullptr);
  1.3077 +    Debugger::onNewScript(cx, script, global);
  1.3078 +
  1.3079 +    return true;
  1.3080 +}
  1.3081 +
  1.3082 +DebugScript *
  1.3083 +JSScript::debugScript()
  1.3084 +{
  1.3085 +    JS_ASSERT(hasDebugScript_);
  1.3086 +    DebugScriptMap *map = compartment()->debugScriptMap;
  1.3087 +    JS_ASSERT(map);
  1.3088 +    DebugScriptMap::Ptr p = map->lookup(this);
  1.3089 +    JS_ASSERT(p);
  1.3090 +    return p->value();
  1.3091 +}
  1.3092 +
  1.3093 +DebugScript *
  1.3094 +JSScript::releaseDebugScript()
  1.3095 +{
  1.3096 +    JS_ASSERT(hasDebugScript_);
  1.3097 +    DebugScriptMap *map = compartment()->debugScriptMap;
  1.3098 +    JS_ASSERT(map);
  1.3099 +    DebugScriptMap::Ptr p = map->lookup(this);
  1.3100 +    JS_ASSERT(p);
  1.3101 +    DebugScript *debug = p->value();
  1.3102 +    map->remove(p);
  1.3103 +    hasDebugScript_ = false;
  1.3104 +    return debug;
  1.3105 +}
  1.3106 +
  1.3107 +void
  1.3108 +JSScript::destroyDebugScript(FreeOp *fop)
  1.3109 +{
  1.3110 +    if (hasDebugScript_) {
  1.3111 +        for (jsbytecode *pc = code(); pc < codeEnd(); pc++) {
  1.3112 +            if (BreakpointSite *site = getBreakpointSite(pc)) {
  1.3113 +                /* Breakpoints are swept before finalization. */
  1.3114 +                JS_ASSERT(site->firstBreakpoint() == nullptr);
  1.3115 +                site->clearTrap(fop, nullptr, nullptr);
  1.3116 +                JS_ASSERT(getBreakpointSite(pc) == nullptr);
  1.3117 +            }
  1.3118 +        }
  1.3119 +        fop->free_(releaseDebugScript());
  1.3120 +    }
  1.3121 +}
  1.3122 +
  1.3123 +bool
  1.3124 +JSScript::ensureHasDebugScript(JSContext *cx)
  1.3125 +{
  1.3126 +    if (hasDebugScript_)
  1.3127 +        return true;
  1.3128 +
  1.3129 +    size_t nbytes = offsetof(DebugScript, breakpoints) + length() * sizeof(BreakpointSite*);
  1.3130 +    DebugScript *debug = (DebugScript *) cx->calloc_(nbytes);
  1.3131 +    if (!debug)
  1.3132 +        return false;
  1.3133 +
  1.3134 +    /* Create compartment's debugScriptMap if necessary. */
  1.3135 +    DebugScriptMap *map = compartment()->debugScriptMap;
  1.3136 +    if (!map) {
  1.3137 +        map = cx->new_<DebugScriptMap>();
  1.3138 +        if (!map || !map->init()) {
  1.3139 +            js_free(debug);
  1.3140 +            js_delete(map);
  1.3141 +            return false;
  1.3142 +        }
  1.3143 +        compartment()->debugScriptMap = map;
  1.3144 +    }
  1.3145 +
  1.3146 +    if (!map->putNew(this, debug)) {
  1.3147 +        js_free(debug);
  1.3148 +        return false;
  1.3149 +    }
  1.3150 +    hasDebugScript_ = true; // safe to set this;  we can't fail after this point
  1.3151 +
  1.3152 +    /*
  1.3153 +     * Ensure that any Interpret() instances running on this script have
  1.3154 +     * interrupts enabled. The interrupts must stay enabled until the
  1.3155 +     * debug state is destroyed.
  1.3156 +     */
  1.3157 +    for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
  1.3158 +        if (iter->isInterpreter())
  1.3159 +            iter->asInterpreter()->enableInterruptsIfRunning(this);
  1.3160 +    }
  1.3161 +
  1.3162 +    return true;
  1.3163 +}
  1.3164 +
  1.3165 +void
  1.3166 +JSScript::setNewStepMode(FreeOp *fop, uint32_t newValue)
  1.3167 +{
  1.3168 +    DebugScript *debug = debugScript();
  1.3169 +    uint32_t prior = debug->stepMode;
  1.3170 +    debug->stepMode = newValue;
  1.3171 +
  1.3172 +    if (!prior != !newValue) {
  1.3173 +#ifdef JS_ION
  1.3174 +        if (hasBaselineScript())
  1.3175 +            baseline->toggleDebugTraps(this, nullptr);
  1.3176 +#endif
  1.3177 +
  1.3178 +        if (!stepModeEnabled() && !debug->numSites)
  1.3179 +            fop->free_(releaseDebugScript());
  1.3180 +    }
  1.3181 +}
  1.3182 +
  1.3183 +bool
  1.3184 +JSScript::setStepModeFlag(JSContext *cx, bool step)
  1.3185 +{
  1.3186 +    if (!ensureHasDebugScript(cx))
  1.3187 +        return false;
  1.3188 +
  1.3189 +    setNewStepMode(cx->runtime()->defaultFreeOp(),
  1.3190 +                   (debugScript()->stepMode & stepCountMask) |
  1.3191 +                   (step ? stepFlagMask : 0));
  1.3192 +    return true;
  1.3193 +}
  1.3194 +
  1.3195 +bool
  1.3196 +JSScript::incrementStepModeCount(JSContext *cx)
  1.3197 +{
  1.3198 +    assertSameCompartment(cx, this);
  1.3199 +    MOZ_ASSERT(cx->compartment()->debugMode());
  1.3200 +
  1.3201 +    if (!ensureHasDebugScript(cx))
  1.3202 +        return false;
  1.3203 +
  1.3204 +    DebugScript *debug = debugScript();
  1.3205 +    uint32_t count = debug->stepMode & stepCountMask;
  1.3206 +    MOZ_ASSERT(((count + 1) & stepCountMask) == count + 1);
  1.3207 +
  1.3208 +    setNewStepMode(cx->runtime()->defaultFreeOp(),
  1.3209 +                   (debug->stepMode & stepFlagMask) |
  1.3210 +                   ((count + 1) & stepCountMask));
  1.3211 +    return true;
  1.3212 +}
  1.3213 +
  1.3214 +void
  1.3215 +JSScript::decrementStepModeCount(FreeOp *fop)
  1.3216 +{
  1.3217 +    DebugScript *debug = debugScript();
  1.3218 +    uint32_t count = debug->stepMode & stepCountMask;
  1.3219 +
  1.3220 +    setNewStepMode(fop,
  1.3221 +                   (debug->stepMode & stepFlagMask) |
  1.3222 +                   ((count - 1) & stepCountMask));
  1.3223 +}
  1.3224 +
  1.3225 +BreakpointSite *
  1.3226 +JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc)
  1.3227 +{
  1.3228 +    if (!ensureHasDebugScript(cx))
  1.3229 +        return nullptr;
  1.3230 +
  1.3231 +    DebugScript *debug = debugScript();
  1.3232 +    BreakpointSite *&site = debug->breakpoints[pcToOffset(pc)];
  1.3233 +
  1.3234 +    if (!site) {
  1.3235 +        site = cx->runtime()->new_<BreakpointSite>(this, pc);
  1.3236 +        if (!site) {
  1.3237 +            js_ReportOutOfMemory(cx);
  1.3238 +            return nullptr;
  1.3239 +        }
  1.3240 +        debug->numSites++;
  1.3241 +    }
  1.3242 +
  1.3243 +    return site;
  1.3244 +}
  1.3245 +
  1.3246 +void
  1.3247 +JSScript::destroyBreakpointSite(FreeOp *fop, jsbytecode *pc)
  1.3248 +{
  1.3249 +    DebugScript *debug = debugScript();
  1.3250 +    BreakpointSite *&site = debug->breakpoints[pcToOffset(pc)];
  1.3251 +    JS_ASSERT(site);
  1.3252 +
  1.3253 +    fop->delete_(site);
  1.3254 +    site = nullptr;
  1.3255 +
  1.3256 +    if (--debug->numSites == 0 && !stepModeEnabled())
  1.3257 +        fop->free_(releaseDebugScript());
  1.3258 +}
  1.3259 +
  1.3260 +void
  1.3261 +JSScript::clearBreakpointsIn(FreeOp *fop, js::Debugger *dbg, JSObject *handler)
  1.3262 +{
  1.3263 +    if (!hasAnyBreakpointsOrStepMode())
  1.3264 +        return;
  1.3265 +
  1.3266 +    for (jsbytecode *pc = code(); pc < codeEnd(); pc++) {
  1.3267 +        BreakpointSite *site = getBreakpointSite(pc);
  1.3268 +        if (site) {
  1.3269 +            Breakpoint *nextbp;
  1.3270 +            for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
  1.3271 +                nextbp = bp->nextInSite();
  1.3272 +                if ((!dbg || bp->debugger == dbg) && (!handler || bp->getHandler() == handler))
  1.3273 +                    bp->destroy(fop);
  1.3274 +            }
  1.3275 +        }
  1.3276 +    }
  1.3277 +}
  1.3278 +
  1.3279 +bool
  1.3280 +JSScript::hasBreakpointsAt(jsbytecode *pc)
  1.3281 +{
  1.3282 +    BreakpointSite *site = getBreakpointSite(pc);
  1.3283 +    if (!site)
  1.3284 +        return false;
  1.3285 +
  1.3286 +    return site->enabledCount > 0 || site->trapHandler;
  1.3287 +}
  1.3288 +
  1.3289 +void
  1.3290 +JSScript::clearTraps(FreeOp *fop)
  1.3291 +{
  1.3292 +    if (!hasAnyBreakpointsOrStepMode())
  1.3293 +        return;
  1.3294 +
  1.3295 +    for (jsbytecode *pc = code(); pc < codeEnd(); pc++) {
  1.3296 +        BreakpointSite *site = getBreakpointSite(pc);
  1.3297 +        if (site)
  1.3298 +            site->clearTrap(fop);
  1.3299 +    }
  1.3300 +}
  1.3301 +
  1.3302 +void
  1.3303 +JSScript::markChildren(JSTracer *trc)
  1.3304 +{
  1.3305 +    // NOTE: this JSScript may be partially initialized at this point.  E.g. we
  1.3306 +    // may have created it and partially initialized it with
  1.3307 +    // JSScript::Create(), but not yet finished initializing it with
  1.3308 +    // fullyInitFromEmitter() or fullyInitTrivial().
  1.3309 +
  1.3310 +    JS_ASSERT_IF(trc->runtime()->gcStrictCompartmentChecking, zone()->isCollecting());
  1.3311 +
  1.3312 +    for (uint32_t i = 0; i < natoms(); ++i) {
  1.3313 +        if (atoms[i])
  1.3314 +            MarkString(trc, &atoms[i], "atom");
  1.3315 +    }
  1.3316 +
  1.3317 +    if (hasObjects()) {
  1.3318 +        ObjectArray *objarray = objects();
  1.3319 +        MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
  1.3320 +    }
  1.3321 +
  1.3322 +    if (hasRegexps()) {
  1.3323 +        ObjectArray *objarray = regexps();
  1.3324 +        MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
  1.3325 +    }
  1.3326 +
  1.3327 +    if (hasConsts()) {
  1.3328 +        ConstArray *constarray = consts();
  1.3329 +        MarkValueRange(trc, constarray->length, constarray->vector, "consts");
  1.3330 +    }
  1.3331 +
  1.3332 +    if (sourceObject()) {
  1.3333 +        JS_ASSERT(sourceObject()->compartment() == compartment());
  1.3334 +        MarkObject(trc, &sourceObject_, "sourceObject");
  1.3335 +    }
  1.3336 +
  1.3337 +    if (functionNonDelazifying())
  1.3338 +        MarkObject(trc, &function_, "function");
  1.3339 +
  1.3340 +    if (enclosingScopeOrOriginalFunction_)
  1.3341 +        MarkObject(trc, &enclosingScopeOrOriginalFunction_, "enclosing");
  1.3342 +
  1.3343 +    if (maybeLazyScript())
  1.3344 +        MarkLazyScriptUnbarriered(trc, &lazyScript, "lazyScript");
  1.3345 +
  1.3346 +    if (IS_GC_MARKING_TRACER(trc)) {
  1.3347 +        compartment()->mark();
  1.3348 +
  1.3349 +        if (code())
  1.3350 +            MarkScriptData(trc->runtime(), code());
  1.3351 +    }
  1.3352 +
  1.3353 +    bindings.trace(trc);
  1.3354 +
  1.3355 +    if (hasAnyBreakpointsOrStepMode()) {
  1.3356 +        for (unsigned i = 0; i < length(); i++) {
  1.3357 +            BreakpointSite *site = debugScript()->breakpoints[i];
  1.3358 +            if (site && site->trapHandler)
  1.3359 +                MarkValue(trc, &site->trapClosure, "trap closure");
  1.3360 +        }
  1.3361 +    }
  1.3362 +
  1.3363 +#ifdef JS_ION
  1.3364 +    jit::TraceIonScripts(trc, this);
  1.3365 +#endif
  1.3366 +}
  1.3367 +
  1.3368 +void
  1.3369 +LazyScript::markChildren(JSTracer *trc)
  1.3370 +{
  1.3371 +    if (function_)
  1.3372 +        MarkObject(trc, &function_, "function");
  1.3373 +
  1.3374 +    if (sourceObject_)
  1.3375 +        MarkObject(trc, &sourceObject_, "sourceObject");
  1.3376 +
  1.3377 +    if (enclosingScope_)
  1.3378 +        MarkObject(trc, &enclosingScope_, "enclosingScope");
  1.3379 +
  1.3380 +    if (script_)
  1.3381 +        MarkScript(trc, &script_, "realScript");
  1.3382 +
  1.3383 +    HeapPtrAtom *freeVariables = this->freeVariables();
  1.3384 +    for (size_t i = 0; i < numFreeVariables(); i++)
  1.3385 +        MarkString(trc, &freeVariables[i], "lazyScriptFreeVariable");
  1.3386 +
  1.3387 +    HeapPtrFunction *innerFunctions = this->innerFunctions();
  1.3388 +    for (size_t i = 0; i < numInnerFunctions(); i++)
  1.3389 +        MarkObject(trc, &innerFunctions[i], "lazyScriptInnerFunction");
  1.3390 +}
  1.3391 +
  1.3392 +void
  1.3393 +LazyScript::finalize(FreeOp *fop)
  1.3394 +{
  1.3395 +    if (table_)
  1.3396 +        fop->free_(table_);
  1.3397 +}
  1.3398 +
  1.3399 +NestedScopeObject *
  1.3400 +JSScript::getStaticScope(jsbytecode *pc)
  1.3401 +{
  1.3402 +    JS_ASSERT(containsPC(pc));
  1.3403 +
  1.3404 +    if (!hasBlockScopes())
  1.3405 +        return nullptr;
  1.3406 +
  1.3407 +    ptrdiff_t offset = pc - main();
  1.3408 +
  1.3409 +    if (offset < 0)
  1.3410 +        return nullptr;
  1.3411 +
  1.3412 +    BlockScopeArray *scopes = blockScopes();
  1.3413 +    NestedScopeObject *blockChain = nullptr;
  1.3414 +
  1.3415 +    // Find the innermost block chain using a binary search.
  1.3416 +    size_t bottom = 0;
  1.3417 +    size_t top = scopes->length;
  1.3418 +
  1.3419 +    while (bottom < top) {
  1.3420 +        size_t mid = bottom + (top - bottom) / 2;
  1.3421 +        const BlockScopeNote *note = &scopes->vector[mid];
  1.3422 +        if (note->start <= offset) {
  1.3423 +            // Block scopes are ordered in the list by their starting offset, and since
  1.3424 +            // blocks form a tree ones earlier in the list may cover the pc even if
  1.3425 +            // later blocks end before the pc. This only happens when the earlier block
  1.3426 +            // is a parent of the later block, so we need to check parents of |mid| in
  1.3427 +            // the searched range for coverage.
  1.3428 +            size_t check = mid;
  1.3429 +            while (check >= bottom) {
  1.3430 +                const BlockScopeNote *checkNote = &scopes->vector[check];
  1.3431 +                JS_ASSERT(checkNote->start <= offset);
  1.3432 +                if (offset < checkNote->start + checkNote->length) {
  1.3433 +                    // We found a matching block chain but there may be inner ones
  1.3434 +                    // at a higher block chain index than mid. Continue the binary search.
  1.3435 +                    if (checkNote->index == BlockScopeNote::NoBlockScopeIndex)
  1.3436 +                        blockChain = nullptr;
  1.3437 +                    else
  1.3438 +                        blockChain = &getObject(checkNote->index)->as<NestedScopeObject>();
  1.3439 +                    break;
  1.3440 +                }
  1.3441 +                if (checkNote->parent == UINT32_MAX)
  1.3442 +                    break;
  1.3443 +                check = checkNote->parent;
  1.3444 +            }
  1.3445 +            bottom = mid + 1;
  1.3446 +        } else {
  1.3447 +            top = mid;
  1.3448 +        }
  1.3449 +    }
  1.3450 +
  1.3451 +    return blockChain;
  1.3452 +}
  1.3453 +
  1.3454 +void
  1.3455 +JSScript::setArgumentsHasVarBinding()
  1.3456 +{
  1.3457 +    argsHasVarBinding_ = true;
  1.3458 +#ifdef JS_ION
  1.3459 +    needsArgsAnalysis_ = true;
  1.3460 +#else
  1.3461 +    // The arguments analysis is performed by IonBuilder.
  1.3462 +    needsArgsObj_ = true;
  1.3463 +#endif
  1.3464 +}
  1.3465 +
  1.3466 +void
  1.3467 +JSScript::setNeedsArgsObj(bool needsArgsObj)
  1.3468 +{
  1.3469 +    JS_ASSERT_IF(needsArgsObj, argumentsHasVarBinding());
  1.3470 +    needsArgsAnalysis_ = false;
  1.3471 +    needsArgsObj_ = needsArgsObj;
  1.3472 +}
  1.3473 +
  1.3474 +void
  1.3475 +js::SetFrameArgumentsObject(JSContext *cx, AbstractFramePtr frame,
  1.3476 +                            HandleScript script, JSObject *argsobj)
  1.3477 +{
  1.3478 +    /*
  1.3479 +     * Replace any optimized arguments in the frame with an explicit arguments
  1.3480 +     * object. Note that 'arguments' may have already been overwritten.
  1.3481 +     */
  1.3482 +
  1.3483 +    InternalBindingsHandle bindings(script, &script->bindings);
  1.3484 +    const uint32_t var = Bindings::argumentsVarIndex(cx, bindings);
  1.3485 +
  1.3486 +    if (script->varIsAliased(var)) {
  1.3487 +        /*
  1.3488 +         * Scan the script to find the slot in the call object that 'arguments'
  1.3489 +         * is assigned to.
  1.3490 +         */
  1.3491 +        jsbytecode *pc = script->code();
  1.3492 +        while (*pc != JSOP_ARGUMENTS)
  1.3493 +            pc += GetBytecodeLength(pc);
  1.3494 +        pc += JSOP_ARGUMENTS_LENGTH;
  1.3495 +        JS_ASSERT(*pc == JSOP_SETALIASEDVAR);
  1.3496 +
  1.3497 +        // Note that here and below, it is insufficient to only check for
  1.3498 +        // JS_OPTIMIZED_ARGUMENTS, as Ion could have optimized out the
  1.3499 +        // arguments slot.
  1.3500 +        if (IsOptimizedPlaceholderMagicValue(frame.callObj().as<ScopeObject>().aliasedVar(pc)))
  1.3501 +            frame.callObj().as<ScopeObject>().setAliasedVar(cx, pc, cx->names().arguments, ObjectValue(*argsobj));
  1.3502 +    } else {
  1.3503 +        if (IsOptimizedPlaceholderMagicValue(frame.unaliasedLocal(var)))
  1.3504 +            frame.unaliasedLocal(var) = ObjectValue(*argsobj);
  1.3505 +    }
  1.3506 +}
  1.3507 +
  1.3508 +/* static */ bool
  1.3509 +JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
  1.3510 +{
  1.3511 +    JS_ASSERT(script->functionNonDelazifying());
  1.3512 +    JS_ASSERT(script->analyzedArgsUsage());
  1.3513 +    JS_ASSERT(script->argumentsHasVarBinding());
  1.3514 +
  1.3515 +    /*
  1.3516 +     * It is possible that the arguments optimization has already failed,
  1.3517 +     * everything has been fixed up, but there was an outstanding magic value
  1.3518 +     * on the stack that has just now flowed into an apply. In this case, there
  1.3519 +     * is nothing to do; GuardFunApplySpeculation will patch in the real
  1.3520 +     * argsobj.
  1.3521 +     */
  1.3522 +    if (script->needsArgsObj())
  1.3523 +        return true;
  1.3524 +
  1.3525 +    JS_ASSERT(!script->isGenerator());
  1.3526 +
  1.3527 +    script->needsArgsObj_ = true;
  1.3528 +
  1.3529 +#ifdef JS_ION
  1.3530 +    /*
  1.3531 +     * Since we can't invalidate baseline scripts, set a flag that's checked from
  1.3532 +     * JIT code to indicate the arguments optimization failed and JSOP_ARGUMENTS
  1.3533 +     * should create an arguments object next time.
  1.3534 +     */
  1.3535 +    if (script->hasBaselineScript())
  1.3536 +        script->baselineScript()->setNeedsArgsObj();
  1.3537 +#endif
  1.3538 +
  1.3539 +    /*
  1.3540 +     * By design, the arguments optimization is only made when there are no
  1.3541 +     * outstanding cases of MagicValue(JS_OPTIMIZED_ARGUMENTS) at any points
  1.3542 +     * where the optimization could fail, other than an active invocation of
  1.3543 +     * 'f.apply(x, arguments)'. Thus, there are no outstanding values of
  1.3544 +     * MagicValue(JS_OPTIMIZED_ARGUMENTS) on the stack. However, there are
  1.3545 +     * three things that need fixup:
  1.3546 +     *  - there may be any number of activations of this script that don't have
  1.3547 +     *    an argsObj that now need one.
  1.3548 +     *  - jit code compiled (and possible active on the stack) with the static
  1.3549 +     *    assumption of !script->needsArgsObj();
  1.3550 +     *  - type inference data for the script assuming script->needsArgsObj
  1.3551 +     */
  1.3552 +    for (AllFramesIter i(cx); !i.done(); ++i) {
  1.3553 +        /*
  1.3554 +         * We cannot reliably create an arguments object for Ion activations of
  1.3555 +         * this script.  To maintain the invariant that "script->needsArgsObj
  1.3556 +         * implies fp->hasArgsObj", the Ion bail mechanism will create an
  1.3557 +         * arguments object right after restoring the BaselineFrame and before
  1.3558 +         * entering Baseline code (in jit::FinishBailoutToBaseline).
  1.3559 +         */
  1.3560 +        if (i.isIon())
  1.3561 +            continue;
  1.3562 +        AbstractFramePtr frame = i.abstractFramePtr();
  1.3563 +        if (frame.isFunctionFrame() && frame.script() == script) {
  1.3564 +            ArgumentsObject *argsobj = ArgumentsObject::createExpected(cx, frame);
  1.3565 +            if (!argsobj) {
  1.3566 +                /*
  1.3567 +                 * We can't leave stack frames with script->needsArgsObj but no
  1.3568 +                 * arguments object. It is, however, safe to leave frames with
  1.3569 +                 * an arguments object but !script->needsArgsObj.
  1.3570 +                 */
  1.3571 +                script->needsArgsObj_ = false;
  1.3572 +                return false;
  1.3573 +            }
  1.3574 +
  1.3575 +            SetFrameArgumentsObject(cx, frame, script, argsobj);
  1.3576 +        }
  1.3577 +    }
  1.3578 +
  1.3579 +    return true;
  1.3580 +}
  1.3581 +
  1.3582 +bool
  1.3583 +JSScript::varIsAliased(uint32_t varSlot)
  1.3584 +{
  1.3585 +    return bindings.bindingIsAliased(bindings.numArgs() + varSlot);
  1.3586 +}
  1.3587 +
  1.3588 +bool
  1.3589 +JSScript::formalIsAliased(unsigned argSlot)
  1.3590 +{
  1.3591 +    return bindings.bindingIsAliased(argSlot);
  1.3592 +}
  1.3593 +
  1.3594 +bool
  1.3595 +JSScript::formalLivesInArgumentsObject(unsigned argSlot)
  1.3596 +{
  1.3597 +    return argsObjAliasesFormals() && !formalIsAliased(argSlot);
  1.3598 +}
  1.3599 +
  1.3600 +LazyScript::LazyScript(JSFunction *fun, void *table, uint64_t packedFields, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
  1.3601 +  : script_(nullptr),
  1.3602 +    function_(fun),
  1.3603 +    enclosingScope_(nullptr),
  1.3604 +    sourceObject_(nullptr),
  1.3605 +    table_(table),
  1.3606 +    packedFields_(packedFields),
  1.3607 +    begin_(begin),
  1.3608 +    end_(end),
  1.3609 +    lineno_(lineno),
  1.3610 +    column_(column)
  1.3611 +{
  1.3612 +    JS_ASSERT(begin <= end);
  1.3613 +}
  1.3614 +
  1.3615 +void
  1.3616 +LazyScript::initScript(JSScript *script)
  1.3617 +{
  1.3618 +    JS_ASSERT(script && !script_);
  1.3619 +    script_ = script;
  1.3620 +}
  1.3621 +
  1.3622 +void
  1.3623 +LazyScript::resetScript()
  1.3624 +{
  1.3625 +    JS_ASSERT(script_);
  1.3626 +    script_ = nullptr;
  1.3627 +}
  1.3628 +
  1.3629 +void
  1.3630 +LazyScript::setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject)
  1.3631 +{
  1.3632 +    JS_ASSERT(!sourceObject_ && !enclosingScope_);
  1.3633 +    JS_ASSERT_IF(enclosingScope, function_->compartment() == enclosingScope->compartment());
  1.3634 +    JS_ASSERT(function_->compartment() == sourceObject->compartment());
  1.3635 +
  1.3636 +    enclosingScope_ = enclosingScope;
  1.3637 +    sourceObject_ = sourceObject;
  1.3638 +}
  1.3639 +
  1.3640 +ScriptSourceObject *
  1.3641 +LazyScript::sourceObject() const
  1.3642 +{
  1.3643 +    return sourceObject_ ? &sourceObject_->as<ScriptSourceObject>() : nullptr;
  1.3644 +}
  1.3645 +
  1.3646 +/* static */ LazyScript *
  1.3647 +LazyScript::CreateRaw(ExclusiveContext *cx, HandleFunction fun,
  1.3648 +                      uint64_t packedFields, uint32_t begin, uint32_t end,
  1.3649 +                      uint32_t lineno, uint32_t column)
  1.3650 +{
  1.3651 +    union {
  1.3652 +        PackedView p;
  1.3653 +        uint64_t packed;
  1.3654 +    };
  1.3655 +
  1.3656 +    packed = packedFields;
  1.3657 +
  1.3658 +    // Reset runtime flags to obtain a fresh LazyScript.
  1.3659 +    p.hasBeenCloned = false;
  1.3660 +    p.treatAsRunOnce = false;
  1.3661 +
  1.3662 +    size_t bytes = (p.numFreeVariables * sizeof(HeapPtrAtom))
  1.3663 +                 + (p.numInnerFunctions * sizeof(HeapPtrFunction));
  1.3664 +
  1.3665 +    ScopedJSFreePtr<void> table(bytes ? cx->malloc_(bytes) : nullptr);
  1.3666 +    if (bytes && !table)
  1.3667 +        return nullptr;
  1.3668 +
  1.3669 +    LazyScript *res = js_NewGCLazyScript(cx);
  1.3670 +    if (!res)
  1.3671 +        return nullptr;
  1.3672 +
  1.3673 +    cx->compartment()->scheduleDelazificationForDebugMode();
  1.3674 +
  1.3675 +    return new (res) LazyScript(fun, table.forget(), packed, begin, end, lineno, column);
  1.3676 +}
  1.3677 +
  1.3678 +/* static */ LazyScript *
  1.3679 +LazyScript::CreateRaw(ExclusiveContext *cx, HandleFunction fun,
  1.3680 +                      uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version,
  1.3681 +                      uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
  1.3682 +{
  1.3683 +    union {
  1.3684 +        PackedView p;
  1.3685 +        uint64_t packedFields;
  1.3686 +    };
  1.3687 +
  1.3688 +    p.version = version;
  1.3689 +    p.numFreeVariables = numFreeVariables;
  1.3690 +    p.numInnerFunctions = numInnerFunctions;
  1.3691 +    p.generatorKindBits = GeneratorKindAsBits(NotGenerator);
  1.3692 +    p.strict = false;
  1.3693 +    p.bindingsAccessedDynamically = false;
  1.3694 +    p.hasDebuggerStatement = false;
  1.3695 +    p.directlyInsideEval = false;
  1.3696 +    p.usesArgumentsAndApply = false;
  1.3697 +
  1.3698 +    LazyScript *res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
  1.3699 +    JS_ASSERT_IF(res, res->version() == version);
  1.3700 +    return res;
  1.3701 +}
  1.3702 +
  1.3703 +/* static */ LazyScript *
  1.3704 +LazyScript::Create(ExclusiveContext *cx, HandleFunction fun,
  1.3705 +                   uint64_t packedFields, uint32_t begin, uint32_t end,
  1.3706 +                   uint32_t lineno, uint32_t column)
  1.3707 +{
  1.3708 +    // Dummy atom which is not a valid property name.
  1.3709 +    RootedAtom dummyAtom(cx, cx->names().comma);
  1.3710 +
  1.3711 +    // Dummy function which is not a valid function as this is the one which is
  1.3712 +    // holding this lazy script.
  1.3713 +    HandleFunction dummyFun = fun;
  1.3714 +
  1.3715 +    LazyScript *res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
  1.3716 +    if (!res)
  1.3717 +        return nullptr;
  1.3718 +
  1.3719 +    // Fill with dummies, to be GC-safe after the initialization of the free
  1.3720 +    // variables and inner functions.
  1.3721 +    size_t i, num;
  1.3722 +    HeapPtrAtom *variables = res->freeVariables();
  1.3723 +    for (i = 0, num = res->numFreeVariables(); i < num; i++)
  1.3724 +        variables[i].init(dummyAtom);
  1.3725 +
  1.3726 +    HeapPtrFunction *functions = res->innerFunctions();
  1.3727 +    for (i = 0, num = res->numInnerFunctions(); i < num; i++)
  1.3728 +        functions[i].init(dummyFun);
  1.3729 +
  1.3730 +    return res;
  1.3731 +}
  1.3732 +
  1.3733 +void
  1.3734 +LazyScript::initRuntimeFields(uint64_t packedFields)
  1.3735 +{
  1.3736 +    union {
  1.3737 +        PackedView p;
  1.3738 +        uint64_t packed;
  1.3739 +    };
  1.3740 +
  1.3741 +    packed = packedFields;
  1.3742 +    p_.hasBeenCloned = p.hasBeenCloned;
  1.3743 +    p_.treatAsRunOnce = p.treatAsRunOnce;
  1.3744 +}
  1.3745 +
  1.3746 +bool
  1.3747 +LazyScript::hasUncompiledEnclosingScript() const
  1.3748 +{
  1.3749 +    // It can happen that we created lazy scripts while compiling an enclosing
  1.3750 +    // script, but we errored out while compiling that script. When we iterate
  1.3751 +    // over lazy script in a compartment, we might see lazy scripts that never
  1.3752 +    // escaped to script and should be ignored.
  1.3753 +    //
  1.3754 +    // If the enclosing scope is a function with a null script or has a script
  1.3755 +    // without code, it was not successfully compiled.
  1.3756 +
  1.3757 +    if (!enclosingScope() || !enclosingScope()->is<JSFunction>())
  1.3758 +        return false;
  1.3759 +
  1.3760 +    JSFunction &fun = enclosingScope()->as<JSFunction>();
  1.3761 +    return fun.isInterpreted() && (!fun.mutableScript() || !fun.nonLazyScript()->code());
  1.3762 +}
  1.3763 +
  1.3764 +uint32_t
  1.3765 +LazyScript::staticLevel(JSContext *cx) const
  1.3766 +{
  1.3767 +    for (StaticScopeIter<NoGC> ssi(enclosingScope()); !ssi.done(); ssi++) {
  1.3768 +        if (ssi.type() == StaticScopeIter<NoGC>::FUNCTION)
  1.3769 +            return ssi.funScript()->staticLevel() + 1;
  1.3770 +    }
  1.3771 +    return 1;
  1.3772 +}
  1.3773 +
  1.3774 +void
  1.3775 +JSScript::updateBaselineOrIonRaw()
  1.3776 +{
  1.3777 +#ifdef JS_ION
  1.3778 +    if (hasIonScript()) {
  1.3779 +        baselineOrIonRaw = ion->method()->raw();
  1.3780 +        baselineOrIonSkipArgCheck = ion->method()->raw() + ion->getSkipArgCheckEntryOffset();
  1.3781 +    } else if (hasBaselineScript()) {
  1.3782 +        baselineOrIonRaw = baseline->method()->raw();
  1.3783 +        baselineOrIonSkipArgCheck = baseline->method()->raw();
  1.3784 +    } else {
  1.3785 +        baselineOrIonRaw = nullptr;
  1.3786 +        baselineOrIonSkipArgCheck = nullptr;
  1.3787 +    }
  1.3788 +#endif
  1.3789 +}
  1.3790 +
  1.3791 +bool
  1.3792 +JSScript::hasLoops()
  1.3793 +{
  1.3794 +    if (!hasTrynotes())
  1.3795 +        return false;
  1.3796 +    JSTryNote *tn = trynotes()->vector;
  1.3797 +    JSTryNote *tnlimit = tn + trynotes()->length;
  1.3798 +    for (; tn < tnlimit; tn++) {
  1.3799 +        if (tn->kind == JSTRY_ITER || tn->kind == JSTRY_LOOP)
  1.3800 +            return true;
  1.3801 +    }
  1.3802 +    return false;
  1.3803 +}
  1.3804 +
  1.3805 +static inline void
  1.3806 +LazyScriptHash(uint32_t lineno, uint32_t column, uint32_t begin, uint32_t end,
  1.3807 +               HashNumber hashes[3])
  1.3808 +{
  1.3809 +    HashNumber hash = lineno;
  1.3810 +    hash = RotateLeft(hash, 4) ^ column;
  1.3811 +    hash = RotateLeft(hash, 4) ^ begin;
  1.3812 +    hash = RotateLeft(hash, 4) ^ end;
  1.3813 +
  1.3814 +    hashes[0] = hash;
  1.3815 +    hashes[1] = RotateLeft(hashes[0], 4) ^ begin;
  1.3816 +    hashes[2] = RotateLeft(hashes[1], 4) ^ end;
  1.3817 +}
  1.3818 +
  1.3819 +void
  1.3820 +LazyScriptHashPolicy::hash(const Lookup &lookup, HashNumber hashes[3])
  1.3821 +{
  1.3822 +    LazyScript *lazy = lookup.lazy;
  1.3823 +    LazyScriptHash(lazy->lineno(), lazy->column(), lazy->begin(), lazy->end(), hashes);
  1.3824 +}
  1.3825 +
  1.3826 +void
  1.3827 +LazyScriptHashPolicy::hash(JSScript *script, HashNumber hashes[3])
  1.3828 +{
  1.3829 +    LazyScriptHash(script->lineno(), script->column(), script->sourceStart(), script->sourceEnd(), hashes);
  1.3830 +}
  1.3831 +
  1.3832 +bool
  1.3833 +LazyScriptHashPolicy::match(JSScript *script, const Lookup &lookup)
  1.3834 +{
  1.3835 +    JSContext *cx = lookup.cx;
  1.3836 +    LazyScript *lazy = lookup.lazy;
  1.3837 +
  1.3838 +    // To be a match, the script and lazy script need to have the same line
  1.3839 +    // and column and to be at the same position within their respective
  1.3840 +    // source blobs, and to have the same source contents and version.
  1.3841 +    //
  1.3842 +    // While the surrounding code in the source may differ, this is
  1.3843 +    // sufficient to ensure that compiling the lazy script will yield an
  1.3844 +    // identical result to compiling the original script.
  1.3845 +    //
  1.3846 +    // Note that the filenames and origin principals of the lazy script and
  1.3847 +    // original script can differ. If there is a match, these will be fixed
  1.3848 +    // up in the resulting clone by the caller.
  1.3849 +
  1.3850 +    if (script->lineno() != lazy->lineno() ||
  1.3851 +        script->column() != lazy->column() ||
  1.3852 +        script->getVersion() != lazy->version() ||
  1.3853 +        script->sourceStart() != lazy->begin() ||
  1.3854 +        script->sourceEnd() != lazy->end())
  1.3855 +    {
  1.3856 +        return false;
  1.3857 +    }
  1.3858 +
  1.3859 +    SourceDataCache::AutoHoldEntry holder;
  1.3860 +
  1.3861 +    const jschar *scriptChars = script->scriptSource()->chars(cx, holder);
  1.3862 +    if (!scriptChars)
  1.3863 +        return false;
  1.3864 +
  1.3865 +    const jschar *lazyChars = lazy->source()->chars(cx, holder);
  1.3866 +    if (!lazyChars)
  1.3867 +        return false;
  1.3868 +
  1.3869 +    size_t begin = script->sourceStart();
  1.3870 +    size_t length = script->sourceEnd() - begin;
  1.3871 +    return !memcmp(scriptChars + begin, lazyChars + begin, length);
  1.3872 +}

mercurial