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 +}