1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsgcinlines.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,642 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jsgcinlines_h 1.11 +#define jsgcinlines_h 1.12 + 1.13 +#include "jsgc.h" 1.14 + 1.15 +#include "gc/Zone.h" 1.16 + 1.17 +namespace js { 1.18 + 1.19 +class Shape; 1.20 + 1.21 +/* 1.22 + * This auto class should be used around any code that might cause a mark bit to 1.23 + * be set on an object in a dead zone. See AutoMaybeTouchDeadZones 1.24 + * for more details. 1.25 + */ 1.26 +struct AutoMarkInDeadZone 1.27 +{ 1.28 + AutoMarkInDeadZone(JS::Zone *zone) 1.29 + : zone(zone), 1.30 + scheduled(zone->scheduledForDestruction) 1.31 + { 1.32 + JSRuntime *rt = zone->runtimeFromMainThread(); 1.33 + if (rt->gcManipulatingDeadZones && zone->scheduledForDestruction) { 1.34 + rt->gcObjectsMarkedInDeadZones++; 1.35 + zone->scheduledForDestruction = false; 1.36 + } 1.37 + } 1.38 + 1.39 + ~AutoMarkInDeadZone() { 1.40 + zone->scheduledForDestruction = scheduled; 1.41 + } 1.42 + 1.43 + private: 1.44 + JS::Zone *zone; 1.45 + bool scheduled; 1.46 +}; 1.47 + 1.48 +inline Allocator *const 1.49 +ThreadSafeContext::allocator() 1.50 +{ 1.51 + JS_ASSERT_IF(isJSContext(), &asJSContext()->zone()->allocator == allocator_); 1.52 + return allocator_; 1.53 +} 1.54 + 1.55 +template <typename T> 1.56 +inline bool 1.57 +ThreadSafeContext::isThreadLocal(T thing) const 1.58 +{ 1.59 + if (!isForkJoinContext()) 1.60 + return true; 1.61 + 1.62 + if (!IsInsideNursery(runtime_, thing) && 1.63 + allocator_->arenas.containsArena(runtime_, thing->arenaHeader())) 1.64 + { 1.65 + // GC should be suppressed in preparation for mutating thread local 1.66 + // objects, as we don't want to trip any barriers. 1.67 + JS_ASSERT(!thing->zoneFromAnyThread()->needsBarrier()); 1.68 + JS_ASSERT(!thing->runtimeFromAnyThread()->needsBarrier()); 1.69 + 1.70 + return true; 1.71 + } 1.72 + 1.73 + return false; 1.74 +} 1.75 + 1.76 +namespace gc { 1.77 + 1.78 +static inline AllocKind 1.79 +GetGCObjectKind(const Class *clasp) 1.80 +{ 1.81 + if (clasp == FunctionClassPtr) 1.82 + return JSFunction::FinalizeKind; 1.83 + uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp); 1.84 + if (clasp->flags & JSCLASS_HAS_PRIVATE) 1.85 + nslots++; 1.86 + return GetGCObjectKind(nslots); 1.87 +} 1.88 + 1.89 +#ifdef JSGC_GENERATIONAL 1.90 +inline bool 1.91 +ShouldNurseryAllocate(const Nursery &nursery, AllocKind kind, InitialHeap heap) 1.92 +{ 1.93 + return nursery.isEnabled() && IsNurseryAllocable(kind) && heap != TenuredHeap; 1.94 +} 1.95 +#endif 1.96 + 1.97 +inline JSGCTraceKind 1.98 +GetGCThingTraceKind(const void *thing) 1.99 +{ 1.100 + JS_ASSERT(thing); 1.101 + const Cell *cell = static_cast<const Cell *>(thing); 1.102 +#ifdef JSGC_GENERATIONAL 1.103 + if (IsInsideNursery(cell->runtimeFromAnyThread(), cell)) 1.104 + return JSTRACE_OBJECT; 1.105 +#endif 1.106 + return MapAllocToTraceKind(cell->tenuredGetAllocKind()); 1.107 +} 1.108 + 1.109 +static inline void 1.110 +GCPoke(JSRuntime *rt) 1.111 +{ 1.112 + rt->gcPoke = true; 1.113 + 1.114 +#ifdef JS_GC_ZEAL 1.115 + /* Schedule a GC to happen "soon" after a GC poke. */ 1.116 + if (rt->gcZeal() == js::gc::ZealPokeValue) 1.117 + rt->gcNextScheduled = 1; 1.118 +#endif 1.119 +} 1.120 + 1.121 +class ArenaIter 1.122 +{ 1.123 + ArenaHeader *aheader; 1.124 + ArenaHeader *remainingHeader; 1.125 + 1.126 + public: 1.127 + ArenaIter() { 1.128 + init(); 1.129 + } 1.130 + 1.131 + ArenaIter(JS::Zone *zone, AllocKind kind) { 1.132 + init(zone, kind); 1.133 + } 1.134 + 1.135 + void init() { 1.136 + aheader = nullptr; 1.137 + remainingHeader = nullptr; 1.138 + } 1.139 + 1.140 + void init(ArenaHeader *aheaderArg) { 1.141 + aheader = aheaderArg; 1.142 + remainingHeader = nullptr; 1.143 + } 1.144 + 1.145 + void init(JS::Zone *zone, AllocKind kind) { 1.146 + aheader = zone->allocator.arenas.getFirstArena(kind); 1.147 + remainingHeader = zone->allocator.arenas.getFirstArenaToSweep(kind); 1.148 + if (!aheader) { 1.149 + aheader = remainingHeader; 1.150 + remainingHeader = nullptr; 1.151 + } 1.152 + } 1.153 + 1.154 + bool done() { 1.155 + return !aheader; 1.156 + } 1.157 + 1.158 + ArenaHeader *get() { 1.159 + return aheader; 1.160 + } 1.161 + 1.162 + void next() { 1.163 + aheader = aheader->next; 1.164 + if (!aheader) { 1.165 + aheader = remainingHeader; 1.166 + remainingHeader = nullptr; 1.167 + } 1.168 + } 1.169 +}; 1.170 + 1.171 +class CellIterImpl 1.172 +{ 1.173 + size_t firstThingOffset; 1.174 + size_t thingSize; 1.175 + ArenaIter aiter; 1.176 + FreeSpan firstSpan; 1.177 + const FreeSpan *span; 1.178 + uintptr_t thing; 1.179 + Cell *cell; 1.180 + 1.181 + protected: 1.182 + CellIterImpl() { 1.183 + } 1.184 + 1.185 + void initSpan(JS::Zone *zone, AllocKind kind) { 1.186 + JS_ASSERT(zone->allocator.arenas.isSynchronizedFreeList(kind)); 1.187 + firstThingOffset = Arena::firstThingOffset(kind); 1.188 + thingSize = Arena::thingSize(kind); 1.189 + firstSpan.initAsEmpty(); 1.190 + span = &firstSpan; 1.191 + thing = span->first; 1.192 + } 1.193 + 1.194 + void init(ArenaHeader *singleAheader) { 1.195 + initSpan(singleAheader->zone, singleAheader->getAllocKind()); 1.196 + aiter.init(singleAheader); 1.197 + next(); 1.198 + aiter.init(); 1.199 + } 1.200 + 1.201 + void init(JS::Zone *zone, AllocKind kind) { 1.202 + initSpan(zone, kind); 1.203 + aiter.init(zone, kind); 1.204 + next(); 1.205 + } 1.206 + 1.207 + public: 1.208 + bool done() const { 1.209 + return !cell; 1.210 + } 1.211 + 1.212 + template<typename T> T *get() const { 1.213 + JS_ASSERT(!done()); 1.214 + return static_cast<T *>(cell); 1.215 + } 1.216 + 1.217 + Cell *getCell() const { 1.218 + JS_ASSERT(!done()); 1.219 + return cell; 1.220 + } 1.221 + 1.222 + void next() { 1.223 + for (;;) { 1.224 + if (thing != span->first) 1.225 + break; 1.226 + if (MOZ_LIKELY(span->hasNext())) { 1.227 + thing = span->last + thingSize; 1.228 + span = span->nextSpan(); 1.229 + break; 1.230 + } 1.231 + if (aiter.done()) { 1.232 + cell = nullptr; 1.233 + return; 1.234 + } 1.235 + ArenaHeader *aheader = aiter.get(); 1.236 + firstSpan = aheader->getFirstFreeSpan(); 1.237 + span = &firstSpan; 1.238 + thing = aheader->arenaAddress() | firstThingOffset; 1.239 + aiter.next(); 1.240 + } 1.241 + cell = reinterpret_cast<Cell *>(thing); 1.242 + thing += thingSize; 1.243 + } 1.244 +}; 1.245 + 1.246 +class CellIterUnderGC : public CellIterImpl 1.247 +{ 1.248 + public: 1.249 + CellIterUnderGC(JS::Zone *zone, AllocKind kind) { 1.250 +#ifdef JSGC_GENERATIONAL 1.251 + JS_ASSERT(zone->runtimeFromAnyThread()->gcNursery.isEmpty()); 1.252 +#endif 1.253 + JS_ASSERT(zone->runtimeFromAnyThread()->isHeapBusy()); 1.254 + init(zone, kind); 1.255 + } 1.256 + 1.257 + CellIterUnderGC(ArenaHeader *aheader) { 1.258 + JS_ASSERT(aheader->zone->runtimeFromAnyThread()->isHeapBusy()); 1.259 + init(aheader); 1.260 + } 1.261 +}; 1.262 + 1.263 +class CellIter : public CellIterImpl 1.264 +{ 1.265 + ArenaLists *lists; 1.266 + AllocKind kind; 1.267 +#ifdef DEBUG 1.268 + size_t *counter; 1.269 +#endif 1.270 + public: 1.271 + CellIter(JS::Zone *zone, AllocKind kind) 1.272 + : lists(&zone->allocator.arenas), 1.273 + kind(kind) 1.274 + { 1.275 + /* 1.276 + * We have a single-threaded runtime, so there's no need to protect 1.277 + * against other threads iterating or allocating. However, we do have 1.278 + * background finalization; we have to wait for this to finish if it's 1.279 + * currently active. 1.280 + */ 1.281 + if (IsBackgroundFinalized(kind) && 1.282 + zone->allocator.arenas.needBackgroundFinalizeWait(kind)) 1.283 + { 1.284 + gc::FinishBackgroundFinalize(zone->runtimeFromMainThread()); 1.285 + } 1.286 + 1.287 +#ifdef JSGC_GENERATIONAL 1.288 + /* Evict the nursery before iterating so we can see all things. */ 1.289 + JSRuntime *rt = zone->runtimeFromMainThread(); 1.290 + if (!rt->gcNursery.isEmpty()) 1.291 + MinorGC(rt, JS::gcreason::EVICT_NURSERY); 1.292 +#endif 1.293 + 1.294 + if (lists->isSynchronizedFreeList(kind)) { 1.295 + lists = nullptr; 1.296 + } else { 1.297 + JS_ASSERT(!zone->runtimeFromMainThread()->isHeapBusy()); 1.298 + lists->copyFreeListToArena(kind); 1.299 + } 1.300 + 1.301 +#ifdef DEBUG 1.302 + /* Assert that no GCs can occur while a CellIter is live. */ 1.303 + counter = &zone->runtimeFromAnyThread()->noGCOrAllocationCheck; 1.304 + ++*counter; 1.305 +#endif 1.306 + 1.307 + init(zone, kind); 1.308 + } 1.309 + 1.310 + ~CellIter() { 1.311 +#ifdef DEBUG 1.312 + JS_ASSERT(*counter > 0); 1.313 + --*counter; 1.314 +#endif 1.315 + if (lists) 1.316 + lists->clearFreeListInArena(kind); 1.317 + } 1.318 +}; 1.319 + 1.320 +class GCZonesIter 1.321 +{ 1.322 + private: 1.323 + ZonesIter zone; 1.324 + 1.325 + public: 1.326 + GCZonesIter(JSRuntime *rt) : zone(rt, WithAtoms) { 1.327 + if (!zone->isCollecting()) 1.328 + next(); 1.329 + } 1.330 + 1.331 + bool done() const { return zone.done(); } 1.332 + 1.333 + void next() { 1.334 + JS_ASSERT(!done()); 1.335 + do { 1.336 + zone.next(); 1.337 + } while (!zone.done() && !zone->isCollecting()); 1.338 + } 1.339 + 1.340 + JS::Zone *get() const { 1.341 + JS_ASSERT(!done()); 1.342 + return zone; 1.343 + } 1.344 + 1.345 + operator JS::Zone *() const { return get(); } 1.346 + JS::Zone *operator->() const { return get(); } 1.347 +}; 1.348 + 1.349 +typedef CompartmentsIterT<GCZonesIter> GCCompartmentsIter; 1.350 + 1.351 +/* Iterates over all zones in the current zone group. */ 1.352 +class GCZoneGroupIter { 1.353 + private: 1.354 + JS::Zone *current; 1.355 + 1.356 + public: 1.357 + GCZoneGroupIter(JSRuntime *rt) { 1.358 + JS_ASSERT(rt->isHeapBusy()); 1.359 + current = rt->gcCurrentZoneGroup; 1.360 + } 1.361 + 1.362 + bool done() const { return !current; } 1.363 + 1.364 + void next() { 1.365 + JS_ASSERT(!done()); 1.366 + current = current->nextNodeInGroup(); 1.367 + } 1.368 + 1.369 + JS::Zone *get() const { 1.370 + JS_ASSERT(!done()); 1.371 + return current; 1.372 + } 1.373 + 1.374 + operator JS::Zone *() const { return get(); } 1.375 + JS::Zone *operator->() const { return get(); } 1.376 +}; 1.377 + 1.378 +typedef CompartmentsIterT<GCZoneGroupIter> GCCompartmentGroupIter; 1.379 + 1.380 +#ifdef JSGC_GENERATIONAL 1.381 +/* 1.382 + * Attempt to allocate a new GC thing out of the nursery. If there is not enough 1.383 + * room in the nursery or there is an OOM, this method will return nullptr. 1.384 + */ 1.385 +template <AllowGC allowGC> 1.386 +inline JSObject * 1.387 +TryNewNurseryObject(ThreadSafeContext *cxArg, size_t thingSize, size_t nDynamicSlots) 1.388 +{ 1.389 + JSContext *cx = cxArg->asJSContext(); 1.390 + 1.391 + JS_ASSERT(!IsAtomsCompartment(cx->compartment())); 1.392 + JSRuntime *rt = cx->runtime(); 1.393 + Nursery &nursery = rt->gcNursery; 1.394 + JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots); 1.395 + if (obj) 1.396 + return obj; 1.397 + if (allowGC && !rt->mainThread.suppressGC) { 1.398 + MinorGC(cx, JS::gcreason::OUT_OF_NURSERY); 1.399 + 1.400 + /* Exceeding gcMaxBytes while tenuring can disable the Nursery. */ 1.401 + if (nursery.isEnabled()) { 1.402 + JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots); 1.403 + JS_ASSERT(obj); 1.404 + return obj; 1.405 + } 1.406 + } 1.407 + return nullptr; 1.408 +} 1.409 +#endif /* JSGC_GENERATIONAL */ 1.410 + 1.411 +static inline bool 1.412 +PossiblyFail() 1.413 +{ 1.414 + JS_OOM_POSSIBLY_FAIL(); 1.415 + return true; 1.416 +} 1.417 + 1.418 +template <AllowGC allowGC> 1.419 +static inline bool 1.420 +CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind) 1.421 +{ 1.422 + if (!cx->isJSContext()) 1.423 + return true; 1.424 + 1.425 + JSContext *ncx = cx->asJSContext(); 1.426 + JSRuntime *rt = ncx->runtime(); 1.427 +#if defined(JS_GC_ZEAL) || defined(DEBUG) 1.428 + JS_ASSERT_IF(rt->isAtomsCompartment(ncx->compartment()), 1.429 + kind == FINALIZE_STRING || 1.430 + kind == FINALIZE_FAT_INLINE_STRING || 1.431 + kind == FINALIZE_JITCODE); 1.432 + JS_ASSERT(!rt->isHeapBusy()); 1.433 + JS_ASSERT(!rt->noGCOrAllocationCheck); 1.434 +#endif 1.435 + 1.436 + // For testing out of memory conditions 1.437 + if (!PossiblyFail()) { 1.438 + js_ReportOutOfMemory(cx); 1.439 + return false; 1.440 + } 1.441 + 1.442 + if (allowGC) { 1.443 +#ifdef JS_GC_ZEAL 1.444 + if (rt->needZealousGC()) 1.445 + js::gc::RunDebugGC(ncx); 1.446 +#endif 1.447 + 1.448 + if (rt->interrupt) { 1.449 + // Invoking the interrupt callback can fail and we can't usefully 1.450 + // handle that here. Just check in case we need to collect instead. 1.451 + js::gc::GCIfNeeded(ncx); 1.452 + } 1.453 + } 1.454 + 1.455 + return true; 1.456 +} 1.457 + 1.458 +template <typename T> 1.459 +static inline void 1.460 +CheckIncrementalZoneState(ThreadSafeContext *cx, T *t) 1.461 +{ 1.462 +#ifdef DEBUG 1.463 + if (!cx->isJSContext()) 1.464 + return; 1.465 + 1.466 + Zone *zone = cx->asJSContext()->zone(); 1.467 + JS_ASSERT_IF(t && zone->wasGCStarted() && (zone->isGCMarking() || zone->isGCSweeping()), 1.468 + t->arenaHeader()->allocatedDuringIncremental); 1.469 +#endif 1.470 +} 1.471 + 1.472 +/* 1.473 + * Allocate a new GC thing. After a successful allocation the caller must 1.474 + * fully initialize the thing before calling any function that can potentially 1.475 + * trigger GC. This will ensure that GC tracing never sees junk values stored 1.476 + * in the partially initialized thing. 1.477 + */ 1.478 + 1.479 +template <AllowGC allowGC> 1.480 +inline JSObject * 1.481 +AllocateObject(ThreadSafeContext *cx, AllocKind kind, size_t nDynamicSlots, InitialHeap heap) 1.482 +{ 1.483 + size_t thingSize = Arena::thingSize(kind); 1.484 + 1.485 + JS_ASSERT(thingSize == Arena::thingSize(kind)); 1.486 + if (!CheckAllocatorState<allowGC>(cx, kind)) 1.487 + return nullptr; 1.488 + 1.489 +#ifdef JSGC_GENERATIONAL 1.490 + if (cx->hasNursery() && ShouldNurseryAllocate(cx->nursery(), kind, heap)) { 1.491 + JSObject *obj = TryNewNurseryObject<allowGC>(cx, thingSize, nDynamicSlots); 1.492 + if (obj) 1.493 + return obj; 1.494 + } 1.495 +#endif 1.496 + 1.497 + HeapSlot *slots = nullptr; 1.498 + if (nDynamicSlots) { 1.499 + slots = cx->pod_malloc<HeapSlot>(nDynamicSlots); 1.500 + if (MOZ_UNLIKELY(!slots)) 1.501 + return nullptr; 1.502 + js::Debug_SetSlotRangeToCrashOnTouch(slots, nDynamicSlots); 1.503 + } 1.504 + 1.505 + JSObject *obj = static_cast<JSObject *>(cx->allocator()->arenas.allocateFromFreeList(kind, thingSize)); 1.506 + if (!obj) 1.507 + obj = static_cast<JSObject *>(js::gc::ArenaLists::refillFreeList<allowGC>(cx, kind)); 1.508 + 1.509 + if (obj) 1.510 + obj->setInitialSlots(slots); 1.511 + else 1.512 + js_free(slots); 1.513 + 1.514 + CheckIncrementalZoneState(cx, obj); 1.515 + return obj; 1.516 +} 1.517 + 1.518 +template <typename T, AllowGC allowGC> 1.519 +inline T * 1.520 +AllocateNonObject(ThreadSafeContext *cx) 1.521 +{ 1.522 + AllocKind kind = MapTypeToFinalizeKind<T>::kind; 1.523 + size_t thingSize = sizeof(T); 1.524 + 1.525 + JS_ASSERT(thingSize == Arena::thingSize(kind)); 1.526 + if (!CheckAllocatorState<allowGC>(cx, kind)) 1.527 + return nullptr; 1.528 + 1.529 + T *t = static_cast<T *>(cx->allocator()->arenas.allocateFromFreeList(kind, thingSize)); 1.530 + if (!t) 1.531 + t = static_cast<T *>(js::gc::ArenaLists::refillFreeList<allowGC>(cx, kind)); 1.532 + 1.533 + CheckIncrementalZoneState(cx, t); 1.534 + return t; 1.535 +} 1.536 + 1.537 +/* 1.538 + * When allocating for initialization from a cached object copy, we will 1.539 + * potentially destroy the cache entry we want to copy if we allow GC. On the 1.540 + * other hand, since these allocations are extremely common, we don't want to 1.541 + * delay GC from these allocation sites. Instead we allow the GC, but still 1.542 + * fail the allocation, forcing the non-cached path. 1.543 + */ 1.544 +template <AllowGC allowGC> 1.545 +inline JSObject * 1.546 +AllocateObjectForCacheHit(JSContext *cx, AllocKind kind, InitialHeap heap) 1.547 +{ 1.548 +#ifdef JSGC_GENERATIONAL 1.549 + if (ShouldNurseryAllocate(cx->nursery(), kind, heap)) { 1.550 + size_t thingSize = Arena::thingSize(kind); 1.551 + 1.552 + JS_ASSERT(thingSize == Arena::thingSize(kind)); 1.553 + if (!CheckAllocatorState<NoGC>(cx, kind)) 1.554 + return nullptr; 1.555 + 1.556 + JSObject *obj = TryNewNurseryObject<NoGC>(cx, thingSize, 0); 1.557 + if (!obj && allowGC) { 1.558 + MinorGC(cx, JS::gcreason::OUT_OF_NURSERY); 1.559 + return nullptr; 1.560 + } 1.561 + return obj; 1.562 + } 1.563 +#endif 1.564 + 1.565 + JSObject *obj = AllocateObject<NoGC>(cx, kind, 0, heap); 1.566 + if (!obj && allowGC) { 1.567 + MaybeGC(cx); 1.568 + return nullptr; 1.569 + } 1.570 + 1.571 + return obj; 1.572 +} 1.573 + 1.574 +} /* namespace gc */ 1.575 + 1.576 +template <js::AllowGC allowGC> 1.577 +inline JSObject * 1.578 +NewGCObject(js::ThreadSafeContext *cx, js::gc::AllocKind kind, size_t nDynamicSlots, js::gc::InitialHeap heap) 1.579 +{ 1.580 + JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST); 1.581 + return js::gc::AllocateObject<allowGC>(cx, kind, nDynamicSlots, heap); 1.582 +} 1.583 + 1.584 +template <js::AllowGC allowGC> 1.585 +inline jit::JitCode * 1.586 +NewJitCode(js::ThreadSafeContext *cx) 1.587 +{ 1.588 + return gc::AllocateNonObject<jit::JitCode, allowGC>(cx); 1.589 +} 1.590 + 1.591 +inline 1.592 +types::TypeObject * 1.593 +NewTypeObject(js::ThreadSafeContext *cx) 1.594 +{ 1.595 + return gc::AllocateNonObject<types::TypeObject, js::CanGC>(cx); 1.596 +} 1.597 + 1.598 +} /* namespace js */ 1.599 + 1.600 +template <js::AllowGC allowGC> 1.601 +inline JSString * 1.602 +js_NewGCString(js::ThreadSafeContext *cx) 1.603 +{ 1.604 + return js::gc::AllocateNonObject<JSString, allowGC>(cx); 1.605 +} 1.606 + 1.607 +template <js::AllowGC allowGC> 1.608 +inline JSFatInlineString * 1.609 +js_NewGCFatInlineString(js::ThreadSafeContext *cx) 1.610 +{ 1.611 + return js::gc::AllocateNonObject<JSFatInlineString, allowGC>(cx); 1.612 +} 1.613 + 1.614 +inline JSExternalString * 1.615 +js_NewGCExternalString(js::ThreadSafeContext *cx) 1.616 +{ 1.617 + return js::gc::AllocateNonObject<JSExternalString, js::CanGC>(cx); 1.618 +} 1.619 + 1.620 +inline JSScript * 1.621 +js_NewGCScript(js::ThreadSafeContext *cx) 1.622 +{ 1.623 + return js::gc::AllocateNonObject<JSScript, js::CanGC>(cx); 1.624 +} 1.625 + 1.626 +inline js::LazyScript * 1.627 +js_NewGCLazyScript(js::ThreadSafeContext *cx) 1.628 +{ 1.629 + return js::gc::AllocateNonObject<js::LazyScript, js::CanGC>(cx); 1.630 +} 1.631 + 1.632 +inline js::Shape * 1.633 +js_NewGCShape(js::ThreadSafeContext *cx) 1.634 +{ 1.635 + return js::gc::AllocateNonObject<js::Shape, js::CanGC>(cx); 1.636 +} 1.637 + 1.638 +template <js::AllowGC allowGC> 1.639 +inline js::BaseShape * 1.640 +js_NewGCBaseShape(js::ThreadSafeContext *cx) 1.641 +{ 1.642 + return js::gc::AllocateNonObject<js::BaseShape, allowGC>(cx); 1.643 +} 1.644 + 1.645 +#endif /* jsgcinlines_h */