Bmalloc and GC should put auxiliaries (butterflies, typed array backing stores) in...
[WebKit.git] / Source / JavaScriptCore / wasm / js / JSWebAssemblyMemory.cpp
1 /*
2  * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "JSWebAssemblyMemory.h"
28
29 #if ENABLE(WEBASSEMBLY)
30
31 #include "JSCInlines.h"
32
33 #include "ArrayBuffer.h"
34 #include "JSArrayBuffer.h"
35
36 namespace JSC {
37
38 const ClassInfo JSWebAssemblyMemory::s_info = { "WebAssembly.Memory", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWebAssemblyMemory) };
39
40 JSWebAssemblyMemory* JSWebAssemblyMemory::create(ExecState* exec, VM& vm, Structure* structure, Ref<Wasm::Memory>&& memory)
41 {
42     auto throwScope = DECLARE_THROW_SCOPE(vm);
43     auto* globalObject = exec->lexicalGlobalObject();
44
45     auto exception = [&] (JSObject* error) {
46         throwException(exec, throwScope, error);
47         return nullptr;
48     };
49
50     if (!globalObject->webAssemblyEnabled())
51         return exception(createEvalError(exec, globalObject->webAssemblyDisabledErrorMessage()));
52
53     auto* instance = new (NotNull, allocateCell<JSWebAssemblyMemory>(vm.heap)) JSWebAssemblyMemory(vm, structure, WTFMove(memory));
54     instance->m_memory->check();
55     instance->finishCreation(vm);
56     return instance;
57 }
58
59 Structure* JSWebAssemblyMemory::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
60 {
61     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
62 }
63
64 JSWebAssemblyMemory::JSWebAssemblyMemory(VM& vm, Structure* structure, Ref<Wasm::Memory>&& memory)
65     : Base(vm, structure)
66     , m_memory(WTFMove(memory))
67 {
68     ASSERT(m_memory->refCount() == 1);
69     m_memoryBase = m_memory->memory();
70     m_memorySize = m_memory->size();
71 }
72
73 JSArrayBuffer* JSWebAssemblyMemory::buffer(VM& vm, JSGlobalObject* globalObject)
74 {
75     if (m_bufferWrapper)
76         return m_bufferWrapper.get();
77
78     // We can't use a ref here since it doesn't have a copy constructor...
79     Ref<Wasm::Memory> protectedMemory = m_memory.get();
80     auto destructor = [protectedMemory = WTFMove(protectedMemory)] (void*) { };
81     m_buffer = ArrayBuffer::createFromBytes(memory().memory(), memory().size(), WTFMove(destructor));
82     m_buffer->makeWasmMemory();
83     m_bufferWrapper.set(vm, this, JSArrayBuffer::create(vm, globalObject->m_arrayBufferStructure.get(), m_buffer.get()));
84     RELEASE_ASSERT(m_bufferWrapper);
85     return m_bufferWrapper.get();
86 }
87
88 Wasm::PageCount JSWebAssemblyMemory::grow(VM& vm, ExecState* exec, uint32_t delta, bool shouldThrowExceptionsOnFailure)
89 {
90     // Note: We can only use exec if shouldThrowExceptionsOnFailure is true.
91     auto throwScope = DECLARE_THROW_SCOPE(vm);
92
93     Wasm::PageCount oldPageCount = memory().sizeInPages();
94
95     if (!Wasm::PageCount::isValid(delta)) {
96         if (shouldThrowExceptionsOnFailure)
97             throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory.grow expects the delta to be a valid page count")));
98         return Wasm::PageCount();
99     }
100
101     Wasm::PageCount newSize = oldPageCount + Wasm::PageCount(delta);
102     if (!newSize) {
103         if (shouldThrowExceptionsOnFailure)
104             throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory.grow expects the grown size to be a valid page count")));
105         return Wasm::PageCount();
106     }
107
108     if (delta) {
109         bool success = memory().grow(vm, newSize);
110         if (!success) {
111             ASSERT(m_memoryBase == memory().memory());
112             ASSERT(m_memorySize == memory().size());
113             if (shouldThrowExceptionsOnFailure)
114                 throwException(exec, throwScope, createOutOfMemoryError(exec));
115             return Wasm::PageCount();
116         }
117         m_memoryBase = memory().memory();
118         m_memorySize = memory().size();
119     }
120
121     // We need to clear out the old array buffer because it might now be pointing
122     // to stale memory.
123     // Neuter the old array.
124     if (m_buffer) {
125         m_buffer->neuter(vm);
126         m_buffer = nullptr;
127         m_bufferWrapper.clear();
128     }
129
130     memory().check();
131
132     vm.heap.reportExtraMemoryAllocated(Wasm::PageCount(delta).bytes());
133     return oldPageCount;
134 }
135
136 void JSWebAssemblyMemory::finishCreation(VM& vm)
137 {
138     Base::finishCreation(vm);
139     ASSERT(inherits(vm, info()));
140     heap()->reportExtraMemoryAllocated(memory().size());
141 }
142
143 void JSWebAssemblyMemory::destroy(JSCell* cell)
144 {
145     auto memory = static_cast<JSWebAssemblyMemory*>(cell);
146     ASSERT(memory->classInfo() == info());
147
148     memory->JSWebAssemblyMemory::~JSWebAssemblyMemory();
149 }
150
151 void JSWebAssemblyMemory::visitChildren(JSCell* cell, SlotVisitor& visitor)
152 {
153     auto* thisObject = jsCast<JSWebAssemblyMemory*>(cell);
154     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
155
156     Base::visitChildren(thisObject, visitor);
157     visitor.append(thisObject->m_bufferWrapper);
158     visitor.reportExtraMemoryVisited(thisObject->memory().size());
159 }
160
161 } // namespace JSC
162
163 #endif // ENABLE(WEBASSEMBLY)