js/src/jsapi.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 /*
michael@0 8 * JavaScript API.
michael@0 9 */
michael@0 10
michael@0 11 #include "jsapi.h"
michael@0 12
michael@0 13 #include "mozilla/FloatingPoint.h"
michael@0 14 #include "mozilla/PodOperations.h"
michael@0 15
michael@0 16 #include <ctype.h>
michael@0 17 #include <stdarg.h>
michael@0 18 #include <string.h>
michael@0 19 #include <sys/stat.h>
michael@0 20
michael@0 21 #include "jsarray.h"
michael@0 22 #include "jsatom.h"
michael@0 23 #include "jsbool.h"
michael@0 24 #include "jscntxt.h"
michael@0 25 #include "jsdate.h"
michael@0 26 #include "jsexn.h"
michael@0 27 #include "jsfun.h"
michael@0 28 #include "jsgc.h"
michael@0 29 #include "jsiter.h"
michael@0 30 #include "jslock.h"
michael@0 31 #include "jsmath.h"
michael@0 32 #include "jsnum.h"
michael@0 33 #include "jsobj.h"
michael@0 34 #include "json.h"
michael@0 35 #include "jsprf.h"
michael@0 36 #include "jsproxy.h"
michael@0 37 #include "jsscript.h"
michael@0 38 #include "jsstr.h"
michael@0 39 #include "jstypes.h"
michael@0 40 #include "jsutil.h"
michael@0 41 #include "jswatchpoint.h"
michael@0 42 #include "jsweakmap.h"
michael@0 43 #ifdef JS_THREADSAFE
michael@0 44 #include "jsworkers.h"
michael@0 45 #endif
michael@0 46 #include "jswrapper.h"
michael@0 47 #include "prmjtime.h"
michael@0 48
michael@0 49 #if ENABLE_YARR_JIT
michael@0 50 #include "assembler/jit/ExecutableAllocator.h"
michael@0 51 #endif
michael@0 52 #include "builtin/Eval.h"
michael@0 53 #include "builtin/Intl.h"
michael@0 54 #include "builtin/MapObject.h"
michael@0 55 #include "builtin/RegExp.h"
michael@0 56 #ifdef ENABLE_BINARYDATA
michael@0 57 #include "builtin/SIMD.h"
michael@0 58 #include "builtin/TypedObject.h"
michael@0 59 #endif
michael@0 60 #include "frontend/BytecodeCompiler.h"
michael@0 61 #include "frontend/FullParseHandler.h" // for JS_BufferIsCompileableUnit
michael@0 62 #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
michael@0 63 #include "gc/Marking.h"
michael@0 64 #include "jit/AsmJSLink.h"
michael@0 65 #include "jit/JitCommon.h"
michael@0 66 #include "js/CharacterEncoding.h"
michael@0 67 #include "js/SliceBudget.h"
michael@0 68 #include "js/StructuredClone.h"
michael@0 69 #if ENABLE_INTL_API
michael@0 70 #include "unicode/uclean.h"
michael@0 71 #include "unicode/utypes.h"
michael@0 72 #endif // ENABLE_INTL_API
michael@0 73 #include "vm/DateObject.h"
michael@0 74 #include "vm/Debugger.h"
michael@0 75 #include "vm/ErrorObject.h"
michael@0 76 #include "vm/Interpreter.h"
michael@0 77 #include "vm/NumericConversions.h"
michael@0 78 #include "vm/RegExpStatics.h"
michael@0 79 #include "vm/Runtime.h"
michael@0 80 #include "vm/Shape.h"
michael@0 81 #include "vm/SharedArrayObject.h"
michael@0 82 #include "vm/StopIterationObject.h"
michael@0 83 #include "vm/StringBuffer.h"
michael@0 84 #include "vm/TypedArrayObject.h"
michael@0 85 #include "vm/WeakMapObject.h"
michael@0 86 #include "vm/WrapperObject.h"
michael@0 87 #include "vm/Xdr.h"
michael@0 88 #include "yarr/BumpPointerAllocator.h"
michael@0 89
michael@0 90 #include "jsatominlines.h"
michael@0 91 #include "jsfuninlines.h"
michael@0 92 #include "jsinferinlines.h"
michael@0 93 #include "jsscriptinlines.h"
michael@0 94
michael@0 95 #include "vm/Interpreter-inl.h"
michael@0 96 #include "vm/ObjectImpl-inl.h"
michael@0 97 #include "vm/String-inl.h"
michael@0 98
michael@0 99 using namespace js;
michael@0 100 using namespace js::gc;
michael@0 101 using namespace js::types;
michael@0 102
michael@0 103 using mozilla::Maybe;
michael@0 104 using mozilla::PodCopy;
michael@0 105 using mozilla::PodZero;
michael@0 106
michael@0 107 using js::frontend::Parser;
michael@0 108
michael@0 109 #ifdef HAVE_VA_LIST_AS_ARRAY
michael@0 110 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
michael@0 111 #else
michael@0 112 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
michael@0 113 #endif
michael@0 114
michael@0 115 /* Make sure that jschar is two bytes unsigned integer */
michael@0 116 JS_STATIC_ASSERT((jschar)-1 > 0);
michael@0 117 JS_STATIC_ASSERT(sizeof(jschar) == 2);
michael@0 118
michael@0 119 JS_PUBLIC_API(int64_t)
michael@0 120 JS_Now()
michael@0 121 {
michael@0 122 return PRMJ_Now();
michael@0 123 }
michael@0 124
michael@0 125 JS_PUBLIC_API(jsval)
michael@0 126 JS_GetNaNValue(JSContext *cx)
michael@0 127 {
michael@0 128 return cx->runtime()->NaNValue;
michael@0 129 }
michael@0 130
michael@0 131 JS_PUBLIC_API(jsval)
michael@0 132 JS_GetNegativeInfinityValue(JSContext *cx)
michael@0 133 {
michael@0 134 return cx->runtime()->negativeInfinityValue;
michael@0 135 }
michael@0 136
michael@0 137 JS_PUBLIC_API(jsval)
michael@0 138 JS_GetPositiveInfinityValue(JSContext *cx)
michael@0 139 {
michael@0 140 return cx->runtime()->positiveInfinityValue;
michael@0 141 }
michael@0 142
michael@0 143 JS_PUBLIC_API(jsval)
michael@0 144 JS_GetEmptyStringValue(JSContext *cx)
michael@0 145 {
michael@0 146 return STRING_TO_JSVAL(cx->runtime()->emptyString);
michael@0 147 }
michael@0 148
michael@0 149 JS_PUBLIC_API(JSString *)
michael@0 150 JS_GetEmptyString(JSRuntime *rt)
michael@0 151 {
michael@0 152 JS_ASSERT(rt->hasContexts());
michael@0 153 return rt->emptyString;
michael@0 154 }
michael@0 155
michael@0 156 namespace js {
michael@0 157
michael@0 158 void
michael@0 159 AssertHeapIsIdle(JSRuntime *rt)
michael@0 160 {
michael@0 161 JS_ASSERT(rt->heapState == js::Idle);
michael@0 162 }
michael@0 163
michael@0 164 void
michael@0 165 AssertHeapIsIdle(JSContext *cx)
michael@0 166 {
michael@0 167 AssertHeapIsIdle(cx->runtime());
michael@0 168 }
michael@0 169
michael@0 170 }
michael@0 171
michael@0 172 static void
michael@0 173 AssertHeapIsIdleOrIterating(JSRuntime *rt)
michael@0 174 {
michael@0 175 JS_ASSERT(!rt->isHeapCollecting());
michael@0 176 }
michael@0 177
michael@0 178 static void
michael@0 179 AssertHeapIsIdleOrIterating(JSContext *cx)
michael@0 180 {
michael@0 181 AssertHeapIsIdleOrIterating(cx->runtime());
michael@0 182 }
michael@0 183
michael@0 184 static void
michael@0 185 AssertHeapIsIdleOrStringIsFlat(JSContext *cx, JSString *str)
michael@0 186 {
michael@0 187 /*
michael@0 188 * We allow some functions to be called during a GC as long as the argument
michael@0 189 * is a flat string, since that will not cause allocation.
michael@0 190 */
michael@0 191 JS_ASSERT_IF(cx->runtime()->isHeapBusy(), str->isFlat());
michael@0 192 }
michael@0 193
michael@0 194 JS_PUBLIC_API(bool)
michael@0 195 JS_ConvertArguments(JSContext *cx, const CallArgs &args, const char *format, ...)
michael@0 196 {
michael@0 197 va_list ap;
michael@0 198 bool ok;
michael@0 199
michael@0 200 AssertHeapIsIdle(cx);
michael@0 201
michael@0 202 va_start(ap, format);
michael@0 203 ok = JS_ConvertArgumentsVA(cx, args, format, ap);
michael@0 204 va_end(ap);
michael@0 205 return ok;
michael@0 206 }
michael@0 207
michael@0 208 JS_PUBLIC_API(bool)
michael@0 209 JS_ConvertArgumentsVA(JSContext *cx, const CallArgs &args, const char *format, va_list ap)
michael@0 210 {
michael@0 211 unsigned index = 0;
michael@0 212 bool required;
michael@0 213 char c;
michael@0 214 double d;
michael@0 215 JSString *str;
michael@0 216 RootedObject obj(cx);
michael@0 217 RootedValue val(cx);
michael@0 218
michael@0 219 AssertHeapIsIdle(cx);
michael@0 220 CHECK_REQUEST(cx);
michael@0 221 assertSameCompartment(cx, args);
michael@0 222 required = true;
michael@0 223 while ((c = *format++) != '\0') {
michael@0 224 if (isspace(c))
michael@0 225 continue;
michael@0 226 if (c == '/') {
michael@0 227 required = false;
michael@0 228 continue;
michael@0 229 }
michael@0 230 if (index == args.length()) {
michael@0 231 if (required) {
michael@0 232 if (JSFunction *fun = ReportIfNotFunction(cx, args.calleev())) {
michael@0 233 char numBuf[12];
michael@0 234 JS_snprintf(numBuf, sizeof numBuf, "%u", args.length());
michael@0 235 JSAutoByteString funNameBytes;
michael@0 236 if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
michael@0 237 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
michael@0 238 JSMSG_MORE_ARGS_NEEDED,
michael@0 239 name, numBuf, (args.length() == 1) ? "" : "s");
michael@0 240 }
michael@0 241 }
michael@0 242 return false;
michael@0 243 }
michael@0 244 break;
michael@0 245 }
michael@0 246 MutableHandleValue arg = args[index++];
michael@0 247 switch (c) {
michael@0 248 case 'b':
michael@0 249 *va_arg(ap, bool *) = ToBoolean(arg);
michael@0 250 break;
michael@0 251 case 'c':
michael@0 252 if (!ToUint16(cx, arg, va_arg(ap, uint16_t *)))
michael@0 253 return false;
michael@0 254 break;
michael@0 255 case 'i':
michael@0 256 case 'j': // "j" was broken, you should not use it.
michael@0 257 if (!ToInt32(cx, arg, va_arg(ap, int32_t *)))
michael@0 258 return false;
michael@0 259 break;
michael@0 260 case 'u':
michael@0 261 if (!ToUint32(cx, arg, va_arg(ap, uint32_t *)))
michael@0 262 return false;
michael@0 263 break;
michael@0 264 case 'd':
michael@0 265 if (!ToNumber(cx, arg, va_arg(ap, double *)))
michael@0 266 return false;
michael@0 267 break;
michael@0 268 case 'I':
michael@0 269 if (!ToNumber(cx, arg, &d))
michael@0 270 return false;
michael@0 271 *va_arg(ap, double *) = ToInteger(d);
michael@0 272 break;
michael@0 273 case 'S':
michael@0 274 case 'W':
michael@0 275 str = ToString<CanGC>(cx, arg);
michael@0 276 if (!str)
michael@0 277 return false;
michael@0 278 arg.setString(str);
michael@0 279 if (c == 'W') {
michael@0 280 JSFlatString *flat = str->ensureFlat(cx);
michael@0 281 if (!flat)
michael@0 282 return false;
michael@0 283 *va_arg(ap, const jschar **) = flat->chars();
michael@0 284 } else {
michael@0 285 *va_arg(ap, JSString **) = str;
michael@0 286 }
michael@0 287 break;
michael@0 288 case 'o':
michael@0 289 if (arg.isNullOrUndefined()) {
michael@0 290 obj = nullptr;
michael@0 291 } else {
michael@0 292 obj = ToObject(cx, arg);
michael@0 293 if (!obj)
michael@0 294 return false;
michael@0 295 }
michael@0 296 arg.setObjectOrNull(obj);
michael@0 297 *va_arg(ap, JSObject **) = obj;
michael@0 298 break;
michael@0 299 case 'f':
michael@0 300 obj = ReportIfNotFunction(cx, arg);
michael@0 301 if (!obj)
michael@0 302 return false;
michael@0 303 arg.setObject(*obj);
michael@0 304 *va_arg(ap, JSFunction **) = &obj->as<JSFunction>();
michael@0 305 break;
michael@0 306 case 'v':
michael@0 307 *va_arg(ap, jsval *) = arg;
michael@0 308 break;
michael@0 309 case '*':
michael@0 310 break;
michael@0 311 default:
michael@0 312 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_CHAR, format);
michael@0 313 return false;
michael@0 314 }
michael@0 315 }
michael@0 316 return true;
michael@0 317 }
michael@0 318
michael@0 319 JS_PUBLIC_API(bool)
michael@0 320 JS_ConvertValue(JSContext *cx, HandleValue value, JSType type, MutableHandleValue vp)
michael@0 321 {
michael@0 322 bool ok;
michael@0 323 RootedObject obj(cx);
michael@0 324 JSString *str;
michael@0 325 double d;
michael@0 326
michael@0 327 AssertHeapIsIdle(cx);
michael@0 328 CHECK_REQUEST(cx);
michael@0 329 assertSameCompartment(cx, value);
michael@0 330 switch (type) {
michael@0 331 case JSTYPE_VOID:
michael@0 332 vp.setUndefined();
michael@0 333 ok = true;
michael@0 334 break;
michael@0 335 case JSTYPE_OBJECT:
michael@0 336 if (value.isNullOrUndefined()) {
michael@0 337 obj.set(nullptr);
michael@0 338 } else {
michael@0 339 obj = ToObject(cx, value);
michael@0 340 if (!obj)
michael@0 341 return false;
michael@0 342 }
michael@0 343 ok = true;
michael@0 344 break;
michael@0 345 case JSTYPE_FUNCTION:
michael@0 346 vp.set(value);
michael@0 347 obj = ReportIfNotFunction(cx, vp);
michael@0 348 ok = (obj != nullptr);
michael@0 349 break;
michael@0 350 case JSTYPE_STRING:
michael@0 351 str = ToString<CanGC>(cx, value);
michael@0 352 ok = (str != nullptr);
michael@0 353 if (ok)
michael@0 354 vp.setString(str);
michael@0 355 break;
michael@0 356 case JSTYPE_NUMBER:
michael@0 357 ok = ToNumber(cx, value, &d);
michael@0 358 if (ok)
michael@0 359 vp.setDouble(d);
michael@0 360 break;
michael@0 361 case JSTYPE_BOOLEAN:
michael@0 362 vp.setBoolean(ToBoolean(value));
michael@0 363 return true;
michael@0 364 default: {
michael@0 365 char numBuf[12];
michael@0 366 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
michael@0 367 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_TYPE, numBuf);
michael@0 368 ok = false;
michael@0 369 break;
michael@0 370 }
michael@0 371 }
michael@0 372 return ok;
michael@0 373 }
michael@0 374
michael@0 375 JS_PUBLIC_API(bool)
michael@0 376 JS_ValueToObject(JSContext *cx, HandleValue value, MutableHandleObject objp)
michael@0 377 {
michael@0 378 AssertHeapIsIdle(cx);
michael@0 379 CHECK_REQUEST(cx);
michael@0 380 assertSameCompartment(cx, value);
michael@0 381 if (value.isNullOrUndefined()) {
michael@0 382 objp.set(nullptr);
michael@0 383 return true;
michael@0 384 }
michael@0 385 JSObject *obj = ToObject(cx, value);
michael@0 386 if (!obj)
michael@0 387 return false;
michael@0 388 objp.set(obj);
michael@0 389 return true;
michael@0 390 }
michael@0 391
michael@0 392 JS_PUBLIC_API(JSFunction *)
michael@0 393 JS_ValueToFunction(JSContext *cx, HandleValue value)
michael@0 394 {
michael@0 395 AssertHeapIsIdle(cx);
michael@0 396 CHECK_REQUEST(cx);
michael@0 397 assertSameCompartment(cx, value);
michael@0 398 return ReportIfNotFunction(cx, value);
michael@0 399 }
michael@0 400
michael@0 401 JS_PUBLIC_API(JSFunction *)
michael@0 402 JS_ValueToConstructor(JSContext *cx, HandleValue value)
michael@0 403 {
michael@0 404 AssertHeapIsIdle(cx);
michael@0 405 CHECK_REQUEST(cx);
michael@0 406 assertSameCompartment(cx, value);
michael@0 407 return ReportIfNotFunction(cx, value);
michael@0 408 }
michael@0 409
michael@0 410 JS_PUBLIC_API(JSString *)
michael@0 411 JS_ValueToSource(JSContext *cx, HandleValue value)
michael@0 412 {
michael@0 413 AssertHeapIsIdle(cx);
michael@0 414 CHECK_REQUEST(cx);
michael@0 415 assertSameCompartment(cx, value);
michael@0 416 return ValueToSource(cx, value);
michael@0 417 }
michael@0 418
michael@0 419 JS_PUBLIC_API(bool)
michael@0 420 JS_DoubleIsInt32(double d, int32_t *ip)
michael@0 421 {
michael@0 422 return mozilla::NumberIsInt32(d, ip);
michael@0 423 }
michael@0 424
michael@0 425 JS_PUBLIC_API(int32_t)
michael@0 426 JS_DoubleToInt32(double d)
michael@0 427 {
michael@0 428 return ToInt32(d);
michael@0 429 }
michael@0 430
michael@0 431 JS_PUBLIC_API(uint32_t)
michael@0 432 JS_DoubleToUint32(double d)
michael@0 433 {
michael@0 434 return ToUint32(d);
michael@0 435 }
michael@0 436
michael@0 437 JS_PUBLIC_API(JSType)
michael@0 438 JS_TypeOfValue(JSContext *cx, HandleValue value)
michael@0 439 {
michael@0 440 AssertHeapIsIdle(cx);
michael@0 441 CHECK_REQUEST(cx);
michael@0 442 assertSameCompartment(cx, value);
michael@0 443 return TypeOfValue(value);
michael@0 444 }
michael@0 445
michael@0 446 JS_PUBLIC_API(const char *)
michael@0 447 JS_GetTypeName(JSContext *cx, JSType type)
michael@0 448 {
michael@0 449 if ((unsigned)type >= (unsigned)JSTYPE_LIMIT)
michael@0 450 return nullptr;
michael@0 451 return TypeStrings[type];
michael@0 452 }
michael@0 453
michael@0 454 JS_PUBLIC_API(bool)
michael@0 455 JS_StrictlyEqual(JSContext *cx, jsval value1, jsval value2, bool *equal)
michael@0 456 {
michael@0 457 AssertHeapIsIdle(cx);
michael@0 458 CHECK_REQUEST(cx);
michael@0 459 assertSameCompartment(cx, value1, value2);
michael@0 460 bool eq;
michael@0 461 if (!StrictlyEqual(cx, value1, value2, &eq))
michael@0 462 return false;
michael@0 463 *equal = eq;
michael@0 464 return true;
michael@0 465 }
michael@0 466
michael@0 467 JS_PUBLIC_API(bool)
michael@0 468 JS_LooselyEqual(JSContext *cx, HandleValue value1, HandleValue value2, bool *equal)
michael@0 469 {
michael@0 470 AssertHeapIsIdle(cx);
michael@0 471 CHECK_REQUEST(cx);
michael@0 472 assertSameCompartment(cx, value1, value2);
michael@0 473 JS_ASSERT(equal);
michael@0 474 return LooselyEqual(cx, value1, value2, equal);
michael@0 475 }
michael@0 476
michael@0 477 JS_PUBLIC_API(bool)
michael@0 478 JS_SameValue(JSContext *cx, jsval value1, jsval value2, bool *same)
michael@0 479 {
michael@0 480 AssertHeapIsIdle(cx);
michael@0 481 CHECK_REQUEST(cx);
michael@0 482 assertSameCompartment(cx, value1, value2);
michael@0 483 bool s;
michael@0 484 if (!SameValue(cx, value1, value2, &s))
michael@0 485 return false;
michael@0 486 *same = s;
michael@0 487 return true;
michael@0 488 }
michael@0 489
michael@0 490 JS_PUBLIC_API(bool)
michael@0 491 JS_IsBuiltinEvalFunction(JSFunction *fun)
michael@0 492 {
michael@0 493 return IsAnyBuiltinEval(fun);
michael@0 494 }
michael@0 495
michael@0 496 JS_PUBLIC_API(bool)
michael@0 497 JS_IsBuiltinFunctionConstructor(JSFunction *fun)
michael@0 498 {
michael@0 499 return fun->isBuiltinFunctionConstructor();
michael@0 500 }
michael@0 501
michael@0 502 /************************************************************************/
michael@0 503
michael@0 504 /*
michael@0 505 * SpiderMonkey's initialization status is tracked here, and it controls things
michael@0 506 * that should happen only once across all runtimes. It's an API requirement
michael@0 507 * that JS_Init (and JS_ShutDown, if called) be called in a thread-aware
michael@0 508 * manner, so this variable doesn't need to be atomic.
michael@0 509 *
michael@0 510 * The only reason at present for the restriction that you can't call
michael@0 511 * JS_Init/stuff/JS_ShutDown multiple times is the Windows PRMJ NowInit
michael@0 512 * initialization code, which uses PR_CallOnce to initialize the PRMJ_Now
michael@0 513 * subsystem. (For reinitialization to be permitted, we'd need to "reset" the
michael@0 514 * called-once status -- doable, but more trouble than it's worth now.)
michael@0 515 * Initializing that subsystem from JS_Init eliminates the problem, but
michael@0 516 * initialization can take a comparatively long time (15ms or so), so we
michael@0 517 * really don't want to do it in JS_Init, and we really do want to do it only
michael@0 518 * when PRMJ_Now is eventually called.
michael@0 519 */
michael@0 520 enum InitState { Uninitialized, Running, ShutDown };
michael@0 521 static InitState jsInitState = Uninitialized;
michael@0 522
michael@0 523 #ifdef DEBUG
michael@0 524 static void
michael@0 525 CheckMessageNumbering()
michael@0 526 {
michael@0 527 // Assert that the numbers associated with the error names in js.msg are
michael@0 528 // monotonically increasing. It's not a compile-time check, but it's
michael@0 529 // better than nothing.
michael@0 530 int errorNumber = 0;
michael@0 531 # define MSG_DEF(name, number, count, exception, format) \
michael@0 532 JS_ASSERT(name == errorNumber++);
michael@0 533 # include "js.msg"
michael@0 534 # undef MSG_DEF
michael@0 535 }
michael@0 536
michael@0 537 static unsigned
michael@0 538 MessageParameterCount(const char *format)
michael@0 539 {
michael@0 540 unsigned numfmtspecs = 0;
michael@0 541 for (const char *fmt = format; *fmt != '\0'; fmt++) {
michael@0 542 if (*fmt == '{' && isdigit(fmt[1]))
michael@0 543 ++numfmtspecs;
michael@0 544 }
michael@0 545 return numfmtspecs;
michael@0 546 }
michael@0 547
michael@0 548 static void
michael@0 549 CheckMessageParameterCounts()
michael@0 550 {
michael@0 551 // Assert that each message format has the correct number of braced
michael@0 552 // parameters.
michael@0 553 # define MSG_DEF(name, number, count, exception, format) \
michael@0 554 JS_BEGIN_MACRO \
michael@0 555 JS_ASSERT(MessageParameterCount(format) == count); \
michael@0 556 JS_END_MACRO;
michael@0 557 # include "js.msg"
michael@0 558 # undef MSG_DEF
michael@0 559 }
michael@0 560 #endif /* DEBUG */
michael@0 561
michael@0 562 JS_PUBLIC_API(bool)
michael@0 563 JS_Init(void)
michael@0 564 {
michael@0 565 MOZ_ASSERT(jsInitState == Uninitialized,
michael@0 566 "must call JS_Init once before any JSAPI operation except "
michael@0 567 "JS_SetICUMemoryFunctions");
michael@0 568 MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
michael@0 569 "how do we have live runtimes before JS_Init?");
michael@0 570
michael@0 571 #ifdef DEBUG
michael@0 572 CheckMessageNumbering();
michael@0 573 CheckMessageParameterCounts();
michael@0 574 #endif
michael@0 575
michael@0 576 using js::TlsPerThreadData;
michael@0 577 if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init())
michael@0 578 return false;
michael@0 579
michael@0 580 #if defined(JS_ION)
michael@0 581 if (!jit::InitializeIon())
michael@0 582 return false;
michael@0 583 #endif
michael@0 584
michael@0 585 if (!ForkJoinContext::initialize())
michael@0 586 return false;
michael@0 587
michael@0 588 #if EXPOSE_INTL_API
michael@0 589 UErrorCode err = U_ZERO_ERROR;
michael@0 590 u_init(&err);
michael@0 591 if (U_FAILURE(err))
michael@0 592 return false;
michael@0 593 #endif // EXPOSE_INTL_API
michael@0 594
michael@0 595 jsInitState = Running;
michael@0 596 return true;
michael@0 597 }
michael@0 598
michael@0 599 JS_PUBLIC_API(void)
michael@0 600 JS_ShutDown(void)
michael@0 601 {
michael@0 602 MOZ_ASSERT(jsInitState == Running,
michael@0 603 "JS_ShutDown must only be called after JS_Init and can't race with it");
michael@0 604 #ifdef DEBUG
michael@0 605 if (JSRuntime::hasLiveRuntimes()) {
michael@0 606 // Gecko is too buggy to assert this just yet.
michael@0 607 fprintf(stderr,
michael@0 608 "WARNING: YOU ARE LEAKING THE WORLD (at least one JSRuntime "
michael@0 609 "and everything alive inside it, that is) AT JS_ShutDown "
michael@0 610 "TIME. FIX THIS!\n");
michael@0 611 }
michael@0 612 #endif
michael@0 613
michael@0 614 #ifdef JS_THREADSAFE
michael@0 615 WorkerThreadState().finish();
michael@0 616 #endif
michael@0 617
michael@0 618 PRMJ_NowShutdown();
michael@0 619
michael@0 620 #if EXPOSE_INTL_API
michael@0 621 u_cleanup();
michael@0 622 #endif // EXPOSE_INTL_API
michael@0 623
michael@0 624 jsInitState = ShutDown;
michael@0 625 }
michael@0 626
michael@0 627 #ifdef DEBUG
michael@0 628 JS_FRIEND_API(bool)
michael@0 629 JS::isGCEnabled()
michael@0 630 {
michael@0 631 return !TlsPerThreadData.get()->suppressGC;
michael@0 632 }
michael@0 633 #else
michael@0 634 JS_FRIEND_API(bool) JS::isGCEnabled() { return true; }
michael@0 635 #endif
michael@0 636
michael@0 637 JS_PUBLIC_API(JSRuntime *)
michael@0 638 JS_NewRuntime(uint32_t maxbytes, JSUseHelperThreads useHelperThreads, JSRuntime *parentRuntime)
michael@0 639 {
michael@0 640 MOZ_ASSERT(jsInitState == Running,
michael@0 641 "must call JS_Init prior to creating any JSRuntimes");
michael@0 642
michael@0 643 // Any parent runtime should be the topmost parent. This assert
michael@0 644 // isn't required for correctness, but ensuring that the parent
michael@0 645 // runtime is not destroyed before this one is more easily done
michael@0 646 // for the main runtime in the process.
michael@0 647 JS_ASSERT_IF(parentRuntime, !parentRuntime->parentRuntime);
michael@0 648
michael@0 649 JSRuntime *rt = js_new<JSRuntime>(parentRuntime, useHelperThreads);
michael@0 650 if (!rt)
michael@0 651 return nullptr;
michael@0 652
michael@0 653 if (!rt->init(maxbytes)) {
michael@0 654 JS_DestroyRuntime(rt);
michael@0 655 return nullptr;
michael@0 656 }
michael@0 657
michael@0 658 return rt;
michael@0 659 }
michael@0 660
michael@0 661 JS_PUBLIC_API(void)
michael@0 662 JS_DestroyRuntime(JSRuntime *rt)
michael@0 663 {
michael@0 664 js_delete(rt);
michael@0 665 }
michael@0 666
michael@0 667 JS_PUBLIC_API(bool)
michael@0 668 JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn)
michael@0 669 {
michael@0 670 MOZ_ASSERT(jsInitState == Uninitialized,
michael@0 671 "must call JS_SetICUMemoryFunctions before any other JSAPI "
michael@0 672 "operation (including JS_Init)");
michael@0 673
michael@0 674 #if EXPOSE_INTL_API
michael@0 675 UErrorCode status = U_ZERO_ERROR;
michael@0 676 u_setMemoryFunctions(/* context = */ nullptr, allocFn, reallocFn, freeFn, &status);
michael@0 677 return U_SUCCESS(status);
michael@0 678 #else
michael@0 679 return true;
michael@0 680 #endif
michael@0 681 }
michael@0 682
michael@0 683 JS_PUBLIC_API(void *)
michael@0 684 JS_GetRuntimePrivate(JSRuntime *rt)
michael@0 685 {
michael@0 686 return rt->data;
michael@0 687 }
michael@0 688
michael@0 689 JS_PUBLIC_API(void)
michael@0 690 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
michael@0 691 {
michael@0 692 rt->data = data;
michael@0 693 }
michael@0 694
michael@0 695 #ifdef JS_THREADSAFE
michael@0 696 static void
michael@0 697 StartRequest(JSContext *cx)
michael@0 698 {
michael@0 699 JSRuntime *rt = cx->runtime();
michael@0 700 JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
michael@0 701
michael@0 702 if (rt->requestDepth) {
michael@0 703 rt->requestDepth++;
michael@0 704 } else {
michael@0 705 /* Indicate that a request is running. */
michael@0 706 rt->requestDepth = 1;
michael@0 707 rt->triggerActivityCallback(true);
michael@0 708 }
michael@0 709 }
michael@0 710
michael@0 711 static void
michael@0 712 StopRequest(JSContext *cx)
michael@0 713 {
michael@0 714 JSRuntime *rt = cx->runtime();
michael@0 715 JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
michael@0 716
michael@0 717 JS_ASSERT(rt->requestDepth != 0);
michael@0 718 if (rt->requestDepth != 1) {
michael@0 719 rt->requestDepth--;
michael@0 720 } else {
michael@0 721 rt->conservativeGC.updateForRequestEnd();
michael@0 722 rt->requestDepth = 0;
michael@0 723 rt->triggerActivityCallback(false);
michael@0 724 }
michael@0 725 }
michael@0 726 #endif /* JS_THREADSAFE */
michael@0 727
michael@0 728 JS_PUBLIC_API(void)
michael@0 729 JS_BeginRequest(JSContext *cx)
michael@0 730 {
michael@0 731 #ifdef JS_THREADSAFE
michael@0 732 cx->outstandingRequests++;
michael@0 733 StartRequest(cx);
michael@0 734 #endif
michael@0 735 }
michael@0 736
michael@0 737 JS_PUBLIC_API(void)
michael@0 738 JS_EndRequest(JSContext *cx)
michael@0 739 {
michael@0 740 #ifdef JS_THREADSAFE
michael@0 741 JS_ASSERT(cx->outstandingRequests != 0);
michael@0 742 cx->outstandingRequests--;
michael@0 743 StopRequest(cx);
michael@0 744 #endif
michael@0 745 }
michael@0 746
michael@0 747 JS_PUBLIC_API(bool)
michael@0 748 JS_IsInRequest(JSRuntime *rt)
michael@0 749 {
michael@0 750 #ifdef JS_THREADSAFE
michael@0 751 JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
michael@0 752 return rt->requestDepth != 0;
michael@0 753 #else
michael@0 754 return false;
michael@0 755 #endif
michael@0 756 }
michael@0 757
michael@0 758 JS_PUBLIC_API(void)
michael@0 759 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback, void *data)
michael@0 760 {
michael@0 761 rt->cxCallback = cxCallback;
michael@0 762 rt->cxCallbackData = data;
michael@0 763 }
michael@0 764
michael@0 765 JS_PUBLIC_API(JSContext *)
michael@0 766 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
michael@0 767 {
michael@0 768 return NewContext(rt, stackChunkSize);
michael@0 769 }
michael@0 770
michael@0 771 JS_PUBLIC_API(void)
michael@0 772 JS_DestroyContext(JSContext *cx)
michael@0 773 {
michael@0 774 JS_ASSERT(!cx->compartment());
michael@0 775 DestroyContext(cx, DCM_FORCE_GC);
michael@0 776 }
michael@0 777
michael@0 778 JS_PUBLIC_API(void)
michael@0 779 JS_DestroyContextNoGC(JSContext *cx)
michael@0 780 {
michael@0 781 JS_ASSERT(!cx->compartment());
michael@0 782 DestroyContext(cx, DCM_NO_GC);
michael@0 783 }
michael@0 784
michael@0 785 JS_PUBLIC_API(void *)
michael@0 786 JS_GetContextPrivate(JSContext *cx)
michael@0 787 {
michael@0 788 return cx->data;
michael@0 789 }
michael@0 790
michael@0 791 JS_PUBLIC_API(void)
michael@0 792 JS_SetContextPrivate(JSContext *cx, void *data)
michael@0 793 {
michael@0 794 cx->data = data;
michael@0 795 }
michael@0 796
michael@0 797 JS_PUBLIC_API(void *)
michael@0 798 JS_GetSecondContextPrivate(JSContext *cx)
michael@0 799 {
michael@0 800 return cx->data2;
michael@0 801 }
michael@0 802
michael@0 803 JS_PUBLIC_API(void)
michael@0 804 JS_SetSecondContextPrivate(JSContext *cx, void *data)
michael@0 805 {
michael@0 806 cx->data2 = data;
michael@0 807 }
michael@0 808
michael@0 809 JS_PUBLIC_API(JSRuntime *)
michael@0 810 JS_GetRuntime(JSContext *cx)
michael@0 811 {
michael@0 812 return cx->runtime();
michael@0 813 }
michael@0 814
michael@0 815 JS_PUBLIC_API(JSRuntime *)
michael@0 816 JS_GetParentRuntime(JSContext *cx)
michael@0 817 {
michael@0 818 JSRuntime *rt = cx->runtime();
michael@0 819 return rt->parentRuntime ? rt->parentRuntime : rt;
michael@0 820 }
michael@0 821
michael@0 822 JS_PUBLIC_API(JSContext *)
michael@0 823 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
michael@0 824 {
michael@0 825 JSContext *cx = *iterp;
michael@0 826 cx = cx ? cx->getNext() : rt->contextList.getFirst();
michael@0 827 *iterp = cx;
michael@0 828 return cx;
michael@0 829 }
michael@0 830
michael@0 831 JS_PUBLIC_API(JSVersion)
michael@0 832 JS_GetVersion(JSContext *cx)
michael@0 833 {
michael@0 834 return VersionNumber(cx->findVersion());
michael@0 835 }
michael@0 836
michael@0 837 JS_PUBLIC_API(void)
michael@0 838 JS_SetVersionForCompartment(JSCompartment *compartment, JSVersion version)
michael@0 839 {
michael@0 840 compartment->options().setVersion(version);
michael@0 841 }
michael@0 842
michael@0 843 static const struct v2smap {
michael@0 844 JSVersion version;
michael@0 845 const char *string;
michael@0 846 } v2smap[] = {
michael@0 847 {JSVERSION_ECMA_3, "ECMAv3"},
michael@0 848 {JSVERSION_1_6, "1.6"},
michael@0 849 {JSVERSION_1_7, "1.7"},
michael@0 850 {JSVERSION_1_8, "1.8"},
michael@0 851 {JSVERSION_ECMA_5, "ECMAv5"},
michael@0 852 {JSVERSION_DEFAULT, js_default_str},
michael@0 853 {JSVERSION_DEFAULT, "1.0"},
michael@0 854 {JSVERSION_DEFAULT, "1.1"},
michael@0 855 {JSVERSION_DEFAULT, "1.2"},
michael@0 856 {JSVERSION_DEFAULT, "1.3"},
michael@0 857 {JSVERSION_DEFAULT, "1.4"},
michael@0 858 {JSVERSION_DEFAULT, "1.5"},
michael@0 859 {JSVERSION_UNKNOWN, nullptr}, /* must be last, nullptr is sentinel */
michael@0 860 };
michael@0 861
michael@0 862 JS_PUBLIC_API(const char *)
michael@0 863 JS_VersionToString(JSVersion version)
michael@0 864 {
michael@0 865 int i;
michael@0 866
michael@0 867 for (i = 0; v2smap[i].string; i++)
michael@0 868 if (v2smap[i].version == version)
michael@0 869 return v2smap[i].string;
michael@0 870 return "unknown";
michael@0 871 }
michael@0 872
michael@0 873 JS_PUBLIC_API(JSVersion)
michael@0 874 JS_StringToVersion(const char *string)
michael@0 875 {
michael@0 876 int i;
michael@0 877
michael@0 878 for (i = 0; v2smap[i].string; i++)
michael@0 879 if (strcmp(v2smap[i].string, string) == 0)
michael@0 880 return v2smap[i].version;
michael@0 881 return JSVERSION_UNKNOWN;
michael@0 882 }
michael@0 883
michael@0 884 JS_PUBLIC_API(JS::RuntimeOptions &)
michael@0 885 JS::RuntimeOptionsRef(JSRuntime *rt)
michael@0 886 {
michael@0 887 return rt->options();
michael@0 888 }
michael@0 889
michael@0 890 JS_PUBLIC_API(JS::RuntimeOptions &)
michael@0 891 JS::RuntimeOptionsRef(JSContext *cx)
michael@0 892 {
michael@0 893 return cx->runtime()->options();
michael@0 894 }
michael@0 895
michael@0 896 JS_PUBLIC_API(JS::ContextOptions &)
michael@0 897 JS::ContextOptionsRef(JSContext *cx)
michael@0 898 {
michael@0 899 return cx->options();
michael@0 900 }
michael@0 901
michael@0 902 JS_PUBLIC_API(const char *)
michael@0 903 JS_GetImplementationVersion(void)
michael@0 904 {
michael@0 905 return "JavaScript-C" MOZILLA_VERSION;
michael@0 906 }
michael@0 907
michael@0 908 JS_PUBLIC_API(void)
michael@0 909 JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback)
michael@0 910 {
michael@0 911 rt->destroyCompartmentCallback = callback;
michael@0 912 }
michael@0 913
michael@0 914 JS_PUBLIC_API(void)
michael@0 915 JS_SetDestroyZoneCallback(JSRuntime *rt, JSZoneCallback callback)
michael@0 916 {
michael@0 917 rt->destroyZoneCallback = callback;
michael@0 918 }
michael@0 919
michael@0 920 JS_PUBLIC_API(void)
michael@0 921 JS_SetSweepZoneCallback(JSRuntime *rt, JSZoneCallback callback)
michael@0 922 {
michael@0 923 rt->sweepZoneCallback = callback;
michael@0 924 }
michael@0 925
michael@0 926 JS_PUBLIC_API(void)
michael@0 927 JS_SetCompartmentNameCallback(JSRuntime *rt, JSCompartmentNameCallback callback)
michael@0 928 {
michael@0 929 rt->compartmentNameCallback = callback;
michael@0 930 }
michael@0 931
michael@0 932 JS_PUBLIC_API(void)
michael@0 933 JS_SetWrapObjectCallbacks(JSRuntime *rt, const JSWrapObjectCallbacks *callbacks)
michael@0 934 {
michael@0 935 rt->wrapObjectCallbacks = callbacks;
michael@0 936 }
michael@0 937
michael@0 938 JS_PUBLIC_API(JSCompartment *)
michael@0 939 JS_EnterCompartment(JSContext *cx, JSObject *target)
michael@0 940 {
michael@0 941 AssertHeapIsIdle(cx);
michael@0 942 CHECK_REQUEST(cx);
michael@0 943
michael@0 944 JSCompartment *oldCompartment = cx->compartment();
michael@0 945 cx->enterCompartment(target->compartment());
michael@0 946 return oldCompartment;
michael@0 947 }
michael@0 948
michael@0 949 JS_PUBLIC_API(JSCompartment *)
michael@0 950 JS_EnterCompartmentOfScript(JSContext *cx, JSScript *target)
michael@0 951 {
michael@0 952 AssertHeapIsIdle(cx);
michael@0 953 CHECK_REQUEST(cx);
michael@0 954 GlobalObject &global = target->global();
michael@0 955 return JS_EnterCompartment(cx, &global);
michael@0 956 }
michael@0 957
michael@0 958 JS_PUBLIC_API(void)
michael@0 959 JS_LeaveCompartment(JSContext *cx, JSCompartment *oldCompartment)
michael@0 960 {
michael@0 961 AssertHeapIsIdle(cx);
michael@0 962 CHECK_REQUEST(cx);
michael@0 963 cx->leaveCompartment(oldCompartment);
michael@0 964 }
michael@0 965
michael@0 966 JSAutoCompartment::JSAutoCompartment(JSContext *cx, JSObject *target)
michael@0 967 : cx_(cx),
michael@0 968 oldCompartment_(cx->compartment())
michael@0 969 {
michael@0 970 AssertHeapIsIdleOrIterating(cx_);
michael@0 971 cx_->enterCompartment(target->compartment());
michael@0 972 }
michael@0 973
michael@0 974 JSAutoCompartment::JSAutoCompartment(JSContext *cx, JSScript *target)
michael@0 975 : cx_(cx),
michael@0 976 oldCompartment_(cx->compartment())
michael@0 977 {
michael@0 978 AssertHeapIsIdleOrIterating(cx_);
michael@0 979 cx_->enterCompartment(target->compartment());
michael@0 980 }
michael@0 981
michael@0 982 JSAutoCompartment::~JSAutoCompartment()
michael@0 983 {
michael@0 984 cx_->leaveCompartment(oldCompartment_);
michael@0 985 }
michael@0 986
michael@0 987 JSAutoNullCompartment::JSAutoNullCompartment(JSContext *cx)
michael@0 988 : cx_(cx),
michael@0 989 oldCompartment_(cx->compartment())
michael@0 990 {
michael@0 991 AssertHeapIsIdleOrIterating(cx_);
michael@0 992 cx_->enterNullCompartment();
michael@0 993 }
michael@0 994
michael@0 995 JSAutoNullCompartment::~JSAutoNullCompartment()
michael@0 996 {
michael@0 997 cx_->leaveCompartment(oldCompartment_);
michael@0 998 }
michael@0 999
michael@0 1000 JS_PUBLIC_API(void)
michael@0 1001 JS_SetCompartmentPrivate(JSCompartment *compartment, void *data)
michael@0 1002 {
michael@0 1003 compartment->data = data;
michael@0 1004 }
michael@0 1005
michael@0 1006 JS_PUBLIC_API(void *)
michael@0 1007 JS_GetCompartmentPrivate(JSCompartment *compartment)
michael@0 1008 {
michael@0 1009 return compartment->data;
michael@0 1010 }
michael@0 1011
michael@0 1012 JS_PUBLIC_API(void)
michael@0 1013 JS_SetZoneUserData(JS::Zone *zone, void *data)
michael@0 1014 {
michael@0 1015 zone->data = data;
michael@0 1016 }
michael@0 1017
michael@0 1018 JS_PUBLIC_API(void *)
michael@0 1019 JS_GetZoneUserData(JS::Zone *zone)
michael@0 1020 {
michael@0 1021 return zone->data;
michael@0 1022 }
michael@0 1023
michael@0 1024 JS_PUBLIC_API(bool)
michael@0 1025 JS_WrapObject(JSContext *cx, MutableHandleObject objp)
michael@0 1026 {
michael@0 1027 AssertHeapIsIdle(cx);
michael@0 1028 CHECK_REQUEST(cx);
michael@0 1029 if (objp)
michael@0 1030 JS::ExposeGCThingToActiveJS(objp, JSTRACE_OBJECT);
michael@0 1031 return cx->compartment()->wrap(cx, objp);
michael@0 1032 }
michael@0 1033
michael@0 1034 JS_PUBLIC_API(bool)
michael@0 1035 JS_WrapValue(JSContext *cx, MutableHandleValue vp)
michael@0 1036 {
michael@0 1037 AssertHeapIsIdle(cx);
michael@0 1038 CHECK_REQUEST(cx);
michael@0 1039 JS::ExposeValueToActiveJS(vp);
michael@0 1040 return cx->compartment()->wrap(cx, vp);
michael@0 1041 }
michael@0 1042
michael@0 1043 JS_PUBLIC_API(bool)
michael@0 1044 JS_WrapId(JSContext *cx, JS::MutableHandleId idp)
michael@0 1045 {
michael@0 1046 AssertHeapIsIdle(cx);
michael@0 1047 CHECK_REQUEST(cx);
michael@0 1048 jsid id = idp.get();
michael@0 1049 if (JSID_IS_STRING(id))
michael@0 1050 JS::ExposeGCThingToActiveJS(JSID_TO_STRING(id), JSTRACE_STRING);
michael@0 1051 else if (JSID_IS_OBJECT(id))
michael@0 1052 JS::ExposeGCThingToActiveJS(JSID_TO_OBJECT(id), JSTRACE_OBJECT);
michael@0 1053 return cx->compartment()->wrapId(cx, idp.address());
michael@0 1054 }
michael@0 1055
michael@0 1056 /*
michael@0 1057 * Identity remapping. Not for casual consumers.
michael@0 1058 *
michael@0 1059 * Normally, an object's contents and its identity are inextricably linked.
michael@0 1060 * Identity is determined by the address of the JSObject* in the heap, and
michael@0 1061 * the contents are what is located at that address. Transplanting allows these
michael@0 1062 * concepts to be separated through a combination of swapping (exchanging the
michael@0 1063 * contents of two same-compartment objects) and remapping cross-compartment
michael@0 1064 * identities by altering wrappers.
michael@0 1065 *
michael@0 1066 * The |origobj| argument should be the object whose identity needs to be
michael@0 1067 * remapped, usually to another compartment. The contents of |origobj| are
michael@0 1068 * destroyed.
michael@0 1069 *
michael@0 1070 * The |target| argument serves two purposes:
michael@0 1071 *
michael@0 1072 * First, |target| serves as a hint for the new identity of the object. The new
michael@0 1073 * identity object will always be in the same compartment as |target|, but
michael@0 1074 * if that compartment already had an object representing |origobj| (either a
michael@0 1075 * cross-compartment wrapper for it, or |origobj| itself if the two arguments
michael@0 1076 * are same-compartment), the existing object is used. Otherwise, |target|
michael@0 1077 * itself is used. To avoid ambiguity, JS_TransplantObject always returns the
michael@0 1078 * new identity.
michael@0 1079 *
michael@0 1080 * Second, the new identity object's contents will be those of |target|. A swap()
michael@0 1081 * is used to make this happen if an object other than |target| is used.
michael@0 1082 *
michael@0 1083 * We don't have a good way to recover from failure in this function, so
michael@0 1084 * we intentionally crash instead.
michael@0 1085 */
michael@0 1086
michael@0 1087 JS_PUBLIC_API(JSObject *)
michael@0 1088 JS_TransplantObject(JSContext *cx, HandleObject origobj, HandleObject target)
michael@0 1089 {
michael@0 1090 AssertHeapIsIdle(cx);
michael@0 1091 JS_ASSERT(origobj != target);
michael@0 1092 JS_ASSERT(!origobj->is<CrossCompartmentWrapperObject>());
michael@0 1093 JS_ASSERT(!target->is<CrossCompartmentWrapperObject>());
michael@0 1094
michael@0 1095 RootedValue origv(cx, ObjectValue(*origobj));
michael@0 1096 RootedObject newIdentity(cx);
michael@0 1097
michael@0 1098 {
michael@0 1099 // Scope to make ~AutoMaybeTouchDeadZones do its GC before the return value is on the stack.
michael@0 1100 AutoMaybeTouchDeadZones agc(cx);
michael@0 1101 AutoDisableProxyCheck adpc(cx->runtime());
michael@0 1102
michael@0 1103 JSCompartment *destination = target->compartment();
michael@0 1104
michael@0 1105 if (origobj->compartment() == destination) {
michael@0 1106 // If the original object is in the same compartment as the
michael@0 1107 // destination, then we know that we won't find a wrapper in the
michael@0 1108 // destination's cross compartment map and that the same
michael@0 1109 // object will continue to work.
michael@0 1110 if (!JSObject::swap(cx, origobj, target))
michael@0 1111 MOZ_CRASH();
michael@0 1112 newIdentity = origobj;
michael@0 1113 } else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
michael@0 1114 // There might already be a wrapper for the original object in
michael@0 1115 // the new compartment. If there is, we use its identity and swap
michael@0 1116 // in the contents of |target|.
michael@0 1117 newIdentity = &p->value().toObject();
michael@0 1118
michael@0 1119 // When we remove origv from the wrapper map, its wrapper, newIdentity,
michael@0 1120 // must immediately cease to be a cross-compartment wrapper. Neuter it.
michael@0 1121 destination->removeWrapper(p);
michael@0 1122 NukeCrossCompartmentWrapper(cx, newIdentity);
michael@0 1123
michael@0 1124 if (!JSObject::swap(cx, newIdentity, target))
michael@0 1125 MOZ_CRASH();
michael@0 1126 } else {
michael@0 1127 // Otherwise, we use |target| for the new identity object.
michael@0 1128 newIdentity = target;
michael@0 1129 }
michael@0 1130
michael@0 1131 // Now, iterate through other scopes looking for references to the
michael@0 1132 // old object, and update the relevant cross-compartment wrappers.
michael@0 1133 if (!RemapAllWrappersForObject(cx, origobj, newIdentity))
michael@0 1134 MOZ_CRASH();
michael@0 1135
michael@0 1136 // Lastly, update the original object to point to the new one.
michael@0 1137 if (origobj->compartment() != destination) {
michael@0 1138 RootedObject newIdentityWrapper(cx, newIdentity);
michael@0 1139 AutoCompartment ac(cx, origobj);
michael@0 1140 if (!JS_WrapObject(cx, &newIdentityWrapper))
michael@0 1141 MOZ_CRASH();
michael@0 1142 JS_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
michael@0 1143 if (!JSObject::swap(cx, origobj, newIdentityWrapper))
michael@0 1144 MOZ_CRASH();
michael@0 1145 origobj->compartment()->putWrapper(cx, ObjectValue(*newIdentity), origv);
michael@0 1146 }
michael@0 1147 }
michael@0 1148
michael@0 1149 // The new identity object might be one of several things. Return it to avoid
michael@0 1150 // ambiguity.
michael@0 1151 return newIdentity;
michael@0 1152 }
michael@0 1153
michael@0 1154 /*
michael@0 1155 * Recompute all cross-compartment wrappers for an object, resetting state.
michael@0 1156 * Gecko uses this to clear Xray wrappers when doing a navigation that reuses
michael@0 1157 * the inner window and global object.
michael@0 1158 */
michael@0 1159 JS_PUBLIC_API(bool)
michael@0 1160 JS_RefreshCrossCompartmentWrappers(JSContext *cx, HandleObject obj)
michael@0 1161 {
michael@0 1162 return RemapAllWrappersForObject(cx, obj, obj);
michael@0 1163 }
michael@0 1164
michael@0 1165 JS_PUBLIC_API(bool)
michael@0 1166 JS_InitStandardClasses(JSContext *cx, HandleObject obj)
michael@0 1167 {
michael@0 1168 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 1169 AssertHeapIsIdle(cx);
michael@0 1170 CHECK_REQUEST(cx);
michael@0 1171
michael@0 1172 cx->setDefaultCompartmentObjectIfUnset(obj);
michael@0 1173 assertSameCompartment(cx, obj);
michael@0 1174
michael@0 1175 Rooted<GlobalObject*> global(cx, &obj->global());
michael@0 1176 return GlobalObject::initStandardClasses(cx, global);
michael@0 1177 }
michael@0 1178
michael@0 1179 #define CLASP(name) (&name##Class)
michael@0 1180 #define OCLASP(name) (&name##Object::class_)
michael@0 1181 #define TYPED_ARRAY_CLASP(type) (&TypedArrayObject::classes[ScalarTypeDescr::type])
michael@0 1182 #define EAGER_ATOM(name) NAME_OFFSET(name)
michael@0 1183 #define EAGER_CLASS_ATOM(name) NAME_OFFSET(name)
michael@0 1184
michael@0 1185 static js::Class DummyClass;
michael@0 1186 static js::Class SentinelClass;
michael@0 1187
michael@0 1188 typedef struct JSStdName {
michael@0 1189 size_t atomOffset; /* offset of atom pointer in JSAtomState */
michael@0 1190 const Class *clasp;
michael@0 1191 bool isDummy() const { return clasp == &DummyClass; };
michael@0 1192 bool isSentinel() const { return clasp == &SentinelClass; };
michael@0 1193 } JSStdName;
michael@0 1194
michael@0 1195 static const JSStdName*
michael@0 1196 LookupStdName(JSRuntime *rt, HandleString name, const JSStdName *table)
michael@0 1197 {
michael@0 1198 MOZ_ASSERT(name->isAtom());
michael@0 1199 for (unsigned i = 0; !table[i].isSentinel(); i++) {
michael@0 1200 if (table[i].isDummy())
michael@0 1201 continue;
michael@0 1202 JSAtom *atom = AtomStateOffsetToName(*rt->commonNames, table[i].atomOffset);
michael@0 1203 MOZ_ASSERT(atom);
michael@0 1204 if (name == atom)
michael@0 1205 return &table[i];
michael@0 1206 }
michael@0 1207
michael@0 1208 return nullptr;
michael@0 1209 }
michael@0 1210
michael@0 1211 /*
michael@0 1212 * Table of standard classes, indexed by JSProtoKey. For entries where the
michael@0 1213 * JSProtoKey does not correspond to a class with a meaningful constructor, we
michael@0 1214 * insert a null entry into the table.
michael@0 1215 */
michael@0 1216 #define STD_NAME_ENTRY(name, code, init, clasp) { EAGER_CLASS_ATOM(name), clasp },
michael@0 1217 #define STD_DUMMY_ENTRY(name, code, init, dummy) { 0, &DummyClass },
michael@0 1218 static const JSStdName standard_class_names[] = {
michael@0 1219 JS_FOR_PROTOTYPES(STD_NAME_ENTRY, STD_DUMMY_ENTRY)
michael@0 1220 { 0, &SentinelClass }
michael@0 1221 };
michael@0 1222
michael@0 1223 /*
michael@0 1224 * Table of top-level function and constant names and the init function of the
michael@0 1225 * corresponding standard class that sets them up.
michael@0 1226 */
michael@0 1227 static const JSStdName builtin_property_names[] = {
michael@0 1228 { EAGER_ATOM(eval), &JSObject::class_ },
michael@0 1229
michael@0 1230 /* Global properties and functions defined by the Number class. */
michael@0 1231 { EAGER_ATOM(NaN), OCLASP(Number) },
michael@0 1232 { EAGER_ATOM(Infinity), OCLASP(Number) },
michael@0 1233 { EAGER_ATOM(isNaN), OCLASP(Number) },
michael@0 1234 { EAGER_ATOM(isFinite), OCLASP(Number) },
michael@0 1235 { EAGER_ATOM(parseFloat), OCLASP(Number) },
michael@0 1236 { EAGER_ATOM(parseInt), OCLASP(Number) },
michael@0 1237
michael@0 1238 /* String global functions. */
michael@0 1239 { EAGER_ATOM(escape), OCLASP(String) },
michael@0 1240 { EAGER_ATOM(unescape), OCLASP(String) },
michael@0 1241 { EAGER_ATOM(decodeURI), OCLASP(String) },
michael@0 1242 { EAGER_ATOM(encodeURI), OCLASP(String) },
michael@0 1243 { EAGER_ATOM(decodeURIComponent), OCLASP(String) },
michael@0 1244 { EAGER_ATOM(encodeURIComponent), OCLASP(String) },
michael@0 1245 #if JS_HAS_UNEVAL
michael@0 1246 { EAGER_ATOM(uneval), OCLASP(String) },
michael@0 1247 #endif
michael@0 1248 #ifdef ENABLE_BINARYDATA
michael@0 1249 { EAGER_ATOM(SIMD), OCLASP(SIMD) },
michael@0 1250 { EAGER_ATOM(TypedObject), OCLASP(TypedObjectModule) },
michael@0 1251 #endif
michael@0 1252
michael@0 1253 { 0, &SentinelClass }
michael@0 1254 };
michael@0 1255
michael@0 1256 #undef CLASP
michael@0 1257 #undef TYPED_ARRAY_CLASP
michael@0 1258 #undef EAGER_ATOM
michael@0 1259 #undef EAGER_CLASS_ATOM
michael@0 1260 #undef EAGER_ATOM_CLASP
michael@0 1261
michael@0 1262 JS_PUBLIC_API(bool)
michael@0 1263 JS_ResolveStandardClass(JSContext *cx, HandleObject obj, HandleId id, bool *resolved)
michael@0 1264 {
michael@0 1265 JSRuntime *rt;
michael@0 1266 const JSStdName *stdnm;
michael@0 1267
michael@0 1268 AssertHeapIsIdle(cx);
michael@0 1269 CHECK_REQUEST(cx);
michael@0 1270 assertSameCompartment(cx, obj, id);
michael@0 1271
michael@0 1272 Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
michael@0 1273 *resolved = false;
michael@0 1274
michael@0 1275 rt = cx->runtime();
michael@0 1276 if (!rt->hasContexts() || !JSID_IS_ATOM(id))
michael@0 1277 return true;
michael@0 1278
michael@0 1279 RootedString idstr(cx, JSID_TO_STRING(id));
michael@0 1280
michael@0 1281 /* Check whether we're resolving 'undefined', and define it if so. */
michael@0 1282 JSAtom *undefinedAtom = cx->names().undefined;
michael@0 1283 if (idstr == undefinedAtom) {
michael@0 1284 *resolved = true;
michael@0 1285 return JSObject::defineProperty(cx, obj, undefinedAtom->asPropertyName(),
michael@0 1286 UndefinedHandleValue,
michael@0 1287 JS_PropertyStub, JS_StrictPropertyStub,
michael@0 1288 JSPROP_PERMANENT | JSPROP_READONLY);
michael@0 1289 }
michael@0 1290
michael@0 1291 /* Try for class constructors/prototypes named by well-known atoms. */
michael@0 1292 stdnm = LookupStdName(rt, idstr, standard_class_names);
michael@0 1293
michael@0 1294 /* Try less frequently used top-level functions and constants. */
michael@0 1295 if (!stdnm)
michael@0 1296 stdnm = LookupStdName(rt, idstr, builtin_property_names);
michael@0 1297
michael@0 1298 // If this class is anonymous, then it doesn't exist as a global
michael@0 1299 // property, so we won't resolve anything.
michael@0 1300 if (stdnm && !(stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)) {
michael@0 1301 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp);
michael@0 1302 if (!GlobalObject::ensureConstructor(cx, global, key))
michael@0 1303 return false;
michael@0 1304
michael@0 1305 *resolved = true;
michael@0 1306 return true;
michael@0 1307 }
michael@0 1308
michael@0 1309 // There is no such property to resolve. An ordinary resolve hook would
michael@0 1310 // just return true at this point. But the global object is special in one
michael@0 1311 // more way: its prototype chain is lazily initialized. That is,
michael@0 1312 // global->getProto() might be null right now because we haven't created
michael@0 1313 // Object.prototype yet. Force it now.
michael@0 1314 if (!global->getOrCreateObjectPrototype(cx))
michael@0 1315 return false;
michael@0 1316
michael@0 1317 return true;
michael@0 1318 }
michael@0 1319
michael@0 1320 JS_PUBLIC_API(bool)
michael@0 1321 JS_EnumerateStandardClasses(JSContext *cx, HandleObject obj)
michael@0 1322 {
michael@0 1323 AssertHeapIsIdle(cx);
michael@0 1324 CHECK_REQUEST(cx);
michael@0 1325 assertSameCompartment(cx, obj);
michael@0 1326 MOZ_ASSERT(obj->is<GlobalObject>());
michael@0 1327 Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
michael@0 1328 return GlobalObject::initStandardClasses(cx, global);
michael@0 1329 }
michael@0 1330
michael@0 1331 JS_PUBLIC_API(bool)
michael@0 1332 JS_GetClassObject(JSContext *cx, JSProtoKey key, MutableHandleObject objp)
michael@0 1333 {
michael@0 1334 AssertHeapIsIdle(cx);
michael@0 1335 CHECK_REQUEST(cx);
michael@0 1336 return GetBuiltinConstructor(cx, key, objp);
michael@0 1337 }
michael@0 1338
michael@0 1339 JS_PUBLIC_API(bool)
michael@0 1340 JS_GetClassPrototype(JSContext *cx, JSProtoKey key, MutableHandleObject objp)
michael@0 1341 {
michael@0 1342 AssertHeapIsIdle(cx);
michael@0 1343 CHECK_REQUEST(cx);
michael@0 1344 return GetBuiltinPrototype(cx, key, objp);
michael@0 1345 }
michael@0 1346
michael@0 1347 JS_PUBLIC_API(JSProtoKey)
michael@0 1348 JS_IdToProtoKey(JSContext *cx, HandleId id)
michael@0 1349 {
michael@0 1350 AssertHeapIsIdle(cx);
michael@0 1351 CHECK_REQUEST(cx);
michael@0 1352
michael@0 1353 if (!JSID_IS_ATOM(id))
michael@0 1354 return JSProto_Null;
michael@0 1355 RootedString idstr(cx, JSID_TO_STRING(id));
michael@0 1356 const JSStdName *stdnm = LookupStdName(cx->runtime(), idstr, standard_class_names);
michael@0 1357 if (!stdnm)
michael@0 1358 return JSProto_Null;
michael@0 1359
michael@0 1360 MOZ_ASSERT(MOZ_ARRAY_LENGTH(standard_class_names) == JSProto_LIMIT + 1);
michael@0 1361 return static_cast<JSProtoKey>(stdnm - standard_class_names);
michael@0 1362 }
michael@0 1363
michael@0 1364 JS_PUBLIC_API(JSObject *)
michael@0 1365 JS_GetObjectPrototype(JSContext *cx, HandleObject forObj)
michael@0 1366 {
michael@0 1367 CHECK_REQUEST(cx);
michael@0 1368 assertSameCompartment(cx, forObj);
michael@0 1369 return forObj->global().getOrCreateObjectPrototype(cx);
michael@0 1370 }
michael@0 1371
michael@0 1372 JS_PUBLIC_API(JSObject *)
michael@0 1373 JS_GetFunctionPrototype(JSContext *cx, HandleObject forObj)
michael@0 1374 {
michael@0 1375 CHECK_REQUEST(cx);
michael@0 1376 assertSameCompartment(cx, forObj);
michael@0 1377 return forObj->global().getOrCreateFunctionPrototype(cx);
michael@0 1378 }
michael@0 1379
michael@0 1380 JS_PUBLIC_API(JSObject *)
michael@0 1381 JS_GetArrayPrototype(JSContext *cx, HandleObject forObj)
michael@0 1382 {
michael@0 1383 CHECK_REQUEST(cx);
michael@0 1384 assertSameCompartment(cx, forObj);
michael@0 1385 Rooted<GlobalObject*> global(cx, &forObj->global());
michael@0 1386 return GlobalObject::getOrCreateArrayPrototype(cx, global);
michael@0 1387 }
michael@0 1388
michael@0 1389 JS_PUBLIC_API(JSObject *)
michael@0 1390 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
michael@0 1391 {
michael@0 1392 AssertHeapIsIdle(cx);
michael@0 1393 assertSameCompartment(cx, obj);
michael@0 1394 return &obj->global();
michael@0 1395 }
michael@0 1396
michael@0 1397 extern JS_PUBLIC_API(bool)
michael@0 1398 JS_IsGlobalObject(JSObject *obj)
michael@0 1399 {
michael@0 1400 return obj->is<GlobalObject>();
michael@0 1401 }
michael@0 1402
michael@0 1403 JS_PUBLIC_API(JSObject *)
michael@0 1404 JS_GetGlobalForCompartmentOrNull(JSContext *cx, JSCompartment *c)
michael@0 1405 {
michael@0 1406 AssertHeapIsIdleOrIterating(cx);
michael@0 1407 assertSameCompartment(cx, c);
michael@0 1408 return c->maybeGlobal();
michael@0 1409 }
michael@0 1410
michael@0 1411 JS_PUBLIC_API(JSObject *)
michael@0 1412 JS::CurrentGlobalOrNull(JSContext *cx)
michael@0 1413 {
michael@0 1414 AssertHeapIsIdleOrIterating(cx);
michael@0 1415 CHECK_REQUEST(cx);
michael@0 1416 if (!cx->compartment())
michael@0 1417 return nullptr;
michael@0 1418 return cx->global();
michael@0 1419 }
michael@0 1420
michael@0 1421 JS_PUBLIC_API(jsval)
michael@0 1422 JS_ComputeThis(JSContext *cx, jsval *vp)
michael@0 1423 {
michael@0 1424 AssertHeapIsIdle(cx);
michael@0 1425 assertSameCompartment(cx, JSValueArray(vp, 2));
michael@0 1426 CallReceiver call = CallReceiverFromVp(vp);
michael@0 1427 if (!BoxNonStrictThis(cx, call))
michael@0 1428 return JSVAL_NULL;
michael@0 1429 return call.thisv();
michael@0 1430 }
michael@0 1431
michael@0 1432 JS_PUBLIC_API(void *)
michael@0 1433 JS_malloc(JSContext *cx, size_t nbytes)
michael@0 1434 {
michael@0 1435 AssertHeapIsIdle(cx);
michael@0 1436 CHECK_REQUEST(cx);
michael@0 1437 return cx->malloc_(nbytes);
michael@0 1438 }
michael@0 1439
michael@0 1440 JS_PUBLIC_API(void *)
michael@0 1441 JS_realloc(JSContext *cx, void *p, size_t nbytes)
michael@0 1442 {
michael@0 1443 AssertHeapIsIdle(cx);
michael@0 1444 CHECK_REQUEST(cx);
michael@0 1445 return cx->realloc_(p, nbytes);
michael@0 1446 }
michael@0 1447
michael@0 1448 JS_PUBLIC_API(void)
michael@0 1449 JS_free(JSContext *cx, void *p)
michael@0 1450 {
michael@0 1451 return js_free(p);
michael@0 1452 }
michael@0 1453
michael@0 1454 JS_PUBLIC_API(void)
michael@0 1455 JS_freeop(JSFreeOp *fop, void *p)
michael@0 1456 {
michael@0 1457 return FreeOp::get(fop)->free_(p);
michael@0 1458 }
michael@0 1459
michael@0 1460 JS_PUBLIC_API(JSFreeOp *)
michael@0 1461 JS_GetDefaultFreeOp(JSRuntime *rt)
michael@0 1462 {
michael@0 1463 return rt->defaultFreeOp();
michael@0 1464 }
michael@0 1465
michael@0 1466 JS_PUBLIC_API(void)
michael@0 1467 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
michael@0 1468 {
michael@0 1469 return cx->runtime()->updateMallocCounter(cx->zone(), nbytes);
michael@0 1470 }
michael@0 1471
michael@0 1472 JS_PUBLIC_API(char *)
michael@0 1473 JS_strdup(JSContext *cx, const char *s)
michael@0 1474 {
michael@0 1475 AssertHeapIsIdle(cx);
michael@0 1476 return js_strdup(cx, s);
michael@0 1477 }
michael@0 1478
michael@0 1479 JS_PUBLIC_API(char *)
michael@0 1480 JS_strdup(JSRuntime *rt, const char *s)
michael@0 1481 {
michael@0 1482 AssertHeapIsIdle(rt);
michael@0 1483 size_t n = strlen(s) + 1;
michael@0 1484 void *p = rt->malloc_(n);
michael@0 1485 if (!p)
michael@0 1486 return nullptr;
michael@0 1487 return static_cast<char*>(js_memcpy(p, s, n));
michael@0 1488 }
michael@0 1489
michael@0 1490 #undef JS_AddRoot
michael@0 1491
michael@0 1492 JS_PUBLIC_API(bool)
michael@0 1493 JS::AddValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp)
michael@0 1494 {
michael@0 1495 AssertHeapIsIdle(cx);
michael@0 1496 CHECK_REQUEST(cx);
michael@0 1497 return AddValueRoot(cx, vp->unsafeGet(), nullptr);
michael@0 1498 }
michael@0 1499
michael@0 1500 JS_PUBLIC_API(bool)
michael@0 1501 JS::AddStringRoot(JSContext *cx, JS::Heap<JSString *> *rp)
michael@0 1502 {
michael@0 1503 AssertHeapIsIdle(cx);
michael@0 1504 CHECK_REQUEST(cx);
michael@0 1505 return AddStringRoot(cx, rp->unsafeGet(), nullptr);
michael@0 1506 }
michael@0 1507
michael@0 1508 JS_PUBLIC_API(bool)
michael@0 1509 JS::AddObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp)
michael@0 1510 {
michael@0 1511 AssertHeapIsIdle(cx);
michael@0 1512 CHECK_REQUEST(cx);
michael@0 1513 return AddObjectRoot(cx, rp->unsafeGet(), nullptr);
michael@0 1514 }
michael@0 1515
michael@0 1516 JS_PUBLIC_API(bool)
michael@0 1517 JS::AddNamedValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp, const char *name)
michael@0 1518 {
michael@0 1519 AssertHeapIsIdle(cx);
michael@0 1520 CHECK_REQUEST(cx);
michael@0 1521 return AddValueRoot(cx, vp->unsafeGet(), name);
michael@0 1522 }
michael@0 1523
michael@0 1524 JS_PUBLIC_API(bool)
michael@0 1525 JS::AddNamedValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp, const char *name)
michael@0 1526 {
michael@0 1527 return AddValueRootRT(rt, vp->unsafeGet(), name);
michael@0 1528 }
michael@0 1529
michael@0 1530 JS_PUBLIC_API(bool)
michael@0 1531 JS::AddNamedStringRoot(JSContext *cx, JS::Heap<JSString *> *rp, const char *name)
michael@0 1532 {
michael@0 1533 AssertHeapIsIdle(cx);
michael@0 1534 CHECK_REQUEST(cx);
michael@0 1535 return AddStringRoot(cx, rp->unsafeGet(), name);
michael@0 1536 }
michael@0 1537
michael@0 1538 JS_PUBLIC_API(bool)
michael@0 1539 JS::AddNamedObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp, const char *name)
michael@0 1540 {
michael@0 1541 AssertHeapIsIdle(cx);
michael@0 1542 CHECK_REQUEST(cx);
michael@0 1543 return AddObjectRoot(cx, rp->unsafeGet(), name);
michael@0 1544 }
michael@0 1545
michael@0 1546 JS_PUBLIC_API(bool)
michael@0 1547 JS::AddNamedScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp, const char *name)
michael@0 1548 {
michael@0 1549 AssertHeapIsIdle(cx);
michael@0 1550 CHECK_REQUEST(cx);
michael@0 1551 return AddScriptRoot(cx, rp->unsafeGet(), name);
michael@0 1552 }
michael@0 1553
michael@0 1554 /* We allow unrooting from finalizers within the GC */
michael@0 1555
michael@0 1556 JS_PUBLIC_API(void)
michael@0 1557 JS::RemoveValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp)
michael@0 1558 {
michael@0 1559 CHECK_REQUEST(cx);
michael@0 1560 RemoveRoot(cx->runtime(), (void *)vp);
michael@0 1561 *vp = UndefinedValue();
michael@0 1562 }
michael@0 1563
michael@0 1564 JS_PUBLIC_API(void)
michael@0 1565 JS::RemoveStringRoot(JSContext *cx, JS::Heap<JSString *> *rp)
michael@0 1566 {
michael@0 1567 CHECK_REQUEST(cx);
michael@0 1568 RemoveRoot(cx->runtime(), (void *)rp);
michael@0 1569 *rp = nullptr;
michael@0 1570 }
michael@0 1571
michael@0 1572 JS_PUBLIC_API(void)
michael@0 1573 JS::RemoveObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp)
michael@0 1574 {
michael@0 1575 CHECK_REQUEST(cx);
michael@0 1576 RemoveRoot(cx->runtime(), (void *)rp);
michael@0 1577 *rp = nullptr;
michael@0 1578 }
michael@0 1579
michael@0 1580 JS_PUBLIC_API(void)
michael@0 1581 JS::RemoveScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp)
michael@0 1582 {
michael@0 1583 CHECK_REQUEST(cx);
michael@0 1584 RemoveRoot(cx->runtime(), (void *)rp);
michael@0 1585 *rp = nullptr;
michael@0 1586 }
michael@0 1587
michael@0 1588 JS_PUBLIC_API(void)
michael@0 1589 JS::RemoveValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp)
michael@0 1590 {
michael@0 1591 RemoveRoot(rt, (void *)vp);
michael@0 1592 *vp = UndefinedValue();
michael@0 1593 }
michael@0 1594
michael@0 1595 JS_PUBLIC_API(void)
michael@0 1596 JS::RemoveStringRootRT(JSRuntime *rt, JS::Heap<JSString *> *rp)
michael@0 1597 {
michael@0 1598 RemoveRoot(rt, (void *)rp);
michael@0 1599 *rp = nullptr;
michael@0 1600 }
michael@0 1601
michael@0 1602 JS_PUBLIC_API(void)
michael@0 1603 JS::RemoveObjectRootRT(JSRuntime *rt, JS::Heap<JSObject *> *rp)
michael@0 1604 {
michael@0 1605 RemoveRoot(rt, (void *)rp);
michael@0 1606 *rp = nullptr;
michael@0 1607 }
michael@0 1608
michael@0 1609 JS_PUBLIC_API(void)
michael@0 1610 JS::RemoveScriptRootRT(JSRuntime *rt, JS::Heap<JSScript *> *rp)
michael@0 1611 {
michael@0 1612 RemoveRoot(rt, (void *)rp);
michael@0 1613 *rp = nullptr;
michael@0 1614 }
michael@0 1615
michael@0 1616 JS_PUBLIC_API(bool)
michael@0 1617 JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
michael@0 1618 {
michael@0 1619 AssertHeapIsIdle(rt);
michael@0 1620 return !!rt->gcBlackRootTracers.append(JSRuntime::ExtraTracer(traceOp, data));
michael@0 1621 }
michael@0 1622
michael@0 1623 JS_PUBLIC_API(void)
michael@0 1624 JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
michael@0 1625 {
michael@0 1626 AssertHeapIsIdle(rt);
michael@0 1627 for (size_t i = 0; i < rt->gcBlackRootTracers.length(); i++) {
michael@0 1628 JSRuntime::ExtraTracer *e = &rt->gcBlackRootTracers[i];
michael@0 1629 if (e->op == traceOp && e->data == data) {
michael@0 1630 rt->gcBlackRootTracers.erase(e);
michael@0 1631 break;
michael@0 1632 }
michael@0 1633 }
michael@0 1634 }
michael@0 1635
michael@0 1636 #ifdef DEBUG
michael@0 1637
michael@0 1638 typedef struct JSHeapDumpNode JSHeapDumpNode;
michael@0 1639
michael@0 1640 struct JSHeapDumpNode {
michael@0 1641 void *thing;
michael@0 1642 JSGCTraceKind kind;
michael@0 1643 JSHeapDumpNode *next; /* next sibling */
michael@0 1644 JSHeapDumpNode *parent; /* node with the thing that refer to thing
michael@0 1645 from this node */
michael@0 1646 char edgeName[1]; /* name of the edge from parent->thing
michael@0 1647 into thing */
michael@0 1648 };
michael@0 1649
michael@0 1650 typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> VisitedSet;
michael@0 1651
michael@0 1652 class DumpingTracer
michael@0 1653 {
michael@0 1654 public:
michael@0 1655 DumpingTracer(JSRuntime *rt, JSTraceCallback callback)
michael@0 1656 : base(rt, callback)
michael@0 1657 {}
michael@0 1658
michael@0 1659 JSTracer base;
michael@0 1660 VisitedSet visited;
michael@0 1661 bool ok;
michael@0 1662 void *startThing;
michael@0 1663 void *thingToFind;
michael@0 1664 void *thingToIgnore;
michael@0 1665 JSHeapDumpNode *parentNode;
michael@0 1666 JSHeapDumpNode **lastNodep;
michael@0 1667 char buffer[200];
michael@0 1668 };
michael@0 1669
michael@0 1670 static void
michael@0 1671 DumpNotify(JSTracer *trc, void **thingp, JSGCTraceKind kind)
michael@0 1672 {
michael@0 1673 JS_ASSERT(trc->callback == DumpNotify);
michael@0 1674
michael@0 1675 DumpingTracer *dtrc = (DumpingTracer *)trc;
michael@0 1676 void *thing = *thingp;
michael@0 1677
michael@0 1678 if (!dtrc->ok || thing == dtrc->thingToIgnore)
michael@0 1679 return;
michael@0 1680
michael@0 1681 /*
michael@0 1682 * Check if we have already seen thing unless it is thingToFind to include
michael@0 1683 * it to the graph each time we reach it and print all live things that
michael@0 1684 * refer to thingToFind.
michael@0 1685 *
michael@0 1686 * This does not print all possible paths leading to thingToFind since
michael@0 1687 * when a thing A refers directly or indirectly to thingToFind and A is
michael@0 1688 * present several times in the graph, we will print only the first path
michael@0 1689 * leading to A and thingToFind, other ways to reach A will be ignored.
michael@0 1690 */
michael@0 1691 if (dtrc->thingToFind != thing) {
michael@0 1692 /*
michael@0 1693 * The startThing check allows to avoid putting startThing into the
michael@0 1694 * hash table before tracing startThing in JS_DumpHeap.
michael@0 1695 */
michael@0 1696 if (thing == dtrc->startThing)
michael@0 1697 return;
michael@0 1698 VisitedSet::AddPtr p = dtrc->visited.lookupForAdd(thing);
michael@0 1699 if (p)
michael@0 1700 return;
michael@0 1701 if (!dtrc->visited.add(p, thing)) {
michael@0 1702 dtrc->ok = false;
michael@0 1703 return;
michael@0 1704 }
michael@0 1705 }
michael@0 1706
michael@0 1707 const char *edgeName = dtrc->base.getTracingEdgeName(dtrc->buffer, sizeof(dtrc->buffer));
michael@0 1708 size_t edgeNameSize = strlen(edgeName) + 1;
michael@0 1709 size_t bytes = offsetof(JSHeapDumpNode, edgeName) + edgeNameSize;
michael@0 1710 JSHeapDumpNode *node = (JSHeapDumpNode *) js_malloc(bytes);
michael@0 1711 if (!node) {
michael@0 1712 dtrc->ok = false;
michael@0 1713 return;
michael@0 1714 }
michael@0 1715
michael@0 1716 node->thing = thing;
michael@0 1717 node->kind = kind;
michael@0 1718 node->next = nullptr;
michael@0 1719 node->parent = dtrc->parentNode;
michael@0 1720 js_memcpy(node->edgeName, edgeName, edgeNameSize);
michael@0 1721
michael@0 1722 JS_ASSERT(!*dtrc->lastNodep);
michael@0 1723 *dtrc->lastNodep = node;
michael@0 1724 dtrc->lastNodep = &node->next;
michael@0 1725 }
michael@0 1726
michael@0 1727 /* Dump node and the chain that leads to thing it contains. */
michael@0 1728 static bool
michael@0 1729 DumpNode(DumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
michael@0 1730 {
michael@0 1731 JSHeapDumpNode *prev, *following;
michael@0 1732 size_t chainLimit;
michael@0 1733 enum { MAX_PARENTS_TO_PRINT = 10 };
michael@0 1734
michael@0 1735 JS_GetTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
michael@0 1736 &dtrc->base, node->thing, node->kind, true);
michael@0 1737 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
michael@0 1738 return false;
michael@0 1739
michael@0 1740 /*
michael@0 1741 * We need to print the parent chain in the reverse order. To do it in
michael@0 1742 * O(N) time where N is the chain length we first reverse the chain while
michael@0 1743 * searching for the top and then print each node while restoring the
michael@0 1744 * chain order.
michael@0 1745 */
michael@0 1746 chainLimit = MAX_PARENTS_TO_PRINT;
michael@0 1747 prev = nullptr;
michael@0 1748 for (;;) {
michael@0 1749 following = node->parent;
michael@0 1750 node->parent = prev;
michael@0 1751 prev = node;
michael@0 1752 node = following;
michael@0 1753 if (!node)
michael@0 1754 break;
michael@0 1755 if (chainLimit == 0) {
michael@0 1756 if (fputs("...", fp) < 0)
michael@0 1757 return false;
michael@0 1758 break;
michael@0 1759 }
michael@0 1760 --chainLimit;
michael@0 1761 }
michael@0 1762
michael@0 1763 node = prev;
michael@0 1764 prev = following;
michael@0 1765 bool ok = true;
michael@0 1766 do {
michael@0 1767 /* Loop must continue even when !ok to restore the parent chain. */
michael@0 1768 if (ok) {
michael@0 1769 if (!prev) {
michael@0 1770 /* Print edge from some runtime root or startThing. */
michael@0 1771 if (fputs(node->edgeName, fp) < 0)
michael@0 1772 ok = false;
michael@0 1773 } else {
michael@0 1774 JS_GetTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
michael@0 1775 &dtrc->base, prev->thing, prev->kind,
michael@0 1776 false);
michael@0 1777 if (fprintf(fp, "(%p %s).%s",
michael@0 1778 prev->thing, dtrc->buffer, node->edgeName) < 0) {
michael@0 1779 ok = false;
michael@0 1780 }
michael@0 1781 }
michael@0 1782 }
michael@0 1783 following = node->parent;
michael@0 1784 node->parent = prev;
michael@0 1785 prev = node;
michael@0 1786 node = following;
michael@0 1787 } while (node);
michael@0 1788
michael@0 1789 return ok && putc('\n', fp) >= 0;
michael@0 1790 }
michael@0 1791
michael@0 1792 JS_PUBLIC_API(bool)
michael@0 1793 JS_DumpHeap(JSRuntime *rt, FILE *fp, void* startThing, JSGCTraceKind startKind,
michael@0 1794 void *thingToFind, size_t maxDepth, void *thingToIgnore)
michael@0 1795 {
michael@0 1796 if (maxDepth == 0)
michael@0 1797 return true;
michael@0 1798
michael@0 1799 DumpingTracer dtrc(rt, DumpNotify);
michael@0 1800 if (!dtrc.visited.init())
michael@0 1801 return false;
michael@0 1802 dtrc.ok = true;
michael@0 1803 dtrc.startThing = startThing;
michael@0 1804 dtrc.thingToFind = thingToFind;
michael@0 1805 dtrc.thingToIgnore = thingToIgnore;
michael@0 1806 dtrc.parentNode = nullptr;
michael@0 1807 JSHeapDumpNode *node = nullptr;
michael@0 1808 dtrc.lastNodep = &node;
michael@0 1809 if (!startThing) {
michael@0 1810 JS_ASSERT(startKind == JSTRACE_OBJECT);
michael@0 1811 TraceRuntime(&dtrc.base);
michael@0 1812 } else {
michael@0 1813 JS_TraceChildren(&dtrc.base, startThing, startKind);
michael@0 1814 }
michael@0 1815
michael@0 1816 if (!node)
michael@0 1817 return dtrc.ok;
michael@0 1818
michael@0 1819 size_t depth = 1;
michael@0 1820 JSHeapDumpNode *children, *next, *parent;
michael@0 1821 bool thingToFindWasTraced = thingToFind && thingToFind == startThing;
michael@0 1822 for (;;) {
michael@0 1823 /*
michael@0 1824 * Loop must continue even when !dtrc.ok to free all nodes allocated
michael@0 1825 * so far.
michael@0 1826 */
michael@0 1827 if (dtrc.ok) {
michael@0 1828 if (thingToFind == nullptr || thingToFind == node->thing)
michael@0 1829 dtrc.ok = DumpNode(&dtrc, fp, node);
michael@0 1830
michael@0 1831 /* Descend into children. */
michael@0 1832 if (dtrc.ok &&
michael@0 1833 depth < maxDepth &&
michael@0 1834 (thingToFind != node->thing || !thingToFindWasTraced)) {
michael@0 1835 dtrc.parentNode = node;
michael@0 1836 children = nullptr;
michael@0 1837 dtrc.lastNodep = &children;
michael@0 1838 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
michael@0 1839 if (thingToFind == node->thing)
michael@0 1840 thingToFindWasTraced = true;
michael@0 1841 if (children != nullptr) {
michael@0 1842 ++depth;
michael@0 1843 node = children;
michael@0 1844 continue;
michael@0 1845 }
michael@0 1846 }
michael@0 1847 }
michael@0 1848
michael@0 1849 /* Move to next or parents next and free the node. */
michael@0 1850 for (;;) {
michael@0 1851 next = node->next;
michael@0 1852 parent = node->parent;
michael@0 1853 js_free(node);
michael@0 1854 node = next;
michael@0 1855 if (node)
michael@0 1856 break;
michael@0 1857 if (!parent)
michael@0 1858 return dtrc.ok;
michael@0 1859 JS_ASSERT(depth > 1);
michael@0 1860 --depth;
michael@0 1861 node = parent;
michael@0 1862 }
michael@0 1863 }
michael@0 1864
michael@0 1865 JS_ASSERT(depth == 1);
michael@0 1866 return dtrc.ok;
michael@0 1867 }
michael@0 1868
michael@0 1869 #endif /* DEBUG */
michael@0 1870
michael@0 1871 extern JS_PUBLIC_API(bool)
michael@0 1872 JS_IsGCMarkingTracer(JSTracer *trc)
michael@0 1873 {
michael@0 1874 return IS_GC_MARKING_TRACER(trc);
michael@0 1875 }
michael@0 1876
michael@0 1877 #ifdef DEBUG
michael@0 1878 extern JS_PUBLIC_API(bool)
michael@0 1879 JS_IsMarkingGray(JSTracer *trc)
michael@0 1880 {
michael@0 1881 JS_ASSERT(JS_IsGCMarkingTracer(trc));
michael@0 1882 return trc->callback == GCMarker::GrayCallback;
michael@0 1883 }
michael@0 1884 #endif
michael@0 1885
michael@0 1886 JS_PUBLIC_API(void)
michael@0 1887 JS_GC(JSRuntime *rt)
michael@0 1888 {
michael@0 1889 AssertHeapIsIdle(rt);
michael@0 1890 JS::PrepareForFullGC(rt);
michael@0 1891 GC(rt, GC_NORMAL, JS::gcreason::API);
michael@0 1892 }
michael@0 1893
michael@0 1894 JS_PUBLIC_API(void)
michael@0 1895 JS_MaybeGC(JSContext *cx)
michael@0 1896 {
michael@0 1897 MaybeGC(cx);
michael@0 1898 }
michael@0 1899
michael@0 1900 JS_PUBLIC_API(void)
michael@0 1901 JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb, void *data)
michael@0 1902 {
michael@0 1903 AssertHeapIsIdle(rt);
michael@0 1904 rt->gcCallback = cb;
michael@0 1905 rt->gcCallbackData = data;
michael@0 1906 }
michael@0 1907
michael@0 1908 JS_PUBLIC_API(void)
michael@0 1909 JS_SetFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb)
michael@0 1910 {
michael@0 1911 AssertHeapIsIdle(rt);
michael@0 1912 rt->gcFinalizeCallback = cb;
michael@0 1913 }
michael@0 1914
michael@0 1915 JS_PUBLIC_API(bool)
michael@0 1916 JS_IsAboutToBeFinalized(JS::Heap<JSObject *> *objp)
michael@0 1917 {
michael@0 1918 return IsObjectAboutToBeFinalized(objp->unsafeGet());
michael@0 1919 }
michael@0 1920
michael@0 1921 JS_PUBLIC_API(bool)
michael@0 1922 JS_IsAboutToBeFinalizedUnbarriered(JSObject **objp)
michael@0 1923 {
michael@0 1924 return IsObjectAboutToBeFinalized(objp);
michael@0 1925 }
michael@0 1926
michael@0 1927 JS_PUBLIC_API(void)
michael@0 1928 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value)
michael@0 1929 {
michael@0 1930 switch (key) {
michael@0 1931 case JSGC_MAX_BYTES: {
michael@0 1932 JS_ASSERT(value >= rt->gcBytes);
michael@0 1933 rt->gcMaxBytes = value;
michael@0 1934 break;
michael@0 1935 }
michael@0 1936 case JSGC_MAX_MALLOC_BYTES:
michael@0 1937 rt->setGCMaxMallocBytes(value);
michael@0 1938 break;
michael@0 1939 case JSGC_SLICE_TIME_BUDGET:
michael@0 1940 rt->gcSliceBudget = SliceBudget::TimeBudget(value);
michael@0 1941 break;
michael@0 1942 case JSGC_MARK_STACK_LIMIT:
michael@0 1943 js::SetMarkStackLimit(rt, value);
michael@0 1944 break;
michael@0 1945 case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
michael@0 1946 rt->gcHighFrequencyTimeThreshold = value;
michael@0 1947 break;
michael@0 1948 case JSGC_HIGH_FREQUENCY_LOW_LIMIT:
michael@0 1949 rt->gcHighFrequencyLowLimitBytes = value * 1024 * 1024;
michael@0 1950 break;
michael@0 1951 case JSGC_HIGH_FREQUENCY_HIGH_LIMIT:
michael@0 1952 rt->gcHighFrequencyHighLimitBytes = value * 1024 * 1024;
michael@0 1953 break;
michael@0 1954 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX:
michael@0 1955 rt->gcHighFrequencyHeapGrowthMax = value / 100.0;
michael@0 1956 MOZ_ASSERT(rt->gcHighFrequencyHeapGrowthMax / 0.85 > 1.0);
michael@0 1957 break;
michael@0 1958 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN:
michael@0 1959 rt->gcHighFrequencyHeapGrowthMin = value / 100.0;
michael@0 1960 MOZ_ASSERT(rt->gcHighFrequencyHeapGrowthMin / 0.85 > 1.0);
michael@0 1961 break;
michael@0 1962 case JSGC_LOW_FREQUENCY_HEAP_GROWTH:
michael@0 1963 rt->gcLowFrequencyHeapGrowth = value / 100.0;
michael@0 1964 MOZ_ASSERT(rt->gcLowFrequencyHeapGrowth / 0.9 > 1.0);
michael@0 1965 break;
michael@0 1966 case JSGC_DYNAMIC_HEAP_GROWTH:
michael@0 1967 rt->gcDynamicHeapGrowth = value;
michael@0 1968 break;
michael@0 1969 case JSGC_DYNAMIC_MARK_SLICE:
michael@0 1970 rt->gcDynamicMarkSlice = value;
michael@0 1971 break;
michael@0 1972 case JSGC_ALLOCATION_THRESHOLD:
michael@0 1973 rt->gcAllocationThreshold = value * 1024 * 1024;
michael@0 1974 break;
michael@0 1975 case JSGC_DECOMMIT_THRESHOLD:
michael@0 1976 rt->gcDecommitThreshold = value * 1024 * 1024;
michael@0 1977 break;
michael@0 1978 default:
michael@0 1979 JS_ASSERT(key == JSGC_MODE);
michael@0 1980 rt->setGCMode(JSGCMode(value));
michael@0 1981 JS_ASSERT(rt->gcMode() == JSGC_MODE_GLOBAL ||
michael@0 1982 rt->gcMode() == JSGC_MODE_COMPARTMENT ||
michael@0 1983 rt->gcMode() == JSGC_MODE_INCREMENTAL);
michael@0 1984 return;
michael@0 1985 }
michael@0 1986 }
michael@0 1987
michael@0 1988 JS_PUBLIC_API(uint32_t)
michael@0 1989 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
michael@0 1990 {
michael@0 1991 switch (key) {
michael@0 1992 case JSGC_MAX_BYTES:
michael@0 1993 return uint32_t(rt->gcMaxBytes);
michael@0 1994 case JSGC_MAX_MALLOC_BYTES:
michael@0 1995 return rt->gcMaxMallocBytes;
michael@0 1996 case JSGC_BYTES:
michael@0 1997 return uint32_t(rt->gcBytes);
michael@0 1998 case JSGC_MODE:
michael@0 1999 return uint32_t(rt->gcMode());
michael@0 2000 case JSGC_UNUSED_CHUNKS:
michael@0 2001 return uint32_t(rt->gcChunkPool.getEmptyCount());
michael@0 2002 case JSGC_TOTAL_CHUNKS:
michael@0 2003 return uint32_t(rt->gcChunkSet.count() + rt->gcChunkPool.getEmptyCount());
michael@0 2004 case JSGC_SLICE_TIME_BUDGET:
michael@0 2005 return uint32_t(rt->gcSliceBudget > 0 ? rt->gcSliceBudget / PRMJ_USEC_PER_MSEC : 0);
michael@0 2006 case JSGC_MARK_STACK_LIMIT:
michael@0 2007 return rt->gcMarker.maxCapacity();
michael@0 2008 case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
michael@0 2009 return rt->gcHighFrequencyTimeThreshold;
michael@0 2010 case JSGC_HIGH_FREQUENCY_LOW_LIMIT:
michael@0 2011 return rt->gcHighFrequencyLowLimitBytes / 1024 / 1024;
michael@0 2012 case JSGC_HIGH_FREQUENCY_HIGH_LIMIT:
michael@0 2013 return rt->gcHighFrequencyHighLimitBytes / 1024 / 1024;
michael@0 2014 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX:
michael@0 2015 return uint32_t(rt->gcHighFrequencyHeapGrowthMax * 100);
michael@0 2016 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN:
michael@0 2017 return uint32_t(rt->gcHighFrequencyHeapGrowthMin * 100);
michael@0 2018 case JSGC_LOW_FREQUENCY_HEAP_GROWTH:
michael@0 2019 return uint32_t(rt->gcLowFrequencyHeapGrowth * 100);
michael@0 2020 case JSGC_DYNAMIC_HEAP_GROWTH:
michael@0 2021 return rt->gcDynamicHeapGrowth;
michael@0 2022 case JSGC_DYNAMIC_MARK_SLICE:
michael@0 2023 return rt->gcDynamicMarkSlice;
michael@0 2024 case JSGC_ALLOCATION_THRESHOLD:
michael@0 2025 return rt->gcAllocationThreshold / 1024 / 1024;
michael@0 2026 default:
michael@0 2027 JS_ASSERT(key == JSGC_NUMBER);
michael@0 2028 return uint32_t(rt->gcNumber);
michael@0 2029 }
michael@0 2030 }
michael@0 2031
michael@0 2032 JS_PUBLIC_API(void)
michael@0 2033 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32_t value)
michael@0 2034 {
michael@0 2035 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
michael@0 2036 }
michael@0 2037
michael@0 2038 JS_PUBLIC_API(uint32_t)
michael@0 2039 JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
michael@0 2040 {
michael@0 2041 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
michael@0 2042 return 0;
michael@0 2043 }
michael@0 2044
michael@0 2045 static const size_t NumGCConfigs = 14;
michael@0 2046 struct JSGCConfig {
michael@0 2047 JSGCParamKey key;
michael@0 2048 uint32_t value;
michael@0 2049 };
michael@0 2050
michael@0 2051 JS_PUBLIC_API(void)
michael@0 2052 JS_SetGCParametersBasedOnAvailableMemory(JSRuntime *rt, uint32_t availMem)
michael@0 2053 {
michael@0 2054 static const JSGCConfig minimal[NumGCConfigs] = {
michael@0 2055 {JSGC_MAX_MALLOC_BYTES, 6 * 1024 * 1024},
michael@0 2056 {JSGC_SLICE_TIME_BUDGET, 30},
michael@0 2057 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
michael@0 2058 {JSGC_HIGH_FREQUENCY_HIGH_LIMIT, 40},
michael@0 2059 {JSGC_HIGH_FREQUENCY_LOW_LIMIT, 0},
michael@0 2060 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, 300},
michael@0 2061 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, 120},
michael@0 2062 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 120},
michael@0 2063 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
michael@0 2064 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
michael@0 2065 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
michael@0 2066 {JSGC_ALLOCATION_THRESHOLD, 1},
michael@0 2067 {JSGC_DECOMMIT_THRESHOLD, 1},
michael@0 2068 {JSGC_MODE, JSGC_MODE_INCREMENTAL}
michael@0 2069 };
michael@0 2070
michael@0 2071 const JSGCConfig *config = minimal;
michael@0 2072 if (availMem > 512) {
michael@0 2073 static const JSGCConfig nominal[NumGCConfigs] = {
michael@0 2074 {JSGC_MAX_MALLOC_BYTES, 6 * 1024 * 1024},
michael@0 2075 {JSGC_SLICE_TIME_BUDGET, 30},
michael@0 2076 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1000},
michael@0 2077 {JSGC_HIGH_FREQUENCY_HIGH_LIMIT, 500},
michael@0 2078 {JSGC_HIGH_FREQUENCY_LOW_LIMIT, 100},
michael@0 2079 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, 300},
michael@0 2080 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, 150},
michael@0 2081 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 150},
michael@0 2082 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
michael@0 2083 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
michael@0 2084 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
michael@0 2085 {JSGC_ALLOCATION_THRESHOLD, 30},
michael@0 2086 {JSGC_DECOMMIT_THRESHOLD, 32},
michael@0 2087 {JSGC_MODE, JSGC_MODE_COMPARTMENT}
michael@0 2088 };
michael@0 2089
michael@0 2090 config = nominal;
michael@0 2091 }
michael@0 2092
michael@0 2093 for (size_t i = 0; i < NumGCConfigs; i++)
michael@0 2094 JS_SetGCParameter(rt, config[i].key, config[i].value);
michael@0 2095 }
michael@0 2096
michael@0 2097
michael@0 2098 JS_PUBLIC_API(JSString *)
michael@0 2099 JS_NewExternalString(JSContext *cx, const jschar *chars, size_t length,
michael@0 2100 const JSStringFinalizer *fin)
michael@0 2101 {
michael@0 2102 AssertHeapIsIdle(cx);
michael@0 2103 CHECK_REQUEST(cx);
michael@0 2104 JSString *s = JSExternalString::new_(cx, chars, length, fin);
michael@0 2105 return s;
michael@0 2106 }
michael@0 2107
michael@0 2108 extern JS_PUBLIC_API(bool)
michael@0 2109 JS_IsExternalString(JSString *str)
michael@0 2110 {
michael@0 2111 return str->isExternal();
michael@0 2112 }
michael@0 2113
michael@0 2114 extern JS_PUBLIC_API(const JSStringFinalizer *)
michael@0 2115 JS_GetExternalStringFinalizer(JSString *str)
michael@0 2116 {
michael@0 2117 return str->asExternal().externalFinalizer();
michael@0 2118 }
michael@0 2119
michael@0 2120 static void
michael@0 2121 SetNativeStackQuota(JSRuntime *rt, StackKind kind, size_t stackSize)
michael@0 2122 {
michael@0 2123 rt->nativeStackQuota[kind] = stackSize;
michael@0 2124 if (rt->nativeStackBase)
michael@0 2125 RecomputeStackLimit(rt, kind);
michael@0 2126 }
michael@0 2127
michael@0 2128 void
michael@0 2129 js::RecomputeStackLimit(JSRuntime *rt, StackKind kind)
michael@0 2130 {
michael@0 2131 size_t stackSize = rt->nativeStackQuota[kind];
michael@0 2132 #if JS_STACK_GROWTH_DIRECTION > 0
michael@0 2133 if (stackSize == 0) {
michael@0 2134 rt->mainThread.nativeStackLimit[kind] = UINTPTR_MAX;
michael@0 2135 } else {
michael@0 2136 JS_ASSERT(rt->nativeStackBase <= size_t(-1) - stackSize);
michael@0 2137 rt->mainThread.nativeStackLimit[kind] =
michael@0 2138 rt->nativeStackBase + stackSize - 1;
michael@0 2139 }
michael@0 2140 #else
michael@0 2141 if (stackSize == 0) {
michael@0 2142 rt->mainThread.nativeStackLimit[kind] = 0;
michael@0 2143 } else {
michael@0 2144 JS_ASSERT(rt->nativeStackBase >= stackSize);
michael@0 2145 rt->mainThread.nativeStackLimit[kind] =
michael@0 2146 rt->nativeStackBase - (stackSize - 1);
michael@0 2147 }
michael@0 2148 #endif
michael@0 2149
michael@0 2150 // If there's no pending interrupt request set on the runtime's main thread's
michael@0 2151 // jitStackLimit, then update it so that it reflects the new nativeStacklimit.
michael@0 2152 //
michael@0 2153 // Note that, for now, we use the untrusted limit for ion. This is fine,
michael@0 2154 // because it's the most conservative limit, and if we hit it, we'll bail
michael@0 2155 // out of ion into the interpeter, which will do a proper recursion check.
michael@0 2156 #ifdef JS_ION
michael@0 2157 if (kind == StackForUntrustedScript) {
michael@0 2158 JSRuntime::AutoLockForInterrupt lock(rt);
michael@0 2159 if (rt->mainThread.jitStackLimit != uintptr_t(-1)) {
michael@0 2160 rt->mainThread.jitStackLimit = rt->mainThread.nativeStackLimit[kind];
michael@0 2161 #ifdef JS_ARM_SIMULATOR
michael@0 2162 rt->mainThread.jitStackLimit = jit::Simulator::StackLimit();
michael@0 2163 #endif
michael@0 2164 }
michael@0 2165 }
michael@0 2166 #endif
michael@0 2167 }
michael@0 2168
michael@0 2169 JS_PUBLIC_API(void)
michael@0 2170 JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize,
michael@0 2171 size_t trustedScriptStackSize,
michael@0 2172 size_t untrustedScriptStackSize)
michael@0 2173 {
michael@0 2174 JS_ASSERT_IF(trustedScriptStackSize,
michael@0 2175 trustedScriptStackSize < systemCodeStackSize);
michael@0 2176 if (!trustedScriptStackSize)
michael@0 2177 trustedScriptStackSize = systemCodeStackSize;
michael@0 2178 JS_ASSERT_IF(untrustedScriptStackSize,
michael@0 2179 untrustedScriptStackSize < trustedScriptStackSize);
michael@0 2180 if (!untrustedScriptStackSize)
michael@0 2181 untrustedScriptStackSize = trustedScriptStackSize;
michael@0 2182 SetNativeStackQuota(rt, StackForSystemCode, systemCodeStackSize);
michael@0 2183 SetNativeStackQuota(rt, StackForTrustedScript, trustedScriptStackSize);
michael@0 2184 SetNativeStackQuota(rt, StackForUntrustedScript, untrustedScriptStackSize);
michael@0 2185 }
michael@0 2186
michael@0 2187 /************************************************************************/
michael@0 2188
michael@0 2189 JS_PUBLIC_API(int)
michael@0 2190 JS_IdArrayLength(JSContext *cx, JSIdArray *ida)
michael@0 2191 {
michael@0 2192 return ida->length;
michael@0 2193 }
michael@0 2194
michael@0 2195 JS_PUBLIC_API(jsid)
michael@0 2196 JS_IdArrayGet(JSContext *cx, JSIdArray *ida, int index)
michael@0 2197 {
michael@0 2198 JS_ASSERT(index >= 0 && index < ida->length);
michael@0 2199 return ida->vector[index];
michael@0 2200 }
michael@0 2201
michael@0 2202 JS_PUBLIC_API(void)
michael@0 2203 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
michael@0 2204 {
michael@0 2205 cx->runtime()->defaultFreeOp()->free_(ida);
michael@0 2206 }
michael@0 2207
michael@0 2208 JS_PUBLIC_API(bool)
michael@0 2209 JS_ValueToId(JSContext *cx, HandleValue value, MutableHandleId idp)
michael@0 2210 {
michael@0 2211 AssertHeapIsIdle(cx);
michael@0 2212 CHECK_REQUEST(cx);
michael@0 2213 assertSameCompartment(cx, value);
michael@0 2214 return ValueToId<CanGC>(cx, value, idp);
michael@0 2215 }
michael@0 2216
michael@0 2217 JS_PUBLIC_API(bool)
michael@0 2218 JS_StringToId(JSContext *cx, HandleString string, MutableHandleId idp)
michael@0 2219 {
michael@0 2220 AssertHeapIsIdle(cx);
michael@0 2221 CHECK_REQUEST(cx);
michael@0 2222 assertSameCompartment(cx, string);
michael@0 2223 RootedValue value(cx, StringValue(string));
michael@0 2224 return ValueToId<CanGC>(cx, value, idp);
michael@0 2225 }
michael@0 2226
michael@0 2227 JS_PUBLIC_API(bool)
michael@0 2228 JS_IdToValue(JSContext *cx, jsid id, MutableHandleValue vp)
michael@0 2229 {
michael@0 2230 AssertHeapIsIdle(cx);
michael@0 2231 CHECK_REQUEST(cx);
michael@0 2232 vp.set(IdToValue(id));
michael@0 2233 assertSameCompartment(cx, vp);
michael@0 2234 return true;
michael@0 2235 }
michael@0 2236
michael@0 2237 JS_PUBLIC_API(bool)
michael@0 2238 JS_DefaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp)
michael@0 2239 {
michael@0 2240 AssertHeapIsIdle(cx);
michael@0 2241 CHECK_REQUEST(cx);
michael@0 2242 JS_ASSERT(obj != nullptr);
michael@0 2243 JS_ASSERT(hint == JSTYPE_VOID || hint == JSTYPE_STRING || hint == JSTYPE_NUMBER);
michael@0 2244 return JSObject::defaultValue(cx, obj, hint, vp);
michael@0 2245 }
michael@0 2246
michael@0 2247 JS_PUBLIC_API(bool)
michael@0 2248 JS_PropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
michael@0 2249 {
michael@0 2250 return true;
michael@0 2251 }
michael@0 2252
michael@0 2253 JS_PUBLIC_API(bool)
michael@0 2254 JS_StrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
michael@0 2255 {
michael@0 2256 return true;
michael@0 2257 }
michael@0 2258
michael@0 2259 JS_PUBLIC_API(bool)
michael@0 2260 JS_DeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded)
michael@0 2261 {
michael@0 2262 *succeeded = true;
michael@0 2263 return true;
michael@0 2264 }
michael@0 2265
michael@0 2266 JS_PUBLIC_API(bool)
michael@0 2267 JS_EnumerateStub(JSContext *cx, HandleObject obj)
michael@0 2268 {
michael@0 2269 return true;
michael@0 2270 }
michael@0 2271
michael@0 2272 JS_PUBLIC_API(bool)
michael@0 2273 JS_ResolveStub(JSContext *cx, HandleObject obj, HandleId id)
michael@0 2274 {
michael@0 2275 return true;
michael@0 2276 }
michael@0 2277
michael@0 2278 JS_PUBLIC_API(bool)
michael@0 2279 JS_ConvertStub(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp)
michael@0 2280 {
michael@0 2281 JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
michael@0 2282 JS_ASSERT(obj);
michael@0 2283 return DefaultValue(cx, obj, type, vp);
michael@0 2284 }
michael@0 2285
michael@0 2286 JS_PUBLIC_API(JSObject *)
michael@0 2287 JS_InitClass(JSContext *cx, HandleObject obj, HandleObject parent_proto,
michael@0 2288 const JSClass *clasp, JSNative constructor, unsigned nargs,
michael@0 2289 const JSPropertySpec *ps, const JSFunctionSpec *fs,
michael@0 2290 const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs)
michael@0 2291 {
michael@0 2292 AssertHeapIsIdle(cx);
michael@0 2293 CHECK_REQUEST(cx);
michael@0 2294 assertSameCompartment(cx, obj, parent_proto);
michael@0 2295 return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor,
michael@0 2296 nargs, ps, fs, static_ps, static_fs);
michael@0 2297 }
michael@0 2298
michael@0 2299 JS_PUBLIC_API(bool)
michael@0 2300 JS_LinkConstructorAndPrototype(JSContext *cx, HandleObject ctor, HandleObject proto)
michael@0 2301 {
michael@0 2302 return LinkConstructorAndPrototype(cx, ctor, proto);
michael@0 2303 }
michael@0 2304
michael@0 2305 JS_PUBLIC_API(const JSClass *)
michael@0 2306 JS_GetClass(JSObject *obj)
michael@0 2307 {
michael@0 2308 return obj->getJSClass();
michael@0 2309 }
michael@0 2310
michael@0 2311 JS_PUBLIC_API(bool)
michael@0 2312 JS_InstanceOf(JSContext *cx, HandleObject obj, const JSClass *clasp, CallArgs *args)
michael@0 2313 {
michael@0 2314 AssertHeapIsIdle(cx);
michael@0 2315 CHECK_REQUEST(cx);
michael@0 2316 #ifdef DEBUG
michael@0 2317 if (args) {
michael@0 2318 assertSameCompartment(cx, obj);
michael@0 2319 assertSameCompartment(cx, args->thisv(), args->calleev());
michael@0 2320 }
michael@0 2321 #endif
michael@0 2322 if (!obj || obj->getJSClass() != clasp) {
michael@0 2323 if (args)
michael@0 2324 ReportIncompatibleMethod(cx, *args, Valueify(clasp));
michael@0 2325 return false;
michael@0 2326 }
michael@0 2327 return true;
michael@0 2328 }
michael@0 2329
michael@0 2330 JS_PUBLIC_API(bool)
michael@0 2331 JS_HasInstance(JSContext *cx, HandleObject obj, HandleValue value, bool *bp)
michael@0 2332 {
michael@0 2333 AssertHeapIsIdle(cx);
michael@0 2334 assertSameCompartment(cx, obj, value);
michael@0 2335 return HasInstance(cx, obj, value, bp);
michael@0 2336 }
michael@0 2337
michael@0 2338 JS_PUBLIC_API(void *)
michael@0 2339 JS_GetPrivate(JSObject *obj)
michael@0 2340 {
michael@0 2341 /* This function can be called by a finalizer. */
michael@0 2342 return obj->getPrivate();
michael@0 2343 }
michael@0 2344
michael@0 2345 JS_PUBLIC_API(void)
michael@0 2346 JS_SetPrivate(JSObject *obj, void *data)
michael@0 2347 {
michael@0 2348 /* This function can be called by a finalizer. */
michael@0 2349 obj->setPrivate(data);
michael@0 2350 }
michael@0 2351
michael@0 2352 JS_PUBLIC_API(void *)
michael@0 2353 JS_GetInstancePrivate(JSContext *cx, HandleObject obj, const JSClass *clasp, CallArgs *args)
michael@0 2354 {
michael@0 2355 if (!JS_InstanceOf(cx, obj, clasp, args))
michael@0 2356 return nullptr;
michael@0 2357 return obj->getPrivate();
michael@0 2358 }
michael@0 2359
michael@0 2360 JS_PUBLIC_API(bool)
michael@0 2361 JS_GetPrototype(JSContext *cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JSObject*> protop)
michael@0 2362 {
michael@0 2363 return JSObject::getProto(cx, obj, protop);
michael@0 2364 }
michael@0 2365
michael@0 2366 JS_PUBLIC_API(bool)
michael@0 2367 JS_SetPrototype(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> proto)
michael@0 2368 {
michael@0 2369 AssertHeapIsIdle(cx);
michael@0 2370 CHECK_REQUEST(cx);
michael@0 2371 assertSameCompartment(cx, obj, proto);
michael@0 2372
michael@0 2373 bool succeeded;
michael@0 2374 if (!JSObject::setProto(cx, obj, proto, &succeeded))
michael@0 2375 return false;
michael@0 2376
michael@0 2377 if (!succeeded) {
michael@0 2378 RootedValue val(cx, ObjectValue(*obj));
michael@0 2379 js_ReportValueError(cx, JSMSG_SETPROTOTYPEOF_FAIL, JSDVG_IGNORE_STACK, val, js::NullPtr());
michael@0 2380 return false;
michael@0 2381 }
michael@0 2382
michael@0 2383 return true;
michael@0 2384 }
michael@0 2385
michael@0 2386 JS_PUBLIC_API(JSObject *)
michael@0 2387 JS_GetParent(JSObject *obj)
michael@0 2388 {
michael@0 2389 JS_ASSERT(!obj->is<ScopeObject>());
michael@0 2390 return obj->getParent();
michael@0 2391 }
michael@0 2392
michael@0 2393 JS_PUBLIC_API(bool)
michael@0 2394 JS_SetParent(JSContext *cx, HandleObject obj, HandleObject parent)
michael@0 2395 {
michael@0 2396 AssertHeapIsIdle(cx);
michael@0 2397 CHECK_REQUEST(cx);
michael@0 2398 JS_ASSERT(!obj->is<ScopeObject>());
michael@0 2399 JS_ASSERT(parent || !obj->getParent());
michael@0 2400 assertSameCompartment(cx, obj, parent);
michael@0 2401
michael@0 2402 return JSObject::setParent(cx, obj, parent);
michael@0 2403 }
michael@0 2404
michael@0 2405 JS_PUBLIC_API(JSObject *)
michael@0 2406 JS_GetConstructor(JSContext *cx, HandleObject proto)
michael@0 2407 {
michael@0 2408 AssertHeapIsIdle(cx);
michael@0 2409 CHECK_REQUEST(cx);
michael@0 2410 assertSameCompartment(cx, proto);
michael@0 2411
michael@0 2412 RootedValue cval(cx);
michael@0 2413 if (!JSObject::getProperty(cx, proto, proto, cx->names().constructor, &cval))
michael@0 2414 return nullptr;
michael@0 2415 if (!IsFunctionObject(cval)) {
michael@0 2416 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
michael@0 2417 proto->getClass()->name);
michael@0 2418 return nullptr;
michael@0 2419 }
michael@0 2420 return &cval.toObject();
michael@0 2421 }
michael@0 2422
michael@0 2423 namespace {
michael@0 2424
michael@0 2425 class AutoCompartmentRooter : private JS::CustomAutoRooter
michael@0 2426 {
michael@0 2427 public:
michael@0 2428 explicit AutoCompartmentRooter(JSContext *cx, JSCompartment *comp
michael@0 2429 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 2430 : CustomAutoRooter(cx), compartment(comp)
michael@0 2431 {
michael@0 2432 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 2433 }
michael@0 2434
michael@0 2435 operator JSCompartment *() {
michael@0 2436 return compartment;
michael@0 2437 }
michael@0 2438
michael@0 2439 JSCompartment *operator->() {
michael@0 2440 return compartment;
michael@0 2441 }
michael@0 2442
michael@0 2443 protected:
michael@0 2444 virtual void trace(JSTracer *trc)
michael@0 2445 {
michael@0 2446 compartment->mark();
michael@0 2447 }
michael@0 2448
michael@0 2449 private:
michael@0 2450 JSCompartment *compartment;
michael@0 2451 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
michael@0 2452 };
michael@0 2453
michael@0 2454 } /* anonymous namespace */
michael@0 2455
michael@0 2456 bool
michael@0 2457 JS::CompartmentOptions::cloneSingletons(JSContext *cx) const
michael@0 2458 {
michael@0 2459 return cloneSingletonsOverride_.get(cx->options().cloneSingletons());
michael@0 2460 }
michael@0 2461
michael@0 2462 JS::CompartmentOptions &
michael@0 2463 JS::CompartmentOptions::setZone(ZoneSpecifier spec)
michael@0 2464 {
michael@0 2465 zone_.spec = spec;
michael@0 2466 return *this;
michael@0 2467 }
michael@0 2468
michael@0 2469 JS::CompartmentOptions &
michael@0 2470 JS::CompartmentOptions::setSameZoneAs(JSObject *obj)
michael@0 2471 {
michael@0 2472 zone_.pointer = static_cast<void *>(obj->zone());
michael@0 2473 return *this;
michael@0 2474 }
michael@0 2475
michael@0 2476 JS::CompartmentOptions &
michael@0 2477 JS::CompartmentOptionsRef(JSCompartment *compartment)
michael@0 2478 {
michael@0 2479 return compartment->options();
michael@0 2480 }
michael@0 2481
michael@0 2482 JS::CompartmentOptions &
michael@0 2483 JS::CompartmentOptionsRef(JSObject *obj)
michael@0 2484 {
michael@0 2485 return obj->compartment()->options();
michael@0 2486 }
michael@0 2487
michael@0 2488 JS::CompartmentOptions &
michael@0 2489 JS::CompartmentOptionsRef(JSContext *cx)
michael@0 2490 {
michael@0 2491 return cx->compartment()->options();
michael@0 2492 }
michael@0 2493
michael@0 2494 JS_PUBLIC_API(JSObject *)
michael@0 2495 JS_NewGlobalObject(JSContext *cx, const JSClass *clasp, JSPrincipals *principals,
michael@0 2496 JS::OnNewGlobalHookOption hookOption,
michael@0 2497 const JS::CompartmentOptions &options /* = JS::CompartmentOptions() */)
michael@0 2498 {
michael@0 2499 AssertHeapIsIdle(cx);
michael@0 2500 CHECK_REQUEST(cx);
michael@0 2501 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 2502 JS_ASSERT(!cx->isExceptionPending());
michael@0 2503
michael@0 2504 JSRuntime *rt = cx->runtime();
michael@0 2505
michael@0 2506 Zone *zone;
michael@0 2507 if (options.zoneSpecifier() == JS::SystemZone)
michael@0 2508 zone = rt->systemZone;
michael@0 2509 else if (options.zoneSpecifier() == JS::FreshZone)
michael@0 2510 zone = nullptr;
michael@0 2511 else
michael@0 2512 zone = static_cast<Zone *>(options.zonePointer());
michael@0 2513
michael@0 2514 AutoCompartmentRooter compartment(cx, NewCompartment(cx, zone, principals, options));
michael@0 2515 if (!compartment)
michael@0 2516 return nullptr;
michael@0 2517
michael@0 2518 // Lazily create the system zone.
michael@0 2519 if (!rt->systemZone && options.zoneSpecifier() == JS::SystemZone) {
michael@0 2520 rt->systemZone = compartment->zone();
michael@0 2521 rt->systemZone->isSystem = true;
michael@0 2522 }
michael@0 2523
michael@0 2524 Rooted<GlobalObject *> global(cx);
michael@0 2525 {
michael@0 2526 AutoCompartment ac(cx, compartment);
michael@0 2527 global = GlobalObject::create(cx, Valueify(clasp));
michael@0 2528 }
michael@0 2529
michael@0 2530 if (!global)
michael@0 2531 return nullptr;
michael@0 2532
michael@0 2533 if (hookOption == JS::FireOnNewGlobalHook)
michael@0 2534 JS_FireOnNewGlobalObject(cx, global);
michael@0 2535
michael@0 2536 return global;
michael@0 2537 }
michael@0 2538
michael@0 2539 JS_PUBLIC_API(void)
michael@0 2540 JS_GlobalObjectTraceHook(JSTracer *trc, JSObject *global)
michael@0 2541 {
michael@0 2542 JS_ASSERT(global->is<GlobalObject>());
michael@0 2543
michael@0 2544 // Off thread parsing and compilation tasks create a dummy global which is then
michael@0 2545 // merged back into the host compartment. Since it used to be a global, it will still
michael@0 2546 // have this trace hook, but it does not have a meaning relative to its new compartment.
michael@0 2547 // We can safely skip it.
michael@0 2548 if (!global->isOwnGlobal())
michael@0 2549 return;
michael@0 2550
michael@0 2551 // Trace the compartment for any GC things that should only stick around if we know the
michael@0 2552 // compartment is live.
michael@0 2553 global->compartment()->trace(trc);
michael@0 2554
michael@0 2555 JSTraceOp trace = global->compartment()->options().getTrace();
michael@0 2556 if (trace)
michael@0 2557 trace(trc, global);
michael@0 2558 }
michael@0 2559
michael@0 2560 JS_PUBLIC_API(void)
michael@0 2561 JS_FireOnNewGlobalObject(JSContext *cx, JS::HandleObject global)
michael@0 2562 {
michael@0 2563 // This hook is infallible, because we don't really want arbitrary script
michael@0 2564 // to be able to throw errors during delicate global creation routines.
michael@0 2565 // This infallibility will eat OOM and slow script, but if that happens
michael@0 2566 // we'll likely run up into them again soon in a fallible context.
michael@0 2567 Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>());
michael@0 2568 Debugger::onNewGlobalObject(cx, globalObject);
michael@0 2569 }
michael@0 2570
michael@0 2571 JS_PUBLIC_API(JSObject *)
michael@0 2572 JS_NewObject(JSContext *cx, const JSClass *jsclasp, HandleObject proto, HandleObject parent)
michael@0 2573 {
michael@0 2574 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 2575 AssertHeapIsIdle(cx);
michael@0 2576 CHECK_REQUEST(cx);
michael@0 2577 assertSameCompartment(cx, proto, parent);
michael@0 2578
michael@0 2579 const Class *clasp = Valueify(jsclasp);
michael@0 2580 if (!clasp)
michael@0 2581 clasp = &JSObject::class_; /* default class is Object */
michael@0 2582
michael@0 2583 JS_ASSERT(clasp != &JSFunction::class_);
michael@0 2584 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
michael@0 2585
michael@0 2586 JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, parent);
michael@0 2587 JS_ASSERT_IF(obj, obj->getParent());
michael@0 2588 return obj;
michael@0 2589 }
michael@0 2590
michael@0 2591 JS_PUBLIC_API(JSObject *)
michael@0 2592 JS_NewObjectWithGivenProto(JSContext *cx, const JSClass *jsclasp, HandleObject proto, HandleObject parent)
michael@0 2593 {
michael@0 2594 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 2595 AssertHeapIsIdle(cx);
michael@0 2596 CHECK_REQUEST(cx);
michael@0 2597 assertSameCompartment(cx, proto, parent);
michael@0 2598
michael@0 2599 const Class *clasp = Valueify(jsclasp);
michael@0 2600 if (!clasp)
michael@0 2601 clasp = &JSObject::class_; /* default class is Object */
michael@0 2602
michael@0 2603 JS_ASSERT(clasp != &JSFunction::class_);
michael@0 2604 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
michael@0 2605
michael@0 2606 JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
michael@0 2607 if (obj)
michael@0 2608 MarkTypeObjectUnknownProperties(cx, obj->type());
michael@0 2609 return obj;
michael@0 2610 }
michael@0 2611
michael@0 2612 JS_PUBLIC_API(JSObject *)
michael@0 2613 JS_NewObjectForConstructor(JSContext *cx, const JSClass *clasp, const CallArgs& args)
michael@0 2614 {
michael@0 2615 AssertHeapIsIdle(cx);
michael@0 2616 CHECK_REQUEST(cx);
michael@0 2617
michael@0 2618 Value callee = args.calleev();
michael@0 2619 assertSameCompartment(cx, callee);
michael@0 2620 RootedObject obj(cx, &callee.toObject());
michael@0 2621 return CreateThis(cx, Valueify(clasp), obj);
michael@0 2622 }
michael@0 2623
michael@0 2624 JS_PUBLIC_API(bool)
michael@0 2625 JS_IsExtensible(JSContext *cx, HandleObject obj, bool *extensible)
michael@0 2626 {
michael@0 2627 return JSObject::isExtensible(cx, obj, extensible);
michael@0 2628 }
michael@0 2629
michael@0 2630 JS_PUBLIC_API(bool)
michael@0 2631 JS_IsNative(JSObject *obj)
michael@0 2632 {
michael@0 2633 return obj->isNative();
michael@0 2634 }
michael@0 2635
michael@0 2636 JS_PUBLIC_API(JSRuntime *)
michael@0 2637 JS_GetObjectRuntime(JSObject *obj)
michael@0 2638 {
michael@0 2639 return obj->compartment()->runtimeFromMainThread();
michael@0 2640 }
michael@0 2641
michael@0 2642 JS_PUBLIC_API(bool)
michael@0 2643 JS_FreezeObject(JSContext *cx, HandleObject obj)
michael@0 2644 {
michael@0 2645 AssertHeapIsIdle(cx);
michael@0 2646 CHECK_REQUEST(cx);
michael@0 2647 assertSameCompartment(cx, obj);
michael@0 2648 return JSObject::freeze(cx, obj);
michael@0 2649 }
michael@0 2650
michael@0 2651 JS_PUBLIC_API(bool)
michael@0 2652 JS_DeepFreezeObject(JSContext *cx, HandleObject obj)
michael@0 2653 {
michael@0 2654 AssertHeapIsIdle(cx);
michael@0 2655 CHECK_REQUEST(cx);
michael@0 2656 assertSameCompartment(cx, obj);
michael@0 2657
michael@0 2658 /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
michael@0 2659 bool extensible;
michael@0 2660 if (!JSObject::isExtensible(cx, obj, &extensible))
michael@0 2661 return false;
michael@0 2662 if (!extensible)
michael@0 2663 return true;
michael@0 2664
michael@0 2665 if (!JSObject::freeze(cx, obj))
michael@0 2666 return false;
michael@0 2667
michael@0 2668 /* Walk slots in obj and if any value is a non-null object, seal it. */
michael@0 2669 for (uint32_t i = 0, n = obj->slotSpan(); i < n; ++i) {
michael@0 2670 const Value &v = obj->getSlot(i);
michael@0 2671 if (v.isPrimitive())
michael@0 2672 continue;
michael@0 2673 RootedObject obj(cx, &v.toObject());
michael@0 2674 if (!JS_DeepFreezeObject(cx, obj))
michael@0 2675 return false;
michael@0 2676 }
michael@0 2677
michael@0 2678 return true;
michael@0 2679 }
michael@0 2680
michael@0 2681 static bool
michael@0 2682 LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id,
michael@0 2683 MutableHandleObject objp, MutableHandleShape propp)
michael@0 2684 {
michael@0 2685 AssertHeapIsIdle(cx);
michael@0 2686 CHECK_REQUEST(cx);
michael@0 2687 assertSameCompartment(cx, obj, id);
michael@0 2688
michael@0 2689 return JSObject::lookupGeneric(cx, obj, id, objp, propp);
michael@0 2690 }
michael@0 2691
michael@0 2692 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
michael@0 2693
michael@0 2694 static bool
michael@0 2695 LookupResult(JSContext *cx, HandleObject obj, HandleObject obj2, HandleId id,
michael@0 2696 HandleShape shape, MutableHandleValue vp)
michael@0 2697 {
michael@0 2698 if (!shape) {
michael@0 2699 /* XXX bad API: no way to tell "not defined" from "void value" */
michael@0 2700 vp.setUndefined();
michael@0 2701 return true;
michael@0 2702 }
michael@0 2703
michael@0 2704 if (!obj2->isNative()) {
michael@0 2705 if (obj2->is<ProxyObject>()) {
michael@0 2706 Rooted<PropertyDescriptor> desc(cx);
michael@0 2707 if (!Proxy::getPropertyDescriptor(cx, obj2, id, &desc))
michael@0 2708 return false;
michael@0 2709 if (!desc.isShared()) {
michael@0 2710 vp.set(desc.value());
michael@0 2711 return true;
michael@0 2712 }
michael@0 2713 }
michael@0 2714 } else if (IsImplicitDenseOrTypedArrayElement(shape)) {
michael@0 2715 vp.set(obj2->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
michael@0 2716 return true;
michael@0 2717 } else {
michael@0 2718 /* Peek at the native property's slot value, without doing a Get. */
michael@0 2719 if (shape->hasSlot()) {
michael@0 2720 vp.set(obj2->nativeGetSlot(shape->slot()));
michael@0 2721 return true;
michael@0 2722 }
michael@0 2723 }
michael@0 2724
michael@0 2725 /* XXX bad API: no way to return "defined but value unknown" */
michael@0 2726 vp.setBoolean(true);
michael@0 2727 return true;
michael@0 2728 }
michael@0 2729
michael@0 2730 JS_PUBLIC_API(bool)
michael@0 2731 JS_LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
michael@0 2732 {
michael@0 2733 RootedObject obj2(cx);
michael@0 2734 RootedShape prop(cx);
michael@0 2735
michael@0 2736 return LookupPropertyById(cx, obj, id, &obj2, &prop) &&
michael@0 2737 LookupResult(cx, obj, obj2, id, prop, vp);
michael@0 2738 }
michael@0 2739
michael@0 2740 JS_PUBLIC_API(bool)
michael@0 2741 JS_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
michael@0 2742 {
michael@0 2743 CHECK_REQUEST(cx);
michael@0 2744 RootedId id(cx);
michael@0 2745 if (!IndexToId(cx, index, &id))
michael@0 2746 return false;
michael@0 2747 return JS_LookupPropertyById(cx, obj, id, vp);
michael@0 2748 }
michael@0 2749
michael@0 2750 JS_PUBLIC_API(bool)
michael@0 2751 JS_LookupProperty(JSContext *cx, HandleObject objArg, const char *name, MutableHandleValue vp)
michael@0 2752 {
michael@0 2753 RootedObject obj(cx, objArg);
michael@0 2754 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 2755 if (!atom)
michael@0 2756 return false;
michael@0 2757
michael@0 2758 RootedId id(cx, AtomToId(atom));
michael@0 2759 return JS_LookupPropertyById(cx, obj, id, vp);
michael@0 2760 }
michael@0 2761
michael@0 2762 JS_PUBLIC_API(bool)
michael@0 2763 JS_LookupUCProperty(JSContext *cx, HandleObject objArg, const jschar *name, size_t namelen,
michael@0 2764 MutableHandleValue vp)
michael@0 2765 {
michael@0 2766 RootedObject obj(cx, objArg);
michael@0 2767 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
michael@0 2768 if (!atom)
michael@0 2769 return false;
michael@0 2770
michael@0 2771 RootedId id(cx, AtomToId(atom));
michael@0 2772 return JS_LookupPropertyById(cx, obj, id, vp);
michael@0 2773 }
michael@0 2774
michael@0 2775 JS_PUBLIC_API(bool)
michael@0 2776 JS_HasPropertyById(JSContext *cx, HandleObject obj, HandleId id, bool *foundp)
michael@0 2777 {
michael@0 2778 RootedObject obj2(cx);
michael@0 2779 RootedShape prop(cx);
michael@0 2780 bool ok = LookupPropertyById(cx, obj, id, &obj2, &prop);
michael@0 2781 *foundp = (prop != nullptr);
michael@0 2782 return ok;
michael@0 2783 }
michael@0 2784
michael@0 2785 JS_PUBLIC_API(bool)
michael@0 2786 JS_HasElement(JSContext *cx, HandleObject obj, uint32_t index, bool *foundp)
michael@0 2787 {
michael@0 2788 AssertHeapIsIdle(cx);
michael@0 2789 CHECK_REQUEST(cx);
michael@0 2790 RootedId id(cx);
michael@0 2791 if (!IndexToId(cx, index, &id))
michael@0 2792 return false;
michael@0 2793 return JS_HasPropertyById(cx, obj, id, foundp);
michael@0 2794 }
michael@0 2795
michael@0 2796 JS_PUBLIC_API(bool)
michael@0 2797 JS_HasProperty(JSContext *cx, HandleObject obj, const char *name, bool *foundp)
michael@0 2798 {
michael@0 2799 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 2800 if (!atom)
michael@0 2801 return false;
michael@0 2802 RootedId id(cx, AtomToId(atom));
michael@0 2803 return JS_HasPropertyById(cx, obj, id, foundp);
michael@0 2804 }
michael@0 2805
michael@0 2806 JS_PUBLIC_API(bool)
michael@0 2807 JS_HasUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, bool *foundp)
michael@0 2808 {
michael@0 2809 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
michael@0 2810 if (!atom)
michael@0 2811 return false;
michael@0 2812 RootedId id(cx, AtomToId(atom));
michael@0 2813 return JS_HasPropertyById(cx, obj, id, foundp);
michael@0 2814 }
michael@0 2815
michael@0 2816 JS_PUBLIC_API(bool)
michael@0 2817 JS_AlreadyHasOwnPropertyById(JSContext *cx, HandleObject obj, HandleId id, bool *foundp)
michael@0 2818 {
michael@0 2819 AssertHeapIsIdle(cx);
michael@0 2820 CHECK_REQUEST(cx);
michael@0 2821 assertSameCompartment(cx, obj, id);
michael@0 2822
michael@0 2823 if (!obj->isNative()) {
michael@0 2824 RootedObject obj2(cx);
michael@0 2825 RootedShape prop(cx);
michael@0 2826
michael@0 2827 if (!LookupPropertyById(cx, obj, id, &obj2, &prop))
michael@0 2828 return false;
michael@0 2829 *foundp = (obj == obj2);
michael@0 2830 return true;
michael@0 2831 }
michael@0 2832
michael@0 2833 // Check for an existing native property on the objct. Be careful not to
michael@0 2834 // call any lookup or resolve hooks.
michael@0 2835
michael@0 2836 if (JSID_IS_INT(id)) {
michael@0 2837 uint32_t index = JSID_TO_INT(id);
michael@0 2838
michael@0 2839 if (obj->containsDenseElement(index)) {
michael@0 2840 *foundp = true;
michael@0 2841 return true;
michael@0 2842 }
michael@0 2843
michael@0 2844 if (obj->is<TypedArrayObject>() && index < obj->as<TypedArrayObject>().length()) {
michael@0 2845 *foundp = true;
michael@0 2846 return true;
michael@0 2847 }
michael@0 2848 }
michael@0 2849
michael@0 2850 *foundp = obj->nativeContains(cx, id);
michael@0 2851 return true;
michael@0 2852 }
michael@0 2853
michael@0 2854 JS_PUBLIC_API(bool)
michael@0 2855 JS_AlreadyHasOwnElement(JSContext *cx, HandleObject obj, uint32_t index, bool *foundp)
michael@0 2856 {
michael@0 2857 AssertHeapIsIdle(cx);
michael@0 2858 CHECK_REQUEST(cx);
michael@0 2859 RootedId id(cx);
michael@0 2860 if (!IndexToId(cx, index, &id))
michael@0 2861 return false;
michael@0 2862 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
michael@0 2863 }
michael@0 2864
michael@0 2865 JS_PUBLIC_API(bool)
michael@0 2866 JS_AlreadyHasOwnProperty(JSContext *cx, HandleObject obj, const char *name, bool *foundp)
michael@0 2867 {
michael@0 2868 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 2869 if (!atom)
michael@0 2870 return false;
michael@0 2871 RootedId id(cx, AtomToId(atom));
michael@0 2872 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
michael@0 2873 }
michael@0 2874
michael@0 2875 JS_PUBLIC_API(bool)
michael@0 2876 JS_AlreadyHasOwnUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
michael@0 2877 bool *foundp)
michael@0 2878 {
michael@0 2879 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
michael@0 2880 if (!atom)
michael@0 2881 return false;
michael@0 2882 RootedId id(cx, AtomToId(atom));
michael@0 2883 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
michael@0 2884 }
michael@0 2885
michael@0 2886 /* Wrapper functions to create wrappers with no corresponding JSJitInfo from API
michael@0 2887 * function arguments.
michael@0 2888 */
michael@0 2889 static JSPropertyOpWrapper
michael@0 2890 GetterWrapper(JSPropertyOp getter)
michael@0 2891 {
michael@0 2892 JSPropertyOpWrapper ret;
michael@0 2893 ret.op = getter;
michael@0 2894 ret.info = nullptr;
michael@0 2895 return ret;
michael@0 2896 }
michael@0 2897
michael@0 2898 static JSStrictPropertyOpWrapper
michael@0 2899 SetterWrapper(JSStrictPropertyOp setter)
michael@0 2900 {
michael@0 2901 JSStrictPropertyOpWrapper ret;
michael@0 2902 ret.op = setter;
michael@0 2903 ret.info = nullptr;
michael@0 2904 return ret;
michael@0 2905 }
michael@0 2906
michael@0 2907 static bool
michael@0 2908 DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
michael@0 2909 const JSPropertyOpWrapper &get, const JSStrictPropertyOpWrapper &set,
michael@0 2910 unsigned attrs, unsigned flags)
michael@0 2911 {
michael@0 2912 PropertyOp getter = get.op;
michael@0 2913 StrictPropertyOp setter = set.op;
michael@0 2914 /*
michael@0 2915 * JSPROP_READONLY has no meaning when accessors are involved. Ideally we'd
michael@0 2916 * throw if this happens, but we've accepted it for long enough that it's
michael@0 2917 * not worth trying to make callers change their ways. Just flip it off on
michael@0 2918 * its way through the API layer so that we can enforce this internally.
michael@0 2919 */
michael@0 2920 if (attrs & (JSPROP_GETTER | JSPROP_SETTER))
michael@0 2921 attrs &= ~JSPROP_READONLY;
michael@0 2922
michael@0 2923 /*
michael@0 2924 * When we use DefineProperty, we need full scriptable Function objects rather
michael@0 2925 * than JSNatives. However, we might be pulling this property descriptor off
michael@0 2926 * of something with JSNative property descriptors. If we are, wrap them in
michael@0 2927 * JS Function objects.
michael@0 2928 */
michael@0 2929 if (attrs & JSPROP_NATIVE_ACCESSORS) {
michael@0 2930 JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
michael@0 2931 JSFunction::Flags zeroFlags = JSAPIToJSFunctionFlags(0);
michael@0 2932 // We can't just use JS_NewFunctionById here because it
michael@0 2933 // assumes a string id.
michael@0 2934 RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr);
michael@0 2935 attrs &= ~JSPROP_NATIVE_ACCESSORS;
michael@0 2936 if (getter) {
michael@0 2937 RootedObject global(cx, (JSObject*) &obj->global());
michael@0 2938 JSFunction *getobj = NewFunction(cx, NullPtr(), (Native) getter, 0,
michael@0 2939 zeroFlags, global, atom);
michael@0 2940 if (!getobj)
michael@0 2941 return false;
michael@0 2942
michael@0 2943 if (get.info)
michael@0 2944 getobj->setJitInfo(get.info);
michael@0 2945
michael@0 2946 getter = JS_DATA_TO_FUNC_PTR(PropertyOp, getobj);
michael@0 2947 attrs |= JSPROP_GETTER;
michael@0 2948 }
michael@0 2949 if (setter) {
michael@0 2950 // Root just the getter, since the setter is not yet a JSObject.
michael@0 2951 AutoRooterGetterSetter getRoot(cx, JSPROP_GETTER, &getter, nullptr);
michael@0 2952 RootedObject global(cx, (JSObject*) &obj->global());
michael@0 2953 JSFunction *setobj = NewFunction(cx, NullPtr(), (Native) setter, 1,
michael@0 2954 zeroFlags, global, atom);
michael@0 2955 if (!setobj)
michael@0 2956 return false;
michael@0 2957
michael@0 2958 if (set.info)
michael@0 2959 setobj->setJitInfo(set.info);
michael@0 2960
michael@0 2961 setter = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setobj);
michael@0 2962 attrs |= JSPROP_SETTER;
michael@0 2963 }
michael@0 2964 }
michael@0 2965
michael@0 2966
michael@0 2967 AssertHeapIsIdle(cx);
michael@0 2968 CHECK_REQUEST(cx);
michael@0 2969 assertSameCompartment(cx, obj, id, value,
michael@0 2970 (attrs & JSPROP_GETTER)
michael@0 2971 ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
michael@0 2972 : nullptr,
michael@0 2973 (attrs & JSPROP_SETTER)
michael@0 2974 ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
michael@0 2975 : nullptr);
michael@0 2976
michael@0 2977 return JSObject::defineGeneric(cx, obj, id, value, getter, setter, attrs);
michael@0 2978 }
michael@0 2979
michael@0 2980 JS_PUBLIC_API(bool)
michael@0 2981 JS_DefinePropertyById(JSContext *cx, JSObject *objArg, jsid idArg, jsval valueArg,
michael@0 2982 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
michael@0 2983 {
michael@0 2984 RootedObject obj(cx, objArg);
michael@0 2985 RootedId id(cx, idArg);
michael@0 2986 RootedValue value(cx, valueArg);
michael@0 2987 return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter),
michael@0 2988 attrs, 0);
michael@0 2989 }
michael@0 2990
michael@0 2991 JS_PUBLIC_API(bool)
michael@0 2992 JS_DefineElement(JSContext *cx, JSObject *objArg, uint32_t index, jsval valueArg,
michael@0 2993 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
michael@0 2994 {
michael@0 2995 RootedObject obj(cx, objArg);
michael@0 2996 RootedValue value(cx, valueArg);
michael@0 2997 AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
michael@0 2998 AssertHeapIsIdle(cx);
michael@0 2999 CHECK_REQUEST(cx);
michael@0 3000 RootedId id(cx);
michael@0 3001 if (!IndexToId(cx, index, &id))
michael@0 3002 return false;
michael@0 3003 return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter),
michael@0 3004 attrs, 0);
michael@0 3005 }
michael@0 3006
michael@0 3007 static bool
michael@0 3008 DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue value,
michael@0 3009 const JSPropertyOpWrapper &getter, const JSStrictPropertyOpWrapper &setter,
michael@0 3010 unsigned attrs, unsigned flags)
michael@0 3011 {
michael@0 3012 AutoRooterGetterSetter gsRoot(cx, attrs, const_cast<JSPropertyOp *>(&getter.op),
michael@0 3013 const_cast<JSStrictPropertyOp *>(&setter.op));
michael@0 3014
michael@0 3015 RootedId id(cx);
michael@0 3016 if (attrs & JSPROP_INDEX) {
michael@0 3017 id.set(INT_TO_JSID(intptr_t(name)));
michael@0 3018 attrs &= ~JSPROP_INDEX;
michael@0 3019 } else {
michael@0 3020 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 3021 if (!atom)
michael@0 3022 return false;
michael@0 3023 id = AtomToId(atom);
michael@0 3024 }
michael@0 3025
michael@0 3026 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags);
michael@0 3027 }
michael@0 3028
michael@0 3029
michael@0 3030 static bool
michael@0 3031 DefineSelfHostedProperty(JSContext *cx,
michael@0 3032 HandleObject obj,
michael@0 3033 const char *name,
michael@0 3034 const char *getterName,
michael@0 3035 const char *setterName,
michael@0 3036 unsigned attrs,
michael@0 3037 unsigned flags)
michael@0 3038 {
michael@0 3039 RootedAtom nameAtom(cx, Atomize(cx, name, strlen(name)));
michael@0 3040 if (!nameAtom)
michael@0 3041 return false;
michael@0 3042
michael@0 3043 RootedAtom getterNameAtom(cx, Atomize(cx, getterName, strlen(getterName)));
michael@0 3044 if (!getterNameAtom)
michael@0 3045 return false;
michael@0 3046
michael@0 3047 RootedValue getterValue(cx);
michael@0 3048 if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, nameAtom,
michael@0 3049 0, &getterValue))
michael@0 3050 {
michael@0 3051 return false;
michael@0 3052 }
michael@0 3053 JS_ASSERT(getterValue.isObject() && getterValue.toObject().is<JSFunction>());
michael@0 3054 RootedFunction getterFunc(cx, &getterValue.toObject().as<JSFunction>());
michael@0 3055 JSPropertyOp getterOp = JS_DATA_TO_FUNC_PTR(PropertyOp, getterFunc.get());
michael@0 3056
michael@0 3057 RootedFunction setterFunc(cx);
michael@0 3058 if (setterName) {
michael@0 3059 RootedAtom setterNameAtom(cx, Atomize(cx, setterName, strlen(setterName)));
michael@0 3060 if (!setterNameAtom)
michael@0 3061 return false;
michael@0 3062
michael@0 3063 RootedValue setterValue(cx);
michael@0 3064 if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, nameAtom,
michael@0 3065 0, &setterValue))
michael@0 3066 {
michael@0 3067 return false;
michael@0 3068 }
michael@0 3069 JS_ASSERT(setterValue.isObject() && setterValue.toObject().is<JSFunction>());
michael@0 3070 setterFunc = &getterValue.toObject().as<JSFunction>();
michael@0 3071 }
michael@0 3072 JSStrictPropertyOp setterOp = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setterFunc.get());
michael@0 3073
michael@0 3074 return DefineProperty(cx, obj, name, JS::UndefinedHandleValue,
michael@0 3075 GetterWrapper(getterOp), SetterWrapper(setterOp),
michael@0 3076 attrs, flags);
michael@0 3077 }
michael@0 3078
michael@0 3079 JS_PUBLIC_API(bool)
michael@0 3080 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue value,
michael@0 3081 unsigned attrs,
michael@0 3082 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
michael@0 3083 {
michael@0 3084 return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter),
michael@0 3085 attrs, 0);
michael@0 3086 }
michael@0 3087
michael@0 3088 JS_PUBLIC_API(bool)
michael@0 3089 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleObject valueArg,
michael@0 3090 unsigned attrs,
michael@0 3091 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
michael@0 3092 {
michael@0 3093 RootedValue value(cx, ObjectValue(*valueArg));
michael@0 3094 return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter),
michael@0 3095 attrs, 0);
michael@0 3096 }
michael@0 3097
michael@0 3098 JS_PUBLIC_API(bool)
michael@0 3099 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleString valueArg,
michael@0 3100 unsigned attrs,
michael@0 3101 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
michael@0 3102 {
michael@0 3103 RootedValue value(cx, StringValue(valueArg));
michael@0 3104 return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter),
michael@0 3105 attrs, 0);
michael@0 3106 }
michael@0 3107
michael@0 3108 JS_PUBLIC_API(bool)
michael@0 3109 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, int32_t valueArg,
michael@0 3110 unsigned attrs,
michael@0 3111 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
michael@0 3112 {
michael@0 3113 Value value = Int32Value(valueArg);
michael@0 3114 return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value),
michael@0 3115 GetterWrapper(getter), SetterWrapper(setter), attrs, 0);
michael@0 3116 }
michael@0 3117
michael@0 3118 JS_PUBLIC_API(bool)
michael@0 3119 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, uint32_t valueArg,
michael@0 3120 unsigned attrs,
michael@0 3121 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
michael@0 3122 {
michael@0 3123 Value value = UINT_TO_JSVAL(valueArg);
michael@0 3124 return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value),
michael@0 3125 GetterWrapper(getter), SetterWrapper(setter), attrs, 0);
michael@0 3126 }
michael@0 3127
michael@0 3128 JS_PUBLIC_API(bool)
michael@0 3129 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, double valueArg,
michael@0 3130 unsigned attrs,
michael@0 3131 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
michael@0 3132 {
michael@0 3133 Value value = NumberValue(valueArg);
michael@0 3134 return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value),
michael@0 3135 GetterWrapper(getter), SetterWrapper(setter), attrs, 0);
michael@0 3136 }
michael@0 3137
michael@0 3138 static bool
michael@0 3139 DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
michael@0 3140 const Value &value_, PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
michael@0 3141 unsigned flags)
michael@0 3142 {
michael@0 3143 RootedValue value(cx, value_);
michael@0 3144 AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
michael@0 3145 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
michael@0 3146 if (!atom)
michael@0 3147 return false;
michael@0 3148 RootedId id(cx, AtomToId(atom));
michael@0 3149 return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter),
michael@0 3150 attrs, flags);
michael@0 3151 }
michael@0 3152
michael@0 3153 JS_PUBLIC_API(bool)
michael@0 3154 JS_DefineUCProperty(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen,
michael@0 3155 jsval valueArg, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
michael@0 3156 {
michael@0 3157 RootedObject obj(cx, objArg);
michael@0 3158 RootedValue value(cx, valueArg);
michael@0 3159 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0);
michael@0 3160 }
michael@0 3161
michael@0 3162 JS_PUBLIC_API(bool)
michael@0 3163 JS_DefineOwnProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue descriptor, bool *bp)
michael@0 3164 {
michael@0 3165 AssertHeapIsIdle(cx);
michael@0 3166 CHECK_REQUEST(cx);
michael@0 3167 assertSameCompartment(cx, obj, id, descriptor);
michael@0 3168
michael@0 3169 return DefineOwnProperty(cx, obj, id, descriptor, bp);
michael@0 3170 }
michael@0 3171
michael@0 3172 JS_PUBLIC_API(JSObject *)
michael@0 3173 JS_DefineObject(JSContext *cx, JSObject *objArg, const char *name, const JSClass *jsclasp,
michael@0 3174 JSObject *protoArg, unsigned attrs)
michael@0 3175 {
michael@0 3176 RootedObject obj(cx, objArg);
michael@0 3177 RootedObject proto(cx, protoArg);
michael@0 3178 AssertHeapIsIdle(cx);
michael@0 3179 CHECK_REQUEST(cx);
michael@0 3180 assertSameCompartment(cx, obj, proto);
michael@0 3181
michael@0 3182 const Class *clasp = Valueify(jsclasp);
michael@0 3183 if (!clasp)
michael@0 3184 clasp = &JSObject::class_; /* default class is Object */
michael@0 3185
michael@0 3186 RootedObject nobj(cx, NewObjectWithClassProto(cx, clasp, proto, obj));
michael@0 3187 if (!nobj)
michael@0 3188 return nullptr;
michael@0 3189
michael@0 3190 RootedValue nobjValue(cx, ObjectValue(*nobj));
michael@0 3191 if (!DefineProperty(cx, obj, name, nobjValue, GetterWrapper(nullptr), SetterWrapper(nullptr),
michael@0 3192 attrs, 0)) {
michael@0 3193 return nullptr;
michael@0 3194 }
michael@0 3195
michael@0 3196 return nobj;
michael@0 3197 }
michael@0 3198
michael@0 3199 JS_PUBLIC_API(bool)
michael@0 3200 JS_DefineConstDoubles(JSContext *cx, HandleObject obj, const JSConstDoubleSpec *cds)
michael@0 3201 {
michael@0 3202 bool ok;
michael@0 3203 unsigned attrs;
michael@0 3204
michael@0 3205 AssertHeapIsIdle(cx);
michael@0 3206 CHECK_REQUEST(cx);
michael@0 3207 JSPropertyOpWrapper noget = GetterWrapper(nullptr);
michael@0 3208 JSStrictPropertyOpWrapper noset = SetterWrapper(nullptr);
michael@0 3209 for (ok = true; cds->name; cds++) {
michael@0 3210 RootedValue value(cx, DoubleValue(cds->dval));
michael@0 3211 attrs = cds->flags;
michael@0 3212 if (!attrs)
michael@0 3213 attrs = JSPROP_READONLY | JSPROP_PERMANENT;
michael@0 3214 ok = DefineProperty(cx, obj, cds->name, value, noget, noset, attrs, 0);
michael@0 3215 if (!ok)
michael@0 3216 break;
michael@0 3217 }
michael@0 3218 return ok;
michael@0 3219 }
michael@0 3220
michael@0 3221 JS_PUBLIC_API(bool)
michael@0 3222 JS_DefineProperties(JSContext *cx, HandleObject obj, const JSPropertySpec *ps)
michael@0 3223 {
michael@0 3224 bool ok;
michael@0 3225 for (ok = true; ps->name; ps++) {
michael@0 3226 if (ps->flags & JSPROP_NATIVE_ACCESSORS) {
michael@0 3227 // If you declare native accessors, then you should have a native
michael@0 3228 // getter.
michael@0 3229 JS_ASSERT(ps->getter.propertyOp.op);
michael@0 3230 // If you do not have a self-hosted getter, you should not have a
michael@0 3231 // self-hosted setter. This is the closest approximation to that
michael@0 3232 // assertion we can have with our setup.
michael@0 3233 JS_ASSERT_IF(ps->setter.propertyOp.info, ps->setter.propertyOp.op);
michael@0 3234
michael@0 3235 ok = DefineProperty(cx, obj, ps->name, JS::UndefinedHandleValue,
michael@0 3236 ps->getter.propertyOp, ps->setter.propertyOp, ps->flags, 0);
michael@0 3237 } else {
michael@0 3238 // If you have self-hosted getter/setter, you can't have a
michael@0 3239 // native one.
michael@0 3240 JS_ASSERT(!ps->getter.propertyOp.op && !ps->setter.propertyOp.op);
michael@0 3241 JS_ASSERT(ps->flags & JSPROP_GETTER);
michael@0 3242 /*
michael@0 3243 * During creation of the self-hosting global, we ignore all
michael@0 3244 * self-hosted properties, as that means we're currently setting up
michael@0 3245 * the global object that the self-hosted code is then compiled
michael@0 3246 * in. That means that Self-hosted properties can't be used in the
michael@0 3247 * self-hosting global itself, right now.
michael@0 3248 */
michael@0 3249 if (cx->runtime()->isSelfHostingGlobal(cx->global()))
michael@0 3250 continue;
michael@0 3251
michael@0 3252 ok = DefineSelfHostedProperty(cx, obj, ps->name,
michael@0 3253 ps->getter.selfHosted.funname,
michael@0 3254 ps->setter.selfHosted.funname,
michael@0 3255 ps->flags, 0);
michael@0 3256 }
michael@0 3257 if (!ok)
michael@0 3258 break;
michael@0 3259 }
michael@0 3260 return ok;
michael@0 3261 }
michael@0 3262
michael@0 3263 static bool
michael@0 3264 GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id,
michael@0 3265 MutableHandle<PropertyDescriptor> desc)
michael@0 3266 {
michael@0 3267 RootedObject obj2(cx);
michael@0 3268 RootedShape shape(cx);
michael@0 3269
michael@0 3270 if (!LookupPropertyById(cx, obj, id, &obj2, &shape))
michael@0 3271 return false;
michael@0 3272
michael@0 3273 desc.clear();
michael@0 3274 if (!shape)
michael@0 3275 return true;
michael@0 3276
michael@0 3277 desc.object().set(obj2);
michael@0 3278 if (obj2->isNative()) {
michael@0 3279 if (IsImplicitDenseOrTypedArrayElement(shape)) {
michael@0 3280 desc.setEnumerable();
michael@0 3281 desc.value().set(obj2->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
michael@0 3282 } else {
michael@0 3283 desc.setAttributes(shape->attributes());
michael@0 3284 desc.setGetter(shape->getter());
michael@0 3285 desc.setSetter(shape->setter());
michael@0 3286 JS_ASSERT(desc.value().isUndefined());
michael@0 3287 if (shape->hasSlot())
michael@0 3288 desc.value().set(obj2->nativeGetSlot(shape->slot()));
michael@0 3289 }
michael@0 3290 } else {
michael@0 3291 if (obj2->is<ProxyObject>())
michael@0 3292 return Proxy::getPropertyDescriptor(cx, obj2, id, desc);
michael@0 3293 if (!JSObject::getGenericAttributes(cx, obj2, id, &desc.attributesRef()))
michael@0 3294 return false;
michael@0 3295 JS_ASSERT(desc.getter() == nullptr);
michael@0 3296 JS_ASSERT(desc.setter() == nullptr);
michael@0 3297 JS_ASSERT(desc.value().isUndefined());
michael@0 3298 }
michael@0 3299 return true;
michael@0 3300 }
michael@0 3301
michael@0 3302 JS_PUBLIC_API(bool)
michael@0 3303 JS_GetOwnPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id,
michael@0 3304 MutableHandle<JSPropertyDescriptor> desc)
michael@0 3305 {
michael@0 3306 AssertHeapIsIdle(cx);
michael@0 3307 CHECK_REQUEST(cx);
michael@0 3308
michael@0 3309 return GetOwnPropertyDescriptor(cx, obj, id, desc);
michael@0 3310 }
michael@0 3311
michael@0 3312 JS_PUBLIC_API(bool)
michael@0 3313 JS_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, const char *name,
michael@0 3314 MutableHandle<JSPropertyDescriptor> desc)
michael@0 3315 {
michael@0 3316 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 3317 if (!atom)
michael@0 3318 return false;
michael@0 3319 RootedId id(cx, AtomToId(atom));
michael@0 3320 return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc);
michael@0 3321 }
michael@0 3322
michael@0 3323 JS_PUBLIC_API(bool)
michael@0 3324 JS_GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id,
michael@0 3325 MutableHandle<JSPropertyDescriptor> desc)
michael@0 3326 {
michael@0 3327 return GetPropertyDescriptorById(cx, obj, id, desc);
michael@0 3328 }
michael@0 3329
michael@0 3330 JS_PUBLIC_API(bool)
michael@0 3331 JS_GetPropertyDescriptor(JSContext *cx, HandleObject obj, const char *name,
michael@0 3332 MutableHandle<JSPropertyDescriptor> desc)
michael@0 3333 {
michael@0 3334 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 3335 if (!atom)
michael@0 3336 return false;
michael@0 3337 RootedId id(cx, AtomToId(atom));
michael@0 3338 return atom && JS_GetPropertyDescriptorById(cx, obj, id, desc);
michael@0 3339 }
michael@0 3340
michael@0 3341 JS_PUBLIC_API(bool)
michael@0 3342 JS_GetPropertyById(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
michael@0 3343 {
michael@0 3344 return JS_ForwardGetPropertyTo(cx, obj, id, obj, vp);
michael@0 3345 }
michael@0 3346
michael@0 3347 JS_PUBLIC_API(bool)
michael@0 3348 JS_ForwardGetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject onBehalfOf,
michael@0 3349 JS::MutableHandleValue vp)
michael@0 3350 {
michael@0 3351 AssertHeapIsIdle(cx);
michael@0 3352 CHECK_REQUEST(cx);
michael@0 3353 assertSameCompartment(cx, obj, id);
michael@0 3354 assertSameCompartment(cx, onBehalfOf);
michael@0 3355
michael@0 3356 return JSObject::getGeneric(cx, obj, onBehalfOf, id, vp);
michael@0 3357 }
michael@0 3358
michael@0 3359 JS_PUBLIC_API(bool)
michael@0 3360 JS_GetElement(JSContext *cx, HandleObject objArg, uint32_t index, MutableHandleValue vp)
michael@0 3361 {
michael@0 3362 return JS_ForwardGetElementTo(cx, objArg, index, objArg, vp);
michael@0 3363 }
michael@0 3364
michael@0 3365 JS_PUBLIC_API(bool)
michael@0 3366 JS_ForwardGetElementTo(JSContext *cx, HandleObject obj, uint32_t index, HandleObject onBehalfOf,
michael@0 3367 MutableHandleValue vp)
michael@0 3368 {
michael@0 3369 AssertHeapIsIdle(cx);
michael@0 3370 CHECK_REQUEST(cx);
michael@0 3371 assertSameCompartment(cx, obj);
michael@0 3372
michael@0 3373 return JSObject::getElement(cx, obj, onBehalfOf, index, vp);
michael@0 3374 }
michael@0 3375
michael@0 3376 JS_PUBLIC_API(bool)
michael@0 3377 JS_GetProperty(JSContext *cx, HandleObject obj, const char *name, MutableHandleValue vp)
michael@0 3378 {
michael@0 3379 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 3380 if (!atom)
michael@0 3381 return false;
michael@0 3382 RootedId id(cx, AtomToId(atom));
michael@0 3383 return JS_GetPropertyById(cx, obj, id, vp);
michael@0 3384 }
michael@0 3385
michael@0 3386 JS_PUBLIC_API(bool)
michael@0 3387 JS_GetUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
michael@0 3388 MutableHandleValue vp)
michael@0 3389 {
michael@0 3390 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
michael@0 3391 if (!atom)
michael@0 3392 return false;
michael@0 3393 RootedId id(cx, AtomToId(atom));
michael@0 3394 return JS_GetPropertyById(cx, obj, id, vp);
michael@0 3395 }
michael@0 3396
michael@0 3397 JS_PUBLIC_API(bool)
michael@0 3398 JS_SetPropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue v)
michael@0 3399 {
michael@0 3400 RootedValue value(cx, v);
michael@0 3401 AssertHeapIsIdle(cx);
michael@0 3402 CHECK_REQUEST(cx);
michael@0 3403 assertSameCompartment(cx, obj, id);
michael@0 3404
michael@0 3405 return JSObject::setGeneric(cx, obj, obj, id, &value, false);
michael@0 3406 }
michael@0 3407
michael@0 3408 static bool
michael@0 3409 SetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
michael@0 3410 {
michael@0 3411 AssertHeapIsIdle(cx);
michael@0 3412 CHECK_REQUEST(cx);
michael@0 3413 assertSameCompartment(cx, obj, vp);
michael@0 3414
michael@0 3415 return JSObject::setElement(cx, obj, obj, index, vp, false);
michael@0 3416 }
michael@0 3417
michael@0 3418 JS_PUBLIC_API(bool)
michael@0 3419 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v)
michael@0 3420 {
michael@0 3421 RootedValue value(cx, v);
michael@0 3422 return SetElement(cx, obj, index, &value);
michael@0 3423 }
michael@0 3424
michael@0 3425 JS_PUBLIC_API(bool)
michael@0 3426 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleObject v)
michael@0 3427 {
michael@0 3428 RootedValue value(cx, ObjectOrNullValue(v));
michael@0 3429 return SetElement(cx, obj, index, &value);
michael@0 3430 }
michael@0 3431
michael@0 3432 JS_PUBLIC_API(bool)
michael@0 3433 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleString v)
michael@0 3434 {
michael@0 3435 RootedValue value(cx, StringValue(v));
michael@0 3436 return SetElement(cx, obj, index, &value);
michael@0 3437 }
michael@0 3438
michael@0 3439 JS_PUBLIC_API(bool)
michael@0 3440 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, int32_t v)
michael@0 3441 {
michael@0 3442 RootedValue value(cx, NumberValue(v));
michael@0 3443 return SetElement(cx, obj, index, &value);
michael@0 3444 }
michael@0 3445
michael@0 3446 JS_PUBLIC_API(bool)
michael@0 3447 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, uint32_t v)
michael@0 3448 {
michael@0 3449 RootedValue value(cx, NumberValue(v));
michael@0 3450 return SetElement(cx, obj, index, &value);
michael@0 3451 }
michael@0 3452
michael@0 3453 JS_PUBLIC_API(bool)
michael@0 3454 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, double v)
michael@0 3455 {
michael@0 3456 RootedValue value(cx, NumberValue(v));
michael@0 3457 return SetElement(cx, obj, index, &value);
michael@0 3458 }
michael@0 3459
michael@0 3460 JS_PUBLIC_API(bool)
michael@0 3461 JS_SetProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue v)
michael@0 3462 {
michael@0 3463 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 3464 if (!atom)
michael@0 3465 return false;
michael@0 3466 RootedId id(cx, AtomToId(atom));
michael@0 3467 return JS_SetPropertyById(cx, obj, id, v);
michael@0 3468 }
michael@0 3469
michael@0 3470 JS_PUBLIC_API(bool)
michael@0 3471 JS_SetUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
michael@0 3472 HandleValue v)
michael@0 3473 {
michael@0 3474 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
michael@0 3475 if (!atom)
michael@0 3476 return false;
michael@0 3477 RootedId id(cx, AtomToId(atom));
michael@0 3478 return JS_SetPropertyById(cx, obj, id, v);
michael@0 3479 }
michael@0 3480
michael@0 3481 JS_PUBLIC_API(bool)
michael@0 3482 JS_DeletePropertyById2(JSContext *cx, HandleObject obj, HandleId id, bool *result)
michael@0 3483 {
michael@0 3484 AssertHeapIsIdle(cx);
michael@0 3485 CHECK_REQUEST(cx);
michael@0 3486 assertSameCompartment(cx, obj, id);
michael@0 3487
michael@0 3488 return JSObject::deleteByValue(cx, obj, IdToValue(id), result);
michael@0 3489 }
michael@0 3490
michael@0 3491 JS_PUBLIC_API(bool)
michael@0 3492 JS_DeleteElement2(JSContext *cx, HandleObject obj, uint32_t index, bool *result)
michael@0 3493 {
michael@0 3494 AssertHeapIsIdle(cx);
michael@0 3495 CHECK_REQUEST(cx);
michael@0 3496 assertSameCompartment(cx, obj);
michael@0 3497
michael@0 3498 return JSObject::deleteElement(cx, obj, index, result);
michael@0 3499 }
michael@0 3500
michael@0 3501 JS_PUBLIC_API(bool)
michael@0 3502 JS_DeleteProperty2(JSContext *cx, HandleObject obj, const char *name, bool *result)
michael@0 3503 {
michael@0 3504 CHECK_REQUEST(cx);
michael@0 3505 assertSameCompartment(cx, obj);
michael@0 3506
michael@0 3507 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 3508 if (!atom)
michael@0 3509 return false;
michael@0 3510 return JSObject::deleteByValue(cx, obj, StringValue(atom), result);
michael@0 3511 }
michael@0 3512
michael@0 3513 JS_PUBLIC_API(bool)
michael@0 3514 JS_DeleteUCProperty2(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
michael@0 3515 bool *result)
michael@0 3516 {
michael@0 3517 CHECK_REQUEST(cx);
michael@0 3518 assertSameCompartment(cx, obj);
michael@0 3519
michael@0 3520 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
michael@0 3521 if (!atom)
michael@0 3522 return false;
michael@0 3523 return JSObject::deleteByValue(cx, obj, StringValue(atom), result);
michael@0 3524 }
michael@0 3525
michael@0 3526 JS_PUBLIC_API(bool)
michael@0 3527 JS_DeletePropertyById(JSContext *cx, HandleObject obj, HandleId id)
michael@0 3528 {
michael@0 3529 bool junk;
michael@0 3530 return JS_DeletePropertyById2(cx, obj, id, &junk);
michael@0 3531 }
michael@0 3532
michael@0 3533 JS_PUBLIC_API(bool)
michael@0 3534 JS_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index)
michael@0 3535 {
michael@0 3536 bool junk;
michael@0 3537 return JS_DeleteElement2(cx, obj, index, &junk);
michael@0 3538 }
michael@0 3539
michael@0 3540 JS_PUBLIC_API(bool)
michael@0 3541 JS_DeleteProperty(JSContext *cx, HandleObject obj, const char *name)
michael@0 3542 {
michael@0 3543 bool junk;
michael@0 3544 return JS_DeleteProperty2(cx, obj, name, &junk);
michael@0 3545 }
michael@0 3546
michael@0 3547 static Shape *
michael@0 3548 LastConfigurableShape(JSObject *obj)
michael@0 3549 {
michael@0 3550 for (Shape::Range<NoGC> r(obj->lastProperty()); !r.empty(); r.popFront()) {
michael@0 3551 Shape *shape = &r.front();
michael@0 3552 if (shape->configurable())
michael@0 3553 return shape;
michael@0 3554 }
michael@0 3555 return nullptr;
michael@0 3556 }
michael@0 3557
michael@0 3558 JS_PUBLIC_API(void)
michael@0 3559 JS_ClearNonGlobalObject(JSContext *cx, HandleObject obj)
michael@0 3560 {
michael@0 3561 AssertHeapIsIdle(cx);
michael@0 3562 CHECK_REQUEST(cx);
michael@0 3563 assertSameCompartment(cx, obj);
michael@0 3564
michael@0 3565 JS_ASSERT(!obj->is<GlobalObject>());
michael@0 3566
michael@0 3567 if (!obj->isNative())
michael@0 3568 return;
michael@0 3569
michael@0 3570 /* Remove all configurable properties from obj. */
michael@0 3571 RootedShape shape(cx);
michael@0 3572 while ((shape = LastConfigurableShape(obj))) {
michael@0 3573 if (!obj->removeProperty(cx, shape->propid()))
michael@0 3574 return;
michael@0 3575 }
michael@0 3576
michael@0 3577 /* Set all remaining writable plain data properties to undefined. */
michael@0 3578 for (Shape::Range<NoGC> r(obj->lastProperty()); !r.empty(); r.popFront()) {
michael@0 3579 Shape *shape = &r.front();
michael@0 3580 if (shape->isDataDescriptor() &&
michael@0 3581 shape->writable() &&
michael@0 3582 shape->hasDefaultSetter() &&
michael@0 3583 shape->hasSlot())
michael@0 3584 {
michael@0 3585 obj->nativeSetSlot(shape->slot(), UndefinedValue());
michael@0 3586 }
michael@0 3587 }
michael@0 3588 }
michael@0 3589
michael@0 3590 JS_PUBLIC_API(void)
michael@0 3591 JS_SetAllNonReservedSlotsToUndefined(JSContext *cx, JSObject *objArg)
michael@0 3592 {
michael@0 3593 RootedObject obj(cx, objArg);
michael@0 3594 AssertHeapIsIdle(cx);
michael@0 3595 CHECK_REQUEST(cx);
michael@0 3596 assertSameCompartment(cx, obj);
michael@0 3597
michael@0 3598 if (!obj->isNative())
michael@0 3599 return;
michael@0 3600
michael@0 3601 const Class *clasp = obj->getClass();
michael@0 3602 unsigned numReserved = JSCLASS_RESERVED_SLOTS(clasp);
michael@0 3603 unsigned numSlots = obj->slotSpan();
michael@0 3604 for (unsigned i = numReserved; i < numSlots; i++)
michael@0 3605 obj->setSlot(i, UndefinedValue());
michael@0 3606 }
michael@0 3607
michael@0 3608 JS_PUBLIC_API(JSIdArray *)
michael@0 3609 JS_Enumerate(JSContext *cx, HandleObject obj)
michael@0 3610 {
michael@0 3611 AssertHeapIsIdle(cx);
michael@0 3612 CHECK_REQUEST(cx);
michael@0 3613 assertSameCompartment(cx, obj);
michael@0 3614
michael@0 3615 AutoIdVector props(cx);
michael@0 3616 JSIdArray *ida;
michael@0 3617 if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
michael@0 3618 return nullptr;
michael@0 3619 return ida;
michael@0 3620 }
michael@0 3621
michael@0 3622 /*
michael@0 3623 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
michael@0 3624 * prop_iterator_class somehow...
michael@0 3625 * + preserve the obj->enumerate API while optimizing the native object case
michael@0 3626 * + native case here uses a JSShape *, but that iterates in reverse!
michael@0 3627 * + so we make non-native match, by reverse-iterating after JS_Enumerating
michael@0 3628 */
michael@0 3629 static const uint32_t JSSLOT_ITER_INDEX = 0;
michael@0 3630
michael@0 3631 static void
michael@0 3632 prop_iter_finalize(FreeOp *fop, JSObject *obj)
michael@0 3633 {
michael@0 3634 void *pdata = obj->getPrivate();
michael@0 3635 if (!pdata)
michael@0 3636 return;
michael@0 3637
michael@0 3638 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
michael@0 3639 /* Non-native case: destroy the ida enumerated when obj was created. */
michael@0 3640 JSIdArray *ida = (JSIdArray *) pdata;
michael@0 3641 fop->free_(ida);
michael@0 3642 }
michael@0 3643 }
michael@0 3644
michael@0 3645 static void
michael@0 3646 prop_iter_trace(JSTracer *trc, JSObject *obj)
michael@0 3647 {
michael@0 3648 void *pdata = obj->getPrivate();
michael@0 3649 if (!pdata)
michael@0 3650 return;
michael@0 3651
michael@0 3652 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
michael@0 3653 /*
michael@0 3654 * Native case: just mark the next property to visit. We don't need a
michael@0 3655 * barrier here because the pointer is updated via setPrivate, which
michael@0 3656 * always takes a barrier.
michael@0 3657 */
michael@0 3658 Shape *tmp = static_cast<Shape *>(pdata);
michael@0 3659 MarkShapeUnbarriered(trc, &tmp, "prop iter shape");
michael@0 3660 obj->setPrivateUnbarriered(tmp);
michael@0 3661 } else {
michael@0 3662 /* Non-native case: mark each id in the JSIdArray private. */
michael@0 3663 JSIdArray *ida = (JSIdArray *) pdata;
michael@0 3664 MarkIdRange(trc, ida->length, ida->vector, "prop iter");
michael@0 3665 }
michael@0 3666 }
michael@0 3667
michael@0 3668 static const Class prop_iter_class = {
michael@0 3669 "PropertyIterator",
michael@0 3670 JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(1),
michael@0 3671 JS_PropertyStub, /* addProperty */
michael@0 3672 JS_DeletePropertyStub, /* delProperty */
michael@0 3673 JS_PropertyStub, /* getProperty */
michael@0 3674 JS_StrictPropertyStub, /* setProperty */
michael@0 3675 JS_EnumerateStub,
michael@0 3676 JS_ResolveStub,
michael@0 3677 JS_ConvertStub,
michael@0 3678 prop_iter_finalize,
michael@0 3679 nullptr, /* call */
michael@0 3680 nullptr, /* hasInstance */
michael@0 3681 nullptr, /* construct */
michael@0 3682 prop_iter_trace
michael@0 3683 };
michael@0 3684
michael@0 3685 JS_PUBLIC_API(JSObject *)
michael@0 3686 JS_NewPropertyIterator(JSContext *cx, HandleObject obj)
michael@0 3687 {
michael@0 3688 AssertHeapIsIdle(cx);
michael@0 3689 CHECK_REQUEST(cx);
michael@0 3690 assertSameCompartment(cx, obj);
michael@0 3691
michael@0 3692 RootedObject iterobj(cx, NewObjectWithClassProto(cx, &prop_iter_class, nullptr, obj));
michael@0 3693 if (!iterobj)
michael@0 3694 return nullptr;
michael@0 3695
michael@0 3696 int index;
michael@0 3697 if (obj->isNative()) {
michael@0 3698 /* Native case: start with the last property in obj. */
michael@0 3699 iterobj->setPrivateGCThing(obj->lastProperty());
michael@0 3700 index = -1;
michael@0 3701 } else {
michael@0 3702 /* Non-native case: enumerate a JSIdArray and keep it via private. */
michael@0 3703 JSIdArray *ida = JS_Enumerate(cx, obj);
michael@0 3704 if (!ida)
michael@0 3705 return nullptr;
michael@0 3706 iterobj->setPrivate((void *)ida);
michael@0 3707 index = ida->length;
michael@0 3708 }
michael@0 3709
michael@0 3710 /* iterobj cannot escape to other threads here. */
michael@0 3711 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(index));
michael@0 3712 return iterobj;
michael@0 3713 }
michael@0 3714
michael@0 3715 JS_PUBLIC_API(bool)
michael@0 3716 JS_NextProperty(JSContext *cx, HandleObject iterobj, jsid *idp)
michael@0 3717 {
michael@0 3718 AssertHeapIsIdle(cx);
michael@0 3719 CHECK_REQUEST(cx);
michael@0 3720 assertSameCompartment(cx, iterobj);
michael@0 3721 int32_t i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
michael@0 3722 if (i < 0) {
michael@0 3723 /* Native case: private data is a property tree node pointer. */
michael@0 3724 JS_ASSERT(iterobj->getParent()->isNative());
michael@0 3725 Shape *shape = static_cast<Shape *>(iterobj->getPrivate());
michael@0 3726
michael@0 3727 while (shape->previous() && !shape->enumerable())
michael@0 3728 shape = shape->previous();
michael@0 3729
michael@0 3730 if (!shape->previous()) {
michael@0 3731 JS_ASSERT(shape->isEmptyShape());
michael@0 3732 *idp = JSID_VOID;
michael@0 3733 } else {
michael@0 3734 iterobj->setPrivateGCThing(const_cast<Shape *>(shape->previous().get()));
michael@0 3735 *idp = shape->propid();
michael@0 3736 }
michael@0 3737 } else {
michael@0 3738 /* Non-native case: use the ida enumerated when iterobj was created. */
michael@0 3739 JSIdArray *ida = (JSIdArray *) iterobj->getPrivate();
michael@0 3740 JS_ASSERT(i <= ida->length);
michael@0 3741 STATIC_ASSUME(i <= ida->length);
michael@0 3742 if (i == 0) {
michael@0 3743 *idp = JSID_VOID;
michael@0 3744 } else {
michael@0 3745 *idp = ida->vector[--i];
michael@0 3746 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
michael@0 3747 }
michael@0 3748 }
michael@0 3749 return true;
michael@0 3750 }
michael@0 3751
michael@0 3752 JS_PUBLIC_API(jsval)
michael@0 3753 JS_GetReservedSlot(JSObject *obj, uint32_t index)
michael@0 3754 {
michael@0 3755 return obj->getReservedSlot(index);
michael@0 3756 }
michael@0 3757
michael@0 3758 JS_PUBLIC_API(void)
michael@0 3759 JS_SetReservedSlot(JSObject *obj, uint32_t index, Value value)
michael@0 3760 {
michael@0 3761 obj->setReservedSlot(index, value);
michael@0 3762 }
michael@0 3763
michael@0 3764 JS_PUBLIC_API(JSObject *)
michael@0 3765 JS_NewArrayObject(JSContext *cx, const JS::HandleValueArray& contents)
michael@0 3766 {
michael@0 3767 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 3768 AssertHeapIsIdle(cx);
michael@0 3769 CHECK_REQUEST(cx);
michael@0 3770
michael@0 3771 assertSameCompartment(cx, contents);
michael@0 3772 return NewDenseCopiedArray(cx, contents.length(), contents.begin());
michael@0 3773 }
michael@0 3774
michael@0 3775 JS_PUBLIC_API(JSObject *)
michael@0 3776 JS_NewArrayObject(JSContext *cx, size_t length)
michael@0 3777 {
michael@0 3778 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 3779 AssertHeapIsIdle(cx);
michael@0 3780 CHECK_REQUEST(cx);
michael@0 3781
michael@0 3782 return NewDenseAllocatedArray(cx, length);
michael@0 3783 }
michael@0 3784
michael@0 3785 JS_PUBLIC_API(bool)
michael@0 3786 JS_IsArrayObject(JSContext *cx, JS::HandleObject obj)
michael@0 3787 {
michael@0 3788 assertSameCompartment(cx, obj);
michael@0 3789 return ObjectClassIs(obj, ESClass_Array, cx);
michael@0 3790 }
michael@0 3791
michael@0 3792 JS_PUBLIC_API(bool)
michael@0 3793 JS_IsArrayObject(JSContext *cx, JS::HandleValue value)
michael@0 3794 {
michael@0 3795 if (!value.isObject())
michael@0 3796 return false;
michael@0 3797 RootedObject obj(cx, &value.toObject());
michael@0 3798 return JS_IsArrayObject(cx, obj);
michael@0 3799 }
michael@0 3800
michael@0 3801 JS_PUBLIC_API(bool)
michael@0 3802 JS_GetArrayLength(JSContext *cx, HandleObject obj, uint32_t *lengthp)
michael@0 3803 {
michael@0 3804 AssertHeapIsIdle(cx);
michael@0 3805 CHECK_REQUEST(cx);
michael@0 3806 assertSameCompartment(cx, obj);
michael@0 3807 return GetLengthProperty(cx, obj, lengthp);
michael@0 3808 }
michael@0 3809
michael@0 3810 JS_PUBLIC_API(bool)
michael@0 3811 JS_SetArrayLength(JSContext *cx, HandleObject obj, uint32_t length)
michael@0 3812 {
michael@0 3813 AssertHeapIsIdle(cx);
michael@0 3814 CHECK_REQUEST(cx);
michael@0 3815 assertSameCompartment(cx, obj);
michael@0 3816 return SetLengthProperty(cx, obj, length);
michael@0 3817 }
michael@0 3818
michael@0 3819 JS_PUBLIC_API(void)
michael@0 3820 JS_HoldPrincipals(JSPrincipals *principals)
michael@0 3821 {
michael@0 3822 ++principals->refcount;
michael@0 3823 }
michael@0 3824
michael@0 3825 JS_PUBLIC_API(void)
michael@0 3826 JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals)
michael@0 3827 {
michael@0 3828 int rc = --principals->refcount;
michael@0 3829 if (rc == 0)
michael@0 3830 rt->destroyPrincipals(principals);
michael@0 3831 }
michael@0 3832
michael@0 3833 JS_PUBLIC_API(void)
michael@0 3834 JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *scb)
michael@0 3835 {
michael@0 3836 JS_ASSERT(scb != &NullSecurityCallbacks);
michael@0 3837 rt->securityCallbacks = scb ? scb : &NullSecurityCallbacks;
michael@0 3838 }
michael@0 3839
michael@0 3840 JS_PUBLIC_API(const JSSecurityCallbacks *)
michael@0 3841 JS_GetSecurityCallbacks(JSRuntime *rt)
michael@0 3842 {
michael@0 3843 return (rt->securityCallbacks != &NullSecurityCallbacks) ? rt->securityCallbacks : nullptr;
michael@0 3844 }
michael@0 3845
michael@0 3846 JS_PUBLIC_API(void)
michael@0 3847 JS_SetTrustedPrincipals(JSRuntime *rt, const JSPrincipals *prin)
michael@0 3848 {
michael@0 3849 rt->setTrustedPrincipals(prin);
michael@0 3850 }
michael@0 3851
michael@0 3852 extern JS_PUBLIC_API(void)
michael@0 3853 JS_InitDestroyPrincipalsCallback(JSRuntime *rt, JSDestroyPrincipalsOp destroyPrincipals)
michael@0 3854 {
michael@0 3855 JS_ASSERT(destroyPrincipals);
michael@0 3856 JS_ASSERT(!rt->destroyPrincipals);
michael@0 3857 rt->destroyPrincipals = destroyPrincipals;
michael@0 3858 }
michael@0 3859
michael@0 3860 JS_PUBLIC_API(JSFunction *)
michael@0 3861 JS_NewFunction(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
michael@0 3862 HandleObject parent, const char *name)
michael@0 3863 {
michael@0 3864 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 3865
michael@0 3866 AssertHeapIsIdle(cx);
michael@0 3867 CHECK_REQUEST(cx);
michael@0 3868 assertSameCompartment(cx, parent);
michael@0 3869
michael@0 3870 RootedAtom atom(cx);
michael@0 3871 if (name) {
michael@0 3872 atom = Atomize(cx, name, strlen(name));
michael@0 3873 if (!atom)
michael@0 3874 return nullptr;
michael@0 3875 }
michael@0 3876
michael@0 3877 JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
michael@0 3878 return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom);
michael@0 3879 }
michael@0 3880
michael@0 3881 JS_PUBLIC_API(JSFunction *)
michael@0 3882 JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
michael@0 3883 HandleObject parent, HandleId id)
michael@0 3884 {
michael@0 3885 JS_ASSERT(JSID_IS_STRING(id));
michael@0 3886 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 3887 JS_ASSERT(native);
michael@0 3888 AssertHeapIsIdle(cx);
michael@0 3889 CHECK_REQUEST(cx);
michael@0 3890 assertSameCompartment(cx, parent);
michael@0 3891
michael@0 3892 RootedAtom name(cx, JSID_TO_ATOM(id));
michael@0 3893 JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
michael@0 3894 return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, name);
michael@0 3895 }
michael@0 3896
michael@0 3897 JS_PUBLIC_API(JSFunction *)
michael@0 3898 JS::GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, HandleId id, unsigned nargs)
michael@0 3899 {
michael@0 3900 JS_ASSERT(JSID_IS_STRING(id));
michael@0 3901 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 3902 AssertHeapIsIdle(cx);
michael@0 3903 CHECK_REQUEST(cx);
michael@0 3904
michael@0 3905 RootedAtom name(cx, JSID_TO_ATOM(id));
michael@0 3906 RootedAtom shName(cx, Atomize(cx, selfHostedName, strlen(selfHostedName)));
michael@0 3907 if (!shName)
michael@0 3908 return nullptr;
michael@0 3909 RootedValue funVal(cx);
michael@0 3910 if (!cx->global()->getSelfHostedFunction(cx, shName, name, nargs, &funVal))
michael@0 3911 return nullptr;
michael@0 3912 return &funVal.toObject().as<JSFunction>();
michael@0 3913 }
michael@0 3914
michael@0 3915 JS_PUBLIC_API(JSObject *)
michael@0 3916 JS_CloneFunctionObject(JSContext *cx, HandleObject funobj, HandleObject parentArg)
michael@0 3917 {
michael@0 3918 RootedObject parent(cx, parentArg);
michael@0 3919
michael@0 3920 AssertHeapIsIdle(cx);
michael@0 3921 CHECK_REQUEST(cx);
michael@0 3922 assertSameCompartment(cx, parent);
michael@0 3923 // Note that funobj can be in a different compartment.
michael@0 3924
michael@0 3925 if (!parent)
michael@0 3926 parent = cx->global();
michael@0 3927
michael@0 3928 if (!funobj->is<JSFunction>()) {
michael@0 3929 AutoCompartment ac(cx, funobj);
michael@0 3930 RootedValue v(cx, ObjectValue(*funobj));
michael@0 3931 ReportIsNotFunction(cx, v);
michael@0 3932 return nullptr;
michael@0 3933 }
michael@0 3934
michael@0 3935 RootedFunction fun(cx, &funobj->as<JSFunction>());
michael@0 3936 if (fun->isInterpretedLazy()) {
michael@0 3937 AutoCompartment ac(cx, funobj);
michael@0 3938 if (!fun->getOrCreateScript(cx))
michael@0 3939 return nullptr;
michael@0 3940 }
michael@0 3941 /*
michael@0 3942 * If a function was compiled to be lexically nested inside some other
michael@0 3943 * script, we cannot clone it without breaking the compiler's assumptions.
michael@0 3944 */
michael@0 3945 if (fun->isInterpreted() && (fun->nonLazyScript()->enclosingStaticScope() ||
michael@0 3946 (fun->nonLazyScript()->compileAndGo() && !parent->is<GlobalObject>())))
michael@0 3947 {
michael@0 3948 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
michael@0 3949 return nullptr;
michael@0 3950 }
michael@0 3951
michael@0 3952 if (fun->isBoundFunction()) {
michael@0 3953 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT);
michael@0 3954 return nullptr;
michael@0 3955 }
michael@0 3956
michael@0 3957 if (fun->isNative() && IsAsmJSModuleNative(fun->native())) {
michael@0 3958 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT);
michael@0 3959 return nullptr;
michael@0 3960 }
michael@0 3961
michael@0 3962 return CloneFunctionObject(cx, fun, parent, fun->getAllocKind());
michael@0 3963 }
michael@0 3964
michael@0 3965 JS_PUBLIC_API(JSObject *)
michael@0 3966 JS_GetFunctionObject(JSFunction *fun)
michael@0 3967 {
michael@0 3968 return fun;
michael@0 3969 }
michael@0 3970
michael@0 3971 JS_PUBLIC_API(JSString *)
michael@0 3972 JS_GetFunctionId(JSFunction *fun)
michael@0 3973 {
michael@0 3974 return fun->atom();
michael@0 3975 }
michael@0 3976
michael@0 3977 JS_PUBLIC_API(JSString *)
michael@0 3978 JS_GetFunctionDisplayId(JSFunction *fun)
michael@0 3979 {
michael@0 3980 return fun->displayAtom();
michael@0 3981 }
michael@0 3982
michael@0 3983 JS_PUBLIC_API(uint16_t)
michael@0 3984 JS_GetFunctionArity(JSFunction *fun)
michael@0 3985 {
michael@0 3986 return fun->nargs();
michael@0 3987 }
michael@0 3988
michael@0 3989 JS_PUBLIC_API(bool)
michael@0 3990 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
michael@0 3991 {
michael@0 3992 return obj->is<JSFunction>();
michael@0 3993 }
michael@0 3994
michael@0 3995 JS_PUBLIC_API(bool)
michael@0 3996 JS_ObjectIsCallable(JSContext *cx, JSObject *obj)
michael@0 3997 {
michael@0 3998 return obj->isCallable();
michael@0 3999 }
michael@0 4000
michael@0 4001 JS_PUBLIC_API(bool)
michael@0 4002 JS_IsNativeFunction(JSObject *funobj, JSNative call)
michael@0 4003 {
michael@0 4004 if (!funobj->is<JSFunction>())
michael@0 4005 return false;
michael@0 4006 JSFunction *fun = &funobj->as<JSFunction>();
michael@0 4007 return fun->isNative() && fun->native() == call;
michael@0 4008 }
michael@0 4009
michael@0 4010 extern JS_PUBLIC_API(bool)
michael@0 4011 JS_IsConstructor(JSFunction *fun)
michael@0 4012 {
michael@0 4013 return fun->isNativeConstructor() || fun->isInterpretedConstructor();
michael@0 4014 }
michael@0 4015
michael@0 4016 JS_PUBLIC_API(JSObject*)
michael@0 4017 JS_BindCallable(JSContext *cx, HandleObject target, HandleObject newThis)
michael@0 4018 {
michael@0 4019 RootedValue thisArg(cx, ObjectValue(*newThis));
michael@0 4020 return js_fun_bind(cx, target, thisArg, nullptr, 0);
michael@0 4021 }
michael@0 4022
michael@0 4023 static bool
michael@0 4024 js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp)
michael@0 4025 {
michael@0 4026 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 4027
michael@0 4028 const JSFunctionSpec *fs = (JSFunctionSpec *)
michael@0 4029 args.callee().as<JSFunction>().getExtendedSlot(0).toPrivate();
michael@0 4030 JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
michael@0 4031
michael@0 4032 if (argc < 1) {
michael@0 4033 js_ReportMissingArg(cx, args.calleev(), 0);
michael@0 4034 return false;
michael@0 4035 }
michael@0 4036
michael@0 4037 /*
michael@0 4038 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
michael@0 4039 * which is almost always the class constructor object, e.g. Array. Then
michael@0 4040 * call the corresponding prototype native method with our first argument
michael@0 4041 * passed as |this|.
michael@0 4042 */
michael@0 4043 memmove(vp + 1, vp + 2, argc * sizeof(jsval));
michael@0 4044
michael@0 4045 /* Clear the last parameter in case too few arguments were passed. */
michael@0 4046 vp[2 + --argc].setUndefined();
michael@0 4047
michael@0 4048 return fs->call.op(cx, argc, vp);
michael@0 4049 }
michael@0 4050
michael@0 4051 JS_PUBLIC_API(bool)
michael@0 4052 JS_DefineFunctions(JSContext *cx, HandleObject obj, const JSFunctionSpec *fs)
michael@0 4053 {
michael@0 4054 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4055 AssertHeapIsIdle(cx);
michael@0 4056 CHECK_REQUEST(cx);
michael@0 4057 assertSameCompartment(cx, obj);
michael@0 4058
michael@0 4059 RootedObject ctor(cx);
michael@0 4060
michael@0 4061 for (; fs->name; fs++) {
michael@0 4062 RootedAtom atom(cx);
michael@0 4063 // If the name starts with "@@", it must be a well-known symbol.
michael@0 4064 if (fs->name[0] != '@' || fs->name[1] != '@')
michael@0 4065 atom = Atomize(cx, fs->name, strlen(fs->name));
michael@0 4066 else if (strcmp(fs->name, "@@iterator") == 0)
michael@0 4067 // FIXME: This atom should be a symbol: bug 918828.
michael@0 4068 atom = cx->names().std_iterator;
michael@0 4069 else
michael@0 4070 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_SYMBOL, fs->name);
michael@0 4071 if (!atom)
michael@0 4072 return false;
michael@0 4073
michael@0 4074 Rooted<jsid> id(cx, AtomToId(atom));
michael@0 4075
michael@0 4076 /*
michael@0 4077 * Define a generic arity N+1 static method for the arity N prototype
michael@0 4078 * method if flags contains JSFUN_GENERIC_NATIVE.
michael@0 4079 */
michael@0 4080 unsigned flags = fs->flags;
michael@0 4081 if (flags & JSFUN_GENERIC_NATIVE) {
michael@0 4082 if (!ctor) {
michael@0 4083 ctor = JS_GetConstructor(cx, obj);
michael@0 4084 if (!ctor)
michael@0 4085 return false;
michael@0 4086 }
michael@0 4087
michael@0 4088 flags &= ~JSFUN_GENERIC_NATIVE;
michael@0 4089 JSFunction *fun = DefineFunction(cx, ctor, id,
michael@0 4090 js_generic_native_method_dispatcher,
michael@0 4091 fs->nargs + 1, flags,
michael@0 4092 JSFunction::ExtendedFinalizeKind);
michael@0 4093 if (!fun)
michael@0 4094 return false;
michael@0 4095
michael@0 4096 /*
michael@0 4097 * As jsapi.h notes, fs must point to storage that lives as long
michael@0 4098 * as fun->object lives.
michael@0 4099 */
michael@0 4100 fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs)));
michael@0 4101 }
michael@0 4102
michael@0 4103 /*
michael@0 4104 * Delay cloning self-hosted functions until they are called. This is
michael@0 4105 * achieved by passing DefineFunction a nullptr JSNative which
michael@0 4106 * produces an interpreted JSFunction where !hasScript. Interpreted
michael@0 4107 * call paths then call InitializeLazyFunctionScript if !hasScript.
michael@0 4108 */
michael@0 4109 if (fs->selfHostedName) {
michael@0 4110 JS_ASSERT(!fs->call.op);
michael@0 4111 JS_ASSERT(!fs->call.info);
michael@0 4112 /*
michael@0 4113 * During creation of the self-hosting global, we ignore all
michael@0 4114 * self-hosted functions, as that means we're currently setting up
michael@0 4115 * the global object that the self-hosted code is then compiled
michael@0 4116 * in. Self-hosted functions can access each other via their names,
michael@0 4117 * but not via the builtin classes they get installed into.
michael@0 4118 */
michael@0 4119 if (cx->runtime()->isSelfHostingGlobal(cx->global()))
michael@0 4120 continue;
michael@0 4121
michael@0 4122 RootedAtom shName(cx, Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName)));
michael@0 4123 if (!shName)
michael@0 4124 return false;
michael@0 4125 RootedValue funVal(cx);
michael@0 4126 if (!cx->global()->getSelfHostedFunction(cx, shName, atom, fs->nargs, &funVal))
michael@0 4127 return false;
michael@0 4128 if (!JSObject::defineGeneric(cx, obj, id, funVal, nullptr, nullptr, flags))
michael@0 4129 return false;
michael@0 4130 } else {
michael@0 4131 JSFunction *fun = DefineFunction(cx, obj, id, fs->call.op, fs->nargs, flags);
michael@0 4132 if (!fun)
michael@0 4133 return false;
michael@0 4134 if (fs->call.info)
michael@0 4135 fun->setJitInfo(fs->call.info);
michael@0 4136 }
michael@0 4137 }
michael@0 4138 return true;
michael@0 4139 }
michael@0 4140
michael@0 4141 JS_PUBLIC_API(JSFunction *)
michael@0 4142 JS_DefineFunction(JSContext *cx, HandleObject obj, const char *name, JSNative call,
michael@0 4143 unsigned nargs, unsigned attrs)
michael@0 4144 {
michael@0 4145 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4146 AssertHeapIsIdle(cx);
michael@0 4147 CHECK_REQUEST(cx);
michael@0 4148 assertSameCompartment(cx, obj);
michael@0 4149 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 4150 if (!atom)
michael@0 4151 return nullptr;
michael@0 4152 Rooted<jsid> id(cx, AtomToId(atom));
michael@0 4153 return DefineFunction(cx, obj, id, call, nargs, attrs);
michael@0 4154 }
michael@0 4155
michael@0 4156 JS_PUBLIC_API(JSFunction *)
michael@0 4157 JS_DefineUCFunction(JSContext *cx, HandleObject obj,
michael@0 4158 const jschar *name, size_t namelen, JSNative call,
michael@0 4159 unsigned nargs, unsigned attrs)
michael@0 4160 {
michael@0 4161 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4162 AssertHeapIsIdle(cx);
michael@0 4163 CHECK_REQUEST(cx);
michael@0 4164 assertSameCompartment(cx, obj);
michael@0 4165 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
michael@0 4166 if (!atom)
michael@0 4167 return nullptr;
michael@0 4168 Rooted<jsid> id(cx, AtomToId(atom));
michael@0 4169 return DefineFunction(cx, obj, id, call, nargs, attrs);
michael@0 4170 }
michael@0 4171
michael@0 4172 extern JS_PUBLIC_API(JSFunction *)
michael@0 4173 JS_DefineFunctionById(JSContext *cx, HandleObject obj, HandleId id, JSNative call,
michael@0 4174 unsigned nargs, unsigned attrs)
michael@0 4175 {
michael@0 4176 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4177 AssertHeapIsIdle(cx);
michael@0 4178 CHECK_REQUEST(cx);
michael@0 4179 assertSameCompartment(cx, obj);
michael@0 4180 return DefineFunction(cx, obj, id, call, nargs, attrs);
michael@0 4181 }
michael@0 4182
michael@0 4183 struct AutoLastFrameCheck
michael@0 4184 {
michael@0 4185 AutoLastFrameCheck(JSContext *cx
michael@0 4186 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 4187 : cx(cx)
michael@0 4188 {
michael@0 4189 JS_ASSERT(cx);
michael@0 4190 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 4191 }
michael@0 4192
michael@0 4193 ~AutoLastFrameCheck() {
michael@0 4194 if (cx->isExceptionPending() &&
michael@0 4195 !JS_IsRunning(cx) &&
michael@0 4196 !cx->options().dontReportUncaught()) {
michael@0 4197 js_ReportUncaughtException(cx);
michael@0 4198 }
michael@0 4199 }
michael@0 4200
michael@0 4201 private:
michael@0 4202 JSContext *cx;
michael@0 4203 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
michael@0 4204 };
michael@0 4205
michael@0 4206 /* Use the fastest available getc. */
michael@0 4207 #if defined(HAVE_GETC_UNLOCKED)
michael@0 4208 # define fast_getc getc_unlocked
michael@0 4209 #elif defined(HAVE__GETC_NOLOCK)
michael@0 4210 # define fast_getc _getc_nolock
michael@0 4211 #else
michael@0 4212 # define fast_getc getc
michael@0 4213 #endif
michael@0 4214
michael@0 4215 typedef js::Vector<char, 8, TempAllocPolicy> FileContents;
michael@0 4216
michael@0 4217 static bool
michael@0 4218 ReadCompleteFile(JSContext *cx, FILE *fp, FileContents &buffer)
michael@0 4219 {
michael@0 4220 /* Get the complete length of the file, if possible. */
michael@0 4221 struct stat st;
michael@0 4222 int ok = fstat(fileno(fp), &st);
michael@0 4223 if (ok != 0)
michael@0 4224 return false;
michael@0 4225 if (st.st_size > 0) {
michael@0 4226 if (!buffer.reserve(st.st_size))
michael@0 4227 return false;
michael@0 4228 }
michael@0 4229
michael@0 4230 // Read in the whole file. Note that we can't assume the data's length
michael@0 4231 // is actually st.st_size, because 1) some files lie about their size
michael@0 4232 // (/dev/zero and /dev/random), and 2) reading files in text mode on
michael@0 4233 // Windows collapses "\r\n" pairs to single \n characters.
michael@0 4234 for (;;) {
michael@0 4235 int c = fast_getc(fp);
michael@0 4236 if (c == EOF)
michael@0 4237 break;
michael@0 4238 if (!buffer.append(c))
michael@0 4239 return false;
michael@0 4240 }
michael@0 4241
michael@0 4242 return true;
michael@0 4243 }
michael@0 4244
michael@0 4245 namespace {
michael@0 4246
michael@0 4247 class AutoFile
michael@0 4248 {
michael@0 4249 FILE *fp_;
michael@0 4250 public:
michael@0 4251 AutoFile()
michael@0 4252 : fp_(nullptr)
michael@0 4253 {}
michael@0 4254 ~AutoFile()
michael@0 4255 {
michael@0 4256 if (fp_ && fp_ != stdin)
michael@0 4257 fclose(fp_);
michael@0 4258 }
michael@0 4259 FILE *fp() const { return fp_; }
michael@0 4260 bool open(JSContext *cx, const char *filename);
michael@0 4261 bool readAll(JSContext *cx, FileContents &buffer)
michael@0 4262 {
michael@0 4263 JS_ASSERT(fp_);
michael@0 4264 return ReadCompleteFile(cx, fp_, buffer);
michael@0 4265 }
michael@0 4266 };
michael@0 4267
michael@0 4268 } /* anonymous namespace */
michael@0 4269
michael@0 4270 /*
michael@0 4271 * Open a source file for reading. Supports "-" and nullptr to mean stdin. The
michael@0 4272 * return value must be fclosed unless it is stdin.
michael@0 4273 */
michael@0 4274 bool
michael@0 4275 AutoFile::open(JSContext *cx, const char *filename)
michael@0 4276 {
michael@0 4277 if (!filename || strcmp(filename, "-") == 0) {
michael@0 4278 fp_ = stdin;
michael@0 4279 } else {
michael@0 4280 fp_ = fopen(filename, "r");
michael@0 4281 if (!fp_) {
michael@0 4282 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_OPEN,
michael@0 4283 filename, "No such file or directory");
michael@0 4284 return false;
michael@0 4285 }
michael@0 4286 }
michael@0 4287 return true;
michael@0 4288 }
michael@0 4289
michael@0 4290 JSObject * const JS::ReadOnlyCompileOptions::nullObjectPtr = nullptr;
michael@0 4291
michael@0 4292 void
michael@0 4293 JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions &rhs)
michael@0 4294 {
michael@0 4295 version = rhs.version;
michael@0 4296 versionSet = rhs.versionSet;
michael@0 4297 utf8 = rhs.utf8;
michael@0 4298 lineno = rhs.lineno;
michael@0 4299 column = rhs.column;
michael@0 4300 compileAndGo = rhs.compileAndGo;
michael@0 4301 forEval = rhs.forEval;
michael@0 4302 noScriptRval = rhs.noScriptRval;
michael@0 4303 selfHostingMode = rhs.selfHostingMode;
michael@0 4304 canLazilyParse = rhs.canLazilyParse;
michael@0 4305 strictOption = rhs.strictOption;
michael@0 4306 extraWarningsOption = rhs.extraWarningsOption;
michael@0 4307 werrorOption = rhs.werrorOption;
michael@0 4308 asmJSOption = rhs.asmJSOption;
michael@0 4309 forceAsync = rhs.forceAsync;
michael@0 4310 installedFile = rhs.installedFile;
michael@0 4311 sourceIsLazy = rhs.sourceIsLazy;
michael@0 4312 introductionType = rhs.introductionType;
michael@0 4313 introductionLineno = rhs.introductionLineno;
michael@0 4314 introductionOffset = rhs.introductionOffset;
michael@0 4315 hasIntroductionInfo = rhs.hasIntroductionInfo;
michael@0 4316 }
michael@0 4317
michael@0 4318 JSPrincipals *
michael@0 4319 JS::ReadOnlyCompileOptions::originPrincipals(ExclusiveContext *cx) const
michael@0 4320 {
michael@0 4321 return NormalizeOriginPrincipals(cx->compartment()->principals, originPrincipals_);
michael@0 4322 }
michael@0 4323
michael@0 4324 JS::OwningCompileOptions::OwningCompileOptions(JSContext *cx)
michael@0 4325 : ReadOnlyCompileOptions(),
michael@0 4326 runtime(GetRuntime(cx)),
michael@0 4327 elementRoot(cx),
michael@0 4328 elementAttributeNameRoot(cx),
michael@0 4329 introductionScriptRoot(cx)
michael@0 4330 {
michael@0 4331 }
michael@0 4332
michael@0 4333 JS::OwningCompileOptions::~OwningCompileOptions()
michael@0 4334 {
michael@0 4335 if (originPrincipals_)
michael@0 4336 JS_DropPrincipals(runtime, originPrincipals_);
michael@0 4337
michael@0 4338 // OwningCompileOptions always owns these, so these casts are okay.
michael@0 4339 js_free(const_cast<char *>(filename_));
michael@0 4340 js_free(const_cast<jschar *>(sourceMapURL_));
michael@0 4341 js_free(const_cast<char *>(introducerFilename_));
michael@0 4342 }
michael@0 4343
michael@0 4344 bool
michael@0 4345 JS::OwningCompileOptions::copy(JSContext *cx, const ReadOnlyCompileOptions &rhs)
michael@0 4346 {
michael@0 4347 copyPODOptions(rhs);
michael@0 4348
michael@0 4349 setOriginPrincipals(rhs.originPrincipals(cx));
michael@0 4350 setElement(rhs.element());
michael@0 4351 setElementAttributeName(rhs.elementAttributeName());
michael@0 4352 setIntroductionScript(rhs.introductionScript());
michael@0 4353
michael@0 4354 return (setFileAndLine(cx, rhs.filename(), rhs.lineno) &&
michael@0 4355 setSourceMapURL(cx, rhs.sourceMapURL()) &&
michael@0 4356 setIntroducerFilename(cx, rhs.introducerFilename()));
michael@0 4357 }
michael@0 4358
michael@0 4359 bool
michael@0 4360 JS::OwningCompileOptions::setFile(JSContext *cx, const char *f)
michael@0 4361 {
michael@0 4362 char *copy = nullptr;
michael@0 4363 if (f) {
michael@0 4364 copy = JS_strdup(cx, f);
michael@0 4365 if (!copy)
michael@0 4366 return false;
michael@0 4367 }
michael@0 4368
michael@0 4369 // OwningCompileOptions always owns filename_, so this cast is okay.
michael@0 4370 js_free(const_cast<char *>(filename_));
michael@0 4371
michael@0 4372 filename_ = copy;
michael@0 4373 return true;
michael@0 4374 }
michael@0 4375
michael@0 4376 bool
michael@0 4377 JS::OwningCompileOptions::setFileAndLine(JSContext *cx, const char *f, unsigned l)
michael@0 4378 {
michael@0 4379 if (!setFile(cx, f))
michael@0 4380 return false;
michael@0 4381
michael@0 4382 lineno = l;
michael@0 4383 return true;
michael@0 4384 }
michael@0 4385
michael@0 4386 bool
michael@0 4387 JS::OwningCompileOptions::setSourceMapURL(JSContext *cx, const jschar *s)
michael@0 4388 {
michael@0 4389 jschar *copy = nullptr;
michael@0 4390 if (s) {
michael@0 4391 copy = js_strdup(cx, s);
michael@0 4392 if (!copy)
michael@0 4393 return false;
michael@0 4394 }
michael@0 4395
michael@0 4396 // OwningCompileOptions always owns sourceMapURL_, so this cast is okay.
michael@0 4397 js_free(const_cast<jschar *>(sourceMapURL_));
michael@0 4398
michael@0 4399 sourceMapURL_ = copy;
michael@0 4400 return true;
michael@0 4401 }
michael@0 4402
michael@0 4403 bool
michael@0 4404 JS::OwningCompileOptions::setIntroducerFilename(JSContext *cx, const char *s)
michael@0 4405 {
michael@0 4406 char *copy = nullptr;
michael@0 4407 if (s) {
michael@0 4408 copy = JS_strdup(cx, s);
michael@0 4409 if (!copy)
michael@0 4410 return false;
michael@0 4411 }
michael@0 4412
michael@0 4413 // OwningCompileOptions always owns introducerFilename_, so this cast is okay.
michael@0 4414 js_free(const_cast<char *>(introducerFilename_));
michael@0 4415
michael@0 4416 introducerFilename_ = copy;
michael@0 4417 return true;
michael@0 4418 }
michael@0 4419
michael@0 4420 bool
michael@0 4421 JS::OwningCompileOptions::wrap(JSContext *cx, JSCompartment *compartment)
michael@0 4422 {
michael@0 4423 if (!compartment->wrap(cx, &elementRoot))
michael@0 4424 return false;
michael@0 4425 if (elementAttributeNameRoot) {
michael@0 4426 if (!compartment->wrap(cx, elementAttributeNameRoot.address()))
michael@0 4427 return false;
michael@0 4428 }
michael@0 4429
michael@0 4430 // There is no equivalent of cross-compartment wrappers for scripts. If
michael@0 4431 // the introduction script would be in a different compartment from the
michael@0 4432 // compiled code, we would be creating a cross-compartment script
michael@0 4433 // reference, which would be bogus. In that case, just don't bother to
michael@0 4434 // retain the introduction script.
michael@0 4435 if (introductionScriptRoot) {
michael@0 4436 if (introductionScriptRoot->compartment() != compartment)
michael@0 4437 introductionScriptRoot = nullptr;
michael@0 4438 }
michael@0 4439
michael@0 4440 return true;
michael@0 4441 }
michael@0 4442
michael@0 4443 JS::CompileOptions::CompileOptions(JSContext *cx, JSVersion version)
michael@0 4444 : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx),
michael@0 4445 introductionScriptRoot(cx)
michael@0 4446 {
michael@0 4447 this->version = (version != JSVERSION_UNKNOWN) ? version : cx->findVersion();
michael@0 4448
michael@0 4449 compileAndGo = false;
michael@0 4450 noScriptRval = cx->options().noScriptRval();
michael@0 4451 strictOption = cx->options().strictMode();
michael@0 4452 extraWarningsOption = cx->options().extraWarnings();
michael@0 4453 werrorOption = cx->options().werror();
michael@0 4454 asmJSOption = cx->runtime()->options().asmJS();
michael@0 4455 }
michael@0 4456
michael@0 4457 bool
michael@0 4458 JS::CompileOptions::wrap(JSContext *cx, JSCompartment *compartment)
michael@0 4459 {
michael@0 4460 if (!compartment->wrap(cx, &elementRoot))
michael@0 4461 return false;
michael@0 4462 if (elementAttributeNameRoot) {
michael@0 4463 if (!compartment->wrap(cx, elementAttributeNameRoot.address()))
michael@0 4464 return false;
michael@0 4465 }
michael@0 4466
michael@0 4467 // There is no equivalent of cross-compartment wrappers for scripts. If
michael@0 4468 // the introduction script would be in a different compartment from the
michael@0 4469 // compiled code, we would be creating a cross-compartment script
michael@0 4470 // reference, which would be bogus. In that case, just don't bother to
michael@0 4471 // retain the introduction script.
michael@0 4472 if (introductionScriptRoot) {
michael@0 4473 if (introductionScriptRoot->compartment() != compartment)
michael@0 4474 introductionScriptRoot = nullptr;
michael@0 4475 }
michael@0 4476
michael@0 4477 return true;
michael@0 4478 }
michael@0 4479
michael@0 4480 bool
michael@0 4481 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
michael@0 4482 SourceBufferHolder &srcBuf, MutableHandleScript script)
michael@0 4483 {
michael@0 4484 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4485 AssertHeapIsIdle(cx);
michael@0 4486 CHECK_REQUEST(cx);
michael@0 4487 assertSameCompartment(cx, obj);
michael@0 4488 AutoLastFrameCheck lfc(cx);
michael@0 4489
michael@0 4490 script.set(frontend::CompileScript(cx, &cx->tempLifoAlloc(), obj, NullPtr(), options, srcBuf));
michael@0 4491 return !!script;
michael@0 4492 }
michael@0 4493
michael@0 4494 JSScript *
michael@0 4495 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
michael@0 4496 const jschar *chars, size_t length)
michael@0 4497 {
michael@0 4498 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
michael@0 4499 RootedScript script(cx);
michael@0 4500 if (!Compile(cx, obj, options, srcBuf, &script))
michael@0 4501 return nullptr;
michael@0 4502 return script;
michael@0 4503 }
michael@0 4504
michael@0 4505 JSScript *
michael@0 4506 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
michael@0 4507 const char *bytes, size_t length)
michael@0 4508 {
michael@0 4509 jschar *chars;
michael@0 4510 if (options.utf8)
michael@0 4511 chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
michael@0 4512 else
michael@0 4513 chars = InflateString(cx, bytes, &length);
michael@0 4514 if (!chars)
michael@0 4515 return nullptr;
michael@0 4516
michael@0 4517 JSScript *script = Compile(cx, obj, options, chars, length);
michael@0 4518 js_free(chars);
michael@0 4519 return script;
michael@0 4520 }
michael@0 4521
michael@0 4522 JSScript *
michael@0 4523 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, FILE *fp)
michael@0 4524 {
michael@0 4525 FileContents buffer(cx);
michael@0 4526 if (!ReadCompleteFile(cx, fp, buffer))
michael@0 4527 return nullptr;
michael@0 4528
michael@0 4529 JSScript *script = Compile(cx, obj, options, buffer.begin(), buffer.length());
michael@0 4530 return script;
michael@0 4531 }
michael@0 4532
michael@0 4533 JSScript *
michael@0 4534 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, const char *filename)
michael@0 4535 {
michael@0 4536 AutoFile file;
michael@0 4537 if (!file.open(cx, filename))
michael@0 4538 return nullptr;
michael@0 4539 CompileOptions options(cx, optionsArg);
michael@0 4540 options.setFileAndLine(filename, 1);
michael@0 4541 return Compile(cx, obj, options, file.fp());
michael@0 4542 }
michael@0 4543
michael@0 4544 JS_PUBLIC_API(bool)
michael@0 4545 JS::CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, size_t length)
michael@0 4546 {
michael@0 4547 static const size_t TINY_LENGTH = 1000;
michael@0 4548 static const size_t HUGE_LENGTH = 100 * 1000;
michael@0 4549
michael@0 4550 // These are heuristics which the caller may choose to ignore (e.g., for
michael@0 4551 // testing purposes).
michael@0 4552 if (!options.forceAsync) {
michael@0 4553 // Compiling off the main thread inolves creating a new Zone and other
michael@0 4554 // significant overheads. Don't bother if the script is tiny.
michael@0 4555 if (length < TINY_LENGTH)
michael@0 4556 return false;
michael@0 4557
michael@0 4558 #ifdef JS_THREADSAFE
michael@0 4559 // If the parsing task would have to wait for GC to complete, it'll probably
michael@0 4560 // be faster to just start it synchronously on the main thread unless the
michael@0 4561 // script is huge.
michael@0 4562 if (OffThreadParsingMustWaitForGC(cx->runtime()) && length < HUGE_LENGTH)
michael@0 4563 return false;
michael@0 4564 #endif // JS_THREADSAFE
michael@0 4565 }
michael@0 4566
michael@0 4567 return cx->runtime()->canUseParallelParsing();
michael@0 4568 }
michael@0 4569
michael@0 4570 JS_PUBLIC_API(bool)
michael@0 4571 JS::CompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options,
michael@0 4572 const jschar *chars, size_t length,
michael@0 4573 OffThreadCompileCallback callback, void *callbackData)
michael@0 4574 {
michael@0 4575 JS_ASSERT(CanCompileOffThread(cx, options, length));
michael@0 4576 return StartOffThreadParseScript(cx, options, chars, length, callback, callbackData);
michael@0 4577 }
michael@0 4578
michael@0 4579 JS_PUBLIC_API(JSScript *)
michael@0 4580 JS::FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token)
michael@0 4581 {
michael@0 4582 #ifdef JS_THREADSAFE
michael@0 4583 JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
michael@0 4584
michael@0 4585 if (maybecx) {
michael@0 4586 RootedScript script(maybecx);
michael@0 4587 {
michael@0 4588 AutoLastFrameCheck lfc(maybecx);
michael@0 4589 script = WorkerThreadState().finishParseTask(maybecx, rt, token);
michael@0 4590 }
michael@0 4591 return script;
michael@0 4592 } else {
michael@0 4593 return WorkerThreadState().finishParseTask(maybecx, rt, token);
michael@0 4594 }
michael@0 4595 #else
michael@0 4596 MOZ_ASSUME_UNREACHABLE("Off thread compilation is not available.");
michael@0 4597 #endif
michael@0 4598 }
michael@0 4599
michael@0 4600 JS_PUBLIC_API(JSScript *)
michael@0 4601 JS_CompileScript(JSContext *cx, JS::HandleObject obj, const char *ascii,
michael@0 4602 size_t length, const JS::CompileOptions &options)
michael@0 4603 {
michael@0 4604 return Compile(cx, obj, options, ascii, length);
michael@0 4605 }
michael@0 4606
michael@0 4607 JS_PUBLIC_API(JSScript *)
michael@0 4608 JS_CompileUCScript(JSContext *cx, JS::HandleObject obj, const jschar *chars,
michael@0 4609 size_t length, const JS::CompileOptions &options)
michael@0 4610 {
michael@0 4611 return Compile(cx, obj, options, chars, length);
michael@0 4612 }
michael@0 4613
michael@0 4614 JS_PUBLIC_API(bool)
michael@0 4615 JS_BufferIsCompilableUnit(JSContext *cx, HandleObject obj, const char *utf8, size_t length)
michael@0 4616 {
michael@0 4617 AssertHeapIsIdle(cx);
michael@0 4618 CHECK_REQUEST(cx);
michael@0 4619 assertSameCompartment(cx, obj);
michael@0 4620
michael@0 4621 cx->clearPendingException();
michael@0 4622
michael@0 4623 jschar *chars = JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(utf8, length), &length).get();
michael@0 4624 if (!chars)
michael@0 4625 return true;
michael@0 4626
michael@0 4627 // Return true on any out-of-memory error or non-EOF-related syntax error, so our
michael@0 4628 // caller doesn't try to collect more buffered source.
michael@0 4629 bool result = true;
michael@0 4630
michael@0 4631 CompileOptions options(cx);
michael@0 4632 options.setCompileAndGo(false);
michael@0 4633 Parser<frontend::FullParseHandler> parser(cx, &cx->tempLifoAlloc(),
michael@0 4634 options, chars, length,
michael@0 4635 /* foldConstants = */ true, nullptr, nullptr);
michael@0 4636 JSErrorReporter older = JS_SetErrorReporter(cx, nullptr);
michael@0 4637 if (!parser.parse(obj)) {
michael@0 4638 // We ran into an error. If it was because we ran out of source, we
michael@0 4639 // return false so our caller knows to try to collect more buffered
michael@0 4640 // source.
michael@0 4641 if (parser.isUnexpectedEOF())
michael@0 4642 result = false;
michael@0 4643
michael@0 4644 cx->clearPendingException();
michael@0 4645 }
michael@0 4646 JS_SetErrorReporter(cx, older);
michael@0 4647
michael@0 4648 js_free(chars);
michael@0 4649 return result;
michael@0 4650 }
michael@0 4651
michael@0 4652 JS_PUBLIC_API(JSObject *)
michael@0 4653 JS_GetGlobalFromScript(JSScript *script)
michael@0 4654 {
michael@0 4655 JS_ASSERT(!script->isCachedEval());
michael@0 4656 return &script->global();
michael@0 4657 }
michael@0 4658
michael@0 4659 JS_PUBLIC_API(bool)
michael@0 4660 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
michael@0 4661 const char *name, unsigned nargs, const char *const *argnames,
michael@0 4662 SourceBufferHolder &srcBuf, MutableHandleFunction fun)
michael@0 4663 {
michael@0 4664 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4665 AssertHeapIsIdle(cx);
michael@0 4666 CHECK_REQUEST(cx);
michael@0 4667 assertSameCompartment(cx, obj);
michael@0 4668 RootedAtom funAtom(cx);
michael@0 4669 AutoLastFrameCheck lfc(cx);
michael@0 4670
michael@0 4671 if (name) {
michael@0 4672 funAtom = Atomize(cx, name, strlen(name));
michael@0 4673 if (!funAtom)
michael@0 4674 return false;
michael@0 4675 }
michael@0 4676
michael@0 4677 AutoNameVector formals(cx);
michael@0 4678 for (unsigned i = 0; i < nargs; i++) {
michael@0 4679 RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
michael@0 4680 if (!argAtom || !formals.append(argAtom->asPropertyName()))
michael@0 4681 return false;
michael@0 4682 }
michael@0 4683
michael@0 4684 fun.set(NewFunction(cx, NullPtr(), nullptr, 0, JSFunction::INTERPRETED, obj,
michael@0 4685 funAtom, JSFunction::FinalizeKind, TenuredObject));
michael@0 4686 if (!fun)
michael@0 4687 return false;
michael@0 4688
michael@0 4689 if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf))
michael@0 4690 return false;
michael@0 4691
michael@0 4692 if (obj && funAtom && options.defineOnScope) {
michael@0 4693 Rooted<jsid> id(cx, AtomToId(funAtom));
michael@0 4694 RootedValue value(cx, ObjectValue(*fun));
michael@0 4695 if (!JSObject::defineGeneric(cx, obj, id, value, nullptr, nullptr, JSPROP_ENUMERATE))
michael@0 4696 return false;
michael@0 4697 }
michael@0 4698
michael@0 4699 return true;
michael@0 4700 }
michael@0 4701
michael@0 4702 JS_PUBLIC_API(JSFunction *)
michael@0 4703 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
michael@0 4704 const char *name, unsigned nargs, const char *const *argnames,
michael@0 4705 const jschar *chars, size_t length)
michael@0 4706 {
michael@0 4707 RootedFunction fun(cx);
michael@0 4708 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
michael@0 4709 if (!JS::CompileFunction(cx, obj, options, name, nargs, argnames, srcBuf, &fun))
michael@0 4710 return nullptr;
michael@0 4711 return fun;
michael@0 4712 }
michael@0 4713
michael@0 4714 JS_PUBLIC_API(JSFunction *)
michael@0 4715 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
michael@0 4716 const char *name, unsigned nargs, const char *const *argnames,
michael@0 4717 const char *bytes, size_t length)
michael@0 4718 {
michael@0 4719 jschar *chars;
michael@0 4720 if (options.utf8)
michael@0 4721 chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
michael@0 4722 else
michael@0 4723 chars = InflateString(cx, bytes, &length);
michael@0 4724 if (!chars)
michael@0 4725 return nullptr;
michael@0 4726
michael@0 4727 JSFunction *fun = CompileFunction(cx, obj, options, name, nargs, argnames, chars, length);
michael@0 4728 js_free(chars);
michael@0 4729 return fun;
michael@0 4730 }
michael@0 4731
michael@0 4732 JS_PUBLIC_API(JSFunction *)
michael@0 4733 JS_CompileUCFunction(JSContext *cx, JS::HandleObject obj, const char *name,
michael@0 4734 unsigned nargs, const char *const *argnames,
michael@0 4735 const jschar *chars, size_t length,
michael@0 4736 const CompileOptions &options)
michael@0 4737 {
michael@0 4738 return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length);
michael@0 4739 }
michael@0 4740
michael@0 4741 JS_PUBLIC_API(JSFunction *)
michael@0 4742 JS_CompileFunction(JSContext *cx, JS::HandleObject obj, const char *name,
michael@0 4743 unsigned nargs, const char *const *argnames,
michael@0 4744 const char *ascii, size_t length,
michael@0 4745 const JS::CompileOptions &options)
michael@0 4746 {
michael@0 4747 return CompileFunction(cx, obj, options, name, nargs, argnames, ascii, length);
michael@0 4748 }
michael@0 4749
michael@0 4750 JS_PUBLIC_API(JSString *)
michael@0 4751 JS_DecompileScript(JSContext *cx, HandleScript script, const char *name, unsigned indent)
michael@0 4752 {
michael@0 4753 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4754
michael@0 4755 AssertHeapIsIdle(cx);
michael@0 4756 CHECK_REQUEST(cx);
michael@0 4757 script->ensureNonLazyCanonicalFunction(cx);
michael@0 4758 RootedFunction fun(cx, script->functionNonDelazifying());
michael@0 4759 if (fun)
michael@0 4760 return JS_DecompileFunction(cx, fun, indent);
michael@0 4761 bool haveSource = script->scriptSource()->hasSourceData();
michael@0 4762 if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
michael@0 4763 return nullptr;
michael@0 4764 return haveSource ? script->sourceData(cx) : js_NewStringCopyZ<CanGC>(cx, "[no source]");
michael@0 4765 }
michael@0 4766
michael@0 4767 JS_PUBLIC_API(JSString *)
michael@0 4768 JS_DecompileFunction(JSContext *cx, HandleFunction fun, unsigned indent)
michael@0 4769 {
michael@0 4770 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4771 AssertHeapIsIdle(cx);
michael@0 4772 CHECK_REQUEST(cx);
michael@0 4773 assertSameCompartment(cx, fun);
michael@0 4774 return FunctionToString(cx, fun, false, !(indent & JS_DONT_PRETTY_PRINT));
michael@0 4775 }
michael@0 4776
michael@0 4777 JS_PUBLIC_API(JSString *)
michael@0 4778 JS_DecompileFunctionBody(JSContext *cx, HandleFunction fun, unsigned indent)
michael@0 4779 {
michael@0 4780 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4781 AssertHeapIsIdle(cx);
michael@0 4782 CHECK_REQUEST(cx);
michael@0 4783 assertSameCompartment(cx, fun);
michael@0 4784 return FunctionToString(cx, fun, true, !(indent & JS_DONT_PRETTY_PRINT));
michael@0 4785 }
michael@0 4786
michael@0 4787 MOZ_NEVER_INLINE static bool
michael@0 4788 ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg, jsval *rval)
michael@0 4789 {
michael@0 4790 RootedScript script(cx, scriptArg);
michael@0 4791
michael@0 4792 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4793 AssertHeapIsIdle(cx);
michael@0 4794 CHECK_REQUEST(cx);
michael@0 4795 assertSameCompartment(cx, obj, scriptArg);
michael@0 4796 AutoLastFrameCheck lfc(cx);
michael@0 4797 return Execute(cx, script, *obj, rval);
michael@0 4798 }
michael@0 4799
michael@0 4800 MOZ_NEVER_INLINE JS_PUBLIC_API(bool)
michael@0 4801 JS_ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg, MutableHandleValue rval)
michael@0 4802 {
michael@0 4803 return ExecuteScript(cx, obj, scriptArg, rval.address());
michael@0 4804 }
michael@0 4805
michael@0 4806 MOZ_NEVER_INLINE JS_PUBLIC_API(bool)
michael@0 4807 JS_ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg)
michael@0 4808 {
michael@0 4809 return ExecuteScript(cx, obj, scriptArg, nullptr);
michael@0 4810 }
michael@0 4811
michael@0 4812 JS_PUBLIC_API(bool)
michael@0 4813 JS::CloneAndExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg)
michael@0 4814 {
michael@0 4815 CHECK_REQUEST(cx);
michael@0 4816 assertSameCompartment(cx, obj);
michael@0 4817 RootedScript script(cx, scriptArg);
michael@0 4818 if (script->compartment() != cx->compartment()) {
michael@0 4819 script = CloneScript(cx, NullPtr(), NullPtr(), script);
michael@0 4820 if (!script)
michael@0 4821 return false;
michael@0 4822 }
michael@0 4823 return ExecuteScript(cx, obj, script, nullptr);
michael@0 4824 }
michael@0 4825
michael@0 4826 JS_PUBLIC_API(bool)
michael@0 4827 JS_ExecuteScriptVersion(JSContext *cx, HandleObject obj, HandleScript script,
michael@0 4828 MutableHandleValue rval, JSVersion version)
michael@0 4829 {
michael@0 4830 return ExecuteScript(cx, obj, script, rval.address());
michael@0 4831 }
michael@0 4832
michael@0 4833 JS_PUBLIC_API(bool)
michael@0 4834 JS_ExecuteScriptVersion(JSContext *cx, HandleObject obj, HandleScript script, JSVersion version)
michael@0 4835 {
michael@0 4836 return ExecuteScript(cx, obj, script, nullptr);
michael@0 4837 }
michael@0 4838
michael@0 4839 static const unsigned LARGE_SCRIPT_LENGTH = 500*1024;
michael@0 4840
michael@0 4841 static bool
michael@0 4842 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
michael@0 4843 SourceBufferHolder &srcBuf, JS::Value *rval)
michael@0 4844 {
michael@0 4845 CompileOptions options(cx, optionsArg);
michael@0 4846 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 4847 AssertHeapIsIdle(cx);
michael@0 4848 CHECK_REQUEST(cx);
michael@0 4849 assertSameCompartment(cx, obj);
michael@0 4850
michael@0 4851 AutoLastFrameCheck lfc(cx);
michael@0 4852
michael@0 4853 options.setCompileAndGo(obj->is<GlobalObject>());
michael@0 4854 options.setNoScriptRval(!rval);
michael@0 4855 SourceCompressionTask sct(cx);
michael@0 4856 RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(),
michael@0 4857 obj, NullPtr(), options,
michael@0 4858 srcBuf, nullptr, 0, &sct));
michael@0 4859 if (!script)
michael@0 4860 return false;
michael@0 4861
michael@0 4862 JS_ASSERT(script->getVersion() == options.version);
michael@0 4863
michael@0 4864 bool result = Execute(cx, script, *obj, rval);
michael@0 4865 if (!sct.complete())
michael@0 4866 result = false;
michael@0 4867
michael@0 4868 // After evaluation, the compiled script will not be run again.
michael@0 4869 // script->ensureRanAnalysis allocated 1 analyze::Bytecode for every opcode
michael@0 4870 // which for large scripts means significant memory. Perform a GC eagerly
michael@0 4871 // to clear out this analysis data before anything happens to inhibit the
michael@0 4872 // flushing of this memory (such as setting requestAnimationFrame).
michael@0 4873 if (script->length() > LARGE_SCRIPT_LENGTH) {
michael@0 4874 script = nullptr;
michael@0 4875 PrepareZoneForGC(cx->zone());
michael@0 4876 GC(cx->runtime(), GC_NORMAL, JS::gcreason::FINISH_LARGE_EVALUTE);
michael@0 4877 }
michael@0 4878
michael@0 4879 return result;
michael@0 4880 }
michael@0 4881
michael@0 4882 static bool
michael@0 4883 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
michael@0 4884 const jschar *chars, size_t length, JS::Value *rval)
michael@0 4885 {
michael@0 4886 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
michael@0 4887 return ::Evaluate(cx, obj, optionsArg, srcBuf, rval);
michael@0 4888 }
michael@0 4889
michael@0 4890 static bool
michael@0 4891 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
michael@0 4892 const char *bytes, size_t length, JS::Value *rval)
michael@0 4893 {
michael@0 4894 jschar *chars;
michael@0 4895 if (options.utf8)
michael@0 4896 chars = UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(bytes, length), &length).get();
michael@0 4897 else
michael@0 4898 chars = InflateString(cx, bytes, &length);
michael@0 4899 if (!chars)
michael@0 4900 return false;
michael@0 4901
michael@0 4902 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::GiveOwnership);
michael@0 4903 bool ok = ::Evaluate(cx, obj, options, srcBuf, rval);
michael@0 4904 return ok;
michael@0 4905 }
michael@0 4906
michael@0 4907 static bool
michael@0 4908 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
michael@0 4909 const char *filename, JS::Value *rval)
michael@0 4910 {
michael@0 4911 FileContents buffer(cx);
michael@0 4912 {
michael@0 4913 AutoFile file;
michael@0 4914 if (!file.open(cx, filename) || !file.readAll(cx, buffer))
michael@0 4915 return false;
michael@0 4916 }
michael@0 4917
michael@0 4918 CompileOptions options(cx, optionsArg);
michael@0 4919 options.setFileAndLine(filename, 1);
michael@0 4920 return Evaluate(cx, obj, options, buffer.begin(), buffer.length(), rval);
michael@0 4921 }
michael@0 4922
michael@0 4923 extern JS_PUBLIC_API(bool)
michael@0 4924 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
michael@0 4925 SourceBufferHolder &srcBuf, MutableHandleValue rval)
michael@0 4926 {
michael@0 4927 return ::Evaluate(cx, obj, optionsArg, srcBuf, rval.address());
michael@0 4928 }
michael@0 4929
michael@0 4930 extern JS_PUBLIC_API(bool)
michael@0 4931 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
michael@0 4932 const jschar *chars, size_t length, MutableHandleValue rval)
michael@0 4933 {
michael@0 4934 return ::Evaluate(cx, obj, optionsArg, chars, length, rval.address());
michael@0 4935 }
michael@0 4936
michael@0 4937 extern JS_PUBLIC_API(bool)
michael@0 4938 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
michael@0 4939 const char *bytes, size_t length, MutableHandleValue rval)
michael@0 4940 {
michael@0 4941 return ::Evaluate(cx, obj, options, bytes, length, rval.address());
michael@0 4942 }
michael@0 4943
michael@0 4944 extern JS_PUBLIC_API(bool)
michael@0 4945 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
michael@0 4946 const char *filename, MutableHandleValue rval)
michael@0 4947 {
michael@0 4948 return ::Evaluate(cx, obj, optionsArg, filename, rval.address());
michael@0 4949 }
michael@0 4950
michael@0 4951 extern JS_PUBLIC_API(bool)
michael@0 4952 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
michael@0 4953 SourceBufferHolder &srcBuf)
michael@0 4954 {
michael@0 4955 return ::Evaluate(cx, obj, optionsArg, srcBuf, nullptr);
michael@0 4956 }
michael@0 4957
michael@0 4958 extern JS_PUBLIC_API(bool)
michael@0 4959 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
michael@0 4960 const jschar *chars, size_t length)
michael@0 4961 {
michael@0 4962 return ::Evaluate(cx, obj, optionsArg, chars, length, nullptr);
michael@0 4963 }
michael@0 4964
michael@0 4965 extern JS_PUBLIC_API(bool)
michael@0 4966 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
michael@0 4967 const char *bytes, size_t length)
michael@0 4968 {
michael@0 4969 return ::Evaluate(cx, obj, options, bytes, length, nullptr);
michael@0 4970 }
michael@0 4971
michael@0 4972 extern JS_PUBLIC_API(bool)
michael@0 4973 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
michael@0 4974 const char *filename)
michael@0 4975 {
michael@0 4976 return ::Evaluate(cx, obj, optionsArg, filename, nullptr);
michael@0 4977 }
michael@0 4978
michael@0 4979 JS_PUBLIC_API(bool)
michael@0 4980 JS_EvaluateUCScript(JSContext *cx, HandleObject obj, const jschar *chars, unsigned length,
michael@0 4981 const char *filename, unsigned lineno, MutableHandleValue rval)
michael@0 4982 {
michael@0 4983 CompileOptions options(cx);
michael@0 4984 options.setFileAndLine(filename, lineno);
michael@0 4985
michael@0 4986 return ::Evaluate(cx, obj, options, chars, length, rval.address());
michael@0 4987 }
michael@0 4988
michael@0 4989 JS_PUBLIC_API(bool)
michael@0 4990 JS_EvaluateUCScript(JSContext *cx, HandleObject obj, SourceBufferHolder &srcBuf,
michael@0 4991 const char *filename, unsigned lineno, MutableHandleValue rval)
michael@0 4992 {
michael@0 4993 CompileOptions options(cx);
michael@0 4994 options.setFileAndLine(filename, lineno);
michael@0 4995
michael@0 4996 return ::Evaluate(cx, obj, options, srcBuf, rval.address());
michael@0 4997 }
michael@0 4998
michael@0 4999 JS_PUBLIC_API(bool)
michael@0 5000 JS_EvaluateScript(JSContext *cx, HandleObject obj, const char *bytes, unsigned nbytes,
michael@0 5001 const char *filename, unsigned lineno, MutableHandleValue rval)
michael@0 5002 {
michael@0 5003 CompileOptions options(cx);
michael@0 5004 options.setFileAndLine(filename, lineno);
michael@0 5005
michael@0 5006 return ::Evaluate(cx, obj, options, bytes, nbytes, rval.address());
michael@0 5007 }
michael@0 5008
michael@0 5009 JS_PUBLIC_API(bool)
michael@0 5010 JS_EvaluateScript(JSContext *cx, HandleObject obj, const char *bytes, unsigned nbytes,
michael@0 5011 const char *filename, unsigned lineno)
michael@0 5012 {
michael@0 5013 CompileOptions options(cx);
michael@0 5014 options.setFileAndLine(filename, lineno);
michael@0 5015
michael@0 5016 return ::Evaluate(cx, obj, options, bytes, nbytes, nullptr);
michael@0 5017 }
michael@0 5018
michael@0 5019 JS_PUBLIC_API(bool)
michael@0 5020 JS_CallFunction(JSContext *cx, HandleObject obj, HandleFunction fun, const HandleValueArray& args,
michael@0 5021 MutableHandleValue rval)
michael@0 5022 {
michael@0 5023 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 5024 AssertHeapIsIdle(cx);
michael@0 5025 CHECK_REQUEST(cx);
michael@0 5026 assertSameCompartment(cx, obj, fun, args);
michael@0 5027 AutoLastFrameCheck lfc(cx);
michael@0 5028
michael@0 5029 return Invoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), args.length(), args.begin(), rval);
michael@0 5030 }
michael@0 5031
michael@0 5032 JS_PUBLIC_API(bool)
michael@0 5033 JS_CallFunctionName(JSContext *cx, HandleObject obj, const char *name, const HandleValueArray& args,
michael@0 5034 MutableHandleValue rval)
michael@0 5035 {
michael@0 5036 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 5037 AssertHeapIsIdle(cx);
michael@0 5038 CHECK_REQUEST(cx);
michael@0 5039 assertSameCompartment(cx, obj, args);
michael@0 5040 AutoLastFrameCheck lfc(cx);
michael@0 5041
michael@0 5042 JSAtom *atom = Atomize(cx, name, strlen(name));
michael@0 5043 if (!atom)
michael@0 5044 return false;
michael@0 5045
michael@0 5046 RootedValue v(cx);
michael@0 5047 RootedId id(cx, AtomToId(atom));
michael@0 5048 if (!JSObject::getGeneric(cx, obj, obj, id, &v))
michael@0 5049 return false;
michael@0 5050
michael@0 5051 return Invoke(cx, ObjectOrNullValue(obj), v, args.length(), args.begin(), rval);
michael@0 5052 }
michael@0 5053
michael@0 5054 JS_PUBLIC_API(bool)
michael@0 5055 JS_CallFunctionValue(JSContext *cx, HandleObject obj, HandleValue fval, const HandleValueArray& args,
michael@0 5056 MutableHandleValue rval)
michael@0 5057 {
michael@0 5058 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
michael@0 5059 AssertHeapIsIdle(cx);
michael@0 5060 CHECK_REQUEST(cx);
michael@0 5061 assertSameCompartment(cx, obj, fval, args);
michael@0 5062 AutoLastFrameCheck lfc(cx);
michael@0 5063
michael@0 5064 return Invoke(cx, ObjectOrNullValue(obj), fval, args.length(), args.begin(), rval);
michael@0 5065 }
michael@0 5066
michael@0 5067 JS_PUBLIC_API(bool)
michael@0 5068 JS::Call(JSContext *cx, HandleValue thisv, HandleValue fval, const JS::HandleValueArray& args,
michael@0 5069 MutableHandleValue rval)
michael@0 5070 {
michael@0 5071 AssertHeapIsIdle(cx);
michael@0 5072 CHECK_REQUEST(cx);
michael@0 5073 assertSameCompartment(cx, thisv, fval, args);
michael@0 5074 AutoLastFrameCheck lfc(cx);
michael@0 5075
michael@0 5076 return Invoke(cx, thisv, fval, args.length(), args.begin(), rval);
michael@0 5077 }
michael@0 5078
michael@0 5079 static JSObject *
michael@0 5080 JS_NewHelper(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
michael@0 5081 {
michael@0 5082 AssertHeapIsIdle(cx);
michael@0 5083 CHECK_REQUEST(cx);
michael@0 5084 assertSameCompartment(cx, ctor, inputArgs);
michael@0 5085
michael@0 5086 // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
michael@0 5087 // is not a simple variation of JSOP_CALL. We have to determine what class
michael@0 5088 // of object to create, create it, and clamp the return value to an object,
michael@0 5089 // among other details. InvokeConstructor does the hard work.
michael@0 5090 InvokeArgs args(cx);
michael@0 5091 if (!args.init(inputArgs.length()))
michael@0 5092 return nullptr;
michael@0 5093
michael@0 5094 args.setCallee(ObjectValue(*ctor));
michael@0 5095 args.setThis(NullValue());
michael@0 5096 PodCopy(args.array(), inputArgs.begin(), inputArgs.length());
michael@0 5097
michael@0 5098 if (!InvokeConstructor(cx, args))
michael@0 5099 return nullptr;
michael@0 5100
michael@0 5101 if (!args.rval().isObject()) {
michael@0 5102 /*
michael@0 5103 * Although constructors may return primitives (via proxies), this
michael@0 5104 * API is asking for an object, so we report an error.
michael@0 5105 */
michael@0 5106 JSAutoByteString bytes;
michael@0 5107 if (js_ValueToPrintable(cx, args.rval(), &bytes)) {
michael@0 5108 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_NEW_RESULT,
michael@0 5109 bytes.ptr());
michael@0 5110 }
michael@0 5111 return nullptr;
michael@0 5112 }
michael@0 5113
michael@0 5114 return &args.rval().toObject();
michael@0 5115 }
michael@0 5116
michael@0 5117 JS_PUBLIC_API(JSObject *)
michael@0 5118 JS_New(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
michael@0 5119 {
michael@0 5120 RootedObject obj(cx);
michael@0 5121 {
michael@0 5122 AutoLastFrameCheck lfc(cx);
michael@0 5123 obj = JS_NewHelper(cx, ctor, inputArgs);
michael@0 5124 }
michael@0 5125 return obj;
michael@0 5126 }
michael@0 5127
michael@0 5128 JS_PUBLIC_API(JSInterruptCallback)
michael@0 5129 JS_SetInterruptCallback(JSRuntime *rt, JSInterruptCallback callback)
michael@0 5130 {
michael@0 5131 JSInterruptCallback old = rt->interruptCallback;
michael@0 5132 rt->interruptCallback = callback;
michael@0 5133 return old;
michael@0 5134 }
michael@0 5135
michael@0 5136 JS_PUBLIC_API(JSInterruptCallback)
michael@0 5137 JS_GetInterruptCallback(JSRuntime *rt)
michael@0 5138 {
michael@0 5139 return rt->interruptCallback;
michael@0 5140 }
michael@0 5141
michael@0 5142 JS_PUBLIC_API(void)
michael@0 5143 JS_RequestInterruptCallback(JSRuntime *rt)
michael@0 5144 {
michael@0 5145 rt->requestInterrupt(JSRuntime::RequestInterruptAnyThread);
michael@0 5146 }
michael@0 5147
michael@0 5148 JS_PUBLIC_API(bool)
michael@0 5149 JS_IsRunning(JSContext *cx)
michael@0 5150 {
michael@0 5151 return cx->currentlyRunning();
michael@0 5152 }
michael@0 5153
michael@0 5154 JS_PUBLIC_API(bool)
michael@0 5155 JS_SaveFrameChain(JSContext *cx)
michael@0 5156 {
michael@0 5157 AssertHeapIsIdleOrIterating(cx);
michael@0 5158 CHECK_REQUEST(cx);
michael@0 5159 return cx->saveFrameChain();
michael@0 5160 }
michael@0 5161
michael@0 5162 JS_PUBLIC_API(void)
michael@0 5163 JS_RestoreFrameChain(JSContext *cx)
michael@0 5164 {
michael@0 5165 AssertHeapIsIdleOrIterating(cx);
michael@0 5166 CHECK_REQUEST(cx);
michael@0 5167 cx->restoreFrameChain();
michael@0 5168 }
michael@0 5169
michael@0 5170 #ifdef MOZ_TRACE_JSCALLS
michael@0 5171 JS_PUBLIC_API(void)
michael@0 5172 JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb)
michael@0 5173 {
michael@0 5174 cx->functionCallback = fcb;
michael@0 5175 }
michael@0 5176
michael@0 5177 JS_PUBLIC_API(JSFunctionCallback)
michael@0 5178 JS_GetFunctionCallback(JSContext *cx)
michael@0 5179 {
michael@0 5180 return cx->functionCallback;
michael@0 5181 }
michael@0 5182 #endif
michael@0 5183
michael@0 5184 /************************************************************************/
michael@0 5185 JS_PUBLIC_API(JSString *)
michael@0 5186 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
michael@0 5187 {
michael@0 5188 AssertHeapIsIdle(cx);
michael@0 5189 CHECK_REQUEST(cx);
michael@0 5190 if (!n)
michael@0 5191 return cx->names().empty;
michael@0 5192 return js_NewStringCopyN<CanGC>(cx, s, n);
michael@0 5193 }
michael@0 5194
michael@0 5195 JS_PUBLIC_API(JSString *)
michael@0 5196 JS_NewStringCopyZ(JSContext *cx, const char *s)
michael@0 5197 {
michael@0 5198 size_t n;
michael@0 5199 jschar *js;
michael@0 5200 JSString *str;
michael@0 5201
michael@0 5202 AssertHeapIsIdle(cx);
michael@0 5203 CHECK_REQUEST(cx);
michael@0 5204 if (!s || !*s)
michael@0 5205 return cx->runtime()->emptyString;
michael@0 5206 n = strlen(s);
michael@0 5207 js = InflateString(cx, s, &n);
michael@0 5208 if (!js)
michael@0 5209 return nullptr;
michael@0 5210 str = js_NewString<CanGC>(cx, js, n);
michael@0 5211 if (!str)
michael@0 5212 js_free(js);
michael@0 5213 return str;
michael@0 5214 }
michael@0 5215
michael@0 5216 JS_PUBLIC_API(bool)
michael@0 5217 JS_StringHasBeenInterned(JSContext *cx, JSString *str)
michael@0 5218 {
michael@0 5219 AssertHeapIsIdle(cx);
michael@0 5220 CHECK_REQUEST(cx);
michael@0 5221
michael@0 5222 if (!str->isAtom())
michael@0 5223 return false;
michael@0 5224
michael@0 5225 return AtomIsInterned(cx, &str->asAtom());
michael@0 5226 }
michael@0 5227
michael@0 5228 JS_PUBLIC_API(jsid)
michael@0 5229 INTERNED_STRING_TO_JSID(JSContext *cx, JSString *str)
michael@0 5230 {
michael@0 5231 JS_ASSERT(str);
michael@0 5232 JS_ASSERT(((size_t)str & JSID_TYPE_MASK) == 0);
michael@0 5233 JS_ASSERT_IF(cx, JS_StringHasBeenInterned(cx, str));
michael@0 5234 return AtomToId(&str->asAtom());
michael@0 5235 }
michael@0 5236
michael@0 5237 JS_PUBLIC_API(JSString *)
michael@0 5238 JS_InternJSString(JSContext *cx, HandleString str)
michael@0 5239 {
michael@0 5240 AssertHeapIsIdle(cx);
michael@0 5241 CHECK_REQUEST(cx);
michael@0 5242 JSAtom *atom = AtomizeString(cx, str, InternAtom);
michael@0 5243 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
michael@0 5244 return atom;
michael@0 5245 }
michael@0 5246
michael@0 5247 JS_PUBLIC_API(JSString *)
michael@0 5248 JS_InternString(JSContext *cx, const char *s)
michael@0 5249 {
michael@0 5250 return JS_InternStringN(cx, s, strlen(s));
michael@0 5251 }
michael@0 5252
michael@0 5253 JS_PUBLIC_API(JSString *)
michael@0 5254 JS_InternStringN(JSContext *cx, const char *s, size_t length)
michael@0 5255 {
michael@0 5256 AssertHeapIsIdle(cx);
michael@0 5257 CHECK_REQUEST(cx);
michael@0 5258 JSAtom *atom = Atomize(cx, s, length, InternAtom);
michael@0 5259 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
michael@0 5260 return atom;
michael@0 5261 }
michael@0 5262
michael@0 5263 JS_PUBLIC_API(JSString *)
michael@0 5264 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
michael@0 5265 {
michael@0 5266 AssertHeapIsIdle(cx);
michael@0 5267 CHECK_REQUEST(cx);
michael@0 5268 return js_NewString<CanGC>(cx, chars, length);
michael@0 5269 }
michael@0 5270
michael@0 5271 JS_PUBLIC_API(JSString *)
michael@0 5272 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
michael@0 5273 {
michael@0 5274 AssertHeapIsIdle(cx);
michael@0 5275 CHECK_REQUEST(cx);
michael@0 5276 if (!n)
michael@0 5277 return cx->names().empty;
michael@0 5278 return js_NewStringCopyN<CanGC>(cx, s, n);
michael@0 5279 }
michael@0 5280
michael@0 5281 JS_PUBLIC_API(JSString *)
michael@0 5282 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
michael@0 5283 {
michael@0 5284 AssertHeapIsIdle(cx);
michael@0 5285 CHECK_REQUEST(cx);
michael@0 5286 if (!s)
michael@0 5287 return cx->runtime()->emptyString;
michael@0 5288 return js_NewStringCopyZ<CanGC>(cx, s);
michael@0 5289 }
michael@0 5290
michael@0 5291 JS_PUBLIC_API(JSString *)
michael@0 5292 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
michael@0 5293 {
michael@0 5294 AssertHeapIsIdle(cx);
michael@0 5295 CHECK_REQUEST(cx);
michael@0 5296 JSAtom *atom = AtomizeChars(cx, s, length, InternAtom);
michael@0 5297 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
michael@0 5298 return atom;
michael@0 5299 }
michael@0 5300
michael@0 5301 JS_PUBLIC_API(JSString *)
michael@0 5302 JS_InternUCString(JSContext *cx, const jschar *s)
michael@0 5303 {
michael@0 5304 return JS_InternUCStringN(cx, s, js_strlen(s));
michael@0 5305 }
michael@0 5306
michael@0 5307 JS_PUBLIC_API(size_t)
michael@0 5308 JS_GetStringLength(JSString *str)
michael@0 5309 {
michael@0 5310 return str->length();
michael@0 5311 }
michael@0 5312
michael@0 5313 JS_PUBLIC_API(const jschar *)
michael@0 5314 JS_GetStringCharsZ(JSContext *cx, JSString *str)
michael@0 5315 {
michael@0 5316 size_t dummy;
michael@0 5317 return JS_GetStringCharsZAndLength(cx, str, &dummy);
michael@0 5318 }
michael@0 5319
michael@0 5320 JS_PUBLIC_API(const jschar *)
michael@0 5321 JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
michael@0 5322 {
michael@0 5323 /*
michael@0 5324 * Don't require |cx->compartment()| to be |str|'s compartment. We don't need
michael@0 5325 * it, and it's annoying for callers.
michael@0 5326 */
michael@0 5327 JS_ASSERT(plength);
michael@0 5328 AssertHeapIsIdleOrStringIsFlat(cx, str);
michael@0 5329 CHECK_REQUEST(cx);
michael@0 5330 JSFlatString *flat = str->ensureFlat(cx);
michael@0 5331 if (!flat)
michael@0 5332 return nullptr;
michael@0 5333 *plength = flat->length();
michael@0 5334 return flat->chars();
michael@0 5335 }
michael@0 5336
michael@0 5337 JS_PUBLIC_API(const jschar *)
michael@0 5338 JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
michael@0 5339 {
michael@0 5340 JS_ASSERT(plength);
michael@0 5341 AssertHeapIsIdleOrStringIsFlat(cx, str);
michael@0 5342 CHECK_REQUEST(cx);
michael@0 5343 assertSameCompartment(cx, str);
michael@0 5344 JSLinearString *linear = str->ensureLinear(cx);
michael@0 5345 if (!linear)
michael@0 5346 return nullptr;
michael@0 5347 *plength = linear->length();
michael@0 5348 return linear->chars();
michael@0 5349 }
michael@0 5350
michael@0 5351 JS_PUBLIC_API(const jschar *)
michael@0 5352 JS_GetInternedStringChars(JSString *str)
michael@0 5353 {
michael@0 5354 JS_ASSERT(str->isAtom());
michael@0 5355 JSFlatString *flat = str->ensureFlat(nullptr);
michael@0 5356 if (!flat)
michael@0 5357 return nullptr;
michael@0 5358 return flat->chars();
michael@0 5359 }
michael@0 5360
michael@0 5361 JS_PUBLIC_API(const jschar *)
michael@0 5362 JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
michael@0 5363 {
michael@0 5364 JS_ASSERT(str->isAtom());
michael@0 5365 JS_ASSERT(plength);
michael@0 5366 JSFlatString *flat = str->ensureFlat(nullptr);
michael@0 5367 if (!flat)
michael@0 5368 return nullptr;
michael@0 5369 *plength = flat->length();
michael@0 5370 return flat->chars();
michael@0 5371 }
michael@0 5372
michael@0 5373 extern JS_PUBLIC_API(JSFlatString *)
michael@0 5374 JS_FlattenString(JSContext *cx, JSString *str)
michael@0 5375 {
michael@0 5376 AssertHeapIsIdle(cx);
michael@0 5377 CHECK_REQUEST(cx);
michael@0 5378 assertSameCompartment(cx, str);
michael@0 5379 JSFlatString *flat = str->ensureFlat(cx);
michael@0 5380 if (!flat)
michael@0 5381 return nullptr;
michael@0 5382 return flat;
michael@0 5383 }
michael@0 5384
michael@0 5385 extern JS_PUBLIC_API(const jschar *)
michael@0 5386 JS_GetFlatStringChars(JSFlatString *str)
michael@0 5387 {
michael@0 5388 return str->chars();
michael@0 5389 }
michael@0 5390
michael@0 5391 JS_PUBLIC_API(bool)
michael@0 5392 JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result)
michael@0 5393 {
michael@0 5394 AssertHeapIsIdle(cx);
michael@0 5395 CHECK_REQUEST(cx);
michael@0 5396
michael@0 5397 return CompareStrings(cx, str1, str2, result);
michael@0 5398 }
michael@0 5399
michael@0 5400 JS_PUBLIC_API(bool)
michael@0 5401 JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, bool *match)
michael@0 5402 {
michael@0 5403 AssertHeapIsIdle(cx);
michael@0 5404 CHECK_REQUEST(cx);
michael@0 5405
michael@0 5406 JSLinearString *linearStr = str->ensureLinear(cx);
michael@0 5407 if (!linearStr)
michael@0 5408 return false;
michael@0 5409 *match = StringEqualsAscii(linearStr, asciiBytes);
michael@0 5410 return true;
michael@0 5411 }
michael@0 5412
michael@0 5413 JS_PUBLIC_API(bool)
michael@0 5414 JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
michael@0 5415 {
michael@0 5416 return StringEqualsAscii(str, asciiBytes);
michael@0 5417 }
michael@0 5418
michael@0 5419 JS_PUBLIC_API(size_t)
michael@0 5420 JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
michael@0 5421 {
michael@0 5422 return PutEscapedString(buffer, size, str, quote);
michael@0 5423 }
michael@0 5424
michael@0 5425 JS_PUBLIC_API(size_t)
michael@0 5426 JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
michael@0 5427 {
michael@0 5428 AssertHeapIsIdle(cx);
michael@0 5429 JSLinearString *linearStr = str->ensureLinear(cx);
michael@0 5430 if (!linearStr)
michael@0 5431 return size_t(-1);
michael@0 5432 return PutEscapedString(buffer, size, linearStr, quote);
michael@0 5433 }
michael@0 5434
michael@0 5435 JS_PUBLIC_API(bool)
michael@0 5436 JS_FileEscapedString(FILE *fp, JSString *str, char quote)
michael@0 5437 {
michael@0 5438 JSLinearString *linearStr = str->ensureLinear(nullptr);
michael@0 5439 return linearStr && FileEscapedString(fp, linearStr, quote);
michael@0 5440 }
michael@0 5441
michael@0 5442 JS_PUBLIC_API(JSString *)
michael@0 5443 JS_NewDependentString(JSContext *cx, HandleString str, size_t start, size_t length)
michael@0 5444 {
michael@0 5445 AssertHeapIsIdle(cx);
michael@0 5446 CHECK_REQUEST(cx);
michael@0 5447 return js_NewDependentString(cx, str, start, length);
michael@0 5448 }
michael@0 5449
michael@0 5450 JS_PUBLIC_API(JSString *)
michael@0 5451 JS_ConcatStrings(JSContext *cx, HandleString left, HandleString right)
michael@0 5452 {
michael@0 5453 AssertHeapIsIdle(cx);
michael@0 5454 CHECK_REQUEST(cx);
michael@0 5455 return ConcatStrings<CanGC>(cx, left, right);
michael@0 5456 }
michael@0 5457
michael@0 5458 JS_PUBLIC_API(bool)
michael@0 5459 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
michael@0 5460 {
michael@0 5461 AssertHeapIsIdle(cx);
michael@0 5462 CHECK_REQUEST(cx);
michael@0 5463
michael@0 5464 if (!dst) {
michael@0 5465 *dstlenp = srclen;
michael@0 5466 return true;
michael@0 5467 }
michael@0 5468
michael@0 5469 size_t dstlen = *dstlenp;
michael@0 5470
michael@0 5471 if (srclen > dstlen) {
michael@0 5472 InflateStringToBuffer(src, dstlen, dst);
michael@0 5473
michael@0 5474 AutoSuppressGC suppress(cx);
michael@0 5475 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL);
michael@0 5476 return false;
michael@0 5477 }
michael@0 5478
michael@0 5479 InflateStringToBuffer(src, srclen, dst);
michael@0 5480 *dstlenp = srclen;
michael@0 5481 return true;
michael@0 5482 }
michael@0 5483
michael@0 5484 JS_PUBLIC_API(char *)
michael@0 5485 JS_EncodeString(JSContext *cx, JSString *str)
michael@0 5486 {
michael@0 5487 AssertHeapIsIdle(cx);
michael@0 5488 CHECK_REQUEST(cx);
michael@0 5489
michael@0 5490 JSLinearString *linear = str->ensureLinear(cx);
michael@0 5491 if (!linear)
michael@0 5492 return nullptr;
michael@0 5493
michael@0 5494 return LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
michael@0 5495 }
michael@0 5496
michael@0 5497 JS_PUBLIC_API(char *)
michael@0 5498 JS_EncodeStringToUTF8(JSContext *cx, HandleString str)
michael@0 5499 {
michael@0 5500 AssertHeapIsIdle(cx);
michael@0 5501 CHECK_REQUEST(cx);
michael@0 5502
michael@0 5503 JSLinearString *linear = str->ensureLinear(cx);
michael@0 5504 if (!linear)
michael@0 5505 return nullptr;
michael@0 5506
michael@0 5507 return TwoByteCharsToNewUTF8CharsZ(cx, linear->range()).c_str();
michael@0 5508 }
michael@0 5509
michael@0 5510 JS_PUBLIC_API(size_t)
michael@0 5511 JS_GetStringEncodingLength(JSContext *cx, JSString *str)
michael@0 5512 {
michael@0 5513 AssertHeapIsIdle(cx);
michael@0 5514 CHECK_REQUEST(cx);
michael@0 5515
michael@0 5516 const jschar *chars = str->getChars(cx);
michael@0 5517 if (!chars)
michael@0 5518 return size_t(-1);
michael@0 5519 return str->length();
michael@0 5520 }
michael@0 5521
michael@0 5522 JS_PUBLIC_API(size_t)
michael@0 5523 JS_EncodeStringToBuffer(JSContext *cx, JSString *str, char *buffer, size_t length)
michael@0 5524 {
michael@0 5525 AssertHeapIsIdle(cx);
michael@0 5526 CHECK_REQUEST(cx);
michael@0 5527
michael@0 5528 /*
michael@0 5529 * FIXME bug 612141 - fix DeflateStringToBuffer interface so the result
michael@0 5530 * would allow to distinguish between insufficient buffer and encoding
michael@0 5531 * error.
michael@0 5532 */
michael@0 5533 size_t writtenLength = length;
michael@0 5534 const jschar *chars = str->getChars(nullptr);
michael@0 5535 if (!chars)
michael@0 5536 return size_t(-1);
michael@0 5537 if (DeflateStringToBuffer(nullptr, chars, str->length(), buffer, &writtenLength)) {
michael@0 5538 JS_ASSERT(writtenLength <= length);
michael@0 5539 return writtenLength;
michael@0 5540 }
michael@0 5541 JS_ASSERT(writtenLength <= length);
michael@0 5542 size_t necessaryLength = str->length();
michael@0 5543 if (necessaryLength == size_t(-1))
michael@0 5544 return size_t(-1);
michael@0 5545 JS_ASSERT(writtenLength == length); // C strings are NOT encoded.
michael@0 5546 return necessaryLength;
michael@0 5547 }
michael@0 5548
michael@0 5549 JS_PUBLIC_API(bool)
michael@0 5550 JS_Stringify(JSContext *cx, MutableHandleValue vp, HandleObject replacer,
michael@0 5551 HandleValue space, JSONWriteCallback callback, void *data)
michael@0 5552 {
michael@0 5553 AssertHeapIsIdle(cx);
michael@0 5554 CHECK_REQUEST(cx);
michael@0 5555 assertSameCompartment(cx, replacer, space);
michael@0 5556 StringBuffer sb(cx);
michael@0 5557 if (!js_Stringify(cx, vp, replacer, space, sb))
michael@0 5558 return false;
michael@0 5559 if (sb.empty()) {
michael@0 5560 HandlePropertyName null = cx->names().null;
michael@0 5561 return callback(null->chars(), null->length(), data);
michael@0 5562 }
michael@0 5563 return callback(sb.begin(), sb.length(), data);
michael@0 5564 }
michael@0 5565
michael@0 5566 JS_PUBLIC_API(bool)
michael@0 5567 JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, JS::MutableHandleValue vp)
michael@0 5568 {
michael@0 5569 AssertHeapIsIdle(cx);
michael@0 5570 CHECK_REQUEST(cx);
michael@0 5571
michael@0 5572 RootedValue reviver(cx, NullValue());
michael@0 5573 return ParseJSONWithReviver(cx, ConstTwoByteChars(chars, len), len, reviver, vp);
michael@0 5574 }
michael@0 5575
michael@0 5576 JS_PUBLIC_API(bool)
michael@0 5577 JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, HandleValue reviver, MutableHandleValue vp)
michael@0 5578 {
michael@0 5579 AssertHeapIsIdle(cx);
michael@0 5580 CHECK_REQUEST(cx);
michael@0 5581 return ParseJSONWithReviver(cx, ConstTwoByteChars(chars, len), len, reviver, vp);
michael@0 5582 }
michael@0 5583
michael@0 5584 /************************************************************************/
michael@0 5585
michael@0 5586 JS_PUBLIC_API(void)
michael@0 5587 JS_ReportError(JSContext *cx, const char *format, ...)
michael@0 5588 {
michael@0 5589 va_list ap;
michael@0 5590
michael@0 5591 AssertHeapIsIdle(cx);
michael@0 5592 va_start(ap, format);
michael@0 5593 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
michael@0 5594 va_end(ap);
michael@0 5595 }
michael@0 5596
michael@0 5597 JS_PUBLIC_API(void)
michael@0 5598 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
michael@0 5599 void *userRef, const unsigned errorNumber, ...)
michael@0 5600 {
michael@0 5601 va_list ap;
michael@0 5602 va_start(ap, errorNumber);
michael@0 5603 JS_ReportErrorNumberVA(cx, errorCallback, userRef, errorNumber, ap);
michael@0 5604 va_end(ap);
michael@0 5605 }
michael@0 5606
michael@0 5607 JS_PUBLIC_API(void)
michael@0 5608 JS_ReportErrorNumberVA(JSContext *cx, JSErrorCallback errorCallback,
michael@0 5609 void *userRef, const unsigned errorNumber,
michael@0 5610 va_list ap)
michael@0 5611 {
michael@0 5612 AssertHeapIsIdle(cx);
michael@0 5613 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
michael@0 5614 errorNumber, ArgumentsAreASCII, ap);
michael@0 5615 }
michael@0 5616
michael@0 5617 JS_PUBLIC_API(void)
michael@0 5618 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
michael@0 5619 void *userRef, const unsigned errorNumber, ...)
michael@0 5620 {
michael@0 5621 va_list ap;
michael@0 5622
michael@0 5623 AssertHeapIsIdle(cx);
michael@0 5624 va_start(ap, errorNumber);
michael@0 5625 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
michael@0 5626 errorNumber, ArgumentsAreUnicode, ap);
michael@0 5627 va_end(ap);
michael@0 5628 }
michael@0 5629
michael@0 5630 JS_PUBLIC_API(void)
michael@0 5631 JS_ReportErrorNumberUCArray(JSContext *cx, JSErrorCallback errorCallback,
michael@0 5632 void *userRef, const unsigned errorNumber,
michael@0 5633 const jschar **args)
michael@0 5634 {
michael@0 5635 AssertHeapIsIdle(cx);
michael@0 5636 js_ReportErrorNumberUCArray(cx, JSREPORT_ERROR, errorCallback, userRef,
michael@0 5637 errorNumber, args);
michael@0 5638 }
michael@0 5639
michael@0 5640 JS_PUBLIC_API(bool)
michael@0 5641 JS_ReportWarning(JSContext *cx, const char *format, ...)
michael@0 5642 {
michael@0 5643 va_list ap;
michael@0 5644 bool ok;
michael@0 5645
michael@0 5646 AssertHeapIsIdle(cx);
michael@0 5647 va_start(ap, format);
michael@0 5648 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
michael@0 5649 va_end(ap);
michael@0 5650 return ok;
michael@0 5651 }
michael@0 5652
michael@0 5653 JS_PUBLIC_API(bool)
michael@0 5654 JS_ReportErrorFlagsAndNumber(JSContext *cx, unsigned flags,
michael@0 5655 JSErrorCallback errorCallback, void *userRef,
michael@0 5656 const unsigned errorNumber, ...)
michael@0 5657 {
michael@0 5658 va_list ap;
michael@0 5659 bool ok;
michael@0 5660
michael@0 5661 AssertHeapIsIdle(cx);
michael@0 5662 va_start(ap, errorNumber);
michael@0 5663 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
michael@0 5664 errorNumber, ArgumentsAreASCII, ap);
michael@0 5665 va_end(ap);
michael@0 5666 return ok;
michael@0 5667 }
michael@0 5668
michael@0 5669 JS_PUBLIC_API(bool)
michael@0 5670 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, unsigned flags,
michael@0 5671 JSErrorCallback errorCallback, void *userRef,
michael@0 5672 const unsigned errorNumber, ...)
michael@0 5673 {
michael@0 5674 va_list ap;
michael@0 5675 bool ok;
michael@0 5676
michael@0 5677 AssertHeapIsIdle(cx);
michael@0 5678 va_start(ap, errorNumber);
michael@0 5679 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
michael@0 5680 errorNumber, ArgumentsAreUnicode, ap);
michael@0 5681 va_end(ap);
michael@0 5682 return ok;
michael@0 5683 }
michael@0 5684
michael@0 5685 JS_PUBLIC_API(void)
michael@0 5686 JS_ReportOutOfMemory(JSContext *cx)
michael@0 5687 {
michael@0 5688 js_ReportOutOfMemory(cx);
michael@0 5689 }
michael@0 5690
michael@0 5691 JS_PUBLIC_API(void)
michael@0 5692 JS_ReportAllocationOverflow(JSContext *cx)
michael@0 5693 {
michael@0 5694 js_ReportAllocationOverflow(cx);
michael@0 5695 }
michael@0 5696
michael@0 5697 JS_PUBLIC_API(JSErrorReporter)
michael@0 5698 JS_GetErrorReporter(JSContext *cx)
michael@0 5699 {
michael@0 5700 return cx->errorReporter;
michael@0 5701 }
michael@0 5702
michael@0 5703 JS_PUBLIC_API(JSErrorReporter)
michael@0 5704 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
michael@0 5705 {
michael@0 5706 JSErrorReporter older;
michael@0 5707
michael@0 5708 older = cx->errorReporter;
michael@0 5709 cx->errorReporter = er;
michael@0 5710 return older;
michael@0 5711 }
michael@0 5712
michael@0 5713 /************************************************************************/
michael@0 5714
michael@0 5715 /*
michael@0 5716 * Dates.
michael@0 5717 */
michael@0 5718 JS_PUBLIC_API(JSObject *)
michael@0 5719 JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec)
michael@0 5720 {
michael@0 5721 AssertHeapIsIdle(cx);
michael@0 5722 CHECK_REQUEST(cx);
michael@0 5723 return js_NewDateObject(cx, year, mon, mday, hour, min, sec);
michael@0 5724 }
michael@0 5725
michael@0 5726 JS_PUBLIC_API(JSObject *)
michael@0 5727 JS_NewDateObjectMsec(JSContext *cx, double msec)
michael@0 5728 {
michael@0 5729 AssertHeapIsIdle(cx);
michael@0 5730 CHECK_REQUEST(cx);
michael@0 5731 return js_NewDateObjectMsec(cx, msec);
michael@0 5732 }
michael@0 5733
michael@0 5734 JS_PUBLIC_API(bool)
michael@0 5735 JS_ObjectIsDate(JSContext *cx, HandleObject obj)
michael@0 5736 {
michael@0 5737 assertSameCompartment(cx, obj);
michael@0 5738 return ObjectClassIs(obj, ESClass_Date, cx);
michael@0 5739 }
michael@0 5740
michael@0 5741 JS_PUBLIC_API(void)
michael@0 5742 JS_ClearDateCaches(JSContext *cx)
michael@0 5743 {
michael@0 5744 AssertHeapIsIdle(cx);
michael@0 5745 CHECK_REQUEST(cx);
michael@0 5746 cx->runtime()->dateTimeInfo.updateTimeZoneAdjustment();
michael@0 5747 }
michael@0 5748
michael@0 5749 /************************************************************************/
michael@0 5750
michael@0 5751 /*
michael@0 5752 * Regular Expressions.
michael@0 5753 */
michael@0 5754 JS_PUBLIC_API(JSObject *)
michael@0 5755 JS_NewRegExpObject(JSContext *cx, HandleObject obj, char *bytes, size_t length, unsigned flags)
michael@0 5756 {
michael@0 5757 AssertHeapIsIdle(cx);
michael@0 5758 CHECK_REQUEST(cx);
michael@0 5759 jschar *chars = InflateString(cx, bytes, &length);
michael@0 5760 if (!chars)
michael@0 5761 return nullptr;
michael@0 5762
michael@0 5763 RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics();
michael@0 5764 RegExpObject *reobj = RegExpObject::create(cx, res, chars, length,
michael@0 5765 RegExpFlag(flags), nullptr);
michael@0 5766 js_free(chars);
michael@0 5767 return reobj;
michael@0 5768 }
michael@0 5769
michael@0 5770 JS_PUBLIC_API(JSObject *)
michael@0 5771 JS_NewUCRegExpObject(JSContext *cx, HandleObject obj, jschar *chars, size_t length,
michael@0 5772 unsigned flags)
michael@0 5773 {
michael@0 5774 AssertHeapIsIdle(cx);
michael@0 5775 CHECK_REQUEST(cx);
michael@0 5776 RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics();
michael@0 5777 return RegExpObject::create(cx, res, chars, length,
michael@0 5778 RegExpFlag(flags), nullptr);
michael@0 5779 }
michael@0 5780
michael@0 5781 JS_PUBLIC_API(void)
michael@0 5782 JS_SetRegExpInput(JSContext *cx, HandleObject obj, HandleString input, bool multiline)
michael@0 5783 {
michael@0 5784 AssertHeapIsIdle(cx);
michael@0 5785 CHECK_REQUEST(cx);
michael@0 5786 assertSameCompartment(cx, input);
michael@0 5787
michael@0 5788 obj->as<GlobalObject>().getRegExpStatics()->reset(cx, input, !!multiline);
michael@0 5789 }
michael@0 5790
michael@0 5791 JS_PUBLIC_API(void)
michael@0 5792 JS_ClearRegExpStatics(JSContext *cx, HandleObject obj)
michael@0 5793 {
michael@0 5794 AssertHeapIsIdle(cx);
michael@0 5795 CHECK_REQUEST(cx);
michael@0 5796 JS_ASSERT(obj);
michael@0 5797
michael@0 5798 obj->as<GlobalObject>().getRegExpStatics()->clear();
michael@0 5799 }
michael@0 5800
michael@0 5801 JS_PUBLIC_API(bool)
michael@0 5802 JS_ExecuteRegExp(JSContext *cx, HandleObject obj, HandleObject reobj, jschar *chars,
michael@0 5803 size_t length, size_t *indexp, bool test, MutableHandleValue rval)
michael@0 5804 {
michael@0 5805 AssertHeapIsIdle(cx);
michael@0 5806 CHECK_REQUEST(cx);
michael@0 5807
michael@0 5808 RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics();
michael@0 5809
michael@0 5810 return ExecuteRegExpLegacy(cx, res, reobj->as<RegExpObject>(), NullPtr(), chars, length, indexp,
michael@0 5811 test, rval);
michael@0 5812 }
michael@0 5813
michael@0 5814 JS_PUBLIC_API(JSObject *)
michael@0 5815 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, unsigned flags)
michael@0 5816 {
michael@0 5817 AssertHeapIsIdle(cx);
michael@0 5818 CHECK_REQUEST(cx);
michael@0 5819 jschar *chars = InflateString(cx, bytes, &length);
michael@0 5820 if (!chars)
michael@0 5821 return nullptr;
michael@0 5822 RegExpObject *reobj = RegExpObject::createNoStatics(cx, chars, length,
michael@0 5823 RegExpFlag(flags), nullptr);
michael@0 5824 js_free(chars);
michael@0 5825 return reobj;
michael@0 5826 }
michael@0 5827
michael@0 5828 JS_PUBLIC_API(JSObject *)
michael@0 5829 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, unsigned flags)
michael@0 5830 {
michael@0 5831 AssertHeapIsIdle(cx);
michael@0 5832 CHECK_REQUEST(cx);
michael@0 5833 return RegExpObject::createNoStatics(cx, chars, length,
michael@0 5834 RegExpFlag(flags), nullptr);
michael@0 5835 }
michael@0 5836
michael@0 5837 JS_PUBLIC_API(bool)
michael@0 5838 JS_ExecuteRegExpNoStatics(JSContext *cx, HandleObject obj, jschar *chars, size_t length,
michael@0 5839 size_t *indexp, bool test, MutableHandleValue rval)
michael@0 5840 {
michael@0 5841 AssertHeapIsIdle(cx);
michael@0 5842 CHECK_REQUEST(cx);
michael@0 5843
michael@0 5844 return ExecuteRegExpLegacy(cx, nullptr, obj->as<RegExpObject>(), NullPtr(), chars, length,
michael@0 5845 indexp, test, rval);
michael@0 5846 }
michael@0 5847
michael@0 5848 JS_PUBLIC_API(bool)
michael@0 5849 JS_ObjectIsRegExp(JSContext *cx, HandleObject obj)
michael@0 5850 {
michael@0 5851 assertSameCompartment(cx, obj);
michael@0 5852 return ObjectClassIs(obj, ESClass_RegExp, cx);
michael@0 5853 }
michael@0 5854
michael@0 5855 JS_PUBLIC_API(unsigned)
michael@0 5856 JS_GetRegExpFlags(JSContext *cx, HandleObject obj)
michael@0 5857 {
michael@0 5858 AssertHeapIsIdle(cx);
michael@0 5859 CHECK_REQUEST(cx);
michael@0 5860
michael@0 5861 return obj->as<RegExpObject>().getFlags();
michael@0 5862 }
michael@0 5863
michael@0 5864 JS_PUBLIC_API(JSString *)
michael@0 5865 JS_GetRegExpSource(JSContext *cx, HandleObject obj)
michael@0 5866 {
michael@0 5867 AssertHeapIsIdle(cx);
michael@0 5868 CHECK_REQUEST(cx);
michael@0 5869
michael@0 5870 return obj->as<RegExpObject>().getSource();
michael@0 5871 }
michael@0 5872
michael@0 5873 /************************************************************************/
michael@0 5874
michael@0 5875 JS_PUBLIC_API(bool)
michael@0 5876 JS_SetDefaultLocale(JSRuntime *rt, const char *locale)
michael@0 5877 {
michael@0 5878 AssertHeapIsIdle(rt);
michael@0 5879 return rt->setDefaultLocale(locale);
michael@0 5880 }
michael@0 5881
michael@0 5882 JS_PUBLIC_API(const char*)
michael@0 5883 JS_GetDefaultLocale(JSRuntime *rt)
michael@0 5884 {
michael@0 5885 AssertHeapIsIdle(rt);
michael@0 5886 return rt->getDefaultLocale();
michael@0 5887 }
michael@0 5888
michael@0 5889 JS_PUBLIC_API(void)
michael@0 5890 JS_ResetDefaultLocale(JSRuntime *rt)
michael@0 5891 {
michael@0 5892 AssertHeapIsIdle(rt);
michael@0 5893 rt->resetDefaultLocale();
michael@0 5894 }
michael@0 5895
michael@0 5896 JS_PUBLIC_API(void)
michael@0 5897 JS_SetLocaleCallbacks(JSRuntime *rt, JSLocaleCallbacks *callbacks)
michael@0 5898 {
michael@0 5899 AssertHeapIsIdle(rt);
michael@0 5900 rt->localeCallbacks = callbacks;
michael@0 5901 }
michael@0 5902
michael@0 5903 JS_PUBLIC_API(JSLocaleCallbacks *)
michael@0 5904 JS_GetLocaleCallbacks(JSRuntime *rt)
michael@0 5905 {
michael@0 5906 /* This function can be called by a finalizer. */
michael@0 5907 return rt->localeCallbacks;
michael@0 5908 }
michael@0 5909
michael@0 5910 /************************************************************************/
michael@0 5911
michael@0 5912 JS_PUBLIC_API(bool)
michael@0 5913 JS_IsExceptionPending(JSContext *cx)
michael@0 5914 {
michael@0 5915 /* This function can be called by a finalizer. */
michael@0 5916 return (bool) cx->isExceptionPending();
michael@0 5917 }
michael@0 5918
michael@0 5919 JS_PUBLIC_API(bool)
michael@0 5920 JS_GetPendingException(JSContext *cx, MutableHandleValue vp)
michael@0 5921 {
michael@0 5922 AssertHeapIsIdle(cx);
michael@0 5923 CHECK_REQUEST(cx);
michael@0 5924 if (!cx->isExceptionPending())
michael@0 5925 return false;
michael@0 5926 return cx->getPendingException(vp);
michael@0 5927 }
michael@0 5928
michael@0 5929 JS_PUBLIC_API(void)
michael@0 5930 JS_SetPendingException(JSContext *cx, HandleValue value)
michael@0 5931 {
michael@0 5932 AssertHeapIsIdle(cx);
michael@0 5933 CHECK_REQUEST(cx);
michael@0 5934 assertSameCompartment(cx, value);
michael@0 5935 cx->setPendingException(value);
michael@0 5936 }
michael@0 5937
michael@0 5938 JS_PUBLIC_API(void)
michael@0 5939 JS_ClearPendingException(JSContext *cx)
michael@0 5940 {
michael@0 5941 AssertHeapIsIdle(cx);
michael@0 5942 cx->clearPendingException();
michael@0 5943 }
michael@0 5944
michael@0 5945 JS_PUBLIC_API(bool)
michael@0 5946 JS_ReportPendingException(JSContext *cx)
michael@0 5947 {
michael@0 5948 AssertHeapIsIdle(cx);
michael@0 5949 CHECK_REQUEST(cx);
michael@0 5950
michael@0 5951 // This can only fail due to oom.
michael@0 5952 bool ok = js_ReportUncaughtException(cx);
michael@0 5953 JS_ASSERT(!cx->isExceptionPending());
michael@0 5954 return ok;
michael@0 5955 }
michael@0 5956
michael@0 5957 JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext *cx)
michael@0 5958 : context(cx), wasThrowing(cx->throwing), exceptionValue(cx)
michael@0 5959 {
michael@0 5960 AssertHeapIsIdle(cx);
michael@0 5961 CHECK_REQUEST(cx);
michael@0 5962 if (wasThrowing) {
michael@0 5963 exceptionValue = cx->unwrappedException_;
michael@0 5964 cx->clearPendingException();
michael@0 5965 }
michael@0 5966 }
michael@0 5967
michael@0 5968 void
michael@0 5969 JS::AutoSaveExceptionState::restore()
michael@0 5970 {
michael@0 5971 context->throwing = wasThrowing;
michael@0 5972 context->unwrappedException_ = exceptionValue;
michael@0 5973 drop();
michael@0 5974 }
michael@0 5975
michael@0 5976 JS::AutoSaveExceptionState::~AutoSaveExceptionState()
michael@0 5977 {
michael@0 5978 if (wasThrowing && !context->isExceptionPending()) {
michael@0 5979 context->throwing = true;
michael@0 5980 context->unwrappedException_ = exceptionValue;
michael@0 5981 }
michael@0 5982 }
michael@0 5983
michael@0 5984 struct JSExceptionState {
michael@0 5985 bool throwing;
michael@0 5986 jsval exception;
michael@0 5987 };
michael@0 5988
michael@0 5989 JS_PUBLIC_API(JSExceptionState *)
michael@0 5990 JS_SaveExceptionState(JSContext *cx)
michael@0 5991 {
michael@0 5992 JSExceptionState *state;
michael@0 5993
michael@0 5994 AssertHeapIsIdle(cx);
michael@0 5995 CHECK_REQUEST(cx);
michael@0 5996 state = cx->pod_malloc<JSExceptionState>();
michael@0 5997 if (state) {
michael@0 5998 state->throwing =
michael@0 5999 JS_GetPendingException(cx, MutableHandleValue::fromMarkedLocation(&state->exception));
michael@0 6000 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
michael@0 6001 AddValueRoot(cx, &state->exception, "JSExceptionState.exception");
michael@0 6002 }
michael@0 6003 return state;
michael@0 6004 }
michael@0 6005
michael@0 6006 JS_PUBLIC_API(void)
michael@0 6007 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
michael@0 6008 {
michael@0 6009 AssertHeapIsIdle(cx);
michael@0 6010 CHECK_REQUEST(cx);
michael@0 6011 if (state) {
michael@0 6012 if (state->throwing)
michael@0 6013 JS_SetPendingException(cx, HandleValue::fromMarkedLocation(&state->exception));
michael@0 6014 else
michael@0 6015 JS_ClearPendingException(cx);
michael@0 6016 JS_DropExceptionState(cx, state);
michael@0 6017 }
michael@0 6018 }
michael@0 6019
michael@0 6020 JS_PUBLIC_API(void)
michael@0 6021 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
michael@0 6022 {
michael@0 6023 AssertHeapIsIdle(cx);
michael@0 6024 CHECK_REQUEST(cx);
michael@0 6025 if (state) {
michael@0 6026 if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
michael@0 6027 assertSameCompartment(cx, state->exception);
michael@0 6028 RemoveRoot(cx->runtime(), &state->exception);
michael@0 6029 }
michael@0 6030 js_free(state);
michael@0 6031 }
michael@0 6032 }
michael@0 6033
michael@0 6034 JS_PUBLIC_API(JSErrorReport *)
michael@0 6035 JS_ErrorFromException(JSContext *cx, HandleObject obj)
michael@0 6036 {
michael@0 6037 AssertHeapIsIdle(cx);
michael@0 6038 CHECK_REQUEST(cx);
michael@0 6039 assertSameCompartment(cx, obj);
michael@0 6040 return js_ErrorFromException(cx, obj);
michael@0 6041 }
michael@0 6042
michael@0 6043 JS_PUBLIC_API(bool)
michael@0 6044 JS_ThrowStopIteration(JSContext *cx)
michael@0 6045 {
michael@0 6046 AssertHeapIsIdle(cx);
michael@0 6047 return js_ThrowStopIteration(cx);
michael@0 6048 }
michael@0 6049
michael@0 6050 JS_PUBLIC_API(bool)
michael@0 6051 JS_IsStopIteration(jsval v)
michael@0 6052 {
michael@0 6053 return v.isObject() && v.toObject().is<StopIterationObject>();
michael@0 6054 }
michael@0 6055
michael@0 6056 JS_PUBLIC_API(intptr_t)
michael@0 6057 JS_GetCurrentThread()
michael@0 6058 {
michael@0 6059 #ifdef JS_THREADSAFE
michael@0 6060 return reinterpret_cast<intptr_t>(PR_GetCurrentThread());
michael@0 6061 #else
michael@0 6062 return 0;
michael@0 6063 #endif
michael@0 6064 }
michael@0 6065
michael@0 6066 extern MOZ_NEVER_INLINE JS_PUBLIC_API(void)
michael@0 6067 JS_AbortIfWrongThread(JSRuntime *rt)
michael@0 6068 {
michael@0 6069 if (!CurrentThreadCanAccessRuntime(rt))
michael@0 6070 MOZ_CRASH();
michael@0 6071 if (!js::TlsPerThreadData.get()->associatedWith(rt))
michael@0 6072 MOZ_CRASH();
michael@0 6073 }
michael@0 6074
michael@0 6075 #ifdef JS_GC_ZEAL
michael@0 6076 JS_PUBLIC_API(void)
michael@0 6077 JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency)
michael@0 6078 {
michael@0 6079 SetGCZeal(cx->runtime(), zeal, frequency);
michael@0 6080 }
michael@0 6081
michael@0 6082 JS_PUBLIC_API(void)
michael@0 6083 JS_ScheduleGC(JSContext *cx, uint32_t count)
michael@0 6084 {
michael@0 6085 cx->runtime()->gcNextScheduled = count;
michael@0 6086 }
michael@0 6087 #endif
michael@0 6088
michael@0 6089 JS_PUBLIC_API(void)
michael@0 6090 JS_SetParallelParsingEnabled(JSRuntime *rt, bool enabled)
michael@0 6091 {
michael@0 6092 #ifdef JS_ION
michael@0 6093 rt->setParallelParsingEnabled(enabled);
michael@0 6094 #endif
michael@0 6095 }
michael@0 6096
michael@0 6097 JS_PUBLIC_API(void)
michael@0 6098 JS_SetParallelIonCompilationEnabled(JSRuntime *rt, bool enabled)
michael@0 6099 {
michael@0 6100 #ifdef JS_ION
michael@0 6101 rt->setParallelIonCompilationEnabled(enabled);
michael@0 6102 #endif
michael@0 6103 }
michael@0 6104
michael@0 6105 JS_PUBLIC_API(void)
michael@0 6106 JS_SetGlobalJitCompilerOption(JSRuntime *rt, JSJitCompilerOption opt, uint32_t value)
michael@0 6107 {
michael@0 6108 #ifdef JS_ION
michael@0 6109
michael@0 6110 switch (opt) {
michael@0 6111 case JSJITCOMPILER_BASELINE_USECOUNT_TRIGGER:
michael@0 6112 if (value == uint32_t(-1)) {
michael@0 6113 jit::JitOptions defaultValues;
michael@0 6114 value = defaultValues.baselineUsesBeforeCompile;
michael@0 6115 }
michael@0 6116 jit::js_JitOptions.baselineUsesBeforeCompile = value;
michael@0 6117 break;
michael@0 6118 case JSJITCOMPILER_ION_USECOUNT_TRIGGER:
michael@0 6119 if (value == uint32_t(-1)) {
michael@0 6120 jit::js_JitOptions.resetUsesBeforeCompile();
michael@0 6121 break;
michael@0 6122 }
michael@0 6123 jit::js_JitOptions.setUsesBeforeCompile(value);
michael@0 6124 if (value == 0)
michael@0 6125 jit::js_JitOptions.setEagerCompilation();
michael@0 6126 break;
michael@0 6127 case JSJITCOMPILER_ION_ENABLE:
michael@0 6128 if (value == 1) {
michael@0 6129 JS::RuntimeOptionsRef(rt).setIon(true);
michael@0 6130 IonSpew(js::jit::IonSpew_Scripts, "Enable ion");
michael@0 6131 } else if (value == 0) {
michael@0 6132 JS::RuntimeOptionsRef(rt).setIon(false);
michael@0 6133 IonSpew(js::jit::IonSpew_Scripts, "Disable ion");
michael@0 6134 }
michael@0 6135 break;
michael@0 6136 case JSJITCOMPILER_BASELINE_ENABLE:
michael@0 6137 if (value == 1) {
michael@0 6138 JS::RuntimeOptionsRef(rt).setBaseline(true);
michael@0 6139 IonSpew(js::jit::IonSpew_BaselineScripts, "Enable baseline");
michael@0 6140 } else if (value == 0) {
michael@0 6141 JS::RuntimeOptionsRef(rt).setBaseline(false);
michael@0 6142 IonSpew(js::jit::IonSpew_BaselineScripts, "Disable baseline");
michael@0 6143 }
michael@0 6144 break;
michael@0 6145 case JSJITCOMPILER_PARALLEL_COMPILATION_ENABLE:
michael@0 6146 if (value == 1) {
michael@0 6147 rt->setParallelIonCompilationEnabled(true);
michael@0 6148 IonSpew(js::jit::IonSpew_Scripts, "Enable parallel compilation");
michael@0 6149 } else if (value == 0) {
michael@0 6150 rt->setParallelIonCompilationEnabled(false);
michael@0 6151 IonSpew(js::jit::IonSpew_Scripts, "Disable parallel compilation");
michael@0 6152 }
michael@0 6153 break;
michael@0 6154 default:
michael@0 6155 break;
michael@0 6156 }
michael@0 6157 #endif
michael@0 6158 }
michael@0 6159
michael@0 6160 JS_PUBLIC_API(int)
michael@0 6161 JS_GetGlobalJitCompilerOption(JSRuntime *rt, JSJitCompilerOption opt)
michael@0 6162 {
michael@0 6163 #ifdef JS_ION
michael@0 6164 switch (opt) {
michael@0 6165 case JSJITCOMPILER_BASELINE_USECOUNT_TRIGGER:
michael@0 6166 return jit::js_JitOptions.baselineUsesBeforeCompile;
michael@0 6167 case JSJITCOMPILER_ION_USECOUNT_TRIGGER:
michael@0 6168 return jit::js_JitOptions.forcedDefaultIonUsesBeforeCompile;
michael@0 6169 case JSJITCOMPILER_ION_ENABLE:
michael@0 6170 return JS::RuntimeOptionsRef(rt).ion();
michael@0 6171 case JSJITCOMPILER_BASELINE_ENABLE:
michael@0 6172 return JS::RuntimeOptionsRef(rt).baseline();
michael@0 6173 case JSJITCOMPILER_PARALLEL_COMPILATION_ENABLE:
michael@0 6174 return rt->canUseParallelIonCompilation();
michael@0 6175 default:
michael@0 6176 break;
michael@0 6177 }
michael@0 6178 #endif
michael@0 6179 return 0;
michael@0 6180 }
michael@0 6181
michael@0 6182 /************************************************************************/
michael@0 6183
michael@0 6184 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN)
michael@0 6185
michael@0 6186 #include "jswin.h"
michael@0 6187
michael@0 6188 /*
michael@0 6189 * Initialization routine for the JS DLL.
michael@0 6190 */
michael@0 6191 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
michael@0 6192 {
michael@0 6193 return TRUE;
michael@0 6194 }
michael@0 6195
michael@0 6196 #endif
michael@0 6197
michael@0 6198 JS_PUBLIC_API(bool)
michael@0 6199 JS_IndexToId(JSContext *cx, uint32_t index, MutableHandleId id)
michael@0 6200 {
michael@0 6201 return IndexToId(cx, index, id);
michael@0 6202 }
michael@0 6203
michael@0 6204 JS_PUBLIC_API(bool)
michael@0 6205 JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, MutableHandleId idp)
michael@0 6206 {
michael@0 6207 RootedAtom atom(cx, AtomizeChars(cx, chars.start().get(), chars.length()));
michael@0 6208 if (!atom)
michael@0 6209 return false;
michael@0 6210 #ifdef DEBUG
michael@0 6211 uint32_t dummy;
michael@0 6212 MOZ_ASSERT(!atom->isIndex(&dummy), "API misuse: |chars| must not encode an index");
michael@0 6213 #endif
michael@0 6214 idp.set(AtomToId(atom));
michael@0 6215 return true;
michael@0 6216 }
michael@0 6217
michael@0 6218 JS_PUBLIC_API(bool)
michael@0 6219 JS_IsIdentifier(JSContext *cx, HandleString str, bool *isIdentifier)
michael@0 6220 {
michael@0 6221 assertSameCompartment(cx, str);
michael@0 6222
michael@0 6223 JSLinearString* linearStr = str->ensureLinear(cx);
michael@0 6224 if (!linearStr)
michael@0 6225 return false;
michael@0 6226
michael@0 6227 *isIdentifier = js::frontend::IsIdentifier(linearStr);
michael@0 6228 return true;
michael@0 6229 }
michael@0 6230
michael@0 6231 namespace JS {
michael@0 6232
michael@0 6233 void
michael@0 6234 AutoFilename::reset(void *newScriptSource)
michael@0 6235 {
michael@0 6236 if (newScriptSource)
michael@0 6237 reinterpret_cast<ScriptSource*>(newScriptSource)->incref();
michael@0 6238 if (scriptSource_)
michael@0 6239 reinterpret_cast<ScriptSource*>(scriptSource_)->decref();
michael@0 6240 scriptSource_ = newScriptSource;
michael@0 6241 }
michael@0 6242
michael@0 6243 const char *
michael@0 6244 AutoFilename::get() const
michael@0 6245 {
michael@0 6246 JS_ASSERT(scriptSource_);
michael@0 6247 return reinterpret_cast<ScriptSource*>(scriptSource_)->filename();
michael@0 6248 }
michael@0 6249
michael@0 6250 JS_PUBLIC_API(bool)
michael@0 6251 DescribeScriptedCaller(JSContext *cx, AutoFilename *filename, unsigned *lineno)
michael@0 6252 {
michael@0 6253 if (lineno)
michael@0 6254 *lineno = 0;
michael@0 6255
michael@0 6256 NonBuiltinFrameIter i(cx);
michael@0 6257 if (i.done())
michael@0 6258 return false;
michael@0 6259
michael@0 6260 // If the caller is hidden, the embedding wants us to return false here so
michael@0 6261 // that it can check its own stack (see HideScriptedCaller).
michael@0 6262 if (i.activation()->scriptedCallerIsHidden())
michael@0 6263 return false;
michael@0 6264
michael@0 6265 if (filename)
michael@0 6266 filename->reset(i.scriptSource());
michael@0 6267 if (lineno)
michael@0 6268 *lineno = i.computeLine();
michael@0 6269 return true;
michael@0 6270 }
michael@0 6271
michael@0 6272 JS_PUBLIC_API(JSObject *)
michael@0 6273 GetScriptedCallerGlobal(JSContext *cx)
michael@0 6274 {
michael@0 6275 NonBuiltinFrameIter i(cx);
michael@0 6276 if (i.done())
michael@0 6277 return nullptr;
michael@0 6278
michael@0 6279 // If the caller is hidden, the embedding wants us to return null here so
michael@0 6280 // that it can check its own stack (see HideScriptedCaller).
michael@0 6281 if (i.activation()->scriptedCallerIsHidden())
michael@0 6282 return nullptr;
michael@0 6283
michael@0 6284 GlobalObject *global = i.activation()->compartment()->maybeGlobal();
michael@0 6285
michael@0 6286 // Noone should be running code in the atoms compartment or running code in
michael@0 6287 // a compartment without any live objects, so there should definitely be a
michael@0 6288 // live global.
michael@0 6289 JS_ASSERT(global);
michael@0 6290
michael@0 6291 return global;
michael@0 6292 }
michael@0 6293
michael@0 6294 JS_PUBLIC_API(void)
michael@0 6295 HideScriptedCaller(JSContext *cx)
michael@0 6296 {
michael@0 6297 MOZ_ASSERT(cx);
michael@0 6298
michael@0 6299 // If there's no accessible activation on the stack, we'll return null from
michael@0 6300 // DescribeScriptedCaller anyway, so there's no need to annotate anything.
michael@0 6301 Activation *act = cx->runtime()->mainThread.activation();
michael@0 6302 if (!act)
michael@0 6303 return;
michael@0 6304 act->hideScriptedCaller();
michael@0 6305 }
michael@0 6306
michael@0 6307 JS_PUBLIC_API(void)
michael@0 6308 UnhideScriptedCaller(JSContext *cx)
michael@0 6309 {
michael@0 6310 Activation *act = cx->runtime()->mainThread.activation();
michael@0 6311 if (!act)
michael@0 6312 return;
michael@0 6313 act->unhideScriptedCaller();
michael@0 6314 }
michael@0 6315
michael@0 6316 } /* namespace JS */
michael@0 6317
michael@0 6318 #ifdef JS_THREADSAFE
michael@0 6319 static PRStatus
michael@0 6320 CallOnce(void *func)
michael@0 6321 {
michael@0 6322 JSInitCallback init = JS_DATA_TO_FUNC_PTR(JSInitCallback, func);
michael@0 6323 return init() ? PR_SUCCESS : PR_FAILURE;
michael@0 6324 }
michael@0 6325 #endif
michael@0 6326
michael@0 6327 JS_PUBLIC_API(bool)
michael@0 6328 JS_CallOnce(JSCallOnceType *once, JSInitCallback func)
michael@0 6329 {
michael@0 6330 #ifdef JS_THREADSAFE
michael@0 6331 return PR_CallOnceWithArg(once, CallOnce, JS_FUNC_TO_DATA_PTR(void *, func)) == PR_SUCCESS;
michael@0 6332 #else
michael@0 6333 if (!*once) {
michael@0 6334 *once = true;
michael@0 6335 return func();
michael@0 6336 } else {
michael@0 6337 return true;
michael@0 6338 }
michael@0 6339 #endif
michael@0 6340 }
michael@0 6341
michael@0 6342 AutoGCRooter::AutoGCRooter(JSContext *cx, ptrdiff_t tag)
michael@0 6343 : down(ContextFriendFields::get(cx)->autoGCRooters),
michael@0 6344 tag_(tag),
michael@0 6345 stackTop(&ContextFriendFields::get(cx)->autoGCRooters)
michael@0 6346 {
michael@0 6347 JS_ASSERT(this != *stackTop);
michael@0 6348 *stackTop = this;
michael@0 6349 }
michael@0 6350
michael@0 6351 AutoGCRooter::AutoGCRooter(ContextFriendFields *cx, ptrdiff_t tag)
michael@0 6352 : down(cx->autoGCRooters),
michael@0 6353 tag_(tag),
michael@0 6354 stackTop(&cx->autoGCRooters)
michael@0 6355 {
michael@0 6356 JS_ASSERT(this != *stackTop);
michael@0 6357 *stackTop = this;
michael@0 6358 }
michael@0 6359
michael@0 6360 #ifdef DEBUG
michael@0 6361 JS_PUBLIC_API(void)
michael@0 6362 JS::AssertArgumentsAreSane(JSContext *cx, HandleValue value)
michael@0 6363 {
michael@0 6364 AssertHeapIsIdle(cx);
michael@0 6365 CHECK_REQUEST(cx);
michael@0 6366 assertSameCompartment(cx, value);
michael@0 6367 }
michael@0 6368 #endif /* DEBUG */
michael@0 6369
michael@0 6370 JS_PUBLIC_API(void *)
michael@0 6371 JS_EncodeScript(JSContext *cx, HandleScript scriptArg, uint32_t *lengthp)
michael@0 6372 {
michael@0 6373 XDREncoder encoder(cx);
michael@0 6374 RootedScript script(cx, scriptArg);
michael@0 6375 if (!encoder.codeScript(&script))
michael@0 6376 return nullptr;
michael@0 6377 return encoder.forgetData(lengthp);
michael@0 6378 }
michael@0 6379
michael@0 6380 JS_PUBLIC_API(void *)
michael@0 6381 JS_EncodeInterpretedFunction(JSContext *cx, HandleObject funobjArg, uint32_t *lengthp)
michael@0 6382 {
michael@0 6383 XDREncoder encoder(cx);
michael@0 6384 RootedObject funobj(cx, funobjArg);
michael@0 6385 if (!encoder.codeFunction(&funobj))
michael@0 6386 return nullptr;
michael@0 6387 return encoder.forgetData(lengthp);
michael@0 6388 }
michael@0 6389
michael@0 6390 JS_PUBLIC_API(JSScript *)
michael@0 6391 JS_DecodeScript(JSContext *cx, const void *data, uint32_t length,
michael@0 6392 JSPrincipals *originPrincipals)
michael@0 6393 {
michael@0 6394 XDRDecoder decoder(cx, data, length, originPrincipals);
michael@0 6395 RootedScript script(cx);
michael@0 6396 if (!decoder.codeScript(&script))
michael@0 6397 return nullptr;
michael@0 6398 return script;
michael@0 6399 }
michael@0 6400
michael@0 6401 JS_PUBLIC_API(JSObject *)
michael@0 6402 JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length,
michael@0 6403 JSPrincipals *originPrincipals)
michael@0 6404 {
michael@0 6405 XDRDecoder decoder(cx, data, length, originPrincipals);
michael@0 6406 RootedObject funobj(cx);
michael@0 6407 if (!decoder.codeFunction(&funobj))
michael@0 6408 return nullptr;
michael@0 6409 return funobj;
michael@0 6410 }
michael@0 6411
michael@0 6412 JS_PUBLIC_API(bool)
michael@0 6413 JS_PreventExtensions(JSContext *cx, JS::HandleObject obj)
michael@0 6414 {
michael@0 6415 bool extensible;
michael@0 6416 if (!JSObject::isExtensible(cx, obj, &extensible))
michael@0 6417 return false;
michael@0 6418 if (!extensible)
michael@0 6419 return true;
michael@0 6420 return JSObject::preventExtensions(cx, obj);
michael@0 6421 }
michael@0 6422
michael@0 6423 JS_PUBLIC_API(void)
michael@0 6424 JS::SetAsmJSCacheOps(JSRuntime *rt, const JS::AsmJSCacheOps *ops)
michael@0 6425 {
michael@0 6426 rt->asmJSCacheOps = *ops;
michael@0 6427 }
michael@0 6428
michael@0 6429 char *
michael@0 6430 JSAutoByteString::encodeLatin1(ExclusiveContext *cx, JSString *str)
michael@0 6431 {
michael@0 6432 JSLinearString *linear = str->ensureLinear(cx);
michael@0 6433 if (!linear)
michael@0 6434 return nullptr;
michael@0 6435
michael@0 6436 mBytes = LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
michael@0 6437 return mBytes;
michael@0 6438 }
michael@0 6439
michael@0 6440 JS_PUBLIC_API(void)
michael@0 6441 JS::SetLargeAllocationFailureCallback(JSRuntime *rt, JS::LargeAllocationFailureCallback lafc)
michael@0 6442 {
michael@0 6443 rt->largeAllocationFailureCallback = lafc;
michael@0 6444 }
michael@0 6445
michael@0 6446 JS_PUBLIC_API(void)
michael@0 6447 JS::SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb)
michael@0 6448 {
michael@0 6449 rt->oomCallback = cb;
michael@0 6450 }
michael@0 6451

mercurial