|
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 #include "jsfriendapi.h" |
|
8 |
|
9 #include "mozilla/PodOperations.h" |
|
10 |
|
11 #include <stdint.h> |
|
12 |
|
13 #include "jscntxt.h" |
|
14 #include "jscompartment.h" |
|
15 #include "jsgc.h" |
|
16 #include "jsobj.h" |
|
17 #include "jsproxy.h" |
|
18 #include "jswatchpoint.h" |
|
19 #include "jsweakmap.h" |
|
20 #include "jswrapper.h" |
|
21 #include "prmjtime.h" |
|
22 |
|
23 #include "builtin/TestingFunctions.h" |
|
24 #include "vm/WrapperObject.h" |
|
25 |
|
26 #include "jsobjinlines.h" |
|
27 |
|
28 #include "vm/ScopeObject-inl.h" |
|
29 |
|
30 using namespace js; |
|
31 using namespace JS; |
|
32 |
|
33 using mozilla::PodArrayZero; |
|
34 |
|
35 // Required by PerThreadDataFriendFields::getMainThread() |
|
36 JS_STATIC_ASSERT(offsetof(JSRuntime, mainThread) == |
|
37 PerThreadDataFriendFields::RuntimeMainThreadOffset); |
|
38 |
|
39 PerThreadDataFriendFields::PerThreadDataFriendFields() |
|
40 { |
|
41 PodArrayZero(nativeStackLimit); |
|
42 #if JS_STACK_GROWTH_DIRECTION > 0 |
|
43 for (int i=0; i<StackKindCount; i++) |
|
44 nativeStackLimit[i] = UINTPTR_MAX; |
|
45 #endif |
|
46 #if defined(JSGC_USE_EXACT_ROOTING) |
|
47 PodArrayZero(thingGCRooters); |
|
48 #endif |
|
49 } |
|
50 |
|
51 JS_FRIEND_API(void) |
|
52 js::SetSourceHook(JSRuntime *rt, SourceHook *hook) |
|
53 { |
|
54 rt->sourceHook = hook; |
|
55 } |
|
56 |
|
57 JS_FRIEND_API(SourceHook *) |
|
58 js::ForgetSourceHook(JSRuntime *rt) |
|
59 { |
|
60 return rt->sourceHook.forget(); |
|
61 } |
|
62 |
|
63 JS_FRIEND_API(void) |
|
64 JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data) |
|
65 { |
|
66 rt->gcGrayRootTracer.op = traceOp; |
|
67 rt->gcGrayRootTracer.data = data; |
|
68 } |
|
69 |
|
70 JS_FRIEND_API(JSString *) |
|
71 JS_GetAnonymousString(JSRuntime *rt) |
|
72 { |
|
73 JS_ASSERT(rt->hasContexts()); |
|
74 return rt->commonNames->anonymous; |
|
75 } |
|
76 |
|
77 JS_FRIEND_API(void) |
|
78 JS_SetIsWorkerRuntime(JSRuntime *rt) |
|
79 { |
|
80 rt->setIsWorkerRuntime(); |
|
81 } |
|
82 |
|
83 JS_FRIEND_API(JSObject *) |
|
84 JS_FindCompilationScope(JSContext *cx, HandleObject objArg) |
|
85 { |
|
86 RootedObject obj(cx, objArg); |
|
87 |
|
88 /* |
|
89 * We unwrap wrappers here. This is a little weird, but it's what's being |
|
90 * asked of us. |
|
91 */ |
|
92 if (obj->is<WrapperObject>()) |
|
93 obj = UncheckedUnwrap(obj); |
|
94 |
|
95 /* |
|
96 * Innerize the target_obj so that we compile in the correct (inner) |
|
97 * scope. |
|
98 */ |
|
99 if (JSObjectOp op = obj->getClass()->ext.innerObject) |
|
100 obj = op(cx, obj); |
|
101 return obj; |
|
102 } |
|
103 |
|
104 JS_FRIEND_API(JSFunction *) |
|
105 JS_GetObjectFunction(JSObject *obj) |
|
106 { |
|
107 if (obj->is<JSFunction>()) |
|
108 return &obj->as<JSFunction>(); |
|
109 return nullptr; |
|
110 } |
|
111 |
|
112 JS_FRIEND_API(bool) |
|
113 JS_SplicePrototype(JSContext *cx, HandleObject obj, HandleObject proto) |
|
114 { |
|
115 /* |
|
116 * Change the prototype of an object which hasn't been used anywhere |
|
117 * and does not share its type with another object. Unlike JS_SetPrototype, |
|
118 * does not nuke type information for the object. |
|
119 */ |
|
120 CHECK_REQUEST(cx); |
|
121 |
|
122 if (!obj->hasSingletonType()) { |
|
123 /* |
|
124 * We can see non-singleton objects when trying to splice prototypes |
|
125 * due to mutable __proto__ (ugh). |
|
126 */ |
|
127 return JS_SetPrototype(cx, obj, proto); |
|
128 } |
|
129 |
|
130 Rooted<TaggedProto> tagged(cx, TaggedProto(proto)); |
|
131 return obj->splicePrototype(cx, obj->getClass(), tagged); |
|
132 } |
|
133 |
|
134 JS_FRIEND_API(JSObject *) |
|
135 JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, HandleObject proto, |
|
136 HandleObject parent) |
|
137 { |
|
138 /* |
|
139 * Create our object with a null proto and then splice in the correct proto |
|
140 * after we setSingletonType, so that we don't pollute the default |
|
141 * TypeObject attached to our proto with information about our object, since |
|
142 * we're not going to be using that TypeObject anyway. |
|
143 */ |
|
144 RootedObject obj(cx, NewObjectWithGivenProto(cx, (const js::Class *)clasp, nullptr, |
|
145 parent, SingletonObject)); |
|
146 if (!obj) |
|
147 return nullptr; |
|
148 if (!JS_SplicePrototype(cx, obj, proto)) |
|
149 return nullptr; |
|
150 return obj; |
|
151 } |
|
152 |
|
153 JS_FRIEND_API(void) |
|
154 JS::PrepareZoneForGC(Zone *zone) |
|
155 { |
|
156 zone->scheduleGC(); |
|
157 } |
|
158 |
|
159 JS_FRIEND_API(void) |
|
160 JS::PrepareForFullGC(JSRuntime *rt) |
|
161 { |
|
162 for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) |
|
163 zone->scheduleGC(); |
|
164 } |
|
165 |
|
166 JS_FRIEND_API(void) |
|
167 JS::PrepareForIncrementalGC(JSRuntime *rt) |
|
168 { |
|
169 if (!JS::IsIncrementalGCInProgress(rt)) |
|
170 return; |
|
171 |
|
172 for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { |
|
173 if (zone->wasGCStarted()) |
|
174 PrepareZoneForGC(zone); |
|
175 } |
|
176 } |
|
177 |
|
178 JS_FRIEND_API(bool) |
|
179 JS::IsGCScheduled(JSRuntime *rt) |
|
180 { |
|
181 for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { |
|
182 if (zone->isGCScheduled()) |
|
183 return true; |
|
184 } |
|
185 |
|
186 return false; |
|
187 } |
|
188 |
|
189 JS_FRIEND_API(void) |
|
190 JS::SkipZoneForGC(Zone *zone) |
|
191 { |
|
192 zone->unscheduleGC(); |
|
193 } |
|
194 |
|
195 JS_FRIEND_API(void) |
|
196 JS::GCForReason(JSRuntime *rt, gcreason::Reason reason) |
|
197 { |
|
198 GC(rt, GC_NORMAL, reason); |
|
199 } |
|
200 |
|
201 JS_FRIEND_API(void) |
|
202 JS::ShrinkingGC(JSRuntime *rt, gcreason::Reason reason) |
|
203 { |
|
204 GC(rt, GC_SHRINK, reason); |
|
205 } |
|
206 |
|
207 JS_FRIEND_API(void) |
|
208 JS::IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis) |
|
209 { |
|
210 GCSlice(rt, GC_NORMAL, reason, millis); |
|
211 } |
|
212 |
|
213 JS_FRIEND_API(void) |
|
214 JS::FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason) |
|
215 { |
|
216 GCFinalSlice(rt, GC_NORMAL, reason); |
|
217 } |
|
218 |
|
219 JS_FRIEND_API(JSPrincipals *) |
|
220 JS_GetCompartmentPrincipals(JSCompartment *compartment) |
|
221 { |
|
222 return compartment->principals; |
|
223 } |
|
224 |
|
225 JS_FRIEND_API(void) |
|
226 JS_SetCompartmentPrincipals(JSCompartment *compartment, JSPrincipals *principals) |
|
227 { |
|
228 // Short circuit if there's no change. |
|
229 if (principals == compartment->principals) |
|
230 return; |
|
231 |
|
232 // Any compartment with the trusted principals -- and there can be |
|
233 // multiple -- is a system compartment. |
|
234 const JSPrincipals *trusted = compartment->runtimeFromMainThread()->trustedPrincipals(); |
|
235 bool isSystem = principals && principals == trusted; |
|
236 |
|
237 // Clear out the old principals, if any. |
|
238 if (compartment->principals) { |
|
239 JS_DropPrincipals(compartment->runtimeFromMainThread(), compartment->principals); |
|
240 compartment->principals = nullptr; |
|
241 // We'd like to assert that our new principals is always same-origin |
|
242 // with the old one, but JSPrincipals doesn't give us a way to do that. |
|
243 // But we can at least assert that we're not switching between system |
|
244 // and non-system. |
|
245 JS_ASSERT(compartment->isSystem == isSystem); |
|
246 } |
|
247 |
|
248 // Set up the new principals. |
|
249 if (principals) { |
|
250 JS_HoldPrincipals(principals); |
|
251 compartment->principals = principals; |
|
252 } |
|
253 |
|
254 // Update the system flag. |
|
255 compartment->isSystem = isSystem; |
|
256 } |
|
257 |
|
258 JS_FRIEND_API(bool) |
|
259 JS_WrapPropertyDescriptor(JSContext *cx, JS::MutableHandle<js::PropertyDescriptor> desc) |
|
260 { |
|
261 return cx->compartment()->wrap(cx, desc); |
|
262 } |
|
263 |
|
264 JS_FRIEND_API(bool) |
|
265 JS_WrapAutoIdVector(JSContext *cx, js::AutoIdVector &props) |
|
266 { |
|
267 return cx->compartment()->wrap(cx, props); |
|
268 } |
|
269 |
|
270 JS_FRIEND_API(void) |
|
271 JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape) |
|
272 { |
|
273 MarkCycleCollectorChildren(trc, static_cast<Shape *>(shape)); |
|
274 } |
|
275 |
|
276 static bool |
|
277 DefineHelpProperty(JSContext *cx, HandleObject obj, const char *prop, const char *value) |
|
278 { |
|
279 RootedAtom atom(cx, Atomize(cx, value, strlen(value))); |
|
280 if (!atom) |
|
281 return false; |
|
282 return JS_DefineProperty(cx, obj, prop, atom, JSPROP_READONLY | JSPROP_PERMANENT, |
|
283 JS_PropertyStub, JS_StrictPropertyStub); |
|
284 } |
|
285 |
|
286 JS_FRIEND_API(bool) |
|
287 JS_DefineFunctionsWithHelp(JSContext *cx, HandleObject obj, const JSFunctionSpecWithHelp *fs) |
|
288 { |
|
289 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
290 |
|
291 CHECK_REQUEST(cx); |
|
292 assertSameCompartment(cx, obj); |
|
293 for (; fs->name; fs++) { |
|
294 JSAtom *atom = Atomize(cx, fs->name, strlen(fs->name)); |
|
295 if (!atom) |
|
296 return false; |
|
297 |
|
298 Rooted<jsid> id(cx, AtomToId(atom)); |
|
299 RootedFunction fun(cx, DefineFunction(cx, obj, id, fs->call, fs->nargs, fs->flags)); |
|
300 if (!fun) |
|
301 return false; |
|
302 |
|
303 if (fs->usage) { |
|
304 if (!DefineHelpProperty(cx, fun, "usage", fs->usage)) |
|
305 return false; |
|
306 } |
|
307 |
|
308 if (fs->help) { |
|
309 if (!DefineHelpProperty(cx, fun, "help", fs->help)) |
|
310 return false; |
|
311 } |
|
312 } |
|
313 |
|
314 return true; |
|
315 } |
|
316 |
|
317 JS_FRIEND_API(bool) |
|
318 js_ObjectClassIs(JSContext *cx, HandleObject obj, ESClassValue classValue) |
|
319 { |
|
320 return ObjectClassIs(obj, classValue, cx); |
|
321 } |
|
322 |
|
323 JS_FRIEND_API(const char *) |
|
324 js_ObjectClassName(JSContext *cx, HandleObject obj) |
|
325 { |
|
326 return JSObject::className(cx, obj); |
|
327 } |
|
328 |
|
329 JS_FRIEND_API(JS::Zone *) |
|
330 js::GetCompartmentZone(JSCompartment *comp) |
|
331 { |
|
332 return comp->zone(); |
|
333 } |
|
334 |
|
335 JS_FRIEND_API(bool) |
|
336 js::IsSystemCompartment(JSCompartment *comp) |
|
337 { |
|
338 return comp->isSystem; |
|
339 } |
|
340 |
|
341 JS_FRIEND_API(bool) |
|
342 js::IsSystemZone(Zone *zone) |
|
343 { |
|
344 return zone->isSystem; |
|
345 } |
|
346 |
|
347 JS_FRIEND_API(bool) |
|
348 js::IsAtomsCompartment(JSCompartment *comp) |
|
349 { |
|
350 return comp->runtimeFromAnyThread()->isAtomsCompartment(comp); |
|
351 } |
|
352 |
|
353 JS_FRIEND_API(bool) |
|
354 js::IsInNonStrictPropertySet(JSContext *cx) |
|
355 { |
|
356 jsbytecode *pc; |
|
357 JSScript *script = cx->currentScript(&pc, JSContext::ALLOW_CROSS_COMPARTMENT); |
|
358 return script && !script->strict() && (js_CodeSpec[*pc].format & JOF_SET); |
|
359 } |
|
360 |
|
361 JS_FRIEND_API(bool) |
|
362 js::IsFunctionObject(JSObject *obj) |
|
363 { |
|
364 return obj->is<JSFunction>(); |
|
365 } |
|
366 |
|
367 JS_FRIEND_API(bool) |
|
368 js::IsScopeObject(JSObject *obj) |
|
369 { |
|
370 return obj->is<ScopeObject>(); |
|
371 } |
|
372 |
|
373 JS_FRIEND_API(bool) |
|
374 js::IsCallObject(JSObject *obj) |
|
375 { |
|
376 return obj->is<CallObject>(); |
|
377 } |
|
378 |
|
379 JS_FRIEND_API(JSObject *) |
|
380 js::GetObjectParentMaybeScope(JSObject *obj) |
|
381 { |
|
382 return obj->enclosingScope(); |
|
383 } |
|
384 |
|
385 JS_FRIEND_API(JSObject *) |
|
386 js::GetGlobalForObjectCrossCompartment(JSObject *obj) |
|
387 { |
|
388 return &obj->global(); |
|
389 } |
|
390 |
|
391 JS_FRIEND_API(void) |
|
392 js::SetPendingExceptionCrossContext(JSContext *cx, JS::HandleValue v) |
|
393 { |
|
394 cx->setPendingException(v); |
|
395 } |
|
396 |
|
397 JS_FRIEND_API(void) |
|
398 js::AssertSameCompartment(JSContext *cx, JSObject *obj) |
|
399 { |
|
400 assertSameCompartment(cx, obj); |
|
401 } |
|
402 |
|
403 #ifdef DEBUG |
|
404 JS_FRIEND_API(void) |
|
405 js::AssertSameCompartment(JSObject *objA, JSObject *objB) |
|
406 { |
|
407 JS_ASSERT(objA->compartment() == objB->compartment()); |
|
408 } |
|
409 #endif |
|
410 |
|
411 JS_FRIEND_API(JSObject *) |
|
412 js::DefaultObjectForContextOrNull(JSContext *cx) |
|
413 { |
|
414 if (cx->options().noDefaultCompartmentObject()) |
|
415 return nullptr; |
|
416 return cx->maybeDefaultCompartmentObject(); |
|
417 } |
|
418 |
|
419 JS_FRIEND_API(void) |
|
420 js::SetDefaultObjectForContext(JSContext *cx, JSObject *obj) |
|
421 { |
|
422 cx->setDefaultCompartmentObject(obj); |
|
423 } |
|
424 |
|
425 JS_FRIEND_API(void) |
|
426 js::NotifyAnimationActivity(JSObject *obj) |
|
427 { |
|
428 obj->compartment()->lastAnimationTime = PRMJ_Now(); |
|
429 } |
|
430 |
|
431 JS_FRIEND_API(uint32_t) |
|
432 js::GetObjectSlotSpan(JSObject *obj) |
|
433 { |
|
434 return obj->slotSpan(); |
|
435 } |
|
436 |
|
437 JS_FRIEND_API(bool) |
|
438 js::IsObjectInContextCompartment(JSObject *obj, const JSContext *cx) |
|
439 { |
|
440 return obj->compartment() == cx->compartment(); |
|
441 } |
|
442 |
|
443 JS_FRIEND_API(bool) |
|
444 js::RunningWithTrustedPrincipals(JSContext *cx) |
|
445 { |
|
446 return cx->runningWithTrustedPrincipals(); |
|
447 } |
|
448 |
|
449 JS_FRIEND_API(JSScript *) |
|
450 js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx) |
|
451 { |
|
452 ScriptFrameIter iter(cx); |
|
453 if (iter.done()) |
|
454 return nullptr; |
|
455 |
|
456 if (!iter.isFunctionFrame()) |
|
457 return nullptr; |
|
458 |
|
459 RootedFunction scriptedCaller(cx, iter.callee()); |
|
460 RootedScript outermost(cx, scriptedCaller->nonLazyScript()); |
|
461 for (StaticScopeIter<NoGC> i(scriptedCaller); !i.done(); i++) { |
|
462 if (i.type() == StaticScopeIter<NoGC>::FUNCTION) |
|
463 outermost = i.funScript(); |
|
464 } |
|
465 return outermost; |
|
466 } |
|
467 |
|
468 JS_FRIEND_API(JSFunction *) |
|
469 js::DefineFunctionWithReserved(JSContext *cx, JSObject *objArg, const char *name, JSNative call, |
|
470 unsigned nargs, unsigned attrs) |
|
471 { |
|
472 RootedObject obj(cx, objArg); |
|
473 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
474 CHECK_REQUEST(cx); |
|
475 assertSameCompartment(cx, obj); |
|
476 JSAtom *atom = Atomize(cx, name, strlen(name)); |
|
477 if (!atom) |
|
478 return nullptr; |
|
479 Rooted<jsid> id(cx, AtomToId(atom)); |
|
480 return DefineFunction(cx, obj, id, call, nargs, attrs, JSFunction::ExtendedFinalizeKind); |
|
481 } |
|
482 |
|
483 JS_FRIEND_API(JSFunction *) |
|
484 js::NewFunctionWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, |
|
485 JSObject *parentArg, const char *name) |
|
486 { |
|
487 RootedObject parent(cx, parentArg); |
|
488 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
489 |
|
490 CHECK_REQUEST(cx); |
|
491 assertSameCompartment(cx, parent); |
|
492 |
|
493 RootedAtom atom(cx); |
|
494 if (name) { |
|
495 atom = Atomize(cx, name, strlen(name)); |
|
496 if (!atom) |
|
497 return nullptr; |
|
498 } |
|
499 |
|
500 JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags); |
|
501 return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom, |
|
502 JSFunction::ExtendedFinalizeKind); |
|
503 } |
|
504 |
|
505 JS_FRIEND_API(JSFunction *) |
|
506 js::NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parentArg, |
|
507 jsid id) |
|
508 { |
|
509 RootedObject parent(cx, parentArg); |
|
510 JS_ASSERT(JSID_IS_STRING(id)); |
|
511 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); |
|
512 CHECK_REQUEST(cx); |
|
513 assertSameCompartment(cx, parent); |
|
514 |
|
515 RootedAtom atom(cx, JSID_TO_ATOM(id)); |
|
516 JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags); |
|
517 return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom, |
|
518 JSFunction::ExtendedFinalizeKind); |
|
519 } |
|
520 |
|
521 JS_FRIEND_API(JSObject *) |
|
522 js::InitClassWithReserved(JSContext *cx, JSObject *objArg, JSObject *parent_protoArg, |
|
523 const JSClass *clasp, JSNative constructor, unsigned nargs, |
|
524 const JSPropertySpec *ps, const JSFunctionSpec *fs, |
|
525 const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs) |
|
526 { |
|
527 RootedObject obj(cx, objArg); |
|
528 RootedObject parent_proto(cx, parent_protoArg); |
|
529 CHECK_REQUEST(cx); |
|
530 assertSameCompartment(cx, obj, parent_proto); |
|
531 return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor, |
|
532 nargs, ps, fs, static_ps, static_fs, nullptr, |
|
533 JSFunction::ExtendedFinalizeKind); |
|
534 } |
|
535 |
|
536 JS_FRIEND_API(const Value &) |
|
537 js::GetFunctionNativeReserved(JSObject *fun, size_t which) |
|
538 { |
|
539 JS_ASSERT(fun->as<JSFunction>().isNative()); |
|
540 return fun->as<JSFunction>().getExtendedSlot(which); |
|
541 } |
|
542 |
|
543 JS_FRIEND_API(void) |
|
544 js::SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val) |
|
545 { |
|
546 JS_ASSERT(fun->as<JSFunction>().isNative()); |
|
547 MOZ_ASSERT_IF(val.isObject(), val.toObject().compartment() == fun->compartment()); |
|
548 fun->as<JSFunction>().setExtendedSlot(which, val); |
|
549 } |
|
550 |
|
551 JS_FRIEND_API(bool) |
|
552 js::GetObjectProto(JSContext *cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JSObject*> proto) |
|
553 { |
|
554 if (IsProxy(obj)) |
|
555 return JS_GetPrototype(cx, obj, proto); |
|
556 |
|
557 proto.set(reinterpret_cast<const shadow::Object*>(obj.get())->type->proto); |
|
558 return true; |
|
559 } |
|
560 |
|
561 JS_FRIEND_API(bool) |
|
562 js::GetOriginalEval(JSContext *cx, HandleObject scope, MutableHandleObject eval) |
|
563 { |
|
564 assertSameCompartment(cx, scope); |
|
565 Rooted<GlobalObject *> global(cx, &scope->global()); |
|
566 return GlobalObject::getOrCreateEval(cx, global, eval); |
|
567 } |
|
568 |
|
569 JS_FRIEND_API(void) |
|
570 js::SetReservedSlotWithBarrier(JSObject *obj, size_t slot, const js::Value &value) |
|
571 { |
|
572 obj->setSlot(slot, value); |
|
573 } |
|
574 |
|
575 JS_FRIEND_API(bool) |
|
576 js::GetGeneric(JSContext *cx, JSObject *objArg, JSObject *receiverArg, jsid idArg, |
|
577 Value *vp) |
|
578 { |
|
579 RootedObject obj(cx, objArg), receiver(cx, receiverArg); |
|
580 RootedId id(cx, idArg); |
|
581 RootedValue value(cx); |
|
582 if (!JSObject::getGeneric(cx, obj, receiver, id, &value)) |
|
583 return false; |
|
584 *vp = value; |
|
585 return true; |
|
586 } |
|
587 |
|
588 void |
|
589 js::SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback) |
|
590 { |
|
591 rt->preserveWrapperCallback = callback; |
|
592 } |
|
593 |
|
594 /* |
|
595 * The below code is for temporary telemetry use. It can be removed when |
|
596 * sufficient data has been harvested. |
|
597 */ |
|
598 |
|
599 namespace js { |
|
600 // Defined in vm/GlobalObject.cpp. |
|
601 extern size_t sSetProtoCalled; |
|
602 } |
|
603 |
|
604 JS_FRIEND_API(size_t) |
|
605 JS_SetProtoCalled(JSContext *) |
|
606 { |
|
607 return sSetProtoCalled; |
|
608 } |
|
609 |
|
610 // Defined in jsiter.cpp. |
|
611 extern size_t sCustomIteratorCount; |
|
612 |
|
613 JS_FRIEND_API(size_t) |
|
614 JS_GetCustomIteratorCount(JSContext *cx) |
|
615 { |
|
616 return sCustomIteratorCount; |
|
617 } |
|
618 |
|
619 JS_FRIEND_API(bool) |
|
620 JS_IsDeadWrapper(JSObject *obj) |
|
621 { |
|
622 if (!obj->is<ProxyObject>()) { |
|
623 return false; |
|
624 } |
|
625 |
|
626 return obj->as<ProxyObject>().handler()->family() == &DeadObjectProxy::sDeadObjectFamily; |
|
627 } |
|
628 |
|
629 void |
|
630 js::TraceWeakMaps(WeakMapTracer *trc) |
|
631 { |
|
632 WeakMapBase::traceAllMappings(trc); |
|
633 WatchpointMap::traceAll(trc); |
|
634 } |
|
635 |
|
636 extern JS_FRIEND_API(bool) |
|
637 js::AreGCGrayBitsValid(JSRuntime *rt) |
|
638 { |
|
639 return rt->gcGrayBitsValid; |
|
640 } |
|
641 |
|
642 JS_FRIEND_API(bool) |
|
643 js::ZoneGlobalsAreAllGray(JS::Zone *zone) |
|
644 { |
|
645 for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { |
|
646 JSObject *obj = comp->maybeGlobal(); |
|
647 if (!obj || !JS::GCThingIsMarkedGray(obj)) |
|
648 return false; |
|
649 } |
|
650 return true; |
|
651 } |
|
652 |
|
653 JS_FRIEND_API(JSGCTraceKind) |
|
654 js::GCThingTraceKind(void *thing) |
|
655 { |
|
656 JS_ASSERT(thing); |
|
657 return gc::GetGCThingTraceKind(thing); |
|
658 } |
|
659 |
|
660 JS_FRIEND_API(void) |
|
661 js::VisitGrayWrapperTargets(Zone *zone, GCThingCallback callback, void *closure) |
|
662 { |
|
663 JSRuntime *rt = zone->runtimeFromMainThread(); |
|
664 for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { |
|
665 for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) { |
|
666 gc::Cell *thing = e.front().key().wrapped; |
|
667 if (!IsInsideNursery(rt, thing) && thing->isMarked(gc::GRAY)) |
|
668 callback(closure, thing); |
|
669 } |
|
670 } |
|
671 } |
|
672 |
|
673 JS_FRIEND_API(JSObject *) |
|
674 js::GetWeakmapKeyDelegate(JSObject *key) |
|
675 { |
|
676 if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) |
|
677 return op(key); |
|
678 return nullptr; |
|
679 } |
|
680 |
|
681 JS_FRIEND_API(void) |
|
682 JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback) |
|
683 { |
|
684 rt->telemetryCallback = callback; |
|
685 } |
|
686 |
|
687 JS_FRIEND_API(JSObject *) |
|
688 JS_CloneObject(JSContext *cx, HandleObject obj, HandleObject protoArg, HandleObject parent) |
|
689 { |
|
690 Rooted<js::TaggedProto> proto(cx, protoArg.get()); |
|
691 return CloneObject(cx, obj, proto, parent); |
|
692 } |
|
693 |
|
694 #ifdef DEBUG |
|
695 JS_FRIEND_API(void) |
|
696 js_DumpString(JSString *str) |
|
697 { |
|
698 str->dump(); |
|
699 } |
|
700 |
|
701 JS_FRIEND_API(void) |
|
702 js_DumpAtom(JSAtom *atom) |
|
703 { |
|
704 atom->dump(); |
|
705 } |
|
706 |
|
707 JS_FRIEND_API(void) |
|
708 js_DumpChars(const jschar *s, size_t n) |
|
709 { |
|
710 fprintf(stderr, "jschar * (%p) = ", (void *) s); |
|
711 JSString::dumpChars(s, n); |
|
712 fputc('\n', stderr); |
|
713 } |
|
714 |
|
715 JS_FRIEND_API(void) |
|
716 js_DumpObject(JSObject *obj) |
|
717 { |
|
718 if (!obj) { |
|
719 fprintf(stderr, "NULL\n"); |
|
720 return; |
|
721 } |
|
722 obj->dump(); |
|
723 } |
|
724 |
|
725 #endif |
|
726 |
|
727 struct DumpHeapTracer : public JSTracer |
|
728 { |
|
729 FILE *output; |
|
730 |
|
731 DumpHeapTracer(FILE *fp, JSRuntime *rt, JSTraceCallback callback, |
|
732 WeakMapTraceKind weakTraceKind) |
|
733 : JSTracer(rt, callback, weakTraceKind), output(fp) |
|
734 {} |
|
735 }; |
|
736 |
|
737 static char |
|
738 MarkDescriptor(void *thing) |
|
739 { |
|
740 gc::Cell *cell = static_cast<gc::Cell*>(thing); |
|
741 if (cell->isMarked(gc::BLACK)) |
|
742 return cell->isMarked(gc::GRAY) ? 'G' : 'B'; |
|
743 else |
|
744 return cell->isMarked(gc::GRAY) ? 'X' : 'W'; |
|
745 } |
|
746 |
|
747 static void |
|
748 DumpHeapVisitZone(JSRuntime *rt, void *data, Zone *zone) |
|
749 { |
|
750 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data); |
|
751 fprintf(dtrc->output, "# zone %p\n", (void *)zone); |
|
752 } |
|
753 |
|
754 static void |
|
755 DumpHeapVisitCompartment(JSRuntime *rt, void *data, JSCompartment *comp) |
|
756 { |
|
757 char name[1024]; |
|
758 if (rt->compartmentNameCallback) |
|
759 (*rt->compartmentNameCallback)(rt, comp, name, sizeof(name)); |
|
760 else |
|
761 strcpy(name, "<unknown>"); |
|
762 |
|
763 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data); |
|
764 fprintf(dtrc->output, "# compartment %s [in zone %p]\n", name, (void *)comp->zone()); |
|
765 } |
|
766 |
|
767 static void |
|
768 DumpHeapVisitArena(JSRuntime *rt, void *data, gc::Arena *arena, |
|
769 JSGCTraceKind traceKind, size_t thingSize) |
|
770 { |
|
771 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data); |
|
772 fprintf(dtrc->output, "# arena allockind=%u size=%u\n", |
|
773 unsigned(arena->aheader.getAllocKind()), unsigned(thingSize)); |
|
774 } |
|
775 |
|
776 static void |
|
777 DumpHeapVisitCell(JSRuntime *rt, void *data, void *thing, |
|
778 JSGCTraceKind traceKind, size_t thingSize) |
|
779 { |
|
780 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(data); |
|
781 char cellDesc[1024 * 32]; |
|
782 JS_GetTraceThingInfo(cellDesc, sizeof(cellDesc), dtrc, thing, traceKind, true); |
|
783 fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing), cellDesc); |
|
784 JS_TraceChildren(dtrc, thing, traceKind); |
|
785 } |
|
786 |
|
787 static void |
|
788 DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind) |
|
789 { |
|
790 if (gc::IsInsideNursery(trc->runtime(), *thingp)) |
|
791 return; |
|
792 |
|
793 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(trc); |
|
794 char buffer[1024]; |
|
795 fprintf(dtrc->output, "> %p %c %s\n", *thingp, MarkDescriptor(*thingp), |
|
796 dtrc->getTracingEdgeName(buffer, sizeof(buffer))); |
|
797 } |
|
798 |
|
799 static void |
|
800 DumpHeapVisitRoot(JSTracer *trc, void **thingp, JSGCTraceKind kind) |
|
801 { |
|
802 if (gc::IsInsideNursery(trc->runtime(), *thingp)) |
|
803 return; |
|
804 |
|
805 DumpHeapTracer *dtrc = static_cast<DumpHeapTracer *>(trc); |
|
806 char buffer[1024]; |
|
807 fprintf(dtrc->output, "%p %c %s\n", *thingp, MarkDescriptor(*thingp), |
|
808 dtrc->getTracingEdgeName(buffer, sizeof(buffer))); |
|
809 } |
|
810 |
|
811 void |
|
812 js::DumpHeapComplete(JSRuntime *rt, FILE *fp, js::DumpHeapNurseryBehaviour nurseryBehaviour) |
|
813 { |
|
814 #ifdef JSGC_GENERATIONAL |
|
815 if (nurseryBehaviour == js::CollectNurseryBeforeDump) |
|
816 MinorGC(rt, JS::gcreason::API); |
|
817 #endif |
|
818 |
|
819 DumpHeapTracer dtrc(fp, rt, DumpHeapVisitRoot, TraceWeakMapKeysValues); |
|
820 TraceRuntime(&dtrc); |
|
821 |
|
822 fprintf(dtrc.output, "==========\n"); |
|
823 |
|
824 dtrc.setTraceCallback(DumpHeapVisitChild); |
|
825 IterateZonesCompartmentsArenasCells(rt, &dtrc, |
|
826 DumpHeapVisitZone, |
|
827 DumpHeapVisitCompartment, |
|
828 DumpHeapVisitArena, |
|
829 DumpHeapVisitCell); |
|
830 |
|
831 fflush(dtrc.output); |
|
832 } |
|
833 |
|
834 JS_FRIEND_API(const JSStructuredCloneCallbacks *) |
|
835 js::GetContextStructuredCloneCallbacks(JSContext *cx) |
|
836 { |
|
837 return cx->runtime()->structuredCloneCallbacks; |
|
838 } |
|
839 |
|
840 #ifdef JS_THREADSAFE |
|
841 JS_FRIEND_API(bool) |
|
842 js::ContextHasOutstandingRequests(const JSContext *cx) |
|
843 { |
|
844 return cx->outstandingRequests > 0; |
|
845 } |
|
846 #endif |
|
847 |
|
848 JS_FRIEND_API(void) |
|
849 js::SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg) |
|
850 { |
|
851 rt->activityCallback = cb; |
|
852 rt->activityCallbackArg = arg; |
|
853 } |
|
854 |
|
855 JS_FRIEND_API(bool) |
|
856 js::IsContextRunningJS(JSContext *cx) |
|
857 { |
|
858 return cx->currentlyRunning(); |
|
859 } |
|
860 |
|
861 JS_FRIEND_API(JS::GCSliceCallback) |
|
862 JS::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback) |
|
863 { |
|
864 JS::GCSliceCallback old = rt->gcSliceCallback; |
|
865 rt->gcSliceCallback = callback; |
|
866 return old; |
|
867 } |
|
868 |
|
869 JS_FRIEND_API(bool) |
|
870 JS::WasIncrementalGC(JSRuntime *rt) |
|
871 { |
|
872 return rt->gcIsIncremental; |
|
873 } |
|
874 |
|
875 jschar * |
|
876 GCDescription::formatMessage(JSRuntime *rt) const |
|
877 { |
|
878 return rt->gcStats.formatMessage(); |
|
879 } |
|
880 |
|
881 jschar * |
|
882 GCDescription::formatJSON(JSRuntime *rt, uint64_t timestamp) const |
|
883 { |
|
884 return rt->gcStats.formatJSON(timestamp); |
|
885 } |
|
886 |
|
887 JS_FRIEND_API(void) |
|
888 JS::NotifyDidPaint(JSRuntime *rt) |
|
889 { |
|
890 if (rt->gcZeal() == gc::ZealFrameVerifierPreValue) { |
|
891 gc::VerifyBarriers(rt, gc::PreBarrierVerifier); |
|
892 return; |
|
893 } |
|
894 |
|
895 if (rt->gcZeal() == gc::ZealFrameVerifierPostValue) { |
|
896 gc::VerifyBarriers(rt, gc::PostBarrierVerifier); |
|
897 return; |
|
898 } |
|
899 |
|
900 if (rt->gcZeal() == gc::ZealFrameGCValue) { |
|
901 PrepareForFullGC(rt); |
|
902 GCSlice(rt, GC_NORMAL, gcreason::REFRESH_FRAME); |
|
903 return; |
|
904 } |
|
905 |
|
906 if (JS::IsIncrementalGCInProgress(rt) && !rt->gcInterFrameGC) { |
|
907 JS::PrepareForIncrementalGC(rt); |
|
908 GCSlice(rt, GC_NORMAL, gcreason::REFRESH_FRAME); |
|
909 } |
|
910 |
|
911 rt->gcInterFrameGC = false; |
|
912 } |
|
913 |
|
914 JS_FRIEND_API(bool) |
|
915 JS::IsIncrementalGCEnabled(JSRuntime *rt) |
|
916 { |
|
917 return rt->gcIncrementalEnabled && rt->gcMode() == JSGC_MODE_INCREMENTAL; |
|
918 } |
|
919 |
|
920 JS_FRIEND_API(bool) |
|
921 JS::IsIncrementalGCInProgress(JSRuntime *rt) |
|
922 { |
|
923 return rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcVerifyPreData; |
|
924 } |
|
925 |
|
926 JS_FRIEND_API(void) |
|
927 JS::DisableIncrementalGC(JSRuntime *rt) |
|
928 { |
|
929 rt->gcIncrementalEnabled = false; |
|
930 } |
|
931 |
|
932 JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt) |
|
933 : runtime(rt) |
|
934 #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL) |
|
935 , restartVerifier(rt->gcVerifyPostData) |
|
936 #endif |
|
937 { |
|
938 #ifdef JSGC_GENERATIONAL |
|
939 if (IsGenerationalGCEnabled(rt)) { |
|
940 #ifdef JS_GC_ZEAL |
|
941 if (restartVerifier) |
|
942 gc::EndVerifyPostBarriers(rt); |
|
943 #endif |
|
944 MinorGC(rt, JS::gcreason::API); |
|
945 rt->gcNursery.disable(); |
|
946 rt->gcStoreBuffer.disable(); |
|
947 } |
|
948 #endif |
|
949 ++rt->gcGenerationalDisabled; |
|
950 } |
|
951 |
|
952 JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC() |
|
953 { |
|
954 JS_ASSERT(runtime->gcGenerationalDisabled > 0); |
|
955 --runtime->gcGenerationalDisabled; |
|
956 #ifdef JSGC_GENERATIONAL |
|
957 if (runtime->gcGenerationalDisabled == 0) { |
|
958 runtime->gcNursery.enable(); |
|
959 runtime->gcStoreBuffer.enable(); |
|
960 #ifdef JS_GC_ZEAL |
|
961 if (restartVerifier) |
|
962 gc::StartVerifyPostBarriers(runtime); |
|
963 #endif |
|
964 } |
|
965 #endif |
|
966 } |
|
967 |
|
968 extern JS_FRIEND_API(bool) |
|
969 JS::IsGenerationalGCEnabled(JSRuntime *rt) |
|
970 { |
|
971 return rt->gcGenerationalDisabled == 0; |
|
972 } |
|
973 |
|
974 JS_FRIEND_API(bool) |
|
975 JS::IsIncrementalBarrierNeeded(JSRuntime *rt) |
|
976 { |
|
977 return rt->gcIncrementalState == gc::MARK && !rt->isHeapBusy(); |
|
978 } |
|
979 |
|
980 JS_FRIEND_API(bool) |
|
981 JS::IsIncrementalBarrierNeeded(JSContext *cx) |
|
982 { |
|
983 return IsIncrementalBarrierNeeded(cx->runtime()); |
|
984 } |
|
985 |
|
986 JS_FRIEND_API(void) |
|
987 JS::IncrementalObjectBarrier(JSObject *obj) |
|
988 { |
|
989 if (!obj) |
|
990 return; |
|
991 |
|
992 JS_ASSERT(!obj->zone()->runtimeFromMainThread()->isHeapMajorCollecting()); |
|
993 |
|
994 AutoMarkInDeadZone amn(obj->zone()); |
|
995 |
|
996 JSObject::writeBarrierPre(obj); |
|
997 } |
|
998 |
|
999 JS_FRIEND_API(void) |
|
1000 JS::IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind) |
|
1001 { |
|
1002 if (!ptr) |
|
1003 return; |
|
1004 |
|
1005 if (kind == JSTRACE_STRING && StringIsPermanentAtom(static_cast<JSString *>(ptr))) |
|
1006 return; |
|
1007 |
|
1008 gc::Cell *cell = static_cast<gc::Cell *>(ptr); |
|
1009 Zone *zone = kind == JSTRACE_OBJECT |
|
1010 ? static_cast<JSObject *>(cell)->zone() |
|
1011 : cell->tenuredZone(); |
|
1012 |
|
1013 JS_ASSERT(!zone->runtimeFromMainThread()->isHeapMajorCollecting()); |
|
1014 |
|
1015 AutoMarkInDeadZone amn(zone); |
|
1016 |
|
1017 if (kind == JSTRACE_OBJECT) |
|
1018 JSObject::writeBarrierPre(static_cast<JSObject*>(cell)); |
|
1019 else if (kind == JSTRACE_STRING) |
|
1020 JSString::writeBarrierPre(static_cast<JSString*>(cell)); |
|
1021 else if (kind == JSTRACE_SCRIPT) |
|
1022 JSScript::writeBarrierPre(static_cast<JSScript*>(cell)); |
|
1023 else if (kind == JSTRACE_LAZY_SCRIPT) |
|
1024 LazyScript::writeBarrierPre(static_cast<LazyScript*>(cell)); |
|
1025 else if (kind == JSTRACE_SHAPE) |
|
1026 Shape::writeBarrierPre(static_cast<Shape*>(cell)); |
|
1027 else if (kind == JSTRACE_BASE_SHAPE) |
|
1028 BaseShape::writeBarrierPre(static_cast<BaseShape*>(cell)); |
|
1029 else if (kind == JSTRACE_TYPE_OBJECT) |
|
1030 types::TypeObject::writeBarrierPre((types::TypeObject *) ptr); |
|
1031 else |
|
1032 MOZ_ASSUME_UNREACHABLE("invalid trace kind"); |
|
1033 } |
|
1034 |
|
1035 JS_FRIEND_API(void) |
|
1036 JS::IncrementalValueBarrier(const Value &v) |
|
1037 { |
|
1038 js::HeapValue::writeBarrierPre(v); |
|
1039 } |
|
1040 |
|
1041 JS_FRIEND_API(void) |
|
1042 JS::PokeGC(JSRuntime *rt) |
|
1043 { |
|
1044 rt->gcPoke = true; |
|
1045 } |
|
1046 |
|
1047 JS_FRIEND_API(JSCompartment *) |
|
1048 js::GetAnyCompartmentInZone(JS::Zone *zone) |
|
1049 { |
|
1050 CompartmentsInZoneIter comp(zone); |
|
1051 JS_ASSERT(!comp.done()); |
|
1052 return comp.get(); |
|
1053 } |
|
1054 |
|
1055 bool |
|
1056 JS::ObjectPtr::isAboutToBeFinalized() |
|
1057 { |
|
1058 return JS_IsAboutToBeFinalized(&value); |
|
1059 } |
|
1060 |
|
1061 void |
|
1062 JS::ObjectPtr::trace(JSTracer *trc, const char *name) |
|
1063 { |
|
1064 JS_CallHeapObjectTracer(trc, &value, name); |
|
1065 } |
|
1066 |
|
1067 JS_FRIEND_API(JSObject *) |
|
1068 js::GetTestingFunctions(JSContext *cx) |
|
1069 { |
|
1070 RootedObject obj(cx, JS_NewObject(cx, nullptr, NullPtr(), NullPtr())); |
|
1071 if (!obj) |
|
1072 return nullptr; |
|
1073 |
|
1074 if (!DefineTestingFunctions(cx, obj, false)) |
|
1075 return nullptr; |
|
1076 |
|
1077 return obj; |
|
1078 } |
|
1079 |
|
1080 #ifdef DEBUG |
|
1081 JS_FRIEND_API(unsigned) |
|
1082 js::GetEnterCompartmentDepth(JSContext *cx) |
|
1083 { |
|
1084 return cx->getEnterCompartmentDepth(); |
|
1085 } |
|
1086 #endif |
|
1087 |
|
1088 JS_FRIEND_API(void) |
|
1089 js::SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks) |
|
1090 { |
|
1091 rt->DOMcallbacks = callbacks; |
|
1092 } |
|
1093 |
|
1094 JS_FRIEND_API(const DOMCallbacks *) |
|
1095 js::GetDOMCallbacks(JSRuntime *rt) |
|
1096 { |
|
1097 return rt->DOMcallbacks; |
|
1098 } |
|
1099 |
|
1100 static const void *gDOMProxyHandlerFamily = nullptr; |
|
1101 static uint32_t gDOMProxyExpandoSlot = 0; |
|
1102 static DOMProxyShadowsCheck gDOMProxyShadowsCheck; |
|
1103 |
|
1104 JS_FRIEND_API(void) |
|
1105 js::SetDOMProxyInformation(const void *domProxyHandlerFamily, uint32_t domProxyExpandoSlot, |
|
1106 DOMProxyShadowsCheck domProxyShadowsCheck) |
|
1107 { |
|
1108 gDOMProxyHandlerFamily = domProxyHandlerFamily; |
|
1109 gDOMProxyExpandoSlot = domProxyExpandoSlot; |
|
1110 gDOMProxyShadowsCheck = domProxyShadowsCheck; |
|
1111 } |
|
1112 |
|
1113 const void * |
|
1114 js::GetDOMProxyHandlerFamily() |
|
1115 { |
|
1116 return gDOMProxyHandlerFamily; |
|
1117 } |
|
1118 |
|
1119 uint32_t |
|
1120 js::GetDOMProxyExpandoSlot() |
|
1121 { |
|
1122 return gDOMProxyExpandoSlot; |
|
1123 } |
|
1124 |
|
1125 DOMProxyShadowsCheck |
|
1126 js::GetDOMProxyShadowsCheck() |
|
1127 { |
|
1128 return gDOMProxyShadowsCheck; |
|
1129 } |
|
1130 |
|
1131 bool |
|
1132 js::detail::IdMatchesAtom(jsid id, JSAtom *atom) |
|
1133 { |
|
1134 return id == INTERNED_STRING_TO_JSID(nullptr, atom); |
|
1135 } |
|
1136 |
|
1137 JS_FRIEND_API(JSContext *) |
|
1138 js::DefaultJSContext(JSRuntime *rt) |
|
1139 { |
|
1140 if (rt->defaultJSContextCallback) { |
|
1141 JSContext *cx = rt->defaultJSContextCallback(rt); |
|
1142 JS_ASSERT(cx); |
|
1143 return cx; |
|
1144 } |
|
1145 JS_ASSERT(rt->contextList.getFirst() == rt->contextList.getLast()); |
|
1146 return rt->contextList.getFirst(); |
|
1147 } |
|
1148 |
|
1149 JS_FRIEND_API(void) |
|
1150 js::SetDefaultJSContextCallback(JSRuntime *rt, DefaultJSContextCallback cb) |
|
1151 { |
|
1152 rt->defaultJSContextCallback = cb; |
|
1153 } |
|
1154 |
|
1155 #ifdef DEBUG |
|
1156 JS_FRIEND_API(void) |
|
1157 js::Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx) |
|
1158 { |
|
1159 rt->activeContext = cx; |
|
1160 } |
|
1161 #endif |
|
1162 |
|
1163 JS_FRIEND_API(void) |
|
1164 js::SetCTypesActivityCallback(JSRuntime *rt, CTypesActivityCallback cb) |
|
1165 { |
|
1166 rt->ctypesActivityCallback = cb; |
|
1167 } |
|
1168 |
|
1169 js::AutoCTypesActivityCallback::AutoCTypesActivityCallback(JSContext *cx, |
|
1170 js::CTypesActivityType beginType, |
|
1171 js::CTypesActivityType endType |
|
1172 MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) |
|
1173 : cx(cx), callback(cx->runtime()->ctypesActivityCallback), endType(endType) |
|
1174 { |
|
1175 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
1176 |
|
1177 if (callback) |
|
1178 callback(cx, beginType); |
|
1179 } |
|
1180 |
|
1181 JS_FRIEND_API(void) |
|
1182 js::SetObjectMetadataCallback(JSContext *cx, ObjectMetadataCallback callback) |
|
1183 { |
|
1184 cx->compartment()->setObjectMetadataCallback(callback); |
|
1185 } |
|
1186 |
|
1187 JS_FRIEND_API(bool) |
|
1188 js::SetObjectMetadata(JSContext *cx, HandleObject obj, HandleObject metadata) |
|
1189 { |
|
1190 return JSObject::setMetadata(cx, obj, metadata); |
|
1191 } |
|
1192 |
|
1193 JS_FRIEND_API(JSObject *) |
|
1194 js::GetObjectMetadata(JSObject *obj) |
|
1195 { |
|
1196 return obj->getMetadata(); |
|
1197 } |
|
1198 |
|
1199 JS_FRIEND_API(void) |
|
1200 js::UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value) |
|
1201 { |
|
1202 JS_ASSERT(obj->isNative()); |
|
1203 JS_ASSERT(index < obj->getDenseInitializedLength()); |
|
1204 obj->setDenseElementWithType(cx, index, value); |
|
1205 } |
|
1206 |
|
1207 JS_FRIEND_API(bool) |
|
1208 js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg, |
|
1209 JS::Handle<js::PropertyDescriptor> descriptor, bool *bp) |
|
1210 { |
|
1211 RootedObject obj(cx, objArg); |
|
1212 RootedId id(cx, idArg); |
|
1213 JS_ASSERT(cx->runtime()->heapState == js::Idle); |
|
1214 CHECK_REQUEST(cx); |
|
1215 assertSameCompartment(cx, obj, id, descriptor.value()); |
|
1216 if (descriptor.hasGetterObject()) |
|
1217 assertSameCompartment(cx, descriptor.getterObject()); |
|
1218 if (descriptor.hasSetterObject()) |
|
1219 assertSameCompartment(cx, descriptor.setterObject()); |
|
1220 |
|
1221 return DefineOwnProperty(cx, HandleObject(obj), id, descriptor, bp); |
|
1222 } |
|
1223 |
|
1224 JS_FRIEND_API(bool) |
|
1225 js_ReportIsNotFunction(JSContext *cx, JS::HandleValue v) |
|
1226 { |
|
1227 return ReportIsNotFunction(cx, v); |
|
1228 } |
|
1229 |
|
1230 #ifdef DEBUG |
|
1231 JS_PUBLIC_API(bool) |
|
1232 js::IsInRequest(JSContext *cx) |
|
1233 { |
|
1234 #ifdef JS_THREADSAFE |
|
1235 return !!cx->runtime()->requestDepth; |
|
1236 #else |
|
1237 return true; |
|
1238 #endif |
|
1239 } |
|
1240 #endif |
|
1241 |
|
1242 #ifdef JSGC_GENERATIONAL |
|
1243 JS_FRIEND_API(void) |
|
1244 JS_StoreObjectPostBarrierCallback(JSContext* cx, |
|
1245 void (*callback)(JSTracer *trc, JSObject *key, void *data), |
|
1246 JSObject *key, void *data) |
|
1247 { |
|
1248 JSRuntime *rt = cx->runtime(); |
|
1249 if (IsInsideNursery(rt, key)) |
|
1250 rt->gcStoreBuffer.putCallback(callback, key, data); |
|
1251 } |
|
1252 |
|
1253 extern JS_FRIEND_API(void) |
|
1254 JS_StoreStringPostBarrierCallback(JSContext* cx, |
|
1255 void (*callback)(JSTracer *trc, JSString *key, void *data), |
|
1256 JSString *key, void *data) |
|
1257 { |
|
1258 JSRuntime *rt = cx->runtime(); |
|
1259 if (IsInsideNursery(rt, key)) |
|
1260 rt->gcStoreBuffer.putCallback(callback, key, data); |
|
1261 } |
|
1262 #endif /* JSGC_GENERATIONAL */ |