js/src/vm/SelfHosting.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "vm/SelfHosting.h"
     9 #include "jscntxt.h"
    10 #include "jscompartment.h"
    11 #include "jsfriendapi.h"
    12 #include "jshashutil.h"
    13 #include "jsobj.h"
    14 #include "jswrapper.h"
    15 #include "selfhosted.out.h"
    17 #include "builtin/Intl.h"
    18 #include "builtin/SelfHostingDefines.h"
    19 #include "builtin/TypedObject.h"
    20 #include "gc/Marking.h"
    21 #include "vm/Compression.h"
    22 #include "vm/ForkJoin.h"
    23 #include "vm/Interpreter.h"
    24 #include "vm/String.h"
    26 #include "jsfuninlines.h"
    27 #include "jsscriptinlines.h"
    29 #include "vm/BooleanObject-inl.h"
    30 #include "vm/NumberObject-inl.h"
    31 #include "vm/StringObject-inl.h"
    33 using namespace js;
    34 using namespace js::selfhosted;
    36 static void
    37 selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
    38 {
    39     PrintError(cx, stderr, message, report, true);
    40 }
    42 static const JSClass self_hosting_global_class = {
    43     "self-hosting-global", JSCLASS_GLOBAL_FLAGS,
    44     JS_PropertyStub,  JS_DeletePropertyStub,
    45     JS_PropertyStub,  JS_StrictPropertyStub,
    46     JS_EnumerateStub, JS_ResolveStub,
    47     JS_ConvertStub,   nullptr,
    48     nullptr, nullptr, nullptr,
    49     JS_GlobalObjectTraceHook
    50 };
    52 bool
    53 js::intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp)
    54 {
    55     CallArgs args = CallArgsFromVp(argc, vp);
    56     RootedValue val(cx, args[0]);
    57     RootedObject obj(cx, ToObject(cx, val));
    58     if (!obj)
    59         return false;
    60     args.rval().setObject(*obj);
    61     return true;
    62 }
    64 static bool
    65 intrinsic_ToInteger(JSContext *cx, unsigned argc, Value *vp)
    66 {
    67     CallArgs args = CallArgsFromVp(argc, vp);
    68     double result;
    69     if (!ToInteger(cx, args[0], &result))
    70         return false;
    71     args.rval().setDouble(result);
    72     return true;
    73 }
    75 bool
    76 js::intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp)
    77 {
    78     CallArgs args = CallArgsFromVp(argc, vp);
    79     Value val = args[0];
    80     bool isCallable = val.isObject() && val.toObject().isCallable();
    81     args.rval().setBoolean(isCallable);
    82     return true;
    83 }
    85 bool
    86 js::intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp)
    87 {
    88     CallArgs args = CallArgsFromVp(argc, vp);
    89     JS_ASSERT(args.length() >= 1);
    90     uint32_t errorNumber = args[0].toInt32();
    92 #ifdef DEBUG
    93     const JSErrorFormatString *efs =
    94         js_GetLocalizedErrorMessage(cx, nullptr, nullptr, errorNumber);
    95     JS_ASSERT(efs->argCount == args.length() - 1);
    96 #endif
    98     JSAutoByteString errorArgs[3];
    99     for (unsigned i = 1; i < 4 && i < args.length(); i++) {
   100         RootedValue val(cx, args[i]);
   101         if (val.isInt32()) {
   102             JSString *str = ToString<CanGC>(cx, val);
   103             if (!str)
   104                 return false;
   105             errorArgs[i - 1].encodeLatin1(cx, str);
   106         } else if (val.isString()) {
   107             errorArgs[i - 1].encodeLatin1(cx, val.toString());
   108         } else {
   109             errorArgs[i - 1].initBytes(DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr()));
   110         }
   111         if (!errorArgs[i - 1])
   112             return false;
   113     }
   115     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, errorNumber,
   116                          errorArgs[0].ptr(), errorArgs[1].ptr(), errorArgs[2].ptr());
   117     return false;
   118 }
   120 /**
   121  * Handles an assertion failure in self-hosted code just like an assertion
   122  * failure in C++ code. Information about the failure can be provided in args[0].
   123  */
   124 static bool
   125 intrinsic_AssertionFailed(JSContext *cx, unsigned argc, Value *vp)
   126 {
   127 #ifdef DEBUG
   128     CallArgs args = CallArgsFromVp(argc, vp);
   129     if (args.length() > 0) {
   130         // try to dump the informative string
   131         JSString *str = ToString<CanGC>(cx, args[0]);
   132         if (str) {
   133             const jschar *chars = str->getChars(cx);
   134             if (chars) {
   135                 fprintf(stderr, "Self-hosted JavaScript assertion info: ");
   136                 JSString::dumpChars(chars, str->length());
   137                 fputc('\n', stderr);
   138             }
   139         }
   140     }
   141 #endif
   142     JS_ASSERT(false);
   143     return false;
   144 }
   146 static bool
   147 intrinsic_MakeConstructible(JSContext *cx, unsigned argc, Value *vp)
   148 {
   149     CallArgs args = CallArgsFromVp(argc, vp);
   150     JS_ASSERT(args.length() == 2);
   151     JS_ASSERT(args[0].isObject());
   152     JS_ASSERT(args[0].toObject().is<JSFunction>());
   153     JS_ASSERT(args[1].isObject());
   155     // Normal .prototype properties aren't enumerable.  But for this to clone
   156     // correctly, it must be enumerable.
   157     RootedObject ctor(cx, &args[0].toObject());
   158     if (!JSObject::defineProperty(cx, ctor, cx->names().prototype, args[1],
   159                                   JS_PropertyStub, JS_StrictPropertyStub,
   160                                   JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
   161     {
   162         return false;
   163     }
   165     ctor->as<JSFunction>().setIsSelfHostedConstructor();
   166     args.rval().setUndefined();
   167     return true;
   168 }
   170 /*
   171  * Used to decompile values in the nearest non-builtin stack frame, falling
   172  * back to decompiling in the current frame. Helpful for printing higher-order
   173  * function arguments.
   174  *
   175  * The user must supply the argument number of the value in question; it
   176  * _cannot_ be automatically determined.
   177  */
   178 static bool
   179 intrinsic_DecompileArg(JSContext *cx, unsigned argc, Value *vp)
   180 {
   181     CallArgs args = CallArgsFromVp(argc, vp);
   182     JS_ASSERT(args.length() == 2);
   184     RootedValue value(cx, args[1]);
   185     ScopedJSFreePtr<char> str(DecompileArgument(cx, args[0].toInt32(), value));
   186     if (!str)
   187         return false;
   188     RootedAtom atom(cx, Atomize(cx, str, strlen(str)));
   189     if (!atom)
   190         return false;
   191     args.rval().setString(atom);
   192     return true;
   193 }
   195 /*
   196  * SetScriptHints(fun, flags): Sets various internal hints to the ion
   197  * compiler for use when compiling |fun| or calls to |fun|.  Flags
   198  * should be a dictionary object.
   199  *
   200  * The function |fun| should be a self-hosted function (in particular,
   201  * it *must* be a JS function).
   202  *
   203  * Possible flags:
   204  * - |cloneAtCallsite: true| will hint that |fun| should be cloned
   205  *   each callsite to improve TI resolution.  This is important for
   206  *   higher-order functions like |Array.map|.
   207  * - |inline: true| will hint that |fun| be inlined regardless of
   208  *   JIT heuristics.
   209  */
   210 static bool
   211 intrinsic_SetScriptHints(JSContext *cx, unsigned argc, Value *vp)
   212 {
   213     CallArgs args = CallArgsFromVp(argc, vp);
   214     JS_ASSERT(args.length() >= 2);
   215     JS_ASSERT(args[0].isObject() && args[0].toObject().is<JSFunction>());
   216     JS_ASSERT(args[1].isObject());
   218     RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
   219     RootedScript funScript(cx, fun->getOrCreateScript(cx));
   220     if (!funScript)
   221         return false;
   222     RootedObject flags(cx, &args[1].toObject());
   224     RootedId id(cx);
   225     RootedValue propv(cx);
   227     id = AtomToId(Atomize(cx, "cloneAtCallsite", strlen("cloneAtCallsite")));
   228     if (!JSObject::getGeneric(cx, flags, flags, id, &propv))
   229         return false;
   230     if (ToBoolean(propv))
   231         funScript->setShouldCloneAtCallsite();
   233     id = AtomToId(Atomize(cx, "inline", strlen("inline")));
   234     if (!JSObject::getGeneric(cx, flags, flags, id, &propv))
   235         return false;
   236     if (ToBoolean(propv))
   237         funScript->setShouldInline();
   239     args.rval().setUndefined();
   240     return true;
   241 }
   243 #ifdef DEBUG
   244 /*
   245  * Dump(val): Dumps a value for debugging, even in parallel mode.
   246  */
   247 bool
   248 intrinsic_Dump(ThreadSafeContext *cx, unsigned argc, Value *vp)
   249 {
   250     CallArgs args = CallArgsFromVp(argc, vp);
   251     js_DumpValue(args[0]);
   252     if (args[0].isObject()) {
   253         fprintf(stderr, "\n");
   254         js_DumpObject(&args[0].toObject());
   255     }
   256     args.rval().setUndefined();
   257     return true;
   258 }
   260 JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(intrinsic_Dump_jitInfo, intrinsic_Dump_jitInfo,
   261                                       intrinsic_Dump);
   263 bool
   264 intrinsic_ParallelSpew(ThreadSafeContext *cx, unsigned argc, Value *vp)
   265 {
   266     CallArgs args = CallArgsFromVp(argc, vp);
   267     JS_ASSERT(args.length() == 1);
   268     JS_ASSERT(args[0].isString());
   270     ScopedThreadSafeStringInspector inspector(args[0].toString());
   271     if (!inspector.ensureChars(cx))
   272         return false;
   274     ScopedJSFreePtr<char> bytes(TwoByteCharsToNewUTF8CharsZ(cx, inspector.range()).c_str());
   275     parallel::Spew(parallel::SpewOps, bytes);
   277     args.rval().setUndefined();
   278     return true;
   279 }
   281 JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(intrinsic_ParallelSpew_jitInfo, intrinsic_ParallelSpew_jitInfo,
   282                                       intrinsic_ParallelSpew);
   283 #endif
   285 /*
   286  * ForkJoin(func, feedback): Invokes |func| many times in parallel.
   287  *
   288  * See ForkJoin.cpp for details and ParallelArray.js for examples.
   289  */
   290 static bool
   291 intrinsic_ForkJoin(JSContext *cx, unsigned argc, Value *vp)
   292 {
   293     CallArgs args = CallArgsFromVp(argc, vp);
   294     return ForkJoin(cx, args);
   295 }
   297 /*
   298  * ForkJoinWorkerNumWorkers(): Returns the number of workers in the fork join
   299  * thread pool, including the main thread.
   300  */
   301 static bool
   302 intrinsic_ForkJoinNumWorkers(JSContext *cx, unsigned argc, Value *vp)
   303 {
   304     CallArgs args = CallArgsFromVp(argc, vp);
   305     args.rval().setInt32(cx->runtime()->threadPool.numWorkers());
   306     return true;
   307 }
   309 /*
   310  * ForkJoinGetSlice(id): Returns the id of the next slice to be worked
   311  * on.
   312  *
   313  * Acts as the identity function when called from outside of a ForkJoin
   314  * thread. This odd API is because intrinsics must be called during the
   315  * parallel warm up phase to populate observed type sets, so we must call it
   316  * even during sequential execution. But since there is no thread pool during
   317  * sequential execution, the selfhosted code is responsible for computing the
   318  * next sequential slice id and passing it in itself.
   319  */
   320 bool
   321 js::intrinsic_ForkJoinGetSlice(JSContext *cx, unsigned argc, Value *vp)
   322 {
   323     CallArgs args = CallArgsFromVp(argc, vp);
   324     MOZ_ASSERT(args.length() == 1);
   325     MOZ_ASSERT(args[0].isInt32());
   326     args.rval().set(args[0]);
   327     return true;
   328 }
   330 static bool
   331 intrinsic_ForkJoinGetSlicePar(ForkJoinContext *cx, unsigned argc, Value *vp)
   332 {
   333     CallArgs args = CallArgsFromVp(argc, vp);
   334     MOZ_ASSERT(args.length() == 1);
   335     MOZ_ASSERT(args[0].isInt32());
   337     uint16_t sliceId;
   338     if (cx->getSlice(&sliceId))
   339         args.rval().setInt32(sliceId);
   340     else
   341         args.rval().setInt32(ThreadPool::MAX_SLICE_ID);
   343     return true;
   344 }
   346 JS_JITINFO_NATIVE_PARALLEL(intrinsic_ForkJoinGetSlice_jitInfo,
   347                            intrinsic_ForkJoinGetSlicePar);
   349 /*
   350  * NewDenseArray(length): Allocates and returns a new dense array with
   351  * the given length where all values are initialized to holes.
   352  */
   353 bool
   354 js::intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp)
   355 {
   356     CallArgs args = CallArgsFromVp(argc, vp);
   358     // Check that index is an int32
   359     if (!args[0].isInt32()) {
   360         JS_ReportError(cx, "Expected int32 as second argument");
   361         return false;
   362     }
   363     uint32_t length = args[0].toInt32();
   365     // Make a new buffer and initialize it up to length.
   366     RootedObject buffer(cx, NewDenseAllocatedArray(cx, length));
   367     if (!buffer)
   368         return false;
   370     types::TypeObject *newtype = types::GetTypeCallerInitObject(cx, JSProto_Array);
   371     if (!newtype)
   372         return false;
   373     buffer->setType(newtype);
   375     JSObject::EnsureDenseResult edr = buffer->ensureDenseElements(cx, length, 0);
   376     switch (edr) {
   377       case JSObject::ED_OK:
   378         args.rval().setObject(*buffer);
   379         return true;
   381       case JSObject::ED_SPARSE: // shouldn't happen!
   382         JS_ASSERT(!"%EnsureDenseArrayElements() would yield sparse array");
   383         JS_ReportError(cx, "%EnsureDenseArrayElements() would yield sparse array");
   384         break;
   386       case JSObject::ED_FAILED:
   387         break;
   388     }
   389     return false;
   390 }
   392 /*
   393  * UnsafePutElements(arr0, idx0, elem0, ..., arrN, idxN, elemN): For each set of
   394  * (arr, idx, elem) arguments that are passed, performs the assignment
   395  * |arr[idx] = elem|. |arr| must be either a dense array or a typed array.
   396  *
   397  * If |arr| is a dense array, the index must be an int32 less than the
   398  * initialized length of |arr|. Use |%EnsureDenseResultArrayElements|
   399  * to ensure that the initialized length is long enough.
   400  *
   401  * If |arr| is a typed array, the index must be an int32 less than the
   402  * length of |arr|.
   403  */
   404 bool
   405 js::intrinsic_UnsafePutElements(JSContext *cx, unsigned argc, Value *vp)
   406 {
   407     CallArgs args = CallArgsFromVp(argc, vp);
   409     if ((args.length() % 3) != 0) {
   410         JS_ReportError(cx, "Incorrect number of arguments, not divisible by 3");
   411         return false;
   412     }
   414     for (uint32_t base = 0; base < args.length(); base += 3) {
   415         uint32_t arri = base;
   416         uint32_t idxi = base+1;
   417         uint32_t elemi = base+2;
   419         JS_ASSERT(args[arri].isObject());
   420         JS_ASSERT(args[arri].toObject().isNative() || IsTypedObjectArray(args[arri].toObject()));
   421         JS_ASSERT(args[idxi].isInt32());
   423         RootedObject arrobj(cx, &args[arri].toObject());
   424         uint32_t idx = args[idxi].toInt32();
   426         if (arrobj->is<TypedArrayObject>() || arrobj->is<TypedObject>()) {
   427             JS_ASSERT(!arrobj->is<TypedArrayObject>() || idx < arrobj->as<TypedArrayObject>().length());
   428             JS_ASSERT(!arrobj->is<TypedObject>() || idx < uint32_t(arrobj->as<TypedObject>().length()));
   429             RootedValue tmp(cx, args[elemi]);
   430             // XXX: Always non-strict.
   431             if (!JSObject::setElement(cx, arrobj, arrobj, idx, &tmp, false))
   432                 return false;
   433         } else {
   434             JS_ASSERT(idx < arrobj->getDenseInitializedLength());
   435             arrobj->setDenseElementWithType(cx, idx, args[elemi]);
   436         }
   437     }
   439     args.rval().setUndefined();
   440     return true;
   441 }
   443 bool
   444 js::intrinsic_DefineValueProperty(JSContext *cx, unsigned argc, Value *vp)
   445 {
   446     CallArgs args = CallArgsFromVp(argc, vp);
   448     MOZ_ASSERT(args.length() == 4);
   449     MOZ_ASSERT(args[0].isObject());
   450     MOZ_ASSERT(args[3].isInt32());
   452     RootedObject obj(cx, &args[0].toObject());
   453     if (obj->is<ProxyObject>()) {
   454         JS_ReportError(cx, "_DefineValueProperty can't be used on proxies");
   455         return false;
   456     }
   457     RootedId id(cx);
   458     if (!ValueToId<CanGC>(cx, args[1], &id))
   459         return false;
   460     RootedValue value(cx, args[2]);
   461     unsigned attributes = args[3].toInt32();
   463     unsigned resolvedAttributes = JSPROP_PERMANENT | JSPROP_READONLY;
   465     MOZ_ASSERT(bool(attributes & ATTR_ENUMERABLE) != bool(attributes & ATTR_NONENUMERABLE),
   466                "_DefineValueProperty must receive either ATTR_ENUMERABLE xor ATTR_NONENUMERABLE");
   467     if (attributes & ATTR_ENUMERABLE)
   468         resolvedAttributes |= JSPROP_ENUMERATE;
   470     MOZ_ASSERT(bool(attributes & ATTR_CONFIGURABLE) != bool(attributes & ATTR_NONCONFIGURABLE),
   471                "_DefineValueProperty must receive either ATTR_CONFIGURABLE xor "
   472                "ATTR_NONCONFIGURABLE");
   473     if (attributes & ATTR_CONFIGURABLE)
   474         resolvedAttributes &= ~JSPROP_PERMANENT;
   476     MOZ_ASSERT(bool(attributes & ATTR_WRITABLE) != bool(attributes & ATTR_NONWRITABLE),
   477                "_DefineValueProperty must receive either ATTR_WRITABLE xor ATTR_NONWRITABLE");
   478     if (attributes & ATTR_WRITABLE)
   479         resolvedAttributes &= ~JSPROP_READONLY;
   481     return JSObject::defineGeneric(cx, obj, id, value, JS_PropertyStub, JS_StrictPropertyStub,
   482                                    resolvedAttributes);
   483 }
   485 bool
   486 js::intrinsic_UnsafeSetReservedSlot(JSContext *cx, unsigned argc, Value *vp)
   487 {
   488     CallArgs args = CallArgsFromVp(argc, vp);
   489     JS_ASSERT(args.length() == 3);
   490     JS_ASSERT(args[0].isObject());
   491     JS_ASSERT(args[1].isInt32());
   493     args[0].toObject().setReservedSlot(args[1].toPrivateUint32(), args[2]);
   494     args.rval().setUndefined();
   495     return true;
   496 }
   498 bool
   499 js::intrinsic_UnsafeGetReservedSlot(JSContext *cx, unsigned argc, Value *vp)
   500 {
   501     CallArgs args = CallArgsFromVp(argc, vp);
   502     JS_ASSERT(args.length() == 2);
   503     JS_ASSERT(args[0].isObject());
   504     JS_ASSERT(args[1].isInt32());
   506     args.rval().set(args[0].toObject().getReservedSlot(args[1].toPrivateUint32()));
   507     return true;
   508 }
   510 bool
   511 js::intrinsic_HaveSameClass(JSContext *cx, unsigned argc, Value *vp)
   512 {
   513     CallArgs args = CallArgsFromVp(argc, vp);
   514     JS_ASSERT(args.length() == 2);
   515     JS_ASSERT(args[0].isObject());
   516     JS_ASSERT(args[1].isObject());
   518     args.rval().setBoolean(args[0].toObject().getClass() == args[1].toObject().getClass());
   519     return true;
   520 }
   522 bool
   523 js::intrinsic_IsPackedArray(JSContext *cx, unsigned argc, Value *vp)
   524 {
   525     CallArgs args = CallArgsFromVp(argc, vp);
   526     JS_ASSERT(args.length() == 1);
   527     JS_ASSERT(args[0].isObject());
   529     JSObject *obj = &args[0].toObject();
   530     bool isPacked = obj->is<ArrayObject>() && !obj->hasLazyType() &&
   531                     !obj->type()->hasAllFlags(types::OBJECT_FLAG_NON_PACKED) &&
   532                     obj->getDenseInitializedLength() == obj->as<ArrayObject>().length();
   534     args.rval().setBoolean(isPacked);
   535     return true;
   536 }
   538 static bool
   539 intrinsic_GetIteratorPrototype(JSContext *cx, unsigned argc, Value *vp)
   540 {
   541     CallArgs args = CallArgsFromVp(argc, vp);
   542     JS_ASSERT(args.length() == 0);
   544     JSObject *obj = GlobalObject::getOrCreateIteratorPrototype(cx, cx->global());
   545     if (!obj)
   546         return false;
   548     args.rval().setObject(*obj);
   549     return true;
   550 }
   552 static bool
   553 intrinsic_NewArrayIterator(JSContext *cx, unsigned argc, Value *vp)
   554 {
   555     CallArgs args = CallArgsFromVp(argc, vp);
   556     JS_ASSERT(args.length() == 0);
   558     RootedObject proto(cx, GlobalObject::getOrCreateArrayIteratorPrototype(cx, cx->global()));
   559     if (!proto)
   560         return false;
   562     JSObject *obj = NewObjectWithGivenProto(cx, proto->getClass(), proto, cx->global());
   563     if (!obj)
   564         return false;
   566     args.rval().setObject(*obj);
   567     return true;
   568 }
   570 static bool
   571 intrinsic_IsArrayIterator(JSContext *cx, unsigned argc, Value *vp)
   572 {
   573     CallArgs args = CallArgsFromVp(argc, vp);
   574     JS_ASSERT(args.length() == 1);
   575     JS_ASSERT(args[0].isObject());
   577     args.rval().setBoolean(args[0].toObject().is<ArrayIteratorObject>());
   578     return true;
   579 }
   581 static bool
   582 intrinsic_NewStringIterator(JSContext *cx, unsigned argc, Value *vp)
   583 {
   584     CallArgs args = CallArgsFromVp(argc, vp);
   585     JS_ASSERT(args.length() == 0);
   587     RootedObject proto(cx, GlobalObject::getOrCreateStringIteratorPrototype(cx, cx->global()));
   588     if (!proto)
   589         return false;
   591     JSObject *obj = NewObjectWithGivenProto(cx, &StringIteratorObject::class_, proto, cx->global());
   592     if (!obj)
   593         return false;
   595     args.rval().setObject(*obj);
   596     return true;
   597 }
   599 static bool
   600 intrinsic_IsStringIterator(JSContext *cx, unsigned argc, Value *vp)
   601 {
   602     CallArgs args = CallArgsFromVp(argc, vp);
   603     JS_ASSERT(args.length() == 1);
   604     JS_ASSERT(args[0].isObject());
   606     args.rval().setBoolean(args[0].toObject().is<StringIteratorObject>());
   607     return true;
   608 }
   610 /*
   611  * ParallelTestsShouldPass(): Returns false if we are running in a
   612  * mode (such as --ion-eager) that is known to cause additional
   613  * bailouts or disqualifications for parallel array tests.
   614  *
   615  * This is needed because the parallel tests generally assert that,
   616  * under normal conditions, they will run without bailouts or
   617  * compilation failures, but this does not hold under "stress-testing"
   618  * conditions like --ion-eager or --no-ti.  However, running the tests
   619  * under those conditions HAS exposed bugs and thus we do not wish to
   620  * disable them entirely.  Instead, we simply disable the assertions
   621  * that state that no bailouts etc should occur.
   622  */
   623 static bool
   624 intrinsic_ParallelTestsShouldPass(JSContext *cx, unsigned argc, Value *vp)
   625 {
   626     CallArgs args = CallArgsFromVp(argc, vp);
   627     args.rval().setBoolean(ParallelTestsShouldPass(cx));
   628     return true;
   629 }
   631 /*
   632  * ShouldForceSequential(): Returns true if parallel ops should take
   633  * the sequential fallback path.
   634  */
   635 bool
   636 js::intrinsic_ShouldForceSequential(JSContext *cx, unsigned argc, Value *vp)
   637 {
   638     CallArgs args = CallArgsFromVp(argc, vp);
   639 #ifdef JS_THREADSAFE
   640     args.rval().setBoolean(cx->runtime()->forkJoinWarmup ||
   641                            InParallelSection());
   642 #else
   643     args.rval().setBoolean(true);
   644 #endif
   645     return true;
   646 }
   648 bool
   649 js::intrinsic_InParallelSection(JSContext *cx, unsigned argc, Value *vp)
   650 {
   651     CallArgs args = CallArgsFromVp(argc, vp);
   652     args.rval().setBoolean(false);
   653     return true;
   654 }
   656 static bool
   657 intrinsic_InParallelSectionPar(ForkJoinContext *cx, unsigned argc, Value *vp)
   658 {
   659     CallArgs args = CallArgsFromVp(argc, vp);
   660     args.rval().setBoolean(true);
   661     return true;
   662 }
   664 JS_JITINFO_NATIVE_PARALLEL(intrinsic_InParallelSection_jitInfo,
   665                            intrinsic_InParallelSectionPar);
   667 /* These wrappers are needed in order to recognize the function
   668  * pointers within the JIT, and the raw js:: functions can't be used
   669  * directly because they take a ThreadSafeContext* argument.
   670  */
   671 bool
   672 js::intrinsic_ObjectIsTypedObject(JSContext *cx, unsigned argc, Value *vp)
   673 {
   674     return js::ObjectIsTypedObject(cx, argc, vp);
   675 }
   677 bool
   678 js::intrinsic_ObjectIsTransparentTypedObject(JSContext *cx, unsigned argc, Value *vp)
   679 {
   680     return js::ObjectIsTransparentTypedObject(cx, argc, vp);
   681 }
   683 bool
   684 js::intrinsic_ObjectIsOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp)
   685 {
   686     return js::ObjectIsOpaqueTypedObject(cx, argc, vp);
   687 }
   689 bool
   690 js::intrinsic_ObjectIsTypeDescr(JSContext *cx, unsigned argc, Value *vp)
   691 {
   692     return js::ObjectIsTypeDescr(cx, argc, vp);
   693 }
   695 bool
   696 js::intrinsic_TypeDescrIsSimpleType(JSContext *cx, unsigned argc, Value *vp)
   697 {
   698     return js::TypeDescrIsSimpleType(cx, argc, vp);
   699 }
   701 bool
   702 js::intrinsic_TypeDescrIsArrayType(JSContext *cx, unsigned argc, Value *vp)
   703 {
   704     return js::TypeDescrIsArrayType(cx, argc, vp);
   705 }
   707 bool
   708 js::intrinsic_TypeDescrIsUnsizedArrayType(JSContext *cx, unsigned argc, Value *vp)
   709 {
   710     return js::TypeDescrIsUnsizedArrayType(cx, argc, vp);
   711 }
   713 bool
   714 js::intrinsic_TypeDescrIsSizedArrayType(JSContext *cx, unsigned argc, Value *vp)
   715 {
   716     return js::TypeDescrIsSizedArrayType(cx, argc, vp);
   717 }
   719 /**
   720  * Returns the default locale as a well-formed, but not necessarily canonicalized,
   721  * BCP-47 language tag.
   722  */
   723 static bool
   724 intrinsic_RuntimeDefaultLocale(JSContext *cx, unsigned argc, Value *vp)
   725 {
   726     CallArgs args = CallArgsFromVp(argc, vp);
   728     const char *locale = cx->runtime()->getDefaultLocale();
   729     if (!locale) {
   730         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEFAULT_LOCALE_ERROR);
   731         return false;
   732     }
   734     RootedString jslocale(cx, JS_NewStringCopyZ(cx, locale));
   735     if (!jslocale)
   736         return false;
   738     args.rval().setString(jslocale);
   739     return true;
   740 }
   742 static const JSFunctionSpec intrinsic_functions[] = {
   743     JS_FN("ToObject",                intrinsic_ToObject,                1,0),
   744     JS_FN("ToInteger",               intrinsic_ToInteger,               1,0),
   745     JS_FN("IsCallable",              intrinsic_IsCallable,              1,0),
   746     JS_FN("ThrowError",              intrinsic_ThrowError,              4,0),
   747     JS_FN("AssertionFailed",         intrinsic_AssertionFailed,         1,0),
   748     JS_FN("SetScriptHints",          intrinsic_SetScriptHints,          2,0),
   749     JS_FN("MakeConstructible",       intrinsic_MakeConstructible,       1,0),
   750     JS_FN("DecompileArg",            intrinsic_DecompileArg,            2,0),
   751     JS_FN("RuntimeDefaultLocale",    intrinsic_RuntimeDefaultLocale,    0,0),
   753     JS_FN("UnsafePutElements",       intrinsic_UnsafePutElements,       3,0),
   754     JS_FN("_DefineValueProperty",    intrinsic_DefineValueProperty,     4,0),
   755     JS_FN("UnsafeSetReservedSlot",   intrinsic_UnsafeSetReservedSlot,   3,0),
   756     JS_FN("UnsafeGetReservedSlot",   intrinsic_UnsafeGetReservedSlot,   2,0),
   757     JS_FN("HaveSameClass",           intrinsic_HaveSameClass,           2,0),
   758     JS_FN("IsPackedArray",           intrinsic_IsPackedArray,           1,0),
   760     JS_FN("GetIteratorPrototype",    intrinsic_GetIteratorPrototype,    0,0),
   762     JS_FN("NewArrayIterator",        intrinsic_NewArrayIterator,        0,0),
   763     JS_FN("IsArrayIterator",         intrinsic_IsArrayIterator,         1,0),
   765     JS_FN("NewStringIterator",       intrinsic_NewStringIterator,       0,0),
   766     JS_FN("IsStringIterator",        intrinsic_IsStringIterator,        1,0),
   768     JS_FN("ForkJoin",                intrinsic_ForkJoin,                2,0),
   769     JS_FN("ForkJoinNumWorkers",      intrinsic_ForkJoinNumWorkers,      0,0),
   770     JS_FN("NewDenseArray",           intrinsic_NewDenseArray,           1,0),
   771     JS_FN("ShouldForceSequential",   intrinsic_ShouldForceSequential,   0,0),
   772     JS_FN("ParallelTestsShouldPass", intrinsic_ParallelTestsShouldPass, 0,0),
   773     JS_FNINFO("ClearThreadLocalArenas",
   774               intrinsic_ClearThreadLocalArenas,
   775               &intrinsic_ClearThreadLocalArenasInfo, 0,0),
   776     JS_FNINFO("SetForkJoinTargetRegion",
   777               intrinsic_SetForkJoinTargetRegion,
   778               &intrinsic_SetForkJoinTargetRegionInfo, 2, 0),
   779     JS_FNINFO("ForkJoinGetSlice",
   780               intrinsic_ForkJoinGetSlice,
   781               &intrinsic_ForkJoinGetSlice_jitInfo, 1, 0),
   782     JS_FNINFO("InParallelSection",
   783               intrinsic_InParallelSection,
   784               &intrinsic_InParallelSection_jitInfo, 0, 0),
   786     // See builtin/TypedObject.h for descriptors of the typedobj functions.
   787     JS_FN("NewOpaqueTypedObject",
   788           js::NewOpaqueTypedObject,
   789           1, 0),
   790     JS_FN("NewDerivedTypedObject",
   791           js::NewDerivedTypedObject,
   792           3, 0),
   793     JS_FNINFO("AttachTypedObject",
   794               JSNativeThreadSafeWrapper<js::AttachTypedObject>,
   795               &js::AttachTypedObjectJitInfo, 3, 0),
   796     JS_FNINFO("SetTypedObjectOffset",
   797               intrinsic_SetTypedObjectOffset,
   798               &js::intrinsic_SetTypedObjectOffsetJitInfo, 2, 0),
   799     JS_FNINFO("ObjectIsTypeDescr",
   800               intrinsic_ObjectIsTypeDescr,
   801               &js::ObjectIsTypeDescrJitInfo, 1, 0),
   802     JS_FNINFO("ObjectIsTypedObject",
   803               intrinsic_ObjectIsTypedObject,
   804               &js::ObjectIsTypedObjectJitInfo, 1, 0),
   805     JS_FNINFO("ObjectIsTransparentTypedObject",
   806               intrinsic_ObjectIsTransparentTypedObject,
   807               &js::ObjectIsTransparentTypedObjectJitInfo, 1, 0),
   808     JS_FNINFO("TypedObjectIsAttached",
   809               JSNativeThreadSafeWrapper<js::TypedObjectIsAttached>,
   810               &js::TypedObjectIsAttachedJitInfo, 1, 0),
   811     JS_FNINFO("ObjectIsOpaqueTypedObject",
   812               intrinsic_ObjectIsOpaqueTypedObject,
   813               &js::ObjectIsOpaqueTypedObjectJitInfo, 1, 0),
   814     JS_FNINFO("TypeDescrIsArrayType",
   815               intrinsic_TypeDescrIsArrayType,
   816               &js::TypeDescrIsArrayTypeJitInfo, 1, 0),
   817     JS_FNINFO("TypeDescrIsUnsizedArrayType",
   818               intrinsic_TypeDescrIsUnsizedArrayType,
   819               &js::TypeDescrIsUnsizedArrayTypeJitInfo, 1, 0),
   820     JS_FNINFO("TypeDescrIsSizedArrayType",
   821               intrinsic_TypeDescrIsSizedArrayType,
   822               &js::TypeDescrIsSizedArrayTypeJitInfo, 1, 0),
   823     JS_FNINFO("TypeDescrIsSimpleType",
   824               intrinsic_TypeDescrIsSimpleType,
   825               &js::TypeDescrIsSimpleTypeJitInfo, 1, 0),
   826     JS_FNINFO("ClampToUint8",
   827               JSNativeThreadSafeWrapper<js::ClampToUint8>,
   828               &js::ClampToUint8JitInfo, 1, 0),
   829     JS_FNINFO("Memcpy",
   830               JSNativeThreadSafeWrapper<js::Memcpy>,
   831               &js::MemcpyJitInfo, 5, 0),
   832     JS_FN("GetTypedObjectModule", js::GetTypedObjectModule, 0, 0),
   833     JS_FN("GetFloat32x4TypeDescr", js::GetFloat32x4TypeDescr, 0, 0),
   834     JS_FN("GetInt32x4TypeDescr", js::GetInt32x4TypeDescr, 0, 0),
   836 #define LOAD_AND_STORE_SCALAR_FN_DECLS(_constant, _type, _name)               \
   837     JS_FNINFO("Store_" #_name,                                                \
   838               JSNativeThreadSafeWrapper<js::StoreScalar##_type::Func>,        \
   839               &js::StoreScalar##_type::JitInfo, 3, 0),                        \
   840     JS_FNINFO("Load_" #_name,                                                 \
   841               JSNativeThreadSafeWrapper<js::LoadScalar##_type::Func>,         \
   842               &js::LoadScalar##_type::JitInfo, 3, 0),
   843     JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(LOAD_AND_STORE_SCALAR_FN_DECLS)
   845 #define LOAD_AND_STORE_REFERENCE_FN_DECLS(_constant, _type, _name)              \
   846     JS_FNINFO("Store_" #_name,                                                  \
   847               JSNativeThreadSafeWrapper<js::StoreReference##_type::Func>,       \
   848               &js::StoreReference##_type::JitInfo, 3, 0),                       \
   849     JS_FNINFO("Load_" #_name,                                                   \
   850               JSNativeThreadSafeWrapper<js::LoadReference##_type::Func>,        \
   851               &js::LoadReference##_type::JitInfo, 3, 0),
   852     JS_FOR_EACH_REFERENCE_TYPE_REPR(LOAD_AND_STORE_REFERENCE_FN_DECLS)
   854     // See builtin/Intl.h for descriptions of the intl_* functions.
   855     JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
   856     JS_FN("intl_availableCollations", intl_availableCollations, 1,0),
   857     JS_FN("intl_Collator", intl_Collator, 2,0),
   858     JS_FN("intl_Collator_availableLocales", intl_Collator_availableLocales, 0,0),
   859     JS_FN("intl_CompareStrings", intl_CompareStrings, 3,0),
   860     JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2,0),
   861     JS_FN("intl_DateTimeFormat_availableLocales", intl_DateTimeFormat_availableLocales, 0,0),
   862     JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0),
   863     JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
   864     JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
   865     JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0),
   866     JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
   867     JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
   869     // See builtin/RegExp.h for descriptions of the regexp_* functions.
   870     JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
   871     JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
   873 #ifdef DEBUG
   874     JS_FNINFO("Dump",
   875               JSNativeThreadSafeWrapper<intrinsic_Dump>,
   876               &intrinsic_Dump_jitInfo, 1,0),
   878     JS_FNINFO("ParallelSpew",
   879               JSNativeThreadSafeWrapper<intrinsic_ParallelSpew>,
   880               &intrinsic_ParallelSpew_jitInfo, 1,0),
   881 #endif
   883     JS_FS_END
   884 };
   886 void
   887 js::FillSelfHostingCompileOptions(CompileOptions &options)
   888 {
   889     /*
   890      * In self-hosting mode, scripts emit JSOP_GETINTRINSIC instead of
   891      * JSOP_NAME or JSOP_GNAME to access unbound variables. JSOP_GETINTRINSIC
   892      * does a name lookup in a special object, whose properties are filled in
   893      * lazily upon first access for a given global.
   894      *
   895      * As that object is inaccessible to client code, the lookups are
   896      * guaranteed to return the original objects, ensuring safe implementation
   897      * of self-hosted builtins.
   898      *
   899      * Additionally, the special syntax callFunction(fun, receiver, ...args)
   900      * is supported, for which bytecode is emitted that invokes |fun| with
   901      * |receiver| as the this-object and ...args as the arguments.
   902      */
   903     options.setIntroductionType("self-hosted");
   904     options.setFileAndLine("self-hosted", 1);
   905     options.setSelfHostingMode(true);
   906     options.setCanLazilyParse(false);
   907     options.setVersion(JSVERSION_LATEST);
   908     options.werrorOption = true;
   909     options.strictOption = true;
   911 #ifdef DEBUG
   912     options.extraWarningsOption = true;
   913 #endif
   914 }
   916 bool
   917 JSRuntime::initSelfHosting(JSContext *cx)
   918 {
   919     JS_ASSERT(!selfHostingGlobal_);
   921     if (cx->runtime()->parentRuntime) {
   922         selfHostingGlobal_ = cx->runtime()->parentRuntime->selfHostingGlobal_;
   923         return true;
   924     }
   926     /*
   927      * Self hosted state can be accessed from threads for other runtimes
   928      * parented to this one, so cannot include state in the nursery.
   929      */
   930     JS::AutoDisableGenerationalGC disable(cx->runtime());
   932     bool receivesDefaultObject = !cx->options().noDefaultCompartmentObject();
   933     RootedObject savedGlobal(cx, receivesDefaultObject
   934                                  ? js::DefaultObjectForContextOrNull(cx)
   935                                  : nullptr);
   936     JS::CompartmentOptions compartmentOptions;
   937     compartmentOptions.setDiscardSource(true);
   938     if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class,
   939                                                   nullptr, JS::DontFireOnNewGlobalHook,
   940                                                   compartmentOptions)))
   941         return false;
   942     JSAutoCompartment ac(cx, selfHostingGlobal_);
   943     if (receivesDefaultObject)
   944         js::SetDefaultObjectForContext(cx, selfHostingGlobal_);
   945     Rooted<GlobalObject*> shg(cx, &selfHostingGlobal_->as<GlobalObject>());
   946     selfHostingGlobal_->compartment()->isSelfHosting = true;
   947     selfHostingGlobal_->compartment()->isSystem = true;
   948     /*
   949      * During initialization of standard classes for the self-hosting global,
   950      * all self-hosted functions are ignored. Thus, we don't create cyclic
   951      * dependencies in the order of initialization.
   952      */
   953     if (!GlobalObject::initStandardClasses(cx, shg))
   954         return false;
   956     if (!JS_DefineFunctions(cx, shg, intrinsic_functions))
   957         return false;
   959     JS_FireOnNewGlobalObject(cx, shg);
   961     CompileOptions options(cx);
   962     FillSelfHostingCompileOptions(options);
   964     /*
   965      * Set a temporary error reporter printing to stderr because it is too
   966      * early in the startup process for any other reporter to be registered
   967      * and we don't want errors in self-hosted code to be silently swallowed.
   968      */
   969     JSErrorReporter oldReporter = JS_SetErrorReporter(cx, selfHosting_ErrorReporter);
   970     RootedValue rv(cx);
   971     bool ok = false;
   973     char *filename = getenv("MOZ_SELFHOSTEDJS");
   974     if (filename) {
   975         RootedScript script(cx, Compile(cx, shg, options, filename));
   976         if (script)
   977             ok = Execute(cx, script, *shg.get(), rv.address());
   978     } else {
   979         uint32_t srcLen = GetRawScriptsSize();
   981 #ifdef USE_ZLIB
   982         const unsigned char *compressed = compressedSources;
   983         uint32_t compressedLen = GetCompressedSize();
   984         ScopedJSFreePtr<char> src(reinterpret_cast<char *>(cx->malloc_(srcLen)));
   985         if (!src || !DecompressString(compressed, compressedLen,
   986                                       reinterpret_cast<unsigned char *>(src.get()), srcLen))
   987         {
   988             return false;
   989         }
   990 #else
   991         const char *src = rawSources;
   992 #endif
   994         ok = Evaluate(cx, shg, options, src, srcLen, &rv);
   995     }
   996     JS_SetErrorReporter(cx, oldReporter);
   997     if (receivesDefaultObject)
   998         js::SetDefaultObjectForContext(cx, savedGlobal);
   999     return ok;
  1002 void
  1003 JSRuntime::finishSelfHosting()
  1005     selfHostingGlobal_ = nullptr;
  1008 void
  1009 JSRuntime::markSelfHostingGlobal(JSTracer *trc)
  1011     if (selfHostingGlobal_ && !parentRuntime)
  1012         MarkObjectRoot(trc, &selfHostingGlobal_, "self-hosting global");
  1015 bool
  1016 JSRuntime::isSelfHostingCompartment(JSCompartment *comp)
  1018     return selfHostingGlobal_->compartment() == comp;
  1021 static bool
  1022 CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp);
  1024 static bool
  1025 GetUnclonedValue(JSContext *cx, HandleObject selfHostedObject, HandleId id, MutableHandleValue vp)
  1027     vp.setUndefined();
  1029     if (JSID_IS_INT(id)) {
  1030         size_t index = JSID_TO_INT(id);
  1031         if (index < selfHostedObject->getDenseInitializedLength() &&
  1032             !selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE))
  1034             vp.set(selfHostedObject->getDenseElement(JSID_TO_INT(id)));
  1035             return true;
  1039     // Since all atoms used by self hosting are marked as permanent, any
  1040     // attempt to look up a non-permanent atom will fail. We should only
  1041     // see such atoms when code is looking for properties on the self
  1042     // hosted global which aren't present.
  1043     if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) {
  1044         JS_ASSERT(selfHostedObject->is<GlobalObject>());
  1045         RootedValue value(cx, IdToValue(id));
  1046         return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
  1047                                         JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
  1050     RootedShape shape(cx, selfHostedObject->nativeLookupPure(id));
  1051     if (!shape) {
  1052         RootedValue value(cx, IdToValue(id));
  1053         return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
  1054                                         JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
  1057     JS_ASSERT(shape->hasSlot() && shape->hasDefaultGetter());
  1058     vp.set(selfHostedObject->getSlot(shape->slot()));
  1059     return true;
  1062 static bool
  1063 CloneProperties(JSContext *cx, HandleObject selfHostedObject, HandleObject clone)
  1065     AutoIdVector ids(cx);
  1067     for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) {
  1068         if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
  1069             if (!ids.append(INT_TO_JSID(i)))
  1070                 return false;
  1074     for (Shape::Range<NoGC> range(selfHostedObject->lastProperty()); !range.empty(); range.popFront()) {
  1075         Shape &shape = range.front();
  1076         if (shape.enumerable() && !ids.append(shape.propid()))
  1077             return false;
  1080     RootedId id(cx);
  1081     RootedValue val(cx);
  1082     RootedValue selfHostedValue(cx);
  1083     for (uint32_t i = 0; i < ids.length(); i++) {
  1084         id = ids[i];
  1085         if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue))
  1086             return false;
  1087         if (!CloneValue(cx, selfHostedValue, &val) ||
  1088             !JS_DefinePropertyById(cx, clone, id, val.get(), nullptr, nullptr, 0))
  1090             return false;
  1094     return true;
  1097 static JSObject *
  1098 CloneObject(JSContext *cx, HandleObject selfHostedObject)
  1100     AutoCycleDetector detect(cx, selfHostedObject);
  1101     if (!detect.init())
  1102         return nullptr;
  1103     if (detect.foundCycle()) {
  1104         JS_ReportError(cx, "SelfHosted cloning cannot handle cyclic object graphs.");
  1105         return nullptr;
  1108     RootedObject clone(cx);
  1109     if (selfHostedObject->is<JSFunction>()) {
  1110         RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>());
  1111         bool hasName = selfHostedFunction->atom() != nullptr;
  1112         // Arrow functions use the first extended slot for their lexical |this| value.
  1113         JS_ASSERT(!selfHostedFunction->isArrow());
  1114         js::gc::AllocKind kind = hasName
  1115                                  ? JSFunction::ExtendedFinalizeKind
  1116                                  : selfHostedFunction->getAllocKind();
  1117         clone = CloneFunctionObject(cx, selfHostedFunction, cx->global(), kind, TenuredObject);
  1118         // To be able to re-lazify the cloned function, its name in the
  1119         // self-hosting compartment has to be stored on the clone.
  1120         if (clone && hasName)
  1121             clone->as<JSFunction>().setExtendedSlot(0, StringValue(selfHostedFunction->atom()));
  1122     } else if (selfHostedObject->is<RegExpObject>()) {
  1123         RegExpObject &reobj = selfHostedObject->as<RegExpObject>();
  1124         RootedAtom source(cx, reobj.getSource());
  1125         JS_ASSERT(source->isPermanentAtom());
  1126         clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), nullptr);
  1127     } else if (selfHostedObject->is<DateObject>()) {
  1128         clone = JS_NewDateObjectMsec(cx, selfHostedObject->as<DateObject>().UTCTime().toNumber());
  1129     } else if (selfHostedObject->is<BooleanObject>()) {
  1130         clone = BooleanObject::create(cx, selfHostedObject->as<BooleanObject>().unbox());
  1131     } else if (selfHostedObject->is<NumberObject>()) {
  1132         clone = NumberObject::create(cx, selfHostedObject->as<NumberObject>().unbox());
  1133     } else if (selfHostedObject->is<StringObject>()) {
  1134         JSString *selfHostedString = selfHostedObject->as<StringObject>().unbox();
  1135         if (!selfHostedString->isFlat())
  1136             MOZ_CRASH();
  1137         RootedString str(cx, js_NewStringCopyN<CanGC>(cx,
  1138                                                       selfHostedString->asFlat().chars(),
  1139                                                       selfHostedString->asFlat().length()));
  1140         if (!str)
  1141             return nullptr;
  1142         clone = StringObject::create(cx, str);
  1143     } else if (selfHostedObject->is<ArrayObject>()) {
  1144         clone = NewDenseEmptyArray(cx, nullptr, TenuredObject);
  1145     } else {
  1146         JS_ASSERT(selfHostedObject->isNative());
  1147         clone = NewObjectWithGivenProto(cx, selfHostedObject->getClass(), nullptr, cx->global(),
  1148                                         selfHostedObject->tenuredGetAllocKind(),
  1149                                         SingletonObject);
  1151     if (!clone)
  1152         return nullptr;
  1153     if (!CloneProperties(cx, selfHostedObject, clone))
  1154         return nullptr;
  1155     return clone;
  1158 static bool
  1159 CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp)
  1161     if (selfHostedValue.isObject()) {
  1162         RootedObject selfHostedObject(cx, &selfHostedValue.toObject());
  1163         JSObject *clone = CloneObject(cx, selfHostedObject);
  1164         if (!clone)
  1165             return false;
  1166         vp.setObject(*clone);
  1167     } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) {
  1168         // Nothing to do here: these are represented inline in the value.
  1169         vp.set(selfHostedValue);
  1170     } else if (selfHostedValue.isString()) {
  1171         if (!selfHostedValue.toString()->isFlat())
  1172             MOZ_CRASH();
  1173         JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat();
  1174         JSString *clone = js_NewStringCopyN<CanGC>(cx,
  1175                                                    selfHostedString->chars(),
  1176                                                    selfHostedString->length());
  1177         if (!clone)
  1178             return false;
  1179         vp.setString(clone);
  1180     } else {
  1181         MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
  1183     return true;
  1186 bool
  1187 JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, HandlePropertyName name,
  1188                                          HandleFunction targetFun)
  1190     RootedId id(cx, NameToId(name));
  1191     RootedValue funVal(cx);
  1192     if (!GetUnclonedValue(cx, HandleObject::fromMarkedLocation(&selfHostingGlobal_), id, &funVal))
  1193         return false;
  1195     RootedFunction sourceFun(cx, &funVal.toObject().as<JSFunction>());
  1196     // JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
  1197     // aren't any.
  1198     JS_ASSERT(!sourceFun->isGenerator());
  1199     RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx));
  1200     if (!sourceScript)
  1201         return false;
  1202     JS_ASSERT(!sourceScript->enclosingStaticScope());
  1203     JSScript *cscript = CloneScript(cx, NullPtr(), targetFun, sourceScript);
  1204     if (!cscript)
  1205         return false;
  1206     cscript->setFunction(targetFun);
  1208     JS_ASSERT(sourceFun->nargs() == targetFun->nargs());
  1209     // The target function might have been relazified after it's flags changed.
  1210     targetFun->setFlags((targetFun->flags() & ~JSFunction::INTERPRETED_LAZY) |
  1211                         sourceFun->flags() | JSFunction::EXTENDED);
  1212     targetFun->setScript(cscript);
  1213     JS_ASSERT(targetFun->isExtended());
  1214     return true;
  1217 bool
  1218 JSRuntime::cloneSelfHostedValue(JSContext *cx, HandlePropertyName name, MutableHandleValue vp)
  1220     RootedId id(cx, NameToId(name));
  1221     RootedValue selfHostedValue(cx);
  1222     if (!GetUnclonedValue(cx, HandleObject::fromMarkedLocation(&selfHostingGlobal_), id, &selfHostedValue))
  1223         return false;
  1225     /*
  1226      * We don't clone if we're operating in the self-hosting global, as that
  1227      * means we're currently executing the self-hosting script while
  1228      * initializing the runtime (see JSRuntime::initSelfHosting).
  1229      */
  1230     if (cx->global() == selfHostingGlobal_) {
  1231         vp.set(selfHostedValue);
  1232         return true;
  1235     return CloneValue(cx, selfHostedValue, vp);
  1238 JSFunction *
  1239 js::SelfHostedFunction(JSContext *cx, HandlePropertyName propName)
  1241     RootedValue func(cx);
  1242     if (!GlobalObject::getIntrinsicValue(cx, cx->global(), propName, &func))
  1243         return nullptr;
  1245     JS_ASSERT(func.isObject());
  1246     JS_ASSERT(func.toObject().is<JSFunction>());
  1247     return &func.toObject().as<JSFunction>();
  1250 bool
  1251 js::IsSelfHostedFunctionWithName(JSFunction *fun, JSAtom *name)
  1253     return fun->isSelfHostedBuiltin() && fun->getExtendedSlot(0).toString() == name;

mercurial