JS_DetachArrayBuffer(JSContext* cx, HandleObject obj, DetachDataDisposition changeData) { if (!obj->is<ArrayBufferObject>()) { JS_ReportError(cx, "ArrayBuffer object required"); return false; } Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>()); if (changeData == ChangeData && buffer->hasStealableContents()) { ArrayBufferObject::BufferContents newContents = AllocateArrayBufferContents(cx, buffer->byteLength()); if (!newContents) return false; if (!ArrayBufferObject::detach(cx, buffer, newContents)) { js_free(newContents.data()); return false; } } else { if (!ArrayBufferObject::detach(cx, buffer, buffer->contents())) return false; } return true; }
static void NoteViewBufferWasDetached(ArrayBufferViewObject* view, ArrayBufferObject::BufferContents newContents, JSContext* cx) { view->notifyBufferDetached(newContents.data()); // Notify compiled jit code that the base pointer has moved. MarkObjectStateChange(cx, view); }
static bool TransferAsmJSMappedBuffer(JSContext* cx, const CallArgs& args, Handle<ArrayBufferObject*> oldBuffer, size_t newByteLength) { size_t oldByteLength = oldBuffer->byteLength(); MOZ_ASSERT(oldByteLength % AsmJSPageSize == 0); MOZ_ASSERT(newByteLength % AsmJSPageSize == 0); ArrayBufferObject::BufferContents stolen = ArrayBufferObject::stealContents(cx, oldBuffer, /* hasStealableContents = */ true); if (!stolen) return false; MOZ_ASSERT(stolen.kind() == ArrayBufferObject::ASMJS_MAPPED); uint8_t* data = stolen.data(); if (newByteLength > oldByteLength) { void* diffStart = data + oldByteLength; size_t diffLength = newByteLength - oldByteLength; # ifdef XP_WIN if (!VirtualAlloc(diffStart, diffLength, MEM_COMMIT, PAGE_READWRITE)) { ReleaseAsmJSMappedData(data); ReportOutOfMemory(cx); return false; } # else // To avoid memset, use MAP_FIXED to clobber the newly-accessible pages // with zero pages. int flags = MAP_FIXED | MAP_PRIVATE | MAP_ANON; if (mmap(diffStart, diffLength, PROT_READ | PROT_WRITE, flags, -1, 0) == MAP_FAILED) { ReleaseAsmJSMappedData(data); ReportOutOfMemory(cx); return false; } # endif MemProfiler::SampleNative(diffStart, diffLength); } else if (newByteLength < oldByteLength) { void* diffStart = data + newByteLength; size_t diffLength = oldByteLength - newByteLength; # ifdef XP_WIN if (!VirtualFree(diffStart, diffLength, MEM_DECOMMIT)) { ReleaseAsmJSMappedData(data); ReportOutOfMemory(cx); return false; } # else if (madvise(diffStart, diffLength, MADV_DONTNEED) || mprotect(diffStart, diffLength, PROT_NONE)) { ReleaseAsmJSMappedData(data); ReportOutOfMemory(cx); return false; } # endif } ArrayBufferObject::BufferContents newContents = ArrayBufferObject::BufferContents::create<ArrayBufferObject::ASMJS_MAPPED>(data); RootedObject newBuffer(cx, ArrayBufferObject::create(cx, newByteLength, newContents)); if (!newBuffer) { ReleaseAsmJSMappedData(data); return false; } args.rval().setObject(*newBuffer); return true; }