1/*
2 * Copyright (C) 2013 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 "FTLAbstractHeap.h"
28
29#if ENABLE(FTL_JIT)
30
31#include "FTLAbbreviations.h"
32#include "FTLAbstractHeapRepository.h"
33#include "FTLOutput.h"
34#include "FTLTypedPointer.h"
35#include "JSCInlines.h"
36#include "Options.h"
37
38namespace JSC { namespace FTL {
39
40LValue AbstractHeap::tbaaMetadataSlow(const AbstractHeapRepository& repository) const
41{
42    m_tbaaMetadata = mdNode(
43        repository.m_context,
44        mdString(repository.m_context, m_heapName),
45        m_parent->tbaaMetadata(repository));
46    return m_tbaaMetadata;
47}
48
49void AbstractHeap::decorateInstruction(LValue instruction, const AbstractHeapRepository& repository) const
50{
51    if (!Options::useFTLTBAA())
52        return;
53    setMetadata(instruction, repository.m_tbaaKind, tbaaMetadata(repository));
54}
55
56IndexedAbstractHeap::IndexedAbstractHeap(LContext context, AbstractHeap* parent, const char* heapName, ptrdiff_t offset, size_t elementSize)
57    : m_heapForAnyIndex(parent, heapName)
58    , m_heapNameLength(strlen(heapName))
59    , m_offset(offset)
60    , m_elementSize(elementSize)
61    , m_scaleTerm(0)
62    , m_canShift(false)
63{
64    // See if there is a common shift amount we could use instead of multiplying. Don't
65    // try too hard. This is just a speculative optimization to reduce load on LLVM.
66    for (unsigned i = 0; i < 4; ++i) {
67        if (1U << i == m_elementSize) {
68            if (i)
69                m_scaleTerm = constInt(intPtrType(context), i, ZeroExtend);
70            m_canShift = true;
71            break;
72        }
73    }
74
75    if (!m_canShift)
76        m_scaleTerm = constInt(intPtrType(context), m_elementSize, ZeroExtend);
77}
78
79IndexedAbstractHeap::~IndexedAbstractHeap()
80{
81}
82
83TypedPointer IndexedAbstractHeap::baseIndex(Output& out, LValue base, LValue index, JSValue indexAsConstant, ptrdiff_t offset)
84{
85    if (indexAsConstant.isInt32())
86        return out.address(base, at(indexAsConstant.asInt32()), offset);
87
88    LValue result;
89    if (m_canShift) {
90        if (!m_scaleTerm)
91            result = out.add(base, index);
92        else
93            result = out.add(base, out.shl(index, m_scaleTerm));
94    } else
95        result = out.add(base, out.mul(index, m_scaleTerm));
96
97    return TypedPointer(atAnyIndex(), out.addPtr(result, m_offset + offset));
98}
99
100const AbstractField& IndexedAbstractHeap::atSlow(ptrdiff_t index)
101{
102    ASSERT(static_cast<size_t>(index) >= m_smallIndices.size());
103
104    if (UNLIKELY(!m_largeIndices))
105        m_largeIndices = adoptPtr(new MapType());
106
107    std::unique_ptr<AbstractField>& field = m_largeIndices->add(index, nullptr).iterator->value;
108    if (!field) {
109        field = std::make_unique<AbstractField>();
110        initialize(*field, index);
111    }
112
113    return *field;
114}
115
116void IndexedAbstractHeap::initialize(AbstractField& field, ptrdiff_t signedIndex)
117{
118    // Build up a name of the form:
119    //
120    //    heapName_hexIndex
121    //
122    // or:
123    //
124    //    heapName_neg_hexIndex
125    //
126    // For example if you access an indexed heap called FooBar at index 5, you'll
127    // get:
128    //
129    //    FooBar_5
130    //
131    // Or if you access an indexed heap called Blah at index -10, you'll get:
132    //
133    //    Blah_neg_A
134    //
135    // This is important because LLVM uses the string to distinguish the types.
136
137    static const char* negSplit = "_neg_";
138    static const char* posSplit = "_";
139
140    bool negative;
141    size_t index;
142    if (signedIndex < 0) {
143        negative = true;
144        index = -signedIndex;
145    } else {
146        negative = false;
147        index = signedIndex;
148    }
149
150    for (unsigned power = 4; power <= sizeof(void*) * 8; power += 4) {
151        if (isGreaterThanNonZeroPowerOfTwo(index, power))
152            continue;
153
154        unsigned numHexlets = power >> 2;
155
156        size_t stringLength = m_heapNameLength + (negative ? strlen(negSplit) : strlen(posSplit)) + numHexlets;
157        char* characters;
158        m_largeIndexNames.append(CString::newUninitialized(stringLength, characters));
159
160        memcpy(characters, m_heapForAnyIndex.heapName(), m_heapNameLength);
161        if (negative)
162            memcpy(characters + m_heapNameLength, negSplit, strlen(negSplit));
163        else
164            memcpy(characters + m_heapNameLength, posSplit, strlen(posSplit));
165
166        size_t accumulator = index;
167        for (unsigned i = 0; i < numHexlets; ++i) {
168            characters[stringLength - i - 1] = lowerNibbleToASCIIHexDigit(accumulator);
169            accumulator >>= 4;
170        }
171
172        field.initialize(&m_heapForAnyIndex, characters, m_offset + signedIndex * m_elementSize);
173        return;
174    }
175
176    RELEASE_ASSERT_NOT_REACHED();
177}
178
179NumberedAbstractHeap::NumberedAbstractHeap(LContext context, AbstractHeap* heap, const char* heapName)
180    : m_indexedHeap(context, heap, heapName, 0, 1)
181{
182}
183
184NumberedAbstractHeap::~NumberedAbstractHeap()
185{
186}
187
188AbsoluteAbstractHeap::AbsoluteAbstractHeap(LContext context, AbstractHeap* heap, const char* heapName)
189    : m_indexedHeap(context, heap, heapName, 0, 1)
190{
191}
192
193AbsoluteAbstractHeap::~AbsoluteAbstractHeap()
194{
195}
196
197} } // namespace JSC::FTL
198
199#endif // ENABLE(FTL_JIT)
200
201