1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 /*
8 * JavaScript API.
9 */
10
11 #include "jsapi.h"
12
13 #include "mozilla/FloatingPoint.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/PodOperations.h"
16 #include "mozilla/Sprintf.h"
17
18 #include <ctype.h>
19 #ifdef __linux__
20 #include <dlfcn.h>
21 #endif
22 #include <stdarg.h>
23 #include <string.h>
24 #include <sys/stat.h>
25
26 #include "jsarray.h"
27 #include "jsbool.h"
28 #include "jsdate.h"
29 #include "jsexn.h"
30 #include "jsfriendapi.h"
31 #include "jsmath.h"
32 #include "jsnum.h"
33 #include "jstypes.h"
34 #include "jsutil.h"
35
36 #include "builtin/AtomicsObject.h"
37 #include "builtin/Eval.h"
38 #include "builtin/JSON.h"
39 #include "builtin/MapObject.h"
40 #include "builtin/Promise.h"
41 #include "builtin/RegExp.h"
42 #include "builtin/Stream.h"
43 #include "builtin/String.h"
44 #include "builtin/Symbol.h"
45 #ifdef ENABLE_SIMD
46 #include "builtin/SIMD.h"
47 #endif
48 #ifdef ENABLE_BINARYDATA
49 #include "builtin/TypedObject.h"
50 #endif
51 #include "frontend/BytecodeCompiler.h"
52 #include "frontend/FullParseHandler.h" // for JS_BufferIsCompileableUnit
53 #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
54 #include "gc/FreeOp.h"
55 #include "gc/Marking.h"
56 #include "gc/Policy.h"
57 #include "gc/PublicIterators.h"
58 #include "gc/WeakMap.h"
59 #include "jit/JitCommon.h"
60 #include "js/CharacterEncoding.h"
61 #include "js/Conversions.h"
62 #include "js/Date.h"
63 #include "js/Initialization.h"
64 #include "js/Proxy.h"
65 #include "js/SliceBudget.h"
66 #include "js/StructuredClone.h"
67 #include "js/Utility.h"
68 #include "js/Wrapper.h"
69 #include "util/StringBuffer.h"
70 #include "util/Text.h"
71 #include "vm/AsyncFunction.h"
72 #include "vm/AsyncIteration.h"
73 #include "vm/DateObject.h"
74 #include "vm/Debugger.h"
75 #include "vm/EnvironmentObject.h"
76 #include "vm/ErrorObject.h"
77 #include "vm/HelperThreads.h"
78 #include "vm/Interpreter.h"
79 #include "vm/Iteration.h"
80 #include "vm/JSAtom.h"
81 #include "vm/JSContext.h"
82 #include "vm/JSFunction.h"
83 #include "vm/JSObject.h"
84 #include "vm/JSScript.h"
85 #include "vm/RegExpStatics.h"
86 #include "vm/Runtime.h"
87 #include "vm/SavedStacks.h"
88 #include "vm/SelfHosting.h"
89 #include "vm/Shape.h"
90 #include "vm/StringType.h"
91 #include "vm/SymbolType.h"
92 #include "vm/WrapperObject.h"
93 #include "vm/Xdr.h"
94 #include "wasm/AsmJS.h"
95 #include "wasm/WasmModule.h"
96
97 #include "vm/Interpreter-inl.h"
98 #include "vm/JSAtom-inl.h"
99 #include "vm/JSFunction-inl.h"
100 #include "vm/JSScript-inl.h"
101 #include "vm/NativeObject-inl.h"
102 #include "vm/SavedStacks-inl.h"
103 #include "vm/StringType-inl.h"
104
105 using namespace js;
106 using namespace js::gc;
107
108 using mozilla::Maybe;
109 using mozilla::PodCopy;
110 using mozilla::Some;
111
112 #ifdef HAVE_VA_LIST_AS_ARRAY
113 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list*)(ap))
114 #else
115 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
116 #endif
117
requireAtLeast(JSContext * cx,const char * fnname,unsigned required) const118 JS_PUBLIC_API bool JS::CallArgs::requireAtLeast(JSContext* cx,
119 const char* fnname,
120 unsigned required) const {
121 if (length() < required) {
122 char numArgsStr[40];
123 SprintfLiteral(numArgsStr, "%u", required - 1);
124 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
125 JSMSG_MORE_ARGS_NEEDED, fnname, numArgsStr,
126 required == 2 ? "" : "s");
127 return false;
128 }
129
130 return true;
131 }
132
ErrorTakesArguments(unsigned msg)133 static bool ErrorTakesArguments(unsigned msg) {
134 MOZ_ASSERT(msg < JSErr_Limit);
135 unsigned argCount = js_ErrorFormatString[msg].argCount;
136 MOZ_ASSERT(argCount <= 2);
137 return argCount == 1 || argCount == 2;
138 }
139
ErrorTakesObjectArgument(unsigned msg)140 static bool ErrorTakesObjectArgument(unsigned msg) {
141 MOZ_ASSERT(msg < JSErr_Limit);
142 unsigned argCount = js_ErrorFormatString[msg].argCount;
143 MOZ_ASSERT(argCount <= 2);
144 return argCount == 2;
145 }
146
reportStrictErrorOrWarning(JSContext * cx,HandleObject obj,HandleId id,bool strict)147 JS_PUBLIC_API bool JS::ObjectOpResult::reportStrictErrorOrWarning(
148 JSContext* cx, HandleObject obj, HandleId id, bool strict) {
149 static_assert(unsigned(OkCode) == unsigned(JSMSG_NOT_AN_ERROR),
150 "unsigned value of OkCode must not be an error code");
151 MOZ_ASSERT(code_ != Uninitialized);
152 MOZ_ASSERT(!ok());
153 assertSameCompartment(cx, obj);
154
155 unsigned flags =
156 strict ? JSREPORT_ERROR : (JSREPORT_WARNING | JSREPORT_STRICT);
157 if (code_ == JSMSG_OBJECT_NOT_EXTENSIBLE) {
158 RootedValue val(cx, ObjectValue(*obj));
159 return ReportValueErrorFlags(cx, flags, code_, JSDVG_IGNORE_STACK, val,
160 nullptr, nullptr, nullptr);
161 }
162
163 if (ErrorTakesArguments(code_)) {
164 RootedValue idv(cx, IdToValue(id));
165 RootedString str(cx, ValueToSource(cx, idv));
166 if (!str) return false;
167
168 JSAutoByteString propName;
169 if (!propName.encodeUtf8(cx, str)) return false;
170
171 if (code_ == JSMSG_SET_NON_OBJECT_RECEIVER) {
172 // We know that the original receiver was a primitive, so unbox it.
173 RootedValue val(cx, ObjectValue(*obj));
174 if (!obj->is<ProxyObject>()) {
175 if (!Unbox(cx, obj, &val)) return false;
176 }
177 return ReportValueErrorFlags(cx, flags, code_, JSDVG_IGNORE_STACK, val,
178 nullptr, propName.ptr(), nullptr);
179 }
180
181 if (ErrorTakesObjectArgument(code_)) {
182 return JS_ReportErrorFlagsAndNumberUTF8(
183 cx, flags, GetErrorMessage, nullptr, code_, obj->getClass()->name,
184 propName.ptr());
185 }
186
187 return JS_ReportErrorFlagsAndNumberUTF8(cx, flags, GetErrorMessage, nullptr,
188 code_, propName.ptr());
189 }
190 return JS_ReportErrorFlagsAndNumberASCII(cx, flags, GetErrorMessage, nullptr,
191 code_);
192 }
193
reportStrictErrorOrWarning(JSContext * cx,HandleObject obj,bool strict)194 JS_PUBLIC_API bool JS::ObjectOpResult::reportStrictErrorOrWarning(
195 JSContext* cx, HandleObject obj, bool strict) {
196 MOZ_ASSERT(code_ != Uninitialized);
197 MOZ_ASSERT(!ok());
198 MOZ_ASSERT(!ErrorTakesArguments(code_));
199 assertSameCompartment(cx, obj);
200
201 unsigned flags =
202 strict ? JSREPORT_ERROR : (JSREPORT_WARNING | JSREPORT_STRICT);
203 return JS_ReportErrorFlagsAndNumberASCII(cx, flags, GetErrorMessage, nullptr,
204 code_);
205 }
206
failCantRedefineProp()207 JS_PUBLIC_API bool JS::ObjectOpResult::failCantRedefineProp() {
208 return fail(JSMSG_CANT_REDEFINE_PROP);
209 }
210
failReadOnly()211 JS_PUBLIC_API bool JS::ObjectOpResult::failReadOnly() {
212 return fail(JSMSG_READ_ONLY);
213 }
214
failGetterOnly()215 JS_PUBLIC_API bool JS::ObjectOpResult::failGetterOnly() {
216 return fail(JSMSG_GETTER_ONLY);
217 }
218
failCantDelete()219 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDelete() {
220 return fail(JSMSG_CANT_DELETE);
221 }
222
failCantSetInterposed()223 JS_PUBLIC_API bool JS::ObjectOpResult::failCantSetInterposed() {
224 return fail(JSMSG_CANT_SET_INTERPOSED);
225 }
226
failCantDefineWindowElement()227 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowElement() {
228 return fail(JSMSG_CANT_DEFINE_WINDOW_ELEMENT);
229 }
230
failCantDeleteWindowElement()231 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDeleteWindowElement() {
232 return fail(JSMSG_CANT_DELETE_WINDOW_ELEMENT);
233 }
234
failCantDeleteWindowNamedProperty()235 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDeleteWindowNamedProperty() {
236 return fail(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY);
237 }
238
failCantPreventExtensions()239 JS_PUBLIC_API bool JS::ObjectOpResult::failCantPreventExtensions() {
240 return fail(JSMSG_CANT_PREVENT_EXTENSIONS);
241 }
242
failCantSetProto()243 JS_PUBLIC_API bool JS::ObjectOpResult::failCantSetProto() {
244 return fail(JSMSG_CANT_SET_PROTO);
245 }
246
failNoNamedSetter()247 JS_PUBLIC_API bool JS::ObjectOpResult::failNoNamedSetter() {
248 return fail(JSMSG_NO_NAMED_SETTER);
249 }
250
failNoIndexedSetter()251 JS_PUBLIC_API bool JS::ObjectOpResult::failNoIndexedSetter() {
252 return fail(JSMSG_NO_INDEXED_SETTER);
253 }
254
JS_Now()255 JS_PUBLIC_API int64_t JS_Now() { return PRMJ_Now(); }
256
JS_GetNaNValue(JSContext * cx)257 JS_PUBLIC_API Value JS_GetNaNValue(JSContext* cx) {
258 return cx->runtime()->NaNValue;
259 }
260
JS_GetNegativeInfinityValue(JSContext * cx)261 JS_PUBLIC_API Value JS_GetNegativeInfinityValue(JSContext* cx) {
262 return cx->runtime()->negativeInfinityValue;
263 }
264
JS_GetPositiveInfinityValue(JSContext * cx)265 JS_PUBLIC_API Value JS_GetPositiveInfinityValue(JSContext* cx) {
266 return cx->runtime()->positiveInfinityValue;
267 }
268
JS_GetEmptyStringValue(JSContext * cx)269 JS_PUBLIC_API Value JS_GetEmptyStringValue(JSContext* cx) {
270 return StringValue(cx->runtime()->emptyString);
271 }
272
JS_GetEmptyString(JSContext * cx)273 JS_PUBLIC_API JSString* JS_GetEmptyString(JSContext* cx) {
274 MOZ_ASSERT(cx->emptyString());
275 return cx->emptyString();
276 }
277
278 namespace js {
279
AssertHeapIsIdle()280 void AssertHeapIsIdle() { MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy()); }
281
282 } // namespace js
283
AssertHeapIsIdleOrIterating()284 static void AssertHeapIsIdleOrIterating() {
285 MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
286 }
287
AssertHeapIsIdleOrStringIsFlat(JSString * str)288 static void AssertHeapIsIdleOrStringIsFlat(JSString* str) {
289 /*
290 * We allow some functions to be called during a GC as long as the argument
291 * is a flat string, since that will not cause allocation.
292 */
293 MOZ_ASSERT_IF(JS::CurrentThreadIsHeapBusy(), str->isFlat());
294 }
295
JS_ValueToObject(JSContext * cx,HandleValue value,MutableHandleObject objp)296 JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, HandleValue value,
297 MutableHandleObject objp) {
298 AssertHeapIsIdle();
299 CHECK_REQUEST(cx);
300 assertSameCompartment(cx, value);
301 if (value.isNullOrUndefined()) {
302 objp.set(nullptr);
303 return true;
304 }
305 JSObject* obj = ToObject(cx, value);
306 if (!obj) return false;
307 objp.set(obj);
308 return true;
309 }
310
JS_ValueToFunction(JSContext * cx,HandleValue value)311 JS_PUBLIC_API JSFunction* JS_ValueToFunction(JSContext* cx, HandleValue value) {
312 AssertHeapIsIdle();
313 CHECK_REQUEST(cx);
314 assertSameCompartment(cx, value);
315 return ReportIfNotFunction(cx, value);
316 }
317
JS_ValueToConstructor(JSContext * cx,HandleValue value)318 JS_PUBLIC_API JSFunction* JS_ValueToConstructor(JSContext* cx,
319 HandleValue value) {
320 AssertHeapIsIdle();
321 CHECK_REQUEST(cx);
322 assertSameCompartment(cx, value);
323 return ReportIfNotFunction(cx, value);
324 }
325
JS_ValueToSource(JSContext * cx,HandleValue value)326 JS_PUBLIC_API JSString* JS_ValueToSource(JSContext* cx, HandleValue value) {
327 AssertHeapIsIdle();
328 CHECK_REQUEST(cx);
329 assertSameCompartment(cx, value);
330 return ValueToSource(cx, value);
331 }
332
JS_DoubleIsInt32(double d,int32_t * ip)333 JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip) {
334 return mozilla::NumberIsInt32(d, ip);
335 }
336
JS_TypeOfValue(JSContext * cx,HandleValue value)337 JS_PUBLIC_API JSType JS_TypeOfValue(JSContext* cx, HandleValue value) {
338 AssertHeapIsIdle();
339 CHECK_REQUEST(cx);
340 assertSameCompartment(cx, value);
341 return TypeOfValue(value);
342 }
343
JS_StrictlyEqual(JSContext * cx,HandleValue value1,HandleValue value2,bool * equal)344 JS_PUBLIC_API bool JS_StrictlyEqual(JSContext* cx, HandleValue value1,
345 HandleValue value2, bool* equal) {
346 AssertHeapIsIdle();
347 CHECK_REQUEST(cx);
348 assertSameCompartment(cx, value1, value2);
349 MOZ_ASSERT(equal);
350 return StrictlyEqual(cx, value1, value2, equal);
351 }
352
JS_LooselyEqual(JSContext * cx,HandleValue value1,HandleValue value2,bool * equal)353 JS_PUBLIC_API bool JS_LooselyEqual(JSContext* cx, HandleValue value1,
354 HandleValue value2, bool* equal) {
355 AssertHeapIsIdle();
356 CHECK_REQUEST(cx);
357 assertSameCompartment(cx, value1, value2);
358 MOZ_ASSERT(equal);
359 return LooselyEqual(cx, value1, value2, equal);
360 }
361
JS_SameValue(JSContext * cx,HandleValue value1,HandleValue value2,bool * same)362 JS_PUBLIC_API bool JS_SameValue(JSContext* cx, HandleValue value1,
363 HandleValue value2, bool* same) {
364 AssertHeapIsIdle();
365 CHECK_REQUEST(cx);
366 assertSameCompartment(cx, value1, value2);
367 MOZ_ASSERT(same);
368 return SameValue(cx, value1, value2, same);
369 }
370
JS_IsBuiltinEvalFunction(JSFunction * fun)371 JS_PUBLIC_API bool JS_IsBuiltinEvalFunction(JSFunction* fun) {
372 return IsAnyBuiltinEval(fun);
373 }
374
JS_IsBuiltinFunctionConstructor(JSFunction * fun)375 JS_PUBLIC_API bool JS_IsBuiltinFunctionConstructor(JSFunction* fun) {
376 return fun->isBuiltinFunctionConstructor();
377 }
378
JS_IsFunctionBound(JSFunction * fun)379 JS_PUBLIC_API bool JS_IsFunctionBound(JSFunction* fun) {
380 return fun->isBoundFunction();
381 }
382
JS_GetBoundFunctionTarget(JSFunction * fun)383 JS_PUBLIC_API JSObject* JS_GetBoundFunctionTarget(JSFunction* fun) {
384 return fun->isBoundFunction() ? fun->getBoundFunctionTarget() : nullptr;
385 }
386
387 /************************************************************************/
388
389 #ifdef DEBUG
isGCEnabled()390 JS_FRIEND_API bool JS::isGCEnabled() { return !TlsContext.get()->suppressGC; }
391 #else
isGCEnabled()392 JS_FRIEND_API bool JS::isGCEnabled() { return true; }
393 #endif
394
JS_NewContext(uint32_t maxbytes,uint32_t maxNurseryBytes,JSRuntime * parentRuntime)395 JS_PUBLIC_API JSContext* JS_NewContext(uint32_t maxbytes,
396 uint32_t maxNurseryBytes,
397 JSRuntime* parentRuntime) {
398 MOZ_ASSERT(JS::detail::libraryInitState == JS::detail::InitState::Running,
399 "must call JS_Init prior to creating any JSContexts");
400
401 // Make sure that all parent runtimes are the topmost parent.
402 while (parentRuntime && parentRuntime->parentRuntime)
403 parentRuntime = parentRuntime->parentRuntime;
404
405 return NewContext(maxbytes, maxNurseryBytes, parentRuntime);
406 }
407
JS_NewCooperativeContext(JSContext * siblingContext)408 JS_PUBLIC_API JSContext* JS_NewCooperativeContext(JSContext* siblingContext) {
409 return NewCooperativeContext(siblingContext);
410 }
411
JS_YieldCooperativeContext(JSContext * cx)412 JS_PUBLIC_API void JS_YieldCooperativeContext(JSContext* cx) {
413 YieldCooperativeContext(cx);
414 }
415
JS_ResumeCooperativeContext(JSContext * cx)416 JS_PUBLIC_API void JS_ResumeCooperativeContext(JSContext* cx) {
417 ResumeCooperativeContext(cx);
418 }
419
JS_DestroyContext(JSContext * cx)420 JS_PUBLIC_API void JS_DestroyContext(JSContext* cx) { DestroyContext(cx); }
421
JS_GetContextPrivate(JSContext * cx)422 JS_PUBLIC_API void* JS_GetContextPrivate(JSContext* cx) { return cx->data; }
423
JS_SetContextPrivate(JSContext * cx,void * data)424 JS_PUBLIC_API void JS_SetContextPrivate(JSContext* cx, void* data) {
425 cx->data = data;
426 }
427
JS_SetFutexCanWait(JSContext * cx)428 JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx) {
429 cx->fx.setCanWait(true);
430 }
431
StartRequest(JSContext * cx)432 static void StartRequest(JSContext* cx) {
433 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
434
435 if (cx->requestDepth) {
436 cx->requestDepth++;
437 } else {
438 /* Indicate that a request is running. */
439 cx->requestDepth = 1;
440 cx->triggerActivityCallback(true);
441 }
442 }
443
StopRequest(JSContext * cx)444 static void StopRequest(JSContext* cx) {
445 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
446
447 MOZ_ASSERT(cx->requestDepth != 0);
448 if (cx->requestDepth != 1) {
449 cx->requestDepth--;
450 } else {
451 cx->requestDepth = 0;
452 cx->triggerActivityCallback(false);
453 }
454 }
455
JS_BeginRequest(JSContext * cx)456 JS_PUBLIC_API void JS_BeginRequest(JSContext* cx) {
457 cx->outstandingRequests++;
458 StartRequest(cx);
459 }
460
JS_EndRequest(JSContext * cx)461 JS_PUBLIC_API void JS_EndRequest(JSContext* cx) {
462 MOZ_ASSERT(cx->outstandingRequests != 0);
463 cx->outstandingRequests--;
464 StopRequest(cx);
465 }
466
JS_GetParentRuntime(JSContext * cx)467 JS_PUBLIC_API JSRuntime* JS_GetParentRuntime(JSContext* cx) {
468 return cx->runtime()->parentRuntime ? cx->runtime()->parentRuntime
469 : cx->runtime();
470 }
471
JS_GetRuntime(JSContext * cx)472 JS_PUBLIC_API JSRuntime* JS_GetRuntime(JSContext* cx) { return cx->runtime(); }
473
SetSingleThreadedExecutionCallbacks(JSContext * cx,BeginSingleThreadedExecutionCallback begin,EndSingleThreadedExecutionCallback end)474 JS_PUBLIC_API void JS::SetSingleThreadedExecutionCallbacks(
475 JSContext* cx, BeginSingleThreadedExecutionCallback begin,
476 EndSingleThreadedExecutionCallback end) {
477 cx->runtime()->beginSingleThreadedExecutionCallback = begin;
478 cx->runtime()->endSingleThreadedExecutionCallback = end;
479 }
480
ContextOptionsRef(JSContext * cx)481 JS_PUBLIC_API JS::ContextOptions& JS::ContextOptionsRef(JSContext* cx) {
482 return cx->options();
483 }
484
InitSelfHostedCode(JSContext * cx)485 JS_PUBLIC_API bool JS::InitSelfHostedCode(JSContext* cx) {
486 MOZ_RELEASE_ASSERT(!cx->runtime()->hasInitializedSelfHosting(),
487 "JS::InitSelfHostedCode() called more than once");
488
489 AutoNoteSingleThreadedRegion anstr;
490
491 JSRuntime* rt = cx->runtime();
492
493 JSAutoRequest ar(cx);
494 if (!rt->initializeAtoms(cx)) return false;
495
496 #ifndef JS_CODEGEN_NONE
497 if (!rt->getJitRuntime(cx)) return false;
498 #endif
499
500 if (!rt->initSelfHosting(cx)) return false;
501
502 if (!rt->parentRuntime && !rt->transformToPermanentAtoms(cx)) return false;
503
504 return true;
505 }
506
JS_GetImplementationVersion(void)507 JS_PUBLIC_API const char* JS_GetImplementationVersion(void) {
508 return "JavaScript-C" MOZILLA_VERSION;
509 }
510
JS_SetDestroyCompartmentCallback(JSContext * cx,JSDestroyCompartmentCallback callback)511 JS_PUBLIC_API void JS_SetDestroyCompartmentCallback(
512 JSContext* cx, JSDestroyCompartmentCallback callback) {
513 cx->runtime()->destroyCompartmentCallback = callback;
514 }
515
JS_SetSizeOfIncludingThisCompartmentCallback(JSContext * cx,JSSizeOfIncludingThisCompartmentCallback callback)516 JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback(
517 JSContext* cx, JSSizeOfIncludingThisCompartmentCallback callback) {
518 cx->runtime()->sizeOfIncludingThisCompartmentCallback = callback;
519 }
520
JS_SetCompartmentNameCallback(JSContext * cx,JSCompartmentNameCallback callback)521 JS_PUBLIC_API void JS_SetCompartmentNameCallback(
522 JSContext* cx, JSCompartmentNameCallback callback) {
523 cx->runtime()->compartmentNameCallback = callback;
524 }
525
526 #if defined(NIGHTLY_BUILD)
JS_SetErrorInterceptorCallback(JSRuntime * rt,JSErrorInterceptor * callback)527 JS_PUBLIC_API void JS_SetErrorInterceptorCallback(
528 JSRuntime* rt, JSErrorInterceptor* callback) {
529 rt->errorInterception.interceptor = callback;
530 }
531
JS_GetErrorInterceptorCallback(JSRuntime * rt)532 JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback(
533 JSRuntime* rt) {
534 return rt->errorInterception.interceptor;
535 }
536
JS_GetErrorType(const JS::Value & val)537 JS_PUBLIC_API Maybe<JSExnType> JS_GetErrorType(const JS::Value& val) {
538 // All errors are objects.
539 if (!val.isObject()) return mozilla::Nothing();
540
541 const JSObject& obj = val.toObject();
542
543 // All errors are `ErrorObject`.
544 if (!obj.is<js::ErrorObject>()) {
545 // Not one of the primitive errors.
546 return mozilla::Nothing();
547 }
548
549 const js::ErrorObject& err = obj.as<js::ErrorObject>();
550 return mozilla::Some(err.type());
551 }
552
553 #endif // defined(NIGHTLY_BUILD)
554
JS_SetWrapObjectCallbacks(JSContext * cx,const JSWrapObjectCallbacks * callbacks)555 JS_PUBLIC_API void JS_SetWrapObjectCallbacks(
556 JSContext* cx, const JSWrapObjectCallbacks* callbacks) {
557 cx->runtime()->wrapObjectCallbacks = callbacks;
558 }
559
JS_SetExternalStringSizeofCallback(JSContext * cx,JSExternalStringSizeofCallback callback)560 JS_PUBLIC_API void JS_SetExternalStringSizeofCallback(
561 JSContext* cx, JSExternalStringSizeofCallback callback) {
562 cx->runtime()->externalStringSizeofCallback = callback;
563 }
564
JS_EnterCompartment(JSContext * cx,JSObject * target)565 JS_PUBLIC_API JSCompartment* JS_EnterCompartment(JSContext* cx,
566 JSObject* target) {
567 AssertHeapIsIdle();
568 CHECK_REQUEST(cx);
569
570 JSCompartment* oldCompartment = cx->compartment();
571 cx->enterCompartmentOf(target);
572 return oldCompartment;
573 }
574
JS_LeaveCompartment(JSContext * cx,JSCompartment * oldCompartment)575 JS_PUBLIC_API void JS_LeaveCompartment(JSContext* cx,
576 JSCompartment* oldCompartment) {
577 AssertHeapIsIdle();
578 CHECK_REQUEST(cx);
579 cx->leaveCompartment(oldCompartment);
580 }
581
JSAutoCompartment(JSContext * cx,JSObject * target MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)582 JSAutoCompartment::JSAutoCompartment(
583 JSContext* cx, JSObject* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
584 : cx_(cx), oldCompartment_(cx->compartment()) {
585 AssertHeapIsIdleOrIterating();
586 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
587 cx_->enterCompartmentOf(target);
588 }
589
JSAutoCompartment(JSContext * cx,JSScript * target MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)590 JSAutoCompartment::JSAutoCompartment(
591 JSContext* cx, JSScript* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
592 : cx_(cx), oldCompartment_(cx->compartment()) {
593 AssertHeapIsIdleOrIterating();
594 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
595 cx_->enterCompartmentOf(target);
596 }
597
~JSAutoCompartment()598 JSAutoCompartment::~JSAutoCompartment() {
599 cx_->leaveCompartment(oldCompartment_);
600 }
601
JSAutoNullableCompartment(JSContext * cx,JSObject * targetOrNull MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)602 JSAutoNullableCompartment::JSAutoNullableCompartment(
603 JSContext* cx,
604 JSObject* targetOrNull MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
605 : cx_(cx), oldCompartment_(cx->compartment()) {
606 AssertHeapIsIdleOrIterating();
607 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
608 if (targetOrNull)
609 cx_->enterCompartmentOf(targetOrNull);
610 else
611 cx_->enterNullCompartment();
612 }
613
~JSAutoNullableCompartment()614 JSAutoNullableCompartment::~JSAutoNullableCompartment() {
615 cx_->leaveCompartment(oldCompartment_);
616 }
617
JS_SetCompartmentPrivate(JSCompartment * compartment,void * data)618 JS_PUBLIC_API void JS_SetCompartmentPrivate(JSCompartment* compartment,
619 void* data) {
620 compartment->data = data;
621 }
622
JS_GetCompartmentPrivate(JSCompartment * compartment)623 JS_PUBLIC_API void* JS_GetCompartmentPrivate(JSCompartment* compartment) {
624 return compartment->data;
625 }
626
JS_MarkCrossZoneId(JSContext * cx,jsid id)627 JS_PUBLIC_API void JS_MarkCrossZoneId(JSContext* cx, jsid id) {
628 cx->markId(id);
629 }
630
JS_MarkCrossZoneIdValue(JSContext * cx,const Value & value)631 JS_PUBLIC_API void JS_MarkCrossZoneIdValue(JSContext* cx, const Value& value) {
632 cx->markAtomValue(value);
633 }
634
NewAddonId(JSContext * cx,HandleString str)635 JS_PUBLIC_API JSAddonId* JS::NewAddonId(JSContext* cx, HandleString str) {
636 return static_cast<JSAddonId*>(JS_AtomizeAndPinJSString(cx, str));
637 }
638
StringOfAddonId(JSAddonId * id)639 JS_PUBLIC_API JSString* JS::StringOfAddonId(JSAddonId* id) { return id; }
640
AddonIdOfObject(JSObject * obj)641 JS_PUBLIC_API JSAddonId* JS::AddonIdOfObject(JSObject* obj) {
642 return obj->compartment()->creationOptions().addonIdOrNull();
643 }
644
JS_SetZoneUserData(JS::Zone * zone,void * data)645 JS_PUBLIC_API void JS_SetZoneUserData(JS::Zone* zone, void* data) {
646 zone->data = data;
647 }
648
JS_GetZoneUserData(JS::Zone * zone)649 JS_PUBLIC_API void* JS_GetZoneUserData(JS::Zone* zone) { return zone->data; }
650
JS_WrapObject(JSContext * cx,MutableHandleObject objp)651 JS_PUBLIC_API bool JS_WrapObject(JSContext* cx, MutableHandleObject objp) {
652 AssertHeapIsIdle();
653 CHECK_REQUEST(cx);
654 if (objp) JS::ExposeObjectToActiveJS(objp);
655 return cx->compartment()->wrap(cx, objp);
656 }
657
JS_WrapValue(JSContext * cx,MutableHandleValue vp)658 JS_PUBLIC_API bool JS_WrapValue(JSContext* cx, MutableHandleValue vp) {
659 AssertHeapIsIdle();
660 CHECK_REQUEST(cx);
661 JS::ExposeValueToActiveJS(vp);
662 return cx->compartment()->wrap(cx, vp);
663 }
664
ReleaseAssertObjectHasNoWrappers(JSContext * cx,HandleObject target)665 static void ReleaseAssertObjectHasNoWrappers(JSContext* cx,
666 HandleObject target) {
667 RootedValue origv(cx, ObjectValue(*target));
668
669 for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
670 if (c->lookupWrapper(origv)) MOZ_CRASH("wrapper found for target object");
671 }
672 }
673
674 /*
675 * Brain transplants. Not for beginners or the squeamish.
676 *
677 * Sometimes a web spec requires us to transplant an object from one
678 * compartment to another, like when a DOM node is inserted into a document in
679 * another window and thus gets "adopted". We cannot literally change the
680 * `.compartment()` of a `JSObject`; that would break the compartment
681 * invariants. However, as usual, we have a workaround using wrappers.
682 *
683 * Of all the wrapper-based workarounds we do, it's safe to say this is the
684 * most spectacular and questionable.
685 *
686 * `JS_TransplantObject(cx, origobj, target)` changes `origobj` into a
687 * simulacrum of `target`, using highly esoteric means. To JS code, the effect
688 * is as if `origobj` magically "became" `target`, but most often what actually
689 * happens is that `origobj` gets turned into a cross-compartment wrapper for
690 * `target`. The old behavior and contents of `origobj` are overwritten or
691 * discarded.
692 *
693 * Thus, to "transplant" an object from one compartment to another:
694 *
695 * 1. Let `origobj` be the object that you want to move. First, create a
696 * clone of it, `target`, in the destination compartment.
697 *
698 * In our DOM adoption example, `target` will be a Node of the same type as
699 * `origobj`, same content, but in the adopting document. We're not done
700 * yet: the spec for DOM adoption requires that `origobj.ownerDocument`
701 * actually change. All we've done so far is make a copy.
702 *
703 * 2. Call `JS_TransplantObject(cx, origobj, target)`. This typically turns
704 * `origobj` into a wrapper for `target`, so that any JS code that has a
705 * reference to `origobj` will observe it to have the behavior of `target`
706 * going forward. In addition, all existing wrappers for `origobj` are
707 * changed into wrappers for `target`, extending the illusion to those
708 * compartments as well.
709 *
710 * During navigation, we use the above technique to transplant the WindowProxy
711 * into the new Window's compartment.
712 *
713 * A few rules:
714 *
715 * - `origobj` and `target` must be two distinct objects of the same
716 * `JSClass`. Some classes may not support transplantation; WindowProxy
717 * objects and DOM nodes are OK.
718 *
719 * - `target` should be created specifically to be passed to this function.
720 * There must be no existing cross-compartment wrappers for it; ideally
721 * there shouldn't be any pointers to it at all, except the one passed in.
722 *
723 * - `target` shouldn't be used afterwards. Instead, `JS_TransplantObject`
724 * returns a pointer to the transplanted object, which might be `target`
725 * but might be some other object in the same compartment. Use that.
726 *
727 * The reason for this last rule is that JS_TransplantObject does very strange
728 * things in some cases, like swapping `target`'s brain with that of another
729 * object. Leaving `target` behaving like its former self is not a goal.
730 *
731 * We don't have a good way to recover from failure in this function, so
732 * we intentionally crash instead.
733 */
734
JS_TransplantObject(JSContext * cx,HandleObject origobj,HandleObject target)735 JS_PUBLIC_API JSObject* JS_TransplantObject(JSContext* cx, HandleObject origobj,
736 HandleObject target) {
737 AssertHeapIsIdle();
738 MOZ_ASSERT(origobj != target);
739 MOZ_ASSERT(!origobj->is<CrossCompartmentWrapperObject>());
740 MOZ_ASSERT(!target->is<CrossCompartmentWrapperObject>());
741 MOZ_ASSERT(origobj->getClass() == target->getClass());
742 ReleaseAssertObjectHasNoWrappers(cx, target);
743
744 RootedValue origv(cx, ObjectValue(*origobj));
745 RootedObject newIdentity(cx);
746
747 // Don't allow a compacting GC to observe any intermediate state.
748 AutoDisableCompactingGC nocgc(cx);
749
750 AutoDisableProxyCheck adpc;
751
752 JSCompartment* destination = target->compartment();
753
754 if (origobj->compartment() == destination) {
755 // If the original object is in the same compartment as the
756 // destination, then we know that we won't find a wrapper in the
757 // destination's cross compartment map and that the same
758 // object will continue to work.
759 AutoCompartment ac(cx, origobj);
760 if (!JSObject::swap(cx, origobj, target)) MOZ_CRASH();
761 newIdentity = origobj;
762 } else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
763 // There might already be a wrapper for the original object in
764 // the new compartment. If there is, we use its identity and swap
765 // in the contents of |target|.
766 newIdentity = &p->value().get().toObject();
767
768 // When we remove origv from the wrapper map, its wrapper, newIdentity,
769 // must immediately cease to be a cross-compartment wrapper. Nuke it.
770 destination->removeWrapper(p);
771 NukeCrossCompartmentWrapper(cx, newIdentity);
772
773 AutoCompartment ac(cx, newIdentity);
774 if (!JSObject::swap(cx, newIdentity, target)) MOZ_CRASH();
775 } else {
776 // Otherwise, we use |target| for the new identity object.
777 newIdentity = target;
778 }
779
780 // Now, iterate through other scopes looking for references to the old
781 // object, and update the relevant cross-compartment wrappers. We do this
782 // even if origobj is in the same compartment as target and thus
783 // `newIdentity == origobj`, because this process also clears out any
784 // cached wrapper state.
785 if (!RemapAllWrappersForObject(cx, origobj, newIdentity)) MOZ_CRASH();
786
787 // Lastly, update the original object to point to the new one.
788 if (origobj->compartment() != destination) {
789 RootedObject newIdentityWrapper(cx, newIdentity);
790 AutoCompartment ac(cx, origobj);
791 if (!JS_WrapObject(cx, &newIdentityWrapper)) MOZ_CRASH();
792 MOZ_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
793 if (!JSObject::swap(cx, origobj, newIdentityWrapper)) MOZ_CRASH();
794 if (!origobj->compartment()->putWrapper(
795 cx, CrossCompartmentKey(newIdentity), origv))
796 MOZ_CRASH();
797 }
798
799 // The new identity object might be one of several things. Return it to avoid
800 // ambiguity.
801 return newIdentity;
802 }
803
804 /*
805 * Recompute all cross-compartment wrappers for an object, resetting state.
806 * Gecko uses this to clear Xray wrappers when doing a navigation that reuses
807 * the inner window and global object.
808 */
JS_RefreshCrossCompartmentWrappers(JSContext * cx,HandleObject obj)809 JS_PUBLIC_API bool JS_RefreshCrossCompartmentWrappers(JSContext* cx,
810 HandleObject obj) {
811 return RemapAllWrappersForObject(cx, obj, obj);
812 }
813
JS_InitStandardClasses(JSContext * cx,HandleObject obj)814 JS_PUBLIC_API bool JS_InitStandardClasses(JSContext* cx, HandleObject obj) {
815 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
816 AssertHeapIsIdle();
817 CHECK_REQUEST(cx);
818
819 assertSameCompartment(cx, obj);
820
821 Rooted<GlobalObject*> global(cx, &obj->global());
822 return GlobalObject::initStandardClasses(cx, global);
823 }
824
825 #define EAGER_ATOM(name) NAME_OFFSET(name)
826
827 typedef struct JSStdName {
828 size_t atomOffset; /* offset of atom pointer in JSAtomState */
829 JSProtoKey key;
isDummyJSStdName830 bool isDummy() const { return key == JSProto_Null; }
isSentinelJSStdName831 bool isSentinel() const { return key == JSProto_LIMIT; }
832 } JSStdName;
833
LookupStdName(const JSAtomState & names,JSAtom * name,const JSStdName * table)834 static const JSStdName* LookupStdName(const JSAtomState& names, JSAtom* name,
835 const JSStdName* table) {
836 for (unsigned i = 0; !table[i].isSentinel(); i++) {
837 if (table[i].isDummy()) continue;
838 JSAtom* atom = AtomStateOffsetToName(names, table[i].atomOffset);
839 MOZ_ASSERT(atom);
840 if (name == atom) return &table[i];
841 }
842
843 return nullptr;
844 }
845
846 /*
847 * Table of standard classes, indexed by JSProtoKey. For entries where the
848 * JSProtoKey does not correspond to a class with a meaningful constructor, we
849 * insert a null entry into the table.
850 */
851 #define STD_NAME_ENTRY(name, init, clasp) {EAGER_ATOM(name), JSProto_##name},
852 #define STD_DUMMY_ENTRY(name, init, dummy) {0, JSProto_Null},
853 static const JSStdName standard_class_names[] = {
854 JS_FOR_PROTOTYPES(STD_NAME_ENTRY, STD_DUMMY_ENTRY){0, JSProto_LIMIT}};
855
856 /*
857 * Table of top-level function and constant names and the JSProtoKey of the
858 * standard class that initializes them.
859 */
860 static const JSStdName builtin_property_names[] = {
861 {EAGER_ATOM(eval), JSProto_Object},
862
863 /* Global properties and functions defined by the Number class. */
864 {EAGER_ATOM(NaN), JSProto_Number},
865 {EAGER_ATOM(Infinity), JSProto_Number},
866 {EAGER_ATOM(isNaN), JSProto_Number},
867 {EAGER_ATOM(isFinite), JSProto_Number},
868 {EAGER_ATOM(parseFloat), JSProto_Number},
869 {EAGER_ATOM(parseInt), JSProto_Number},
870
871 /* String global functions. */
872 {EAGER_ATOM(escape), JSProto_String},
873 {EAGER_ATOM(unescape), JSProto_String},
874 {EAGER_ATOM(decodeURI), JSProto_String},
875 {EAGER_ATOM(encodeURI), JSProto_String},
876 {EAGER_ATOM(decodeURIComponent), JSProto_String},
877 {EAGER_ATOM(encodeURIComponent), JSProto_String},
878 {EAGER_ATOM(uneval), JSProto_String},
879
880 {0, JSProto_LIMIT}};
881
882 #undef EAGER_ATOM
883
JS_ResolveStandardClass(JSContext * cx,HandleObject obj,HandleId id,bool * resolved)884 JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx, HandleObject obj,
885 HandleId id, bool* resolved) {
886 const JSStdName* stdnm;
887
888 AssertHeapIsIdle();
889 CHECK_REQUEST(cx);
890 assertSameCompartment(cx, obj, id);
891
892 Handle<GlobalObject*> global = obj.as<GlobalObject>();
893 *resolved = false;
894
895 if (!JSID_IS_ATOM(id)) return true;
896
897 /* Check whether we're resolving 'undefined', and define it if so. */
898 JSAtom* idAtom = JSID_TO_ATOM(id);
899 JSAtom* undefinedAtom = cx->names().undefined;
900 if (idAtom == undefinedAtom) {
901 *resolved = true;
902 return DefineDataProperty(
903 cx, global, id, UndefinedHandleValue,
904 JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING);
905 }
906
907 /* Try for class constructors/prototypes named by well-known atoms. */
908 stdnm = LookupStdName(cx->names(), idAtom, standard_class_names);
909
910 /* Try less frequently used top-level functions and constants. */
911 if (!stdnm)
912 stdnm = LookupStdName(cx->names(), idAtom, builtin_property_names);
913
914 if (stdnm && GlobalObject::skipDeselectedConstructor(cx, stdnm->key))
915 stdnm = nullptr;
916
917 // If this class is anonymous, then it doesn't exist as a global
918 // property, so we won't resolve anything.
919 JSProtoKey key = stdnm ? stdnm->key : JSProto_Null;
920 if (key != JSProto_Null) {
921 const Class* clasp = ProtoKeyToClass(key);
922 if (!clasp || !(clasp->flags & JSCLASS_IS_ANONYMOUS)) {
923 if (!GlobalObject::ensureConstructor(cx, global, key)) return false;
924
925 *resolved = true;
926 return true;
927 }
928 }
929
930 // There is no such property to resolve. An ordinary resolve hook would
931 // just return true at this point. But the global object is special in one
932 // more way: its prototype chain is lazily initialized. That is,
933 // global->getProto() might be null right now because we haven't created
934 // Object.prototype yet. Force it now.
935 return GlobalObject::getOrCreateObjectPrototype(cx, global);
936 }
937
JS_MayResolveStandardClass(const JSAtomState & names,jsid id,JSObject * maybeObj)938 JS_PUBLIC_API bool JS_MayResolveStandardClass(const JSAtomState& names, jsid id,
939 JSObject* maybeObj) {
940 MOZ_ASSERT_IF(maybeObj, maybeObj->is<GlobalObject>());
941
942 // The global object's resolve hook is special: JS_ResolveStandardClass
943 // initializes the prototype chain lazily. Only attempt to optimize here
944 // if we know the prototype chain has been initialized.
945 if (!maybeObj || !maybeObj->staticPrototype()) return true;
946
947 if (!JSID_IS_ATOM(id)) return false;
948
949 JSAtom* atom = JSID_TO_ATOM(id);
950
951 // This will return true even for deselected constructors. (To do
952 // better, we need a JSContext here; it's fine as it is.)
953
954 return atom == names.undefined ||
955 LookupStdName(names, atom, standard_class_names) ||
956 LookupStdName(names, atom, builtin_property_names);
957 }
958
JS_EnumerateStandardClasses(JSContext * cx,HandleObject obj)959 JS_PUBLIC_API bool JS_EnumerateStandardClasses(JSContext* cx,
960 HandleObject obj) {
961 AssertHeapIsIdle();
962 CHECK_REQUEST(cx);
963 assertSameCompartment(cx, obj);
964 Handle<GlobalObject*> global = obj.as<GlobalObject>();
965 return GlobalObject::initStandardClasses(cx, global);
966 }
967
EnumerateUnresolvedStandardClasses(JSContext * cx,Handle<GlobalObject * > global,AutoIdVector & properties,const JSStdName * table)968 static bool EnumerateUnresolvedStandardClasses(JSContext* cx,
969 Handle<GlobalObject*> global,
970 AutoIdVector& properties,
971 const JSStdName* table) {
972 for (unsigned i = 0; !table[i].isSentinel(); i++) {
973 if (table[i].isDummy()) continue;
974
975 JSProtoKey key = table[i].key;
976
977 // If the standard class has been resolved, the properties have been
978 // defined on the global so we don't need to add them here.
979 if (global->isStandardClassResolved(key)) continue;
980
981 if (GlobalObject::skipDeselectedConstructor(cx, key)) continue;
982
983 if (const Class* clasp = ProtoKeyToClass(key)) {
984 if (clasp->flags & JSCLASS_IS_ANONYMOUS) continue;
985 if (!clasp->specShouldDefineConstructor()) continue;
986 }
987
988 jsid id = NameToId(AtomStateOffsetToName(cx->names(), table[i].atomOffset));
989 if (!properties.append(id)) return false;
990 }
991
992 return true;
993 }
994
JS_NewEnumerateStandardClasses(JSContext * cx,JS::HandleObject obj,JS::AutoIdVector & properties,bool enumerableOnly)995 JS_PUBLIC_API bool JS_NewEnumerateStandardClasses(JSContext* cx,
996 JS::HandleObject obj,
997 JS::AutoIdVector& properties,
998 bool enumerableOnly) {
999 if (enumerableOnly) {
1000 // There are no enumerable lazy properties.
1001 return true;
1002 }
1003
1004 Handle<GlobalObject*> global = obj.as<GlobalObject>();
1005
1006 // It's fine to always append |undefined| here, it's non-configurable and
1007 // the enumeration code filters duplicates.
1008 if (!properties.append(NameToId(cx->names().undefined))) return false;
1009
1010 if (!EnumerateUnresolvedStandardClasses(cx, global, properties,
1011 standard_class_names))
1012 return false;
1013 if (!EnumerateUnresolvedStandardClasses(cx, global, properties,
1014 builtin_property_names))
1015 return false;
1016
1017 return true;
1018 }
1019
JS_GetClassObject(JSContext * cx,JSProtoKey key,MutableHandleObject objp)1020 JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key,
1021 MutableHandleObject objp) {
1022 AssertHeapIsIdle();
1023 CHECK_REQUEST(cx);
1024 JSObject* obj = GlobalObject::getOrCreateConstructor(cx, key);
1025 if (!obj) return false;
1026 objp.set(obj);
1027 return true;
1028 }
1029
JS_GetClassPrototype(JSContext * cx,JSProtoKey key,MutableHandleObject objp)1030 JS_PUBLIC_API bool JS_GetClassPrototype(JSContext* cx, JSProtoKey key,
1031 MutableHandleObject objp) {
1032 AssertHeapIsIdle();
1033 CHECK_REQUEST(cx);
1034 JSObject* proto = GlobalObject::getOrCreatePrototype(cx, key);
1035 if (!proto) return false;
1036 objp.set(proto);
1037 return true;
1038 }
1039
1040 namespace JS {
1041
ProtoKeyToId(JSContext * cx,JSProtoKey key,MutableHandleId idp)1042 JS_PUBLIC_API void ProtoKeyToId(JSContext* cx, JSProtoKey key,
1043 MutableHandleId idp) {
1044 idp.set(NameToId(ClassName(key, cx)));
1045 }
1046
1047 } /* namespace JS */
1048
JS_IdToProtoKey(JSContext * cx,HandleId id)1049 JS_PUBLIC_API JSProtoKey JS_IdToProtoKey(JSContext* cx, HandleId id) {
1050 AssertHeapIsIdle();
1051 CHECK_REQUEST(cx);
1052 assertSameCompartment(cx, id);
1053
1054 if (!JSID_IS_ATOM(id)) return JSProto_Null;
1055
1056 JSAtom* atom = JSID_TO_ATOM(id);
1057 const JSStdName* stdnm =
1058 LookupStdName(cx->names(), atom, standard_class_names);
1059 if (!stdnm) return JSProto_Null;
1060
1061 if (GlobalObject::skipDeselectedConstructor(cx, stdnm->key))
1062 return JSProto_Null;
1063
1064 MOZ_ASSERT(MOZ_ARRAY_LENGTH(standard_class_names) == JSProto_LIMIT + 1);
1065 return static_cast<JSProtoKey>(stdnm - standard_class_names);
1066 }
1067
JS_GetObjectPrototype(JSContext * cx,HandleObject forObj)1068 JS_PUBLIC_API JSObject* JS_GetObjectPrototype(JSContext* cx,
1069 HandleObject forObj) {
1070 CHECK_REQUEST(cx);
1071 assertSameCompartment(cx, forObj);
1072 Rooted<GlobalObject*> global(cx, &forObj->global());
1073 return GlobalObject::getOrCreateObjectPrototype(cx, global);
1074 }
1075
JS_GetFunctionPrototype(JSContext * cx,HandleObject forObj)1076 JS_PUBLIC_API JSObject* JS_GetFunctionPrototype(JSContext* cx,
1077 HandleObject forObj) {
1078 CHECK_REQUEST(cx);
1079 assertSameCompartment(cx, forObj);
1080 Rooted<GlobalObject*> global(cx, &forObj->global());
1081 return GlobalObject::getOrCreateFunctionPrototype(cx, global);
1082 }
1083
JS_GetArrayPrototype(JSContext * cx,HandleObject forObj)1084 JS_PUBLIC_API JSObject* JS_GetArrayPrototype(JSContext* cx,
1085 HandleObject forObj) {
1086 CHECK_REQUEST(cx);
1087 assertSameCompartment(cx, forObj);
1088 Rooted<GlobalObject*> global(cx, &forObj->global());
1089 return GlobalObject::getOrCreateArrayPrototype(cx, global);
1090 }
1091
JS_GetErrorPrototype(JSContext * cx)1092 JS_PUBLIC_API JSObject* JS_GetErrorPrototype(JSContext* cx) {
1093 CHECK_REQUEST(cx);
1094 Rooted<GlobalObject*> global(cx, cx->global());
1095 return GlobalObject::getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR);
1096 }
1097
JS_GetIteratorPrototype(JSContext * cx)1098 JS_PUBLIC_API JSObject* JS_GetIteratorPrototype(JSContext* cx) {
1099 CHECK_REQUEST(cx);
1100 Rooted<GlobalObject*> global(cx, cx->global());
1101 return GlobalObject::getOrCreateIteratorPrototype(cx, global);
1102 }
1103
JS_GetGlobalForObject(JSContext * cx,JSObject * obj)1104 JS_PUBLIC_API JSObject* JS_GetGlobalForObject(JSContext* cx, JSObject* obj) {
1105 AssertHeapIsIdle();
1106 assertSameCompartment(cx, obj);
1107 return &obj->global();
1108 }
1109
JS_IsGlobalObject(JSObject * obj)1110 extern JS_PUBLIC_API bool JS_IsGlobalObject(JSObject* obj) {
1111 return obj->is<GlobalObject>();
1112 }
1113
JS_GlobalLexicalEnvironment(JSObject * obj)1114 extern JS_PUBLIC_API JSObject* JS_GlobalLexicalEnvironment(JSObject* obj) {
1115 return &obj->as<GlobalObject>().lexicalEnvironment();
1116 }
1117
JS_HasExtensibleLexicalEnvironment(JSObject * obj)1118 extern JS_PUBLIC_API bool JS_HasExtensibleLexicalEnvironment(JSObject* obj) {
1119 return obj->is<GlobalObject>() ||
1120 obj->compartment()->getNonSyntacticLexicalEnvironment(obj);
1121 }
1122
JS_ExtensibleLexicalEnvironment(JSObject * obj)1123 extern JS_PUBLIC_API JSObject* JS_ExtensibleLexicalEnvironment(JSObject* obj) {
1124 JSObject* lexical = nullptr;
1125 if (obj->is<GlobalObject>())
1126 lexical = JS_GlobalLexicalEnvironment(obj);
1127 else
1128 lexical = obj->compartment()->getNonSyntacticLexicalEnvironment(obj);
1129 MOZ_ASSERT(lexical);
1130 return lexical;
1131 }
1132
JS_GetGlobalForCompartmentOrNull(JSContext * cx,JSCompartment * c)1133 JS_PUBLIC_API JSObject* JS_GetGlobalForCompartmentOrNull(JSContext* cx,
1134 JSCompartment* c) {
1135 AssertHeapIsIdleOrIterating();
1136 assertSameCompartment(cx, c);
1137 return c->maybeGlobal();
1138 }
1139
CurrentGlobalOrNull(JSContext * cx)1140 JS_PUBLIC_API JSObject* JS::CurrentGlobalOrNull(JSContext* cx) {
1141 AssertHeapIsIdleOrIterating();
1142 CHECK_REQUEST(cx);
1143 if (!cx->compartment()) return nullptr;
1144 return cx->global();
1145 }
1146
ComputeThis(JSContext * cx,Value * vp)1147 JS_PUBLIC_API Value JS::detail::ComputeThis(JSContext* cx, Value* vp) {
1148 AssertHeapIsIdle();
1149 assertSameCompartment(cx, JSValueArray(vp, 2));
1150
1151 MutableHandleValue thisv = MutableHandleValue::fromMarkedLocation(&vp[1]);
1152 if (!BoxNonStrictThis(cx, thisv, thisv)) return NullValue();
1153
1154 return thisv;
1155 }
1156
JS_malloc(JSContext * cx,size_t nbytes)1157 JS_PUBLIC_API void* JS_malloc(JSContext* cx, size_t nbytes) {
1158 AssertHeapIsIdle();
1159 CHECK_REQUEST(cx);
1160 return static_cast<void*>(cx->zone()->pod_malloc<uint8_t>(nbytes));
1161 }
1162
JS_realloc(JSContext * cx,void * p,size_t oldBytes,size_t newBytes)1163 JS_PUBLIC_API void* JS_realloc(JSContext* cx, void* p, size_t oldBytes,
1164 size_t newBytes) {
1165 AssertHeapIsIdle();
1166 CHECK_REQUEST(cx);
1167 return static_cast<void*>(cx->zone()->pod_realloc<uint8_t>(
1168 static_cast<uint8_t*>(p), oldBytes, newBytes));
1169 }
1170
JS_free(JSContext * cx,void * p)1171 JS_PUBLIC_API void JS_free(JSContext* cx, void* p) { return js_free(p); }
1172
JS_freeop(JSFreeOp * fop,void * p)1173 JS_PUBLIC_API void JS_freeop(JSFreeOp* fop, void* p) {
1174 return FreeOp::get(fop)->free_(p);
1175 }
1176
JS_updateMallocCounter(JSContext * cx,size_t nbytes)1177 JS_PUBLIC_API void JS_updateMallocCounter(JSContext* cx, size_t nbytes) {
1178 return cx->updateMallocCounter(nbytes);
1179 }
1180
JS_strdup(JSContext * cx,const char * s)1181 JS_PUBLIC_API char* JS_strdup(JSContext* cx, const char* s) {
1182 AssertHeapIsIdle();
1183 return DuplicateString(cx, s).release();
1184 }
1185
1186 #undef JS_AddRoot
1187
JS_AddExtraGCRootsTracer(JSContext * cx,JSTraceDataOp traceOp,void * data)1188 JS_PUBLIC_API bool JS_AddExtraGCRootsTracer(JSContext* cx,
1189 JSTraceDataOp traceOp, void* data) {
1190 return cx->runtime()->gc.addBlackRootsTracer(traceOp, data);
1191 }
1192
JS_RemoveExtraGCRootsTracer(JSContext * cx,JSTraceDataOp traceOp,void * data)1193 JS_PUBLIC_API void JS_RemoveExtraGCRootsTracer(JSContext* cx,
1194 JSTraceDataOp traceOp,
1195 void* data) {
1196 return cx->runtime()->gc.removeBlackRootsTracer(traceOp, data);
1197 }
1198
IsIdleGCTaskNeeded(JSRuntime * rt)1199 JS_PUBLIC_API bool JS::IsIdleGCTaskNeeded(JSRuntime* rt) {
1200 // Currently, we only collect nursery during idle time.
1201 return rt->gc.nursery().needIdleTimeCollection();
1202 }
1203
RunIdleTimeGCTask(JSRuntime * rt)1204 JS_PUBLIC_API void JS::RunIdleTimeGCTask(JSRuntime* rt) {
1205 GCRuntime& gc = rt->gc;
1206 if (gc.nursery().needIdleTimeCollection()) {
1207 gc.minorGC(JS::gcreason::IDLE_TIME_COLLECTION);
1208 }
1209 }
1210
JS_GC(JSContext * cx)1211 JS_PUBLIC_API void JS_GC(JSContext* cx) {
1212 AssertHeapIsIdle();
1213 JS::PrepareForFullGC(cx);
1214 cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::API);
1215 }
1216
JS_MaybeGC(JSContext * cx)1217 JS_PUBLIC_API void JS_MaybeGC(JSContext* cx) {
1218 GCRuntime& gc = cx->runtime()->gc;
1219 gc.maybeGC(cx->zone());
1220 }
1221
JS_SetGCCallback(JSContext * cx,JSGCCallback cb,void * data)1222 JS_PUBLIC_API void JS_SetGCCallback(JSContext* cx, JSGCCallback cb,
1223 void* data) {
1224 AssertHeapIsIdle();
1225 cx->runtime()->gc.setGCCallback(cb, data);
1226 }
1227
JS_SetObjectsTenuredCallback(JSContext * cx,JSObjectsTenuredCallback cb,void * data)1228 JS_PUBLIC_API void JS_SetObjectsTenuredCallback(JSContext* cx,
1229 JSObjectsTenuredCallback cb,
1230 void* data) {
1231 AssertHeapIsIdle();
1232 cx->runtime()->gc.setObjectsTenuredCallback(cb, data);
1233 }
1234
JS_AddFinalizeCallback(JSContext * cx,JSFinalizeCallback cb,void * data)1235 JS_PUBLIC_API bool JS_AddFinalizeCallback(JSContext* cx, JSFinalizeCallback cb,
1236 void* data) {
1237 AssertHeapIsIdle();
1238 return cx->runtime()->gc.addFinalizeCallback(cb, data);
1239 }
1240
JS_RemoveFinalizeCallback(JSContext * cx,JSFinalizeCallback cb)1241 JS_PUBLIC_API void JS_RemoveFinalizeCallback(JSContext* cx,
1242 JSFinalizeCallback cb) {
1243 cx->runtime()->gc.removeFinalizeCallback(cb);
1244 }
1245
JS_AddWeakPointerZonesCallback(JSContext * cx,JSWeakPointerZonesCallback cb,void * data)1246 JS_PUBLIC_API bool JS_AddWeakPointerZonesCallback(JSContext* cx,
1247 JSWeakPointerZonesCallback cb,
1248 void* data) {
1249 AssertHeapIsIdle();
1250 return cx->runtime()->gc.addWeakPointerZonesCallback(cb, data);
1251 }
1252
JS_RemoveWeakPointerZonesCallback(JSContext * cx,JSWeakPointerZonesCallback cb)1253 JS_PUBLIC_API void JS_RemoveWeakPointerZonesCallback(
1254 JSContext* cx, JSWeakPointerZonesCallback cb) {
1255 cx->runtime()->gc.removeWeakPointerZonesCallback(cb);
1256 }
1257
JS_AddWeakPointerCompartmentCallback(JSContext * cx,JSWeakPointerCompartmentCallback cb,void * data)1258 JS_PUBLIC_API bool JS_AddWeakPointerCompartmentCallback(
1259 JSContext* cx, JSWeakPointerCompartmentCallback cb, void* data) {
1260 AssertHeapIsIdle();
1261 return cx->runtime()->gc.addWeakPointerCompartmentCallback(cb, data);
1262 }
1263
JS_RemoveWeakPointerCompartmentCallback(JSContext * cx,JSWeakPointerCompartmentCallback cb)1264 JS_PUBLIC_API void JS_RemoveWeakPointerCompartmentCallback(
1265 JSContext* cx, JSWeakPointerCompartmentCallback cb) {
1266 cx->runtime()->gc.removeWeakPointerCompartmentCallback(cb);
1267 }
1268
JS_UpdateWeakPointerAfterGC(JS::Heap<JSObject * > * objp)1269 JS_PUBLIC_API void JS_UpdateWeakPointerAfterGC(JS::Heap<JSObject*>* objp) {
1270 JS_UpdateWeakPointerAfterGCUnbarriered(objp->unsafeGet());
1271 }
1272
JS_UpdateWeakPointerAfterGCUnbarriered(JSObject ** objp)1273 JS_PUBLIC_API void JS_UpdateWeakPointerAfterGCUnbarriered(JSObject** objp) {
1274 if (IsAboutToBeFinalizedUnbarriered(objp)) *objp = nullptr;
1275 }
1276
JS_SetGCParameter(JSContext * cx,JSGCParamKey key,uint32_t value)1277 JS_PUBLIC_API void JS_SetGCParameter(JSContext* cx, JSGCParamKey key,
1278 uint32_t value) {
1279 cx->runtime()->gc.waitBackgroundSweepEnd();
1280 AutoLockGC lock(cx->runtime());
1281 MOZ_ALWAYS_TRUE(cx->runtime()->gc.setParameter(key, value, lock));
1282 }
1283
JS_ResetGCParameter(JSContext * cx,JSGCParamKey key)1284 JS_PUBLIC_API void JS_ResetGCParameter(JSContext* cx, JSGCParamKey key) {
1285 cx->runtime()->gc.waitBackgroundSweepEnd();
1286 AutoLockGC lock(cx->runtime());
1287 cx->runtime()->gc.resetParameter(key, lock);
1288 }
1289
JS_GetGCParameter(JSContext * cx,JSGCParamKey key)1290 JS_PUBLIC_API uint32_t JS_GetGCParameter(JSContext* cx, JSGCParamKey key) {
1291 AutoLockGC lock(cx->runtime());
1292 return cx->runtime()->gc.getParameter(key, lock);
1293 }
1294
1295 static const size_t NumGCConfigs = 14;
1296 struct JSGCConfig {
1297 JSGCParamKey key;
1298 uint32_t value;
1299 };
1300
JS_SetGCParametersBasedOnAvailableMemory(JSContext * cx,uint32_t availMem)1301 JS_PUBLIC_API void JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx,
1302 uint32_t availMem) {
1303 static const JSGCConfig minimal[NumGCConfigs] = {
1304 {JSGC_MAX_MALLOC_BYTES, 6 * 1024 * 1024},
1305 {JSGC_SLICE_TIME_BUDGET, 30},
1306 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1307 {JSGC_HIGH_FREQUENCY_HIGH_LIMIT, 40},
1308 {JSGC_HIGH_FREQUENCY_LOW_LIMIT, 0},
1309 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, 300},
1310 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, 120},
1311 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 120},
1312 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1313 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1314 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1315 {JSGC_ALLOCATION_THRESHOLD, 1},
1316 {JSGC_MODE, JSGC_MODE_INCREMENTAL}};
1317
1318 const JSGCConfig* config = minimal;
1319 if (availMem > 512) {
1320 static const JSGCConfig nominal[NumGCConfigs] = {
1321 {JSGC_MAX_MALLOC_BYTES, 6 * 1024 * 1024},
1322 {JSGC_SLICE_TIME_BUDGET, 30},
1323 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1000},
1324 {JSGC_HIGH_FREQUENCY_HIGH_LIMIT, 500},
1325 {JSGC_HIGH_FREQUENCY_LOW_LIMIT, 100},
1326 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, 300},
1327 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, 150},
1328 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 150},
1329 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1330 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1331 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1332 {JSGC_ALLOCATION_THRESHOLD, 30},
1333 {JSGC_MODE, JSGC_MODE_ZONE}};
1334
1335 config = nominal;
1336 }
1337
1338 for (size_t i = 0; i < NumGCConfigs; i++)
1339 JS_SetGCParameter(cx, config[i].key, config[i].value);
1340 }
1341
JS_NewExternalString(JSContext * cx,const char16_t * chars,size_t length,const JSStringFinalizer * fin)1342 JS_PUBLIC_API JSString* JS_NewExternalString(JSContext* cx,
1343 const char16_t* chars,
1344 size_t length,
1345 const JSStringFinalizer* fin) {
1346 AssertHeapIsIdle();
1347 CHECK_REQUEST(cx);
1348 JSString* s = JSExternalString::new_(cx, chars, length, fin);
1349 return s;
1350 }
1351
JS_NewMaybeExternalString(JSContext * cx,const char16_t * chars,size_t length,const JSStringFinalizer * fin,bool * allocatedExternal)1352 JS_PUBLIC_API JSString* JS_NewMaybeExternalString(JSContext* cx,
1353 const char16_t* chars,
1354 size_t length,
1355 const JSStringFinalizer* fin,
1356 bool* allocatedExternal) {
1357 AssertHeapIsIdle();
1358 CHECK_REQUEST(cx);
1359 return NewMaybeExternalString(cx, chars, length, fin, allocatedExternal);
1360 }
1361
JS_IsExternalString(JSString * str)1362 extern JS_PUBLIC_API bool JS_IsExternalString(JSString* str) {
1363 return str->isExternal();
1364 }
1365
JS_GetExternalStringFinalizer(JSString * str)1366 extern JS_PUBLIC_API const JSStringFinalizer* JS_GetExternalStringFinalizer(
1367 JSString* str) {
1368 return str->asExternal().externalFinalizer();
1369 }
1370
SetNativeStackQuotaAndLimit(JSContext * cx,JS::StackKind kind,size_t stackSize)1371 static void SetNativeStackQuotaAndLimit(JSContext* cx, JS::StackKind kind,
1372 size_t stackSize) {
1373 cx->nativeStackQuota[kind] = stackSize;
1374
1375 #if JS_STACK_GROWTH_DIRECTION > 0
1376 if (stackSize == 0) {
1377 cx->nativeStackLimit[kind] = UINTPTR_MAX;
1378 } else {
1379 MOZ_ASSERT(cx->nativeStackBase <= size_t(-1) - stackSize);
1380 cx->nativeStackLimit[kind] = cx->nativeStackBase + stackSize - 1;
1381 }
1382 #else
1383 if (stackSize == 0) {
1384 cx->nativeStackLimit[kind] = 0;
1385 } else {
1386 MOZ_ASSERT(cx->nativeStackBase >= stackSize);
1387 cx->nativeStackLimit[kind] = cx->nativeStackBase - (stackSize - 1);
1388 }
1389 #endif
1390 }
1391
JS_SetNativeStackQuota(JSContext * cx,size_t systemCodeStackSize,size_t trustedScriptStackSize,size_t untrustedScriptStackSize)1392 JS_PUBLIC_API void JS_SetNativeStackQuota(JSContext* cx,
1393 size_t systemCodeStackSize,
1394 size_t trustedScriptStackSize,
1395 size_t untrustedScriptStackSize) {
1396 MOZ_ASSERT(cx->requestDepth == 0);
1397
1398 if (!trustedScriptStackSize)
1399 trustedScriptStackSize = systemCodeStackSize;
1400 else
1401 MOZ_ASSERT(trustedScriptStackSize < systemCodeStackSize);
1402
1403 if (!untrustedScriptStackSize)
1404 untrustedScriptStackSize = trustedScriptStackSize;
1405 else
1406 MOZ_ASSERT(untrustedScriptStackSize < trustedScriptStackSize);
1407
1408 SetNativeStackQuotaAndLimit(cx, JS::StackForSystemCode, systemCodeStackSize);
1409 SetNativeStackQuotaAndLimit(cx, JS::StackForTrustedScript,
1410 trustedScriptStackSize);
1411 SetNativeStackQuotaAndLimit(cx, JS::StackForUntrustedScript,
1412 untrustedScriptStackSize);
1413
1414 if (cx->isCooperativelyScheduled()) cx->initJitStackLimit();
1415 }
1416
1417 /************************************************************************/
1418
JS_ValueToId(JSContext * cx,HandleValue value,MutableHandleId idp)1419 JS_PUBLIC_API bool JS_ValueToId(JSContext* cx, HandleValue value,
1420 MutableHandleId idp) {
1421 AssertHeapIsIdle();
1422 CHECK_REQUEST(cx);
1423 assertSameCompartment(cx, value);
1424 return ValueToId<CanGC>(cx, value, idp);
1425 }
1426
JS_StringToId(JSContext * cx,HandleString string,MutableHandleId idp)1427 JS_PUBLIC_API bool JS_StringToId(JSContext* cx, HandleString string,
1428 MutableHandleId idp) {
1429 AssertHeapIsIdle();
1430 CHECK_REQUEST(cx);
1431 assertSameCompartment(cx, string);
1432 RootedValue value(cx, StringValue(string));
1433 return ValueToId<CanGC>(cx, value, idp);
1434 }
1435
JS_IdToValue(JSContext * cx,jsid id,MutableHandleValue vp)1436 JS_PUBLIC_API bool JS_IdToValue(JSContext* cx, jsid id, MutableHandleValue vp) {
1437 AssertHeapIsIdle();
1438 CHECK_REQUEST(cx);
1439 assertSameCompartment(cx, id);
1440 vp.set(IdToValue(id));
1441 assertSameCompartment(cx, vp);
1442 return true;
1443 }
1444
ToPrimitive(JSContext * cx,HandleObject obj,JSType hint,MutableHandleValue vp)1445 JS_PUBLIC_API bool JS::ToPrimitive(JSContext* cx, HandleObject obj, JSType hint,
1446 MutableHandleValue vp) {
1447 AssertHeapIsIdle();
1448 CHECK_REQUEST(cx);
1449 assertSameCompartment(cx, obj);
1450 MOZ_ASSERT(obj != nullptr);
1451 MOZ_ASSERT(hint == JSTYPE_UNDEFINED || hint == JSTYPE_STRING ||
1452 hint == JSTYPE_NUMBER);
1453 vp.setObject(*obj);
1454 return ToPrimitiveSlow(cx, hint, vp);
1455 }
1456
GetFirstArgumentAsTypeHint(JSContext * cx,CallArgs args,JSType * result)1457 JS_PUBLIC_API bool JS::GetFirstArgumentAsTypeHint(JSContext* cx, CallArgs args,
1458 JSType* result) {
1459 if (!args.get(0).isString()) {
1460 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1461 JSMSG_NOT_EXPECTED_TYPE, "Symbol.toPrimitive",
1462 "\"string\", \"number\", or \"default\"",
1463 InformalValueTypeName(args.get(0)));
1464 return false;
1465 }
1466
1467 RootedString str(cx, args.get(0).toString());
1468 bool match;
1469
1470 if (!EqualStrings(cx, str, cx->names().default_, &match)) return false;
1471 if (match) {
1472 *result = JSTYPE_UNDEFINED;
1473 return true;
1474 }
1475
1476 if (!EqualStrings(cx, str, cx->names().string, &match)) return false;
1477 if (match) {
1478 *result = JSTYPE_STRING;
1479 return true;
1480 }
1481
1482 if (!EqualStrings(cx, str, cx->names().number, &match)) return false;
1483 if (match) {
1484 *result = JSTYPE_NUMBER;
1485 return true;
1486 }
1487
1488 JSAutoByteString bytes;
1489 const char* source = ValueToSourceForError(cx, args.get(0), bytes);
1490 if (!source) {
1491 ReportOutOfMemory(cx);
1492 return false;
1493 }
1494
1495 JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
1496 JSMSG_NOT_EXPECTED_TYPE, "Symbol.toPrimitive",
1497 "\"string\", \"number\", or \"default\"", source);
1498 return false;
1499 }
1500
JS_InitClass(JSContext * cx,HandleObject obj,HandleObject parent_proto,const JSClass * clasp,JSNative constructor,unsigned nargs,const JSPropertySpec * ps,const JSFunctionSpec * fs,const JSPropertySpec * static_ps,const JSFunctionSpec * static_fs)1501 JS_PUBLIC_API JSObject* JS_InitClass(JSContext* cx, HandleObject obj,
1502 HandleObject parent_proto,
1503 const JSClass* clasp, JSNative constructor,
1504 unsigned nargs, const JSPropertySpec* ps,
1505 const JSFunctionSpec* fs,
1506 const JSPropertySpec* static_ps,
1507 const JSFunctionSpec* static_fs) {
1508 AssertHeapIsIdle();
1509 CHECK_REQUEST(cx);
1510 assertSameCompartment(cx, obj, parent_proto);
1511 return InitClass(cx, obj, parent_proto, Valueify(clasp), constructor, nargs,
1512 ps, fs, static_ps, static_fs);
1513 }
1514
JS_LinkConstructorAndPrototype(JSContext * cx,HandleObject ctor,HandleObject proto)1515 JS_PUBLIC_API bool JS_LinkConstructorAndPrototype(JSContext* cx,
1516 HandleObject ctor,
1517 HandleObject proto) {
1518 return LinkConstructorAndPrototype(cx, ctor, proto);
1519 }
1520
JS_GetClass(JSObject * obj)1521 JS_PUBLIC_API const JSClass* JS_GetClass(JSObject* obj) {
1522 return obj->getJSClass();
1523 }
1524
JS_InstanceOf(JSContext * cx,HandleObject obj,const JSClass * clasp,CallArgs * args)1525 JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx, HandleObject obj,
1526 const JSClass* clasp, CallArgs* args) {
1527 AssertHeapIsIdle();
1528 CHECK_REQUEST(cx);
1529 #ifdef DEBUG
1530 if (args) {
1531 assertSameCompartment(cx, obj);
1532 assertSameCompartment(cx, args->thisv(), args->calleev());
1533 }
1534 #endif
1535 if (!obj || obj->getJSClass() != clasp) {
1536 if (args) ReportIncompatibleMethod(cx, *args, Valueify(clasp));
1537 return false;
1538 }
1539 return true;
1540 }
1541
JS_HasInstance(JSContext * cx,HandleObject obj,HandleValue value,bool * bp)1542 JS_PUBLIC_API bool JS_HasInstance(JSContext* cx, HandleObject obj,
1543 HandleValue value, bool* bp) {
1544 AssertHeapIsIdle();
1545 assertSameCompartment(cx, obj, value);
1546 return HasInstance(cx, obj, value, bp);
1547 }
1548
JS_GetPrivate(JSObject * obj)1549 JS_PUBLIC_API void* JS_GetPrivate(JSObject* obj) {
1550 /* This function can be called by a finalizer. */
1551 return obj->as<NativeObject>().getPrivate();
1552 }
1553
JS_SetPrivate(JSObject * obj,void * data)1554 JS_PUBLIC_API void JS_SetPrivate(JSObject* obj, void* data) {
1555 /* This function can be called by a finalizer. */
1556 obj->as<NativeObject>().setPrivate(data);
1557 }
1558
JS_GetInstancePrivate(JSContext * cx,HandleObject obj,const JSClass * clasp,CallArgs * args)1559 JS_PUBLIC_API void* JS_GetInstancePrivate(JSContext* cx, HandleObject obj,
1560 const JSClass* clasp,
1561 CallArgs* args) {
1562 if (!JS_InstanceOf(cx, obj, clasp, args)) return nullptr;
1563 return obj->as<NativeObject>().getPrivate();
1564 }
1565
JS_GetConstructor(JSContext * cx,HandleObject proto)1566 JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx, HandleObject proto) {
1567 AssertHeapIsIdle();
1568 CHECK_REQUEST(cx);
1569 assertSameCompartment(cx, proto);
1570
1571 RootedValue cval(cx);
1572 if (!GetProperty(cx, proto, proto, cx->names().constructor, &cval))
1573 return nullptr;
1574 if (!IsFunctionObject(cval)) {
1575 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1576 JSMSG_NO_CONSTRUCTOR, proto->getClass()->name);
1577 return nullptr;
1578 }
1579 return &cval.toObject();
1580 }
1581
extraWarnings(JSContext * cx) const1582 bool JS::CompartmentBehaviors::extraWarnings(JSContext* cx) const {
1583 return extraWarningsOverride_.get(cx->options().extraWarnings());
1584 }
1585
1586 JS::CompartmentCreationOptions&
setSystemZone()1587 JS::CompartmentCreationOptions::setSystemZone() {
1588 zoneSpec_ = JS::SystemZone;
1589 zonePointer_ = nullptr;
1590 return *this;
1591 }
1592
setExistingZone(JSObject * obj)1593 JS::CompartmentCreationOptions& JS::CompartmentCreationOptions::setExistingZone(
1594 JSObject* obj) {
1595 zoneSpec_ = JS::ExistingZone;
1596 zonePointer_ = obj->zone();
1597 return *this;
1598 }
1599
1600 JS::CompartmentCreationOptions&
setNewZoneInNewZoneGroup()1601 JS::CompartmentCreationOptions::setNewZoneInNewZoneGroup() {
1602 zoneSpec_ = JS::NewZoneInNewZoneGroup;
1603 zonePointer_ = nullptr;
1604 return *this;
1605 }
1606
1607 JS::CompartmentCreationOptions&
setNewZoneInSystemZoneGroup()1608 JS::CompartmentCreationOptions::setNewZoneInSystemZoneGroup() {
1609 zoneSpec_ = JS::NewZoneInSystemZoneGroup;
1610 zonePointer_ = nullptr;
1611 return *this;
1612 }
1613
1614 JS::CompartmentCreationOptions&
setNewZoneInExistingZoneGroup(JSObject * obj)1615 JS::CompartmentCreationOptions::setNewZoneInExistingZoneGroup(JSObject* obj) {
1616 zoneSpec_ = JS::NewZoneInExistingZoneGroup;
1617 zonePointer_ = obj->zone()->group();
1618 return *this;
1619 }
1620
CompartmentCreationOptionsRef(JSCompartment * compartment)1621 const JS::CompartmentCreationOptions& JS::CompartmentCreationOptionsRef(
1622 JSCompartment* compartment) {
1623 return compartment->creationOptions();
1624 }
1625
CompartmentCreationOptionsRef(JSObject * obj)1626 const JS::CompartmentCreationOptions& JS::CompartmentCreationOptionsRef(
1627 JSObject* obj) {
1628 return obj->compartment()->creationOptions();
1629 }
1630
CompartmentCreationOptionsRef(JSContext * cx)1631 const JS::CompartmentCreationOptions& JS::CompartmentCreationOptionsRef(
1632 JSContext* cx) {
1633 return cx->compartment()->creationOptions();
1634 }
1635
getSharedMemoryAndAtomicsEnabled() const1636 bool JS::CompartmentCreationOptions::getSharedMemoryAndAtomicsEnabled() const {
1637 #if defined(ENABLE_SHARED_ARRAY_BUFFER)
1638 return sharedMemoryAndAtomics_;
1639 #else
1640 return false;
1641 #endif
1642 }
1643
1644 JS::CompartmentCreationOptions&
setSharedMemoryAndAtomicsEnabled(bool flag)1645 JS::CompartmentCreationOptions::setSharedMemoryAndAtomicsEnabled(bool flag) {
1646 #if defined(ENABLE_SHARED_ARRAY_BUFFER)
1647 sharedMemoryAndAtomics_ = flag;
1648 #endif
1649 return *this;
1650 }
1651
CompartmentBehaviorsRef(JSCompartment * compartment)1652 JS::CompartmentBehaviors& JS::CompartmentBehaviorsRef(
1653 JSCompartment* compartment) {
1654 return compartment->behaviors();
1655 }
1656
CompartmentBehaviorsRef(JSObject * obj)1657 JS::CompartmentBehaviors& JS::CompartmentBehaviorsRef(JSObject* obj) {
1658 return obj->compartment()->behaviors();
1659 }
1660
CompartmentBehaviorsRef(JSContext * cx)1661 JS::CompartmentBehaviors& JS::CompartmentBehaviorsRef(JSContext* cx) {
1662 return cx->compartment()->behaviors();
1663 }
1664
JS_NewGlobalObject(JSContext * cx,const JSClass * clasp,JSPrincipals * principals,JS::OnNewGlobalHookOption hookOption,const JS::CompartmentOptions & options)1665 JS_PUBLIC_API JSObject* JS_NewGlobalObject(
1666 JSContext* cx, const JSClass* clasp, JSPrincipals* principals,
1667 JS::OnNewGlobalHookOption hookOption,
1668 const JS::CompartmentOptions& options) {
1669 MOZ_RELEASE_ASSERT(
1670 cx->runtime()->hasInitializedSelfHosting(),
1671 "Must call JS::InitSelfHostedCode() before creating a global");
1672
1673 AssertHeapIsIdle();
1674 CHECK_REQUEST(cx);
1675
1676 return GlobalObject::new_(cx, Valueify(clasp), principals, hookOption,
1677 options);
1678 }
1679
JS_GlobalObjectTraceHook(JSTracer * trc,JSObject * global)1680 JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global) {
1681 MOZ_ASSERT(global->is<GlobalObject>());
1682
1683 // Off thread parsing and compilation tasks create a dummy global which is
1684 // then merged back into the host compartment. Since it used to be a
1685 // global, it will still have this trace hook, but it does not have a
1686 // meaning relative to its new compartment. We can safely skip it.
1687 //
1688 // Similarly, if we GC when creating the global, we may not have set that
1689 // global's compartment's global pointer yet. In this case, the compartment
1690 // will not yet contain anything that needs to be traced.
1691 if (!global->isOwnGlobal(trc)) return;
1692
1693 // Trace the compartment for any GC things that should only stick around if
1694 // we know the global is live.
1695 global->compartment()->traceGlobal(trc);
1696
1697 if (JSTraceOp trace = global->compartment()->creationOptions().getTrace())
1698 trace(trc, global);
1699 }
1700
JS_FireOnNewGlobalObject(JSContext * cx,JS::HandleObject global)1701 JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx,
1702 JS::HandleObject global) {
1703 // This hook is infallible, because we don't really want arbitrary script
1704 // to be able to throw errors during delicate global creation routines.
1705 // This infallibility will eat OOM and slow script, but if that happens
1706 // we'll likely run up into them again soon in a fallible context.
1707 assertSameCompartment(cx, global);
1708 Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>());
1709 Debugger::onNewGlobalObject(cx, globalObject);
1710 }
1711
JS_NewObject(JSContext * cx,const JSClass * jsclasp)1712 JS_PUBLIC_API JSObject* JS_NewObject(JSContext* cx, const JSClass* jsclasp) {
1713 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
1714 AssertHeapIsIdle();
1715 CHECK_REQUEST(cx);
1716
1717 const Class* clasp = Valueify(jsclasp);
1718 if (!clasp) clasp = &PlainObject::class_; /* default class is Object */
1719
1720 MOZ_ASSERT(clasp != &JSFunction::class_);
1721 MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
1722
1723 return NewObjectWithClassProto(cx, clasp, nullptr);
1724 }
1725
JS_NewObjectWithGivenProto(JSContext * cx,const JSClass * jsclasp,HandleObject proto)1726 JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProto(JSContext* cx,
1727 const JSClass* jsclasp,
1728 HandleObject proto) {
1729 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
1730 AssertHeapIsIdle();
1731 CHECK_REQUEST(cx);
1732 assertSameCompartment(cx, proto);
1733
1734 const Class* clasp = Valueify(jsclasp);
1735 if (!clasp) clasp = &PlainObject::class_; /* default class is Object */
1736
1737 MOZ_ASSERT(clasp != &JSFunction::class_);
1738 MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
1739
1740 return NewObjectWithGivenProto(cx, clasp, proto);
1741 }
1742
JS_NewPlainObject(JSContext * cx)1743 JS_PUBLIC_API JSObject* JS_NewPlainObject(JSContext* cx) {
1744 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
1745 AssertHeapIsIdle();
1746 CHECK_REQUEST(cx);
1747
1748 return NewBuiltinClassInstance<PlainObject>(cx);
1749 }
1750
JS_NewObjectForConstructor(JSContext * cx,const JSClass * clasp,const CallArgs & args)1751 JS_PUBLIC_API JSObject* JS_NewObjectForConstructor(JSContext* cx,
1752 const JSClass* clasp,
1753 const CallArgs& args) {
1754 AssertHeapIsIdle();
1755 CHECK_REQUEST(cx);
1756
1757 Value callee = args.calleev();
1758 assertSameCompartment(cx, callee);
1759 RootedObject obj(cx, &callee.toObject());
1760 return CreateThis(cx, Valueify(clasp), obj);
1761 }
1762
JS_IsNative(JSObject * obj)1763 JS_PUBLIC_API bool JS_IsNative(JSObject* obj) { return obj->isNative(); }
1764
AssertObjectBelongsToCurrentThread(JSObject * obj)1765 JS_PUBLIC_API void JS::AssertObjectBelongsToCurrentThread(JSObject* obj) {
1766 JSRuntime* rt = obj->compartment()->runtimeFromAnyThread();
1767 MOZ_RELEASE_ASSERT(CurrentThreadCanAccessRuntime(rt));
1768 }
1769
1770 /*** Standard internal methods **********************************************/
1771
JS_GetPrototype(JSContext * cx,HandleObject obj,MutableHandleObject result)1772 JS_PUBLIC_API bool JS_GetPrototype(JSContext* cx, HandleObject obj,
1773 MutableHandleObject result) {
1774 assertSameCompartment(cx, obj);
1775 return GetPrototype(cx, obj, result);
1776 }
1777
JS_SetPrototype(JSContext * cx,HandleObject obj,HandleObject proto)1778 JS_PUBLIC_API bool JS_SetPrototype(JSContext* cx, HandleObject obj,
1779 HandleObject proto) {
1780 AssertHeapIsIdle();
1781 CHECK_REQUEST(cx);
1782 assertSameCompartment(cx, obj, proto);
1783
1784 return SetPrototype(cx, obj, proto);
1785 }
1786
JS_GetPrototypeIfOrdinary(JSContext * cx,HandleObject obj,bool * isOrdinary,MutableHandleObject result)1787 JS_PUBLIC_API bool JS_GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj,
1788 bool* isOrdinary,
1789 MutableHandleObject result) {
1790 assertSameCompartment(cx, obj);
1791 return GetPrototypeIfOrdinary(cx, obj, isOrdinary, result);
1792 }
1793
JS_IsExtensible(JSContext * cx,HandleObject obj,bool * extensible)1794 JS_PUBLIC_API bool JS_IsExtensible(JSContext* cx, HandleObject obj,
1795 bool* extensible) {
1796 assertSameCompartment(cx, obj);
1797 return IsExtensible(cx, obj, extensible);
1798 }
1799
JS_PreventExtensions(JSContext * cx,JS::HandleObject obj,ObjectOpResult & result)1800 JS_PUBLIC_API bool JS_PreventExtensions(JSContext* cx, JS::HandleObject obj,
1801 ObjectOpResult& result) {
1802 assertSameCompartment(cx, obj);
1803 return PreventExtensions(cx, obj, result);
1804 }
1805
JS_SetImmutablePrototype(JSContext * cx,JS::HandleObject obj,bool * succeeded)1806 JS_PUBLIC_API bool JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj,
1807 bool* succeeded) {
1808 assertSameCompartment(cx, obj);
1809 return SetImmutablePrototype(cx, obj, succeeded);
1810 }
1811
JS_GetOwnPropertyDescriptorById(JSContext * cx,HandleObject obj,HandleId id,MutableHandle<PropertyDescriptor> desc)1812 JS_PUBLIC_API bool JS_GetOwnPropertyDescriptorById(
1813 JSContext* cx, HandleObject obj, HandleId id,
1814 MutableHandle<PropertyDescriptor> desc) {
1815 AssertHeapIsIdle();
1816 CHECK_REQUEST(cx);
1817 assertSameCompartment(cx, obj, id);
1818
1819 return GetOwnPropertyDescriptor(cx, obj, id, desc);
1820 }
1821
JS_GetOwnPropertyDescriptor(JSContext * cx,HandleObject obj,const char * name,MutableHandle<PropertyDescriptor> desc)1822 JS_PUBLIC_API bool JS_GetOwnPropertyDescriptor(
1823 JSContext* cx, HandleObject obj, const char* name,
1824 MutableHandle<PropertyDescriptor> desc) {
1825 JSAtom* atom = Atomize(cx, name, strlen(name));
1826 if (!atom) return false;
1827 RootedId id(cx, AtomToId(atom));
1828 return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc);
1829 }
1830
JS_GetOwnUCPropertyDescriptor(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,MutableHandle<PropertyDescriptor> desc)1831 JS_PUBLIC_API bool JS_GetOwnUCPropertyDescriptor(
1832 JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen,
1833 MutableHandle<PropertyDescriptor> desc) {
1834 JSAtom* atom = AtomizeChars(cx, name, namelen);
1835 if (!atom) return false;
1836 RootedId id(cx, AtomToId(atom));
1837 return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc);
1838 }
1839
JS_GetPropertyDescriptorById(JSContext * cx,HandleObject obj,HandleId id,MutableHandle<PropertyDescriptor> desc)1840 JS_PUBLIC_API bool JS_GetPropertyDescriptorById(
1841 JSContext* cx, HandleObject obj, HandleId id,
1842 MutableHandle<PropertyDescriptor> desc) {
1843 assertSameCompartment(cx, obj, id);
1844 return GetPropertyDescriptor(cx, obj, id, desc);
1845 }
1846
JS_GetPropertyDescriptor(JSContext * cx,HandleObject obj,const char * name,MutableHandle<PropertyDescriptor> desc)1847 JS_PUBLIC_API bool JS_GetPropertyDescriptor(
1848 JSContext* cx, HandleObject obj, const char* name,
1849 MutableHandle<PropertyDescriptor> desc) {
1850 JSAtom* atom = Atomize(cx, name, strlen(name));
1851 if (!atom) return false;
1852 RootedId id(cx, AtomToId(atom));
1853 return JS_GetPropertyDescriptorById(cx, obj, id, desc);
1854 }
1855
JS_GetUCPropertyDescriptor(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,MutableHandle<PropertyDescriptor> desc)1856 JS_PUBLIC_API bool JS_GetUCPropertyDescriptor(
1857 JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen,
1858 MutableHandle<PropertyDescriptor> desc) {
1859 JSAtom* atom = AtomizeChars(cx, name, namelen);
1860 if (!atom) {
1861 return false;
1862 }
1863 RootedId id(cx, AtomToId(atom));
1864 return JS_GetPropertyDescriptorById(cx, obj, id, desc);
1865 }
1866
DefinePropertyByDescriptor(JSContext * cx,HandleObject obj,HandleId id,Handle<PropertyDescriptor> desc,ObjectOpResult & result)1867 static bool DefinePropertyByDescriptor(JSContext* cx, HandleObject obj,
1868 HandleId id,
1869 Handle<PropertyDescriptor> desc,
1870 ObjectOpResult& result) {
1871 AssertHeapIsIdle();
1872 CHECK_REQUEST(cx);
1873 assertSameCompartment(cx, obj, id, desc);
1874 return DefineProperty(cx, obj, id, desc, result);
1875 }
1876
JS_DefinePropertyById(JSContext * cx,HandleObject obj,HandleId id,Handle<PropertyDescriptor> desc,ObjectOpResult & result)1877 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, HandleObject obj,
1878 HandleId id,
1879 Handle<PropertyDescriptor> desc,
1880 ObjectOpResult& result) {
1881 return DefinePropertyByDescriptor(cx, obj, id, desc, result);
1882 }
1883
JS_DefinePropertyById(JSContext * cx,HandleObject obj,HandleId id,Handle<PropertyDescriptor> desc)1884 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, HandleObject obj,
1885 HandleId id,
1886 Handle<PropertyDescriptor> desc) {
1887 ObjectOpResult result;
1888 return DefinePropertyByDescriptor(cx, obj, id, desc, result) &&
1889 result.checkStrict(cx, obj, id);
1890 }
1891
DefineAccessorPropertyById(JSContext * cx,HandleObject obj,HandleId id,const JSNativeWrapper & get,const JSNativeWrapper & set,unsigned attrs)1892 static bool DefineAccessorPropertyById(JSContext* cx, HandleObject obj,
1893 HandleId id, const JSNativeWrapper& get,
1894 const JSNativeWrapper& set,
1895 unsigned attrs) {
1896 JSGetterOp getter = JS_CAST_NATIVE_TO(get.op, JSGetterOp);
1897 JSSetterOp setter = JS_CAST_NATIVE_TO(set.op, JSSetterOp);
1898
1899 // JSPROP_READONLY has no meaning when accessors are involved. Ideally we'd
1900 // throw if this happens, but we've accepted it for long enough that it's
1901 // not worth trying to make callers change their ways. Just flip it off on
1902 // its way through the API layer so that we can enforce this internally.
1903 if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) attrs &= ~JSPROP_READONLY;
1904
1905 // When we use DefineProperty, we need full scriptable Function objects rather
1906 // than JSNatives. However, we might be pulling this property descriptor off
1907 // of something with JSNative property descriptors. If we are, wrap them in
1908 // JS Function objects.
1909
1910 // If !(attrs & JSPROP_PROPOP_ACCESSORS), then getter/setter are both
1911 // possibly-null JSNatives (or possibly-null JSFunction* if JSPROP_GETTER or
1912 // JSPROP_SETTER is appropriately set).
1913 if (!(attrs & JSPROP_PROPOP_ACCESSORS)) {
1914 if (getter && !(attrs & JSPROP_GETTER)) {
1915 RootedAtom atom(cx, IdToFunctionName(cx, id, FunctionPrefixKind::Get));
1916 if (!atom) return false;
1917 JSFunction* getobj = NewNativeFunction(cx, (Native)getter, 0, atom);
1918 if (!getobj) return false;
1919
1920 if (get.info) getobj->setJitInfo(get.info);
1921
1922 getter = JS_DATA_TO_FUNC_PTR(GetterOp, getobj);
1923 attrs |= JSPROP_GETTER;
1924 }
1925 if (setter && !(attrs & JSPROP_SETTER)) {
1926 // Root just the getter, since the setter is not yet a JSObject.
1927 AutoRooterGetterSetter getRoot(cx, JSPROP_GETTER, &getter, nullptr);
1928 RootedAtom atom(cx, IdToFunctionName(cx, id, FunctionPrefixKind::Set));
1929 if (!atom) return false;
1930 JSFunction* setobj = NewNativeFunction(cx, (Native)setter, 1, atom);
1931 if (!setobj) return false;
1932
1933 if (set.info) setobj->setJitInfo(set.info);
1934
1935 setter = JS_DATA_TO_FUNC_PTR(SetterOp, setobj);
1936 attrs |= JSPROP_SETTER;
1937 }
1938 } else {
1939 attrs &= ~JSPROP_PROPOP_ACCESSORS;
1940 }
1941
1942 AssertHeapIsIdle();
1943 CHECK_REQUEST(cx);
1944 assertSameCompartment(
1945 cx, obj, id,
1946 (attrs & JSPROP_GETTER) ? JS_FUNC_TO_DATA_PTR(JSObject*, getter)
1947 : nullptr,
1948 (attrs & JSPROP_SETTER) ? JS_FUNC_TO_DATA_PTR(JSObject*, setter)
1949 : nullptr);
1950
1951 return js::DefineAccessorProperty(cx, obj, id, getter, setter, attrs);
1952 }
1953
DefineDataPropertyById(JSContext * cx,HandleObject obj,HandleId id,HandleValue value,unsigned attrs)1954 static bool DefineDataPropertyById(JSContext* cx, HandleObject obj, HandleId id,
1955 HandleValue value, unsigned attrs) {
1956 MOZ_ASSERT(
1957 !(attrs & (JSPROP_GETTER | JSPROP_SETTER | JSPROP_PROPOP_ACCESSORS)));
1958
1959 AssertHeapIsIdle();
1960 CHECK_REQUEST(cx);
1961 assertSameCompartment(cx, obj, id, value);
1962
1963 return js::DefineDataProperty(cx, obj, id, value, attrs);
1964 }
1965
1966 /*
1967 * Wrapper functions to create wrappers with no corresponding JSJitInfo from API
1968 * function arguments.
1969 */
NativeOpWrapper(Native native)1970 static JSNativeWrapper NativeOpWrapper(Native native) {
1971 JSNativeWrapper ret;
1972 ret.op = native;
1973 ret.info = nullptr;
1974 return ret;
1975 }
1976
JS_DefinePropertyById(JSContext * cx,HandleObject obj,HandleId id,HandleValue value,unsigned attrs)1977 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, HandleObject obj,
1978 HandleId id, HandleValue value,
1979 unsigned attrs) {
1980 return DefineDataPropertyById(cx, obj, id, value, attrs);
1981 }
1982
JS_DefinePropertyById(JSContext * cx,HandleObject obj,HandleId id,Native getter,Native setter,unsigned attrs)1983 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, HandleObject obj,
1984 HandleId id, Native getter,
1985 Native setter, unsigned attrs) {
1986 return DefineAccessorPropertyById(cx, obj, id, NativeOpWrapper(getter),
1987 NativeOpWrapper(setter), attrs);
1988 }
1989
JS_DefinePropertyById(JSContext * cx,HandleObject obj,HandleId id,HandleObject valueArg,unsigned attrs)1990 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, HandleObject obj,
1991 HandleId id, HandleObject valueArg,
1992 unsigned attrs) {
1993 RootedValue value(cx, ObjectValue(*valueArg));
1994 return DefineDataPropertyById(cx, obj, id, value, attrs);
1995 }
1996
JS_DefinePropertyById(JSContext * cx,HandleObject obj,HandleId id,HandleString valueArg,unsigned attrs)1997 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, HandleObject obj,
1998 HandleId id, HandleString valueArg,
1999 unsigned attrs) {
2000 RootedValue value(cx, StringValue(valueArg));
2001 return DefineDataPropertyById(cx, obj, id, value, attrs);
2002 }
2003
JS_DefinePropertyById(JSContext * cx,HandleObject obj,HandleId id,int32_t valueArg,unsigned attrs)2004 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, HandleObject obj,
2005 HandleId id, int32_t valueArg,
2006 unsigned attrs) {
2007 Value value = Int32Value(valueArg);
2008 return DefineDataPropertyById(cx, obj, id,
2009 HandleValue::fromMarkedLocation(&value), attrs);
2010 }
2011
JS_DefinePropertyById(JSContext * cx,HandleObject obj,HandleId id,uint32_t valueArg,unsigned attrs)2012 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, HandleObject obj,
2013 HandleId id, uint32_t valueArg,
2014 unsigned attrs) {
2015 Value value = NumberValue(valueArg);
2016 return DefineDataPropertyById(cx, obj, id,
2017 HandleValue::fromMarkedLocation(&value), attrs);
2018 }
2019
JS_DefinePropertyById(JSContext * cx,HandleObject obj,HandleId id,double valueArg,unsigned attrs)2020 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, HandleObject obj,
2021 HandleId id, double valueArg,
2022 unsigned attrs) {
2023 Value value = NumberValue(valueArg);
2024 return DefineDataPropertyById(cx, obj, id,
2025 HandleValue::fromMarkedLocation(&value), attrs);
2026 }
2027
DefineAccessorProperty(JSContext * cx,HandleObject obj,const char * name,const JSNativeWrapper & getter,const JSNativeWrapper & setter,unsigned attrs)2028 static bool DefineAccessorProperty(JSContext* cx, HandleObject obj,
2029 const char* name,
2030 const JSNativeWrapper& getter,
2031 const JSNativeWrapper& setter,
2032 unsigned attrs) {
2033 AutoRooterGetterSetter gsRoot(cx, attrs, const_cast<JSNative*>(&getter.op),
2034 const_cast<JSNative*>(&setter.op));
2035
2036 JSAtom* atom = Atomize(cx, name, strlen(name));
2037 if (!atom) return false;
2038 RootedId id(cx, AtomToId(atom));
2039
2040 return DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs);
2041 }
2042
DefineDataProperty(JSContext * cx,HandleObject obj,const char * name,HandleValue value,unsigned attrs)2043 static bool DefineDataProperty(JSContext* cx, HandleObject obj,
2044 const char* name, HandleValue value,
2045 unsigned attrs) {
2046 JSAtom* atom = Atomize(cx, name, strlen(name));
2047 if (!atom) return false;
2048 RootedId id(cx, AtomToId(atom));
2049
2050 return DefineDataPropertyById(cx, obj, id, value, attrs);
2051 }
2052
JS_DefineProperty(JSContext * cx,HandleObject obj,const char * name,HandleValue value,unsigned attrs)2053 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, HandleObject obj,
2054 const char* name, HandleValue value,
2055 unsigned attrs) {
2056 return DefineDataProperty(cx, obj, name, value, attrs);
2057 }
2058
JS_DefineProperty(JSContext * cx,HandleObject obj,const char * name,Native getter,Native setter,unsigned attrs)2059 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, HandleObject obj,
2060 const char* name, Native getter,
2061 Native setter, unsigned attrs) {
2062 return DefineAccessorProperty(cx, obj, name, NativeOpWrapper(getter),
2063 NativeOpWrapper(setter), attrs);
2064 }
2065
JS_DefineProperty(JSContext * cx,HandleObject obj,const char * name,HandleObject valueArg,unsigned attrs)2066 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, HandleObject obj,
2067 const char* name, HandleObject valueArg,
2068 unsigned attrs) {
2069 RootedValue value(cx, ObjectValue(*valueArg));
2070 return DefineDataProperty(cx, obj, name, value, attrs);
2071 }
2072
JS_DefineProperty(JSContext * cx,HandleObject obj,const char * name,HandleString valueArg,unsigned attrs)2073 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, HandleObject obj,
2074 const char* name, HandleString valueArg,
2075 unsigned attrs) {
2076 RootedValue value(cx, StringValue(valueArg));
2077 return DefineDataProperty(cx, obj, name, value, attrs);
2078 }
2079
JS_DefineProperty(JSContext * cx,HandleObject obj,const char * name,int32_t valueArg,unsigned attrs)2080 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, HandleObject obj,
2081 const char* name, int32_t valueArg,
2082 unsigned attrs) {
2083 Value value = Int32Value(valueArg);
2084 return DefineDataProperty(cx, obj, name,
2085 HandleValue::fromMarkedLocation(&value), attrs);
2086 }
2087
JS_DefineProperty(JSContext * cx,HandleObject obj,const char * name,uint32_t valueArg,unsigned attrs)2088 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, HandleObject obj,
2089 const char* name, uint32_t valueArg,
2090 unsigned attrs) {
2091 Value value = NumberValue(valueArg);
2092 return DefineDataProperty(cx, obj, name,
2093 HandleValue::fromMarkedLocation(&value), attrs);
2094 }
2095
JS_DefineProperty(JSContext * cx,HandleObject obj,const char * name,double valueArg,unsigned attrs)2096 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, HandleObject obj,
2097 const char* name, double valueArg,
2098 unsigned attrs) {
2099 Value value = NumberValue(valueArg);
2100 return DefineDataProperty(cx, obj, name,
2101 HandleValue::fromMarkedLocation(&value), attrs);
2102 }
2103
2104 #define AUTO_NAMELEN(s, n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
2105
JS_DefineUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,Handle<PropertyDescriptor> desc,ObjectOpResult & result)2106 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, HandleObject obj,
2107 const char16_t* name, size_t namelen,
2108 Handle<PropertyDescriptor> desc,
2109 ObjectOpResult& result) {
2110 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2111 if (!atom) return false;
2112 RootedId id(cx, AtomToId(atom));
2113 return DefinePropertyByDescriptor(cx, obj, id, desc, result);
2114 }
2115
JS_DefineUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,Handle<PropertyDescriptor> desc)2116 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, HandleObject obj,
2117 const char16_t* name, size_t namelen,
2118 Handle<PropertyDescriptor> desc) {
2119 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2120 if (!atom) return false;
2121 RootedId id(cx, AtomToId(atom));
2122 ObjectOpResult result;
2123 return DefinePropertyByDescriptor(cx, obj, id, desc, result) &&
2124 result.checkStrict(cx, obj, id);
2125 }
2126
DefineUCAccessorProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,Native getter,Native setter,unsigned attrs)2127 static bool DefineUCAccessorProperty(JSContext* cx, HandleObject obj,
2128 const char16_t* name, size_t namelen,
2129 Native getter, Native setter,
2130 unsigned attrs) {
2131 AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
2132 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2133 if (!atom) return false;
2134 RootedId id(cx, AtomToId(atom));
2135 return DefineAccessorPropertyById(cx, obj, id, NativeOpWrapper(getter),
2136 NativeOpWrapper(setter), attrs);
2137 }
2138
DefineUCDataProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,HandleValue value,unsigned attrs)2139 static bool DefineUCDataProperty(JSContext* cx, HandleObject obj,
2140 const char16_t* name, size_t namelen,
2141 HandleValue value, unsigned attrs) {
2142 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2143 if (!atom) return false;
2144 RootedId id(cx, AtomToId(atom));
2145 return DefineDataPropertyById(cx, obj, id, value, attrs);
2146 }
2147
JS_DefineUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,HandleValue value,unsigned attrs)2148 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, HandleObject obj,
2149 const char16_t* name, size_t namelen,
2150 HandleValue value, unsigned attrs) {
2151 return DefineUCDataProperty(cx, obj, name, namelen, value, attrs);
2152 }
2153
JS_DefineUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,Native getter,Native setter,unsigned attrs)2154 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, HandleObject obj,
2155 const char16_t* name, size_t namelen,
2156 Native getter, Native setter,
2157 unsigned attrs) {
2158 return DefineUCAccessorProperty(cx, obj, name, namelen, getter, setter,
2159 attrs);
2160 }
2161
JS_DefineUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,HandleObject valueArg,unsigned attrs)2162 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, HandleObject obj,
2163 const char16_t* name, size_t namelen,
2164 HandleObject valueArg, unsigned attrs) {
2165 RootedValue value(cx, ObjectValue(*valueArg));
2166 return DefineUCDataProperty(cx, obj, name, namelen, value, attrs);
2167 }
2168
JS_DefineUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,HandleString valueArg,unsigned attrs)2169 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, HandleObject obj,
2170 const char16_t* name, size_t namelen,
2171 HandleString valueArg, unsigned attrs) {
2172 RootedValue value(cx, StringValue(valueArg));
2173 return DefineUCDataProperty(cx, obj, name, namelen, value, attrs);
2174 }
2175
JS_DefineUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,int32_t valueArg,unsigned attrs)2176 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, HandleObject obj,
2177 const char16_t* name, size_t namelen,
2178 int32_t valueArg, unsigned attrs) {
2179 Value value = Int32Value(valueArg);
2180 return DefineUCDataProperty(cx, obj, name, namelen,
2181 HandleValue::fromMarkedLocation(&value), attrs);
2182 }
2183
JS_DefineUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,uint32_t valueArg,unsigned attrs)2184 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, HandleObject obj,
2185 const char16_t* name, size_t namelen,
2186 uint32_t valueArg, unsigned attrs) {
2187 Value value = NumberValue(valueArg);
2188 return DefineUCDataProperty(cx, obj, name, namelen,
2189 HandleValue::fromMarkedLocation(&value), attrs);
2190 }
2191
JS_DefineUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,double valueArg,unsigned attrs)2192 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, HandleObject obj,
2193 const char16_t* name, size_t namelen,
2194 double valueArg, unsigned attrs) {
2195 Value value = NumberValue(valueArg);
2196 return DefineUCDataProperty(cx, obj, name, namelen,
2197 HandleValue::fromMarkedLocation(&value), attrs);
2198 }
2199
DefineAccessorElement(JSContext * cx,HandleObject obj,uint32_t index,unsigned attrs,Native getter,Native setter)2200 static bool DefineAccessorElement(JSContext* cx, HandleObject obj,
2201 uint32_t index, unsigned attrs, Native getter,
2202 Native setter) {
2203 assertSameCompartment(cx, obj);
2204 AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
2205 AssertHeapIsIdle();
2206 CHECK_REQUEST(cx);
2207 RootedId id(cx);
2208 if (!IndexToId(cx, index, &id)) return false;
2209 return DefineAccessorPropertyById(cx, obj, id, NativeOpWrapper(getter),
2210 NativeOpWrapper(setter), attrs);
2211 }
2212
DefineDataElement(JSContext * cx,HandleObject obj,uint32_t index,HandleValue value,unsigned attrs)2213 static bool DefineDataElement(JSContext* cx, HandleObject obj, uint32_t index,
2214 HandleValue value, unsigned attrs) {
2215 assertSameCompartment(cx, obj, value);
2216 AssertHeapIsIdle();
2217 CHECK_REQUEST(cx);
2218 RootedId id(cx);
2219 if (!IndexToId(cx, index, &id)) return false;
2220 return DefineDataPropertyById(cx, obj, id, value, attrs);
2221 }
2222
JS_DefineElement(JSContext * cx,HandleObject obj,uint32_t index,HandleValue value,unsigned attrs)2223 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, HandleObject obj,
2224 uint32_t index, HandleValue value,
2225 unsigned attrs) {
2226 return ::DefineDataElement(cx, obj, index, value, attrs);
2227 }
2228
JS_DefineElement(JSContext * cx,HandleObject obj,uint32_t index,Native getter,Native setter,unsigned attrs)2229 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, HandleObject obj,
2230 uint32_t index, Native getter,
2231 Native setter, unsigned attrs) {
2232 return DefineAccessorElement(cx, obj, index, attrs, getter, setter);
2233 }
2234
JS_DefineElement(JSContext * cx,HandleObject obj,uint32_t index,HandleObject valueArg,unsigned attrs)2235 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, HandleObject obj,
2236 uint32_t index, HandleObject valueArg,
2237 unsigned attrs) {
2238 RootedValue value(cx, ObjectValue(*valueArg));
2239 return ::DefineDataElement(cx, obj, index, value, attrs);
2240 }
2241
JS_DefineElement(JSContext * cx,HandleObject obj,uint32_t index,HandleString valueArg,unsigned attrs)2242 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, HandleObject obj,
2243 uint32_t index, HandleString valueArg,
2244 unsigned attrs) {
2245 RootedValue value(cx, StringValue(valueArg));
2246 return ::DefineDataElement(cx, obj, index, value, attrs);
2247 }
2248
JS_DefineElement(JSContext * cx,HandleObject obj,uint32_t index,int32_t valueArg,unsigned attrs)2249 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, HandleObject obj,
2250 uint32_t index, int32_t valueArg,
2251 unsigned attrs) {
2252 Value value = Int32Value(valueArg);
2253 return ::DefineDataElement(cx, obj, index,
2254 HandleValue::fromMarkedLocation(&value), attrs);
2255 }
2256
JS_DefineElement(JSContext * cx,HandleObject obj,uint32_t index,uint32_t valueArg,unsigned attrs)2257 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, HandleObject obj,
2258 uint32_t index, uint32_t valueArg,
2259 unsigned attrs) {
2260 Value value = NumberValue(valueArg);
2261 return ::DefineDataElement(cx, obj, index,
2262 HandleValue::fromMarkedLocation(&value), attrs);
2263 }
2264
JS_DefineElement(JSContext * cx,HandleObject obj,uint32_t index,double valueArg,unsigned attrs)2265 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, HandleObject obj,
2266 uint32_t index, double valueArg,
2267 unsigned attrs) {
2268 Value value = NumberValue(valueArg);
2269 return ::DefineDataElement(cx, obj, index,
2270 HandleValue::fromMarkedLocation(&value), attrs);
2271 }
2272
JS_HasPropertyById(JSContext * cx,HandleObject obj,HandleId id,bool * foundp)2273 JS_PUBLIC_API bool JS_HasPropertyById(JSContext* cx, HandleObject obj,
2274 HandleId id, bool* foundp) {
2275 AssertHeapIsIdle();
2276 CHECK_REQUEST(cx);
2277 assertSameCompartment(cx, obj, id);
2278
2279 return HasProperty(cx, obj, id, foundp);
2280 }
2281
JS_HasProperty(JSContext * cx,HandleObject obj,const char * name,bool * foundp)2282 JS_PUBLIC_API bool JS_HasProperty(JSContext* cx, HandleObject obj,
2283 const char* name, bool* foundp) {
2284 JSAtom* atom = Atomize(cx, name, strlen(name));
2285 if (!atom) return false;
2286 RootedId id(cx, AtomToId(atom));
2287 return JS_HasPropertyById(cx, obj, id, foundp);
2288 }
2289
JS_HasUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,bool * foundp)2290 JS_PUBLIC_API bool JS_HasUCProperty(JSContext* cx, HandleObject obj,
2291 const char16_t* name, size_t namelen,
2292 bool* foundp) {
2293 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2294 if (!atom) return false;
2295 RootedId id(cx, AtomToId(atom));
2296 return JS_HasPropertyById(cx, obj, id, foundp);
2297 }
2298
JS_HasElement(JSContext * cx,HandleObject obj,uint32_t index,bool * foundp)2299 JS_PUBLIC_API bool JS_HasElement(JSContext* cx, HandleObject obj,
2300 uint32_t index, bool* foundp) {
2301 AssertHeapIsIdle();
2302 CHECK_REQUEST(cx);
2303 RootedId id(cx);
2304 if (!IndexToId(cx, index, &id)) return false;
2305 return JS_HasPropertyById(cx, obj, id, foundp);
2306 }
2307
JS_HasOwnPropertyById(JSContext * cx,HandleObject obj,HandleId id,bool * foundp)2308 JS_PUBLIC_API bool JS_HasOwnPropertyById(JSContext* cx, HandleObject obj,
2309 HandleId id, bool* foundp) {
2310 AssertHeapIsIdle();
2311 CHECK_REQUEST(cx);
2312 assertSameCompartment(cx, obj, id);
2313
2314 return HasOwnProperty(cx, obj, id, foundp);
2315 }
2316
JS_HasOwnProperty(JSContext * cx,HandleObject obj,const char * name,bool * foundp)2317 JS_PUBLIC_API bool JS_HasOwnProperty(JSContext* cx, HandleObject obj,
2318 const char* name, bool* foundp) {
2319 JSAtom* atom = Atomize(cx, name, strlen(name));
2320 if (!atom) return false;
2321 RootedId id(cx, AtomToId(atom));
2322 return JS_HasOwnPropertyById(cx, obj, id, foundp);
2323 }
2324
JS_ForwardGetPropertyTo(JSContext * cx,HandleObject obj,HandleId id,HandleValue receiver,MutableHandleValue vp)2325 JS_PUBLIC_API bool JS_ForwardGetPropertyTo(JSContext* cx, HandleObject obj,
2326 HandleId id, HandleValue receiver,
2327 MutableHandleValue vp) {
2328 AssertHeapIsIdle();
2329 CHECK_REQUEST(cx);
2330 assertSameCompartment(cx, obj, id, receiver);
2331
2332 return GetProperty(cx, obj, receiver, id, vp);
2333 }
2334
JS_ForwardGetElementTo(JSContext * cx,HandleObject obj,uint32_t index,HandleObject receiver,MutableHandleValue vp)2335 JS_PUBLIC_API bool JS_ForwardGetElementTo(JSContext* cx, HandleObject obj,
2336 uint32_t index, HandleObject receiver,
2337 MutableHandleValue vp) {
2338 AssertHeapIsIdle();
2339 CHECK_REQUEST(cx);
2340 assertSameCompartment(cx, obj);
2341
2342 return GetElement(cx, obj, receiver, index, vp);
2343 }
2344
JS_GetPropertyById(JSContext * cx,HandleObject obj,HandleId id,MutableHandleValue vp)2345 JS_PUBLIC_API bool JS_GetPropertyById(JSContext* cx, HandleObject obj,
2346 HandleId id, MutableHandleValue vp) {
2347 RootedValue receiver(cx, ObjectValue(*obj));
2348 return JS_ForwardGetPropertyTo(cx, obj, id, receiver, vp);
2349 }
2350
JS_GetProperty(JSContext * cx,HandleObject obj,const char * name,MutableHandleValue vp)2351 JS_PUBLIC_API bool JS_GetProperty(JSContext* cx, HandleObject obj,
2352 const char* name, MutableHandleValue vp) {
2353 JSAtom* atom = Atomize(cx, name, strlen(name));
2354 if (!atom) return false;
2355 RootedId id(cx, AtomToId(atom));
2356 return JS_GetPropertyById(cx, obj, id, vp);
2357 }
2358
JS_GetUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,MutableHandleValue vp)2359 JS_PUBLIC_API bool JS_GetUCProperty(JSContext* cx, HandleObject obj,
2360 const char16_t* name, size_t namelen,
2361 MutableHandleValue vp) {
2362 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2363 if (!atom) return false;
2364 RootedId id(cx, AtomToId(atom));
2365 return JS_GetPropertyById(cx, obj, id, vp);
2366 }
2367
JS_GetElement(JSContext * cx,HandleObject objArg,uint32_t index,MutableHandleValue vp)2368 JS_PUBLIC_API bool JS_GetElement(JSContext* cx, HandleObject objArg,
2369 uint32_t index, MutableHandleValue vp) {
2370 return JS_ForwardGetElementTo(cx, objArg, index, objArg, vp);
2371 }
2372
JS_ForwardSetPropertyTo(JSContext * cx,HandleObject obj,HandleId id,HandleValue v,HandleValue receiver,ObjectOpResult & result)2373 JS_PUBLIC_API bool JS_ForwardSetPropertyTo(JSContext* cx, HandleObject obj,
2374 HandleId id, HandleValue v,
2375 HandleValue receiver,
2376 ObjectOpResult& result) {
2377 AssertHeapIsIdle();
2378 CHECK_REQUEST(cx);
2379 assertSameCompartment(cx, obj, id, v, receiver);
2380
2381 return SetProperty(cx, obj, id, v, receiver, result);
2382 }
2383
JS_SetPropertyById(JSContext * cx,HandleObject obj,HandleId id,HandleValue v)2384 JS_PUBLIC_API bool JS_SetPropertyById(JSContext* cx, HandleObject obj,
2385 HandleId id, HandleValue v) {
2386 AssertHeapIsIdle();
2387 CHECK_REQUEST(cx);
2388 assertSameCompartment(cx, obj, id, v);
2389
2390 RootedValue receiver(cx, ObjectValue(*obj));
2391 ObjectOpResult ignored;
2392 return SetProperty(cx, obj, id, v, receiver, ignored);
2393 }
2394
JS_SetProperty(JSContext * cx,HandleObject obj,const char * name,HandleValue v)2395 JS_PUBLIC_API bool JS_SetProperty(JSContext* cx, HandleObject obj,
2396 const char* name, HandleValue v) {
2397 JSAtom* atom = Atomize(cx, name, strlen(name));
2398 if (!atom) return false;
2399 RootedId id(cx, AtomToId(atom));
2400 return JS_SetPropertyById(cx, obj, id, v);
2401 }
2402
JS_SetUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,HandleValue v)2403 JS_PUBLIC_API bool JS_SetUCProperty(JSContext* cx, HandleObject obj,
2404 const char16_t* name, size_t namelen,
2405 HandleValue v) {
2406 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2407 if (!atom) return false;
2408 RootedId id(cx, AtomToId(atom));
2409 return JS_SetPropertyById(cx, obj, id, v);
2410 }
2411
SetElement(JSContext * cx,HandleObject obj,uint32_t index,HandleValue v)2412 static bool SetElement(JSContext* cx, HandleObject obj, uint32_t index,
2413 HandleValue v) {
2414 AssertHeapIsIdle();
2415 CHECK_REQUEST(cx);
2416 assertSameCompartment(cx, obj, v);
2417
2418 RootedValue receiver(cx, ObjectValue(*obj));
2419 ObjectOpResult ignored;
2420 return SetElement(cx, obj, index, v, receiver, ignored);
2421 }
2422
JS_SetElement(JSContext * cx,HandleObject obj,uint32_t index,HandleValue v)2423 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, HandleObject obj,
2424 uint32_t index, HandleValue v) {
2425 return SetElement(cx, obj, index, v);
2426 }
2427
JS_SetElement(JSContext * cx,HandleObject obj,uint32_t index,HandleObject v)2428 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, HandleObject obj,
2429 uint32_t index, HandleObject v) {
2430 RootedValue value(cx, ObjectOrNullValue(v));
2431 return SetElement(cx, obj, index, value);
2432 }
2433
JS_SetElement(JSContext * cx,HandleObject obj,uint32_t index,HandleString v)2434 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, HandleObject obj,
2435 uint32_t index, HandleString v) {
2436 RootedValue value(cx, StringValue(v));
2437 return SetElement(cx, obj, index, value);
2438 }
2439
JS_SetElement(JSContext * cx,HandleObject obj,uint32_t index,int32_t v)2440 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, HandleObject obj,
2441 uint32_t index, int32_t v) {
2442 RootedValue value(cx, NumberValue(v));
2443 return SetElement(cx, obj, index, value);
2444 }
2445
JS_SetElement(JSContext * cx,HandleObject obj,uint32_t index,uint32_t v)2446 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, HandleObject obj,
2447 uint32_t index, uint32_t v) {
2448 RootedValue value(cx, NumberValue(v));
2449 return SetElement(cx, obj, index, value);
2450 }
2451
JS_SetElement(JSContext * cx,HandleObject obj,uint32_t index,double v)2452 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, HandleObject obj,
2453 uint32_t index, double v) {
2454 RootedValue value(cx, NumberValue(v));
2455 return SetElement(cx, obj, index, value);
2456 }
2457
JS_DeletePropertyById(JSContext * cx,HandleObject obj,HandleId id,ObjectOpResult & result)2458 JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, HandleObject obj,
2459 HandleId id, ObjectOpResult& result) {
2460 AssertHeapIsIdle();
2461 CHECK_REQUEST(cx);
2462 assertSameCompartment(cx, obj, id);
2463
2464 return DeleteProperty(cx, obj, id, result);
2465 }
2466
JS_DeleteProperty(JSContext * cx,HandleObject obj,const char * name,ObjectOpResult & result)2467 JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, HandleObject obj,
2468 const char* name, ObjectOpResult& result) {
2469 CHECK_REQUEST(cx);
2470 assertSameCompartment(cx, obj);
2471
2472 JSAtom* atom = Atomize(cx, name, strlen(name));
2473 if (!atom) return false;
2474 RootedId id(cx, AtomToId(atom));
2475 return DeleteProperty(cx, obj, id, result);
2476 }
2477
JS_DeleteUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,ObjectOpResult & result)2478 JS_PUBLIC_API bool JS_DeleteUCProperty(JSContext* cx, HandleObject obj,
2479 const char16_t* name, size_t namelen,
2480 ObjectOpResult& result) {
2481 CHECK_REQUEST(cx);
2482 assertSameCompartment(cx, obj);
2483
2484 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2485 if (!atom) return false;
2486 RootedId id(cx, AtomToId(atom));
2487 return DeleteProperty(cx, obj, id, result);
2488 }
2489
JS_DeleteElement(JSContext * cx,HandleObject obj,uint32_t index,ObjectOpResult & result)2490 JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, HandleObject obj,
2491 uint32_t index, ObjectOpResult& result) {
2492 AssertHeapIsIdle();
2493 CHECK_REQUEST(cx);
2494 assertSameCompartment(cx, obj);
2495
2496 return DeleteElement(cx, obj, index, result);
2497 }
2498
JS_DeletePropertyById(JSContext * cx,HandleObject obj,HandleId id)2499 JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, HandleObject obj,
2500 HandleId id) {
2501 ObjectOpResult ignored;
2502 return JS_DeletePropertyById(cx, obj, id, ignored);
2503 }
2504
JS_DeleteProperty(JSContext * cx,HandleObject obj,const char * name)2505 JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, HandleObject obj,
2506 const char* name) {
2507 ObjectOpResult ignored;
2508 return JS_DeleteProperty(cx, obj, name, ignored);
2509 }
2510
JS_DeleteElement(JSContext * cx,HandleObject obj,uint32_t index)2511 JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, HandleObject obj,
2512 uint32_t index) {
2513 ObjectOpResult ignored;
2514 return JS_DeleteElement(cx, obj, index, ignored);
2515 }
2516
JS_Enumerate(JSContext * cx,HandleObject obj,JS::MutableHandle<IdVector> props)2517 JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, HandleObject obj,
2518 JS::MutableHandle<IdVector> props) {
2519 AssertHeapIsIdle();
2520 CHECK_REQUEST(cx);
2521 assertSameCompartment(cx, obj, props);
2522 MOZ_ASSERT(props.empty());
2523
2524 AutoIdVector ids(cx);
2525 if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &ids)) return false;
2526
2527 return props.append(ids.begin(), ids.end());
2528 }
2529
IsCallable(JSObject * obj)2530 JS_PUBLIC_API bool JS::IsCallable(JSObject* obj) { return obj->isCallable(); }
2531
IsConstructor(JSObject * obj)2532 JS_PUBLIC_API bool JS::IsConstructor(JSObject* obj) {
2533 return obj->isConstructor();
2534 }
2535
JS_CallFunctionValue(JSContext * cx,HandleObject obj,HandleValue fval,const HandleValueArray & args,MutableHandleValue rval)2536 JS_PUBLIC_API bool JS_CallFunctionValue(JSContext* cx, HandleObject obj,
2537 HandleValue fval,
2538 const HandleValueArray& args,
2539 MutableHandleValue rval) {
2540 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
2541 AssertHeapIsIdle();
2542 CHECK_REQUEST(cx);
2543 assertSameCompartment(cx, obj, fval, args);
2544
2545 InvokeArgs iargs(cx);
2546 if (!FillArgumentsFromArraylike(cx, iargs, args)) return false;
2547
2548 RootedValue thisv(cx, ObjectOrNullValue(obj));
2549 return Call(cx, fval, thisv, iargs, rval);
2550 }
2551
JS_CallFunction(JSContext * cx,HandleObject obj,HandleFunction fun,const HandleValueArray & args,MutableHandleValue rval)2552 JS_PUBLIC_API bool JS_CallFunction(JSContext* cx, HandleObject obj,
2553 HandleFunction fun,
2554 const HandleValueArray& args,
2555 MutableHandleValue rval) {
2556 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
2557 AssertHeapIsIdle();
2558 CHECK_REQUEST(cx);
2559 assertSameCompartment(cx, obj, fun, args);
2560
2561 InvokeArgs iargs(cx);
2562 if (!FillArgumentsFromArraylike(cx, iargs, args)) return false;
2563
2564 RootedValue fval(cx, ObjectValue(*fun));
2565 RootedValue thisv(cx, ObjectOrNullValue(obj));
2566 return Call(cx, fval, thisv, iargs, rval);
2567 }
2568
JS_CallFunctionName(JSContext * cx,HandleObject obj,const char * name,const HandleValueArray & args,MutableHandleValue rval)2569 JS_PUBLIC_API bool JS_CallFunctionName(JSContext* cx, HandleObject obj,
2570 const char* name,
2571 const HandleValueArray& args,
2572 MutableHandleValue rval) {
2573 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
2574 AssertHeapIsIdle();
2575 CHECK_REQUEST(cx);
2576 assertSameCompartment(cx, obj, args);
2577
2578 JSAtom* atom = Atomize(cx, name, strlen(name));
2579 if (!atom) return false;
2580
2581 RootedValue fval(cx);
2582 RootedId id(cx, AtomToId(atom));
2583 if (!GetProperty(cx, obj, obj, id, &fval)) return false;
2584
2585 InvokeArgs iargs(cx);
2586 if (!FillArgumentsFromArraylike(cx, iargs, args)) return false;
2587
2588 RootedValue thisv(cx, ObjectOrNullValue(obj));
2589 return Call(cx, fval, thisv, iargs, rval);
2590 }
2591
Call(JSContext * cx,HandleValue thisv,HandleValue fval,const JS::HandleValueArray & args,MutableHandleValue rval)2592 JS_PUBLIC_API bool JS::Call(JSContext* cx, HandleValue thisv, HandleValue fval,
2593 const JS::HandleValueArray& args,
2594 MutableHandleValue rval) {
2595 AssertHeapIsIdle();
2596 CHECK_REQUEST(cx);
2597 assertSameCompartment(cx, thisv, fval, args);
2598
2599 InvokeArgs iargs(cx);
2600 if (!FillArgumentsFromArraylike(cx, iargs, args)) return false;
2601
2602 return Call(cx, fval, thisv, iargs, rval);
2603 }
2604
Construct(JSContext * cx,HandleValue fval,HandleObject newTarget,const JS::HandleValueArray & args,MutableHandleObject objp)2605 JS_PUBLIC_API bool JS::Construct(JSContext* cx, HandleValue fval,
2606 HandleObject newTarget,
2607 const JS::HandleValueArray& args,
2608 MutableHandleObject objp) {
2609 AssertHeapIsIdle();
2610 CHECK_REQUEST(cx);
2611 assertSameCompartment(cx, fval, newTarget, args);
2612
2613 if (!IsConstructor(fval)) {
2614 ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval,
2615 nullptr);
2616 return false;
2617 }
2618
2619 RootedValue newTargetVal(cx, ObjectValue(*newTarget));
2620 if (!IsConstructor(newTargetVal)) {
2621 ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK,
2622 newTargetVal, nullptr);
2623 return false;
2624 }
2625
2626 ConstructArgs cargs(cx);
2627 if (!FillArgumentsFromArraylike(cx, cargs, args)) return false;
2628
2629 return js::Construct(cx, fval, cargs, newTargetVal, objp);
2630 }
2631
Construct(JSContext * cx,HandleValue fval,const JS::HandleValueArray & args,MutableHandleObject objp)2632 JS_PUBLIC_API bool JS::Construct(JSContext* cx, HandleValue fval,
2633 const JS::HandleValueArray& args,
2634 MutableHandleObject objp) {
2635 AssertHeapIsIdle();
2636 CHECK_REQUEST(cx);
2637 assertSameCompartment(cx, fval, args);
2638
2639 if (!IsConstructor(fval)) {
2640 ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval,
2641 nullptr);
2642 return false;
2643 }
2644
2645 ConstructArgs cargs(cx);
2646 if (!FillArgumentsFromArraylike(cx, cargs, args)) return false;
2647
2648 return js::Construct(cx, fval, cargs, fval, objp);
2649 }
2650
2651 /* * */
2652
JS_AlreadyHasOwnPropertyById(JSContext * cx,HandleObject obj,HandleId id,bool * foundp)2653 JS_PUBLIC_API bool JS_AlreadyHasOwnPropertyById(JSContext* cx, HandleObject obj,
2654 HandleId id, bool* foundp) {
2655 AssertHeapIsIdle();
2656 CHECK_REQUEST(cx);
2657 assertSameCompartment(cx, obj, id);
2658
2659 if (!obj->isNative()) return js::HasOwnProperty(cx, obj, id, foundp);
2660
2661 RootedNativeObject nativeObj(cx, &obj->as<NativeObject>());
2662 Rooted<PropertyResult> prop(cx);
2663 NativeLookupOwnPropertyNoResolve(cx, nativeObj, id, &prop);
2664 *foundp = prop.isFound();
2665 return true;
2666 }
2667
JS_AlreadyHasOwnProperty(JSContext * cx,HandleObject obj,const char * name,bool * foundp)2668 JS_PUBLIC_API bool JS_AlreadyHasOwnProperty(JSContext* cx, HandleObject obj,
2669 const char* name, bool* foundp) {
2670 JSAtom* atom = Atomize(cx, name, strlen(name));
2671 if (!atom) return false;
2672 RootedId id(cx, AtomToId(atom));
2673 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
2674 }
2675
JS_AlreadyHasOwnUCProperty(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,bool * foundp)2676 JS_PUBLIC_API bool JS_AlreadyHasOwnUCProperty(JSContext* cx, HandleObject obj,
2677 const char16_t* name,
2678 size_t namelen, bool* foundp) {
2679 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2680 if (!atom) return false;
2681 RootedId id(cx, AtomToId(atom));
2682 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
2683 }
2684
JS_AlreadyHasOwnElement(JSContext * cx,HandleObject obj,uint32_t index,bool * foundp)2685 JS_PUBLIC_API bool JS_AlreadyHasOwnElement(JSContext* cx, HandleObject obj,
2686 uint32_t index, bool* foundp) {
2687 AssertHeapIsIdle();
2688 CHECK_REQUEST(cx);
2689 RootedId id(cx);
2690 if (!IndexToId(cx, index, &id)) return false;
2691 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
2692 }
2693
JS_FreezeObject(JSContext * cx,HandleObject obj)2694 JS_PUBLIC_API bool JS_FreezeObject(JSContext* cx, HandleObject obj) {
2695 AssertHeapIsIdle();
2696 CHECK_REQUEST(cx);
2697 assertSameCompartment(cx, obj);
2698 return FreezeObject(cx, obj);
2699 }
2700
DeepFreezeSlot(JSContext * cx,const Value & v)2701 static bool DeepFreezeSlot(JSContext* cx, const Value& v) {
2702 if (v.isPrimitive()) return true;
2703 RootedObject obj(cx, &v.toObject());
2704 return JS_DeepFreezeObject(cx, obj);
2705 }
2706
JS_DeepFreezeObject(JSContext * cx,HandleObject obj)2707 JS_PUBLIC_API bool JS_DeepFreezeObject(JSContext* cx, HandleObject obj) {
2708 AssertHeapIsIdle();
2709 CHECK_REQUEST(cx);
2710 assertSameCompartment(cx, obj);
2711
2712 /* Assume that non-extensible objects are already deep-frozen, to avoid
2713 * divergence. */
2714 bool extensible;
2715 if (!IsExtensible(cx, obj, &extensible)) return false;
2716 if (!extensible) return true;
2717
2718 if (!FreezeObject(cx, obj)) return false;
2719
2720 /* Walk slots in obj and if any value is a non-null object, seal it. */
2721 if (obj->isNative()) {
2722 RootedNativeObject nobj(cx, &obj->as<NativeObject>());
2723 for (uint32_t i = 0, n = nobj->slotSpan(); i < n; ++i) {
2724 if (!DeepFreezeSlot(cx, nobj->getSlot(i))) return false;
2725 }
2726 for (uint32_t i = 0, n = nobj->getDenseInitializedLength(); i < n; ++i) {
2727 if (!DeepFreezeSlot(cx, nobj->getDenseElement(i))) return false;
2728 }
2729 }
2730
2731 return true;
2732 }
2733
DefineSelfHostedProperty(JSContext * cx,HandleObject obj,HandleId id,const char * getterName,const char * setterName,unsigned attrs)2734 static bool DefineSelfHostedProperty(JSContext* cx, HandleObject obj,
2735 HandleId id, const char* getterName,
2736 const char* setterName, unsigned attrs) {
2737 JSAtom* getterNameAtom = Atomize(cx, getterName, strlen(getterName));
2738 if (!getterNameAtom) return false;
2739 RootedPropertyName getterNameName(cx, getterNameAtom->asPropertyName());
2740
2741 RootedAtom name(cx, IdToFunctionName(cx, id));
2742 if (!name) return false;
2743
2744 RootedValue getterValue(cx);
2745 if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), getterNameName,
2746 name, 0, &getterValue)) {
2747 return false;
2748 }
2749 MOZ_ASSERT(getterValue.isObject() && getterValue.toObject().is<JSFunction>());
2750 RootedFunction getterFunc(cx, &getterValue.toObject().as<JSFunction>());
2751 JSNative getterOp = JS_DATA_TO_FUNC_PTR(JSNative, getterFunc.get());
2752
2753 RootedFunction setterFunc(cx);
2754 if (setterName) {
2755 JSAtom* setterNameAtom = Atomize(cx, setterName, strlen(setterName));
2756 if (!setterNameAtom) return false;
2757 RootedPropertyName setterNameName(cx, setterNameAtom->asPropertyName());
2758
2759 RootedValue setterValue(cx);
2760 if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), setterNameName,
2761 name, 0, &setterValue)) {
2762 return false;
2763 }
2764 MOZ_ASSERT(setterValue.isObject() &&
2765 setterValue.toObject().is<JSFunction>());
2766 setterFunc = &setterValue.toObject().as<JSFunction>();
2767 }
2768 JSNative setterOp = JS_DATA_TO_FUNC_PTR(JSNative, setterFunc.get());
2769
2770 return DefineAccessorPropertyById(cx, obj, id, NativeOpWrapper(getterOp),
2771 NativeOpWrapper(setterOp), attrs);
2772 }
2773
JS_DefineObject(JSContext * cx,HandleObject obj,const char * name,const JSClass * jsclasp,unsigned attrs)2774 JS_PUBLIC_API JSObject* JS_DefineObject(JSContext* cx, HandleObject obj,
2775 const char* name,
2776 const JSClass* jsclasp,
2777 unsigned attrs) {
2778 AssertHeapIsIdle();
2779 CHECK_REQUEST(cx);
2780 assertSameCompartment(cx, obj);
2781
2782 const Class* clasp = Valueify(jsclasp);
2783 if (!clasp) clasp = &PlainObject::class_; /* default class is Object */
2784
2785 RootedObject nobj(cx, NewObjectWithClassProto(cx, clasp, nullptr));
2786 if (!nobj) return nullptr;
2787
2788 RootedValue nobjValue(cx, ObjectValue(*nobj));
2789 if (!DefineDataProperty(cx, obj, name, nobjValue, attrs)) return nullptr;
2790
2791 return nobj;
2792 }
2793
ValueFromScalar(double x)2794 static inline Value ValueFromScalar(double x) { return DoubleValue(x); }
ValueFromScalar(int32_t x)2795 static inline Value ValueFromScalar(int32_t x) { return Int32Value(x); }
2796
2797 template <typename T>
DefineConstScalar(JSContext * cx,HandleObject obj,const JSConstScalarSpec<T> * cds)2798 static bool DefineConstScalar(JSContext* cx, HandleObject obj,
2799 const JSConstScalarSpec<T>* cds) {
2800 AssertHeapIsIdle();
2801 CHECK_REQUEST(cx);
2802 unsigned attrs = JSPROP_READONLY | JSPROP_PERMANENT;
2803 for (; cds->name; cds++) {
2804 RootedValue value(cx, ValueFromScalar(cds->val));
2805 if (!DefineDataProperty(cx, obj, cds->name, value, attrs)) return false;
2806 }
2807 return true;
2808 }
2809
JS_DefineConstDoubles(JSContext * cx,HandleObject obj,const JSConstDoubleSpec * cds)2810 JS_PUBLIC_API bool JS_DefineConstDoubles(JSContext* cx, HandleObject obj,
2811 const JSConstDoubleSpec* cds) {
2812 return DefineConstScalar(cx, obj, cds);
2813 }
JS_DefineConstIntegers(JSContext * cx,HandleObject obj,const JSConstIntegerSpec * cis)2814 JS_PUBLIC_API bool JS_DefineConstIntegers(JSContext* cx, HandleObject obj,
2815 const JSConstIntegerSpec* cis) {
2816 return DefineConstScalar(cx, obj, cis);
2817 }
2818
getValue(JSContext * cx,MutableHandleValue vp) const2819 JS_PUBLIC_API bool JSPropertySpec::getValue(JSContext* cx,
2820 MutableHandleValue vp) const {
2821 MOZ_ASSERT(!isAccessor());
2822
2823 if (value.type == JSVAL_TYPE_STRING) {
2824 RootedAtom atom(cx, Atomize(cx, value.string, strlen(value.string)));
2825 if (!atom) return false;
2826 vp.setString(atom);
2827 } else {
2828 MOZ_ASSERT(value.type == JSVAL_TYPE_INT32);
2829 vp.setInt32(value.int32);
2830 }
2831
2832 return true;
2833 }
2834
PropertySpecNameToSymbolCode(const char * name)2835 static JS::SymbolCode PropertySpecNameToSymbolCode(const char* name) {
2836 MOZ_ASSERT(JS::PropertySpecNameIsSymbol(name));
2837 uintptr_t u = reinterpret_cast<uintptr_t>(name);
2838 return JS::SymbolCode(u - 1);
2839 }
2840
PropertySpecNameToId(JSContext * cx,const char * name,MutableHandleId id,js::PinningBehavior pin=js::DoNotPinAtom)2841 bool PropertySpecNameToId(JSContext* cx, const char* name, MutableHandleId id,
2842 js::PinningBehavior pin = js::DoNotPinAtom) {
2843 if (JS::PropertySpecNameIsSymbol(name)) {
2844 JS::SymbolCode which = PropertySpecNameToSymbolCode(name);
2845 id.set(SYMBOL_TO_JSID(cx->wellKnownSymbols().get(which)));
2846 } else {
2847 JSAtom* atom = Atomize(cx, name, strlen(name), pin);
2848 if (!atom) return false;
2849 id.set(AtomToId(atom));
2850 }
2851 return true;
2852 }
2853
PropertySpecNameToPermanentId(JSContext * cx,const char * name,jsid * idp)2854 JS_PUBLIC_API bool JS::PropertySpecNameToPermanentId(JSContext* cx,
2855 const char* name,
2856 jsid* idp) {
2857 // We are calling fromMarkedLocation(idp) even though idp points to a
2858 // location that will never be marked. This is OK because the whole point
2859 // of this API is to populate *idp with a jsid that does not need to be
2860 // marked.
2861 return PropertySpecNameToId(
2862 cx, name, MutableHandleId::fromMarkedLocation(idp), js::PinAtom);
2863 }
2864
JS_DefineProperties(JSContext * cx,HandleObject obj,const JSPropertySpec * ps)2865 JS_PUBLIC_API bool JS_DefineProperties(JSContext* cx, HandleObject obj,
2866 const JSPropertySpec* ps) {
2867 RootedId id(cx);
2868
2869 for (; ps->name; ps++) {
2870 if (!PropertySpecNameToId(cx, ps->name, &id)) return false;
2871
2872 if (ps->isAccessor()) {
2873 if (ps->isSelfHosted()) {
2874 if (!DefineSelfHostedProperty(
2875 cx, obj, id, ps->accessors.getter.selfHosted.funname,
2876 ps->accessors.setter.selfHosted.funname, ps->flags)) {
2877 return false;
2878 }
2879 } else {
2880 if (!DefineAccessorPropertyById(
2881 cx, obj, id, ps->accessors.getter.native,
2882 ps->accessors.setter.native, ps->flags)) {
2883 return false;
2884 }
2885 }
2886 } else {
2887 RootedValue v(cx);
2888 if (!ps->getValue(cx, &v)) return false;
2889
2890 if (!DefineDataPropertyById(cx, obj, id, v,
2891 ps->flags & ~JSPROP_INTERNAL_USE_BIT))
2892 return false;
2893 }
2894 }
2895 return true;
2896 }
2897
ObjectToCompletePropertyDescriptor(JSContext * cx,HandleObject obj,HandleValue descObj,MutableHandle<PropertyDescriptor> desc)2898 JS_PUBLIC_API bool JS::ObjectToCompletePropertyDescriptor(
2899 JSContext* cx, HandleObject obj, HandleValue descObj,
2900 MutableHandle<PropertyDescriptor> desc) {
2901 // |obj| can be in a different compartment here. The caller is responsible
2902 // for wrapping it (see JS_WrapPropertyDescriptor).
2903 assertSameCompartment(cx, descObj);
2904 if (!ToPropertyDescriptor(cx, descObj, true, desc)) return false;
2905 CompletePropertyDescriptor(desc);
2906 desc.object().set(obj);
2907 return true;
2908 }
2909
JS_SetAllNonReservedSlotsToUndefined(JSContext * cx,JSObject * objArg)2910 JS_PUBLIC_API void JS_SetAllNonReservedSlotsToUndefined(JSContext* cx,
2911 JSObject* objArg) {
2912 RootedObject obj(cx, objArg);
2913 AssertHeapIsIdle();
2914 CHECK_REQUEST(cx);
2915 assertSameCompartment(cx, obj);
2916
2917 if (!obj->isNative()) return;
2918
2919 const Class* clasp = obj->getClass();
2920 unsigned numReserved = JSCLASS_RESERVED_SLOTS(clasp);
2921 unsigned numSlots = obj->as<NativeObject>().slotSpan();
2922 for (unsigned i = numReserved; i < numSlots; i++)
2923 obj->as<NativeObject>().setSlot(i, UndefinedValue());
2924 }
2925
JS_GetReservedSlot(JSObject * obj,uint32_t index)2926 JS_PUBLIC_API Value JS_GetReservedSlot(JSObject* obj, uint32_t index) {
2927 return obj->as<NativeObject>().getReservedSlot(index);
2928 }
2929
JS_SetReservedSlot(JSObject * obj,uint32_t index,const Value & value)2930 JS_PUBLIC_API void JS_SetReservedSlot(JSObject* obj, uint32_t index,
2931 const Value& value) {
2932 obj->as<NativeObject>().setReservedSlot(index, value);
2933 }
2934
JS_NewArrayObject(JSContext * cx,const JS::HandleValueArray & contents)2935 JS_PUBLIC_API JSObject* JS_NewArrayObject(
2936 JSContext* cx, const JS::HandleValueArray& contents) {
2937 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
2938 AssertHeapIsIdle();
2939 CHECK_REQUEST(cx);
2940
2941 assertSameCompartment(cx, contents);
2942 return NewDenseCopiedArray(cx, contents.length(), contents.begin());
2943 }
2944
JS_NewArrayObject(JSContext * cx,size_t length)2945 JS_PUBLIC_API JSObject* JS_NewArrayObject(JSContext* cx, size_t length) {
2946 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
2947 AssertHeapIsIdle();
2948 CHECK_REQUEST(cx);
2949
2950 return NewDenseFullyAllocatedArray(cx, length);
2951 }
2952
IsGivenTypeObject(JSContext * cx,JS::HandleObject obj,const ESClass & typeClass,bool * isType)2953 inline bool IsGivenTypeObject(JSContext* cx, JS::HandleObject obj,
2954 const ESClass& typeClass, bool* isType) {
2955 assertSameCompartment(cx, obj);
2956
2957 ESClass cls;
2958 if (!GetBuiltinClass(cx, obj, &cls)) return false;
2959
2960 *isType = cls == typeClass;
2961 return true;
2962 }
2963
JS_IsArrayObject(JSContext * cx,JS::HandleObject obj,bool * isArray)2964 JS_PUBLIC_API bool JS_IsArrayObject(JSContext* cx, JS::HandleObject obj,
2965 bool* isArray) {
2966 return IsGivenTypeObject(cx, obj, ESClass::Array, isArray);
2967 }
2968
JS_IsArrayObject(JSContext * cx,JS::HandleValue value,bool * isArray)2969 JS_PUBLIC_API bool JS_IsArrayObject(JSContext* cx, JS::HandleValue value,
2970 bool* isArray) {
2971 if (!value.isObject()) {
2972 *isArray = false;
2973 return true;
2974 }
2975
2976 RootedObject obj(cx, &value.toObject());
2977 return JS_IsArrayObject(cx, obj, isArray);
2978 }
2979
JS_GetArrayLength(JSContext * cx,HandleObject obj,uint32_t * lengthp)2980 JS_PUBLIC_API bool JS_GetArrayLength(JSContext* cx, HandleObject obj,
2981 uint32_t* lengthp) {
2982 AssertHeapIsIdle();
2983 CHECK_REQUEST(cx);
2984 assertSameCompartment(cx, obj);
2985 return GetLengthProperty(cx, obj, lengthp);
2986 }
2987
JS_SetArrayLength(JSContext * cx,HandleObject obj,uint32_t length)2988 JS_PUBLIC_API bool JS_SetArrayLength(JSContext* cx, HandleObject obj,
2989 uint32_t length) {
2990 AssertHeapIsIdle();
2991 CHECK_REQUEST(cx);
2992 assertSameCompartment(cx, obj);
2993 return SetLengthProperty(cx, obj, length);
2994 }
2995
IsMapObject(JSContext * cx,JS::HandleObject obj,bool * isMap)2996 JS_PUBLIC_API bool JS::IsMapObject(JSContext* cx, JS::HandleObject obj,
2997 bool* isMap) {
2998 return IsGivenTypeObject(cx, obj, ESClass::Map, isMap);
2999 }
3000
IsSetObject(JSContext * cx,JS::HandleObject obj,bool * isSet)3001 JS_PUBLIC_API bool JS::IsSetObject(JSContext* cx, JS::HandleObject obj,
3002 bool* isSet) {
3003 return IsGivenTypeObject(cx, obj, ESClass::Set, isSet);
3004 }
3005
JS_HoldPrincipals(JSPrincipals * principals)3006 JS_PUBLIC_API void JS_HoldPrincipals(JSPrincipals* principals) {
3007 ++principals->refcount;
3008 }
3009
JS_DropPrincipals(JSContext * cx,JSPrincipals * principals)3010 JS_PUBLIC_API void JS_DropPrincipals(JSContext* cx, JSPrincipals* principals) {
3011 int rc = --principals->refcount;
3012 if (rc == 0) cx->runtime()->destroyPrincipals(principals);
3013 }
3014
JS_SetSecurityCallbacks(JSContext * cx,const JSSecurityCallbacks * scb)3015 JS_PUBLIC_API void JS_SetSecurityCallbacks(JSContext* cx,
3016 const JSSecurityCallbacks* scb) {
3017 MOZ_ASSERT(scb != &NullSecurityCallbacks);
3018 cx->runtime()->securityCallbacks = scb ? scb : &NullSecurityCallbacks;
3019 }
3020
JS_GetSecurityCallbacks(JSContext * cx)3021 JS_PUBLIC_API const JSSecurityCallbacks* JS_GetSecurityCallbacks(
3022 JSContext* cx) {
3023 return (cx->runtime()->securityCallbacks != &NullSecurityCallbacks)
3024 ? cx->runtime()->securityCallbacks.ref()
3025 : nullptr;
3026 }
3027
JS_SetTrustedPrincipals(JSContext * cx,JSPrincipals * prin)3028 JS_PUBLIC_API void JS_SetTrustedPrincipals(JSContext* cx, JSPrincipals* prin) {
3029 cx->runtime()->setTrustedPrincipals(prin);
3030 }
3031
JS_InitDestroyPrincipalsCallback(JSContext * cx,JSDestroyPrincipalsOp destroyPrincipals)3032 extern JS_PUBLIC_API void JS_InitDestroyPrincipalsCallback(
3033 JSContext* cx, JSDestroyPrincipalsOp destroyPrincipals) {
3034 MOZ_ASSERT(destroyPrincipals);
3035 MOZ_ASSERT(!cx->runtime()->destroyPrincipals);
3036 cx->runtime()->destroyPrincipals = destroyPrincipals;
3037 }
3038
JS_InitReadPrincipalsCallback(JSContext * cx,JSReadPrincipalsOp read)3039 extern JS_PUBLIC_API void JS_InitReadPrincipalsCallback(
3040 JSContext* cx, JSReadPrincipalsOp read) {
3041 MOZ_ASSERT(read);
3042 MOZ_ASSERT(!cx->runtime()->readPrincipals);
3043 cx->runtime()->readPrincipals = read;
3044 }
3045
JS_NewFunction(JSContext * cx,JSNative native,unsigned nargs,unsigned flags,const char * name)3046 JS_PUBLIC_API JSFunction* JS_NewFunction(JSContext* cx, JSNative native,
3047 unsigned nargs, unsigned flags,
3048 const char* name) {
3049 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3050
3051 AssertHeapIsIdle();
3052 CHECK_REQUEST(cx);
3053
3054 RootedAtom atom(cx);
3055 if (name) {
3056 atom = Atomize(cx, name, strlen(name));
3057 if (!atom) return nullptr;
3058 }
3059
3060 return (flags & JSFUN_CONSTRUCTOR)
3061 ? NewNativeConstructor(cx, native, nargs, atom)
3062 : NewNativeFunction(cx, native, nargs, atom);
3063 }
3064
GetSelfHostedFunction(JSContext * cx,const char * selfHostedName,HandleId id,unsigned nargs)3065 JS_PUBLIC_API JSFunction* JS::GetSelfHostedFunction(JSContext* cx,
3066 const char* selfHostedName,
3067 HandleId id,
3068 unsigned nargs) {
3069 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3070 AssertHeapIsIdle();
3071 CHECK_REQUEST(cx);
3072 assertSameCompartment(cx, id);
3073
3074 RootedAtom name(cx, IdToFunctionName(cx, id));
3075 if (!name) return nullptr;
3076
3077 JSAtom* shAtom = Atomize(cx, selfHostedName, strlen(selfHostedName));
3078 if (!shAtom) return nullptr;
3079 RootedPropertyName shName(cx, shAtom->asPropertyName());
3080 RootedValue funVal(cx);
3081 if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name,
3082 nargs, &funVal))
3083 return nullptr;
3084 return &funVal.toObject().as<JSFunction>();
3085 }
3086
NewFunctionFromSpec(JSContext * cx,const JSFunctionSpec * fs,HandleId id)3087 JS_PUBLIC_API JSFunction* JS::NewFunctionFromSpec(JSContext* cx,
3088 const JSFunctionSpec* fs,
3089 HandleId id) {
3090 assertSameCompartment(cx, id);
3091
3092 // Delay cloning self-hosted functions until they are called. This is
3093 // achieved by passing DefineFunction a nullptr JSNative which produces an
3094 // interpreted JSFunction where !hasScript. Interpreted call paths then
3095 // call InitializeLazyFunctionScript if !hasScript.
3096 if (fs->selfHostedName) {
3097 MOZ_ASSERT(!fs->call.op);
3098 MOZ_ASSERT(!fs->call.info);
3099
3100 JSAtom* shAtom =
3101 Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName));
3102 if (!shAtom) return nullptr;
3103 RootedPropertyName shName(cx, shAtom->asPropertyName());
3104 RootedAtom name(cx, IdToFunctionName(cx, id));
3105 if (!name) return nullptr;
3106 RootedValue funVal(cx);
3107 if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name,
3108 fs->nargs, &funVal)) {
3109 return nullptr;
3110 }
3111 return &funVal.toObject().as<JSFunction>();
3112 }
3113
3114 RootedAtom atom(cx, IdToFunctionName(cx, id));
3115 if (!atom) return nullptr;
3116
3117 JSFunction* fun;
3118 if (!fs->call.op)
3119 fun =
3120 NewScriptedFunction(cx, fs->nargs, JSFunction::INTERPRETED_LAZY, atom);
3121 else if (fs->flags & JSFUN_CONSTRUCTOR)
3122 fun = NewNativeConstructor(cx, fs->call.op, fs->nargs, atom);
3123 else
3124 fun = NewNativeFunction(cx, fs->call.op, fs->nargs, atom);
3125 if (!fun) return nullptr;
3126
3127 if (fs->call.info) fun->setJitInfo(fs->call.info);
3128 return fun;
3129 }
3130
CreateNonSyntacticEnvironmentChain(JSContext * cx,AutoObjectVector & envChain,MutableHandleObject env,MutableHandleScope scope)3131 static bool CreateNonSyntacticEnvironmentChain(JSContext* cx,
3132 AutoObjectVector& envChain,
3133 MutableHandleObject env,
3134 MutableHandleScope scope) {
3135 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
3136 if (!js::CreateObjectsForEnvironmentChain(cx, envChain, globalLexical, env))
3137 return false;
3138
3139 if (!envChain.empty()) {
3140 scope.set(GlobalScope::createEmpty(cx, ScopeKind::NonSyntactic));
3141 if (!scope) return false;
3142
3143 // The XPConnect subscript loader, which may pass in its own
3144 // environments to load scripts in, expects the environment chain to
3145 // be the holder of "var" declarations. In SpiderMonkey, such objects
3146 // are called "qualified varobjs", the "qualified" part meaning the
3147 // declaration was qualified by "var". There is only sadness.
3148 //
3149 // See JSObject::isQualifiedVarObj.
3150 if (!JSObject::setQualifiedVarObj(cx, env)) return false;
3151
3152 // Also get a non-syntactic lexical environment to capture 'let' and
3153 // 'const' bindings. To persist lexical bindings, we have a 1-1
3154 // mapping with the final unwrapped environment object (the
3155 // environment that stores the 'var' bindings) and the lexical
3156 // environment.
3157 //
3158 // TODOshu: disallow the subscript loader from using non-distinguished
3159 // objects as dynamic scopes.
3160 env.set(
3161 cx->compartment()->getOrCreateNonSyntacticLexicalEnvironment(cx, env));
3162 if (!env) return false;
3163 } else {
3164 scope.set(&cx->global()->emptyGlobalScope());
3165 }
3166
3167 return true;
3168 }
3169
IsFunctionCloneable(HandleFunction fun)3170 static bool IsFunctionCloneable(HandleFunction fun) {
3171 // If a function was compiled with non-global syntactic environments on
3172 // the environment chain, we could have baked in EnvironmentCoordinates
3173 // into the script. We cannot clone it without breaking the compiler's
3174 // assumptions.
3175 for (ScopeIter si(fun->nonLazyScript()->enclosingScope()); si; si++) {
3176 if (si.scope()->is<GlobalScope>()) return true;
3177 if (si.hasSyntacticEnvironment()) return false;
3178 }
3179
3180 return true;
3181 }
3182
CloneFunctionObject(JSContext * cx,HandleObject funobj,HandleObject env,HandleScope scope)3183 static JSObject* CloneFunctionObject(JSContext* cx, HandleObject funobj,
3184 HandleObject env, HandleScope scope) {
3185 AssertHeapIsIdle();
3186 CHECK_REQUEST(cx);
3187 assertSameCompartment(cx, env);
3188 MOZ_ASSERT(env);
3189 // Note that funobj can be in a different compartment.
3190
3191 if (!funobj->is<JSFunction>()) {
3192 AutoCompartment ac(cx, funobj);
3193 RootedValue v(cx, ObjectValue(*funobj));
3194 ReportIsNotFunction(cx, v);
3195 return nullptr;
3196 }
3197
3198 RootedFunction fun(cx, &funobj->as<JSFunction>());
3199 if (fun->isInterpretedLazy()) {
3200 AutoCompartment ac(cx, funobj);
3201 if (!JSFunction::getOrCreateScript(cx, fun)) return nullptr;
3202 }
3203
3204 // Only allow cloning normal, interpreted functions.
3205 if (fun->isNative() || fun->isBoundFunction() ||
3206 fun->kind() != JSFunction::NormalFunction || fun->isExtended()) {
3207 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
3208 JSMSG_CANT_CLONE_OBJECT);
3209 return nullptr;
3210 }
3211
3212 if (!IsFunctionCloneable(fun)) {
3213 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
3214 JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
3215 return nullptr;
3216 }
3217
3218 if (CanReuseScriptForClone(cx->compartment(), fun, env)) {
3219 // If the script is to be reused, either the script can already handle
3220 // non-syntactic scopes, or there is only the standard global lexical
3221 // scope.
3222 #ifdef DEBUG
3223 // Fail here if we OOM during debug asserting.
3224 // CloneFunctionReuseScript will delazify the script anyways, so we
3225 // are not creating an extra failure condition for DEBUG builds.
3226 if (!JSFunction::getOrCreateScript(cx, fun)) return nullptr;
3227 MOZ_ASSERT(scope->as<GlobalScope>().isSyntactic() ||
3228 fun->nonLazyScript()->hasNonSyntacticScope());
3229 #endif
3230 return CloneFunctionReuseScript(cx, fun, env, fun->getAllocKind());
3231 }
3232
3233 JSFunction* clone =
3234 CloneFunctionAndScript(cx, fun, env, scope, fun->getAllocKind());
3235
3236 #ifdef DEBUG
3237 // The cloned function should itself be cloneable.
3238 RootedFunction cloneRoot(cx, clone);
3239 MOZ_ASSERT_IF(cloneRoot, IsFunctionCloneable(cloneRoot));
3240 #endif
3241
3242 return clone;
3243 }
3244
CloneFunctionObject(JSContext * cx,HandleObject funobj)3245 JS_PUBLIC_API JSObject* JS::CloneFunctionObject(JSContext* cx,
3246 HandleObject funobj) {
3247 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
3248 RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
3249 return CloneFunctionObject(cx, funobj, globalLexical, emptyGlobalScope);
3250 }
3251
CloneFunctionObject(JSContext * cx,HandleObject funobj,AutoObjectVector & envChain)3252 extern JS_PUBLIC_API JSObject* JS::CloneFunctionObject(
3253 JSContext* cx, HandleObject funobj, AutoObjectVector& envChain) {
3254 RootedObject env(cx);
3255 RootedScope scope(cx);
3256 if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
3257 return nullptr;
3258 return CloneFunctionObject(cx, funobj, env, scope);
3259 }
3260
JS_GetFunctionObject(JSFunction * fun)3261 JS_PUBLIC_API JSObject* JS_GetFunctionObject(JSFunction* fun) { return fun; }
3262
JS_GetFunctionId(JSFunction * fun)3263 JS_PUBLIC_API JSString* JS_GetFunctionId(JSFunction* fun) {
3264 return fun->explicitName();
3265 }
3266
JS_GetFunctionDisplayId(JSFunction * fun)3267 JS_PUBLIC_API JSString* JS_GetFunctionDisplayId(JSFunction* fun) {
3268 return fun->displayAtom();
3269 }
3270
JS_GetFunctionArity(JSFunction * fun)3271 JS_PUBLIC_API uint16_t JS_GetFunctionArity(JSFunction* fun) {
3272 return fun->nargs();
3273 }
3274
JS_ObjectIsFunction(JSContext * cx,JSObject * obj)3275 JS_PUBLIC_API bool JS_ObjectIsFunction(JSContext* cx, JSObject* obj) {
3276 return obj->is<JSFunction>();
3277 }
3278
JS_IsNativeFunction(JSObject * funobj,JSNative call)3279 JS_PUBLIC_API bool JS_IsNativeFunction(JSObject* funobj, JSNative call) {
3280 if (!funobj->is<JSFunction>()) return false;
3281 JSFunction* fun = &funobj->as<JSFunction>();
3282 return fun->isNative() && fun->native() == call;
3283 }
3284
JS_IsConstructor(JSFunction * fun)3285 extern JS_PUBLIC_API bool JS_IsConstructor(JSFunction* fun) {
3286 return fun->isConstructor();
3287 }
3288
JS_DefineFunctions(JSContext * cx,HandleObject obj,const JSFunctionSpec * fs)3289 JS_PUBLIC_API bool JS_DefineFunctions(JSContext* cx, HandleObject obj,
3290 const JSFunctionSpec* fs) {
3291 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3292 AssertHeapIsIdle();
3293 CHECK_REQUEST(cx);
3294 assertSameCompartment(cx, obj);
3295
3296 return DefineFunctions(cx, obj, fs, NotIntrinsic);
3297 }
3298
JS_DefineFunction(JSContext * cx,HandleObject obj,const char * name,JSNative call,unsigned nargs,unsigned attrs)3299 JS_PUBLIC_API JSFunction* JS_DefineFunction(JSContext* cx, HandleObject obj,
3300 const char* name, JSNative call,
3301 unsigned nargs, unsigned attrs) {
3302 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3303 AssertHeapIsIdle();
3304 CHECK_REQUEST(cx);
3305 assertSameCompartment(cx, obj);
3306 JSAtom* atom = Atomize(cx, name, strlen(name));
3307 if (!atom) return nullptr;
3308 Rooted<jsid> id(cx, AtomToId(atom));
3309 return DefineFunction(cx, obj, id, call, nargs, attrs);
3310 }
3311
JS_DefineUCFunction(JSContext * cx,HandleObject obj,const char16_t * name,size_t namelen,JSNative call,unsigned nargs,unsigned attrs)3312 JS_PUBLIC_API JSFunction* JS_DefineUCFunction(JSContext* cx, HandleObject obj,
3313 const char16_t* name,
3314 size_t namelen, JSNative call,
3315 unsigned nargs, unsigned attrs) {
3316 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3317 AssertHeapIsIdle();
3318 CHECK_REQUEST(cx);
3319 assertSameCompartment(cx, obj);
3320 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3321 if (!atom) return nullptr;
3322 Rooted<jsid> id(cx, AtomToId(atom));
3323 return DefineFunction(cx, obj, id, call, nargs, attrs);
3324 }
3325
JS_DefineFunctionById(JSContext * cx,HandleObject obj,HandleId id,JSNative call,unsigned nargs,unsigned attrs)3326 extern JS_PUBLIC_API JSFunction* JS_DefineFunctionById(
3327 JSContext* cx, HandleObject obj, HandleId id, JSNative call, unsigned nargs,
3328 unsigned attrs) {
3329 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3330 AssertHeapIsIdle();
3331 CHECK_REQUEST(cx);
3332 assertSameCompartment(cx, obj, id);
3333 return DefineFunction(cx, obj, id, call, nargs, attrs);
3334 }
3335
3336 /* Use the fastest available getc. */
3337 #if defined(HAVE_GETC_UNLOCKED)
3338 #define fast_getc getc_unlocked
3339 #elif defined(HAVE__GETC_NOLOCK)
3340 #define fast_getc _getc_nolock
3341 #else
3342 #define fast_getc getc
3343 #endif
3344
3345 typedef Vector<char, 8, TempAllocPolicy> FileContents;
3346
ReadCompleteFile(JSContext * cx,FILE * fp,FileContents & buffer)3347 static bool ReadCompleteFile(JSContext* cx, FILE* fp, FileContents& buffer) {
3348 /* Get the complete length of the file, if possible. */
3349 struct stat st;
3350 int ok = fstat(fileno(fp), &st);
3351 if (ok != 0) return false;
3352 if (st.st_size > 0) {
3353 if (!buffer.reserve(st.st_size)) return false;
3354 }
3355
3356 // Read in the whole file. Note that we can't assume the data's length
3357 // is actually st.st_size, because 1) some files lie about their size
3358 // (/dev/zero and /dev/random), and 2) reading files in text mode on
3359 // Windows collapses "\r\n" pairs to single \n characters.
3360 for (;;) {
3361 int c = fast_getc(fp);
3362 if (c == EOF) break;
3363 if (!buffer.append(c)) return false;
3364 }
3365
3366 return true;
3367 }
3368
3369 namespace {
3370
3371 class AutoFile {
3372 FILE* fp_;
3373
3374 public:
AutoFile()3375 AutoFile() : fp_(nullptr) {}
~AutoFile()3376 ~AutoFile() {
3377 if (fp_ && fp_ != stdin) fclose(fp_);
3378 }
fp() const3379 FILE* fp() const { return fp_; }
3380 bool open(JSContext* cx, const char* filename);
readAll(JSContext * cx,FileContents & buffer)3381 bool readAll(JSContext* cx, FileContents& buffer) {
3382 MOZ_ASSERT(fp_);
3383 return ReadCompleteFile(cx, fp_, buffer);
3384 }
3385 };
3386
3387 } /* anonymous namespace */
3388
3389 /*
3390 * Open a source file for reading. Supports "-" and nullptr to mean stdin. The
3391 * return value must be fclosed unless it is stdin.
3392 */
open(JSContext * cx,const char * filename)3393 bool AutoFile::open(JSContext* cx, const char* filename) {
3394 if (!filename || strcmp(filename, "-") == 0) {
3395 fp_ = stdin;
3396 } else {
3397 fp_ = fopen(filename, "r");
3398 if (!fp_) {
3399 /*
3400 * Use Latin1 variant here because the encoding of filename is
3401 * platform dependent.
3402 */
3403 JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_CANT_OPEN,
3404 filename, "No such file or directory");
3405 return false;
3406 }
3407 }
3408 return true;
3409 }
3410
copyPODTransitiveOptions(const TransitiveCompileOptions & rhs)3411 void JS::TransitiveCompileOptions::copyPODTransitiveOptions(
3412 const TransitiveCompileOptions& rhs) {
3413 mutedErrors_ = rhs.mutedErrors_;
3414 utf8 = rhs.utf8;
3415 selfHostingMode = rhs.selfHostingMode;
3416 canLazilyParse = rhs.canLazilyParse;
3417 strictOption = rhs.strictOption;
3418 extraWarningsOption = rhs.extraWarningsOption;
3419 expressionClosuresOption = rhs.expressionClosuresOption;
3420 werrorOption = rhs.werrorOption;
3421 asmJSOption = rhs.asmJSOption;
3422 throwOnAsmJSValidationFailureOption = rhs.throwOnAsmJSValidationFailureOption;
3423 forceAsync = rhs.forceAsync;
3424 sourceIsLazy = rhs.sourceIsLazy;
3425 introductionType = rhs.introductionType;
3426 introductionLineno = rhs.introductionLineno;
3427 introductionOffset = rhs.introductionOffset;
3428 hasIntroductionInfo = rhs.hasIntroductionInfo;
3429 isProbablySystemOrAddonCode = rhs.isProbablySystemOrAddonCode;
3430 hideScriptFromDebugger = rhs.hideScriptFromDebugger;
3431 };
3432
copyPODOptions(const ReadOnlyCompileOptions & rhs)3433 void JS::ReadOnlyCompileOptions::copyPODOptions(
3434 const ReadOnlyCompileOptions& rhs) {
3435 copyPODTransitiveOptions(rhs);
3436 lineno = rhs.lineno;
3437 column = rhs.column;
3438 scriptSourceOffset = rhs.scriptSourceOffset;
3439 isRunOnce = rhs.isRunOnce;
3440 noScriptRval = rhs.noScriptRval;
3441 nonSyntacticScope = rhs.nonSyntacticScope;
3442 }
3443
OwningCompileOptions(JSContext * cx)3444 JS::OwningCompileOptions::OwningCompileOptions(JSContext* cx)
3445 : ReadOnlyCompileOptions(),
3446 elementRoot(cx),
3447 elementAttributeNameRoot(cx),
3448 introductionScriptRoot(cx) {}
3449
~OwningCompileOptions()3450 JS::OwningCompileOptions::~OwningCompileOptions() {
3451 // OwningCompileOptions always owns these, so these casts are okay.
3452 js_free(const_cast<char*>(filename_));
3453 js_free(const_cast<char16_t*>(sourceMapURL_));
3454 js_free(const_cast<char*>(introducerFilename_));
3455 }
3456
copy(JSContext * cx,const ReadOnlyCompileOptions & rhs)3457 bool JS::OwningCompileOptions::copy(JSContext* cx,
3458 const ReadOnlyCompileOptions& rhs) {
3459 copyPODOptions(rhs);
3460
3461 setElement(rhs.element());
3462 setElementAttributeName(rhs.elementAttributeName());
3463 setIntroductionScript(rhs.introductionScript());
3464
3465 return setFileAndLine(cx, rhs.filename(), rhs.lineno) &&
3466 setSourceMapURL(cx, rhs.sourceMapURL()) &&
3467 setIntroducerFilename(cx, rhs.introducerFilename());
3468 }
3469
setFile(JSContext * cx,const char * f)3470 bool JS::OwningCompileOptions::setFile(JSContext* cx, const char* f) {
3471 char* copy = nullptr;
3472 if (f) {
3473 copy = JS_strdup(cx, f);
3474 if (!copy) return false;
3475 }
3476
3477 // OwningCompileOptions always owns filename_, so this cast is okay.
3478 js_free(const_cast<char*>(filename_));
3479
3480 filename_ = copy;
3481 return true;
3482 }
3483
setFileAndLine(JSContext * cx,const char * f,unsigned l)3484 bool JS::OwningCompileOptions::setFileAndLine(JSContext* cx, const char* f,
3485 unsigned l) {
3486 if (!setFile(cx, f)) return false;
3487
3488 lineno = l;
3489 return true;
3490 }
3491
setSourceMapURL(JSContext * cx,const char16_t * s)3492 bool JS::OwningCompileOptions::setSourceMapURL(JSContext* cx,
3493 const char16_t* s) {
3494 UniqueTwoByteChars copy;
3495 if (s) {
3496 copy = DuplicateString(cx, s);
3497 if (!copy) return false;
3498 }
3499
3500 // OwningCompileOptions always owns sourceMapURL_, so this cast is okay.
3501 js_free(const_cast<char16_t*>(sourceMapURL_));
3502
3503 sourceMapURL_ = copy.release();
3504 return true;
3505 }
3506
setIntroducerFilename(JSContext * cx,const char * s)3507 bool JS::OwningCompileOptions::setIntroducerFilename(JSContext* cx,
3508 const char* s) {
3509 char* copy = nullptr;
3510 if (s) {
3511 copy = JS_strdup(cx, s);
3512 if (!copy) return false;
3513 }
3514
3515 // OwningCompileOptions always owns introducerFilename_, so this cast is okay.
3516 js_free(const_cast<char*>(introducerFilename_));
3517
3518 introducerFilename_ = copy;
3519 return true;
3520 }
3521
CompileOptions(JSContext * cx)3522 JS::CompileOptions::CompileOptions(JSContext* cx)
3523 : ReadOnlyCompileOptions(),
3524 elementRoot(cx),
3525 elementAttributeNameRoot(cx),
3526 introductionScriptRoot(cx) {
3527 strictOption = cx->options().strictMode();
3528 extraWarningsOption = cx->compartment()->behaviors().extraWarnings(cx);
3529 expressionClosuresOption = cx->options().expressionClosures();
3530 isProbablySystemOrAddonCode =
3531 cx->compartment()->isProbablySystemOrAddonCode();
3532 werrorOption = cx->options().werror();
3533 if (!cx->options().asmJS())
3534 asmJSOption = AsmJSOption::Disabled;
3535 else if (cx->compartment()->debuggerObservesAsmJS())
3536 asmJSOption = AsmJSOption::DisabledByDebugger;
3537 else
3538 asmJSOption = AsmJSOption::Enabled;
3539 throwOnAsmJSValidationFailureOption =
3540 cx->options().throwOnAsmJSValidationFailure();
3541 }
3542
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,SourceBufferHolder & srcBuf,MutableHandleScript script)3543 static bool Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
3544 SourceBufferHolder& srcBuf, MutableHandleScript script) {
3545 ScopeKind scopeKind =
3546 options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global;
3547
3548 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3549 AssertHeapIsIdle();
3550 CHECK_REQUEST(cx);
3551
3552 script.set(frontend::CompileGlobalScript(cx, cx->tempLifoAlloc(), scopeKind,
3553 options, srcBuf));
3554 return !!script;
3555 }
3556
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,const char16_t * chars,size_t length,MutableHandleScript script)3557 static bool Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
3558 const char16_t* chars, size_t length,
3559 MutableHandleScript script) {
3560 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
3561 return ::Compile(cx, options, srcBuf, script);
3562 }
3563
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,const char * bytes,size_t length,MutableHandleScript script)3564 static bool Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
3565 const char* bytes, size_t length,
3566 MutableHandleScript script) {
3567 UniqueTwoByteChars chars;
3568 if (options.utf8)
3569 chars.reset(
3570 UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length)
3571 .get());
3572 else
3573 chars.reset(InflateString(cx, bytes, length));
3574 if (!chars) return false;
3575
3576 return ::Compile(cx, options, chars.get(), length, script);
3577 }
3578
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,FILE * fp,MutableHandleScript script)3579 static bool Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
3580 FILE* fp, MutableHandleScript script) {
3581 FileContents buffer(cx);
3582 if (!ReadCompleteFile(cx, fp, buffer)) return false;
3583
3584 return ::Compile(cx, options, buffer.begin(), buffer.length(), script);
3585 }
3586
Compile(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,const char * filename,MutableHandleScript script)3587 static bool Compile(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
3588 const char* filename, MutableHandleScript script) {
3589 AutoFile file;
3590 if (!file.open(cx, filename)) return false;
3591 CompileOptions options(cx, optionsArg);
3592 options.setFileAndLine(filename, 1);
3593 return ::Compile(cx, options, file.fp(), script);
3594 }
3595
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,SourceBufferHolder & srcBuf,JS::MutableHandleScript script)3596 bool JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
3597 SourceBufferHolder& srcBuf, JS::MutableHandleScript script) {
3598 return ::Compile(cx, options, srcBuf, script);
3599 }
3600
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,const char * bytes,size_t length,JS::MutableHandleScript script)3601 bool JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
3602 const char* bytes, size_t length,
3603 JS::MutableHandleScript script) {
3604 return ::Compile(cx, options, bytes, length, script);
3605 }
3606
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,const char16_t * chars,size_t length,JS::MutableHandleScript script)3607 bool JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
3608 const char16_t* chars, size_t length,
3609 JS::MutableHandleScript script) {
3610 return ::Compile(cx, options, chars, length, script);
3611 }
3612
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,FILE * file,JS::MutableHandleScript script)3613 bool JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
3614 FILE* file, JS::MutableHandleScript script) {
3615 return ::Compile(cx, options, file, script);
3616 }
3617
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,const char * filename,JS::MutableHandleScript script)3618 bool JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
3619 const char* filename, JS::MutableHandleScript script) {
3620 return ::Compile(cx, options, filename, script);
3621 }
3622
CompileForNonSyntacticScope(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,SourceBufferHolder & srcBuf,JS::MutableHandleScript script)3623 bool JS::CompileForNonSyntacticScope(JSContext* cx,
3624 const ReadOnlyCompileOptions& optionsArg,
3625 SourceBufferHolder& srcBuf,
3626 JS::MutableHandleScript script) {
3627 CompileOptions options(cx, optionsArg);
3628 options.setNonSyntacticScope(true);
3629 return ::Compile(cx, options, srcBuf, script);
3630 }
3631
CompileForNonSyntacticScope(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,const char * bytes,size_t length,JS::MutableHandleScript script)3632 bool JS::CompileForNonSyntacticScope(JSContext* cx,
3633 const ReadOnlyCompileOptions& optionsArg,
3634 const char* bytes, size_t length,
3635 JS::MutableHandleScript script) {
3636 CompileOptions options(cx, optionsArg);
3637 options.setNonSyntacticScope(true);
3638 return ::Compile(cx, options, bytes, length, script);
3639 }
3640
CompileForNonSyntacticScope(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,const char16_t * chars,size_t length,JS::MutableHandleScript script)3641 bool JS::CompileForNonSyntacticScope(JSContext* cx,
3642 const ReadOnlyCompileOptions& optionsArg,
3643 const char16_t* chars, size_t length,
3644 JS::MutableHandleScript script) {
3645 CompileOptions options(cx, optionsArg);
3646 options.setNonSyntacticScope(true);
3647 return ::Compile(cx, options, chars, length, script);
3648 }
3649
CompileForNonSyntacticScope(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,FILE * file,JS::MutableHandleScript script)3650 bool JS::CompileForNonSyntacticScope(JSContext* cx,
3651 const ReadOnlyCompileOptions& optionsArg,
3652 FILE* file,
3653 JS::MutableHandleScript script) {
3654 CompileOptions options(cx, optionsArg);
3655 options.setNonSyntacticScope(true);
3656 return ::Compile(cx, options, file, script);
3657 }
3658
CompileForNonSyntacticScope(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,const char * filename,JS::MutableHandleScript script)3659 bool JS::CompileForNonSyntacticScope(JSContext* cx,
3660 const ReadOnlyCompileOptions& optionsArg,
3661 const char* filename,
3662 JS::MutableHandleScript script) {
3663 CompileOptions options(cx, optionsArg);
3664 options.setNonSyntacticScope(true);
3665 return ::Compile(cx, options, filename, script);
3666 }
3667
3668 enum class OffThread {
3669 Compile,
3670 Decode,
3671 };
3672
CanDoOffThread(JSContext * cx,const ReadOnlyCompileOptions & options,size_t length,OffThread what)3673 static bool CanDoOffThread(JSContext* cx, const ReadOnlyCompileOptions& options,
3674 size_t length, OffThread what) {
3675 static const size_t TINY_LENGTH = 5 * 1000;
3676 static const size_t HUGE_SRC_LENGTH = 100 * 1000;
3677 static const size_t HUGE_BC_LENGTH = 367 * 1000;
3678
3679 // These are heuristics which the caller may choose to ignore (e.g., for
3680 // testing purposes).
3681 if (!options.forceAsync) {
3682 // Compiling off the active thread inolves creating a new Zone and other
3683 // significant overheads. Don't bother if the script is tiny.
3684 if (length < TINY_LENGTH) return false;
3685
3686 // If the parsing task would have to wait for GC to complete, it'll probably
3687 // be faster to just start it synchronously on the active thread unless the
3688 // script is huge.
3689 if (OffThreadParsingMustWaitForGC(cx->runtime())) {
3690 if (what == OffThread::Compile && length < HUGE_SRC_LENGTH) return false;
3691 if (what == OffThread::Decode && length < HUGE_BC_LENGTH) return false;
3692 }
3693 }
3694
3695 return cx->runtime()->canUseParallelParsing() && CanUseExtraThreads();
3696 }
3697
CanCompileOffThread(JSContext * cx,const ReadOnlyCompileOptions & options,size_t length)3698 JS_PUBLIC_API bool JS::CanCompileOffThread(
3699 JSContext* cx, const ReadOnlyCompileOptions& options, size_t length) {
3700 return CanDoOffThread(cx, options, length, OffThread::Compile);
3701 }
3702
CanDecodeOffThread(JSContext * cx,const ReadOnlyCompileOptions & options,size_t length)3703 JS_PUBLIC_API bool JS::CanDecodeOffThread(JSContext* cx,
3704 const ReadOnlyCompileOptions& options,
3705 size_t length) {
3706 return CanDoOffThread(cx, options, length, OffThread::Decode);
3707 }
3708
CompileOffThread(JSContext * cx,const ReadOnlyCompileOptions & options,const char16_t * chars,size_t length,OffThreadCompileCallback callback,void * callbackData)3709 JS_PUBLIC_API bool JS::CompileOffThread(JSContext* cx,
3710 const ReadOnlyCompileOptions& options,
3711 const char16_t* chars, size_t length,
3712 OffThreadCompileCallback callback,
3713 void* callbackData) {
3714 MOZ_ASSERT(CanCompileOffThread(cx, options, length));
3715 return StartOffThreadParseScript(cx, options, chars, length, callback,
3716 callbackData);
3717 }
3718
FinishOffThreadScript(JSContext * cx,void * token)3719 JS_PUBLIC_API JSScript* JS::FinishOffThreadScript(JSContext* cx, void* token) {
3720 MOZ_ASSERT(cx);
3721 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
3722 return HelperThreadState().finishScriptParseTask(cx, token);
3723 }
3724
CancelOffThreadScript(JSContext * cx,void * token)3725 JS_PUBLIC_API void JS::CancelOffThreadScript(JSContext* cx, void* token) {
3726 MOZ_ASSERT(cx);
3727 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
3728 HelperThreadState().cancelParseTask(cx->runtime(), ParseTaskKind::Script,
3729 token);
3730 }
3731
CompileOffThreadModule(JSContext * cx,const ReadOnlyCompileOptions & options,const char16_t * chars,size_t length,OffThreadCompileCallback callback,void * callbackData)3732 JS_PUBLIC_API bool JS::CompileOffThreadModule(
3733 JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars,
3734 size_t length, OffThreadCompileCallback callback, void* callbackData) {
3735 MOZ_ASSERT(CanCompileOffThread(cx, options, length));
3736 return StartOffThreadParseModule(cx, options, chars, length, callback,
3737 callbackData);
3738 }
3739
FinishOffThreadModule(JSContext * cx,void * token)3740 JS_PUBLIC_API JSObject* JS::FinishOffThreadModule(JSContext* cx, void* token) {
3741 MOZ_ASSERT(cx);
3742 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
3743 return HelperThreadState().finishModuleParseTask(cx, token);
3744 }
3745
CancelOffThreadModule(JSContext * cx,void * token)3746 JS_PUBLIC_API void JS::CancelOffThreadModule(JSContext* cx, void* token) {
3747 MOZ_ASSERT(cx);
3748 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
3749 HelperThreadState().cancelParseTask(cx->runtime(), ParseTaskKind::Module,
3750 token);
3751 }
3752
DecodeOffThreadScript(JSContext * cx,const ReadOnlyCompileOptions & options,mozilla::Vector<uint8_t> & buffer,size_t cursor,OffThreadCompileCallback callback,void * callbackData)3753 JS_PUBLIC_API bool JS::DecodeOffThreadScript(
3754 JSContext* cx, const ReadOnlyCompileOptions& options,
3755 mozilla::Vector<uint8_t>& buffer /* TranscodeBuffer& */, size_t cursor,
3756 OffThreadCompileCallback callback, void* callbackData) {
3757 JS::TranscodeRange range(buffer.begin() + cursor, buffer.length() - cursor);
3758 MOZ_ASSERT(CanDecodeOffThread(cx, options, range.length()));
3759 return StartOffThreadDecodeScript(cx, options, range, callback, callbackData);
3760 }
3761
DecodeOffThreadScript(JSContext * cx,const ReadOnlyCompileOptions & options,const mozilla::Range<uint8_t> & range,OffThreadCompileCallback callback,void * callbackData)3762 JS_PUBLIC_API bool JS::DecodeOffThreadScript(
3763 JSContext* cx, const ReadOnlyCompileOptions& options,
3764 const mozilla::Range<uint8_t>& range /* TranscodeRange& */,
3765 OffThreadCompileCallback callback, void* callbackData) {
3766 MOZ_ASSERT(CanDecodeOffThread(cx, options, range.length()));
3767 return StartOffThreadDecodeScript(cx, options, range, callback, callbackData);
3768 }
3769
DecodeMultiOffThreadScripts(JSContext * cx,const ReadOnlyCompileOptions & options,TranscodeSources & sources,OffThreadCompileCallback callback,void * callbackData)3770 JS_PUBLIC_API bool JS::DecodeMultiOffThreadScripts(
3771 JSContext* cx, const ReadOnlyCompileOptions& options,
3772 TranscodeSources& sources, OffThreadCompileCallback callback,
3773 void* callbackData) {
3774 #ifdef DEBUG
3775 size_t length = 0;
3776 for (auto& source : sources) {
3777 length += source.range.length();
3778 }
3779 MOZ_ASSERT(CanCompileOffThread(cx, options, length));
3780 #endif
3781 return StartOffThreadDecodeMultiScripts(cx, options, sources, callback,
3782 callbackData);
3783 }
3784
FinishOffThreadScriptDecoder(JSContext * cx,void * token)3785 JS_PUBLIC_API JSScript* JS::FinishOffThreadScriptDecoder(JSContext* cx,
3786 void* token) {
3787 MOZ_ASSERT(cx);
3788 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
3789 return HelperThreadState().finishScriptDecodeTask(cx, token);
3790 }
3791
CancelOffThreadScriptDecoder(JSContext * cx,void * token)3792 JS_PUBLIC_API void JS::CancelOffThreadScriptDecoder(JSContext* cx,
3793 void* token) {
3794 MOZ_ASSERT(cx);
3795 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
3796 HelperThreadState().cancelParseTask(cx->runtime(),
3797 ParseTaskKind::ScriptDecode, token);
3798 }
3799
FinishMultiOffThreadScriptsDecoder(JSContext * cx,void * token,MutableHandle<ScriptVector> scripts)3800 JS_PUBLIC_API bool JS::FinishMultiOffThreadScriptsDecoder(
3801 JSContext* cx, void* token, MutableHandle<ScriptVector> scripts) {
3802 MOZ_ASSERT(cx);
3803 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
3804 return HelperThreadState().finishMultiScriptsDecodeTask(cx, token, scripts);
3805 }
3806
CancelMultiOffThreadScriptsDecoder(JSContext * cx,void * token)3807 JS_PUBLIC_API void JS::CancelMultiOffThreadScriptsDecoder(JSContext* cx,
3808 void* token) {
3809 MOZ_ASSERT(cx);
3810 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
3811 HelperThreadState().cancelParseTask(cx->runtime(),
3812 ParseTaskKind::MultiScriptsDecode, token);
3813 }
3814
JS_CompileScript(JSContext * cx,const char * ascii,size_t length,const JS::CompileOptions & options,MutableHandleScript script)3815 JS_PUBLIC_API bool JS_CompileScript(JSContext* cx, const char* ascii,
3816 size_t length,
3817 const JS::CompileOptions& options,
3818 MutableHandleScript script) {
3819 return ::Compile(cx, options, ascii, length, script);
3820 }
3821
JS_CompileUCScript(JSContext * cx,const char16_t * chars,size_t length,const JS::CompileOptions & options,MutableHandleScript script)3822 JS_PUBLIC_API bool JS_CompileUCScript(JSContext* cx, const char16_t* chars,
3823 size_t length,
3824 const JS::CompileOptions& options,
3825 MutableHandleScript script) {
3826 return ::Compile(cx, options, chars, length, script);
3827 }
3828
JS_BufferIsCompilableUnit(JSContext * cx,HandleObject obj,const char * utf8,size_t length)3829 JS_PUBLIC_API bool JS_BufferIsCompilableUnit(JSContext* cx, HandleObject obj,
3830 const char* utf8, size_t length) {
3831 AssertHeapIsIdle();
3832 CHECK_REQUEST(cx);
3833 assertSameCompartment(cx, obj);
3834
3835 cx->clearPendingException();
3836
3837 char16_t* chars =
3838 JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(utf8, length), &length)
3839 .get();
3840 if (!chars) return true;
3841
3842 // Return true on any out-of-memory error or non-EOF-related syntax error, so
3843 // our caller doesn't try to collect more buffered source.
3844 bool result = true;
3845
3846 CompileOptions options(cx);
3847 frontend::UsedNameTracker usedNames(cx);
3848 if (!usedNames.init()) return false;
3849 frontend::Parser<frontend::FullParseHandler, char16_t> parser(
3850 cx, cx->tempLifoAlloc(), options, chars, length,
3851 /* foldConstants = */ true, usedNames, nullptr, nullptr);
3852 JS::WarningReporter older = JS::SetWarningReporter(cx, nullptr);
3853 if (!parser.checkOptions() || !parser.parse()) {
3854 // We ran into an error. If it was because we ran out of source, we
3855 // return false so our caller knows to try to collect more buffered
3856 // source.
3857 if (parser.isUnexpectedEOF()) result = false;
3858
3859 cx->clearPendingException();
3860 }
3861 JS::SetWarningReporter(cx, older);
3862
3863 js_free(chars);
3864 return result;
3865 }
3866
JS_GetGlobalFromScript(JSScript * script)3867 JS_PUBLIC_API JSObject* JS_GetGlobalFromScript(JSScript* script) {
3868 MOZ_ASSERT(!script->isCachedEval());
3869 return &script->global();
3870 }
3871
JS_GetScriptFilename(JSScript * script)3872 JS_PUBLIC_API const char* JS_GetScriptFilename(JSScript* script) {
3873 // This is called from ThreadStackHelper which can be called from another
3874 // thread or inside a signal hander, so we need to be careful in case a
3875 // copmacting GC is currently moving things around.
3876 return script->maybeForwardedFilename();
3877 }
3878
JS_GetScriptBaseLineNumber(JSContext * cx,JSScript * script)3879 JS_PUBLIC_API unsigned JS_GetScriptBaseLineNumber(JSContext* cx,
3880 JSScript* script) {
3881 return script->lineno();
3882 }
3883
JS_GetFunctionScript(JSContext * cx,HandleFunction fun)3884 JS_PUBLIC_API JSScript* JS_GetFunctionScript(JSContext* cx,
3885 HandleFunction fun) {
3886 if (fun->isNative()) return nullptr;
3887 if (fun->isInterpretedLazy()) {
3888 AutoCompartment funCompartment(cx, fun);
3889 JSScript* script = JSFunction::getOrCreateScript(cx, fun);
3890 if (!script) MOZ_CRASH();
3891 return script;
3892 }
3893 return fun->nonLazyScript();
3894 }
3895
3896 /*
3897 * enclosingScope is a scope, if any (e.g. a WithScope). If the scope is the
3898 * global scope, this must be null.
3899 *
3900 * enclosingEnv is an environment to use, if it's not the global.
3901 */
CompileFunction(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,HandleAtom name,bool isInvalidName,SourceBufferHolder & srcBuf,uint32_t parameterListEnd,HandleObject enclosingEnv,HandleScope enclosingScope,MutableHandleFunction fun)3902 static bool CompileFunction(
3903 JSContext* cx, const ReadOnlyCompileOptions& optionsArg, HandleAtom name,
3904 bool isInvalidName, SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
3905 HandleObject enclosingEnv, HandleScope enclosingScope,
3906 MutableHandleFunction fun) {
3907 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3908 AssertHeapIsIdle();
3909 CHECK_REQUEST(cx);
3910 assertSameCompartment(cx, enclosingEnv);
3911 RootedAtom funAtom(cx);
3912
3913 fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
3914 isInvalidName ? nullptr : name,
3915 /* proto = */ nullptr, gc::AllocKind::FUNCTION,
3916 TenuredObject, enclosingEnv));
3917 if (!fun) return false;
3918
3919 // Make sure the static scope chain matches up when we have a
3920 // non-syntactic scope.
3921 MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(enclosingEnv),
3922 enclosingScope->hasOnChain(ScopeKind::NonSyntactic));
3923
3924 if (!frontend::CompileStandaloneFunction(cx, fun, optionsArg, srcBuf,
3925 Some(parameterListEnd),
3926 enclosingScope)) {
3927 return false;
3928 }
3929
3930 // When function name is not valid identifier, generated function source
3931 // in srcBuf doesn't have function name. Set it here.
3932 if (isInvalidName) fun->setAtom(name);
3933
3934 return true;
3935 }
3936
BuildFunctionString(const char * name,size_t nameLen,unsigned nargs,const char * const * argnames,const SourceBufferHolder & srcBuf,StringBuffer * out,uint32_t * parameterListEnd)3937 static MOZ_MUST_USE bool BuildFunctionString(const char* name, size_t nameLen,
3938 unsigned nargs,
3939 const char* const* argnames,
3940 const SourceBufferHolder& srcBuf,
3941 StringBuffer* out,
3942 uint32_t* parameterListEnd) {
3943 MOZ_ASSERT(out);
3944 MOZ_ASSERT(parameterListEnd);
3945
3946 if (!out->ensureTwoByteChars()) return false;
3947 if (!out->append("function ")) return false;
3948 if (name) {
3949 if (!out->append(name, nameLen)) return false;
3950 }
3951 if (!out->append("(")) return false;
3952 for (unsigned i = 0; i < nargs; i++) {
3953 if (i != 0) {
3954 if (!out->append(", ")) return false;
3955 }
3956 if (!out->append(argnames[i], strlen(argnames[i]))) return false;
3957 }
3958
3959 // Remember the position of ")".
3960 *parameterListEnd = out->length();
3961 MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
3962
3963 if (!out->append(FunctionConstructorMedialSigils)) return false;
3964 if (!out->append(srcBuf.get(), srcBuf.length())) return false;
3965 if (!out->append(FunctionConstructorFinalBrace)) return false;
3966
3967 return true;
3968 }
3969
CompileFunction(JSContext * cx,AutoObjectVector & envChain,const ReadOnlyCompileOptions & options,const char * name,unsigned nargs,const char * const * argnames,SourceBufferHolder & srcBuf,MutableHandleFunction fun)3970 JS_PUBLIC_API bool JS::CompileFunction(JSContext* cx,
3971 AutoObjectVector& envChain,
3972 const ReadOnlyCompileOptions& options,
3973 const char* name, unsigned nargs,
3974 const char* const* argnames,
3975 SourceBufferHolder& srcBuf,
3976 MutableHandleFunction fun) {
3977 RootedObject env(cx);
3978 RootedScope scope(cx);
3979 if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
3980 return false;
3981
3982 size_t nameLen = 0;
3983 bool isInvalidName = false;
3984 RootedAtom nameAtom(cx);
3985 if (name) {
3986 nameLen = strlen(name);
3987 nameAtom = Atomize(cx, name, nameLen);
3988 if (!nameAtom) return false;
3989
3990 // If name is not valid identifier
3991 if (!js::frontend::IsIdentifier(name, nameLen)) isInvalidName = true;
3992 }
3993
3994 uint32_t parameterListEnd;
3995 StringBuffer funStr(cx);
3996 if (!BuildFunctionString(isInvalidName ? nullptr : name, nameLen, nargs,
3997 argnames, srcBuf, &funStr, ¶meterListEnd)) {
3998 return false;
3999 }
4000
4001 size_t newLen = funStr.length();
4002 SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen,
4003 SourceBufferHolder::GiveOwnership);
4004
4005 return CompileFunction(cx, options, nameAtom, isInvalidName, newSrcBuf,
4006 parameterListEnd, env, scope, fun);
4007 }
4008
CompileFunction(JSContext * cx,AutoObjectVector & envChain,const ReadOnlyCompileOptions & options,const char * name,unsigned nargs,const char * const * argnames,const char16_t * chars,size_t length,MutableHandleFunction fun)4009 JS_PUBLIC_API bool JS::CompileFunction(JSContext* cx,
4010 AutoObjectVector& envChain,
4011 const ReadOnlyCompileOptions& options,
4012 const char* name, unsigned nargs,
4013 const char* const* argnames,
4014 const char16_t* chars, size_t length,
4015 MutableHandleFunction fun) {
4016 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
4017 return CompileFunction(cx, envChain, options, name, nargs, argnames, srcBuf,
4018 fun);
4019 }
4020
CompileFunction(JSContext * cx,AutoObjectVector & envChain,const ReadOnlyCompileOptions & options,const char * name,unsigned nargs,const char * const * argnames,const char * bytes,size_t length,MutableHandleFunction fun)4021 JS_PUBLIC_API bool JS::CompileFunction(JSContext* cx,
4022 AutoObjectVector& envChain,
4023 const ReadOnlyCompileOptions& options,
4024 const char* name, unsigned nargs,
4025 const char* const* argnames,
4026 const char* bytes, size_t length,
4027 MutableHandleFunction fun) {
4028 UniqueTwoByteChars chars;
4029 if (options.utf8)
4030 chars.reset(
4031 UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length)
4032 .get());
4033 else
4034 chars.reset(InflateString(cx, bytes, length));
4035 if (!chars) return false;
4036
4037 return CompileFunction(cx, envChain, options, name, nargs, argnames,
4038 chars.get(), length, fun);
4039 }
4040
InitScriptSourceElement(JSContext * cx,HandleScript script,HandleObject element,HandleString elementAttrName)4041 JS_PUBLIC_API bool JS::InitScriptSourceElement(JSContext* cx,
4042 HandleScript script,
4043 HandleObject element,
4044 HandleString elementAttrName) {
4045 MOZ_ASSERT(cx);
4046 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
4047
4048 RootedScriptSource sso(cx, &script->sourceObject()->as<ScriptSourceObject>());
4049 return ScriptSourceObject::initElementProperties(cx, sso, element,
4050 elementAttrName);
4051 }
4052
ExposeScriptToDebugger(JSContext * cx,HandleScript script)4053 JS_PUBLIC_API void JS::ExposeScriptToDebugger(JSContext* cx,
4054 HandleScript script) {
4055 MOZ_ASSERT(cx);
4056 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
4057
4058 MOZ_ASSERT(script->hideScriptFromDebugger());
4059 script->clearHideScriptFromDebugger();
4060 Debugger::onNewScript(cx, script);
4061 }
4062
JS_DecompileScript(JSContext * cx,HandleScript script)4063 JS_PUBLIC_API JSString* JS_DecompileScript(JSContext* cx, HandleScript script) {
4064 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4065
4066 AssertHeapIsIdle();
4067 CHECK_REQUEST(cx);
4068 script->ensureNonLazyCanonicalFunction();
4069 RootedFunction fun(cx, script->functionNonDelazifying());
4070 if (fun) return JS_DecompileFunction(cx, fun);
4071 bool haveSource = script->scriptSource()->hasSourceData();
4072 if (!haveSource &&
4073 !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
4074 return nullptr;
4075 return haveSource ? JSScript::sourceData(cx, script)
4076 : NewStringCopyZ<CanGC>(cx, "[no source]");
4077 }
4078
JS_DecompileFunction(JSContext * cx,HandleFunction fun)4079 JS_PUBLIC_API JSString* JS_DecompileFunction(JSContext* cx,
4080 HandleFunction fun) {
4081 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4082 AssertHeapIsIdle();
4083 CHECK_REQUEST(cx);
4084 assertSameCompartment(cx, fun);
4085 return FunctionToString(cx, fun, /* isToSource = */ false);
4086 }
4087
ExecuteScript(JSContext * cx,HandleObject scope,HandleScript script,Value * rval)4088 MOZ_NEVER_INLINE static bool ExecuteScript(JSContext* cx, HandleObject scope,
4089 HandleScript script, Value* rval) {
4090 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4091 AssertHeapIsIdle();
4092 CHECK_REQUEST(cx);
4093 assertSameCompartment(cx, scope, script);
4094 MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(scope),
4095 script->hasNonSyntacticScope());
4096 return Execute(cx, script, *scope, rval);
4097 }
4098
ExecuteScript(JSContext * cx,AutoObjectVector & envChain,HandleScript scriptArg,Value * rval)4099 static bool ExecuteScript(JSContext* cx, AutoObjectVector& envChain,
4100 HandleScript scriptArg, Value* rval) {
4101 RootedObject env(cx);
4102 RootedScope dummy(cx);
4103 if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &dummy))
4104 return false;
4105
4106 RootedScript script(cx, scriptArg);
4107 if (!script->hasNonSyntacticScope() && !IsGlobalLexicalEnvironment(env)) {
4108 script = CloneGlobalScript(cx, ScopeKind::NonSyntactic, script);
4109 if (!script) return false;
4110 js::Debugger::onNewScript(cx, script);
4111 }
4112
4113 return ExecuteScript(cx, env, script, rval);
4114 }
4115
JS_ExecuteScript(JSContext * cx,HandleScript scriptArg,MutableHandleValue rval)4116 MOZ_NEVER_INLINE JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
4117 HandleScript scriptArg,
4118 MutableHandleValue rval) {
4119 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
4120 return ExecuteScript(cx, globalLexical, scriptArg, rval.address());
4121 }
4122
JS_ExecuteScript(JSContext * cx,HandleScript scriptArg)4123 MOZ_NEVER_INLINE JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
4124 HandleScript scriptArg) {
4125 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
4126 return ExecuteScript(cx, globalLexical, scriptArg, nullptr);
4127 }
4128
JS_ExecuteScript(JSContext * cx,AutoObjectVector & envChain,HandleScript scriptArg,MutableHandleValue rval)4129 MOZ_NEVER_INLINE JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
4130 AutoObjectVector& envChain,
4131 HandleScript scriptArg,
4132 MutableHandleValue rval) {
4133 return ExecuteScript(cx, envChain, scriptArg, rval.address());
4134 }
4135
JS_ExecuteScript(JSContext * cx,AutoObjectVector & envChain,HandleScript scriptArg)4136 MOZ_NEVER_INLINE JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
4137 AutoObjectVector& envChain,
4138 HandleScript scriptArg) {
4139 return ExecuteScript(cx, envChain, scriptArg, nullptr);
4140 }
4141
CloneAndExecuteScript(JSContext * cx,HandleScript scriptArg,JS::MutableHandleValue rval)4142 JS_PUBLIC_API bool JS::CloneAndExecuteScript(JSContext* cx,
4143 HandleScript scriptArg,
4144 JS::MutableHandleValue rval) {
4145 CHECK_REQUEST(cx);
4146 RootedScript script(cx, scriptArg);
4147 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
4148 if (script->compartment() != cx->compartment()) {
4149 script = CloneGlobalScript(cx, ScopeKind::Global, script);
4150 if (!script) return false;
4151
4152 js::Debugger::onNewScript(cx, script);
4153 }
4154 return ExecuteScript(cx, globalLexical, script, rval.address());
4155 }
4156
CloneAndExecuteScript(JSContext * cx,JS::AutoObjectVector & envChain,HandleScript scriptArg,JS::MutableHandleValue rval)4157 JS_PUBLIC_API bool JS::CloneAndExecuteScript(JSContext* cx,
4158 JS::AutoObjectVector& envChain,
4159 HandleScript scriptArg,
4160 JS::MutableHandleValue rval) {
4161 CHECK_REQUEST(cx);
4162 RootedScript script(cx, scriptArg);
4163 if (script->compartment() != cx->compartment()) {
4164 script = CloneGlobalScript(cx, ScopeKind::NonSyntactic, script);
4165 if (!script) return false;
4166
4167 js::Debugger::onNewScript(cx, script);
4168 }
4169 return ExecuteScript(cx, envChain, script, rval.address());
4170 }
4171
Evaluate(JSContext * cx,ScopeKind scopeKind,HandleObject env,const ReadOnlyCompileOptions & optionsArg,SourceBufferHolder & srcBuf,MutableHandleValue rval)4172 static bool Evaluate(JSContext* cx, ScopeKind scopeKind, HandleObject env,
4173 const ReadOnlyCompileOptions& optionsArg,
4174 SourceBufferHolder& srcBuf, MutableHandleValue rval) {
4175 CompileOptions options(cx, optionsArg);
4176 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4177 AssertHeapIsIdle();
4178 CHECK_REQUEST(cx);
4179 assertSameCompartment(cx, env);
4180 MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(env),
4181 scopeKind == ScopeKind::NonSyntactic);
4182
4183 options.setIsRunOnce(true);
4184 RootedScript script(
4185 cx, frontend::CompileGlobalScript(cx, cx->tempLifoAlloc(), scopeKind,
4186 options, srcBuf));
4187 if (!script) return false;
4188
4189 bool result = Execute(cx, script, *env,
4190 options.noScriptRval ? nullptr : rval.address());
4191
4192 return result;
4193 }
4194
Evaluate(JSContext * cx,AutoObjectVector & envChain,const ReadOnlyCompileOptions & optionsArg,SourceBufferHolder & srcBuf,MutableHandleValue rval)4195 static bool Evaluate(JSContext* cx, AutoObjectVector& envChain,
4196 const ReadOnlyCompileOptions& optionsArg,
4197 SourceBufferHolder& srcBuf, MutableHandleValue rval) {
4198 RootedObject env(cx);
4199 RootedScope scope(cx);
4200 if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
4201 return false;
4202 return ::Evaluate(cx, scope->kind(), env, optionsArg, srcBuf, rval);
4203 }
4204
Evaluate(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,const char16_t * chars,size_t length,MutableHandleValue rval)4205 static bool Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
4206 const char16_t* chars, size_t length,
4207 MutableHandleValue rval) {
4208 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
4209 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
4210 return ::Evaluate(cx, ScopeKind::Global, globalLexical, optionsArg, srcBuf,
4211 rval);
4212 }
4213
Evaluate(JSContext * cx,const ReadOnlyCompileOptions & options,const char * bytes,size_t length,MutableHandleValue rval)4214 extern JS_PUBLIC_API bool JS::Evaluate(JSContext* cx,
4215 const ReadOnlyCompileOptions& options,
4216 const char* bytes, size_t length,
4217 MutableHandleValue rval) {
4218 char16_t* chars;
4219 if (options.utf8)
4220 chars =
4221 UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(bytes, length), &length)
4222 .get();
4223 else
4224 chars = InflateString(cx, bytes, length);
4225 if (!chars) return false;
4226
4227 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::GiveOwnership);
4228 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
4229 bool ok =
4230 ::Evaluate(cx, ScopeKind::Global, globalLexical, options, srcBuf, rval);
4231 return ok;
4232 }
4233
Evaluate(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,const char * filename,MutableHandleValue rval)4234 static bool Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
4235 const char* filename, MutableHandleValue rval) {
4236 FileContents buffer(cx);
4237 {
4238 AutoFile file;
4239 if (!file.open(cx, filename) || !file.readAll(cx, buffer)) return false;
4240 }
4241
4242 CompileOptions options(cx, optionsArg);
4243 options.setFileAndLine(filename, 1);
4244 return Evaluate(cx, options, buffer.begin(), buffer.length(), rval);
4245 }
4246
Evaluate(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,SourceBufferHolder & srcBuf,MutableHandleValue rval)4247 JS_PUBLIC_API bool JS::Evaluate(JSContext* cx,
4248 const ReadOnlyCompileOptions& optionsArg,
4249 SourceBufferHolder& srcBuf,
4250 MutableHandleValue rval) {
4251 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
4252 return ::Evaluate(cx, ScopeKind::Global, globalLexical, optionsArg, srcBuf,
4253 rval);
4254 }
4255
Evaluate(JSContext * cx,AutoObjectVector & envChain,const ReadOnlyCompileOptions & optionsArg,SourceBufferHolder & srcBuf,MutableHandleValue rval)4256 JS_PUBLIC_API bool JS::Evaluate(JSContext* cx, AutoObjectVector& envChain,
4257 const ReadOnlyCompileOptions& optionsArg,
4258 SourceBufferHolder& srcBuf,
4259 MutableHandleValue rval) {
4260 return ::Evaluate(cx, envChain, optionsArg, srcBuf, rval);
4261 }
4262
Evaluate(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,const char16_t * chars,size_t length,MutableHandleValue rval)4263 JS_PUBLIC_API bool JS::Evaluate(JSContext* cx,
4264 const ReadOnlyCompileOptions& optionsArg,
4265 const char16_t* chars, size_t length,
4266 MutableHandleValue rval) {
4267 return ::Evaluate(cx, optionsArg, chars, length, rval);
4268 }
4269
Evaluate(JSContext * cx,AutoObjectVector & envChain,const ReadOnlyCompileOptions & optionsArg,const char16_t * chars,size_t length,MutableHandleValue rval)4270 JS_PUBLIC_API bool JS::Evaluate(JSContext* cx, AutoObjectVector& envChain,
4271 const ReadOnlyCompileOptions& optionsArg,
4272 const char16_t* chars, size_t length,
4273 MutableHandleValue rval) {
4274 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
4275 return ::Evaluate(cx, envChain, optionsArg, srcBuf, rval);
4276 }
4277
Evaluate(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,const char * filename,MutableHandleValue rval)4278 JS_PUBLIC_API bool JS::Evaluate(JSContext* cx,
4279 const ReadOnlyCompileOptions& optionsArg,
4280 const char* filename, MutableHandleValue rval) {
4281 return ::Evaluate(cx, optionsArg, filename, rval);
4282 }
4283
GetModuleResolveHook(JSContext * cx)4284 JS_PUBLIC_API JSFunction* JS::GetModuleResolveHook(JSContext* cx) {
4285 AssertHeapIsIdle();
4286 CHECK_REQUEST(cx);
4287 return cx->global()->moduleResolveHook();
4288 }
4289
SetModuleResolveHook(JSContext * cx,HandleFunction func)4290 JS_PUBLIC_API void JS::SetModuleResolveHook(JSContext* cx,
4291 HandleFunction func) {
4292 AssertHeapIsIdle();
4293 CHECK_REQUEST(cx);
4294 assertSameCompartment(cx, func);
4295 cx->global()->setModuleResolveHook(func);
4296 }
4297
CompileModule(JSContext * cx,const ReadOnlyCompileOptions & options,SourceBufferHolder & srcBuf,JS::MutableHandleObject module)4298 JS_PUBLIC_API bool JS::CompileModule(JSContext* cx,
4299 const ReadOnlyCompileOptions& options,
4300 SourceBufferHolder& srcBuf,
4301 JS::MutableHandleObject module) {
4302 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4303 AssertHeapIsIdle();
4304 CHECK_REQUEST(cx);
4305
4306 module.set(frontend::CompileModule(cx, options, srcBuf));
4307 return !!module;
4308 }
4309
SetModuleHostDefinedField(JSObject * module,const JS::Value & value)4310 JS_PUBLIC_API void JS::SetModuleHostDefinedField(JSObject* module,
4311 const JS::Value& value) {
4312 module->as<ModuleObject>().setHostDefinedField(value);
4313 }
4314
GetModuleHostDefinedField(JSObject * module)4315 JS_PUBLIC_API JS::Value JS::GetModuleHostDefinedField(JSObject* module) {
4316 return module->as<ModuleObject>().hostDefinedField();
4317 }
4318
ModuleInstantiate(JSContext * cx,JS::HandleObject moduleArg)4319 JS_PUBLIC_API bool JS::ModuleInstantiate(JSContext* cx,
4320 JS::HandleObject moduleArg) {
4321 AssertHeapIsIdle();
4322 CHECK_REQUEST(cx);
4323 releaseAssertSameCompartment(cx, moduleArg);
4324 return ModuleObject::Instantiate(cx, moduleArg.as<ModuleObject>());
4325 }
4326
ModuleEvaluate(JSContext * cx,JS::HandleObject moduleArg)4327 JS_PUBLIC_API bool JS::ModuleEvaluate(JSContext* cx,
4328 JS::HandleObject moduleArg) {
4329 AssertHeapIsIdle();
4330 CHECK_REQUEST(cx);
4331 releaseAssertSameCompartment(cx, moduleArg);
4332 return ModuleObject::Evaluate(cx, moduleArg.as<ModuleObject>());
4333 }
4334
GetRequestedModules(JSContext * cx,JS::HandleObject moduleArg)4335 JS_PUBLIC_API JSObject* JS::GetRequestedModules(JSContext* cx,
4336 JS::HandleObject moduleArg) {
4337 AssertHeapIsIdle();
4338 CHECK_REQUEST(cx);
4339 assertSameCompartment(cx, moduleArg);
4340 return &moduleArg->as<ModuleObject>().requestedModules();
4341 }
4342
GetRequestedModuleSpecifier(JSContext * cx,JS::HandleValue value)4343 JS_PUBLIC_API JSString* JS::GetRequestedModuleSpecifier(JSContext* cx,
4344 JS::HandleValue value) {
4345 AssertHeapIsIdle();
4346 CHECK_REQUEST(cx);
4347 assertSameCompartment(cx, value);
4348 JSObject* obj = &value.toObject();
4349 return obj->as<RequestedModuleObject>().moduleSpecifier();
4350 }
4351
GetRequestedModuleSourcePos(JSContext * cx,JS::HandleValue value,uint32_t * lineNumber,uint32_t * columnNumber)4352 JS_PUBLIC_API void JS::GetRequestedModuleSourcePos(JSContext* cx,
4353 JS::HandleValue value,
4354 uint32_t* lineNumber,
4355 uint32_t* columnNumber) {
4356 AssertHeapIsIdle();
4357 CHECK_REQUEST(cx);
4358 assertSameCompartment(cx, value);
4359 MOZ_ASSERT(lineNumber);
4360 MOZ_ASSERT(columnNumber);
4361 auto& requested = value.toObject().as<RequestedModuleObject>();
4362 *lineNumber = requested.lineNumber();
4363 *columnNumber = requested.columnNumber();
4364 }
4365
GetModuleScript(JS::HandleObject moduleRecord)4366 JS_PUBLIC_API JSScript* JS::GetModuleScript(JS::HandleObject moduleRecord) {
4367 AssertHeapIsIdle();
4368 return moduleRecord->as<ModuleObject>().script();
4369 }
4370
JS_New(JSContext * cx,HandleObject ctor,const JS::HandleValueArray & inputArgs)4371 JS_PUBLIC_API JSObject* JS_New(JSContext* cx, HandleObject ctor,
4372 const JS::HandleValueArray& inputArgs) {
4373 AssertHeapIsIdle();
4374 CHECK_REQUEST(cx);
4375 assertSameCompartment(cx, ctor, inputArgs);
4376
4377 RootedValue ctorVal(cx, ObjectValue(*ctor));
4378 if (!IsConstructor(ctorVal)) {
4379 ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, ctorVal,
4380 nullptr);
4381 return nullptr;
4382 }
4383
4384 ConstructArgs args(cx);
4385 if (!FillArgumentsFromArraylike(cx, args, inputArgs)) return nullptr;
4386
4387 RootedObject obj(cx);
4388 if (!js::Construct(cx, ctorVal, args, ctorVal, &obj)) return nullptr;
4389
4390 return obj;
4391 }
4392
JS_CheckForInterrupt(JSContext * cx)4393 JS_PUBLIC_API bool JS_CheckForInterrupt(JSContext* cx) {
4394 return js::CheckForInterrupt(cx);
4395 }
4396
JS_AddInterruptCallback(JSContext * cx,JSInterruptCallback callback)4397 JS_PUBLIC_API bool JS_AddInterruptCallback(JSContext* cx,
4398 JSInterruptCallback callback) {
4399 return cx->interruptCallbacks().append(callback);
4400 }
4401
JS_DisableInterruptCallback(JSContext * cx)4402 JS_PUBLIC_API bool JS_DisableInterruptCallback(JSContext* cx) {
4403 bool result = cx->interruptCallbackDisabled;
4404 cx->interruptCallbackDisabled = true;
4405 return result;
4406 }
4407
JS_ResetInterruptCallback(JSContext * cx,bool enable)4408 JS_PUBLIC_API void JS_ResetInterruptCallback(JSContext* cx, bool enable) {
4409 cx->interruptCallbackDisabled = enable;
4410 }
4411
4412 /************************************************************************/
4413
4414 /*
4415 * Promises.
4416 */
SetGetIncumbentGlobalCallback(JSContext * cx,JSGetIncumbentGlobalCallback callback)4417 JS_PUBLIC_API void JS::SetGetIncumbentGlobalCallback(
4418 JSContext* cx, JSGetIncumbentGlobalCallback callback) {
4419 cx->getIncumbentGlobalCallback = callback;
4420 }
4421
SetEnqueuePromiseJobCallback(JSContext * cx,JSEnqueuePromiseJobCallback callback,void * data)4422 JS_PUBLIC_API void JS::SetEnqueuePromiseJobCallback(
4423 JSContext* cx, JSEnqueuePromiseJobCallback callback,
4424 void* data /* = nullptr */) {
4425 cx->enqueuePromiseJobCallback = callback;
4426 cx->enqueuePromiseJobCallbackData = data;
4427 }
4428
SetPromiseRejectionTrackerCallback(JSContext * cx,JSPromiseRejectionTrackerCallback callback,void * data)4429 extern JS_PUBLIC_API void JS::SetPromiseRejectionTrackerCallback(
4430 JSContext* cx, JSPromiseRejectionTrackerCallback callback,
4431 void* data /* = nullptr */) {
4432 cx->promiseRejectionTrackerCallback = callback;
4433 cx->promiseRejectionTrackerCallbackData = data;
4434 }
4435
NewPromiseObject(JSContext * cx,HandleObject executor,HandleObject proto)4436 JS_PUBLIC_API JSObject* JS::NewPromiseObject(
4437 JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */) {
4438 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4439 AssertHeapIsIdle();
4440 CHECK_REQUEST(cx);
4441 assertSameCompartment(cx, executor, proto);
4442
4443 if (!executor) return PromiseObject::createSkippingExecutor(cx);
4444
4445 MOZ_ASSERT(IsCallable(executor));
4446 return PromiseObject::create(cx, executor, proto);
4447 }
4448
IsPromiseObject(JS::HandleObject obj)4449 JS_PUBLIC_API bool JS::IsPromiseObject(JS::HandleObject obj) {
4450 return obj->is<PromiseObject>();
4451 }
4452
GetPromiseConstructor(JSContext * cx)4453 JS_PUBLIC_API JSObject* JS::GetPromiseConstructor(JSContext* cx) {
4454 CHECK_REQUEST(cx);
4455 Rooted<GlobalObject*> global(cx, cx->global());
4456 return GlobalObject::getOrCreatePromiseConstructor(cx, global);
4457 }
4458
GetPromisePrototype(JSContext * cx)4459 JS_PUBLIC_API JSObject* JS::GetPromisePrototype(JSContext* cx) {
4460 CHECK_REQUEST(cx);
4461 Rooted<GlobalObject*> global(cx, cx->global());
4462 return GlobalObject::getOrCreatePromisePrototype(cx, global);
4463 }
4464
GetPromiseState(JS::HandleObject promiseObj_)4465 JS_PUBLIC_API JS::PromiseState JS::GetPromiseState(
4466 JS::HandleObject promiseObj_) {
4467 JSObject* promiseObj = CheckedUnwrap(promiseObj_);
4468 if (!promiseObj || !promiseObj->is<PromiseObject>())
4469 return JS::PromiseState::Pending;
4470
4471 return promiseObj->as<PromiseObject>().state();
4472 }
4473
GetPromiseID(JS::HandleObject promise)4474 JS_PUBLIC_API uint64_t JS::GetPromiseID(JS::HandleObject promise) {
4475 return promise->as<PromiseObject>().getID();
4476 }
4477
GetPromiseResult(JS::HandleObject promiseObj)4478 JS_PUBLIC_API JS::Value JS::GetPromiseResult(JS::HandleObject promiseObj) {
4479 PromiseObject* promise = &promiseObj->as<PromiseObject>();
4480 MOZ_ASSERT(promise->state() != JS::PromiseState::Pending);
4481 return promise->state() == JS::PromiseState::Fulfilled ? promise->value()
4482 : promise->reason();
4483 }
4484
GetPromiseAllocationSite(JS::HandleObject promise)4485 JS_PUBLIC_API JSObject* JS::GetPromiseAllocationSite(JS::HandleObject promise) {
4486 return promise->as<PromiseObject>().allocationSite();
4487 }
4488
GetPromiseResolutionSite(JS::HandleObject promise)4489 JS_PUBLIC_API JSObject* JS::GetPromiseResolutionSite(JS::HandleObject promise) {
4490 return promise->as<PromiseObject>().resolutionSite();
4491 }
4492
4493 #ifdef DEBUG
DumpPromiseAllocationSite(JSContext * cx,JS::HandleObject promise)4494 JS_PUBLIC_API void JS::DumpPromiseAllocationSite(JSContext* cx,
4495 JS::HandleObject promise) {
4496 RootedObject stack(cx, promise->as<PromiseObject>().allocationSite());
4497 UniqueChars stackStr(
4498 reinterpret_cast<char*>(BuildUTF8StackString(cx, stack).get()));
4499 if (stackStr.get()) fputs(stackStr.get(), stderr);
4500 }
4501
DumpPromiseResolutionSite(JSContext * cx,JS::HandleObject promise)4502 JS_PUBLIC_API void JS::DumpPromiseResolutionSite(JSContext* cx,
4503 JS::HandleObject promise) {
4504 RootedObject stack(cx, promise->as<PromiseObject>().resolutionSite());
4505 UniqueChars stackStr(
4506 reinterpret_cast<char*>(BuildUTF8StackString(cx, stack).get()));
4507 if (stackStr.get()) fputs(stackStr.get(), stderr);
4508 }
4509 #endif
4510
CallOriginalPromiseResolve(JSContext * cx,JS::HandleValue resolutionValue)4511 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseResolve(
4512 JSContext* cx, JS::HandleValue resolutionValue) {
4513 AssertHeapIsIdle();
4514 CHECK_REQUEST(cx);
4515 assertSameCompartment(cx, resolutionValue);
4516
4517 RootedObject promise(cx,
4518 PromiseObject::unforgeableResolve(cx, resolutionValue));
4519 MOZ_ASSERT_IF(promise, CheckedUnwrap(promise)->is<PromiseObject>());
4520 return promise;
4521 }
4522
CallOriginalPromiseReject(JSContext * cx,JS::HandleValue rejectionValue)4523 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseReject(
4524 JSContext* cx, JS::HandleValue rejectionValue) {
4525 AssertHeapIsIdle();
4526 CHECK_REQUEST(cx);
4527 assertSameCompartment(cx, rejectionValue);
4528
4529 RootedObject promise(cx,
4530 PromiseObject::unforgeableReject(cx, rejectionValue));
4531 MOZ_ASSERT_IF(promise, CheckedUnwrap(promise)->is<PromiseObject>());
4532 return promise;
4533 }
4534
ResolveOrRejectPromise(JSContext * cx,JS::HandleObject promiseObj,JS::HandleValue resultOrReason_,bool reject)4535 static bool ResolveOrRejectPromise(JSContext* cx, JS::HandleObject promiseObj,
4536 JS::HandleValue resultOrReason_,
4537 bool reject) {
4538 AssertHeapIsIdle();
4539 CHECK_REQUEST(cx);
4540 assertSameCompartment(cx, promiseObj, resultOrReason_);
4541
4542 mozilla::Maybe<AutoCompartment> ac;
4543 Rooted<PromiseObject*> promise(cx);
4544 RootedValue resultOrReason(cx, resultOrReason_);
4545 if (IsWrapper(promiseObj)) {
4546 JSObject* unwrappedPromiseObj = CheckedUnwrap(promiseObj);
4547 if (!unwrappedPromiseObj) {
4548 ReportAccessDenied(cx);
4549 return false;
4550 }
4551 promise = &unwrappedPromiseObj->as<PromiseObject>();
4552 ac.emplace(cx, promise);
4553 if (!cx->compartment()->wrap(cx, &resultOrReason)) return false;
4554 } else {
4555 promise = promiseObj.as<PromiseObject>();
4556 }
4557
4558 return reject ? PromiseObject::reject(cx, promise, resultOrReason)
4559 : PromiseObject::resolve(cx, promise, resultOrReason);
4560 }
4561
ResolvePromise(JSContext * cx,JS::HandleObject promiseObj,JS::HandleValue resolutionValue)4562 JS_PUBLIC_API bool JS::ResolvePromise(JSContext* cx,
4563 JS::HandleObject promiseObj,
4564 JS::HandleValue resolutionValue) {
4565 return ResolveOrRejectPromise(cx, promiseObj, resolutionValue, false);
4566 }
4567
RejectPromise(JSContext * cx,JS::HandleObject promiseObj,JS::HandleValue rejectionValue)4568 JS_PUBLIC_API bool JS::RejectPromise(JSContext* cx, JS::HandleObject promiseObj,
4569 JS::HandleValue rejectionValue) {
4570 return ResolveOrRejectPromise(cx, promiseObj, rejectionValue, true);
4571 }
4572
CallOriginalPromiseThenImpl(JSContext * cx,JS::HandleObject promiseObj,JS::HandleObject onResolvedObj_,JS::HandleObject onRejectedObj_,JS::MutableHandleObject resultObj,bool createDependent)4573 static bool CallOriginalPromiseThenImpl(JSContext* cx,
4574 JS::HandleObject promiseObj,
4575 JS::HandleObject onResolvedObj_,
4576 JS::HandleObject onRejectedObj_,
4577 JS::MutableHandleObject resultObj,
4578 bool createDependent) {
4579 AssertHeapIsIdle();
4580 CHECK_REQUEST(cx);
4581 assertSameCompartment(cx, promiseObj, onResolvedObj_, onRejectedObj_);
4582
4583 MOZ_ASSERT_IF(onResolvedObj_, IsCallable(onResolvedObj_));
4584 MOZ_ASSERT_IF(onRejectedObj_, IsCallable(onRejectedObj_));
4585
4586 {
4587 mozilla::Maybe<AutoCompartment> ac;
4588 Rooted<PromiseObject*> promise(cx);
4589 RootedObject onResolvedObj(cx, onResolvedObj_);
4590 RootedObject onRejectedObj(cx, onRejectedObj_);
4591 if (IsWrapper(promiseObj)) {
4592 JSObject* unwrappedPromiseObj = CheckedUnwrap(promiseObj);
4593 if (!unwrappedPromiseObj) {
4594 ReportAccessDenied(cx);
4595 return false;
4596 }
4597 promise = &unwrappedPromiseObj->as<PromiseObject>();
4598 ac.emplace(cx, promise);
4599 if (!cx->compartment()->wrap(cx, &onResolvedObj) ||
4600 !cx->compartment()->wrap(cx, &onRejectedObj)) {
4601 return false;
4602 }
4603 } else {
4604 promise = promiseObj.as<PromiseObject>();
4605 }
4606
4607 RootedValue onFulfilled(cx, ObjectOrNullValue(onResolvedObj));
4608 RootedValue onRejected(cx, ObjectOrNullValue(onRejectedObj));
4609 if (!OriginalPromiseThen(cx, promise, onFulfilled, onRejected, resultObj,
4610 createDependent))
4611 return false;
4612 }
4613
4614 if (resultObj) {
4615 if (!cx->compartment()->wrap(cx, resultObj)) return false;
4616 }
4617 return true;
4618 }
4619
CallOriginalPromiseThen(JSContext * cx,JS::HandleObject promiseObj,JS::HandleObject onResolvedObj,JS::HandleObject onRejectedObj)4620 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseThen(
4621 JSContext* cx, JS::HandleObject promiseObj, JS::HandleObject onResolvedObj,
4622 JS::HandleObject onRejectedObj) {
4623 RootedObject resultPromise(cx);
4624 if (!CallOriginalPromiseThenImpl(cx, promiseObj, onResolvedObj, onRejectedObj,
4625 &resultPromise, true))
4626 return nullptr;
4627 return resultPromise;
4628 }
4629
AddPromiseReactions(JSContext * cx,JS::HandleObject promiseObj,JS::HandleObject onResolvedObj,JS::HandleObject onRejectedObj)4630 JS_PUBLIC_API bool JS::AddPromiseReactions(JSContext* cx,
4631 JS::HandleObject promiseObj,
4632 JS::HandleObject onResolvedObj,
4633 JS::HandleObject onRejectedObj) {
4634 RootedObject resultPromise(cx);
4635 bool result = CallOriginalPromiseThenImpl(
4636 cx, promiseObj, onResolvedObj, onRejectedObj, &resultPromise, false);
4637 MOZ_ASSERT(!resultPromise);
4638 return result;
4639 }
4640
4641 /**
4642 * Unforgeable version of Promise.all for internal use.
4643 *
4644 * Takes a dense array of Promise objects and returns a promise that's
4645 * resolved with an array of resolution values when all those promises ahve
4646 * been resolved, or rejected with the rejection value of the first rejected
4647 * promise.
4648 *
4649 * Asserts that the array is dense and all entries are Promise objects.
4650 */
GetWaitForAllPromise(JSContext * cx,const JS::AutoObjectVector & promises)4651 JS_PUBLIC_API JSObject* JS::GetWaitForAllPromise(
4652 JSContext* cx, const JS::AutoObjectVector& promises) {
4653 AssertHeapIsIdle();
4654 CHECK_REQUEST(cx);
4655
4656 return js::GetWaitForAllPromise(cx, promises);
4657 }
4658
NewReadableDefaultStreamObject(JSContext * cx,JS::HandleObject underlyingSource,JS::HandleFunction size,double highWaterMark,JS::HandleObject proto)4659 JS_PUBLIC_API JSObject* JS::NewReadableDefaultStreamObject(
4660 JSContext* cx, JS::HandleObject underlyingSource /* = nullptr */,
4661 JS::HandleFunction size /* = nullptr */, double highWaterMark /* = 1 */,
4662 JS::HandleObject proto /* = nullptr */) {
4663 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4664 AssertHeapIsIdle();
4665 CHECK_REQUEST(cx);
4666
4667 RootedObject source(cx, underlyingSource);
4668 if (!source) {
4669 source = NewBuiltinClassInstance<PlainObject>(cx);
4670 if (!source) return nullptr;
4671 }
4672 RootedValue sourceVal(cx, ObjectValue(*source));
4673 RootedValue sizeVal(cx, size ? ObjectValue(*size) : UndefinedValue());
4674 RootedValue highWaterMarkVal(cx, NumberValue(highWaterMark));
4675 return ReadableStream::createDefaultStream(cx, sourceVal, sizeVal,
4676 highWaterMarkVal, proto);
4677 }
4678
NewReadableByteStreamObject(JSContext * cx,JS::HandleObject underlyingSource,double highWaterMark,JS::HandleObject proto)4679 JS_PUBLIC_API JSObject* JS::NewReadableByteStreamObject(
4680 JSContext* cx, JS::HandleObject underlyingSource /* = nullptr */,
4681 double highWaterMark /* = 1 */, JS::HandleObject proto /* = nullptr */) {
4682 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4683 AssertHeapIsIdle();
4684 CHECK_REQUEST(cx);
4685
4686 RootedObject source(cx, underlyingSource);
4687 if (!source) {
4688 source = NewBuiltinClassInstance<PlainObject>(cx);
4689 if (!source) return nullptr;
4690 }
4691 RootedValue sourceVal(cx, ObjectValue(*source));
4692 RootedValue highWaterMarkVal(cx, NumberValue(highWaterMark));
4693 return ReadableStream::createByteStream(cx, sourceVal, highWaterMarkVal,
4694 proto);
4695 }
4696
SetReadableStreamCallbacks(JSContext * cx,JS::RequestReadableStreamDataCallback dataRequestCallback,JS::WriteIntoReadRequestBufferCallback writeIntoReadRequestCallback,JS::CancelReadableStreamCallback cancelCallback,JS::ReadableStreamClosedCallback closedCallback,JS::ReadableStreamErroredCallback erroredCallback,JS::ReadableStreamFinalizeCallback finalizeCallback)4697 extern JS_PUBLIC_API void JS::SetReadableStreamCallbacks(
4698 JSContext* cx, JS::RequestReadableStreamDataCallback dataRequestCallback,
4699 JS::WriteIntoReadRequestBufferCallback writeIntoReadRequestCallback,
4700 JS::CancelReadableStreamCallback cancelCallback,
4701 JS::ReadableStreamClosedCallback closedCallback,
4702 JS::ReadableStreamErroredCallback erroredCallback,
4703 JS::ReadableStreamFinalizeCallback finalizeCallback) {
4704 MOZ_ASSERT(dataRequestCallback);
4705 MOZ_ASSERT(writeIntoReadRequestCallback);
4706 MOZ_ASSERT(cancelCallback);
4707 MOZ_ASSERT(closedCallback);
4708 MOZ_ASSERT(erroredCallback);
4709 MOZ_ASSERT(finalizeCallback);
4710
4711 JSRuntime* rt = cx->runtime();
4712
4713 MOZ_ASSERT(!rt->readableStreamDataRequestCallback);
4714 MOZ_ASSERT(!rt->readableStreamWriteIntoReadRequestCallback);
4715 MOZ_ASSERT(!rt->readableStreamCancelCallback);
4716 MOZ_ASSERT(!rt->readableStreamClosedCallback);
4717 MOZ_ASSERT(!rt->readableStreamErroredCallback);
4718 MOZ_ASSERT(!rt->readableStreamFinalizeCallback);
4719
4720 rt->readableStreamDataRequestCallback = dataRequestCallback;
4721 rt->readableStreamWriteIntoReadRequestCallback = writeIntoReadRequestCallback;
4722 rt->readableStreamCancelCallback = cancelCallback;
4723 rt->readableStreamClosedCallback = closedCallback;
4724 rt->readableStreamErroredCallback = erroredCallback;
4725 rt->readableStreamFinalizeCallback = finalizeCallback;
4726 }
4727
HasReadableStreamCallbacks(JSContext * cx)4728 JS_PUBLIC_API bool JS::HasReadableStreamCallbacks(JSContext* cx) {
4729 return cx->runtime()->readableStreamDataRequestCallback;
4730 }
4731
NewReadableExternalSourceStreamObject(JSContext * cx,void * underlyingSource,uint8_t flags,HandleObject proto)4732 JS_PUBLIC_API JSObject* JS::NewReadableExternalSourceStreamObject(
4733 JSContext* cx, void* underlyingSource, uint8_t flags /* = 0 */,
4734 HandleObject proto /* = nullptr */) {
4735 MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4736 AssertHeapIsIdle();
4737 CHECK_REQUEST(cx);
4738
4739 #ifdef DEBUG
4740 JSRuntime* rt = cx->runtime();
4741 MOZ_ASSERT(rt->readableStreamDataRequestCallback);
4742 MOZ_ASSERT(rt->readableStreamWriteIntoReadRequestCallback);
4743 MOZ_ASSERT(rt->readableStreamCancelCallback);
4744 MOZ_ASSERT(rt->readableStreamClosedCallback);
4745 MOZ_ASSERT(rt->readableStreamErroredCallback);
4746 MOZ_ASSERT(rt->readableStreamFinalizeCallback);
4747 #endif // DEBUG
4748
4749 return ReadableStream::createExternalSourceStream(cx, underlyingSource, flags,
4750 proto);
4751 }
4752
4753 JS_PUBLIC_API uint8_t
ReadableStreamGetEmbeddingFlags(const JSObject * stream)4754 JS::ReadableStreamGetEmbeddingFlags(const JSObject* stream) {
4755 return stream->as<ReadableStream>().embeddingFlags();
4756 }
4757
IsReadableStream(const JSObject * obj)4758 JS_PUBLIC_API bool JS::IsReadableStream(const JSObject* obj) {
4759 return obj->is<ReadableStream>();
4760 }
4761
IsReadableStreamReader(const JSObject * obj)4762 JS_PUBLIC_API bool JS::IsReadableStreamReader(const JSObject* obj) {
4763 return obj->is<ReadableStreamDefaultReader>() ||
4764 obj->is<ReadableStreamBYOBReader>();
4765 }
4766
IsReadableStreamDefaultReader(const JSObject * obj)4767 JS_PUBLIC_API bool JS::IsReadableStreamDefaultReader(const JSObject* obj) {
4768 return obj->is<ReadableStreamDefaultReader>();
4769 }
4770
IsReadableStreamBYOBReader(const JSObject * obj)4771 JS_PUBLIC_API bool JS::IsReadableStreamBYOBReader(const JSObject* obj) {
4772 return obj->is<ReadableStreamBYOBReader>();
4773 }
4774
ReadableStreamIsReadable(const JSObject * stream)4775 JS_PUBLIC_API bool JS::ReadableStreamIsReadable(const JSObject* stream) {
4776 return stream->as<ReadableStream>().readable();
4777 }
4778
ReadableStreamIsLocked(const JSObject * stream)4779 JS_PUBLIC_API bool JS::ReadableStreamIsLocked(const JSObject* stream) {
4780 return stream->as<ReadableStream>().locked();
4781 }
4782
ReadableStreamIsDisturbed(const JSObject * stream)4783 JS_PUBLIC_API bool JS::ReadableStreamIsDisturbed(const JSObject* stream) {
4784 return stream->as<ReadableStream>().disturbed();
4785 }
4786
ReadableStreamCancel(JSContext * cx,HandleObject streamObj,HandleValue reason)4787 JS_PUBLIC_API JSObject* JS::ReadableStreamCancel(JSContext* cx,
4788 HandleObject streamObj,
4789 HandleValue reason) {
4790 AssertHeapIsIdle();
4791 CHECK_REQUEST(cx);
4792 assertSameCompartment(cx, streamObj);
4793 assertSameCompartment(cx, reason);
4794
4795 Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
4796 return ReadableStream::cancel(cx, stream, reason);
4797 }
4798
ReadableStreamGetMode(const JSObject * stream)4799 JS_PUBLIC_API JS::ReadableStreamMode JS::ReadableStreamGetMode(
4800 const JSObject* stream) {
4801 return stream->as<ReadableStream>().mode();
4802 }
4803
ReadableStreamGetReader(JSContext * cx,HandleObject streamObj,ReadableStreamReaderMode mode)4804 JS_PUBLIC_API JSObject* JS::ReadableStreamGetReader(
4805 JSContext* cx, HandleObject streamObj, ReadableStreamReaderMode mode) {
4806 AssertHeapIsIdle();
4807 CHECK_REQUEST(cx);
4808 assertSameCompartment(cx, streamObj);
4809
4810 Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
4811 return ReadableStream::getReader(cx, stream, mode);
4812 }
4813
ReadableStreamGetExternalUnderlyingSource(JSContext * cx,HandleObject streamObj,void ** source)4814 JS_PUBLIC_API bool JS::ReadableStreamGetExternalUnderlyingSource(
4815 JSContext* cx, HandleObject streamObj, void** source) {
4816 AssertHeapIsIdle();
4817 CHECK_REQUEST(cx);
4818 assertSameCompartment(cx, streamObj);
4819
4820 Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
4821 return ReadableStream::getExternalSource(cx, stream, source);
4822 }
4823
ReadableStreamReleaseExternalUnderlyingSource(JSObject * stream)4824 JS_PUBLIC_API void JS::ReadableStreamReleaseExternalUnderlyingSource(
4825 JSObject* stream) {
4826 stream->as<ReadableStream>().releaseExternalSource();
4827 }
4828
ReadableStreamUpdateDataAvailableFromSource(JSContext * cx,JS::HandleObject streamObj,uint32_t availableData)4829 JS_PUBLIC_API bool JS::ReadableStreamUpdateDataAvailableFromSource(
4830 JSContext* cx, JS::HandleObject streamObj, uint32_t availableData) {
4831 AssertHeapIsIdle();
4832 CHECK_REQUEST(cx);
4833 assertSameCompartment(cx, streamObj);
4834
4835 Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
4836 return ReadableStream::updateDataAvailableFromSource(cx, stream,
4837 availableData);
4838 }
4839
ReadableStreamTee(JSContext * cx,HandleObject streamObj,MutableHandleObject branch1Obj,MutableHandleObject branch2Obj)4840 JS_PUBLIC_API bool JS::ReadableStreamTee(JSContext* cx, HandleObject streamObj,
4841 MutableHandleObject branch1Obj,
4842 MutableHandleObject branch2Obj) {
4843 AssertHeapIsIdle();
4844 CHECK_REQUEST(cx);
4845 assertSameCompartment(cx, streamObj);
4846
4847 Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
4848 Rooted<ReadableStream*> branch1Stream(cx);
4849 Rooted<ReadableStream*> branch2Stream(cx);
4850
4851 if (!ReadableStream::tee(cx, stream, false, &branch1Stream, &branch2Stream))
4852 return false;
4853
4854 branch1Obj.set(branch1Stream);
4855 branch2Obj.set(branch2Stream);
4856
4857 return true;
4858 }
4859
ReadableStreamGetDesiredSize(JSObject * streamObj,bool * hasValue,double * value)4860 JS_PUBLIC_API void JS::ReadableStreamGetDesiredSize(JSObject* streamObj,
4861 bool* hasValue,
4862 double* value) {
4863 streamObj->as<ReadableStream>().desiredSize(hasValue, value);
4864 }
4865
ReadableStreamClose(JSContext * cx,HandleObject streamObj)4866 JS_PUBLIC_API bool JS::ReadableStreamClose(JSContext* cx,
4867 HandleObject streamObj) {
4868 AssertHeapIsIdle();
4869 CHECK_REQUEST(cx);
4870 assertSameCompartment(cx, streamObj);
4871
4872 Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
4873 return ReadableStream::close(cx, stream);
4874 }
4875
ReadableStreamEnqueue(JSContext * cx,HandleObject streamObj,HandleValue chunk)4876 JS_PUBLIC_API bool JS::ReadableStreamEnqueue(JSContext* cx,
4877 HandleObject streamObj,
4878 HandleValue chunk) {
4879 AssertHeapIsIdle();
4880 CHECK_REQUEST(cx);
4881 assertSameCompartment(cx, streamObj);
4882 assertSameCompartment(cx, chunk);
4883
4884 Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
4885 if (stream->mode() != JS::ReadableStreamMode::Default) {
4886 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
4887 JSMSG_READABLESTREAM_NOT_DEFAULT_CONTROLLER,
4888 "JS::ReadableStreamEnqueue");
4889 return false;
4890 }
4891 return ReadableStream::enqueue(cx, stream, chunk);
4892 }
4893
ReadableByteStreamEnqueueBuffer(JSContext * cx,HandleObject streamObj,HandleObject chunkObj)4894 JS_PUBLIC_API bool JS::ReadableByteStreamEnqueueBuffer(JSContext* cx,
4895 HandleObject streamObj,
4896 HandleObject chunkObj) {
4897 AssertHeapIsIdle();
4898 CHECK_REQUEST(cx);
4899 assertSameCompartment(cx, streamObj);
4900 assertSameCompartment(cx, chunkObj);
4901
4902 Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
4903 if (stream->mode() != JS::ReadableStreamMode::Byte) {
4904 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
4905 JSMSG_READABLESTREAM_NOT_BYTE_STREAM_CONTROLLER,
4906 "JS::ReadableByteStreamEnqueueBuffer");
4907 return false;
4908 }
4909
4910 Rooted<ArrayBufferObject*> buffer(cx);
4911 if (chunkObj->is<ArrayBufferViewObject>()) {
4912 bool dummy;
4913 buffer = &JS_GetArrayBufferViewBuffer(cx, chunkObj, &dummy)
4914 ->as<ArrayBufferObject>();
4915 } else if (chunkObj->is<ArrayBufferObject>()) {
4916 buffer = &chunkObj->as<ArrayBufferObject>();
4917 } else {
4918 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
4919 JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNK,
4920 "JS::ReadableByteStreamEnqueueBuffer");
4921 return false;
4922 }
4923
4924 return ReadableStream::enqueueBuffer(cx, stream, buffer);
4925 }
4926
ReadableStreamError(JSContext * cx,HandleObject streamObj,HandleValue error)4927 JS_PUBLIC_API bool JS::ReadableStreamError(JSContext* cx,
4928 HandleObject streamObj,
4929 HandleValue error) {
4930 AssertHeapIsIdle();
4931 CHECK_REQUEST(cx);
4932 assertSameCompartment(cx, streamObj);
4933 assertSameCompartment(cx, error);
4934
4935 Rooted<ReadableStream*> stream(cx, &streamObj->as<ReadableStream>());
4936 return js::ReadableStream::error(cx, stream, error);
4937 }
4938
ReadableStreamReaderIsClosed(const JSObject * reader)4939 JS_PUBLIC_API bool JS::ReadableStreamReaderIsClosed(const JSObject* reader) {
4940 return js::ReadableStreamReaderIsClosed(reader);
4941 }
4942
ReadableStreamReaderCancel(JSContext * cx,HandleObject reader,HandleValue reason)4943 JS_PUBLIC_API bool JS::ReadableStreamReaderCancel(JSContext* cx,
4944 HandleObject reader,
4945 HandleValue reason) {
4946 AssertHeapIsIdle();
4947 CHECK_REQUEST(cx);
4948 assertSameCompartment(cx, reader);
4949 assertSameCompartment(cx, reason);
4950
4951 return js::ReadableStreamReaderCancel(cx, reader, reason);
4952 }
4953
ReadableStreamReaderReleaseLock(JSContext * cx,HandleObject reader)4954 JS_PUBLIC_API bool JS::ReadableStreamReaderReleaseLock(JSContext* cx,
4955 HandleObject reader) {
4956 AssertHeapIsIdle();
4957 CHECK_REQUEST(cx);
4958 assertSameCompartment(cx, reader);
4959
4960 return js::ReadableStreamReaderReleaseLock(cx, reader);
4961 }
4962
ReadableStreamDefaultReaderRead(JSContext * cx,HandleObject readerObj)4963 JS_PUBLIC_API JSObject* JS::ReadableStreamDefaultReaderRead(
4964 JSContext* cx, HandleObject readerObj) {
4965 AssertHeapIsIdle();
4966 CHECK_REQUEST(cx);
4967 assertSameCompartment(cx, readerObj);
4968
4969 Rooted<ReadableStreamDefaultReader*> reader(
4970 cx, &readerObj->as<ReadableStreamDefaultReader>());
4971 return js::ReadableStreamDefaultReader::read(cx, reader);
4972 }
4973
ReadableStreamBYOBReaderRead(JSContext * cx,HandleObject readerObj,HandleObject viewObj)4974 JS_PUBLIC_API JSObject* JS::ReadableStreamBYOBReaderRead(JSContext* cx,
4975 HandleObject readerObj,
4976 HandleObject viewObj) {
4977 AssertHeapIsIdle();
4978 CHECK_REQUEST(cx);
4979 assertSameCompartment(cx, readerObj);
4980 assertSameCompartment(cx, viewObj);
4981
4982 Rooted<ReadableStreamBYOBReader*> reader(
4983 cx, &readerObj->as<ReadableStreamBYOBReader>());
4984 Rooted<ArrayBufferViewObject*> view(cx,
4985 &viewObj->as<ArrayBufferViewObject>());
4986 return js::ReadableStreamBYOBReader::read(cx, reader, view);
4987 }
4988
InitDispatchToEventLoop(JSContext * cx,JS::DispatchToEventLoopCallback callback,void * closure)4989 JS_PUBLIC_API void JS::InitDispatchToEventLoop(
4990 JSContext* cx, JS::DispatchToEventLoopCallback callback, void* closure) {
4991 cx->runtime()->offThreadPromiseState.ref().init(callback, closure);
4992 }
4993
ShutdownAsyncTasks(JSContext * cx)4994 JS_PUBLIC_API void JS::ShutdownAsyncTasks(JSContext* cx) {
4995 cx->runtime()->offThreadPromiseState.ref().shutdown(cx);
4996 }
4997
InitConsumeStreamCallback(JSContext * cx,ConsumeStreamCallback callback)4998 JS_PUBLIC_API void JS::InitConsumeStreamCallback(
4999 JSContext* cx, ConsumeStreamCallback callback) {
5000 cx->runtime()->consumeStreamCallback = callback;
5001 }
5002
JS_RequestInterruptCallback(JSContext * cx)5003 JS_PUBLIC_API void JS_RequestInterruptCallback(JSContext* cx) {
5004 cx->requestInterrupt(JSContext::RequestInterruptUrgent);
5005 }
5006
JS_RequestInterruptCallbackCanWait(JSContext * cx)5007 JS_PUBLIC_API void JS_RequestInterruptCallbackCanWait(JSContext* cx) {
5008 cx->requestInterrupt(JSContext::RequestInterruptCanWait);
5009 }
5010
AutoSetAsyncStackForNewCalls(JSContext * cx,HandleObject stack,const char * asyncCause,JS::AutoSetAsyncStackForNewCalls::AsyncCallKind kind)5011 JS::AutoSetAsyncStackForNewCalls::AutoSetAsyncStackForNewCalls(
5012 JSContext* cx, HandleObject stack, const char* asyncCause,
5013 JS::AutoSetAsyncStackForNewCalls::AsyncCallKind kind)
5014 : cx(cx),
5015 oldAsyncStack(cx, cx->asyncStackForNewActivations()),
5016 oldAsyncCause(cx->asyncCauseForNewActivations),
5017 oldAsyncCallIsExplicit(cx->asyncCallIsExplicit) {
5018 CHECK_REQUEST(cx);
5019
5020 // The option determines whether we actually use the new values at this
5021 // point. It will not affect restoring the previous values when the object
5022 // is destroyed, so if the option changes it won't cause consistency issues.
5023 if (!cx->options().asyncStack()) return;
5024
5025 SavedFrame* asyncStack = &stack->as<SavedFrame>();
5026
5027 cx->asyncStackForNewActivations() = asyncStack;
5028 cx->asyncCauseForNewActivations = asyncCause;
5029 cx->asyncCallIsExplicit = kind == AsyncCallKind::EXPLICIT;
5030 }
5031
~AutoSetAsyncStackForNewCalls()5032 JS::AutoSetAsyncStackForNewCalls::~AutoSetAsyncStackForNewCalls() {
5033 cx->asyncCauseForNewActivations = oldAsyncCause;
5034 cx->asyncStackForNewActivations() =
5035 oldAsyncStack ? &oldAsyncStack->as<SavedFrame>() : nullptr;
5036 cx->asyncCallIsExplicit = oldAsyncCallIsExplicit;
5037 }
5038
5039 /************************************************************************/
JS_NewStringCopyN(JSContext * cx,const char * s,size_t n)5040 JS_PUBLIC_API JSString* JS_NewStringCopyN(JSContext* cx, const char* s,
5041 size_t n) {
5042 AssertHeapIsIdle();
5043 CHECK_REQUEST(cx);
5044 return NewStringCopyN<CanGC>(cx, s, n);
5045 }
5046
JS_NewStringCopyZ(JSContext * cx,const char * s)5047 JS_PUBLIC_API JSString* JS_NewStringCopyZ(JSContext* cx, const char* s) {
5048 AssertHeapIsIdle();
5049 CHECK_REQUEST(cx);
5050 if (!s) return cx->runtime()->emptyString;
5051 return NewStringCopyZ<CanGC>(cx, s);
5052 }
5053
JS_NewStringCopyUTF8Z(JSContext * cx,const JS::ConstUTF8CharsZ s)5054 JS_PUBLIC_API JSString* JS_NewStringCopyUTF8Z(JSContext* cx,
5055 const JS::ConstUTF8CharsZ s) {
5056 AssertHeapIsIdle();
5057 CHECK_REQUEST(cx);
5058 return NewStringCopyUTF8Z<CanGC>(cx, s);
5059 }
5060
JS_NewStringCopyUTF8N(JSContext * cx,const JS::UTF8Chars s)5061 JS_PUBLIC_API JSString* JS_NewStringCopyUTF8N(JSContext* cx,
5062 const JS::UTF8Chars s) {
5063 AssertHeapIsIdle();
5064 CHECK_REQUEST(cx);
5065 return NewStringCopyUTF8N<CanGC>(cx, s);
5066 }
5067
JS_StringHasBeenPinned(JSContext * cx,JSString * str)5068 JS_PUBLIC_API bool JS_StringHasBeenPinned(JSContext* cx, JSString* str) {
5069 AssertHeapIsIdle();
5070 CHECK_REQUEST(cx);
5071
5072 if (!str->isAtom()) return false;
5073
5074 return AtomIsPinned(cx, &str->asAtom());
5075 }
5076
INTERNED_STRING_TO_JSID(JSContext * cx,JSString * str)5077 JS_PUBLIC_API jsid INTERNED_STRING_TO_JSID(JSContext* cx, JSString* str) {
5078 MOZ_ASSERT(str);
5079 MOZ_ASSERT(((size_t)str & JSID_TYPE_MASK) == 0);
5080 MOZ_ASSERT_IF(cx, JS_StringHasBeenPinned(cx, str));
5081 return AtomToId(&str->asAtom());
5082 }
5083
JS_AtomizeAndPinJSString(JSContext * cx,HandleString str)5084 JS_PUBLIC_API JSString* JS_AtomizeAndPinJSString(JSContext* cx,
5085 HandleString str) {
5086 AssertHeapIsIdle();
5087 CHECK_REQUEST(cx);
5088 JSAtom* atom = AtomizeString(cx, str, PinAtom);
5089 MOZ_ASSERT_IF(atom, JS_StringHasBeenPinned(cx, atom));
5090 return atom;
5091 }
5092
JS_AtomizeString(JSContext * cx,const char * s)5093 JS_PUBLIC_API JSString* JS_AtomizeString(JSContext* cx, const char* s) {
5094 return JS_AtomizeStringN(cx, s, strlen(s));
5095 }
5096
JS_AtomizeStringN(JSContext * cx,const char * s,size_t length)5097 JS_PUBLIC_API JSString* JS_AtomizeStringN(JSContext* cx, const char* s,
5098 size_t length) {
5099 AssertHeapIsIdle();
5100 CHECK_REQUEST(cx);
5101 return Atomize(cx, s, length, DoNotPinAtom);
5102 }
5103
JS_AtomizeAndPinString(JSContext * cx,const char * s)5104 JS_PUBLIC_API JSString* JS_AtomizeAndPinString(JSContext* cx, const char* s) {
5105 return JS_AtomizeAndPinStringN(cx, s, strlen(s));
5106 }
5107
JS_AtomizeAndPinStringN(JSContext * cx,const char * s,size_t length)5108 JS_PUBLIC_API JSString* JS_AtomizeAndPinStringN(JSContext* cx, const char* s,
5109 size_t length) {
5110 AssertHeapIsIdle();
5111 CHECK_REQUEST(cx);
5112 JSAtom* atom = Atomize(cx, s, length, PinAtom);
5113 MOZ_ASSERT_IF(atom, JS_StringHasBeenPinned(cx, atom));
5114 return atom;
5115 }
5116
JS_NewLatin1String(JSContext * cx,JS::Latin1Char * chars,size_t length)5117 JS_PUBLIC_API JSString* JS_NewLatin1String(JSContext* cx, JS::Latin1Char* chars,
5118 size_t length) {
5119 AssertHeapIsIdle();
5120 CHECK_REQUEST(cx);
5121 return NewString<CanGC>(cx, chars, length);
5122 }
5123
JS_NewUCString(JSContext * cx,char16_t * chars,size_t length)5124 JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx, char16_t* chars,
5125 size_t length) {
5126 AssertHeapIsIdle();
5127 CHECK_REQUEST(cx);
5128 return NewString<CanGC>(cx, chars, length);
5129 }
5130
JS_NewUCStringCopyN(JSContext * cx,const char16_t * s,size_t n)5131 JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx, const char16_t* s,
5132 size_t n) {
5133 AssertHeapIsIdle();
5134 CHECK_REQUEST(cx);
5135 if (!n) return cx->names().empty;
5136 return NewStringCopyN<CanGC>(cx, s, n);
5137 }
5138
JS_NewUCStringCopyZ(JSContext * cx,const char16_t * s)5139 JS_PUBLIC_API JSString* JS_NewUCStringCopyZ(JSContext* cx, const char16_t* s) {
5140 AssertHeapIsIdle();
5141 CHECK_REQUEST(cx);
5142 if (!s) return cx->runtime()->emptyString;
5143 return NewStringCopyZ<CanGC>(cx, s);
5144 }
5145
JS_AtomizeUCString(JSContext * cx,const char16_t * s)5146 JS_PUBLIC_API JSString* JS_AtomizeUCString(JSContext* cx, const char16_t* s) {
5147 return JS_AtomizeUCStringN(cx, s, js_strlen(s));
5148 }
5149
JS_AtomizeUCStringN(JSContext * cx,const char16_t * s,size_t length)5150 JS_PUBLIC_API JSString* JS_AtomizeUCStringN(JSContext* cx, const char16_t* s,
5151 size_t length) {
5152 AssertHeapIsIdle();
5153 CHECK_REQUEST(cx);
5154 return AtomizeChars(cx, s, length, DoNotPinAtom);
5155 }
5156
JS_AtomizeAndPinUCStringN(JSContext * cx,const char16_t * s,size_t length)5157 JS_PUBLIC_API JSString* JS_AtomizeAndPinUCStringN(JSContext* cx,
5158 const char16_t* s,
5159 size_t length) {
5160 AssertHeapIsIdle();
5161 CHECK_REQUEST(cx);
5162 JSAtom* atom = AtomizeChars(cx, s, length, PinAtom);
5163 MOZ_ASSERT_IF(atom, JS_StringHasBeenPinned(cx, atom));
5164 return atom;
5165 }
5166
JS_AtomizeAndPinUCString(JSContext * cx,const char16_t * s)5167 JS_PUBLIC_API JSString* JS_AtomizeAndPinUCString(JSContext* cx,
5168 const char16_t* s) {
5169 return JS_AtomizeAndPinUCStringN(cx, s, js_strlen(s));
5170 }
5171
JS_GetStringLength(JSString * str)5172 JS_PUBLIC_API size_t JS_GetStringLength(JSString* str) { return str->length(); }
5173
JS_StringIsFlat(JSString * str)5174 JS_PUBLIC_API bool JS_StringIsFlat(JSString* str) { return str->isFlat(); }
5175
JS_StringHasLatin1Chars(JSString * str)5176 JS_PUBLIC_API bool JS_StringHasLatin1Chars(JSString* str) {
5177 return str->hasLatin1Chars();
5178 }
5179
JS_GetLatin1StringCharsAndLength(JSContext * cx,const JS::AutoRequireNoGC & nogc,JSString * str,size_t * plength)5180 JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength(
5181 JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str,
5182 size_t* plength) {
5183 MOZ_ASSERT(plength);
5184 AssertHeapIsIdleOrStringIsFlat(str);
5185 CHECK_REQUEST(cx);
5186 assertSameCompartment(cx, str);
5187 JSLinearString* linear = str->ensureLinear(cx);
5188 if (!linear) return nullptr;
5189 *plength = linear->length();
5190 return linear->latin1Chars(nogc);
5191 }
5192
JS_GetTwoByteStringCharsAndLength(JSContext * cx,const JS::AutoRequireNoGC & nogc,JSString * str,size_t * plength)5193 JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength(
5194 JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str,
5195 size_t* plength) {
5196 MOZ_ASSERT(plength);
5197 AssertHeapIsIdleOrStringIsFlat(str);
5198 CHECK_REQUEST(cx);
5199 assertSameCompartment(cx, str);
5200 JSLinearString* linear = str->ensureLinear(cx);
5201 if (!linear) return nullptr;
5202 *plength = linear->length();
5203 return linear->twoByteChars(nogc);
5204 }
5205
JS_GetTwoByteExternalStringChars(JSString * str)5206 JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars(JSString* str) {
5207 return str->asExternal().twoByteChars();
5208 }
5209
JS_GetStringCharAt(JSContext * cx,JSString * str,size_t index,char16_t * res)5210 JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str,
5211 size_t index, char16_t* res) {
5212 AssertHeapIsIdleOrStringIsFlat(str);
5213 CHECK_REQUEST(cx);
5214 assertSameCompartment(cx, str);
5215
5216 JSLinearString* linear = str->ensureLinear(cx);
5217 if (!linear) return false;
5218
5219 *res = linear->latin1OrTwoByteChar(index);
5220 return true;
5221 }
5222
JS_GetFlatStringCharAt(JSFlatString * str,size_t index)5223 JS_PUBLIC_API char16_t JS_GetFlatStringCharAt(JSFlatString* str, size_t index) {
5224 return str->latin1OrTwoByteChar(index);
5225 }
5226
JS_CopyStringChars(JSContext * cx,mozilla::Range<char16_t> dest,JSString * str)5227 JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx,
5228 mozilla::Range<char16_t> dest,
5229 JSString* str) {
5230 AssertHeapIsIdleOrStringIsFlat(str);
5231 CHECK_REQUEST(cx);
5232 assertSameCompartment(cx, str);
5233
5234 JSLinearString* linear = str->ensureLinear(cx);
5235 if (!linear) return false;
5236
5237 MOZ_ASSERT(linear->length() <= dest.length());
5238 CopyChars(dest.begin().get(), *linear);
5239 return true;
5240 }
5241
JS_GetLatin1InternedStringChars(const JS::AutoRequireNoGC & nogc,JSString * str)5242 JS_PUBLIC_API const Latin1Char* JS_GetLatin1InternedStringChars(
5243 const JS::AutoRequireNoGC& nogc, JSString* str) {
5244 MOZ_ASSERT(str->isAtom());
5245 JSFlatString* flat = str->ensureFlat(nullptr);
5246 if (!flat) return nullptr;
5247 return flat->latin1Chars(nogc);
5248 }
5249
JS_GetTwoByteInternedStringChars(const JS::AutoRequireNoGC & nogc,JSString * str)5250 JS_PUBLIC_API const char16_t* JS_GetTwoByteInternedStringChars(
5251 const JS::AutoRequireNoGC& nogc, JSString* str) {
5252 MOZ_ASSERT(str->isAtom());
5253 JSFlatString* flat = str->ensureFlat(nullptr);
5254 if (!flat) return nullptr;
5255 return flat->twoByteChars(nogc);
5256 }
5257
JS_FlattenString(JSContext * cx,JSString * str)5258 extern JS_PUBLIC_API JSFlatString* JS_FlattenString(JSContext* cx,
5259 JSString* str) {
5260 AssertHeapIsIdle();
5261 CHECK_REQUEST(cx);
5262 assertSameCompartment(cx, str);
5263 JSFlatString* flat = str->ensureFlat(cx);
5264 if (!flat) return nullptr;
5265 return flat;
5266 }
5267
JS_GetLatin1FlatStringChars(const JS::AutoRequireNoGC & nogc,JSFlatString * str)5268 extern JS_PUBLIC_API const Latin1Char* JS_GetLatin1FlatStringChars(
5269 const JS::AutoRequireNoGC& nogc, JSFlatString* str) {
5270 return str->latin1Chars(nogc);
5271 }
5272
JS_GetTwoByteFlatStringChars(const JS::AutoRequireNoGC & nogc,JSFlatString * str)5273 extern JS_PUBLIC_API const char16_t* JS_GetTwoByteFlatStringChars(
5274 const JS::AutoRequireNoGC& nogc, JSFlatString* str) {
5275 return str->twoByteChars(nogc);
5276 }
5277
JS_CompareStrings(JSContext * cx,JSString * str1,JSString * str2,int32_t * result)5278 JS_PUBLIC_API bool JS_CompareStrings(JSContext* cx, JSString* str1,
5279 JSString* str2, int32_t* result) {
5280 AssertHeapIsIdle();
5281 CHECK_REQUEST(cx);
5282
5283 return CompareStrings(cx, str1, str2, result);
5284 }
5285
JS_StringEqualsAscii(JSContext * cx,JSString * str,const char * asciiBytes,bool * match)5286 JS_PUBLIC_API bool JS_StringEqualsAscii(JSContext* cx, JSString* str,
5287 const char* asciiBytes, bool* match) {
5288 AssertHeapIsIdle();
5289 CHECK_REQUEST(cx);
5290
5291 JSLinearString* linearStr = str->ensureLinear(cx);
5292 if (!linearStr) return false;
5293 *match = StringEqualsAscii(linearStr, asciiBytes);
5294 return true;
5295 }
5296
JS_FlatStringEqualsAscii(JSFlatString * str,const char * asciiBytes)5297 JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str,
5298 const char* asciiBytes) {
5299 return StringEqualsAscii(str, asciiBytes);
5300 }
5301
JS_PutEscapedFlatString(char * buffer,size_t size,JSFlatString * str,char quote)5302 JS_PUBLIC_API size_t JS_PutEscapedFlatString(char* buffer, size_t size,
5303 JSFlatString* str, char quote) {
5304 return PutEscapedString(buffer, size, str, quote);
5305 }
5306
JS_PutEscapedString(JSContext * cx,char * buffer,size_t size,JSString * str,char quote)5307 JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer,
5308 size_t size, JSString* str,
5309 char quote) {
5310 AssertHeapIsIdle();
5311 JSLinearString* linearStr = str->ensureLinear(cx);
5312 if (!linearStr) return size_t(-1);
5313 return PutEscapedString(buffer, size, linearStr, quote);
5314 }
5315
JS_FileEscapedString(FILE * fp,JSString * str,char quote)5316 JS_PUBLIC_API bool JS_FileEscapedString(FILE* fp, JSString* str, char quote) {
5317 JSLinearString* linearStr = str->ensureLinear(nullptr);
5318 return linearStr && FileEscapedString(fp, linearStr, quote);
5319 }
5320
JS_NewDependentString(JSContext * cx,HandleString str,size_t start,size_t length)5321 JS_PUBLIC_API JSString* JS_NewDependentString(JSContext* cx, HandleString str,
5322 size_t start, size_t length) {
5323 AssertHeapIsIdle();
5324 CHECK_REQUEST(cx);
5325 return NewDependentString(cx, str, start, length);
5326 }
5327
JS_ConcatStrings(JSContext * cx,HandleString left,HandleString right)5328 JS_PUBLIC_API JSString* JS_ConcatStrings(JSContext* cx, HandleString left,
5329 HandleString right) {
5330 AssertHeapIsIdle();
5331 CHECK_REQUEST(cx);
5332 return ConcatStrings<CanGC>(cx, left, right);
5333 }
5334
JS_DecodeBytes(JSContext * cx,const char * src,size_t srclen,char16_t * dst,size_t * dstlenp)5335 JS_PUBLIC_API bool JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen,
5336 char16_t* dst, size_t* dstlenp) {
5337 AssertHeapIsIdle();
5338 CHECK_REQUEST(cx);
5339
5340 if (!dst) {
5341 *dstlenp = srclen;
5342 return true;
5343 }
5344
5345 size_t dstlen = *dstlenp;
5346
5347 if (srclen > dstlen) {
5348 CopyAndInflateChars(dst, src, dstlen);
5349
5350 AutoSuppressGC suppress(cx);
5351 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5352 JSMSG_BUFFER_TOO_SMALL);
5353 return false;
5354 }
5355
5356 CopyAndInflateChars(dst, src, srclen);
5357 *dstlenp = srclen;
5358 return true;
5359 }
5360
EncodeLatin1(JSContext * cx,JSString * str)5361 static char* EncodeLatin1(JSContext* cx, JSString* str) {
5362 JSLinearString* linear = str->ensureLinear(cx);
5363 if (!linear) return nullptr;
5364
5365 JS::AutoCheckCannotGC nogc;
5366 if (linear->hasTwoByteChars())
5367 return JS::LossyTwoByteCharsToNewLatin1CharsZ(cx,
5368 linear->twoByteRange(nogc))
5369 .c_str();
5370
5371 size_t len = str->length();
5372 Latin1Char* buf = cx->pod_malloc<Latin1Char>(len + 1);
5373 if (!buf) {
5374 ReportOutOfMemory(cx);
5375 return nullptr;
5376 }
5377
5378 mozilla::PodCopy(buf, linear->latin1Chars(nogc), len);
5379 buf[len] = '\0';
5380 return reinterpret_cast<char*>(buf);
5381 }
5382
JS_EncodeString(JSContext * cx,JSString * str)5383 JS_PUBLIC_API char* JS_EncodeString(JSContext* cx, JSString* str) {
5384 AssertHeapIsIdle();
5385 CHECK_REQUEST(cx);
5386
5387 return EncodeLatin1(cx, str);
5388 }
5389
JS_EncodeStringToUTF8(JSContext * cx,HandleString str)5390 JS_PUBLIC_API char* JS_EncodeStringToUTF8(JSContext* cx, HandleString str) {
5391 AssertHeapIsIdle();
5392 CHECK_REQUEST(cx);
5393
5394 return StringToNewUTF8CharsZ(cx, *str).release();
5395 }
5396
JS_GetStringEncodingLength(JSContext * cx,JSString * str)5397 JS_PUBLIC_API size_t JS_GetStringEncodingLength(JSContext* cx, JSString* str) {
5398 AssertHeapIsIdle();
5399 CHECK_REQUEST(cx);
5400
5401 if (!str->ensureLinear(cx)) return size_t(-1);
5402 return str->length();
5403 }
5404
JS_EncodeStringToBuffer(JSContext * cx,JSString * str,char * buffer,size_t length)5405 JS_PUBLIC_API size_t JS_EncodeStringToBuffer(JSContext* cx, JSString* str,
5406 char* buffer, size_t length) {
5407 AssertHeapIsIdle();
5408 CHECK_REQUEST(cx);
5409
5410 /*
5411 * FIXME bug 612141 - fix DeflateStringToBuffer interface so the result
5412 * would allow to distinguish between insufficient buffer and encoding
5413 * error.
5414 */
5415 size_t writtenLength = length;
5416 JSLinearString* linear = str->ensureLinear(cx);
5417 if (!linear) return size_t(-1);
5418
5419 bool res;
5420 if (linear->hasLatin1Chars()) {
5421 JS::AutoCheckCannotGC nogc;
5422 res = DeflateStringToBuffer(nullptr, linear->latin1Chars(nogc),
5423 linear->length(), buffer, &writtenLength);
5424 } else {
5425 JS::AutoCheckCannotGC nogc;
5426 res = DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc),
5427 linear->length(), buffer, &writtenLength);
5428 }
5429 if (res) {
5430 MOZ_ASSERT(writtenLength <= length);
5431 return writtenLength;
5432 }
5433 MOZ_ASSERT(writtenLength <= length);
5434 size_t necessaryLength = str->length();
5435 if (necessaryLength == size_t(-1)) return size_t(-1);
5436 MOZ_ASSERT(writtenLength == length); // C strings are NOT encoded.
5437 return necessaryLength;
5438 }
5439
NewSymbol(JSContext * cx,HandleString description)5440 JS_PUBLIC_API JS::Symbol* JS::NewSymbol(JSContext* cx,
5441 HandleString description) {
5442 AssertHeapIsIdle();
5443 CHECK_REQUEST(cx);
5444 if (description) assertSameCompartment(cx, description);
5445
5446 return Symbol::new_(cx, SymbolCode::UniqueSymbol, description);
5447 }
5448
GetSymbolFor(JSContext * cx,HandleString key)5449 JS_PUBLIC_API JS::Symbol* JS::GetSymbolFor(JSContext* cx, HandleString key) {
5450 AssertHeapIsIdle();
5451 CHECK_REQUEST(cx);
5452 assertSameCompartment(cx, key);
5453
5454 return Symbol::for_(cx, key);
5455 }
5456
GetSymbolDescription(HandleSymbol symbol)5457 JS_PUBLIC_API JSString* JS::GetSymbolDescription(HandleSymbol symbol) {
5458 return symbol->description();
5459 }
5460
GetSymbolCode(Handle<Symbol * > symbol)5461 JS_PUBLIC_API JS::SymbolCode JS::GetSymbolCode(Handle<Symbol*> symbol) {
5462 return symbol->code();
5463 }
5464
GetWellKnownSymbol(JSContext * cx,JS::SymbolCode which)5465 JS_PUBLIC_API JS::Symbol* JS::GetWellKnownSymbol(JSContext* cx,
5466 JS::SymbolCode which) {
5467 return cx->wellKnownSymbols().get(uint32_t(which));
5468 }
5469
5470 #ifdef DEBUG
PropertySpecNameIsDigits(const char * s)5471 static bool PropertySpecNameIsDigits(const char* s) {
5472 if (JS::PropertySpecNameIsSymbol(s)) return false;
5473 if (!*s) return false;
5474 for (; *s; s++) {
5475 if (*s < '0' || *s > '9') return false;
5476 }
5477 return true;
5478 }
5479 #endif // DEBUG
5480
PropertySpecNameEqualsId(const char * name,HandleId id)5481 JS_PUBLIC_API bool JS::PropertySpecNameEqualsId(const char* name, HandleId id) {
5482 if (JS::PropertySpecNameIsSymbol(name)) {
5483 if (!JSID_IS_SYMBOL(id)) return false;
5484 Symbol* sym = JSID_TO_SYMBOL(id);
5485 return sym->isWellKnownSymbol() &&
5486 sym->code() == PropertySpecNameToSymbolCode(name);
5487 }
5488
5489 MOZ_ASSERT(!PropertySpecNameIsDigits(name));
5490 return JSID_IS_ATOM(id) && JS_FlatStringEqualsAscii(JSID_TO_ATOM(id), name);
5491 }
5492
JS_Stringify(JSContext * cx,MutableHandleValue vp,HandleObject replacer,HandleValue space,JSONWriteCallback callback,void * data)5493 JS_PUBLIC_API bool JS_Stringify(JSContext* cx, MutableHandleValue vp,
5494 HandleObject replacer, HandleValue space,
5495 JSONWriteCallback callback, void* data) {
5496 AssertHeapIsIdle();
5497 CHECK_REQUEST(cx);
5498 assertSameCompartment(cx, replacer, space);
5499 StringBuffer sb(cx);
5500 if (!sb.ensureTwoByteChars()) return false;
5501 if (!Stringify(cx, vp, replacer, space, sb, StringifyBehavior::Normal))
5502 return false;
5503 if (sb.empty() && !sb.append(cx->names().null)) return false;
5504 return callback(sb.rawTwoByteBegin(), sb.length(), data);
5505 }
5506
ToJSONMaybeSafely(JSContext * cx,JS::HandleObject input,JSONWriteCallback callback,void * data)5507 JS_PUBLIC_API bool JS::ToJSONMaybeSafely(JSContext* cx, JS::HandleObject input,
5508 JSONWriteCallback callback,
5509 void* data) {
5510 AssertHeapIsIdle();
5511 CHECK_REQUEST(cx);
5512 assertSameCompartment(cx, input);
5513
5514 StringBuffer sb(cx);
5515 if (!sb.ensureTwoByteChars()) return false;
5516
5517 RootedValue inputValue(cx, ObjectValue(*input));
5518 if (!Stringify(cx, &inputValue, nullptr, NullHandleValue, sb,
5519 StringifyBehavior::RestrictedSafe))
5520 return false;
5521
5522 if (sb.empty() && !sb.append(cx->names().null)) return false;
5523
5524 return callback(sb.rawTwoByteBegin(), sb.length(), data);
5525 }
5526
JS_ParseJSON(JSContext * cx,const char16_t * chars,uint32_t len,MutableHandleValue vp)5527 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, const char16_t* chars,
5528 uint32_t len, MutableHandleValue vp) {
5529 AssertHeapIsIdle();
5530 CHECK_REQUEST(cx);
5531 return ParseJSONWithReviver(cx, mozilla::Range<const char16_t>(chars, len),
5532 NullHandleValue, vp);
5533 }
5534
JS_ParseJSON(JSContext * cx,HandleString str,MutableHandleValue vp)5535 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, HandleString str,
5536 MutableHandleValue vp) {
5537 return JS_ParseJSONWithReviver(cx, str, NullHandleValue, vp);
5538 }
5539
JS_ParseJSONWithReviver(JSContext * cx,const char16_t * chars,uint32_t len,HandleValue reviver,MutableHandleValue vp)5540 JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, const char16_t* chars,
5541 uint32_t len, HandleValue reviver,
5542 MutableHandleValue vp) {
5543 AssertHeapIsIdle();
5544 CHECK_REQUEST(cx);
5545 return ParseJSONWithReviver(cx, mozilla::Range<const char16_t>(chars, len),
5546 reviver, vp);
5547 }
5548
JS_ParseJSONWithReviver(JSContext * cx,HandleString str,HandleValue reviver,MutableHandleValue vp)5549 JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, HandleString str,
5550 HandleValue reviver,
5551 MutableHandleValue vp) {
5552 AssertHeapIsIdle();
5553 CHECK_REQUEST(cx);
5554 assertSameCompartment(cx, str);
5555
5556 AutoStableStringChars stableChars(cx);
5557 if (!stableChars.init(cx, str)) return false;
5558
5559 return stableChars.isLatin1()
5560 ? ParseJSONWithReviver(cx, stableChars.latin1Range(), reviver, vp)
5561 : ParseJSONWithReviver(cx, stableChars.twoByteRange(), reviver,
5562 vp);
5563 }
5564
5565 /************************************************************************/
5566
JS_ReportErrorASCII(JSContext * cx,const char * format,...)5567 JS_PUBLIC_API void JS_ReportErrorASCII(JSContext* cx, const char* format, ...) {
5568 va_list ap;
5569
5570 AssertHeapIsIdle();
5571 va_start(ap, format);
5572 ReportErrorVA(cx, JSREPORT_ERROR, format, ArgumentsAreASCII, ap);
5573 va_end(ap);
5574 }
5575
JS_ReportErrorLatin1(JSContext * cx,const char * format,...)5576 JS_PUBLIC_API void JS_ReportErrorLatin1(JSContext* cx, const char* format,
5577 ...) {
5578 va_list ap;
5579
5580 AssertHeapIsIdle();
5581 va_start(ap, format);
5582 ReportErrorVA(cx, JSREPORT_ERROR, format, ArgumentsAreLatin1, ap);
5583 va_end(ap);
5584 }
5585
JS_ReportErrorUTF8(JSContext * cx,const char * format,...)5586 JS_PUBLIC_API void JS_ReportErrorUTF8(JSContext* cx, const char* format, ...) {
5587 va_list ap;
5588
5589 AssertHeapIsIdle();
5590 va_start(ap, format);
5591 ReportErrorVA(cx, JSREPORT_ERROR, format, ArgumentsAreUTF8, ap);
5592 va_end(ap);
5593 }
5594
JS_ReportErrorNumberASCII(JSContext * cx,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)5595 JS_PUBLIC_API void JS_ReportErrorNumberASCII(JSContext* cx,
5596 JSErrorCallback errorCallback,
5597 void* userRef,
5598 const unsigned errorNumber, ...) {
5599 va_list ap;
5600 va_start(ap, errorNumber);
5601 JS_ReportErrorNumberASCIIVA(cx, errorCallback, userRef, errorNumber, ap);
5602 va_end(ap);
5603 }
5604
JS_ReportErrorNumberASCIIVA(JSContext * cx,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,va_list ap)5605 JS_PUBLIC_API void JS_ReportErrorNumberASCIIVA(JSContext* cx,
5606 JSErrorCallback errorCallback,
5607 void* userRef,
5608 const unsigned errorNumber,
5609 va_list ap) {
5610 AssertHeapIsIdle();
5611 ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef, errorNumber,
5612 ArgumentsAreASCII, ap);
5613 }
5614
JS_ReportErrorNumberLatin1(JSContext * cx,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)5615 JS_PUBLIC_API void JS_ReportErrorNumberLatin1(JSContext* cx,
5616 JSErrorCallback errorCallback,
5617 void* userRef,
5618 const unsigned errorNumber, ...) {
5619 va_list ap;
5620 va_start(ap, errorNumber);
5621 JS_ReportErrorNumberLatin1VA(cx, errorCallback, userRef, errorNumber, ap);
5622 va_end(ap);
5623 }
5624
JS_ReportErrorNumberLatin1VA(JSContext * cx,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,va_list ap)5625 JS_PUBLIC_API void JS_ReportErrorNumberLatin1VA(JSContext* cx,
5626 JSErrorCallback errorCallback,
5627 void* userRef,
5628 const unsigned errorNumber,
5629 va_list ap) {
5630 AssertHeapIsIdle();
5631 ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef, errorNumber,
5632 ArgumentsAreLatin1, ap);
5633 }
5634
JS_ReportErrorNumberUTF8(JSContext * cx,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)5635 JS_PUBLIC_API void JS_ReportErrorNumberUTF8(JSContext* cx,
5636 JSErrorCallback errorCallback,
5637 void* userRef,
5638 const unsigned errorNumber, ...) {
5639 va_list ap;
5640 va_start(ap, errorNumber);
5641 JS_ReportErrorNumberUTF8VA(cx, errorCallback, userRef, errorNumber, ap);
5642 va_end(ap);
5643 }
5644
JS_ReportErrorNumberUTF8VA(JSContext * cx,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,va_list ap)5645 JS_PUBLIC_API void JS_ReportErrorNumberUTF8VA(JSContext* cx,
5646 JSErrorCallback errorCallback,
5647 void* userRef,
5648 const unsigned errorNumber,
5649 va_list ap) {
5650 AssertHeapIsIdle();
5651 ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef, errorNumber,
5652 ArgumentsAreUTF8, ap);
5653 }
5654
JS_ReportErrorNumberUC(JSContext * cx,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)5655 JS_PUBLIC_API void JS_ReportErrorNumberUC(JSContext* cx,
5656 JSErrorCallback errorCallback,
5657 void* userRef,
5658 const unsigned errorNumber, ...) {
5659 va_list ap;
5660
5661 AssertHeapIsIdle();
5662 va_start(ap, errorNumber);
5663 ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef, errorNumber,
5664 ArgumentsAreUnicode, ap);
5665 va_end(ap);
5666 }
5667
JS_ReportErrorNumberUCArray(JSContext * cx,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,const char16_t ** args)5668 JS_PUBLIC_API void JS_ReportErrorNumberUCArray(JSContext* cx,
5669 JSErrorCallback errorCallback,
5670 void* userRef,
5671 const unsigned errorNumber,
5672 const char16_t** args) {
5673 AssertHeapIsIdle();
5674 ReportErrorNumberUCArray(cx, JSREPORT_ERROR, errorCallback, userRef,
5675 errorNumber, args);
5676 }
5677
JS_ReportWarningASCII(JSContext * cx,const char * format,...)5678 JS_PUBLIC_API bool JS_ReportWarningASCII(JSContext* cx, const char* format,
5679 ...) {
5680 va_list ap;
5681 bool ok;
5682
5683 AssertHeapIsIdle();
5684 va_start(ap, format);
5685 ok = ReportErrorVA(cx, JSREPORT_WARNING, format, ArgumentsAreASCII, ap);
5686 va_end(ap);
5687 return ok;
5688 }
5689
JS_ReportWarningLatin1(JSContext * cx,const char * format,...)5690 JS_PUBLIC_API bool JS_ReportWarningLatin1(JSContext* cx, const char* format,
5691 ...) {
5692 va_list ap;
5693 bool ok;
5694
5695 AssertHeapIsIdle();
5696 va_start(ap, format);
5697 ok = ReportErrorVA(cx, JSREPORT_WARNING, format, ArgumentsAreLatin1, ap);
5698 va_end(ap);
5699 return ok;
5700 }
5701
JS_ReportWarningUTF8(JSContext * cx,const char * format,...)5702 JS_PUBLIC_API bool JS_ReportWarningUTF8(JSContext* cx, const char* format,
5703 ...) {
5704 va_list ap;
5705 bool ok;
5706
5707 AssertHeapIsIdle();
5708 va_start(ap, format);
5709 ok = ReportErrorVA(cx, JSREPORT_WARNING, format, ArgumentsAreUTF8, ap);
5710 va_end(ap);
5711 return ok;
5712 }
5713
JS_ReportErrorFlagsAndNumberASCII(JSContext * cx,unsigned flags,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)5714 JS_PUBLIC_API bool JS_ReportErrorFlagsAndNumberASCII(
5715 JSContext* cx, unsigned flags, JSErrorCallback errorCallback, void* userRef,
5716 const unsigned errorNumber, ...) {
5717 va_list ap;
5718 bool ok;
5719
5720 AssertHeapIsIdle();
5721 va_start(ap, errorNumber);
5722 ok = ReportErrorNumberVA(cx, flags, errorCallback, userRef, errorNumber,
5723 ArgumentsAreASCII, ap);
5724 va_end(ap);
5725 return ok;
5726 }
5727
JS_ReportErrorFlagsAndNumberLatin1(JSContext * cx,unsigned flags,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)5728 JS_PUBLIC_API bool JS_ReportErrorFlagsAndNumberLatin1(
5729 JSContext* cx, unsigned flags, JSErrorCallback errorCallback, void* userRef,
5730 const unsigned errorNumber, ...) {
5731 va_list ap;
5732 bool ok;
5733
5734 AssertHeapIsIdle();
5735 va_start(ap, errorNumber);
5736 ok = ReportErrorNumberVA(cx, flags, errorCallback, userRef, errorNumber,
5737 ArgumentsAreLatin1, ap);
5738 va_end(ap);
5739 return ok;
5740 }
5741
JS_ReportErrorFlagsAndNumberUTF8(JSContext * cx,unsigned flags,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)5742 JS_PUBLIC_API bool JS_ReportErrorFlagsAndNumberUTF8(
5743 JSContext* cx, unsigned flags, JSErrorCallback errorCallback, void* userRef,
5744 const unsigned errorNumber, ...) {
5745 va_list ap;
5746 bool ok;
5747
5748 AssertHeapIsIdle();
5749 va_start(ap, errorNumber);
5750 ok = ReportErrorNumberVA(cx, flags, errorCallback, userRef, errorNumber,
5751 ArgumentsAreUTF8, ap);
5752 va_end(ap);
5753 return ok;
5754 }
5755
JS_ReportErrorFlagsAndNumberUC(JSContext * cx,unsigned flags,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)5756 JS_PUBLIC_API bool JS_ReportErrorFlagsAndNumberUC(JSContext* cx, unsigned flags,
5757 JSErrorCallback errorCallback,
5758 void* userRef,
5759 const unsigned errorNumber,
5760 ...) {
5761 va_list ap;
5762 bool ok;
5763
5764 AssertHeapIsIdle();
5765 va_start(ap, errorNumber);
5766 ok = ReportErrorNumberVA(cx, flags, errorCallback, userRef, errorNumber,
5767 ArgumentsAreUnicode, ap);
5768 va_end(ap);
5769 return ok;
5770 }
5771
JS_ReportOutOfMemory(JSContext * cx)5772 JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx) {
5773 ReportOutOfMemory(cx);
5774 }
5775
JS_ReportAllocationOverflow(JSContext * cx)5776 JS_PUBLIC_API void JS_ReportAllocationOverflow(JSContext* cx) {
5777 ReportAllocationOverflow(cx);
5778 }
5779
GetWarningReporter(JSContext * cx)5780 JS_PUBLIC_API JS::WarningReporter JS::GetWarningReporter(JSContext* cx) {
5781 return cx->runtime()->warningReporter;
5782 }
5783
SetWarningReporter(JSContext * cx,JS::WarningReporter reporter)5784 JS_PUBLIC_API JS::WarningReporter JS::SetWarningReporter(
5785 JSContext* cx, JS::WarningReporter reporter) {
5786 WarningReporter older = cx->runtime()->warningReporter;
5787 cx->runtime()->warningReporter = reporter;
5788 return older;
5789 }
5790
5791 /************************************************************************/
5792
5793 /*
5794 * Dates.
5795 */
JS_NewDateObject(JSContext * cx,int year,int mon,int mday,int hour,int min,int sec)5796 JS_PUBLIC_API JSObject* JS_NewDateObject(JSContext* cx, int year, int mon,
5797 int mday, int hour, int min, int sec) {
5798 AssertHeapIsIdle();
5799 CHECK_REQUEST(cx);
5800 return NewDateObject(cx, year, mon, mday, hour, min, sec);
5801 }
5802
NewDateObject(JSContext * cx,JS::ClippedTime time)5803 JS_PUBLIC_API JSObject* JS::NewDateObject(JSContext* cx, JS::ClippedTime time) {
5804 AssertHeapIsIdle();
5805 CHECK_REQUEST(cx);
5806 return NewDateObjectMsec(cx, time);
5807 }
5808
JS_ObjectIsDate(JSContext * cx,HandleObject obj,bool * isDate)5809 JS_PUBLIC_API bool JS_ObjectIsDate(JSContext* cx, HandleObject obj,
5810 bool* isDate) {
5811 assertSameCompartment(cx, obj);
5812
5813 ESClass cls;
5814 if (!GetBuiltinClass(cx, obj, &cls)) return false;
5815
5816 *isDate = cls == ESClass::Date;
5817 return true;
5818 }
5819
5820 /************************************************************************/
5821
5822 /*
5823 * Regular Expressions.
5824 */
JS_NewRegExpObject(JSContext * cx,const char * bytes,size_t length,unsigned flags)5825 JS_PUBLIC_API JSObject* JS_NewRegExpObject(JSContext* cx, const char* bytes,
5826 size_t length, unsigned flags) {
5827 AssertHeapIsIdle();
5828 CHECK_REQUEST(cx);
5829
5830 ScopedJSFreePtr<char16_t> chars(InflateString(cx, bytes, length));
5831 if (!chars) return nullptr;
5832
5833 return RegExpObject::create(cx, chars.get(), length, RegExpFlag(flags),
5834 cx->tempLifoAlloc(), GenericObject);
5835 }
5836
JS_NewUCRegExpObject(JSContext * cx,const char16_t * chars,size_t length,unsigned flags)5837 JS_PUBLIC_API JSObject* JS_NewUCRegExpObject(JSContext* cx,
5838 const char16_t* chars,
5839 size_t length, unsigned flags) {
5840 AssertHeapIsIdle();
5841 CHECK_REQUEST(cx);
5842
5843 return RegExpObject::create(cx, chars, length, RegExpFlag(flags),
5844 cx->tempLifoAlloc(), GenericObject);
5845 }
5846
JS_SetRegExpInput(JSContext * cx,HandleObject obj,HandleString input)5847 JS_PUBLIC_API bool JS_SetRegExpInput(JSContext* cx, HandleObject obj,
5848 HandleString input) {
5849 AssertHeapIsIdle();
5850 CHECK_REQUEST(cx);
5851 assertSameCompartment(cx, input);
5852
5853 Handle<GlobalObject*> global = obj.as<GlobalObject>();
5854 RegExpStatics* res = GlobalObject::getRegExpStatics(cx, global);
5855 if (!res) return false;
5856
5857 res->reset(input);
5858 return true;
5859 }
5860
JS_ClearRegExpStatics(JSContext * cx,HandleObject obj)5861 JS_PUBLIC_API bool JS_ClearRegExpStatics(JSContext* cx, HandleObject obj) {
5862 AssertHeapIsIdle();
5863 CHECK_REQUEST(cx);
5864 MOZ_ASSERT(obj);
5865
5866 Handle<GlobalObject*> global = obj.as<GlobalObject>();
5867 RegExpStatics* res = GlobalObject::getRegExpStatics(cx, global);
5868 if (!res) return false;
5869
5870 res->clear();
5871 return true;
5872 }
5873
JS_ExecuteRegExp(JSContext * cx,HandleObject obj,HandleObject reobj,char16_t * chars,size_t length,size_t * indexp,bool test,MutableHandleValue rval)5874 JS_PUBLIC_API bool JS_ExecuteRegExp(JSContext* cx, HandleObject obj,
5875 HandleObject reobj, char16_t* chars,
5876 size_t length, size_t* indexp, bool test,
5877 MutableHandleValue rval) {
5878 AssertHeapIsIdle();
5879 CHECK_REQUEST(cx);
5880
5881 Handle<GlobalObject*> global = obj.as<GlobalObject>();
5882 RegExpStatics* res = GlobalObject::getRegExpStatics(cx, global);
5883 if (!res) return false;
5884
5885 RootedLinearString input(cx, NewStringCopyN<CanGC>(cx, chars, length));
5886 if (!input) return false;
5887
5888 return ExecuteRegExpLegacy(cx, res, reobj.as<RegExpObject>(), input, indexp,
5889 test, rval);
5890 }
5891
JS_ExecuteRegExpNoStatics(JSContext * cx,HandleObject obj,char16_t * chars,size_t length,size_t * indexp,bool test,MutableHandleValue rval)5892 JS_PUBLIC_API bool JS_ExecuteRegExpNoStatics(JSContext* cx, HandleObject obj,
5893 char16_t* chars, size_t length,
5894 size_t* indexp, bool test,
5895 MutableHandleValue rval) {
5896 AssertHeapIsIdle();
5897 CHECK_REQUEST(cx);
5898
5899 RootedLinearString input(cx, NewStringCopyN<CanGC>(cx, chars, length));
5900 if (!input) return false;
5901
5902 return ExecuteRegExpLegacy(cx, nullptr, obj.as<RegExpObject>(), input, indexp,
5903 test, rval);
5904 }
5905
JS_ObjectIsRegExp(JSContext * cx,HandleObject obj,bool * isRegExp)5906 JS_PUBLIC_API bool JS_ObjectIsRegExp(JSContext* cx, HandleObject obj,
5907 bool* isRegExp) {
5908 assertSameCompartment(cx, obj);
5909
5910 ESClass cls;
5911 if (!GetBuiltinClass(cx, obj, &cls)) return false;
5912
5913 *isRegExp = cls == ESClass::RegExp;
5914 return true;
5915 }
5916
JS_GetRegExpFlags(JSContext * cx,HandleObject obj)5917 JS_PUBLIC_API unsigned JS_GetRegExpFlags(JSContext* cx, HandleObject obj) {
5918 AssertHeapIsIdle();
5919 CHECK_REQUEST(cx);
5920
5921 RegExpShared* shared = RegExpToShared(cx, obj);
5922 if (!shared) return false;
5923 return shared->getFlags();
5924 }
5925
JS_GetRegExpSource(JSContext * cx,HandleObject obj)5926 JS_PUBLIC_API JSString* JS_GetRegExpSource(JSContext* cx, HandleObject obj) {
5927 AssertHeapIsIdle();
5928 CHECK_REQUEST(cx);
5929
5930 RegExpShared* shared = RegExpToShared(cx, obj);
5931 if (!shared) return nullptr;
5932 return shared->getSource();
5933 }
5934
5935 /************************************************************************/
5936
JS_SetDefaultLocale(JSRuntime * rt,const char * locale)5937 JS_PUBLIC_API bool JS_SetDefaultLocale(JSRuntime* rt, const char* locale) {
5938 AssertHeapIsIdle();
5939 return rt->setDefaultLocale(locale);
5940 }
5941
JS_GetDefaultLocale(JSContext * cx)5942 JS_PUBLIC_API UniqueChars JS_GetDefaultLocale(JSContext* cx) {
5943 AssertHeapIsIdle();
5944 if (const char* locale = cx->runtime()->getDefaultLocale())
5945 return UniqueChars(JS_strdup(cx, locale));
5946
5947 return nullptr;
5948 }
5949
JS_ResetDefaultLocale(JSRuntime * rt)5950 JS_PUBLIC_API void JS_ResetDefaultLocale(JSRuntime* rt) {
5951 AssertHeapIsIdle();
5952 rt->resetDefaultLocale();
5953 }
5954
JS_SetLocaleCallbacks(JSRuntime * rt,const JSLocaleCallbacks * callbacks)5955 JS_PUBLIC_API void JS_SetLocaleCallbacks(JSRuntime* rt,
5956 const JSLocaleCallbacks* callbacks) {
5957 AssertHeapIsIdle();
5958 rt->localeCallbacks = callbacks;
5959 }
5960
JS_GetLocaleCallbacks(JSRuntime * rt)5961 JS_PUBLIC_API const JSLocaleCallbacks* JS_GetLocaleCallbacks(JSRuntime* rt) {
5962 /* This function can be called by a finalizer. */
5963 return rt->localeCallbacks;
5964 }
5965
5966 /************************************************************************/
5967
JS_IsExceptionPending(JSContext * cx)5968 JS_PUBLIC_API bool JS_IsExceptionPending(JSContext* cx) {
5969 /* This function can be called by a finalizer. */
5970 return (bool)cx->isExceptionPending();
5971 }
5972
JS_GetPendingException(JSContext * cx,MutableHandleValue vp)5973 JS_PUBLIC_API bool JS_GetPendingException(JSContext* cx,
5974 MutableHandleValue vp) {
5975 AssertHeapIsIdle();
5976 CHECK_REQUEST(cx);
5977 if (!cx->isExceptionPending()) return false;
5978 return cx->getPendingException(vp);
5979 }
5980
JS_SetPendingException(JSContext * cx,HandleValue value)5981 JS_PUBLIC_API void JS_SetPendingException(JSContext* cx, HandleValue value) {
5982 AssertHeapIsIdle();
5983 CHECK_REQUEST(cx);
5984 releaseAssertSameCompartment(cx, value);
5985 cx->setPendingException(value);
5986 }
5987
JS_ClearPendingException(JSContext * cx)5988 JS_PUBLIC_API void JS_ClearPendingException(JSContext* cx) {
5989 AssertHeapIsIdle();
5990 cx->clearPendingException();
5991 }
5992
AutoSaveExceptionState(JSContext * cx)5993 JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext* cx)
5994 : context(cx),
5995 wasPropagatingForcedReturn(cx->propagatingForcedReturn_),
5996 wasOverRecursed(cx->overRecursed_),
5997 wasThrowing(cx->throwing),
5998 exceptionValue(cx) {
5999 AssertHeapIsIdle();
6000 CHECK_REQUEST(cx);
6001 if (wasPropagatingForcedReturn) cx->clearPropagatingForcedReturn();
6002 if (wasOverRecursed) cx->overRecursed_ = false;
6003 if (wasThrowing) {
6004 exceptionValue = cx->unwrappedException();
6005 cx->clearPendingException();
6006 }
6007 }
6008
restore()6009 void JS::AutoSaveExceptionState::restore() {
6010 context->propagatingForcedReturn_ = wasPropagatingForcedReturn;
6011 context->overRecursed_ = wasOverRecursed;
6012 context->throwing = wasThrowing;
6013 context->unwrappedException() = exceptionValue;
6014 drop();
6015 }
6016
~AutoSaveExceptionState()6017 JS::AutoSaveExceptionState::~AutoSaveExceptionState() {
6018 if (!context->isExceptionPending()) {
6019 if (wasPropagatingForcedReturn) context->setPropagatingForcedReturn();
6020 if (wasThrowing) {
6021 context->overRecursed_ = wasOverRecursed;
6022 context->throwing = true;
6023 context->unwrappedException() = exceptionValue;
6024 }
6025 }
6026 }
6027
6028 struct JSExceptionState {
JSExceptionStateJSExceptionState6029 explicit JSExceptionState(JSContext* cx) : exception(cx) {}
6030 bool throwing;
6031 PersistentRootedValue exception;
6032 };
6033
JS_SaveExceptionState(JSContext * cx)6034 JS_PUBLIC_API JSExceptionState* JS_SaveExceptionState(JSContext* cx) {
6035 JSExceptionState* state;
6036
6037 AssertHeapIsIdle();
6038 CHECK_REQUEST(cx);
6039 state = cx->new_<JSExceptionState>(cx);
6040 if (state) state->throwing = JS_GetPendingException(cx, &state->exception);
6041 return state;
6042 }
6043
JS_RestoreExceptionState(JSContext * cx,JSExceptionState * state)6044 JS_PUBLIC_API void JS_RestoreExceptionState(JSContext* cx,
6045 JSExceptionState* state) {
6046 AssertHeapIsIdle();
6047 CHECK_REQUEST(cx);
6048 if (state) {
6049 if (state->throwing)
6050 JS_SetPendingException(cx, state->exception);
6051 else
6052 JS_ClearPendingException(cx);
6053 JS_DropExceptionState(cx, state);
6054 }
6055 }
6056
JS_DropExceptionState(JSContext * cx,JSExceptionState * state)6057 JS_PUBLIC_API void JS_DropExceptionState(JSContext* cx,
6058 JSExceptionState* state) {
6059 AssertHeapIsIdle();
6060 CHECK_REQUEST(cx);
6061 js_delete(state);
6062 }
6063
JS_ErrorFromException(JSContext * cx,HandleObject obj)6064 JS_PUBLIC_API JSErrorReport* JS_ErrorFromException(JSContext* cx,
6065 HandleObject obj) {
6066 AssertHeapIsIdle();
6067 CHECK_REQUEST(cx);
6068 assertSameCompartment(cx, obj);
6069 return ErrorFromException(cx, obj);
6070 }
6071
initBorrowedLinebuf(const char16_t * linebufArg,size_t linebufLengthArg,size_t tokenOffsetArg)6072 void JSErrorReport::initBorrowedLinebuf(const char16_t* linebufArg,
6073 size_t linebufLengthArg,
6074 size_t tokenOffsetArg) {
6075 MOZ_ASSERT(linebufArg);
6076 MOZ_ASSERT(tokenOffsetArg <= linebufLengthArg);
6077 MOZ_ASSERT(linebufArg[linebufLengthArg] == '\0');
6078
6079 linebuf_ = linebufArg;
6080 linebufLength_ = linebufLengthArg;
6081 tokenOffset_ = tokenOffsetArg;
6082 }
6083
freeLinebuf()6084 void JSErrorReport::freeLinebuf() {
6085 if (ownsLinebuf_ && linebuf_) {
6086 js_free((void*)linebuf_);
6087 ownsLinebuf_ = false;
6088 }
6089 linebuf_ = nullptr;
6090 }
6091
newMessageString(JSContext * cx)6092 JSString* JSErrorBase::newMessageString(JSContext* cx) {
6093 if (!message_) return cx->runtime()->emptyString;
6094
6095 return JS_NewStringCopyUTF8Z(cx, message_);
6096 }
6097
freeMessage()6098 void JSErrorBase::freeMessage() {
6099 if (ownsMessage_) {
6100 js_free((void*)message_.get());
6101 ownsMessage_ = false;
6102 }
6103 message_ = JS::ConstUTF8CharsZ();
6104 }
6105
JSErrorNotes()6106 JSErrorNotes::JSErrorNotes() : notes_() {}
6107
~JSErrorNotes()6108 JSErrorNotes::~JSErrorNotes() {}
6109
CreateErrorNoteVA(JSContext * cx,const char * filename,unsigned lineno,unsigned column,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,ErrorArgumentsType argumentsType,va_list ap)6110 static UniquePtr<JSErrorNotes::Note> CreateErrorNoteVA(
6111 JSContext* cx, const char* filename, unsigned lineno, unsigned column,
6112 JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber,
6113 ErrorArgumentsType argumentsType, va_list ap) {
6114 auto note = MakeUnique<JSErrorNotes::Note>();
6115 if (!note) {
6116 ReportOutOfMemory(cx);
6117 return nullptr;
6118 }
6119
6120 note->errorNumber = errorNumber;
6121 note->filename = filename;
6122 note->lineno = lineno;
6123 note->column = column;
6124
6125 if (!ExpandErrorArgumentsVA(cx, errorCallback, userRef, errorNumber, nullptr,
6126 argumentsType, note.get(), ap)) {
6127 return nullptr;
6128 }
6129
6130 return note;
6131 }
6132
addNoteASCII(JSContext * cx,const char * filename,unsigned lineno,unsigned column,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)6133 bool JSErrorNotes::addNoteASCII(JSContext* cx, const char* filename,
6134 unsigned lineno, unsigned column,
6135 JSErrorCallback errorCallback, void* userRef,
6136 const unsigned errorNumber, ...) {
6137 va_list ap;
6138 va_start(ap, errorNumber);
6139 auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback,
6140 userRef, errorNumber, ArgumentsAreASCII, ap);
6141 va_end(ap);
6142
6143 if (!note) return false;
6144 if (!notes_.append(Move(note))) return false;
6145 return true;
6146 }
6147
addNoteLatin1(JSContext * cx,const char * filename,unsigned lineno,unsigned column,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)6148 bool JSErrorNotes::addNoteLatin1(JSContext* cx, const char* filename,
6149 unsigned lineno, unsigned column,
6150 JSErrorCallback errorCallback, void* userRef,
6151 const unsigned errorNumber, ...) {
6152 va_list ap;
6153 va_start(ap, errorNumber);
6154 auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback,
6155 userRef, errorNumber, ArgumentsAreLatin1, ap);
6156 va_end(ap);
6157
6158 if (!note) return false;
6159 if (!notes_.append(Move(note))) return false;
6160 return true;
6161 }
6162
addNoteUTF8(JSContext * cx,const char * filename,unsigned lineno,unsigned column,JSErrorCallback errorCallback,void * userRef,const unsigned errorNumber,...)6163 bool JSErrorNotes::addNoteUTF8(JSContext* cx, const char* filename,
6164 unsigned lineno, unsigned column,
6165 JSErrorCallback errorCallback, void* userRef,
6166 const unsigned errorNumber, ...) {
6167 va_list ap;
6168 va_start(ap, errorNumber);
6169 auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback,
6170 userRef, errorNumber, ArgumentsAreUTF8, ap);
6171 va_end(ap);
6172
6173 if (!note) return false;
6174 if (!notes_.append(Move(note))) return false;
6175 return true;
6176 }
6177
length()6178 JS_PUBLIC_API size_t JSErrorNotes::length() { return notes_.length(); }
6179
copy(JSContext * cx)6180 UniquePtr<JSErrorNotes> JSErrorNotes::copy(JSContext* cx) {
6181 auto copiedNotes = MakeUnique<JSErrorNotes>();
6182 if (!copiedNotes) {
6183 ReportOutOfMemory(cx);
6184 return nullptr;
6185 }
6186
6187 for (auto&& note : *this) {
6188 js::UniquePtr<JSErrorNotes::Note> copied(CopyErrorNote(cx, note.get()));
6189 if (!copied) return nullptr;
6190
6191 if (!copiedNotes->notes_.append(Move(copied))) return nullptr;
6192 }
6193
6194 return copiedNotes;
6195 }
6196
begin()6197 JS_PUBLIC_API JSErrorNotes::iterator JSErrorNotes::begin() {
6198 return iterator(notes_.begin());
6199 }
6200
end()6201 JS_PUBLIC_API JSErrorNotes::iterator JSErrorNotes::end() {
6202 return iterator(notes_.end());
6203 }
6204
JS_AbortIfWrongThread(JSContext * cx)6205 extern MOZ_NEVER_INLINE JS_PUBLIC_API void JS_AbortIfWrongThread(
6206 JSContext* cx) {
6207 if (!CurrentThreadCanAccessRuntime(cx->runtime())) MOZ_CRASH();
6208 if (TlsContext.get() != cx) MOZ_CRASH();
6209 }
6210
6211 #ifdef JS_GC_ZEAL
JS_GetGCZealBits(JSContext * cx,uint32_t * zealBits,uint32_t * frequency,uint32_t * nextScheduled)6212 JS_PUBLIC_API void JS_GetGCZealBits(JSContext* cx, uint32_t* zealBits,
6213 uint32_t* frequency,
6214 uint32_t* nextScheduled) {
6215 cx->runtime()->gc.getZealBits(zealBits, frequency, nextScheduled);
6216 }
6217
JS_SetGCZeal(JSContext * cx,uint8_t zeal,uint32_t frequency)6218 JS_PUBLIC_API void JS_SetGCZeal(JSContext* cx, uint8_t zeal,
6219 uint32_t frequency) {
6220 cx->runtime()->gc.setZeal(zeal, frequency);
6221 }
6222
JS_ScheduleGC(JSContext * cx,uint32_t count)6223 JS_PUBLIC_API void JS_ScheduleGC(JSContext* cx, uint32_t count) {
6224 cx->runtime()->gc.setNextScheduled(count);
6225 }
6226 #endif
6227
JS_SetParallelParsingEnabled(JSContext * cx,bool enabled)6228 JS_PUBLIC_API void JS_SetParallelParsingEnabled(JSContext* cx, bool enabled) {
6229 cx->runtime()->setParallelParsingEnabled(enabled);
6230 }
6231
JS_SetOffthreadIonCompilationEnabled(JSContext * cx,bool enabled)6232 JS_PUBLIC_API void JS_SetOffthreadIonCompilationEnabled(JSContext* cx,
6233 bool enabled) {
6234 cx->runtime()->setOffthreadIonCompilationEnabled(enabled);
6235 }
6236
JS_SetGlobalJitCompilerOption(JSContext * cx,JSJitCompilerOption opt,uint32_t value)6237 JS_PUBLIC_API void JS_SetGlobalJitCompilerOption(JSContext* cx,
6238 JSJitCompilerOption opt,
6239 uint32_t value) {
6240 JSRuntime* rt = cx->runtime();
6241 switch (opt) {
6242 case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER:
6243 if (value == uint32_t(-1)) {
6244 jit::DefaultJitOptions defaultValues;
6245 value = defaultValues.baselineWarmUpThreshold;
6246 }
6247 jit::JitOptions.baselineWarmUpThreshold = value;
6248 break;
6249 case JSJITCOMPILER_ION_WARMUP_TRIGGER:
6250 if (value == uint32_t(-1)) {
6251 jit::JitOptions.resetCompilerWarmUpThreshold();
6252 break;
6253 }
6254 jit::JitOptions.setCompilerWarmUpThreshold(value);
6255 if (value == 0) jit::JitOptions.setEagerCompilation();
6256 break;
6257 case JSJITCOMPILER_ION_GVN_ENABLE:
6258 if (value == 0) {
6259 jit::JitOptions.enableGvn(false);
6260 JitSpew(js::jit::JitSpew_IonScripts, "Disable ion's GVN");
6261 } else {
6262 jit::JitOptions.enableGvn(true);
6263 JitSpew(js::jit::JitSpew_IonScripts, "Enable ion's GVN");
6264 }
6265 break;
6266 case JSJITCOMPILER_ION_FORCE_IC:
6267 if (value == 0) {
6268 jit::JitOptions.forceInlineCaches = false;
6269 JitSpew(js::jit::JitSpew_IonScripts,
6270 "IonBuilder: Enable non-IC optimizations.");
6271 } else {
6272 jit::JitOptions.forceInlineCaches = true;
6273 JitSpew(js::jit::JitSpew_IonScripts,
6274 "IonBuilder: Disable non-IC optimizations.");
6275 }
6276 break;
6277 case JSJITCOMPILER_ION_CHECK_RANGE_ANALYSIS:
6278 if (value == 0) {
6279 jit::JitOptions.checkRangeAnalysis = false;
6280 JitSpew(js::jit::JitSpew_IonScripts,
6281 "IonBuilder: Enable range analysis checks.");
6282 } else {
6283 jit::JitOptions.checkRangeAnalysis = true;
6284 JitSpew(js::jit::JitSpew_IonScripts,
6285 "IonBuilder: Disable range analysis checks.");
6286 }
6287 break;
6288 case JSJITCOMPILER_ION_ENABLE:
6289 if (value == 1) {
6290 JS::ContextOptionsRef(cx).setIon(true);
6291 JitSpew(js::jit::JitSpew_IonScripts, "Enable ion");
6292 } else if (value == 0) {
6293 JS::ContextOptionsRef(cx).setIon(false);
6294 JitSpew(js::jit::JitSpew_IonScripts, "Disable ion");
6295 }
6296 break;
6297 case JSJITCOMPILER_BASELINE_ENABLE:
6298 if (value == 1) {
6299 JS::ContextOptionsRef(cx).setBaseline(true);
6300 ReleaseAllJITCode(rt->defaultFreeOp());
6301 JitSpew(js::jit::JitSpew_BaselineScripts, "Enable baseline");
6302 } else if (value == 0) {
6303 JS::ContextOptionsRef(cx).setBaseline(false);
6304 ReleaseAllJITCode(rt->defaultFreeOp());
6305 JitSpew(js::jit::JitSpew_BaselineScripts, "Disable baseline");
6306 }
6307 break;
6308 case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE:
6309 if (value == 1) {
6310 rt->setOffthreadIonCompilationEnabled(true);
6311 JitSpew(js::jit::JitSpew_IonScripts, "Enable offthread compilation");
6312 } else if (value == 0) {
6313 rt->setOffthreadIonCompilationEnabled(false);
6314 JitSpew(js::jit::JitSpew_IonScripts, "Disable offthread compilation");
6315 }
6316 break;
6317 case JSJITCOMPILER_JUMP_THRESHOLD:
6318 if (value == uint32_t(-1)) {
6319 jit::DefaultJitOptions defaultValues;
6320 value = defaultValues.jumpThreshold;
6321 }
6322 jit::JitOptions.jumpThreshold = value;
6323 break;
6324 case JSJITCOMPILER_UNBOXED_OBJECTS:
6325 jit::JitOptions.disableUnboxedObjects = !value;
6326 break;
6327 case JSJITCOMPILER_SIMULATOR_ALWAYS_INTERRUPT:
6328 jit::JitOptions.simulatorAlwaysInterrupt = !!value;
6329 break;
6330 case JSJITCOMPILER_SPECTRE_INDEX_MASKING:
6331 jit::JitOptions.spectreIndexMasking = !!value;
6332 break;
6333 case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_BARRIERS:
6334 jit::JitOptions.spectreObjectMitigationsBarriers = !!value;
6335 break;
6336 case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_MISC:
6337 jit::JitOptions.spectreObjectMitigationsMisc = !!value;
6338 break;
6339 case JSJITCOMPILER_SPECTRE_STRING_MITIGATIONS:
6340 jit::JitOptions.spectreStringMitigations = !!value;
6341 break;
6342 case JSJITCOMPILER_SPECTRE_VALUE_MASKING:
6343 jit::JitOptions.spectreValueMasking = !!value;
6344 break;
6345 case JSJITCOMPILER_SPECTRE_JIT_TO_CXX_CALLS:
6346 jit::JitOptions.spectreJitToCxxCalls = !!value;
6347 break;
6348 case JSJITCOMPILER_ASMJS_ATOMICS_ENABLE:
6349 jit::JitOptions.asmJSAtomicsEnable = !!value;
6350 break;
6351 case JSJITCOMPILER_WASM_FOLD_OFFSETS:
6352 jit::JitOptions.wasmFoldOffsets = !!value;
6353 break;
6354 case JSJITCOMPILER_WASM_DELAY_TIER2:
6355 jit::JitOptions.wasmDelayTier2 = !!value;
6356 break;
6357 case JSJITCOMPILER_ION_INTERRUPT_WITHOUT_SIGNAL:
6358 jit::JitOptions.ionInterruptWithoutSignals = !!value;
6359 break;
6360 #ifdef DEBUG
6361 case JSJITCOMPILER_FULL_DEBUG_CHECKS:
6362 jit::JitOptions.fullDebugChecks = !!value;
6363 break;
6364 #endif
6365 default:
6366 break;
6367 }
6368 }
6369
JS_GetGlobalJitCompilerOption(JSContext * cx,JSJitCompilerOption opt,uint32_t * valueOut)6370 JS_PUBLIC_API bool JS_GetGlobalJitCompilerOption(JSContext* cx,
6371 JSJitCompilerOption opt,
6372 uint32_t* valueOut) {
6373 MOZ_ASSERT(valueOut);
6374 #ifndef JS_CODEGEN_NONE
6375 JSRuntime* rt = cx->runtime();
6376 switch (opt) {
6377 case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER:
6378 *valueOut = jit::JitOptions.baselineWarmUpThreshold;
6379 break;
6380 case JSJITCOMPILER_ION_WARMUP_TRIGGER:
6381 *valueOut = jit::JitOptions.forcedDefaultIonWarmUpThreshold.valueOr(
6382 jit::OptimizationInfo::CompilerWarmupThreshold);
6383 break;
6384 case JSJITCOMPILER_ION_FORCE_IC:
6385 *valueOut = jit::JitOptions.forceInlineCaches;
6386 break;
6387 case JSJITCOMPILER_ION_CHECK_RANGE_ANALYSIS:
6388 *valueOut = jit::JitOptions.checkRangeAnalysis;
6389 break;
6390 case JSJITCOMPILER_ION_ENABLE:
6391 *valueOut = JS::ContextOptionsRef(cx).ion();
6392 break;
6393 case JSJITCOMPILER_BASELINE_ENABLE:
6394 *valueOut = JS::ContextOptionsRef(cx).baseline();
6395 break;
6396 case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE:
6397 *valueOut = rt->canUseOffthreadIonCompilation();
6398 break;
6399 case JSJITCOMPILER_ASMJS_ATOMICS_ENABLE:
6400 *valueOut = jit::JitOptions.asmJSAtomicsEnable ? 1 : 0;
6401 break;
6402 case JSJITCOMPILER_WASM_FOLD_OFFSETS:
6403 *valueOut = jit::JitOptions.wasmFoldOffsets ? 1 : 0;
6404 break;
6405 case JSJITCOMPILER_ION_INTERRUPT_WITHOUT_SIGNAL:
6406 *valueOut = jit::JitOptions.ionInterruptWithoutSignals ? 1 : 0;
6407 break;
6408 #ifdef DEBUG
6409 case JSJITCOMPILER_FULL_DEBUG_CHECKS:
6410 *valueOut = jit::JitOptions.fullDebugChecks ? 1 : 0;
6411 break;
6412 #endif
6413 default:
6414 return false;
6415 }
6416 #else
6417 *valueOut = 0;
6418 #endif
6419 return true;
6420 }
6421
6422 /************************************************************************/
6423
6424 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && \
6425 defined(XP_WIN)
6426
6427 #include "util/Windows.h"
6428
6429 /*
6430 * Initialization routine for the JS DLL.
6431 */
DllMain(HINSTANCE hDLL,DWORD dwReason,LPVOID lpReserved)6432 BOOL WINAPI DllMain(HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) {
6433 return TRUE;
6434 }
6435
6436 #endif
6437
JS_IndexToId(JSContext * cx,uint32_t index,MutableHandleId id)6438 JS_PUBLIC_API bool JS_IndexToId(JSContext* cx, uint32_t index,
6439 MutableHandleId id) {
6440 return IndexToId(cx, index, id);
6441 }
6442
JS_CharsToId(JSContext * cx,JS::TwoByteChars chars,MutableHandleId idp)6443 JS_PUBLIC_API bool JS_CharsToId(JSContext* cx, JS::TwoByteChars chars,
6444 MutableHandleId idp) {
6445 RootedAtom atom(cx, AtomizeChars(cx, chars.begin().get(), chars.length()));
6446 if (!atom) return false;
6447 #ifdef DEBUG
6448 uint32_t dummy;
6449 MOZ_ASSERT(!atom->isIndex(&dummy),
6450 "API misuse: |chars| must not encode an index");
6451 #endif
6452 idp.set(AtomToId(atom));
6453 return true;
6454 }
6455
JS_IsIdentifier(JSContext * cx,HandleString str,bool * isIdentifier)6456 JS_PUBLIC_API bool JS_IsIdentifier(JSContext* cx, HandleString str,
6457 bool* isIdentifier) {
6458 assertSameCompartment(cx, str);
6459
6460 JSLinearString* linearStr = str->ensureLinear(cx);
6461 if (!linearStr) return false;
6462
6463 *isIdentifier = js::frontend::IsIdentifier(linearStr);
6464 return true;
6465 }
6466
JS_IsIdentifier(const char16_t * chars,size_t length)6467 JS_PUBLIC_API bool JS_IsIdentifier(const char16_t* chars, size_t length) {
6468 return js::frontend::IsIdentifier(chars, length);
6469 }
6470
6471 namespace JS {
6472
reset()6473 void AutoFilename::reset() {
6474 if (ss_) {
6475 ss_->decref();
6476 ss_ = nullptr;
6477 }
6478 if (filename_.is<const char*>())
6479 filename_.as<const char*>() = nullptr;
6480 else
6481 filename_.as<UniqueChars>().reset();
6482 }
6483
setScriptSource(js::ScriptSource * p)6484 void AutoFilename::setScriptSource(js::ScriptSource* p) {
6485 MOZ_ASSERT(!ss_);
6486 MOZ_ASSERT(!get());
6487 ss_ = p;
6488 if (p) {
6489 p->incref();
6490 setUnowned(p->filename());
6491 }
6492 }
6493
setUnowned(const char * filename)6494 void AutoFilename::setUnowned(const char* filename) {
6495 MOZ_ASSERT(!get());
6496 filename_.as<const char*>() = filename ? filename : "";
6497 }
6498
setOwned(UniqueChars && filename)6499 void AutoFilename::setOwned(UniqueChars&& filename) {
6500 MOZ_ASSERT(!get());
6501 filename_ = AsVariant(Move(filename));
6502 }
6503
get() const6504 const char* AutoFilename::get() const {
6505 if (filename_.is<const char*>()) return filename_.as<const char*>();
6506 return filename_.as<UniqueChars>().get();
6507 }
6508
DescribeScriptedCaller(JSContext * cx,AutoFilename * filename,unsigned * lineno,unsigned * column)6509 JS_PUBLIC_API bool DescribeScriptedCaller(JSContext* cx, AutoFilename* filename,
6510 unsigned* lineno, unsigned* column) {
6511 if (filename) filename->reset();
6512 if (lineno) *lineno = 0;
6513 if (column) *column = 0;
6514
6515 if (!cx->compartment()) return false;
6516
6517 NonBuiltinFrameIter i(cx, cx->compartment()->principals());
6518 if (i.done()) return false;
6519
6520 // If the caller is hidden, the embedding wants us to return false here so
6521 // that it can check its own stack (see HideScriptedCaller).
6522 if (i.activation()->scriptedCallerIsHidden()) return false;
6523
6524 if (filename) {
6525 if (i.isWasm()) {
6526 // For Wasm, copy out the filename, there is no script source.
6527 UniqueChars copy = DuplicateString(i.filename() ? i.filename() : "");
6528 if (!copy)
6529 filename->setUnowned("out of memory");
6530 else
6531 filename->setOwned(Move(copy));
6532 } else {
6533 // All other frames have a script source to read the filename from.
6534 filename->setScriptSource(i.scriptSource());
6535 }
6536 }
6537
6538 if (lineno)
6539 *lineno = i.computeLine(column);
6540 else if (column)
6541 i.computeLine(column);
6542
6543 return true;
6544 }
6545
6546 // Fast path to get the activation to use for GetScriptedCallerGlobal. If this
6547 // returns false, the fast path didn't work out and the caller has to use the
6548 // (much slower) NonBuiltinFrameIter path.
6549 //
6550 // The optimization here is that we skip Ion-inlined frames and only look at
6551 // 'outer' frames. That's fine: each activation is tied to a single compartment,
6552 // so if an activation contains at least one non-self-hosted frame, we can use
6553 // the activation's global for GetScriptedCallerGlobal. If, however, all 'outer'
6554 // frames are self-hosted, it's possible Ion inlined a non-self-hosted script,
6555 // so we must return false and use the slower path.
GetScriptedCallerActivationFast(JSContext * cx,Activation ** activation)6556 static bool GetScriptedCallerActivationFast(JSContext* cx,
6557 Activation** activation) {
6558 ActivationIterator activationIter(cx);
6559
6560 if (activationIter.done()) {
6561 *activation = nullptr;
6562 return true;
6563 }
6564
6565 *activation = activationIter.activation();
6566
6567 if (activationIter->isJit()) {
6568 for (OnlyJSJitFrameIter iter(activationIter); !iter.done(); ++iter) {
6569 if (iter.frame().isScripted() && !iter.frame().script()->selfHosted())
6570 return true;
6571 }
6572 } else if (activationIter->isInterpreter()) {
6573 for (InterpreterFrameIterator iter((*activation)->asInterpreter());
6574 !iter.done(); ++iter) {
6575 if (!iter.frame()->script()->selfHosted()) return true;
6576 }
6577 }
6578
6579 return false;
6580 }
6581
GetScriptedCallerGlobal(JSContext * cx)6582 JS_PUBLIC_API JSObject* GetScriptedCallerGlobal(JSContext* cx) {
6583 Activation* activation;
6584
6585 if (GetScriptedCallerActivationFast(cx, &activation)) {
6586 if (!activation) return nullptr;
6587 } else {
6588 NonBuiltinFrameIter i(cx);
6589 if (i.done()) return nullptr;
6590 activation = i.activation();
6591 }
6592
6593 // If the caller is hidden, the embedding wants us to return null here so
6594 // that it can check its own stack (see HideScriptedCaller).
6595 if (activation->scriptedCallerIsHidden()) return nullptr;
6596
6597 GlobalObject* global = activation->compartment()->maybeGlobal();
6598
6599 // Noone should be running code in the atoms compartment or running code in
6600 // a compartment without any live objects, so there should definitely be a
6601 // live global.
6602 MOZ_ASSERT(global);
6603
6604 return global;
6605 }
6606
HideScriptedCaller(JSContext * cx)6607 JS_PUBLIC_API void HideScriptedCaller(JSContext* cx) {
6608 MOZ_ASSERT(cx);
6609
6610 // If there's no accessible activation on the stack, we'll return null from
6611 // DescribeScriptedCaller anyway, so there's no need to annotate anything.
6612 Activation* act = cx->activation();
6613 if (!act) return;
6614 act->hideScriptedCaller();
6615 }
6616
UnhideScriptedCaller(JSContext * cx)6617 JS_PUBLIC_API void UnhideScriptedCaller(JSContext* cx) {
6618 Activation* act = cx->activation();
6619 if (!act) return;
6620 act->unhideScriptedCaller();
6621 }
6622
6623 } /* namespace JS */
6624
6625 #ifdef JS_DEBUG
AssertArgumentsAreSane(JSContext * cx,HandleValue value)6626 JS_PUBLIC_API void JS::detail::AssertArgumentsAreSane(JSContext* cx,
6627 HandleValue value) {
6628 AssertHeapIsIdle();
6629 CHECK_REQUEST(cx);
6630 assertSameCompartment(cx, value);
6631 }
6632 #endif /* JS_DEBUG */
6633
EncodeScript(JSContext * cx,TranscodeBuffer & buffer,HandleScript scriptArg)6634 JS_PUBLIC_API JS::TranscodeResult JS::EncodeScript(JSContext* cx,
6635 TranscodeBuffer& buffer,
6636 HandleScript scriptArg) {
6637 XDREncoder encoder(cx, buffer, buffer.length());
6638 RootedScript script(cx, scriptArg);
6639 if (!encoder.codeScript(&script)) buffer.clearAndFree();
6640 MOZ_ASSERT(!buffer.empty() == (encoder.resultCode() == TranscodeResult_Ok));
6641 return encoder.resultCode();
6642 }
6643
EncodeInterpretedFunction(JSContext * cx,TranscodeBuffer & buffer,HandleObject funobjArg)6644 JS_PUBLIC_API JS::TranscodeResult JS::EncodeInterpretedFunction(
6645 JSContext* cx, TranscodeBuffer& buffer, HandleObject funobjArg) {
6646 XDREncoder encoder(cx, buffer, buffer.length());
6647 RootedFunction funobj(cx, &funobjArg->as<JSFunction>());
6648 if (!encoder.codeFunction(&funobj)) buffer.clearAndFree();
6649 MOZ_ASSERT(!buffer.empty() == (encoder.resultCode() == TranscodeResult_Ok));
6650 return encoder.resultCode();
6651 }
6652
DecodeScript(JSContext * cx,TranscodeBuffer & buffer,JS::MutableHandleScript scriptp,size_t cursorIndex)6653 JS_PUBLIC_API JS::TranscodeResult JS::DecodeScript(
6654 JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleScript scriptp,
6655 size_t cursorIndex) {
6656 XDRDecoder decoder(cx, buffer, cursorIndex);
6657 decoder.codeScript(scriptp);
6658 MOZ_ASSERT(bool(scriptp) == (decoder.resultCode() == TranscodeResult_Ok));
6659 return decoder.resultCode();
6660 }
6661
DecodeScript(JSContext * cx,const TranscodeRange & range,JS::MutableHandleScript scriptp)6662 JS_PUBLIC_API JS::TranscodeResult JS::DecodeScript(
6663 JSContext* cx, const TranscodeRange& range,
6664 JS::MutableHandleScript scriptp) {
6665 XDRDecoder decoder(cx, range);
6666 decoder.codeScript(scriptp);
6667 MOZ_ASSERT(bool(scriptp) == (decoder.resultCode() == TranscodeResult_Ok));
6668 return decoder.resultCode();
6669 }
6670
DecodeInterpretedFunction(JSContext * cx,TranscodeBuffer & buffer,JS::MutableHandleFunction funp,size_t cursorIndex)6671 JS_PUBLIC_API JS::TranscodeResult JS::DecodeInterpretedFunction(
6672 JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleFunction funp,
6673 size_t cursorIndex) {
6674 XDRDecoder decoder(cx, buffer, cursorIndex);
6675 decoder.codeFunction(funp);
6676 MOZ_ASSERT(bool(funp) == (decoder.resultCode() == TranscodeResult_Ok));
6677 return decoder.resultCode();
6678 }
6679
StartIncrementalEncoding(JSContext * cx,JS::HandleScript script)6680 JS_PUBLIC_API bool JS::StartIncrementalEncoding(JSContext* cx,
6681 JS::HandleScript script) {
6682 if (!script) return false;
6683 if (!script->scriptSource()->xdrEncodeTopLevel(cx, script)) return false;
6684 return true;
6685 }
6686
FinishIncrementalEncoding(JSContext * cx,JS::HandleScript script,TranscodeBuffer & buffer)6687 JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx,
6688 JS::HandleScript script,
6689 TranscodeBuffer& buffer) {
6690 if (!script) return false;
6691 if (!script->scriptSource()->xdrFinalizeEncoder(buffer)) return false;
6692 return true;
6693 }
6694
SetBuildIdOp(JSContext * cx,JS::BuildIdOp buildIdOp)6695 JS_PUBLIC_API void JS::SetBuildIdOp(JSContext* cx, JS::BuildIdOp buildIdOp) {
6696 cx->runtime()->buildIdOp = buildIdOp;
6697 }
6698
SetAsmJSCacheOps(JSContext * cx,const JS::AsmJSCacheOps * ops)6699 JS_PUBLIC_API void JS::SetAsmJSCacheOps(JSContext* cx,
6700 const JS::AsmJSCacheOps* ops) {
6701 cx->runtime()->asmJSCacheOps = *ops;
6702 }
6703
IsWasmModuleObject(HandleObject obj)6704 bool JS::IsWasmModuleObject(HandleObject obj) {
6705 JSObject* unwrapped = CheckedUnwrap(obj);
6706 if (!unwrapped) return false;
6707 return unwrapped->is<WasmModuleObject>();
6708 }
6709
GetWasmModule(HandleObject obj)6710 JS_PUBLIC_API RefPtr<JS::WasmModule> JS::GetWasmModule(HandleObject obj) {
6711 MOZ_ASSERT(JS::IsWasmModuleObject(obj));
6712 return &CheckedUnwrap(obj)->as<WasmModuleObject>().module();
6713 }
6714
CompiledWasmModuleAssumptionsMatch(PRFileDesc * compiled,JS::BuildIdCharVector && buildId)6715 JS_PUBLIC_API bool JS::CompiledWasmModuleAssumptionsMatch(
6716 PRFileDesc* compiled, JS::BuildIdCharVector&& buildId) {
6717 return wasm::CompiledModuleAssumptionsMatch(compiled, Move(buildId));
6718 }
6719
DeserializeWasmModule(PRFileDesc * bytecode,PRFileDesc * maybeCompiled,JS::BuildIdCharVector && buildId,UniqueChars file,unsigned line,unsigned column)6720 JS_PUBLIC_API RefPtr<JS::WasmModule> JS::DeserializeWasmModule(
6721 PRFileDesc* bytecode, PRFileDesc* maybeCompiled,
6722 JS::BuildIdCharVector&& buildId, UniqueChars file, unsigned line,
6723 unsigned column) {
6724 return wasm::DeserializeModule(bytecode, maybeCompiled, Move(buildId),
6725 Move(file), line, column);
6726 }
6727
SetProcessLargeAllocationFailureCallback(JS::LargeAllocationFailureCallback lafc)6728 JS_PUBLIC_API void JS::SetProcessLargeAllocationFailureCallback(
6729 JS::LargeAllocationFailureCallback lafc) {
6730 MOZ_ASSERT(!OnLargeAllocationFailure);
6731 OnLargeAllocationFailure = lafc;
6732 }
6733
SetOutOfMemoryCallback(JSContext * cx,OutOfMemoryCallback cb,void * data)6734 JS_PUBLIC_API void JS::SetOutOfMemoryCallback(JSContext* cx,
6735 OutOfMemoryCallback cb,
6736 void* data) {
6737 cx->runtime()->oomCallback = cb;
6738 cx->runtime()->oomCallbackData = data;
6739 }
6740
FirstSubsumedFrame(JSContext * cx,bool ignoreSelfHostedFrames)6741 JS::FirstSubsumedFrame::FirstSubsumedFrame(
6742 JSContext* cx, bool ignoreSelfHostedFrames /* = true */)
6743 : JS::FirstSubsumedFrame(cx, cx->compartment()->principals(),
6744 ignoreSelfHostedFrames) {}
6745
CaptureCurrentStack(JSContext * cx,JS::MutableHandleObject stackp,JS::StackCapture && capture)6746 JS_PUBLIC_API bool JS::CaptureCurrentStack(
6747 JSContext* cx, JS::MutableHandleObject stackp,
6748 JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */) {
6749 AssertHeapIsIdle();
6750 CHECK_REQUEST(cx);
6751 MOZ_RELEASE_ASSERT(cx->compartment());
6752
6753 JSCompartment* compartment = cx->compartment();
6754 Rooted<SavedFrame*> frame(cx);
6755 if (!compartment->savedStacks().saveCurrentStack(cx, &frame,
6756 mozilla::Move(capture)))
6757 return false;
6758 stackp.set(frame.get());
6759 return true;
6760 }
6761
CopyAsyncStack(JSContext * cx,JS::HandleObject asyncStack,JS::HandleString asyncCause,JS::MutableHandleObject stackp,const Maybe<size_t> & maxFrameCount)6762 JS_PUBLIC_API bool JS::CopyAsyncStack(JSContext* cx,
6763 JS::HandleObject asyncStack,
6764 JS::HandleString asyncCause,
6765 JS::MutableHandleObject stackp,
6766 const Maybe<size_t>& maxFrameCount) {
6767 AssertHeapIsIdle();
6768 CHECK_REQUEST(cx);
6769 MOZ_RELEASE_ASSERT(cx->compartment());
6770
6771 js::AssertObjectIsSavedFrameOrWrapper(cx, asyncStack);
6772 JSCompartment* compartment = cx->compartment();
6773 Rooted<SavedFrame*> frame(cx);
6774 if (!compartment->savedStacks().copyAsyncStack(cx, asyncStack, asyncCause,
6775 &frame, maxFrameCount))
6776 return false;
6777 stackp.set(frame.get());
6778 return true;
6779 }
6780
GetObjectZone(JSObject * obj)6781 JS_PUBLIC_API Zone* JS::GetObjectZone(JSObject* obj) { return obj->zone(); }
6782
GetNurseryStringZone(JSString * str)6783 JS_PUBLIC_API Zone* JS::GetNurseryStringZone(JSString* str) {
6784 MOZ_ASSERT(!str->isTenured());
6785 return str->zone();
6786 }
6787
GCThingTraceKind(void * thing)6788 JS_PUBLIC_API JS::TraceKind JS::GCThingTraceKind(void* thing) {
6789 MOZ_ASSERT(thing);
6790 return static_cast<js::gc::Cell*>(thing)->getTraceKind();
6791 }
6792
SetStackFormat(JSContext * cx,js::StackFormat format)6793 JS_PUBLIC_API void js::SetStackFormat(JSContext* cx, js::StackFormat format) {
6794 cx->runtime()->setStackFormat(format);
6795 }
6796
GetStackFormat(JSContext * cx)6797 JS_PUBLIC_API js::StackFormat js::GetStackFormat(JSContext* cx) {
6798 return cx->runtime()->stackFormat();
6799 }
6800
6801 namespace js {
6802
NoteIntentionalCrash()6803 JS_PUBLIC_API void NoteIntentionalCrash() {
6804 #ifdef __linux__
6805 static bool* addr =
6806 reinterpret_cast<bool*>(dlsym(RTLD_DEFAULT, "gBreakpadInjectorEnabled"));
6807 if (addr) *addr = false;
6808 #endif
6809 }
6810
6811 } // namespace js
6812