Exemplo n.º 1
0
void
ArrayBufferObject::setDataPointer(BufferContents contents, OwnsState ownsData)
{
    setSlot(DATA_SLOT, PrivateValue(contents.data()));
    setOwnsData(ownsData);
    setFlags((flags() & ~KIND_MASK) | contents.kind());
}
Exemplo n.º 2
0
/* static */ ArrayBufferObject::BufferContents
ArrayBufferObject::stealContents(JSContext* cx, Handle<ArrayBufferObject*> buffer,
                                 bool hasStealableContents)
{
    MOZ_ASSERT_IF(hasStealableContents, buffer->hasStealableContents());

    BufferContents oldContents(buffer->dataPointer(), buffer->bufferKind());
    BufferContents newContents = AllocateArrayBufferContents(cx, buffer->byteLength());
    if (!newContents)
        return BufferContents::createPlain(nullptr);

    if (hasStealableContents) {
        // Return the old contents and give the detached buffer a pointer to
        // freshly allocated memory that we will never write to and should
        // never get committed.
        buffer->setOwnsData(DoesntOwnData);
        if (!ArrayBufferObject::detach(cx, buffer, newContents)) {
            js_free(newContents.data());
            return BufferContents::createPlain(nullptr);
        }
        return oldContents;
    }

    // Create a new chunk of memory to return since we cannot steal the
    // existing contents away from the buffer.
    memcpy(newContents.data(), oldContents.data(), buffer->byteLength());
    if (!ArrayBufferObject::detach(cx, buffer, oldContents)) {
        js_free(newContents.data());
        return BufferContents::createPlain(nullptr);
    }
    return newContents;
}
Exemplo n.º 3
0
/* static */ bool
ArrayBufferObject::prepareForAsmJS(JSContext* cx, Handle<ArrayBufferObject*> buffer, bool signalsForOOB)
{
    MOZ_ASSERT(buffer->byteLength() % wasm::PageSize == 0);

    if (signalsForOOB) {
#ifdef ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB
        if (buffer->isWasmMapped())
            return true;

        // This can't happen except via the shell toggling signals.enabled.
        if (buffer->isWasmMalloced()) {
            JS_ReportError(cx, "can't access same buffer with and without signals enabled");
            return false;
        }

        if (buffer->forInlineTypedObject()) {
            JS_ReportError(cx, "ArrayBuffer can't be used by asm.js");
            return false;
        }

        void* data = AllocateWasmMappedMemory(buffer->byteLength());
        if (!data) {
            ReportOutOfMemory(cx);
            return false;
        }

        // Copy over the current contents of the typed array.
        memcpy(data, buffer->dataPointer(), buffer->byteLength());

        // Swap the new elements into the ArrayBufferObject. Mark the
        // ArrayBufferObject so we don't do this again.
        BufferContents newContents = BufferContents::create<WASM_MAPPED>(data);
        buffer->changeContents(cx, newContents);
        MOZ_ASSERT(data == buffer->dataPointer());
        return true;
#else
        MOZ_CRASH("shouldn't be using signal handlers for out-of-bounds");
#endif  // ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB
    }

    if (buffer->forInlineTypedObject()) {
        JS_ReportError(cx, "ArrayBuffer can't be used by asm.js");
        return false;
    }

    if (!buffer->ownsData()) {
        BufferContents contents = AllocateArrayBufferContents(cx, buffer->byteLength());
        if (!contents)
            return false;
        memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
        buffer->changeContents(cx, contents);
    }

    buffer->setIsWasmMalloced();
    return true;
}
Exemplo n.º 4
0
/* static */ bool
ArrayBufferObject::detach(JSContext* cx, Handle<ArrayBufferObject*> buffer,
                          BufferContents newContents)
{
    if (buffer->isWasm()) {
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY);
        return false;
    }

    // When detaching buffers where we don't know all views, the new data must
    // match the old data. All missing views are typed objects, which do not
    // expect their data to ever change.
    MOZ_ASSERT_IF(buffer->forInlineTypedObject(),
                  newContents.data() == buffer->dataPointer());

    // When detaching a buffer with typed object views, any jitcode accessing
    // such views must be deoptimized so that detachment checks are performed.
    // This is done by setting a compartment-wide flag indicating that buffers
    // with typed object views have been detached.
    if (buffer->hasTypedObjectViews()) {
        // Make sure the global object's group has been instantiated, so the
        // flag change will be observed.
        AutoEnterOOMUnsafeRegion oomUnsafe;
        if (!cx->global()->getGroup(cx))
            oomUnsafe.crash("ArrayBufferObject::detach");
        MarkObjectGroupFlags(cx, cx->global(), OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER);
        cx->compartment()->detachedTypedObjects = 1;
    }

    // Update all views of the buffer to account for the buffer having been
    // detached, and clear the buffer's data and list of views.

    if (InnerViewTable::ViewVector* views = cx->compartment()->innerViews.maybeViewsUnbarriered(buffer)) {
        for (size_t i = 0; i < views->length(); i++)
            NoteViewBufferWasDetached((*views)[i], newContents, cx);
        cx->compartment()->innerViews.removeViews(buffer);
    }
    if (buffer->firstView()) {
        if (buffer->forInlineTypedObject()) {
            // The buffer points to inline data in its first view, so to keep
            // this pointer alive we don't clear out the first view.
            MOZ_ASSERT(buffer->firstView()->is<InlineTransparentTypedObject>());
        } else {
            NoteViewBufferWasDetached(buffer->firstView(), newContents, cx);
            buffer->setFirstView(nullptr);
        }
    }

    if (newContents.data() != buffer->dataPointer())
        buffer->setNewOwnedData(cx->runtime()->defaultFreeOp(), newContents);

    buffer->setByteLength(0);
    buffer->setIsDetached();
    return true;
}
Exemplo n.º 5
0
/* static */ bool
ArrayBufferObject::neuter(JSContext* cx, Handle<ArrayBufferObject*> buffer,
                          BufferContents newContents)
{
    if (buffer->isAsmJS() && !OnDetachAsmJSArrayBuffer(cx, buffer))
        return false;

    // When neutering buffers where we don't know all views, the new data must
    // match the old data. All missing views are typed objects, which do not
    // expect their data to ever change.
    MOZ_ASSERT_IF(buffer->forInlineTypedObject(),
                  newContents.data() == buffer->dataPointer());

    // When neutering a buffer with typed object views, any jitcode which
    // accesses such views needs to be deoptimized so that neuter checks are
    // performed. This is done by setting a compartment wide flag indicating
    // that buffers with typed object views have been neutered.
    if (buffer->hasTypedObjectViews()) {
        // Make sure the global object's group has been instantiated, so the
        // flag change will be observed.
        AutoEnterOOMUnsafeRegion oomUnsafe;
        if (!cx->global()->getGroup(cx))
            oomUnsafe.crash("ArrayBufferObject::neuter");
        MarkObjectGroupFlags(cx, cx->global(), OBJECT_FLAG_TYPED_OBJECT_NEUTERED);
        cx->compartment()->neuteredTypedObjects = 1;
    }

    // Neuter all views on the buffer, clear out the list of views and the
    // buffer's data.

    if (InnerViewTable::ViewVector* views = cx->compartment()->innerViews.maybeViewsUnbarriered(buffer)) {
        for (size_t i = 0; i < views->length(); i++)
            buffer->neuterView(cx, (*views)[i], newContents);
        cx->compartment()->innerViews.removeViews(buffer);
    }
    if (buffer->firstView()) {
        if (buffer->forInlineTypedObject()) {
            // The buffer points to inline data in its first view, so to keep
            // this pointer alive we don't clear out the first view.
            MOZ_ASSERT(buffer->firstView()->is<InlineTransparentTypedObject>());
        } else {
            buffer->neuterView(cx, buffer->firstView(), newContents);
            buffer->setFirstView(nullptr);
        }
    }

    if (newContents.data() != buffer->dataPointer())
        buffer->setNewOwnedData(cx->runtime()->defaultFreeOp(), newContents);

    buffer->setByteLength(0);
    buffer->setIsNeutered();
    return true;
}
Exemplo n.º 6
0
void
ArrayBufferObject::neuterView(JSContext* cx, ArrayBufferViewObject* view,
                              BufferContents newContents)
{
    view->neuter(newContents.data());

    // Notify compiled jit code that the base pointer has moved.
    MarkObjectStateChange(cx, view);
}
Exemplo n.º 7
0
void
ArrayBufferObject::setNewOwnedData(FreeOp* fop, BufferContents newContents)
{
    if (ownsData()) {
        MOZ_ASSERT(newContents.data() != dataPointer());
        releaseData(fop);
    }

    setDataPointer(newContents, OwnsData);
}
Exemplo n.º 8
0
/* static */ bool
ArrayBufferObject::prepareForAsmJSNoSignals(JSContext* cx, Handle<ArrayBufferObject*> buffer)
{
    if (buffer->forInlineTypedObject()) {
        JS_ReportError(cx, "ArrayBuffer can't be used by asm.js");
        return false;
    }

    if (!buffer->ownsData()) {
        BufferContents contents = AllocateArrayBufferContents(cx, buffer->byteLength());
        if (!contents)
            return false;
        memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
        buffer->changeContents(cx, contents);
    }

    buffer->setIsAsmJSMalloced();
    return true;
}
Exemplo n.º 9
0
void
ArrayBufferObject::changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
                                      uint8_t* oldDataPointer, BufferContents newContents)
{
    // Watch out for NULL data pointers in views. This means that the view
    // is not fully initialized (in which case it'll be initialized later
    // with the correct pointer).
    uint8_t* viewDataPointer = view->dataPointer();
    if (viewDataPointer) {
        MOZ_ASSERT(newContents);
        ptrdiff_t offset = viewDataPointer - oldDataPointer;
        viewDataPointer = static_cast<uint8_t*>(newContents.data()) + offset;
        view->setDataPointer(viewDataPointer);
    }

    // Notify compiled jit code that the base pointer has moved.
    MarkObjectStateChange(cx, view);
}