js/src/builtin/TestingFunctions.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "builtin/TestingFunctions.h"
michael@0 8
michael@0 9 #include "jsapi.h"
michael@0 10 #include "jscntxt.h"
michael@0 11 #include "jsfriendapi.h"
michael@0 12 #include "jsgc.h"
michael@0 13 #include "jsobj.h"
michael@0 14 #ifndef JS_MORE_DETERMINISTIC
michael@0 15 #include "jsprf.h"
michael@0 16 #endif
michael@0 17 #include "jswrapper.h"
michael@0 18
michael@0 19 #include "jit/AsmJS.h"
michael@0 20 #include "jit/AsmJSLink.h"
michael@0 21 #include "js/StructuredClone.h"
michael@0 22 #include "vm/ForkJoin.h"
michael@0 23 #include "vm/GlobalObject.h"
michael@0 24 #include "vm/Interpreter.h"
michael@0 25 #include "vm/ProxyObject.h"
michael@0 26 #include "vm/SavedStacks.h"
michael@0 27 #include "vm/TraceLogging.h"
michael@0 28
michael@0 29 #include "jscntxtinlines.h"
michael@0 30 #include "jsobjinlines.h"
michael@0 31
michael@0 32 using namespace js;
michael@0 33 using namespace JS;
michael@0 34
michael@0 35 using mozilla::ArrayLength;
michael@0 36
michael@0 37 // If fuzzingSafe is set, remove functionality that could cause problems with
michael@0 38 // fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE.
michael@0 39 static bool fuzzingSafe = false;
michael@0 40
michael@0 41 static bool
michael@0 42 GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp)
michael@0 43 {
michael@0 44 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 45 RootedObject info(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
michael@0 46 if (!info)
michael@0 47 return false;
michael@0 48
michael@0 49 RootedValue value(cx, BooleanValue(false));
michael@0 50 if (!JS_SetProperty(cx, info, "rooting-analysis", value))
michael@0 51 return false;
michael@0 52
michael@0 53 #ifdef JSGC_USE_EXACT_ROOTING
michael@0 54 value = BooleanValue(true);
michael@0 55 #else
michael@0 56 value = BooleanValue(false);
michael@0 57 #endif
michael@0 58 if (!JS_SetProperty(cx, info, "exact-rooting", value))
michael@0 59 return false;
michael@0 60
michael@0 61 #ifdef DEBUG
michael@0 62 value = BooleanValue(true);
michael@0 63 #else
michael@0 64 value = BooleanValue(false);
michael@0 65 #endif
michael@0 66 if (!JS_SetProperty(cx, info, "debug", value))
michael@0 67 return false;
michael@0 68
michael@0 69 #ifdef JS_HAS_CTYPES
michael@0 70 value = BooleanValue(true);
michael@0 71 #else
michael@0 72 value = BooleanValue(false);
michael@0 73 #endif
michael@0 74 if (!JS_SetProperty(cx, info, "has-ctypes", value))
michael@0 75 return false;
michael@0 76
michael@0 77 #ifdef JS_CPU_X86
michael@0 78 value = BooleanValue(true);
michael@0 79 #else
michael@0 80 value = BooleanValue(false);
michael@0 81 #endif
michael@0 82 if (!JS_SetProperty(cx, info, "x86", value))
michael@0 83 return false;
michael@0 84
michael@0 85 #ifdef JS_CPU_X64
michael@0 86 value = BooleanValue(true);
michael@0 87 #else
michael@0 88 value = BooleanValue(false);
michael@0 89 #endif
michael@0 90 if (!JS_SetProperty(cx, info, "x64", value))
michael@0 91 return false;
michael@0 92
michael@0 93 #ifdef JS_ARM_SIMULATOR
michael@0 94 value = BooleanValue(true);
michael@0 95 #else
michael@0 96 value = BooleanValue(false);
michael@0 97 #endif
michael@0 98 if (!JS_SetProperty(cx, info, "arm-simulator", value))
michael@0 99 return false;
michael@0 100
michael@0 101 #ifdef MOZ_ASAN
michael@0 102 value = BooleanValue(true);
michael@0 103 #else
michael@0 104 value = BooleanValue(false);
michael@0 105 #endif
michael@0 106 if (!JS_SetProperty(cx, info, "asan", value))
michael@0 107 return false;
michael@0 108
michael@0 109 #ifdef JS_GC_ZEAL
michael@0 110 value = BooleanValue(true);
michael@0 111 #else
michael@0 112 value = BooleanValue(false);
michael@0 113 #endif
michael@0 114 if (!JS_SetProperty(cx, info, "has-gczeal", value))
michael@0 115 return false;
michael@0 116
michael@0 117 #ifdef JS_THREADSAFE
michael@0 118 value = BooleanValue(true);
michael@0 119 #else
michael@0 120 value = BooleanValue(false);
michael@0 121 #endif
michael@0 122 if (!JS_SetProperty(cx, info, "threadsafe", value))
michael@0 123 return false;
michael@0 124
michael@0 125 #ifdef JS_MORE_DETERMINISTIC
michael@0 126 value = BooleanValue(true);
michael@0 127 #else
michael@0 128 value = BooleanValue(false);
michael@0 129 #endif
michael@0 130 if (!JS_SetProperty(cx, info, "more-deterministic", value))
michael@0 131 return false;
michael@0 132
michael@0 133 #ifdef MOZ_PROFILING
michael@0 134 value = BooleanValue(true);
michael@0 135 #else
michael@0 136 value = BooleanValue(false);
michael@0 137 #endif
michael@0 138 if (!JS_SetProperty(cx, info, "profiling", value))
michael@0 139 return false;
michael@0 140
michael@0 141 #ifdef INCLUDE_MOZILLA_DTRACE
michael@0 142 value = BooleanValue(true);
michael@0 143 #else
michael@0 144 value = BooleanValue(false);
michael@0 145 #endif
michael@0 146 if (!JS_SetProperty(cx, info, "dtrace", value))
michael@0 147 return false;
michael@0 148
michael@0 149 #ifdef MOZ_TRACE_JSCALLS
michael@0 150 value = BooleanValue(true);
michael@0 151 #else
michael@0 152 value = BooleanValue(false);
michael@0 153 #endif
michael@0 154 if (!JS_SetProperty(cx, info, "trace-jscalls-api", value))
michael@0 155 return false;
michael@0 156
michael@0 157 #ifdef JSGC_INCREMENTAL
michael@0 158 value = BooleanValue(true);
michael@0 159 #else
michael@0 160 value = BooleanValue(false);
michael@0 161 #endif
michael@0 162 if (!JS_SetProperty(cx, info, "incremental-gc", value))
michael@0 163 return false;
michael@0 164
michael@0 165 #ifdef JSGC_GENERATIONAL
michael@0 166 value = BooleanValue(true);
michael@0 167 #else
michael@0 168 value = BooleanValue(false);
michael@0 169 #endif
michael@0 170 if (!JS_SetProperty(cx, info, "generational-gc", value))
michael@0 171 return false;
michael@0 172
michael@0 173 #ifdef MOZ_VALGRIND
michael@0 174 value = BooleanValue(true);
michael@0 175 #else
michael@0 176 value = BooleanValue(false);
michael@0 177 #endif
michael@0 178 if (!JS_SetProperty(cx, info, "valgrind", value))
michael@0 179 return false;
michael@0 180
michael@0 181 #ifdef JS_OOM_DO_BACKTRACES
michael@0 182 value = BooleanValue(true);
michael@0 183 #else
michael@0 184 value = BooleanValue(false);
michael@0 185 #endif
michael@0 186 if (!JS_SetProperty(cx, info, "oom-backtraces", value))
michael@0 187 return false;
michael@0 188
michael@0 189 #ifdef ENABLE_PARALLEL_JS
michael@0 190 value = BooleanValue(true);
michael@0 191 #else
michael@0 192 value = BooleanValue(false);
michael@0 193 #endif
michael@0 194 if (!JS_SetProperty(cx, info, "parallelJS", value))
michael@0 195 return false;
michael@0 196
michael@0 197 #ifdef ENABLE_BINARYDATA
michael@0 198 value = BooleanValue(true);
michael@0 199 #else
michael@0 200 value = BooleanValue(false);
michael@0 201 #endif
michael@0 202 if (!JS_SetProperty(cx, info, "binary-data", value))
michael@0 203 return false;
michael@0 204
michael@0 205 #ifdef EXPOSE_INTL_API
michael@0 206 value = BooleanValue(true);
michael@0 207 #else
michael@0 208 value = BooleanValue(false);
michael@0 209 #endif
michael@0 210 if (!JS_SetProperty(cx, info, "intl-api", value))
michael@0 211 return false;
michael@0 212
michael@0 213 args.rval().setObject(*info);
michael@0 214 return true;
michael@0 215 }
michael@0 216
michael@0 217 static bool
michael@0 218 GC(JSContext *cx, unsigned argc, jsval *vp)
michael@0 219 {
michael@0 220 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 221
michael@0 222 /*
michael@0 223 * If the first argument is 'compartment', we collect any compartments
michael@0 224 * previously scheduled for GC via schedulegc. If the first argument is an
michael@0 225 * object, we collect the object's compartment (and any other compartments
michael@0 226 * scheduled for GC). Otherwise, we collect all compartments.
michael@0 227 */
michael@0 228 bool compartment = false;
michael@0 229 if (args.length() == 1) {
michael@0 230 Value arg = args[0];
michael@0 231 if (arg.isString()) {
michael@0 232 if (!JS_StringEqualsAscii(cx, arg.toString(), "compartment", &compartment))
michael@0 233 return false;
michael@0 234 } else if (arg.isObject()) {
michael@0 235 PrepareZoneForGC(UncheckedUnwrap(&arg.toObject())->zone());
michael@0 236 compartment = true;
michael@0 237 }
michael@0 238 }
michael@0 239
michael@0 240 #ifndef JS_MORE_DETERMINISTIC
michael@0 241 size_t preBytes = cx->runtime()->gcBytes;
michael@0 242 #endif
michael@0 243
michael@0 244 if (compartment)
michael@0 245 PrepareForDebugGC(cx->runtime());
michael@0 246 else
michael@0 247 PrepareForFullGC(cx->runtime());
michael@0 248 GCForReason(cx->runtime(), gcreason::API);
michael@0 249
michael@0 250 char buf[256] = { '\0' };
michael@0 251 #ifndef JS_MORE_DETERMINISTIC
michael@0 252 JS_snprintf(buf, sizeof(buf), "before %lu, after %lu\n",
michael@0 253 (unsigned long)preBytes, (unsigned long)cx->runtime()->gcBytes);
michael@0 254 #endif
michael@0 255 JSString *str = JS_NewStringCopyZ(cx, buf);
michael@0 256 if (!str)
michael@0 257 return false;
michael@0 258 args.rval().setString(str);
michael@0 259 return true;
michael@0 260 }
michael@0 261
michael@0 262 static bool
michael@0 263 MinorGC(JSContext *cx, unsigned argc, jsval *vp)
michael@0 264 {
michael@0 265 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 266 #ifdef JSGC_GENERATIONAL
michael@0 267 if (args.get(0) == BooleanValue(true))
michael@0 268 cx->runtime()->gcStoreBuffer.setAboutToOverflow();
michael@0 269
michael@0 270 MinorGC(cx, gcreason::API);
michael@0 271 #endif
michael@0 272 args.rval().setUndefined();
michael@0 273 return true;
michael@0 274 }
michael@0 275
michael@0 276 static const struct ParamPair {
michael@0 277 const char *name;
michael@0 278 JSGCParamKey param;
michael@0 279 } paramMap[] = {
michael@0 280 {"maxBytes", JSGC_MAX_BYTES },
michael@0 281 {"maxMallocBytes", JSGC_MAX_MALLOC_BYTES},
michael@0 282 {"gcBytes", JSGC_BYTES},
michael@0 283 {"gcNumber", JSGC_NUMBER},
michael@0 284 {"sliceTimeBudget", JSGC_SLICE_TIME_BUDGET},
michael@0 285 {"markStackLimit", JSGC_MARK_STACK_LIMIT}
michael@0 286 };
michael@0 287
michael@0 288 // Keep this in sync with above params.
michael@0 289 #define GC_PARAMETER_ARGS_LIST "maxBytes, maxMallocBytes, gcBytes, gcNumber, sliceTimeBudget, or markStackLimit"
michael@0 290
michael@0 291 static bool
michael@0 292 GCParameter(JSContext *cx, unsigned argc, Value *vp)
michael@0 293 {
michael@0 294 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 295
michael@0 296 JSString *str = ToString(cx, args.get(0));
michael@0 297 if (!str)
michael@0 298 return false;
michael@0 299
michael@0 300 JSFlatString *flatStr = JS_FlattenString(cx, str);
michael@0 301 if (!flatStr)
michael@0 302 return false;
michael@0 303
michael@0 304 size_t paramIndex = 0;
michael@0 305 for (;; paramIndex++) {
michael@0 306 if (paramIndex == ArrayLength(paramMap)) {
michael@0 307 JS_ReportError(cx,
michael@0 308 "the first argument must be one of " GC_PARAMETER_ARGS_LIST);
michael@0 309 return false;
michael@0 310 }
michael@0 311 if (JS_FlatStringEqualsAscii(flatStr, paramMap[paramIndex].name))
michael@0 312 break;
michael@0 313 }
michael@0 314 JSGCParamKey param = paramMap[paramIndex].param;
michael@0 315
michael@0 316 // Request mode.
michael@0 317 if (args.length() == 1) {
michael@0 318 uint32_t value = JS_GetGCParameter(cx->runtime(), param);
michael@0 319 args.rval().setNumber(value);
michael@0 320 return true;
michael@0 321 }
michael@0 322
michael@0 323 if (param == JSGC_NUMBER || param == JSGC_BYTES) {
michael@0 324 JS_ReportError(cx, "Attempt to change read-only parameter %s",
michael@0 325 paramMap[paramIndex].name);
michael@0 326 return false;
michael@0 327 }
michael@0 328
michael@0 329 uint32_t value;
michael@0 330 if (!ToUint32(cx, args[1], &value))
michael@0 331 return false;
michael@0 332
michael@0 333 if (!value) {
michael@0 334 JS_ReportError(cx, "the second argument must be convertable to uint32_t "
michael@0 335 "with non-zero value");
michael@0 336 return false;
michael@0 337 }
michael@0 338
michael@0 339 if (param == JSGC_MARK_STACK_LIMIT && IsIncrementalGCInProgress(cx->runtime())) {
michael@0 340 JS_ReportError(cx, "attempt to set markStackLimit while a GC is in progress");
michael@0 341 return false;
michael@0 342 }
michael@0 343
michael@0 344 if (param == JSGC_MAX_BYTES) {
michael@0 345 uint32_t gcBytes = JS_GetGCParameter(cx->runtime(), JSGC_BYTES);
michael@0 346 if (value < gcBytes) {
michael@0 347 JS_ReportError(cx,
michael@0 348 "attempt to set maxBytes to the value less than the current "
michael@0 349 "gcBytes (%u)",
michael@0 350 gcBytes);
michael@0 351 return false;
michael@0 352 }
michael@0 353 }
michael@0 354
michael@0 355 JS_SetGCParameter(cx->runtime(), param, value);
michael@0 356 args.rval().setUndefined();
michael@0 357 return true;
michael@0 358 }
michael@0 359
michael@0 360 static bool
michael@0 361 IsProxy(JSContext *cx, unsigned argc, Value *vp)
michael@0 362 {
michael@0 363 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 364 if (args.length() != 1) {
michael@0 365 JS_ReportError(cx, "the function takes exactly one argument");
michael@0 366 return false;
michael@0 367 }
michael@0 368 if (!args[0].isObject()) {
michael@0 369 args.rval().setBoolean(false);
michael@0 370 return true;
michael@0 371 }
michael@0 372 args.rval().setBoolean(args[0].toObject().is<ProxyObject>());
michael@0 373 return true;
michael@0 374 }
michael@0 375
michael@0 376 static bool
michael@0 377 IsLazyFunction(JSContext *cx, unsigned argc, Value *vp)
michael@0 378 {
michael@0 379 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 380 if (args.length() != 1) {
michael@0 381 JS_ReportError(cx, "The function takes exactly one argument.");
michael@0 382 return false;
michael@0 383 }
michael@0 384 if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
michael@0 385 JS_ReportError(cx, "The first argument should be a function.");
michael@0 386 return true;
michael@0 387 }
michael@0 388 args.rval().setBoolean(args[0].toObject().as<JSFunction>().isInterpretedLazy());
michael@0 389 return true;
michael@0 390 }
michael@0 391
michael@0 392 static bool
michael@0 393 IsRelazifiableFunction(JSContext *cx, unsigned argc, Value *vp)
michael@0 394 {
michael@0 395 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 396 if (args.length() != 1) {
michael@0 397 JS_ReportError(cx, "The function takes exactly one argument.");
michael@0 398 return false;
michael@0 399 }
michael@0 400 if (!args[0].isObject() ||
michael@0 401 !args[0].toObject().is<JSFunction>())
michael@0 402 {
michael@0 403 JS_ReportError(cx, "The first argument should be a function.");
michael@0 404 return true;
michael@0 405 }
michael@0 406
michael@0 407 JSFunction *fun = &args[0].toObject().as<JSFunction>();
michael@0 408 args.rval().setBoolean(fun->hasScript() && fun->nonLazyScript()->isRelazifiable());
michael@0 409 return true;
michael@0 410 }
michael@0 411
michael@0 412 static bool
michael@0 413 InternalConst(JSContext *cx, unsigned argc, jsval *vp)
michael@0 414 {
michael@0 415 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 416 if (args.length() == 0) {
michael@0 417 JS_ReportError(cx, "the function takes exactly one argument");
michael@0 418 return false;
michael@0 419 }
michael@0 420
michael@0 421 JSString *str = ToString(cx, args[0]);
michael@0 422 if (!str)
michael@0 423 return false;
michael@0 424 JSFlatString *flat = JS_FlattenString(cx, str);
michael@0 425 if (!flat)
michael@0 426 return false;
michael@0 427
michael@0 428 if (JS_FlatStringEqualsAscii(flat, "INCREMENTAL_MARK_STACK_BASE_CAPACITY")) {
michael@0 429 args.rval().setNumber(uint32_t(js::INCREMENTAL_MARK_STACK_BASE_CAPACITY));
michael@0 430 } else {
michael@0 431 JS_ReportError(cx, "unknown const name");
michael@0 432 return false;
michael@0 433 }
michael@0 434 return true;
michael@0 435 }
michael@0 436
michael@0 437 static bool
michael@0 438 GCPreserveCode(JSContext *cx, unsigned argc, jsval *vp)
michael@0 439 {
michael@0 440 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 441
michael@0 442 if (args.length() != 0) {
michael@0 443 RootedObject callee(cx, &args.callee());
michael@0 444 ReportUsageError(cx, callee, "Wrong number of arguments");
michael@0 445 return false;
michael@0 446 }
michael@0 447
michael@0 448 cx->runtime()->alwaysPreserveCode = true;
michael@0 449
michael@0 450 args.rval().setUndefined();
michael@0 451 return true;
michael@0 452 }
michael@0 453
michael@0 454 #ifdef JS_GC_ZEAL
michael@0 455 static bool
michael@0 456 GCZeal(JSContext *cx, unsigned argc, Value *vp)
michael@0 457 {
michael@0 458 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 459
michael@0 460 if (args.length() > 2) {
michael@0 461 RootedObject callee(cx, &args.callee());
michael@0 462 ReportUsageError(cx, callee, "Too many arguments");
michael@0 463 return false;
michael@0 464 }
michael@0 465
michael@0 466 uint32_t zeal;
michael@0 467 if (!ToUint32(cx, args.get(0), &zeal))
michael@0 468 return false;
michael@0 469
michael@0 470 uint32_t frequency = JS_DEFAULT_ZEAL_FREQ;
michael@0 471 if (args.length() >= 2) {
michael@0 472 if (!ToUint32(cx, args.get(1), &frequency))
michael@0 473 return false;
michael@0 474 }
michael@0 475
michael@0 476 JS_SetGCZeal(cx, (uint8_t)zeal, frequency);
michael@0 477 args.rval().setUndefined();
michael@0 478 return true;
michael@0 479 }
michael@0 480
michael@0 481 static bool
michael@0 482 ScheduleGC(JSContext *cx, unsigned argc, Value *vp)
michael@0 483 {
michael@0 484 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 485
michael@0 486 if (args.length() != 1) {
michael@0 487 RootedObject callee(cx, &args.callee());
michael@0 488 ReportUsageError(cx, callee, "Wrong number of arguments");
michael@0 489 return false;
michael@0 490 }
michael@0 491
michael@0 492 if (args[0].isInt32()) {
michael@0 493 /* Schedule a GC to happen after |arg| allocations. */
michael@0 494 JS_ScheduleGC(cx, args[0].toInt32());
michael@0 495 } else if (args[0].isObject()) {
michael@0 496 /* Ensure that |zone| is collected during the next GC. */
michael@0 497 Zone *zone = UncheckedUnwrap(&args[0].toObject())->zone();
michael@0 498 PrepareZoneForGC(zone);
michael@0 499 } else if (args[0].isString()) {
michael@0 500 /* This allows us to schedule atomsCompartment for GC. */
michael@0 501 PrepareZoneForGC(args[0].toString()->zone());
michael@0 502 }
michael@0 503
michael@0 504 args.rval().setUndefined();
michael@0 505 return true;
michael@0 506 }
michael@0 507
michael@0 508 static bool
michael@0 509 SelectForGC(JSContext *cx, unsigned argc, Value *vp)
michael@0 510 {
michael@0 511 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 512
michael@0 513 JSRuntime *rt = cx->runtime();
michael@0 514 for (unsigned i = 0; i < args.length(); i++) {
michael@0 515 if (args[i].isObject()) {
michael@0 516 if (!rt->gcSelectedForMarking.append(&args[i].toObject()))
michael@0 517 return false;
michael@0 518 }
michael@0 519 }
michael@0 520
michael@0 521 args.rval().setUndefined();
michael@0 522 return true;
michael@0 523 }
michael@0 524
michael@0 525 static bool
michael@0 526 VerifyPreBarriers(JSContext *cx, unsigned argc, jsval *vp)
michael@0 527 {
michael@0 528 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 529
michael@0 530 if (args.length() > 0) {
michael@0 531 RootedObject callee(cx, &args.callee());
michael@0 532 ReportUsageError(cx, callee, "Too many arguments");
michael@0 533 return false;
michael@0 534 }
michael@0 535
michael@0 536 gc::VerifyBarriers(cx->runtime(), gc::PreBarrierVerifier);
michael@0 537 args.rval().setUndefined();
michael@0 538 return true;
michael@0 539 }
michael@0 540
michael@0 541 static bool
michael@0 542 VerifyPostBarriers(JSContext *cx, unsigned argc, jsval *vp)
michael@0 543 {
michael@0 544 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 545 if (args.length()) {
michael@0 546 RootedObject callee(cx, &args.callee());
michael@0 547 ReportUsageError(cx, callee, "Too many arguments");
michael@0 548 return false;
michael@0 549 }
michael@0 550 gc::VerifyBarriers(cx->runtime(), gc::PostBarrierVerifier);
michael@0 551 args.rval().setUndefined();
michael@0 552 return true;
michael@0 553 }
michael@0 554
michael@0 555 static bool
michael@0 556 GCState(JSContext *cx, unsigned argc, jsval *vp)
michael@0 557 {
michael@0 558 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 559
michael@0 560 if (args.length() != 0) {
michael@0 561 RootedObject callee(cx, &args.callee());
michael@0 562 ReportUsageError(cx, callee, "Too many arguments");
michael@0 563 return false;
michael@0 564 }
michael@0 565
michael@0 566 const char *state;
michael@0 567 gc::State globalState = cx->runtime()->gcIncrementalState;
michael@0 568 if (globalState == gc::NO_INCREMENTAL)
michael@0 569 state = "none";
michael@0 570 else if (globalState == gc::MARK)
michael@0 571 state = "mark";
michael@0 572 else if (globalState == gc::SWEEP)
michael@0 573 state = "sweep";
michael@0 574 else
michael@0 575 MOZ_ASSUME_UNREACHABLE("Unobserveable global GC state");
michael@0 576
michael@0 577 JSString *str = JS_NewStringCopyZ(cx, state);
michael@0 578 if (!str)
michael@0 579 return false;
michael@0 580 args.rval().setString(str);
michael@0 581 return true;
michael@0 582 }
michael@0 583
michael@0 584 static bool
michael@0 585 DeterministicGC(JSContext *cx, unsigned argc, jsval *vp)
michael@0 586 {
michael@0 587 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 588
michael@0 589 if (args.length() != 1) {
michael@0 590 RootedObject callee(cx, &args.callee());
michael@0 591 ReportUsageError(cx, callee, "Wrong number of arguments");
michael@0 592 return false;
michael@0 593 }
michael@0 594
michael@0 595 gc::SetDeterministicGC(cx, ToBoolean(args[0]));
michael@0 596 args.rval().setUndefined();
michael@0 597 return true;
michael@0 598 }
michael@0 599 #endif /* JS_GC_ZEAL */
michael@0 600
michael@0 601 static bool
michael@0 602 GCSlice(JSContext *cx, unsigned argc, Value *vp)
michael@0 603 {
michael@0 604 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 605
michael@0 606 if (args.length() > 1) {
michael@0 607 RootedObject callee(cx, &args.callee());
michael@0 608 ReportUsageError(cx, callee, "Wrong number of arguments");
michael@0 609 return false;
michael@0 610 }
michael@0 611
michael@0 612 bool limit = true;
michael@0 613 uint32_t budget = 0;
michael@0 614 if (args.length() == 1) {
michael@0 615 if (!ToUint32(cx, args[0], &budget))
michael@0 616 return false;
michael@0 617 } else {
michael@0 618 limit = false;
michael@0 619 }
michael@0 620
michael@0 621 GCDebugSlice(cx->runtime(), limit, budget);
michael@0 622 args.rval().setUndefined();
michael@0 623 return true;
michael@0 624 }
michael@0 625
michael@0 626 static bool
michael@0 627 ValidateGC(JSContext *cx, unsigned argc, jsval *vp)
michael@0 628 {
michael@0 629 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 630
michael@0 631 if (args.length() != 1) {
michael@0 632 RootedObject callee(cx, &args.callee());
michael@0 633 ReportUsageError(cx, callee, "Wrong number of arguments");
michael@0 634 return false;
michael@0 635 }
michael@0 636
michael@0 637 gc::SetValidateGC(cx, ToBoolean(args[0]));
michael@0 638 args.rval().setUndefined();
michael@0 639 return true;
michael@0 640 }
michael@0 641
michael@0 642 static bool
michael@0 643 FullCompartmentChecks(JSContext *cx, unsigned argc, jsval *vp)
michael@0 644 {
michael@0 645 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 646
michael@0 647 if (args.length() != 1) {
michael@0 648 RootedObject callee(cx, &args.callee());
michael@0 649 ReportUsageError(cx, callee, "Wrong number of arguments");
michael@0 650 return false;
michael@0 651 }
michael@0 652
michael@0 653 gc::SetFullCompartmentChecks(cx, ToBoolean(args[0]));
michael@0 654 args.rval().setUndefined();
michael@0 655 return true;
michael@0 656 }
michael@0 657
michael@0 658 static bool
michael@0 659 NondeterministicGetWeakMapKeys(JSContext *cx, unsigned argc, jsval *vp)
michael@0 660 {
michael@0 661 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 662
michael@0 663 if (args.length() != 1) {
michael@0 664 RootedObject callee(cx, &args.callee());
michael@0 665 ReportUsageError(cx, callee, "Wrong number of arguments");
michael@0 666 return false;
michael@0 667 }
michael@0 668 if (!args[0].isObject()) {
michael@0 669 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
michael@0 670 "nondeterministicGetWeakMapKeys", "WeakMap",
michael@0 671 InformalValueTypeName(args[0]));
michael@0 672 return false;
michael@0 673 }
michael@0 674 RootedObject arr(cx);
michael@0 675 RootedObject mapObj(cx, &args[0].toObject());
michael@0 676 if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &arr))
michael@0 677 return false;
michael@0 678 if (!arr) {
michael@0 679 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
michael@0 680 "nondeterministicGetWeakMapKeys", "WeakMap",
michael@0 681 args[0].toObject().getClass()->name);
michael@0 682 return false;
michael@0 683 }
michael@0 684 args.rval().setObject(*arr);
michael@0 685 return true;
michael@0 686 }
michael@0 687
michael@0 688 struct JSCountHeapNode {
michael@0 689 void *thing;
michael@0 690 JSGCTraceKind kind;
michael@0 691 JSCountHeapNode *next;
michael@0 692 };
michael@0 693
michael@0 694 typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> VisitedSet;
michael@0 695
michael@0 696 class CountHeapTracer
michael@0 697 {
michael@0 698 public:
michael@0 699 CountHeapTracer(JSRuntime *rt, JSTraceCallback callback) : base(rt, callback) {}
michael@0 700
michael@0 701 JSTracer base;
michael@0 702 VisitedSet visited;
michael@0 703 JSCountHeapNode *traceList;
michael@0 704 JSCountHeapNode *recycleList;
michael@0 705 bool ok;
michael@0 706 };
michael@0 707
michael@0 708 static void
michael@0 709 CountHeapNotify(JSTracer *trc, void **thingp, JSGCTraceKind kind)
michael@0 710 {
michael@0 711 JS_ASSERT(trc->callback == CountHeapNotify);
michael@0 712
michael@0 713 CountHeapTracer *countTracer = (CountHeapTracer *)trc;
michael@0 714 void *thing = *thingp;
michael@0 715
michael@0 716 if (!countTracer->ok)
michael@0 717 return;
michael@0 718
michael@0 719 VisitedSet::AddPtr p = countTracer->visited.lookupForAdd(thing);
michael@0 720 if (p)
michael@0 721 return;
michael@0 722
michael@0 723 if (!countTracer->visited.add(p, thing)) {
michael@0 724 countTracer->ok = false;
michael@0 725 return;
michael@0 726 }
michael@0 727
michael@0 728 JSCountHeapNode *node = countTracer->recycleList;
michael@0 729 if (node) {
michael@0 730 countTracer->recycleList = node->next;
michael@0 731 } else {
michael@0 732 node = js_pod_malloc<JSCountHeapNode>();
michael@0 733 if (!node) {
michael@0 734 countTracer->ok = false;
michael@0 735 return;
michael@0 736 }
michael@0 737 }
michael@0 738 node->thing = thing;
michael@0 739 node->kind = kind;
michael@0 740 node->next = countTracer->traceList;
michael@0 741 countTracer->traceList = node;
michael@0 742 }
michael@0 743
michael@0 744 static const struct TraceKindPair {
michael@0 745 const char *name;
michael@0 746 int32_t kind;
michael@0 747 } traceKindNames[] = {
michael@0 748 { "all", -1 },
michael@0 749 { "object", JSTRACE_OBJECT },
michael@0 750 { "string", JSTRACE_STRING },
michael@0 751 };
michael@0 752
michael@0 753 static bool
michael@0 754 CountHeap(JSContext *cx, unsigned argc, jsval *vp)
michael@0 755 {
michael@0 756 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 757
michael@0 758 RootedValue startValue(cx, UndefinedValue());
michael@0 759 if (args.length() > 0) {
michael@0 760 jsval v = args[0];
michael@0 761 if (v.isMarkable()) {
michael@0 762 startValue = v;
michael@0 763 } else if (!v.isNull()) {
michael@0 764 JS_ReportError(cx,
michael@0 765 "the first argument is not null or a heap-allocated "
michael@0 766 "thing");
michael@0 767 return false;
michael@0 768 }
michael@0 769 }
michael@0 770
michael@0 771 RootedValue traceValue(cx);
michael@0 772 int32_t traceKind = -1;
michael@0 773 void *traceThing = nullptr;
michael@0 774 if (args.length() > 1) {
michael@0 775 JSString *str = ToString(cx, args[1]);
michael@0 776 if (!str)
michael@0 777 return false;
michael@0 778 JSFlatString *flatStr = JS_FlattenString(cx, str);
michael@0 779 if (!flatStr)
michael@0 780 return false;
michael@0 781 if (JS_FlatStringEqualsAscii(flatStr, "specific")) {
michael@0 782 if (args.length() < 3) {
michael@0 783 JS_ReportError(cx, "tracing of specific value requested "
michael@0 784 "but no value provided");
michael@0 785 return false;
michael@0 786 }
michael@0 787 traceValue = args[2];
michael@0 788 if (!traceValue.isMarkable()){
michael@0 789 JS_ReportError(cx, "cannot trace this kind of value");
michael@0 790 return false;
michael@0 791 }
michael@0 792 traceThing = traceValue.toGCThing();
michael@0 793 } else {
michael@0 794 for (size_t i = 0; ;) {
michael@0 795 if (JS_FlatStringEqualsAscii(flatStr, traceKindNames[i].name)) {
michael@0 796 traceKind = traceKindNames[i].kind;
michael@0 797 break;
michael@0 798 }
michael@0 799 if (++i == ArrayLength(traceKindNames)) {
michael@0 800 JSAutoByteString bytes(cx, str);
michael@0 801 if (!!bytes)
michael@0 802 JS_ReportError(cx, "trace kind name '%s' is unknown", bytes.ptr());
michael@0 803 return false;
michael@0 804 }
michael@0 805 }
michael@0 806 }
michael@0 807 }
michael@0 808
michael@0 809 CountHeapTracer countTracer(JS_GetRuntime(cx), CountHeapNotify);
michael@0 810 if (!countTracer.visited.init()) {
michael@0 811 JS_ReportOutOfMemory(cx);
michael@0 812 return false;
michael@0 813 }
michael@0 814 countTracer.ok = true;
michael@0 815 countTracer.traceList = nullptr;
michael@0 816 countTracer.recycleList = nullptr;
michael@0 817
michael@0 818 if (startValue.isUndefined()) {
michael@0 819 JS_TraceRuntime(&countTracer.base);
michael@0 820 } else {
michael@0 821 JS_CallValueTracer(&countTracer.base, startValue.address(), "root");
michael@0 822 }
michael@0 823
michael@0 824 JSCountHeapNode *node;
michael@0 825 size_t counter = 0;
michael@0 826 while ((node = countTracer.traceList) != nullptr) {
michael@0 827 if (traceThing == nullptr) {
michael@0 828 // We are looking for all nodes with a specific kind
michael@0 829 if (traceKind == -1 || node->kind == traceKind)
michael@0 830 counter++;
michael@0 831 } else {
michael@0 832 // We are looking for some specific thing
michael@0 833 if (node->thing == traceThing)
michael@0 834 counter++;
michael@0 835 }
michael@0 836 countTracer.traceList = node->next;
michael@0 837 node->next = countTracer.recycleList;
michael@0 838 countTracer.recycleList = node;
michael@0 839 JS_TraceChildren(&countTracer.base, node->thing, node->kind);
michael@0 840 }
michael@0 841 while ((node = countTracer.recycleList) != nullptr) {
michael@0 842 countTracer.recycleList = node->next;
michael@0 843 js_free(node);
michael@0 844 }
michael@0 845 if (!countTracer.ok) {
michael@0 846 JS_ReportOutOfMemory(cx);
michael@0 847 return false;
michael@0 848 }
michael@0 849
michael@0 850 args.rval().setNumber(double(counter));
michael@0 851 return true;
michael@0 852 }
michael@0 853
michael@0 854 static bool
michael@0 855 GetSavedFrameCount(JSContext *cx, unsigned argc, jsval *vp)
michael@0 856 {
michael@0 857 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 858 args.rval().setNumber(cx->compartment()->savedStacks().count());
michael@0 859 return true;
michael@0 860 }
michael@0 861
michael@0 862 static bool
michael@0 863 SaveStack(JSContext *cx, unsigned argc, jsval *vp)
michael@0 864 {
michael@0 865 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 866 Rooted<SavedFrame*> frame(cx);
michael@0 867 if (!cx->compartment()->savedStacks().saveCurrentStack(cx, &frame))
michael@0 868 return false;
michael@0 869 args.rval().setObject(*frame.get());
michael@0 870 return true;
michael@0 871 }
michael@0 872
michael@0 873 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
michael@0 874 static bool
michael@0 875 OOMAfterAllocations(JSContext *cx, unsigned argc, jsval *vp)
michael@0 876 {
michael@0 877 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 878 if (args.length() != 1) {
michael@0 879 JS_ReportError(cx, "count argument required");
michael@0 880 return false;
michael@0 881 }
michael@0 882
michael@0 883 uint32_t count;
michael@0 884 if (!JS::ToUint32(cx, args[0], &count))
michael@0 885 return false;
michael@0 886
michael@0 887 OOM_maxAllocations = OOM_counter + count;
michael@0 888 return true;
michael@0 889 }
michael@0 890 #endif
michael@0 891
michael@0 892 static unsigned finalizeCount = 0;
michael@0 893
michael@0 894 static void
michael@0 895 finalize_counter_finalize(JSFreeOp *fop, JSObject *obj)
michael@0 896 {
michael@0 897 ++finalizeCount;
michael@0 898 }
michael@0 899
michael@0 900 static const JSClass FinalizeCounterClass = {
michael@0 901 "FinalizeCounter", JSCLASS_IS_ANONYMOUS,
michael@0 902 JS_PropertyStub, /* addProperty */
michael@0 903 JS_DeletePropertyStub, /* delProperty */
michael@0 904 JS_PropertyStub, /* getProperty */
michael@0 905 JS_StrictPropertyStub, /* setProperty */
michael@0 906 JS_EnumerateStub,
michael@0 907 JS_ResolveStub,
michael@0 908 JS_ConvertStub,
michael@0 909 finalize_counter_finalize
michael@0 910 };
michael@0 911
michael@0 912 static bool
michael@0 913 MakeFinalizeObserver(JSContext *cx, unsigned argc, jsval *vp)
michael@0 914 {
michael@0 915 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 916 RootedObject scope(cx, JS::CurrentGlobalOrNull(cx));
michael@0 917 if (!scope)
michael@0 918 return false;
michael@0 919
michael@0 920 JSObject *obj = JS_NewObjectWithGivenProto(cx, &FinalizeCounterClass, JS::NullPtr(), scope);
michael@0 921 if (!obj)
michael@0 922 return false;
michael@0 923
michael@0 924 args.rval().setObject(*obj);
michael@0 925 return true;
michael@0 926 }
michael@0 927
michael@0 928 static bool
michael@0 929 FinalizeCount(JSContext *cx, unsigned argc, jsval *vp)
michael@0 930 {
michael@0 931 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 932 args.rval().setInt32(finalizeCount);
michael@0 933 return true;
michael@0 934 }
michael@0 935
michael@0 936 static bool
michael@0 937 DumpHeapComplete(JSContext *cx, unsigned argc, jsval *vp)
michael@0 938 {
michael@0 939 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 940
michael@0 941 DumpHeapNurseryBehaviour nurseryBehaviour = js::IgnoreNurseryObjects;
michael@0 942 FILE *dumpFile = nullptr;
michael@0 943
michael@0 944 unsigned i = 0;
michael@0 945 if (args.length() > i) {
michael@0 946 Value v = args[i];
michael@0 947 if (v.isString()) {
michael@0 948 JSString *str = v.toString();
michael@0 949 bool same = false;
michael@0 950 if (!JS_StringEqualsAscii(cx, str, "collectNurseryBeforeDump", &same))
michael@0 951 return false;
michael@0 952 if (same) {
michael@0 953 nurseryBehaviour = js::CollectNurseryBeforeDump;
michael@0 954 ++i;
michael@0 955 }
michael@0 956 }
michael@0 957 }
michael@0 958
michael@0 959 if (args.length() > i) {
michael@0 960 Value v = args[i];
michael@0 961 if (v.isString()) {
michael@0 962 if (!fuzzingSafe) {
michael@0 963 JSString *str = v.toString();
michael@0 964 JSAutoByteString fileNameBytes;
michael@0 965 if (!fileNameBytes.encodeLatin1(cx, str))
michael@0 966 return false;
michael@0 967 const char *fileName = fileNameBytes.ptr();
michael@0 968 dumpFile = fopen(fileName, "w");
michael@0 969 if (!dumpFile) {
michael@0 970 JS_ReportError(cx, "can't open %s", fileName);
michael@0 971 return false;
michael@0 972 }
michael@0 973 }
michael@0 974 ++i;
michael@0 975 }
michael@0 976 }
michael@0 977
michael@0 978 if (i != args.length()) {
michael@0 979 JS_ReportError(cx, "bad arguments passed to dumpHeapComplete");
michael@0 980 return false;
michael@0 981 }
michael@0 982
michael@0 983 js::DumpHeapComplete(JS_GetRuntime(cx), dumpFile ? dumpFile : stdout, nurseryBehaviour);
michael@0 984
michael@0 985 if (dumpFile)
michael@0 986 fclose(dumpFile);
michael@0 987
michael@0 988 args.rval().setUndefined();
michael@0 989 return true;
michael@0 990 }
michael@0 991
michael@0 992 static bool
michael@0 993 Terminate(JSContext *cx, unsigned arg, jsval *vp)
michael@0 994 {
michael@0 995 #ifdef JS_MORE_DETERMINISTIC
michael@0 996 // Print a message to stderr in more-deterministic builds to help jsfunfuzz
michael@0 997 // find uncatchable-exception bugs.
michael@0 998 fprintf(stderr, "terminate called\n");
michael@0 999 #endif
michael@0 1000
michael@0 1001 JS_ClearPendingException(cx);
michael@0 1002 return false;
michael@0 1003 }
michael@0 1004
michael@0 1005 static bool
michael@0 1006 EnableSPSProfilingAssertions(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1007 {
michael@0 1008 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1009 if (!args.get(0).isBoolean()) {
michael@0 1010 RootedObject arg(cx, &args.callee());
michael@0 1011 ReportUsageError(cx, arg, "Must have one boolean argument");
michael@0 1012 return false;
michael@0 1013 }
michael@0 1014
michael@0 1015 static ProfileEntry stack[1000];
michael@0 1016 static uint32_t stack_size = 0;
michael@0 1017
michael@0 1018 // Disable before re-enabling; see the assertion in |SPSProfiler::setProfilingStack|.
michael@0 1019 if (cx->runtime()->spsProfiler.installed())
michael@0 1020 cx->runtime()->spsProfiler.enable(false);
michael@0 1021 SetRuntimeProfilingStack(cx->runtime(), stack, &stack_size, 1000);
michael@0 1022 cx->runtime()->spsProfiler.enableSlowAssertions(args[0].toBoolean());
michael@0 1023 cx->runtime()->spsProfiler.enable(true);
michael@0 1024
michael@0 1025 args.rval().setUndefined();
michael@0 1026 return true;
michael@0 1027 }
michael@0 1028
michael@0 1029 static bool
michael@0 1030 DisableSPSProfiling(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1031 {
michael@0 1032 if (cx->runtime()->spsProfiler.installed())
michael@0 1033 cx->runtime()->spsProfiler.enable(false);
michael@0 1034 return true;
michael@0 1035 }
michael@0 1036
michael@0 1037 static bool
michael@0 1038 EnableOsiPointRegisterChecks(JSContext *, unsigned argc, jsval *vp)
michael@0 1039 {
michael@0 1040 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1041 #if defined(JS_ION) && defined(CHECK_OSIPOINT_REGISTERS)
michael@0 1042 jit::js_JitOptions.checkOsiPointRegisters = true;
michael@0 1043 #endif
michael@0 1044 args.rval().setUndefined();
michael@0 1045 return true;
michael@0 1046 }
michael@0 1047
michael@0 1048 static bool
michael@0 1049 DisplayName(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1050 {
michael@0 1051 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1052 if (!args.get(0).isObject() || !args[0].toObject().is<JSFunction>()) {
michael@0 1053 RootedObject arg(cx, &args.callee());
michael@0 1054 ReportUsageError(cx, arg, "Must have one function argument");
michael@0 1055 return false;
michael@0 1056 }
michael@0 1057
michael@0 1058 JSFunction *fun = &args[0].toObject().as<JSFunction>();
michael@0 1059 JSString *str = fun->displayAtom();
michael@0 1060 args.rval().setString(str ? str : cx->runtime()->emptyString);
michael@0 1061 return true;
michael@0 1062 }
michael@0 1063
michael@0 1064 bool
michael@0 1065 js::testingFunc_inParallelSection(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1066 {
michael@0 1067 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1068
michael@0 1069 // If we were actually *in* a parallel section, then this function
michael@0 1070 // would be inlined to TRUE in ion-generated code.
michael@0 1071 JS_ASSERT(!InParallelSection());
michael@0 1072 args.rval().setBoolean(false);
michael@0 1073 return true;
michael@0 1074 }
michael@0 1075
michael@0 1076 static bool
michael@0 1077 ShellObjectMetadataCallback(JSContext *cx, JSObject **pmetadata)
michael@0 1078 {
michael@0 1079 RootedObject obj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
michael@0 1080 if (!obj)
michael@0 1081 return false;
michael@0 1082
michael@0 1083 RootedObject stack(cx, NewDenseEmptyArray(cx));
michael@0 1084 if (!stack)
michael@0 1085 return false;
michael@0 1086
michael@0 1087 static int createdIndex = 0;
michael@0 1088 createdIndex++;
michael@0 1089
michael@0 1090 if (!JS_DefineProperty(cx, obj, "index", createdIndex, 0,
michael@0 1091 JS_PropertyStub, JS_StrictPropertyStub))
michael@0 1092 {
michael@0 1093 return false;
michael@0 1094 }
michael@0 1095
michael@0 1096 if (!JS_DefineProperty(cx, obj, "stack", stack, 0,
michael@0 1097 JS_PropertyStub, JS_StrictPropertyStub))
michael@0 1098 {
michael@0 1099 return false;
michael@0 1100 }
michael@0 1101
michael@0 1102 int stackIndex = 0;
michael@0 1103 for (NonBuiltinScriptFrameIter iter(cx); !iter.done(); ++iter) {
michael@0 1104 if (iter.isFunctionFrame() && iter.compartment() == cx->compartment()) {
michael@0 1105 if (!JS_DefinePropertyById(cx, stack, INT_TO_JSID(stackIndex), ObjectValue(*iter.callee()),
michael@0 1106 JS_PropertyStub, JS_StrictPropertyStub, 0))
michael@0 1107 {
michael@0 1108 return false;
michael@0 1109 }
michael@0 1110 stackIndex++;
michael@0 1111 }
michael@0 1112 }
michael@0 1113
michael@0 1114 *pmetadata = obj;
michael@0 1115 return true;
michael@0 1116 }
michael@0 1117
michael@0 1118 static bool
michael@0 1119 SetObjectMetadataCallback(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1120 {
michael@0 1121 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1122
michael@0 1123 bool enabled = args.length() ? ToBoolean(args[0]) : false;
michael@0 1124 SetObjectMetadataCallback(cx, enabled ? ShellObjectMetadataCallback : nullptr);
michael@0 1125
michael@0 1126 args.rval().setUndefined();
michael@0 1127 return true;
michael@0 1128 }
michael@0 1129
michael@0 1130 static bool
michael@0 1131 SetObjectMetadata(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1132 {
michael@0 1133 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1134 if (args.length() != 2 || !args[0].isObject() || !args[1].isObject()) {
michael@0 1135 JS_ReportError(cx, "Both arguments must be objects");
michael@0 1136 return false;
michael@0 1137 }
michael@0 1138
michael@0 1139 args.rval().setUndefined();
michael@0 1140
michael@0 1141 RootedObject obj(cx, &args[0].toObject());
michael@0 1142 RootedObject metadata(cx, &args[1].toObject());
michael@0 1143 return SetObjectMetadata(cx, obj, metadata);
michael@0 1144 }
michael@0 1145
michael@0 1146 static bool
michael@0 1147 GetObjectMetadata(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1148 {
michael@0 1149 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1150 if (args.length() != 1 || !args[0].isObject()) {
michael@0 1151 JS_ReportError(cx, "Argument must be an object");
michael@0 1152 return false;
michael@0 1153 }
michael@0 1154
michael@0 1155 args.rval().setObjectOrNull(GetObjectMetadata(&args[0].toObject()));
michael@0 1156 return true;
michael@0 1157 }
michael@0 1158
michael@0 1159 bool
michael@0 1160 js::testingFunc_bailout(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1161 {
michael@0 1162 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1163
michael@0 1164 // NOP when not in IonMonkey
michael@0 1165 args.rval().setUndefined();
michael@0 1166 return true;
michael@0 1167 }
michael@0 1168
michael@0 1169 bool
michael@0 1170 js::testingFunc_assertFloat32(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1171 {
michael@0 1172 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1173
michael@0 1174 // NOP when not in IonMonkey
michael@0 1175 args.rval().setUndefined();
michael@0 1176 return true;
michael@0 1177 }
michael@0 1178
michael@0 1179 static bool
michael@0 1180 SetJitCompilerOption(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1181 {
michael@0 1182 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1183 RootedObject callee(cx, &args.callee());
michael@0 1184
michael@0 1185 if (args.length() != 2) {
michael@0 1186 ReportUsageError(cx, callee, "Wrong number of arguments.");
michael@0 1187 return false;
michael@0 1188 }
michael@0 1189
michael@0 1190 if (!args[0].isString()) {
michael@0 1191 ReportUsageError(cx, callee, "First argument must be a String.");
michael@0 1192 return false;
michael@0 1193 }
michael@0 1194
michael@0 1195 if (!args[1].isInt32()) {
michael@0 1196 ReportUsageError(cx, callee, "Second argument must be an Int32.");
michael@0 1197 return false;
michael@0 1198 }
michael@0 1199
michael@0 1200 JSFlatString *strArg = JS_FlattenString(cx, args[0].toString());
michael@0 1201
michael@0 1202 #define JIT_COMPILER_MATCH(key, string) \
michael@0 1203 else if (JS_FlatStringEqualsAscii(strArg, string)) \
michael@0 1204 opt = JSJITCOMPILER_ ## key;
michael@0 1205
michael@0 1206 JSJitCompilerOption opt = JSJITCOMPILER_NOT_AN_OPTION;
michael@0 1207 if (false) {}
michael@0 1208 JIT_COMPILER_OPTIONS(JIT_COMPILER_MATCH);
michael@0 1209 #undef JIT_COMPILER_MATCH
michael@0 1210
michael@0 1211 if (opt == JSJITCOMPILER_NOT_AN_OPTION) {
michael@0 1212 ReportUsageError(cx, callee, "First argument does not name a valid option (see jsapi.h).");
michael@0 1213 return false;
michael@0 1214 }
michael@0 1215
michael@0 1216 int32_t number = args[1].toInt32();
michael@0 1217 if (number < 0)
michael@0 1218 number = -1;
michael@0 1219
michael@0 1220 JS_SetGlobalJitCompilerOption(cx->runtime(), opt, uint32_t(number));
michael@0 1221
michael@0 1222 args.rval().setUndefined();
michael@0 1223 return true;
michael@0 1224 }
michael@0 1225
michael@0 1226 static bool
michael@0 1227 GetJitCompilerOptions(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1228 {
michael@0 1229 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1230 RootedObject info(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
michael@0 1231 if (!info)
michael@0 1232 return false;
michael@0 1233
michael@0 1234 RootedValue value(cx);
michael@0 1235
michael@0 1236 #define JIT_COMPILER_MATCH(key, string) \
michael@0 1237 opt = JSJITCOMPILER_ ## key; \
michael@0 1238 value.setInt32(JS_GetGlobalJitCompilerOption(cx->runtime(), opt)); \
michael@0 1239 if (!JS_SetProperty(cx, info, string, value)) \
michael@0 1240 return false;
michael@0 1241
michael@0 1242 JSJitCompilerOption opt = JSJITCOMPILER_NOT_AN_OPTION;
michael@0 1243 JIT_COMPILER_OPTIONS(JIT_COMPILER_MATCH);
michael@0 1244 #undef JIT_COMPILER_MATCH
michael@0 1245
michael@0 1246 args.rval().setObject(*info);
michael@0 1247
michael@0 1248 return true;
michael@0 1249 }
michael@0 1250
michael@0 1251 static bool
michael@0 1252 SetIonCheckGraphCoherency(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1253 {
michael@0 1254 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1255 #ifdef JS_ION
michael@0 1256 jit::js_JitOptions.checkGraphConsistency = ToBoolean(args.get(0));
michael@0 1257 #endif
michael@0 1258 args.rval().setUndefined();
michael@0 1259 return true;
michael@0 1260 }
michael@0 1261
michael@0 1262 class CloneBufferObject : public JSObject {
michael@0 1263 static const JSPropertySpec props_[2];
michael@0 1264 static const size_t DATA_SLOT = 0;
michael@0 1265 static const size_t LENGTH_SLOT = 1;
michael@0 1266 static const size_t NUM_SLOTS = 2;
michael@0 1267
michael@0 1268 public:
michael@0 1269 static const Class class_;
michael@0 1270
michael@0 1271 static CloneBufferObject *Create(JSContext *cx) {
michael@0 1272 RootedObject obj(cx, JS_NewObject(cx, Jsvalify(&class_), JS::NullPtr(), JS::NullPtr()));
michael@0 1273 if (!obj)
michael@0 1274 return nullptr;
michael@0 1275 obj->setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
michael@0 1276 obj->setReservedSlot(LENGTH_SLOT, Int32Value(0));
michael@0 1277
michael@0 1278 if (!JS_DefineProperties(cx, obj, props_))
michael@0 1279 return nullptr;
michael@0 1280
michael@0 1281 return &obj->as<CloneBufferObject>();
michael@0 1282 }
michael@0 1283
michael@0 1284 static CloneBufferObject *Create(JSContext *cx, JSAutoStructuredCloneBuffer *buffer) {
michael@0 1285 Rooted<CloneBufferObject*> obj(cx, Create(cx));
michael@0 1286 if (!obj)
michael@0 1287 return nullptr;
michael@0 1288 uint64_t *datap;
michael@0 1289 size_t nbytes;
michael@0 1290 buffer->steal(&datap, &nbytes);
michael@0 1291 obj->setData(datap);
michael@0 1292 obj->setNBytes(nbytes);
michael@0 1293 return obj;
michael@0 1294 }
michael@0 1295
michael@0 1296 uint64_t *data() const {
michael@0 1297 return static_cast<uint64_t*>(getReservedSlot(DATA_SLOT).toPrivate());
michael@0 1298 }
michael@0 1299
michael@0 1300 void setData(uint64_t *aData) {
michael@0 1301 JS_ASSERT(!data());
michael@0 1302 setReservedSlot(DATA_SLOT, PrivateValue(aData));
michael@0 1303 }
michael@0 1304
michael@0 1305 size_t nbytes() const {
michael@0 1306 return getReservedSlot(LENGTH_SLOT).toInt32();
michael@0 1307 }
michael@0 1308
michael@0 1309 void setNBytes(size_t nbytes) {
michael@0 1310 JS_ASSERT(nbytes <= UINT32_MAX);
michael@0 1311 setReservedSlot(LENGTH_SLOT, Int32Value(nbytes));
michael@0 1312 }
michael@0 1313
michael@0 1314 // Discard an owned clone buffer.
michael@0 1315 void discard() {
michael@0 1316 if (data())
michael@0 1317 JS_ClearStructuredClone(data(), nbytes(), nullptr, nullptr);
michael@0 1318 setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
michael@0 1319 }
michael@0 1320
michael@0 1321 static bool
michael@0 1322 setCloneBuffer_impl(JSContext* cx, CallArgs args) {
michael@0 1323 if (args.length() != 1 || !args[0].isString()) {
michael@0 1324 JS_ReportError(cx,
michael@0 1325 "the first argument argument must be maxBytes, "
michael@0 1326 "maxMallocBytes, gcStackpoolLifespan, gcBytes or "
michael@0 1327 "gcNumber");
michael@0 1328 JS_ReportError(cx, "clonebuffer setter requires a single string argument");
michael@0 1329 return false;
michael@0 1330 }
michael@0 1331
michael@0 1332 if (fuzzingSafe) {
michael@0 1333 // A manually-created clonebuffer could easily trigger a crash
michael@0 1334 args.rval().setUndefined();
michael@0 1335 return true;
michael@0 1336 }
michael@0 1337
michael@0 1338 Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>());
michael@0 1339 obj->discard();
michael@0 1340
michael@0 1341 char *str = JS_EncodeString(cx, args[0].toString());
michael@0 1342 if (!str)
michael@0 1343 return false;
michael@0 1344 obj->setData(reinterpret_cast<uint64_t*>(str));
michael@0 1345 obj->setNBytes(JS_GetStringLength(args[0].toString()));
michael@0 1346
michael@0 1347 args.rval().setUndefined();
michael@0 1348 return true;
michael@0 1349 }
michael@0 1350
michael@0 1351 static bool
michael@0 1352 is(HandleValue v) {
michael@0 1353 return v.isObject() && v.toObject().is<CloneBufferObject>();
michael@0 1354 }
michael@0 1355
michael@0 1356 static bool
michael@0 1357 setCloneBuffer(JSContext* cx, unsigned int argc, JS::Value* vp) {
michael@0 1358 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1359 return CallNonGenericMethod<is, setCloneBuffer_impl>(cx, args);
michael@0 1360 }
michael@0 1361
michael@0 1362 static bool
michael@0 1363 getCloneBuffer_impl(JSContext* cx, CallArgs args) {
michael@0 1364 Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>());
michael@0 1365 JS_ASSERT(args.length() == 0);
michael@0 1366
michael@0 1367 if (!obj->data()) {
michael@0 1368 args.rval().setUndefined();
michael@0 1369 return true;
michael@0 1370 }
michael@0 1371
michael@0 1372 bool hasTransferable;
michael@0 1373 if (!JS_StructuredCloneHasTransferables(obj->data(), obj->nbytes(), &hasTransferable))
michael@0 1374 return false;
michael@0 1375
michael@0 1376 if (hasTransferable) {
michael@0 1377 JS_ReportError(cx, "cannot retrieve structured clone buffer with transferables");
michael@0 1378 return false;
michael@0 1379 }
michael@0 1380
michael@0 1381 JSString *str = JS_NewStringCopyN(cx, reinterpret_cast<char*>(obj->data()), obj->nbytes());
michael@0 1382 if (!str)
michael@0 1383 return false;
michael@0 1384 args.rval().setString(str);
michael@0 1385 return true;
michael@0 1386 }
michael@0 1387
michael@0 1388 static bool
michael@0 1389 getCloneBuffer(JSContext* cx, unsigned int argc, JS::Value* vp) {
michael@0 1390 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1391 return CallNonGenericMethod<is, getCloneBuffer_impl>(cx, args);
michael@0 1392 }
michael@0 1393
michael@0 1394 static void Finalize(FreeOp *fop, JSObject *obj) {
michael@0 1395 obj->as<CloneBufferObject>().discard();
michael@0 1396 }
michael@0 1397 };
michael@0 1398
michael@0 1399 const Class CloneBufferObject::class_ = {
michael@0 1400 "CloneBuffer", JSCLASS_HAS_RESERVED_SLOTS(CloneBufferObject::NUM_SLOTS),
michael@0 1401 JS_PropertyStub, /* addProperty */
michael@0 1402 JS_DeletePropertyStub, /* delProperty */
michael@0 1403 JS_PropertyStub, /* getProperty */
michael@0 1404 JS_StrictPropertyStub, /* setProperty */
michael@0 1405 JS_EnumerateStub,
michael@0 1406 JS_ResolveStub,
michael@0 1407 JS_ConvertStub,
michael@0 1408 Finalize,
michael@0 1409 nullptr, /* call */
michael@0 1410 nullptr, /* hasInstance */
michael@0 1411 nullptr, /* construct */
michael@0 1412 nullptr, /* trace */
michael@0 1413 JS_NULL_CLASS_SPEC,
michael@0 1414 JS_NULL_CLASS_EXT,
michael@0 1415 JS_NULL_OBJECT_OPS
michael@0 1416 };
michael@0 1417
michael@0 1418 const JSPropertySpec CloneBufferObject::props_[] = {
michael@0 1419 JS_PSGS("clonebuffer", getCloneBuffer, setCloneBuffer, 0),
michael@0 1420 JS_PS_END
michael@0 1421 };
michael@0 1422
michael@0 1423 static bool
michael@0 1424 Serialize(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1425 {
michael@0 1426 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1427
michael@0 1428 JSAutoStructuredCloneBuffer clonebuf;
michael@0 1429 if (!clonebuf.write(cx, args.get(0), args.get(1)))
michael@0 1430 return false;
michael@0 1431
michael@0 1432 RootedObject obj(cx, CloneBufferObject::Create(cx, &clonebuf));
michael@0 1433 if (!obj)
michael@0 1434 return false;
michael@0 1435
michael@0 1436 args.rval().setObject(*obj);
michael@0 1437 return true;
michael@0 1438 }
michael@0 1439
michael@0 1440 static bool
michael@0 1441 Deserialize(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1442 {
michael@0 1443 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1444
michael@0 1445 if (args.length() != 1 || !args[0].isObject()) {
michael@0 1446 JS_ReportError(cx, "deserialize requires a single clonebuffer argument");
michael@0 1447 return false;
michael@0 1448 }
michael@0 1449
michael@0 1450 if (!args[0].toObject().is<CloneBufferObject>()) {
michael@0 1451 JS_ReportError(cx, "deserialize requires a clonebuffer");
michael@0 1452 return false;
michael@0 1453 }
michael@0 1454
michael@0 1455 Rooted<CloneBufferObject*> obj(cx, &args[0].toObject().as<CloneBufferObject>());
michael@0 1456
michael@0 1457 // Clone buffer was already consumed?
michael@0 1458 if (!obj->data()) {
michael@0 1459 JS_ReportError(cx, "deserialize given invalid clone buffer "
michael@0 1460 "(transferables already consumed?)");
michael@0 1461 return false;
michael@0 1462 }
michael@0 1463
michael@0 1464 bool hasTransferable;
michael@0 1465 if (!JS_StructuredCloneHasTransferables(obj->data(), obj->nbytes(), &hasTransferable))
michael@0 1466 return false;
michael@0 1467
michael@0 1468 RootedValue deserialized(cx);
michael@0 1469 if (!JS_ReadStructuredClone(cx, obj->data(), obj->nbytes(),
michael@0 1470 JS_STRUCTURED_CLONE_VERSION, &deserialized, nullptr, nullptr)) {
michael@0 1471 return false;
michael@0 1472 }
michael@0 1473 args.rval().set(deserialized);
michael@0 1474
michael@0 1475 if (hasTransferable)
michael@0 1476 obj->discard();
michael@0 1477
michael@0 1478 return true;
michael@0 1479 }
michael@0 1480
michael@0 1481 static bool
michael@0 1482 Neuter(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1483 {
michael@0 1484 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1485
michael@0 1486 if (args.length() != 2) {
michael@0 1487 JS_ReportError(cx, "wrong number of arguments to neuter()");
michael@0 1488 return false;
michael@0 1489 }
michael@0 1490
michael@0 1491 RootedObject obj(cx);
michael@0 1492 if (!JS_ValueToObject(cx, args[0], &obj))
michael@0 1493 return false;
michael@0 1494
michael@0 1495 if (!obj) {
michael@0 1496 JS_ReportError(cx, "neuter must be passed an object");
michael@0 1497 return false;
michael@0 1498 }
michael@0 1499
michael@0 1500 NeuterDataDisposition changeData;
michael@0 1501 RootedString str(cx, JS::ToString(cx, args[1]));
michael@0 1502 if (!str)
michael@0 1503 return false;
michael@0 1504 JSAutoByteString dataDisposition(cx, str);
michael@0 1505 if (!dataDisposition)
michael@0 1506 return false;
michael@0 1507 if (strcmp(dataDisposition.ptr(), "same-data") == 0) {
michael@0 1508 changeData = KeepData;
michael@0 1509 } else if (strcmp(dataDisposition.ptr(), "change-data") == 0) {
michael@0 1510 changeData = ChangeData;
michael@0 1511 } else {
michael@0 1512 JS_ReportError(cx, "unknown parameter 2 to neuter()");
michael@0 1513 return false;
michael@0 1514 }
michael@0 1515
michael@0 1516 if (!JS_NeuterArrayBuffer(cx, obj, changeData))
michael@0 1517 return false;
michael@0 1518
michael@0 1519 args.rval().setUndefined();
michael@0 1520 return true;
michael@0 1521 }
michael@0 1522
michael@0 1523 static bool
michael@0 1524 WorkerThreadCount(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1525 {
michael@0 1526 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1527 #ifdef JS_THREADSAFE
michael@0 1528 args.rval().setInt32(cx->runtime()->useHelperThreads() ? WorkerThreadState().threadCount : 0);
michael@0 1529 #else
michael@0 1530 args.rval().setInt32(0);
michael@0 1531 #endif
michael@0 1532 return true;
michael@0 1533 }
michael@0 1534
michael@0 1535 static bool
michael@0 1536 TimesAccessed(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1537 {
michael@0 1538 static int32_t accessed = 0;
michael@0 1539 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1540 args.rval().setInt32(++accessed);
michael@0 1541 return true;
michael@0 1542 }
michael@0 1543
michael@0 1544 static bool
michael@0 1545 EnableTraceLogger(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1546 {
michael@0 1547 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1548 TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
michael@0 1549 args.rval().setBoolean(TraceLoggerEnable(logger));
michael@0 1550
michael@0 1551 return true;
michael@0 1552 }
michael@0 1553
michael@0 1554 static bool
michael@0 1555 DisableTraceLogger(JSContext *cx, unsigned argc, jsval *vp)
michael@0 1556 {
michael@0 1557 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 1558 TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
michael@0 1559 args.rval().setBoolean(TraceLoggerDisable(logger));
michael@0 1560
michael@0 1561 return true;
michael@0 1562 }
michael@0 1563
michael@0 1564 static const JSFunctionSpecWithHelp TestingFunctions[] = {
michael@0 1565 JS_FN_HELP("gc", ::GC, 0, 0,
michael@0 1566 "gc([obj] | 'compartment')",
michael@0 1567 " Run the garbage collector. When obj is given, GC only its compartment.\n"
michael@0 1568 " If 'compartment' is given, GC any compartments that were scheduled for\n"
michael@0 1569 " GC via schedulegc."),
michael@0 1570
michael@0 1571 JS_FN_HELP("minorgc", ::MinorGC, 0, 0,
michael@0 1572 "minorgc([aboutToOverflow])",
michael@0 1573 " Run a minor collector on the Nursery. When aboutToOverflow is true, marks\n"
michael@0 1574 " the store buffer as about-to-overflow before collecting."),
michael@0 1575
michael@0 1576 JS_FN_HELP("gcparam", GCParameter, 2, 0,
michael@0 1577 "gcparam(name [, value])",
michael@0 1578 " Wrapper for JS_[GS]etGCParameter. The name is one of " GC_PARAMETER_ARGS_LIST),
michael@0 1579
michael@0 1580 JS_FN_HELP("getBuildConfiguration", GetBuildConfiguration, 0, 0,
michael@0 1581 "getBuildConfiguration()",
michael@0 1582 " Return an object describing some of the configuration options SpiderMonkey\n"
michael@0 1583 " was built with."),
michael@0 1584
michael@0 1585 JS_FN_HELP("countHeap", CountHeap, 0, 0,
michael@0 1586 "countHeap([start[, kind[, thing]]])",
michael@0 1587 " Count the number of live GC things in the heap or things reachable from\n"
michael@0 1588 " start when it is given and is not null. kind is either 'all' (default) to\n"
michael@0 1589 " count all things or one of 'object', 'double', 'string', 'function'\n"
michael@0 1590 " to count only things of that kind. If kind is the string 'specific',\n"
michael@0 1591 " then you can provide an extra argument with some specific traceable\n"
michael@0 1592 " thing to count.\n"),
michael@0 1593
michael@0 1594 JS_FN_HELP("getSavedFrameCount", GetSavedFrameCount, 0, 0,
michael@0 1595 "getSavedFrameCount()",
michael@0 1596 " Return the number of SavedFrame instances stored in this compartment's\n"
michael@0 1597 " SavedStacks cache."),
michael@0 1598
michael@0 1599 JS_FN_HELP("saveStack", SaveStack, 0, 0,
michael@0 1600 "saveStack()",
michael@0 1601 " Capture a stack.\n"),
michael@0 1602
michael@0 1603 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
michael@0 1604 JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 1, 0,
michael@0 1605 "oomAfterAllocations(count)",
michael@0 1606 " After 'count' js_malloc memory allocations, fail every following allocation\n"
michael@0 1607 " (return NULL)."),
michael@0 1608 #endif
michael@0 1609
michael@0 1610 JS_FN_HELP("makeFinalizeObserver", MakeFinalizeObserver, 0, 0,
michael@0 1611 "makeFinalizeObserver()",
michael@0 1612 " Get a special object whose finalization increases the counter returned\n"
michael@0 1613 " by the finalizeCount function."),
michael@0 1614
michael@0 1615 JS_FN_HELP("finalizeCount", FinalizeCount, 0, 0,
michael@0 1616 "finalizeCount()",
michael@0 1617 " Return the current value of the finalization counter that is incremented\n"
michael@0 1618 " each time an object returned by the makeFinalizeObserver is finalized."),
michael@0 1619
michael@0 1620 JS_FN_HELP("gcPreserveCode", GCPreserveCode, 0, 0,
michael@0 1621 "gcPreserveCode()",
michael@0 1622 " Preserve JIT code during garbage collections."),
michael@0 1623
michael@0 1624 #ifdef JS_GC_ZEAL
michael@0 1625 JS_FN_HELP("gczeal", GCZeal, 2, 0,
michael@0 1626 "gczeal(level, [period])",
michael@0 1627 " Specifies how zealous the garbage collector should be. Values for level:\n"
michael@0 1628 " 0: Normal amount of collection\n"
michael@0 1629 " 1: Collect when roots are added or removed\n"
michael@0 1630 " 2: Collect when memory is allocated\n"
michael@0 1631 " 3: Collect when the window paints (browser only)\n"
michael@0 1632 " 4: Verify pre write barriers between instructions\n"
michael@0 1633 " 5: Verify pre write barriers between paints\n"
michael@0 1634 " 6: Verify stack rooting\n"
michael@0 1635 " 7: Collect the nursery every N nursery allocations\n"
michael@0 1636 " 8: Incremental GC in two slices: 1) mark roots 2) finish collection\n"
michael@0 1637 " 9: Incremental GC in two slices: 1) mark all 2) new marking and finish\n"
michael@0 1638 " 10: Incremental GC in multiple slices\n"
michael@0 1639 " 11: Verify post write barriers between instructions\n"
michael@0 1640 " 12: Verify post write barriers between paints\n"
michael@0 1641 " 13: Check internal hashtables on minor GC\n"
michael@0 1642 " Period specifies that collection happens every n allocations.\n"),
michael@0 1643
michael@0 1644 JS_FN_HELP("schedulegc", ScheduleGC, 1, 0,
michael@0 1645 "schedulegc(num | obj)",
michael@0 1646 " If num is given, schedule a GC after num allocations.\n"
michael@0 1647 " If obj is given, schedule a GC of obj's compartment."),
michael@0 1648
michael@0 1649 JS_FN_HELP("selectforgc", SelectForGC, 0, 0,
michael@0 1650 "selectforgc(obj1, obj2, ...)",
michael@0 1651 " Schedule the given objects to be marked in the next GC slice."),
michael@0 1652
michael@0 1653 JS_FN_HELP("verifyprebarriers", VerifyPreBarriers, 0, 0,
michael@0 1654 "verifyprebarriers()",
michael@0 1655 " Start or end a run of the pre-write barrier verifier."),
michael@0 1656
michael@0 1657 JS_FN_HELP("verifypostbarriers", VerifyPostBarriers, 0, 0,
michael@0 1658 "verifypostbarriers()",
michael@0 1659 " Start or end a run of the post-write barrier verifier."),
michael@0 1660
michael@0 1661 JS_FN_HELP("gcstate", GCState, 0, 0,
michael@0 1662 "gcstate()",
michael@0 1663 " Report the global GC state."),
michael@0 1664
michael@0 1665 JS_FN_HELP("deterministicgc", DeterministicGC, 1, 0,
michael@0 1666 "deterministicgc(true|false)",
michael@0 1667 " If true, only allow determinstic GCs to run."),
michael@0 1668 #endif
michael@0 1669
michael@0 1670 JS_FN_HELP("gcslice", GCSlice, 1, 0,
michael@0 1671 "gcslice(n)",
michael@0 1672 " Run an incremental GC slice that marks about n objects."),
michael@0 1673
michael@0 1674 JS_FN_HELP("validategc", ValidateGC, 1, 0,
michael@0 1675 "validategc(true|false)",
michael@0 1676 " If true, a separate validation step is performed after an incremental GC."),
michael@0 1677
michael@0 1678 JS_FN_HELP("fullcompartmentchecks", FullCompartmentChecks, 1, 0,
michael@0 1679 "fullcompartmentchecks(true|false)",
michael@0 1680 " If true, check for compartment mismatches before every GC."),
michael@0 1681
michael@0 1682 JS_FN_HELP("nondeterministicGetWeakMapKeys", NondeterministicGetWeakMapKeys, 1, 0,
michael@0 1683 "nondeterministicGetWeakMapKeys(weakmap)",
michael@0 1684 " Return an array of the keys in the given WeakMap."),
michael@0 1685
michael@0 1686 JS_FN_HELP("internalConst", InternalConst, 1, 0,
michael@0 1687 "internalConst(name)",
michael@0 1688 " Query an internal constant for the engine. See InternalConst source for\n"
michael@0 1689 " the list of constant names."),
michael@0 1690
michael@0 1691 JS_FN_HELP("isProxy", IsProxy, 1, 0,
michael@0 1692 "isProxy(obj)",
michael@0 1693 " If true, obj is a proxy of some sort"),
michael@0 1694
michael@0 1695 JS_FN_HELP("dumpHeapComplete", DumpHeapComplete, 1, 0,
michael@0 1696 "dumpHeapComplete(['collectNurseryBeforeDump'], [filename])",
michael@0 1697 " Dump reachable and unreachable objects to the named file, or to stdout. If\n"
michael@0 1698 " 'collectNurseryBeforeDump' is specified, a minor GC is performed first,\n"
michael@0 1699 " otherwise objects in the nursery are ignored."),
michael@0 1700
michael@0 1701 JS_FN_HELP("terminate", Terminate, 0, 0,
michael@0 1702 "terminate()",
michael@0 1703 " Terminate JavaScript execution, as if we had run out of\n"
michael@0 1704 " memory or been terminated by the slow script dialog."),
michael@0 1705
michael@0 1706 JS_FN_HELP("enableSPSProfilingAssertions", EnableSPSProfilingAssertions, 1, 0,
michael@0 1707 "enableSPSProfilingAssertions(slow)",
michael@0 1708 " Enables SPS instrumentation and corresponding assertions. If 'slow' is\n"
michael@0 1709 " true, then even slower assertions are enabled for all generated JIT code.\n"
michael@0 1710 " When 'slow' is false, then instrumentation is enabled, but the slow\n"
michael@0 1711 " assertions are disabled."),
michael@0 1712
michael@0 1713 JS_FN_HELP("disableSPSProfiling", DisableSPSProfiling, 1, 0,
michael@0 1714 "disableSPSProfiling()",
michael@0 1715 " Disables SPS instrumentation"),
michael@0 1716
michael@0 1717 JS_FN_HELP("enableOsiPointRegisterChecks", EnableOsiPointRegisterChecks, 0, 0,
michael@0 1718 "enableOsiPointRegisterChecks()",
michael@0 1719 "Emit extra code to verify live regs at the start of a VM call are not\n"
michael@0 1720 "modified before its OsiPoint."),
michael@0 1721
michael@0 1722 JS_FN_HELP("displayName", DisplayName, 1, 0,
michael@0 1723 "displayName(fn)",
michael@0 1724 " Gets the display name for a function, which can possibly be a guessed or\n"
michael@0 1725 " inferred name based on where the function was defined. This can be\n"
michael@0 1726 " different from the 'name' property on the function."),
michael@0 1727
michael@0 1728 JS_FN_HELP("isAsmJSCompilationAvailable", IsAsmJSCompilationAvailable, 0, 0,
michael@0 1729 "isAsmJSCompilationAvailable",
michael@0 1730 " Returns whether asm.js compilation is currently available or whether it is disabled\n"
michael@0 1731 " (e.g., by the debugger)."),
michael@0 1732
michael@0 1733 JS_FN_HELP("getJitCompilerOptions", GetJitCompilerOptions, 0, 0,
michael@0 1734 "getCompilerOptions()",
michael@0 1735 "Return an object describing some of the JIT compiler options.\n"),
michael@0 1736
michael@0 1737 JS_FN_HELP("isAsmJSModule", IsAsmJSModule, 1, 0,
michael@0 1738 "isAsmJSModule(fn)",
michael@0 1739 " Returns whether the given value is a function containing \"use asm\" that has been\n"
michael@0 1740 " validated according to the asm.js spec."),
michael@0 1741
michael@0 1742 JS_FN_HELP("isAsmJSModuleLoadedFromCache", IsAsmJSModuleLoadedFromCache, 1, 0,
michael@0 1743 "isAsmJSModuleLoadedFromCache(fn)",
michael@0 1744 " Return whether the given asm.js module function has been loaded directly\n"
michael@0 1745 " from the cache. This function throws an error if fn is not a validated asm.js\n"
michael@0 1746 " module."),
michael@0 1747
michael@0 1748 JS_FN_HELP("isAsmJSFunction", IsAsmJSFunction, 1, 0,
michael@0 1749 "isAsmJSFunction(fn)",
michael@0 1750 " Returns whether the given value is a nested function in an asm.js module that has been\n"
michael@0 1751 " both compile- and link-time validated."),
michael@0 1752
michael@0 1753 JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0,
michael@0 1754 "isLazyFunction(fun)",
michael@0 1755 " True if fun is a lazy JSFunction."),
michael@0 1756
michael@0 1757 JS_FN_HELP("isRelazifiableFunction", IsRelazifiableFunction, 1, 0,
michael@0 1758 "isRelazifiableFunction(fun)",
michael@0 1759 " Ture if fun is a JSFunction with a relazifiable JSScript."),
michael@0 1760
michael@0 1761 JS_FN_HELP("inParallelSection", testingFunc_inParallelSection, 0, 0,
michael@0 1762 "inParallelSection()",
michael@0 1763 " True if this code is executing within a parallel section."),
michael@0 1764
michael@0 1765 JS_FN_HELP("setObjectMetadataCallback", SetObjectMetadataCallback, 1, 0,
michael@0 1766 "setObjectMetadataCallback(fn)",
michael@0 1767 " Specify function to supply metadata for all newly created objects."),
michael@0 1768
michael@0 1769 JS_FN_HELP("setObjectMetadata", SetObjectMetadata, 2, 0,
michael@0 1770 "setObjectMetadata(obj, metadataObj)",
michael@0 1771 " Change the metadata for an object."),
michael@0 1772
michael@0 1773 JS_FN_HELP("getObjectMetadata", GetObjectMetadata, 1, 0,
michael@0 1774 "getObjectMetadata(obj)",
michael@0 1775 " Get the metadata for an object."),
michael@0 1776
michael@0 1777 JS_FN_HELP("bailout", testingFunc_bailout, 0, 0,
michael@0 1778 "bailout()",
michael@0 1779 " Force a bailout out of ionmonkey (if running in ionmonkey)."),
michael@0 1780
michael@0 1781 JS_FN_HELP("setJitCompilerOption", SetJitCompilerOption, 2, 0,
michael@0 1782 "setCompilerOption(<option>, <number>)",
michael@0 1783 " Set a compiler option indexed in JSCompileOption enum to a number.\n"),
michael@0 1784
michael@0 1785 JS_FN_HELP("setIonCheckGraphCoherency", SetIonCheckGraphCoherency, 1, 0,
michael@0 1786 "setIonCheckGraphCoherency(bool)",
michael@0 1787 " Set whether Ion should perform graph consistency (DEBUG-only) assertions. These assertions\n"
michael@0 1788 " are valuable and should be generally enabled, however they can be very expensive for large\n"
michael@0 1789 " (asm.js) programs."),
michael@0 1790
michael@0 1791 JS_FN_HELP("serialize", Serialize, 1, 0,
michael@0 1792 "serialize(data, [transferables])",
michael@0 1793 " Serialize 'data' using JS_WriteStructuredClone. Returns a structured\n"
michael@0 1794 " clone buffer object."),
michael@0 1795
michael@0 1796 JS_FN_HELP("deserialize", Deserialize, 1, 0,
michael@0 1797 "deserialize(clonebuffer)",
michael@0 1798 " Deserialize data generated by serialize."),
michael@0 1799
michael@0 1800 JS_FN_HELP("neuter", Neuter, 1, 0,
michael@0 1801 "neuter(buffer, \"change-data\"|\"same-data\")",
michael@0 1802 " Neuter the given ArrayBuffer object as if it had been transferred to a\n"
michael@0 1803 " WebWorker. \"change-data\" will update the internal data pointer.\n"
michael@0 1804 " \"same-data\" will leave it set to its original value, to mimic eg\n"
michael@0 1805 " asm.js ArrayBuffer neutering."),
michael@0 1806
michael@0 1807 JS_FN_HELP("workerThreadCount", WorkerThreadCount, 0, 0,
michael@0 1808 "workerThreadCount()",
michael@0 1809 " Returns the number of worker threads available for off-main-thread tasks."),
michael@0 1810
michael@0 1811 JS_FN_HELP("startTraceLogger", EnableTraceLogger, 0, 0,
michael@0 1812 "startTraceLogger()",
michael@0 1813 " Start logging the mainThread.\n"
michael@0 1814 " Note: tracelogging starts automatically. Disable it by setting environment variable\n"
michael@0 1815 " TLOPTIONS=disableMainThread"),
michael@0 1816
michael@0 1817 JS_FN_HELP("stopTraceLogger", DisableTraceLogger, 0, 0,
michael@0 1818 "startTraceLogger()",
michael@0 1819 " Stop logging the mainThread."),
michael@0 1820 JS_FS_HELP_END
michael@0 1821 };
michael@0 1822
michael@0 1823 static const JSPropertySpec TestingProperties[] = {
michael@0 1824 JS_PSG("timesAccessed", TimesAccessed, 0),
michael@0 1825 JS_PS_END
michael@0 1826 };
michael@0 1827
michael@0 1828 bool
michael@0 1829 js::DefineTestingFunctions(JSContext *cx, HandleObject obj, bool fuzzingSafe_)
michael@0 1830 {
michael@0 1831 fuzzingSafe = fuzzingSafe_;
michael@0 1832 if (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0')
michael@0 1833 fuzzingSafe = true;
michael@0 1834
michael@0 1835 if (!JS_DefineProperties(cx, obj, TestingProperties))
michael@0 1836 return false;
michael@0 1837
michael@0 1838 return JS_DefineFunctionsWithHelp(cx, obj, TestingFunctions);
michael@0 1839 }

mercurial