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