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, &parameterListEnd)) {
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