js/src/vm/SelfHosting.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/vm/SelfHosting.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1254 @@
     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 +#include "vm/SelfHosting.h"
    1.11 +
    1.12 +#include "jscntxt.h"
    1.13 +#include "jscompartment.h"
    1.14 +#include "jsfriendapi.h"
    1.15 +#include "jshashutil.h"
    1.16 +#include "jsobj.h"
    1.17 +#include "jswrapper.h"
    1.18 +#include "selfhosted.out.h"
    1.19 +
    1.20 +#include "builtin/Intl.h"
    1.21 +#include "builtin/SelfHostingDefines.h"
    1.22 +#include "builtin/TypedObject.h"
    1.23 +#include "gc/Marking.h"
    1.24 +#include "vm/Compression.h"
    1.25 +#include "vm/ForkJoin.h"
    1.26 +#include "vm/Interpreter.h"
    1.27 +#include "vm/String.h"
    1.28 +
    1.29 +#include "jsfuninlines.h"
    1.30 +#include "jsscriptinlines.h"
    1.31 +
    1.32 +#include "vm/BooleanObject-inl.h"
    1.33 +#include "vm/NumberObject-inl.h"
    1.34 +#include "vm/StringObject-inl.h"
    1.35 +
    1.36 +using namespace js;
    1.37 +using namespace js::selfhosted;
    1.38 +
    1.39 +static void
    1.40 +selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
    1.41 +{
    1.42 +    PrintError(cx, stderr, message, report, true);
    1.43 +}
    1.44 +
    1.45 +static const JSClass self_hosting_global_class = {
    1.46 +    "self-hosting-global", JSCLASS_GLOBAL_FLAGS,
    1.47 +    JS_PropertyStub,  JS_DeletePropertyStub,
    1.48 +    JS_PropertyStub,  JS_StrictPropertyStub,
    1.49 +    JS_EnumerateStub, JS_ResolveStub,
    1.50 +    JS_ConvertStub,   nullptr,
    1.51 +    nullptr, nullptr, nullptr,
    1.52 +    JS_GlobalObjectTraceHook
    1.53 +};
    1.54 +
    1.55 +bool
    1.56 +js::intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp)
    1.57 +{
    1.58 +    CallArgs args = CallArgsFromVp(argc, vp);
    1.59 +    RootedValue val(cx, args[0]);
    1.60 +    RootedObject obj(cx, ToObject(cx, val));
    1.61 +    if (!obj)
    1.62 +        return false;
    1.63 +    args.rval().setObject(*obj);
    1.64 +    return true;
    1.65 +}
    1.66 +
    1.67 +static bool
    1.68 +intrinsic_ToInteger(JSContext *cx, unsigned argc, Value *vp)
    1.69 +{
    1.70 +    CallArgs args = CallArgsFromVp(argc, vp);
    1.71 +    double result;
    1.72 +    if (!ToInteger(cx, args[0], &result))
    1.73 +        return false;
    1.74 +    args.rval().setDouble(result);
    1.75 +    return true;
    1.76 +}
    1.77 +
    1.78 +bool
    1.79 +js::intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp)
    1.80 +{
    1.81 +    CallArgs args = CallArgsFromVp(argc, vp);
    1.82 +    Value val = args[0];
    1.83 +    bool isCallable = val.isObject() && val.toObject().isCallable();
    1.84 +    args.rval().setBoolean(isCallable);
    1.85 +    return true;
    1.86 +}
    1.87 +
    1.88 +bool
    1.89 +js::intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp)
    1.90 +{
    1.91 +    CallArgs args = CallArgsFromVp(argc, vp);
    1.92 +    JS_ASSERT(args.length() >= 1);
    1.93 +    uint32_t errorNumber = args[0].toInt32();
    1.94 +
    1.95 +#ifdef DEBUG
    1.96 +    const JSErrorFormatString *efs =
    1.97 +        js_GetLocalizedErrorMessage(cx, nullptr, nullptr, errorNumber);
    1.98 +    JS_ASSERT(efs->argCount == args.length() - 1);
    1.99 +#endif
   1.100 +
   1.101 +    JSAutoByteString errorArgs[3];
   1.102 +    for (unsigned i = 1; i < 4 && i < args.length(); i++) {
   1.103 +        RootedValue val(cx, args[i]);
   1.104 +        if (val.isInt32()) {
   1.105 +            JSString *str = ToString<CanGC>(cx, val);
   1.106 +            if (!str)
   1.107 +                return false;
   1.108 +            errorArgs[i - 1].encodeLatin1(cx, str);
   1.109 +        } else if (val.isString()) {
   1.110 +            errorArgs[i - 1].encodeLatin1(cx, val.toString());
   1.111 +        } else {
   1.112 +            errorArgs[i - 1].initBytes(DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr()));
   1.113 +        }
   1.114 +        if (!errorArgs[i - 1])
   1.115 +            return false;
   1.116 +    }
   1.117 +
   1.118 +    JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, errorNumber,
   1.119 +                         errorArgs[0].ptr(), errorArgs[1].ptr(), errorArgs[2].ptr());
   1.120 +    return false;
   1.121 +}
   1.122 +
   1.123 +/**
   1.124 + * Handles an assertion failure in self-hosted code just like an assertion
   1.125 + * failure in C++ code. Information about the failure can be provided in args[0].
   1.126 + */
   1.127 +static bool
   1.128 +intrinsic_AssertionFailed(JSContext *cx, unsigned argc, Value *vp)
   1.129 +{
   1.130 +#ifdef DEBUG
   1.131 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.132 +    if (args.length() > 0) {
   1.133 +        // try to dump the informative string
   1.134 +        JSString *str = ToString<CanGC>(cx, args[0]);
   1.135 +        if (str) {
   1.136 +            const jschar *chars = str->getChars(cx);
   1.137 +            if (chars) {
   1.138 +                fprintf(stderr, "Self-hosted JavaScript assertion info: ");
   1.139 +                JSString::dumpChars(chars, str->length());
   1.140 +                fputc('\n', stderr);
   1.141 +            }
   1.142 +        }
   1.143 +    }
   1.144 +#endif
   1.145 +    JS_ASSERT(false);
   1.146 +    return false;
   1.147 +}
   1.148 +
   1.149 +static bool
   1.150 +intrinsic_MakeConstructible(JSContext *cx, unsigned argc, Value *vp)
   1.151 +{
   1.152 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.153 +    JS_ASSERT(args.length() == 2);
   1.154 +    JS_ASSERT(args[0].isObject());
   1.155 +    JS_ASSERT(args[0].toObject().is<JSFunction>());
   1.156 +    JS_ASSERT(args[1].isObject());
   1.157 +
   1.158 +    // Normal .prototype properties aren't enumerable.  But for this to clone
   1.159 +    // correctly, it must be enumerable.
   1.160 +    RootedObject ctor(cx, &args[0].toObject());
   1.161 +    if (!JSObject::defineProperty(cx, ctor, cx->names().prototype, args[1],
   1.162 +                                  JS_PropertyStub, JS_StrictPropertyStub,
   1.163 +                                  JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
   1.164 +    {
   1.165 +        return false;
   1.166 +    }
   1.167 +
   1.168 +    ctor->as<JSFunction>().setIsSelfHostedConstructor();
   1.169 +    args.rval().setUndefined();
   1.170 +    return true;
   1.171 +}
   1.172 +
   1.173 +/*
   1.174 + * Used to decompile values in the nearest non-builtin stack frame, falling
   1.175 + * back to decompiling in the current frame. Helpful for printing higher-order
   1.176 + * function arguments.
   1.177 + *
   1.178 + * The user must supply the argument number of the value in question; it
   1.179 + * _cannot_ be automatically determined.
   1.180 + */
   1.181 +static bool
   1.182 +intrinsic_DecompileArg(JSContext *cx, unsigned argc, Value *vp)
   1.183 +{
   1.184 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.185 +    JS_ASSERT(args.length() == 2);
   1.186 +
   1.187 +    RootedValue value(cx, args[1]);
   1.188 +    ScopedJSFreePtr<char> str(DecompileArgument(cx, args[0].toInt32(), value));
   1.189 +    if (!str)
   1.190 +        return false;
   1.191 +    RootedAtom atom(cx, Atomize(cx, str, strlen(str)));
   1.192 +    if (!atom)
   1.193 +        return false;
   1.194 +    args.rval().setString(atom);
   1.195 +    return true;
   1.196 +}
   1.197 +
   1.198 +/*
   1.199 + * SetScriptHints(fun, flags): Sets various internal hints to the ion
   1.200 + * compiler for use when compiling |fun| or calls to |fun|.  Flags
   1.201 + * should be a dictionary object.
   1.202 + *
   1.203 + * The function |fun| should be a self-hosted function (in particular,
   1.204 + * it *must* be a JS function).
   1.205 + *
   1.206 + * Possible flags:
   1.207 + * - |cloneAtCallsite: true| will hint that |fun| should be cloned
   1.208 + *   each callsite to improve TI resolution.  This is important for
   1.209 + *   higher-order functions like |Array.map|.
   1.210 + * - |inline: true| will hint that |fun| be inlined regardless of
   1.211 + *   JIT heuristics.
   1.212 + */
   1.213 +static bool
   1.214 +intrinsic_SetScriptHints(JSContext *cx, unsigned argc, Value *vp)
   1.215 +{
   1.216 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.217 +    JS_ASSERT(args.length() >= 2);
   1.218 +    JS_ASSERT(args[0].isObject() && args[0].toObject().is<JSFunction>());
   1.219 +    JS_ASSERT(args[1].isObject());
   1.220 +
   1.221 +    RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
   1.222 +    RootedScript funScript(cx, fun->getOrCreateScript(cx));
   1.223 +    if (!funScript)
   1.224 +        return false;
   1.225 +    RootedObject flags(cx, &args[1].toObject());
   1.226 +
   1.227 +    RootedId id(cx);
   1.228 +    RootedValue propv(cx);
   1.229 +
   1.230 +    id = AtomToId(Atomize(cx, "cloneAtCallsite", strlen("cloneAtCallsite")));
   1.231 +    if (!JSObject::getGeneric(cx, flags, flags, id, &propv))
   1.232 +        return false;
   1.233 +    if (ToBoolean(propv))
   1.234 +        funScript->setShouldCloneAtCallsite();
   1.235 +
   1.236 +    id = AtomToId(Atomize(cx, "inline", strlen("inline")));
   1.237 +    if (!JSObject::getGeneric(cx, flags, flags, id, &propv))
   1.238 +        return false;
   1.239 +    if (ToBoolean(propv))
   1.240 +        funScript->setShouldInline();
   1.241 +
   1.242 +    args.rval().setUndefined();
   1.243 +    return true;
   1.244 +}
   1.245 +
   1.246 +#ifdef DEBUG
   1.247 +/*
   1.248 + * Dump(val): Dumps a value for debugging, even in parallel mode.
   1.249 + */
   1.250 +bool
   1.251 +intrinsic_Dump(ThreadSafeContext *cx, unsigned argc, Value *vp)
   1.252 +{
   1.253 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.254 +    js_DumpValue(args[0]);
   1.255 +    if (args[0].isObject()) {
   1.256 +        fprintf(stderr, "\n");
   1.257 +        js_DumpObject(&args[0].toObject());
   1.258 +    }
   1.259 +    args.rval().setUndefined();
   1.260 +    return true;
   1.261 +}
   1.262 +
   1.263 +JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(intrinsic_Dump_jitInfo, intrinsic_Dump_jitInfo,
   1.264 +                                      intrinsic_Dump);
   1.265 +
   1.266 +bool
   1.267 +intrinsic_ParallelSpew(ThreadSafeContext *cx, unsigned argc, Value *vp)
   1.268 +{
   1.269 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.270 +    JS_ASSERT(args.length() == 1);
   1.271 +    JS_ASSERT(args[0].isString());
   1.272 +
   1.273 +    ScopedThreadSafeStringInspector inspector(args[0].toString());
   1.274 +    if (!inspector.ensureChars(cx))
   1.275 +        return false;
   1.276 +
   1.277 +    ScopedJSFreePtr<char> bytes(TwoByteCharsToNewUTF8CharsZ(cx, inspector.range()).c_str());
   1.278 +    parallel::Spew(parallel::SpewOps, bytes);
   1.279 +
   1.280 +    args.rval().setUndefined();
   1.281 +    return true;
   1.282 +}
   1.283 +
   1.284 +JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(intrinsic_ParallelSpew_jitInfo, intrinsic_ParallelSpew_jitInfo,
   1.285 +                                      intrinsic_ParallelSpew);
   1.286 +#endif
   1.287 +
   1.288 +/*
   1.289 + * ForkJoin(func, feedback): Invokes |func| many times in parallel.
   1.290 + *
   1.291 + * See ForkJoin.cpp for details and ParallelArray.js for examples.
   1.292 + */
   1.293 +static bool
   1.294 +intrinsic_ForkJoin(JSContext *cx, unsigned argc, Value *vp)
   1.295 +{
   1.296 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.297 +    return ForkJoin(cx, args);
   1.298 +}
   1.299 +
   1.300 +/*
   1.301 + * ForkJoinWorkerNumWorkers(): Returns the number of workers in the fork join
   1.302 + * thread pool, including the main thread.
   1.303 + */
   1.304 +static bool
   1.305 +intrinsic_ForkJoinNumWorkers(JSContext *cx, unsigned argc, Value *vp)
   1.306 +{
   1.307 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.308 +    args.rval().setInt32(cx->runtime()->threadPool.numWorkers());
   1.309 +    return true;
   1.310 +}
   1.311 +
   1.312 +/*
   1.313 + * ForkJoinGetSlice(id): Returns the id of the next slice to be worked
   1.314 + * on.
   1.315 + *
   1.316 + * Acts as the identity function when called from outside of a ForkJoin
   1.317 + * thread. This odd API is because intrinsics must be called during the
   1.318 + * parallel warm up phase to populate observed type sets, so we must call it
   1.319 + * even during sequential execution. But since there is no thread pool during
   1.320 + * sequential execution, the selfhosted code is responsible for computing the
   1.321 + * next sequential slice id and passing it in itself.
   1.322 + */
   1.323 +bool
   1.324 +js::intrinsic_ForkJoinGetSlice(JSContext *cx, unsigned argc, Value *vp)
   1.325 +{
   1.326 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.327 +    MOZ_ASSERT(args.length() == 1);
   1.328 +    MOZ_ASSERT(args[0].isInt32());
   1.329 +    args.rval().set(args[0]);
   1.330 +    return true;
   1.331 +}
   1.332 +
   1.333 +static bool
   1.334 +intrinsic_ForkJoinGetSlicePar(ForkJoinContext *cx, unsigned argc, Value *vp)
   1.335 +{
   1.336 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.337 +    MOZ_ASSERT(args.length() == 1);
   1.338 +    MOZ_ASSERT(args[0].isInt32());
   1.339 +
   1.340 +    uint16_t sliceId;
   1.341 +    if (cx->getSlice(&sliceId))
   1.342 +        args.rval().setInt32(sliceId);
   1.343 +    else
   1.344 +        args.rval().setInt32(ThreadPool::MAX_SLICE_ID);
   1.345 +
   1.346 +    return true;
   1.347 +}
   1.348 +
   1.349 +JS_JITINFO_NATIVE_PARALLEL(intrinsic_ForkJoinGetSlice_jitInfo,
   1.350 +                           intrinsic_ForkJoinGetSlicePar);
   1.351 +
   1.352 +/*
   1.353 + * NewDenseArray(length): Allocates and returns a new dense array with
   1.354 + * the given length where all values are initialized to holes.
   1.355 + */
   1.356 +bool
   1.357 +js::intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp)
   1.358 +{
   1.359 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.360 +
   1.361 +    // Check that index is an int32
   1.362 +    if (!args[0].isInt32()) {
   1.363 +        JS_ReportError(cx, "Expected int32 as second argument");
   1.364 +        return false;
   1.365 +    }
   1.366 +    uint32_t length = args[0].toInt32();
   1.367 +
   1.368 +    // Make a new buffer and initialize it up to length.
   1.369 +    RootedObject buffer(cx, NewDenseAllocatedArray(cx, length));
   1.370 +    if (!buffer)
   1.371 +        return false;
   1.372 +
   1.373 +    types::TypeObject *newtype = types::GetTypeCallerInitObject(cx, JSProto_Array);
   1.374 +    if (!newtype)
   1.375 +        return false;
   1.376 +    buffer->setType(newtype);
   1.377 +
   1.378 +    JSObject::EnsureDenseResult edr = buffer->ensureDenseElements(cx, length, 0);
   1.379 +    switch (edr) {
   1.380 +      case JSObject::ED_OK:
   1.381 +        args.rval().setObject(*buffer);
   1.382 +        return true;
   1.383 +
   1.384 +      case JSObject::ED_SPARSE: // shouldn't happen!
   1.385 +        JS_ASSERT(!"%EnsureDenseArrayElements() would yield sparse array");
   1.386 +        JS_ReportError(cx, "%EnsureDenseArrayElements() would yield sparse array");
   1.387 +        break;
   1.388 +
   1.389 +      case JSObject::ED_FAILED:
   1.390 +        break;
   1.391 +    }
   1.392 +    return false;
   1.393 +}
   1.394 +
   1.395 +/*
   1.396 + * UnsafePutElements(arr0, idx0, elem0, ..., arrN, idxN, elemN): For each set of
   1.397 + * (arr, idx, elem) arguments that are passed, performs the assignment
   1.398 + * |arr[idx] = elem|. |arr| must be either a dense array or a typed array.
   1.399 + *
   1.400 + * If |arr| is a dense array, the index must be an int32 less than the
   1.401 + * initialized length of |arr|. Use |%EnsureDenseResultArrayElements|
   1.402 + * to ensure that the initialized length is long enough.
   1.403 + *
   1.404 + * If |arr| is a typed array, the index must be an int32 less than the
   1.405 + * length of |arr|.
   1.406 + */
   1.407 +bool
   1.408 +js::intrinsic_UnsafePutElements(JSContext *cx, unsigned argc, Value *vp)
   1.409 +{
   1.410 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.411 +
   1.412 +    if ((args.length() % 3) != 0) {
   1.413 +        JS_ReportError(cx, "Incorrect number of arguments, not divisible by 3");
   1.414 +        return false;
   1.415 +    }
   1.416 +
   1.417 +    for (uint32_t base = 0; base < args.length(); base += 3) {
   1.418 +        uint32_t arri = base;
   1.419 +        uint32_t idxi = base+1;
   1.420 +        uint32_t elemi = base+2;
   1.421 +
   1.422 +        JS_ASSERT(args[arri].isObject());
   1.423 +        JS_ASSERT(args[arri].toObject().isNative() || IsTypedObjectArray(args[arri].toObject()));
   1.424 +        JS_ASSERT(args[idxi].isInt32());
   1.425 +
   1.426 +        RootedObject arrobj(cx, &args[arri].toObject());
   1.427 +        uint32_t idx = args[idxi].toInt32();
   1.428 +
   1.429 +        if (arrobj->is<TypedArrayObject>() || arrobj->is<TypedObject>()) {
   1.430 +            JS_ASSERT(!arrobj->is<TypedArrayObject>() || idx < arrobj->as<TypedArrayObject>().length());
   1.431 +            JS_ASSERT(!arrobj->is<TypedObject>() || idx < uint32_t(arrobj->as<TypedObject>().length()));
   1.432 +            RootedValue tmp(cx, args[elemi]);
   1.433 +            // XXX: Always non-strict.
   1.434 +            if (!JSObject::setElement(cx, arrobj, arrobj, idx, &tmp, false))
   1.435 +                return false;
   1.436 +        } else {
   1.437 +            JS_ASSERT(idx < arrobj->getDenseInitializedLength());
   1.438 +            arrobj->setDenseElementWithType(cx, idx, args[elemi]);
   1.439 +        }
   1.440 +    }
   1.441 +
   1.442 +    args.rval().setUndefined();
   1.443 +    return true;
   1.444 +}
   1.445 +
   1.446 +bool
   1.447 +js::intrinsic_DefineValueProperty(JSContext *cx, unsigned argc, Value *vp)
   1.448 +{
   1.449 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.450 +
   1.451 +    MOZ_ASSERT(args.length() == 4);
   1.452 +    MOZ_ASSERT(args[0].isObject());
   1.453 +    MOZ_ASSERT(args[3].isInt32());
   1.454 +
   1.455 +    RootedObject obj(cx, &args[0].toObject());
   1.456 +    if (obj->is<ProxyObject>()) {
   1.457 +        JS_ReportError(cx, "_DefineValueProperty can't be used on proxies");
   1.458 +        return false;
   1.459 +    }
   1.460 +    RootedId id(cx);
   1.461 +    if (!ValueToId<CanGC>(cx, args[1], &id))
   1.462 +        return false;
   1.463 +    RootedValue value(cx, args[2]);
   1.464 +    unsigned attributes = args[3].toInt32();
   1.465 +
   1.466 +    unsigned resolvedAttributes = JSPROP_PERMANENT | JSPROP_READONLY;
   1.467 +
   1.468 +    MOZ_ASSERT(bool(attributes & ATTR_ENUMERABLE) != bool(attributes & ATTR_NONENUMERABLE),
   1.469 +               "_DefineValueProperty must receive either ATTR_ENUMERABLE xor ATTR_NONENUMERABLE");
   1.470 +    if (attributes & ATTR_ENUMERABLE)
   1.471 +        resolvedAttributes |= JSPROP_ENUMERATE;
   1.472 +
   1.473 +    MOZ_ASSERT(bool(attributes & ATTR_CONFIGURABLE) != bool(attributes & ATTR_NONCONFIGURABLE),
   1.474 +               "_DefineValueProperty must receive either ATTR_CONFIGURABLE xor "
   1.475 +               "ATTR_NONCONFIGURABLE");
   1.476 +    if (attributes & ATTR_CONFIGURABLE)
   1.477 +        resolvedAttributes &= ~JSPROP_PERMANENT;
   1.478 +
   1.479 +    MOZ_ASSERT(bool(attributes & ATTR_WRITABLE) != bool(attributes & ATTR_NONWRITABLE),
   1.480 +               "_DefineValueProperty must receive either ATTR_WRITABLE xor ATTR_NONWRITABLE");
   1.481 +    if (attributes & ATTR_WRITABLE)
   1.482 +        resolvedAttributes &= ~JSPROP_READONLY;
   1.483 +
   1.484 +    return JSObject::defineGeneric(cx, obj, id, value, JS_PropertyStub, JS_StrictPropertyStub,
   1.485 +                                   resolvedAttributes);
   1.486 +}
   1.487 +
   1.488 +bool
   1.489 +js::intrinsic_UnsafeSetReservedSlot(JSContext *cx, unsigned argc, Value *vp)
   1.490 +{
   1.491 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.492 +    JS_ASSERT(args.length() == 3);
   1.493 +    JS_ASSERT(args[0].isObject());
   1.494 +    JS_ASSERT(args[1].isInt32());
   1.495 +
   1.496 +    args[0].toObject().setReservedSlot(args[1].toPrivateUint32(), args[2]);
   1.497 +    args.rval().setUndefined();
   1.498 +    return true;
   1.499 +}
   1.500 +
   1.501 +bool
   1.502 +js::intrinsic_UnsafeGetReservedSlot(JSContext *cx, unsigned argc, Value *vp)
   1.503 +{
   1.504 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.505 +    JS_ASSERT(args.length() == 2);
   1.506 +    JS_ASSERT(args[0].isObject());
   1.507 +    JS_ASSERT(args[1].isInt32());
   1.508 +
   1.509 +    args.rval().set(args[0].toObject().getReservedSlot(args[1].toPrivateUint32()));
   1.510 +    return true;
   1.511 +}
   1.512 +
   1.513 +bool
   1.514 +js::intrinsic_HaveSameClass(JSContext *cx, unsigned argc, Value *vp)
   1.515 +{
   1.516 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.517 +    JS_ASSERT(args.length() == 2);
   1.518 +    JS_ASSERT(args[0].isObject());
   1.519 +    JS_ASSERT(args[1].isObject());
   1.520 +
   1.521 +    args.rval().setBoolean(args[0].toObject().getClass() == args[1].toObject().getClass());
   1.522 +    return true;
   1.523 +}
   1.524 +
   1.525 +bool
   1.526 +js::intrinsic_IsPackedArray(JSContext *cx, unsigned argc, Value *vp)
   1.527 +{
   1.528 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.529 +    JS_ASSERT(args.length() == 1);
   1.530 +    JS_ASSERT(args[0].isObject());
   1.531 +
   1.532 +    JSObject *obj = &args[0].toObject();
   1.533 +    bool isPacked = obj->is<ArrayObject>() && !obj->hasLazyType() &&
   1.534 +                    !obj->type()->hasAllFlags(types::OBJECT_FLAG_NON_PACKED) &&
   1.535 +                    obj->getDenseInitializedLength() == obj->as<ArrayObject>().length();
   1.536 +
   1.537 +    args.rval().setBoolean(isPacked);
   1.538 +    return true;
   1.539 +}
   1.540 +
   1.541 +static bool
   1.542 +intrinsic_GetIteratorPrototype(JSContext *cx, unsigned argc, Value *vp)
   1.543 +{
   1.544 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.545 +    JS_ASSERT(args.length() == 0);
   1.546 +
   1.547 +    JSObject *obj = GlobalObject::getOrCreateIteratorPrototype(cx, cx->global());
   1.548 +    if (!obj)
   1.549 +        return false;
   1.550 +
   1.551 +    args.rval().setObject(*obj);
   1.552 +    return true;
   1.553 +}
   1.554 +
   1.555 +static bool
   1.556 +intrinsic_NewArrayIterator(JSContext *cx, unsigned argc, Value *vp)
   1.557 +{
   1.558 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.559 +    JS_ASSERT(args.length() == 0);
   1.560 +
   1.561 +    RootedObject proto(cx, GlobalObject::getOrCreateArrayIteratorPrototype(cx, cx->global()));
   1.562 +    if (!proto)
   1.563 +        return false;
   1.564 +
   1.565 +    JSObject *obj = NewObjectWithGivenProto(cx, proto->getClass(), proto, cx->global());
   1.566 +    if (!obj)
   1.567 +        return false;
   1.568 +
   1.569 +    args.rval().setObject(*obj);
   1.570 +    return true;
   1.571 +}
   1.572 +
   1.573 +static bool
   1.574 +intrinsic_IsArrayIterator(JSContext *cx, unsigned argc, Value *vp)
   1.575 +{
   1.576 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.577 +    JS_ASSERT(args.length() == 1);
   1.578 +    JS_ASSERT(args[0].isObject());
   1.579 +
   1.580 +    args.rval().setBoolean(args[0].toObject().is<ArrayIteratorObject>());
   1.581 +    return true;
   1.582 +}
   1.583 +
   1.584 +static bool
   1.585 +intrinsic_NewStringIterator(JSContext *cx, unsigned argc, Value *vp)
   1.586 +{
   1.587 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.588 +    JS_ASSERT(args.length() == 0);
   1.589 +
   1.590 +    RootedObject proto(cx, GlobalObject::getOrCreateStringIteratorPrototype(cx, cx->global()));
   1.591 +    if (!proto)
   1.592 +        return false;
   1.593 +
   1.594 +    JSObject *obj = NewObjectWithGivenProto(cx, &StringIteratorObject::class_, proto, cx->global());
   1.595 +    if (!obj)
   1.596 +        return false;
   1.597 +
   1.598 +    args.rval().setObject(*obj);
   1.599 +    return true;
   1.600 +}
   1.601 +
   1.602 +static bool
   1.603 +intrinsic_IsStringIterator(JSContext *cx, unsigned argc, Value *vp)
   1.604 +{
   1.605 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.606 +    JS_ASSERT(args.length() == 1);
   1.607 +    JS_ASSERT(args[0].isObject());
   1.608 +
   1.609 +    args.rval().setBoolean(args[0].toObject().is<StringIteratorObject>());
   1.610 +    return true;
   1.611 +}
   1.612 +
   1.613 +/*
   1.614 + * ParallelTestsShouldPass(): Returns false if we are running in a
   1.615 + * mode (such as --ion-eager) that is known to cause additional
   1.616 + * bailouts or disqualifications for parallel array tests.
   1.617 + *
   1.618 + * This is needed because the parallel tests generally assert that,
   1.619 + * under normal conditions, they will run without bailouts or
   1.620 + * compilation failures, but this does not hold under "stress-testing"
   1.621 + * conditions like --ion-eager or --no-ti.  However, running the tests
   1.622 + * under those conditions HAS exposed bugs and thus we do not wish to
   1.623 + * disable them entirely.  Instead, we simply disable the assertions
   1.624 + * that state that no bailouts etc should occur.
   1.625 + */
   1.626 +static bool
   1.627 +intrinsic_ParallelTestsShouldPass(JSContext *cx, unsigned argc, Value *vp)
   1.628 +{
   1.629 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.630 +    args.rval().setBoolean(ParallelTestsShouldPass(cx));
   1.631 +    return true;
   1.632 +}
   1.633 +
   1.634 +/*
   1.635 + * ShouldForceSequential(): Returns true if parallel ops should take
   1.636 + * the sequential fallback path.
   1.637 + */
   1.638 +bool
   1.639 +js::intrinsic_ShouldForceSequential(JSContext *cx, unsigned argc, Value *vp)
   1.640 +{
   1.641 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.642 +#ifdef JS_THREADSAFE
   1.643 +    args.rval().setBoolean(cx->runtime()->forkJoinWarmup ||
   1.644 +                           InParallelSection());
   1.645 +#else
   1.646 +    args.rval().setBoolean(true);
   1.647 +#endif
   1.648 +    return true;
   1.649 +}
   1.650 +
   1.651 +bool
   1.652 +js::intrinsic_InParallelSection(JSContext *cx, unsigned argc, Value *vp)
   1.653 +{
   1.654 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.655 +    args.rval().setBoolean(false);
   1.656 +    return true;
   1.657 +}
   1.658 +
   1.659 +static bool
   1.660 +intrinsic_InParallelSectionPar(ForkJoinContext *cx, unsigned argc, Value *vp)
   1.661 +{
   1.662 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.663 +    args.rval().setBoolean(true);
   1.664 +    return true;
   1.665 +}
   1.666 +
   1.667 +JS_JITINFO_NATIVE_PARALLEL(intrinsic_InParallelSection_jitInfo,
   1.668 +                           intrinsic_InParallelSectionPar);
   1.669 +
   1.670 +/* These wrappers are needed in order to recognize the function
   1.671 + * pointers within the JIT, and the raw js:: functions can't be used
   1.672 + * directly because they take a ThreadSafeContext* argument.
   1.673 + */
   1.674 +bool
   1.675 +js::intrinsic_ObjectIsTypedObject(JSContext *cx, unsigned argc, Value *vp)
   1.676 +{
   1.677 +    return js::ObjectIsTypedObject(cx, argc, vp);
   1.678 +}
   1.679 +
   1.680 +bool
   1.681 +js::intrinsic_ObjectIsTransparentTypedObject(JSContext *cx, unsigned argc, Value *vp)
   1.682 +{
   1.683 +    return js::ObjectIsTransparentTypedObject(cx, argc, vp);
   1.684 +}
   1.685 +
   1.686 +bool
   1.687 +js::intrinsic_ObjectIsOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp)
   1.688 +{
   1.689 +    return js::ObjectIsOpaqueTypedObject(cx, argc, vp);
   1.690 +}
   1.691 +
   1.692 +bool
   1.693 +js::intrinsic_ObjectIsTypeDescr(JSContext *cx, unsigned argc, Value *vp)
   1.694 +{
   1.695 +    return js::ObjectIsTypeDescr(cx, argc, vp);
   1.696 +}
   1.697 +
   1.698 +bool
   1.699 +js::intrinsic_TypeDescrIsSimpleType(JSContext *cx, unsigned argc, Value *vp)
   1.700 +{
   1.701 +    return js::TypeDescrIsSimpleType(cx, argc, vp);
   1.702 +}
   1.703 +
   1.704 +bool
   1.705 +js::intrinsic_TypeDescrIsArrayType(JSContext *cx, unsigned argc, Value *vp)
   1.706 +{
   1.707 +    return js::TypeDescrIsArrayType(cx, argc, vp);
   1.708 +}
   1.709 +
   1.710 +bool
   1.711 +js::intrinsic_TypeDescrIsUnsizedArrayType(JSContext *cx, unsigned argc, Value *vp)
   1.712 +{
   1.713 +    return js::TypeDescrIsUnsizedArrayType(cx, argc, vp);
   1.714 +}
   1.715 +
   1.716 +bool
   1.717 +js::intrinsic_TypeDescrIsSizedArrayType(JSContext *cx, unsigned argc, Value *vp)
   1.718 +{
   1.719 +    return js::TypeDescrIsSizedArrayType(cx, argc, vp);
   1.720 +}
   1.721 +
   1.722 +/**
   1.723 + * Returns the default locale as a well-formed, but not necessarily canonicalized,
   1.724 + * BCP-47 language tag.
   1.725 + */
   1.726 +static bool
   1.727 +intrinsic_RuntimeDefaultLocale(JSContext *cx, unsigned argc, Value *vp)
   1.728 +{
   1.729 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.730 +
   1.731 +    const char *locale = cx->runtime()->getDefaultLocale();
   1.732 +    if (!locale) {
   1.733 +        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEFAULT_LOCALE_ERROR);
   1.734 +        return false;
   1.735 +    }
   1.736 +
   1.737 +    RootedString jslocale(cx, JS_NewStringCopyZ(cx, locale));
   1.738 +    if (!jslocale)
   1.739 +        return false;
   1.740 +
   1.741 +    args.rval().setString(jslocale);
   1.742 +    return true;
   1.743 +}
   1.744 +
   1.745 +static const JSFunctionSpec intrinsic_functions[] = {
   1.746 +    JS_FN("ToObject",                intrinsic_ToObject,                1,0),
   1.747 +    JS_FN("ToInteger",               intrinsic_ToInteger,               1,0),
   1.748 +    JS_FN("IsCallable",              intrinsic_IsCallable,              1,0),
   1.749 +    JS_FN("ThrowError",              intrinsic_ThrowError,              4,0),
   1.750 +    JS_FN("AssertionFailed",         intrinsic_AssertionFailed,         1,0),
   1.751 +    JS_FN("SetScriptHints",          intrinsic_SetScriptHints,          2,0),
   1.752 +    JS_FN("MakeConstructible",       intrinsic_MakeConstructible,       1,0),
   1.753 +    JS_FN("DecompileArg",            intrinsic_DecompileArg,            2,0),
   1.754 +    JS_FN("RuntimeDefaultLocale",    intrinsic_RuntimeDefaultLocale,    0,0),
   1.755 +
   1.756 +    JS_FN("UnsafePutElements",       intrinsic_UnsafePutElements,       3,0),
   1.757 +    JS_FN("_DefineValueProperty",    intrinsic_DefineValueProperty,     4,0),
   1.758 +    JS_FN("UnsafeSetReservedSlot",   intrinsic_UnsafeSetReservedSlot,   3,0),
   1.759 +    JS_FN("UnsafeGetReservedSlot",   intrinsic_UnsafeGetReservedSlot,   2,0),
   1.760 +    JS_FN("HaveSameClass",           intrinsic_HaveSameClass,           2,0),
   1.761 +    JS_FN("IsPackedArray",           intrinsic_IsPackedArray,           1,0),
   1.762 +
   1.763 +    JS_FN("GetIteratorPrototype",    intrinsic_GetIteratorPrototype,    0,0),
   1.764 +
   1.765 +    JS_FN("NewArrayIterator",        intrinsic_NewArrayIterator,        0,0),
   1.766 +    JS_FN("IsArrayIterator",         intrinsic_IsArrayIterator,         1,0),
   1.767 +
   1.768 +    JS_FN("NewStringIterator",       intrinsic_NewStringIterator,       0,0),
   1.769 +    JS_FN("IsStringIterator",        intrinsic_IsStringIterator,        1,0),
   1.770 +
   1.771 +    JS_FN("ForkJoin",                intrinsic_ForkJoin,                2,0),
   1.772 +    JS_FN("ForkJoinNumWorkers",      intrinsic_ForkJoinNumWorkers,      0,0),
   1.773 +    JS_FN("NewDenseArray",           intrinsic_NewDenseArray,           1,0),
   1.774 +    JS_FN("ShouldForceSequential",   intrinsic_ShouldForceSequential,   0,0),
   1.775 +    JS_FN("ParallelTestsShouldPass", intrinsic_ParallelTestsShouldPass, 0,0),
   1.776 +    JS_FNINFO("ClearThreadLocalArenas",
   1.777 +              intrinsic_ClearThreadLocalArenas,
   1.778 +              &intrinsic_ClearThreadLocalArenasInfo, 0,0),
   1.779 +    JS_FNINFO("SetForkJoinTargetRegion",
   1.780 +              intrinsic_SetForkJoinTargetRegion,
   1.781 +              &intrinsic_SetForkJoinTargetRegionInfo, 2, 0),
   1.782 +    JS_FNINFO("ForkJoinGetSlice",
   1.783 +              intrinsic_ForkJoinGetSlice,
   1.784 +              &intrinsic_ForkJoinGetSlice_jitInfo, 1, 0),
   1.785 +    JS_FNINFO("InParallelSection",
   1.786 +              intrinsic_InParallelSection,
   1.787 +              &intrinsic_InParallelSection_jitInfo, 0, 0),
   1.788 +
   1.789 +    // See builtin/TypedObject.h for descriptors of the typedobj functions.
   1.790 +    JS_FN("NewOpaqueTypedObject",
   1.791 +          js::NewOpaqueTypedObject,
   1.792 +          1, 0),
   1.793 +    JS_FN("NewDerivedTypedObject",
   1.794 +          js::NewDerivedTypedObject,
   1.795 +          3, 0),
   1.796 +    JS_FNINFO("AttachTypedObject",
   1.797 +              JSNativeThreadSafeWrapper<js::AttachTypedObject>,
   1.798 +              &js::AttachTypedObjectJitInfo, 3, 0),
   1.799 +    JS_FNINFO("SetTypedObjectOffset",
   1.800 +              intrinsic_SetTypedObjectOffset,
   1.801 +              &js::intrinsic_SetTypedObjectOffsetJitInfo, 2, 0),
   1.802 +    JS_FNINFO("ObjectIsTypeDescr",
   1.803 +              intrinsic_ObjectIsTypeDescr,
   1.804 +              &js::ObjectIsTypeDescrJitInfo, 1, 0),
   1.805 +    JS_FNINFO("ObjectIsTypedObject",
   1.806 +              intrinsic_ObjectIsTypedObject,
   1.807 +              &js::ObjectIsTypedObjectJitInfo, 1, 0),
   1.808 +    JS_FNINFO("ObjectIsTransparentTypedObject",
   1.809 +              intrinsic_ObjectIsTransparentTypedObject,
   1.810 +              &js::ObjectIsTransparentTypedObjectJitInfo, 1, 0),
   1.811 +    JS_FNINFO("TypedObjectIsAttached",
   1.812 +              JSNativeThreadSafeWrapper<js::TypedObjectIsAttached>,
   1.813 +              &js::TypedObjectIsAttachedJitInfo, 1, 0),
   1.814 +    JS_FNINFO("ObjectIsOpaqueTypedObject",
   1.815 +              intrinsic_ObjectIsOpaqueTypedObject,
   1.816 +              &js::ObjectIsOpaqueTypedObjectJitInfo, 1, 0),
   1.817 +    JS_FNINFO("TypeDescrIsArrayType",
   1.818 +              intrinsic_TypeDescrIsArrayType,
   1.819 +              &js::TypeDescrIsArrayTypeJitInfo, 1, 0),
   1.820 +    JS_FNINFO("TypeDescrIsUnsizedArrayType",
   1.821 +              intrinsic_TypeDescrIsUnsizedArrayType,
   1.822 +              &js::TypeDescrIsUnsizedArrayTypeJitInfo, 1, 0),
   1.823 +    JS_FNINFO("TypeDescrIsSizedArrayType",
   1.824 +              intrinsic_TypeDescrIsSizedArrayType,
   1.825 +              &js::TypeDescrIsSizedArrayTypeJitInfo, 1, 0),
   1.826 +    JS_FNINFO("TypeDescrIsSimpleType",
   1.827 +              intrinsic_TypeDescrIsSimpleType,
   1.828 +              &js::TypeDescrIsSimpleTypeJitInfo, 1, 0),
   1.829 +    JS_FNINFO("ClampToUint8",
   1.830 +              JSNativeThreadSafeWrapper<js::ClampToUint8>,
   1.831 +              &js::ClampToUint8JitInfo, 1, 0),
   1.832 +    JS_FNINFO("Memcpy",
   1.833 +              JSNativeThreadSafeWrapper<js::Memcpy>,
   1.834 +              &js::MemcpyJitInfo, 5, 0),
   1.835 +    JS_FN("GetTypedObjectModule", js::GetTypedObjectModule, 0, 0),
   1.836 +    JS_FN("GetFloat32x4TypeDescr", js::GetFloat32x4TypeDescr, 0, 0),
   1.837 +    JS_FN("GetInt32x4TypeDescr", js::GetInt32x4TypeDescr, 0, 0),
   1.838 +
   1.839 +#define LOAD_AND_STORE_SCALAR_FN_DECLS(_constant, _type, _name)               \
   1.840 +    JS_FNINFO("Store_" #_name,                                                \
   1.841 +              JSNativeThreadSafeWrapper<js::StoreScalar##_type::Func>,        \
   1.842 +              &js::StoreScalar##_type::JitInfo, 3, 0),                        \
   1.843 +    JS_FNINFO("Load_" #_name,                                                 \
   1.844 +              JSNativeThreadSafeWrapper<js::LoadScalar##_type::Func>,         \
   1.845 +              &js::LoadScalar##_type::JitInfo, 3, 0),
   1.846 +    JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(LOAD_AND_STORE_SCALAR_FN_DECLS)
   1.847 +
   1.848 +#define LOAD_AND_STORE_REFERENCE_FN_DECLS(_constant, _type, _name)              \
   1.849 +    JS_FNINFO("Store_" #_name,                                                  \
   1.850 +              JSNativeThreadSafeWrapper<js::StoreReference##_type::Func>,       \
   1.851 +              &js::StoreReference##_type::JitInfo, 3, 0),                       \
   1.852 +    JS_FNINFO("Load_" #_name,                                                   \
   1.853 +              JSNativeThreadSafeWrapper<js::LoadReference##_type::Func>,        \
   1.854 +              &js::LoadReference##_type::JitInfo, 3, 0),
   1.855 +    JS_FOR_EACH_REFERENCE_TYPE_REPR(LOAD_AND_STORE_REFERENCE_FN_DECLS)
   1.856 +
   1.857 +    // See builtin/Intl.h for descriptions of the intl_* functions.
   1.858 +    JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
   1.859 +    JS_FN("intl_availableCollations", intl_availableCollations, 1,0),
   1.860 +    JS_FN("intl_Collator", intl_Collator, 2,0),
   1.861 +    JS_FN("intl_Collator_availableLocales", intl_Collator_availableLocales, 0,0),
   1.862 +    JS_FN("intl_CompareStrings", intl_CompareStrings, 3,0),
   1.863 +    JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2,0),
   1.864 +    JS_FN("intl_DateTimeFormat_availableLocales", intl_DateTimeFormat_availableLocales, 0,0),
   1.865 +    JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0),
   1.866 +    JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
   1.867 +    JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
   1.868 +    JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0),
   1.869 +    JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
   1.870 +    JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
   1.871 +
   1.872 +    // See builtin/RegExp.h for descriptions of the regexp_* functions.
   1.873 +    JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
   1.874 +    JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
   1.875 +
   1.876 +#ifdef DEBUG
   1.877 +    JS_FNINFO("Dump",
   1.878 +              JSNativeThreadSafeWrapper<intrinsic_Dump>,
   1.879 +              &intrinsic_Dump_jitInfo, 1,0),
   1.880 +
   1.881 +    JS_FNINFO("ParallelSpew",
   1.882 +              JSNativeThreadSafeWrapper<intrinsic_ParallelSpew>,
   1.883 +              &intrinsic_ParallelSpew_jitInfo, 1,0),
   1.884 +#endif
   1.885 +
   1.886 +    JS_FS_END
   1.887 +};
   1.888 +
   1.889 +void
   1.890 +js::FillSelfHostingCompileOptions(CompileOptions &options)
   1.891 +{
   1.892 +    /*
   1.893 +     * In self-hosting mode, scripts emit JSOP_GETINTRINSIC instead of
   1.894 +     * JSOP_NAME or JSOP_GNAME to access unbound variables. JSOP_GETINTRINSIC
   1.895 +     * does a name lookup in a special object, whose properties are filled in
   1.896 +     * lazily upon first access for a given global.
   1.897 +     *
   1.898 +     * As that object is inaccessible to client code, the lookups are
   1.899 +     * guaranteed to return the original objects, ensuring safe implementation
   1.900 +     * of self-hosted builtins.
   1.901 +     *
   1.902 +     * Additionally, the special syntax callFunction(fun, receiver, ...args)
   1.903 +     * is supported, for which bytecode is emitted that invokes |fun| with
   1.904 +     * |receiver| as the this-object and ...args as the arguments.
   1.905 +     */
   1.906 +    options.setIntroductionType("self-hosted");
   1.907 +    options.setFileAndLine("self-hosted", 1);
   1.908 +    options.setSelfHostingMode(true);
   1.909 +    options.setCanLazilyParse(false);
   1.910 +    options.setVersion(JSVERSION_LATEST);
   1.911 +    options.werrorOption = true;
   1.912 +    options.strictOption = true;
   1.913 +
   1.914 +#ifdef DEBUG
   1.915 +    options.extraWarningsOption = true;
   1.916 +#endif
   1.917 +}
   1.918 +
   1.919 +bool
   1.920 +JSRuntime::initSelfHosting(JSContext *cx)
   1.921 +{
   1.922 +    JS_ASSERT(!selfHostingGlobal_);
   1.923 +
   1.924 +    if (cx->runtime()->parentRuntime) {
   1.925 +        selfHostingGlobal_ = cx->runtime()->parentRuntime->selfHostingGlobal_;
   1.926 +        return true;
   1.927 +    }
   1.928 +
   1.929 +    /*
   1.930 +     * Self hosted state can be accessed from threads for other runtimes
   1.931 +     * parented to this one, so cannot include state in the nursery.
   1.932 +     */
   1.933 +    JS::AutoDisableGenerationalGC disable(cx->runtime());
   1.934 +
   1.935 +    bool receivesDefaultObject = !cx->options().noDefaultCompartmentObject();
   1.936 +    RootedObject savedGlobal(cx, receivesDefaultObject
   1.937 +                                 ? js::DefaultObjectForContextOrNull(cx)
   1.938 +                                 : nullptr);
   1.939 +    JS::CompartmentOptions compartmentOptions;
   1.940 +    compartmentOptions.setDiscardSource(true);
   1.941 +    if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class,
   1.942 +                                                  nullptr, JS::DontFireOnNewGlobalHook,
   1.943 +                                                  compartmentOptions)))
   1.944 +        return false;
   1.945 +    JSAutoCompartment ac(cx, selfHostingGlobal_);
   1.946 +    if (receivesDefaultObject)
   1.947 +        js::SetDefaultObjectForContext(cx, selfHostingGlobal_);
   1.948 +    Rooted<GlobalObject*> shg(cx, &selfHostingGlobal_->as<GlobalObject>());
   1.949 +    selfHostingGlobal_->compartment()->isSelfHosting = true;
   1.950 +    selfHostingGlobal_->compartment()->isSystem = true;
   1.951 +    /*
   1.952 +     * During initialization of standard classes for the self-hosting global,
   1.953 +     * all self-hosted functions are ignored. Thus, we don't create cyclic
   1.954 +     * dependencies in the order of initialization.
   1.955 +     */
   1.956 +    if (!GlobalObject::initStandardClasses(cx, shg))
   1.957 +        return false;
   1.958 +
   1.959 +    if (!JS_DefineFunctions(cx, shg, intrinsic_functions))
   1.960 +        return false;
   1.961 +
   1.962 +    JS_FireOnNewGlobalObject(cx, shg);
   1.963 +
   1.964 +    CompileOptions options(cx);
   1.965 +    FillSelfHostingCompileOptions(options);
   1.966 +
   1.967 +    /*
   1.968 +     * Set a temporary error reporter printing to stderr because it is too
   1.969 +     * early in the startup process for any other reporter to be registered
   1.970 +     * and we don't want errors in self-hosted code to be silently swallowed.
   1.971 +     */
   1.972 +    JSErrorReporter oldReporter = JS_SetErrorReporter(cx, selfHosting_ErrorReporter);
   1.973 +    RootedValue rv(cx);
   1.974 +    bool ok = false;
   1.975 +
   1.976 +    char *filename = getenv("MOZ_SELFHOSTEDJS");
   1.977 +    if (filename) {
   1.978 +        RootedScript script(cx, Compile(cx, shg, options, filename));
   1.979 +        if (script)
   1.980 +            ok = Execute(cx, script, *shg.get(), rv.address());
   1.981 +    } else {
   1.982 +        uint32_t srcLen = GetRawScriptsSize();
   1.983 +
   1.984 +#ifdef USE_ZLIB
   1.985 +        const unsigned char *compressed = compressedSources;
   1.986 +        uint32_t compressedLen = GetCompressedSize();
   1.987 +        ScopedJSFreePtr<char> src(reinterpret_cast<char *>(cx->malloc_(srcLen)));
   1.988 +        if (!src || !DecompressString(compressed, compressedLen,
   1.989 +                                      reinterpret_cast<unsigned char *>(src.get()), srcLen))
   1.990 +        {
   1.991 +            return false;
   1.992 +        }
   1.993 +#else
   1.994 +        const char *src = rawSources;
   1.995 +#endif
   1.996 +
   1.997 +        ok = Evaluate(cx, shg, options, src, srcLen, &rv);
   1.998 +    }
   1.999 +    JS_SetErrorReporter(cx, oldReporter);
  1.1000 +    if (receivesDefaultObject)
  1.1001 +        js::SetDefaultObjectForContext(cx, savedGlobal);
  1.1002 +    return ok;
  1.1003 +}
  1.1004 +
  1.1005 +void
  1.1006 +JSRuntime::finishSelfHosting()
  1.1007 +{
  1.1008 +    selfHostingGlobal_ = nullptr;
  1.1009 +}
  1.1010 +
  1.1011 +void
  1.1012 +JSRuntime::markSelfHostingGlobal(JSTracer *trc)
  1.1013 +{
  1.1014 +    if (selfHostingGlobal_ && !parentRuntime)
  1.1015 +        MarkObjectRoot(trc, &selfHostingGlobal_, "self-hosting global");
  1.1016 +}
  1.1017 +
  1.1018 +bool
  1.1019 +JSRuntime::isSelfHostingCompartment(JSCompartment *comp)
  1.1020 +{
  1.1021 +    return selfHostingGlobal_->compartment() == comp;
  1.1022 +}
  1.1023 +
  1.1024 +static bool
  1.1025 +CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp);
  1.1026 +
  1.1027 +static bool
  1.1028 +GetUnclonedValue(JSContext *cx, HandleObject selfHostedObject, HandleId id, MutableHandleValue vp)
  1.1029 +{
  1.1030 +    vp.setUndefined();
  1.1031 +
  1.1032 +    if (JSID_IS_INT(id)) {
  1.1033 +        size_t index = JSID_TO_INT(id);
  1.1034 +        if (index < selfHostedObject->getDenseInitializedLength() &&
  1.1035 +            !selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE))
  1.1036 +        {
  1.1037 +            vp.set(selfHostedObject->getDenseElement(JSID_TO_INT(id)));
  1.1038 +            return true;
  1.1039 +        }
  1.1040 +    }
  1.1041 +
  1.1042 +    // Since all atoms used by self hosting are marked as permanent, any
  1.1043 +    // attempt to look up a non-permanent atom will fail. We should only
  1.1044 +    // see such atoms when code is looking for properties on the self
  1.1045 +    // hosted global which aren't present.
  1.1046 +    if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) {
  1.1047 +        JS_ASSERT(selfHostedObject->is<GlobalObject>());
  1.1048 +        RootedValue value(cx, IdToValue(id));
  1.1049 +        return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
  1.1050 +                                        JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
  1.1051 +    }
  1.1052 +
  1.1053 +    RootedShape shape(cx, selfHostedObject->nativeLookupPure(id));
  1.1054 +    if (!shape) {
  1.1055 +        RootedValue value(cx, IdToValue(id));
  1.1056 +        return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
  1.1057 +                                        JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
  1.1058 +    }
  1.1059 +
  1.1060 +    JS_ASSERT(shape->hasSlot() && shape->hasDefaultGetter());
  1.1061 +    vp.set(selfHostedObject->getSlot(shape->slot()));
  1.1062 +    return true;
  1.1063 +}
  1.1064 +
  1.1065 +static bool
  1.1066 +CloneProperties(JSContext *cx, HandleObject selfHostedObject, HandleObject clone)
  1.1067 +{
  1.1068 +    AutoIdVector ids(cx);
  1.1069 +
  1.1070 +    for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) {
  1.1071 +        if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
  1.1072 +            if (!ids.append(INT_TO_JSID(i)))
  1.1073 +                return false;
  1.1074 +        }
  1.1075 +    }
  1.1076 +
  1.1077 +    for (Shape::Range<NoGC> range(selfHostedObject->lastProperty()); !range.empty(); range.popFront()) {
  1.1078 +        Shape &shape = range.front();
  1.1079 +        if (shape.enumerable() && !ids.append(shape.propid()))
  1.1080 +            return false;
  1.1081 +    }
  1.1082 +
  1.1083 +    RootedId id(cx);
  1.1084 +    RootedValue val(cx);
  1.1085 +    RootedValue selfHostedValue(cx);
  1.1086 +    for (uint32_t i = 0; i < ids.length(); i++) {
  1.1087 +        id = ids[i];
  1.1088 +        if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue))
  1.1089 +            return false;
  1.1090 +        if (!CloneValue(cx, selfHostedValue, &val) ||
  1.1091 +            !JS_DefinePropertyById(cx, clone, id, val.get(), nullptr, nullptr, 0))
  1.1092 +        {
  1.1093 +            return false;
  1.1094 +        }
  1.1095 +    }
  1.1096 +
  1.1097 +    return true;
  1.1098 +}
  1.1099 +
  1.1100 +static JSObject *
  1.1101 +CloneObject(JSContext *cx, HandleObject selfHostedObject)
  1.1102 +{
  1.1103 +    AutoCycleDetector detect(cx, selfHostedObject);
  1.1104 +    if (!detect.init())
  1.1105 +        return nullptr;
  1.1106 +    if (detect.foundCycle()) {
  1.1107 +        JS_ReportError(cx, "SelfHosted cloning cannot handle cyclic object graphs.");
  1.1108 +        return nullptr;
  1.1109 +    }
  1.1110 +
  1.1111 +    RootedObject clone(cx);
  1.1112 +    if (selfHostedObject->is<JSFunction>()) {
  1.1113 +        RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>());
  1.1114 +        bool hasName = selfHostedFunction->atom() != nullptr;
  1.1115 +        // Arrow functions use the first extended slot for their lexical |this| value.
  1.1116 +        JS_ASSERT(!selfHostedFunction->isArrow());
  1.1117 +        js::gc::AllocKind kind = hasName
  1.1118 +                                 ? JSFunction::ExtendedFinalizeKind
  1.1119 +                                 : selfHostedFunction->getAllocKind();
  1.1120 +        clone = CloneFunctionObject(cx, selfHostedFunction, cx->global(), kind, TenuredObject);
  1.1121 +        // To be able to re-lazify the cloned function, its name in the
  1.1122 +        // self-hosting compartment has to be stored on the clone.
  1.1123 +        if (clone && hasName)
  1.1124 +            clone->as<JSFunction>().setExtendedSlot(0, StringValue(selfHostedFunction->atom()));
  1.1125 +    } else if (selfHostedObject->is<RegExpObject>()) {
  1.1126 +        RegExpObject &reobj = selfHostedObject->as<RegExpObject>();
  1.1127 +        RootedAtom source(cx, reobj.getSource());
  1.1128 +        JS_ASSERT(source->isPermanentAtom());
  1.1129 +        clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), nullptr);
  1.1130 +    } else if (selfHostedObject->is<DateObject>()) {
  1.1131 +        clone = JS_NewDateObjectMsec(cx, selfHostedObject->as<DateObject>().UTCTime().toNumber());
  1.1132 +    } else if (selfHostedObject->is<BooleanObject>()) {
  1.1133 +        clone = BooleanObject::create(cx, selfHostedObject->as<BooleanObject>().unbox());
  1.1134 +    } else if (selfHostedObject->is<NumberObject>()) {
  1.1135 +        clone = NumberObject::create(cx, selfHostedObject->as<NumberObject>().unbox());
  1.1136 +    } else if (selfHostedObject->is<StringObject>()) {
  1.1137 +        JSString *selfHostedString = selfHostedObject->as<StringObject>().unbox();
  1.1138 +        if (!selfHostedString->isFlat())
  1.1139 +            MOZ_CRASH();
  1.1140 +        RootedString str(cx, js_NewStringCopyN<CanGC>(cx,
  1.1141 +                                                      selfHostedString->asFlat().chars(),
  1.1142 +                                                      selfHostedString->asFlat().length()));
  1.1143 +        if (!str)
  1.1144 +            return nullptr;
  1.1145 +        clone = StringObject::create(cx, str);
  1.1146 +    } else if (selfHostedObject->is<ArrayObject>()) {
  1.1147 +        clone = NewDenseEmptyArray(cx, nullptr, TenuredObject);
  1.1148 +    } else {
  1.1149 +        JS_ASSERT(selfHostedObject->isNative());
  1.1150 +        clone = NewObjectWithGivenProto(cx, selfHostedObject->getClass(), nullptr, cx->global(),
  1.1151 +                                        selfHostedObject->tenuredGetAllocKind(),
  1.1152 +                                        SingletonObject);
  1.1153 +    }
  1.1154 +    if (!clone)
  1.1155 +        return nullptr;
  1.1156 +    if (!CloneProperties(cx, selfHostedObject, clone))
  1.1157 +        return nullptr;
  1.1158 +    return clone;
  1.1159 +}
  1.1160 +
  1.1161 +static bool
  1.1162 +CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp)
  1.1163 +{
  1.1164 +    if (selfHostedValue.isObject()) {
  1.1165 +        RootedObject selfHostedObject(cx, &selfHostedValue.toObject());
  1.1166 +        JSObject *clone = CloneObject(cx, selfHostedObject);
  1.1167 +        if (!clone)
  1.1168 +            return false;
  1.1169 +        vp.setObject(*clone);
  1.1170 +    } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) {
  1.1171 +        // Nothing to do here: these are represented inline in the value.
  1.1172 +        vp.set(selfHostedValue);
  1.1173 +    } else if (selfHostedValue.isString()) {
  1.1174 +        if (!selfHostedValue.toString()->isFlat())
  1.1175 +            MOZ_CRASH();
  1.1176 +        JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat();
  1.1177 +        JSString *clone = js_NewStringCopyN<CanGC>(cx,
  1.1178 +                                                   selfHostedString->chars(),
  1.1179 +                                                   selfHostedString->length());
  1.1180 +        if (!clone)
  1.1181 +            return false;
  1.1182 +        vp.setString(clone);
  1.1183 +    } else {
  1.1184 +        MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
  1.1185 +    }
  1.1186 +    return true;
  1.1187 +}
  1.1188 +
  1.1189 +bool
  1.1190 +JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, HandlePropertyName name,
  1.1191 +                                         HandleFunction targetFun)
  1.1192 +{
  1.1193 +    RootedId id(cx, NameToId(name));
  1.1194 +    RootedValue funVal(cx);
  1.1195 +    if (!GetUnclonedValue(cx, HandleObject::fromMarkedLocation(&selfHostingGlobal_), id, &funVal))
  1.1196 +        return false;
  1.1197 +
  1.1198 +    RootedFunction sourceFun(cx, &funVal.toObject().as<JSFunction>());
  1.1199 +    // JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
  1.1200 +    // aren't any.
  1.1201 +    JS_ASSERT(!sourceFun->isGenerator());
  1.1202 +    RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx));
  1.1203 +    if (!sourceScript)
  1.1204 +        return false;
  1.1205 +    JS_ASSERT(!sourceScript->enclosingStaticScope());
  1.1206 +    JSScript *cscript = CloneScript(cx, NullPtr(), targetFun, sourceScript);
  1.1207 +    if (!cscript)
  1.1208 +        return false;
  1.1209 +    cscript->setFunction(targetFun);
  1.1210 +
  1.1211 +    JS_ASSERT(sourceFun->nargs() == targetFun->nargs());
  1.1212 +    // The target function might have been relazified after it's flags changed.
  1.1213 +    targetFun->setFlags((targetFun->flags() & ~JSFunction::INTERPRETED_LAZY) |
  1.1214 +                        sourceFun->flags() | JSFunction::EXTENDED);
  1.1215 +    targetFun->setScript(cscript);
  1.1216 +    JS_ASSERT(targetFun->isExtended());
  1.1217 +    return true;
  1.1218 +}
  1.1219 +
  1.1220 +bool
  1.1221 +JSRuntime::cloneSelfHostedValue(JSContext *cx, HandlePropertyName name, MutableHandleValue vp)
  1.1222 +{
  1.1223 +    RootedId id(cx, NameToId(name));
  1.1224 +    RootedValue selfHostedValue(cx);
  1.1225 +    if (!GetUnclonedValue(cx, HandleObject::fromMarkedLocation(&selfHostingGlobal_), id, &selfHostedValue))
  1.1226 +        return false;
  1.1227 +
  1.1228 +    /*
  1.1229 +     * We don't clone if we're operating in the self-hosting global, as that
  1.1230 +     * means we're currently executing the self-hosting script while
  1.1231 +     * initializing the runtime (see JSRuntime::initSelfHosting).
  1.1232 +     */
  1.1233 +    if (cx->global() == selfHostingGlobal_) {
  1.1234 +        vp.set(selfHostedValue);
  1.1235 +        return true;
  1.1236 +    }
  1.1237 +
  1.1238 +    return CloneValue(cx, selfHostedValue, vp);
  1.1239 +}
  1.1240 +
  1.1241 +JSFunction *
  1.1242 +js::SelfHostedFunction(JSContext *cx, HandlePropertyName propName)
  1.1243 +{
  1.1244 +    RootedValue func(cx);
  1.1245 +    if (!GlobalObject::getIntrinsicValue(cx, cx->global(), propName, &func))
  1.1246 +        return nullptr;
  1.1247 +
  1.1248 +    JS_ASSERT(func.isObject());
  1.1249 +    JS_ASSERT(func.toObject().is<JSFunction>());
  1.1250 +    return &func.toObject().as<JSFunction>();
  1.1251 +}
  1.1252 +
  1.1253 +bool
  1.1254 +js::IsSelfHostedFunctionWithName(JSFunction *fun, JSAtom *name)
  1.1255 +{
  1.1256 +    return fun->isSelfHostedBuiltin() && fun->getExtendedSlot(0).toString() == name;
  1.1257 +}

mercurial