0a69ec7165ea8573eedb83a3cf39302c8d8792ff
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSImmutableButterfly.h
1 /*
2  * Copyright (C) 2018 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 #pragma once
27
28 #include "IndexingHeader.h"
29 #include "JSCell.h"
30
31 namespace JSC {
32
33 class JSImmutableButterfly : public JSCell {
34     using Base = JSCell;
35
36 public:
37     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
38
39     DECLARE_INFO;
40
41     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType)
42     {
43         return Structure::create(vm, globalObject, prototype, TypeInfo(JSImmutableButterflyType, StructureFlags), info(), indexingType);
44     }
45
46     ALWAYS_INLINE static JSImmutableButterfly* tryCreate(VM& vm, Structure* structure, unsigned size)
47     {
48         Checked<size_t, RecordOverflow> checkedAllocationSize = allocationSize(size);
49         if (UNLIKELY(checkedAllocationSize.hasOverflowed()))
50             return nullptr;
51
52         void* buffer = tryAllocateCell<JSImmutableButterfly>(vm.heap, checkedAllocationSize.unsafeGet());
53         if (UNLIKELY(!buffer))
54             return nullptr;
55         JSImmutableButterfly* result = new (NotNull, buffer) JSImmutableButterfly(vm, structure, size);
56         result->finishCreation(vm);
57         return result;
58     }
59
60     static JSImmutableButterfly* create(VM& vm, IndexingType indexingType, unsigned length)
61     {
62         auto* array = tryCreate(vm, vm.immutableButterflyStructures[arrayIndexFromIndexingType(indexingType) - NumberOfIndexingShapes].get(), length);
63         RELEASE_ASSERT(array);
64         return array;
65     }
66
67     unsigned publicLength() const { return m_header.publicLength(); }
68     unsigned vectorLength() const { return m_header.vectorLength(); }
69     unsigned length() const { return m_header.publicLength(); }
70
71     Butterfly* toButterfly() const { return bitwise_cast<Butterfly*>(bitwise_cast<char*>(this) + offsetOfData()); }
72     static JSImmutableButterfly* fromButterfly(Butterfly* butterfly) { return bitwise_cast<JSImmutableButterfly*>(bitwise_cast<char*>(butterfly) - offsetOfData()); }
73
74     JSValue get(unsigned index) const
75     {
76         if (!hasDouble(indexingMode()))
77             return toButterfly()->contiguous().at(this, index).get();
78         double value = toButterfly()->contiguousDouble().at(this, index);
79         // Holes are not supported yet.
80         ASSERT(!std::isnan(value));
81         return jsNumber(value);
82     }
83
84     static void visitChildren(JSCell*, SlotVisitor&);
85
86     void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
87
88     template<typename>
89     static CompleteSubspace* subspaceFor(VM& vm)
90     {
91         // We allocate out of the JSValue gigacage as other code expects all butterflies to live there.
92         return &vm.jsValueGigacageAuxiliarySpace;
93     }
94
95     // Only call this if you just allocated this butterfly.
96     void setIndex(VM& vm, unsigned index, JSValue value)
97     {
98         if (hasDouble(indexingType()))
99             toButterfly()->contiguousDouble().atUnsafe(index) = value.asNumber();
100         else
101             toButterfly()->contiguous().atUnsafe(index).set(vm, this, value);
102     }
103
104 private:
105     static constexpr size_t offsetOfData()
106     {
107         return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSImmutableButterfly));
108     }
109
110     static Checked<size_t, RecordOverflow> allocationSize(Checked<size_t, RecordOverflow> numItems)
111     {
112         return offsetOfData() + numItems * sizeof(WriteBarrier<Unknown>);
113     }
114
115     JSImmutableButterfly(VM& vm, Structure* structure, unsigned length)
116         : Base(vm, structure)
117     {
118         m_header.setVectorLength(length);
119         m_header.setPublicLength(length);
120     }
121
122     IndexingHeader m_header;
123 };
124
125 } // namespace JSC