1/*
2 * Copyright (C) 2014 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 "PolymorphicGetByIdList.h"
28
29#if ENABLE(JIT)
30
31#include "CodeBlock.h"
32#include "Heap.h"
33#include "JSCInlines.h"
34#include "StructureStubInfo.h"
35
36namespace JSC {
37
38GetByIdAccess::GetByIdAccess(
39    VM& vm, JSCell* owner, AccessType type, PassRefPtr<JITStubRoutine> stubRoutine,
40    Structure* structure, StructureChain* chain, unsigned chainCount)
41    : m_type(type)
42    , m_chainCount(chainCount)
43    , m_structure(vm, owner, structure)
44    , m_stubRoutine(stubRoutine)
45{
46    if (chain)
47        m_chain.set(vm, owner, chain);
48}
49
50GetByIdAccess::~GetByIdAccess()
51{
52}
53
54GetByIdAccess GetByIdAccess::fromStructureStubInfo(StructureStubInfo& stubInfo)
55{
56    MacroAssemblerCodePtr initialSlowPath =
57        stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase);
58
59    GetByIdAccess result;
60
61    switch (stubInfo.accessType) {
62    case access_get_by_id_self:
63        result.m_type = SimpleInline;
64        result.m_structure.copyFrom(stubInfo.u.getByIdSelf.baseObjectStructure);
65        result.m_stubRoutine = JITStubRoutine::createSelfManagedRoutine(initialSlowPath);
66        break;
67
68    case access_get_by_id_chain:
69        result.m_structure.copyFrom(stubInfo.u.getByIdChain.baseObjectStructure);
70        result.m_chain.copyFrom(stubInfo.u.getByIdChain.chain);
71        result.m_chainCount = stubInfo.u.getByIdChain.count;
72        result.m_stubRoutine = stubInfo.stubRoutine;
73        if (stubInfo.u.getByIdChain.isDirect)
74            result.m_type = SimpleStub;
75        else
76            result.m_type = Getter;
77        break;
78
79    default:
80        RELEASE_ASSERT_NOT_REACHED();
81    }
82
83    return result;
84}
85
86bool GetByIdAccess::visitWeak(RepatchBuffer& repatchBuffer) const
87{
88    if (m_structure && !Heap::isMarked(m_structure.get()))
89        return false;
90    if (m_chain && !Heap::isMarked(m_chain.get()))
91        return false;
92    if (!m_stubRoutine->visitWeak(repatchBuffer))
93        return false;
94    return true;
95}
96
97PolymorphicGetByIdList::PolymorphicGetByIdList(StructureStubInfo& stubInfo)
98{
99    if (stubInfo.accessType == access_unset)
100        return;
101
102    m_list.append(GetByIdAccess::fromStructureStubInfo(stubInfo));
103}
104
105PolymorphicGetByIdList* PolymorphicGetByIdList::from(StructureStubInfo& stubInfo)
106{
107    if (stubInfo.accessType == access_get_by_id_list)
108        return stubInfo.u.getByIdList.list;
109
110    ASSERT(
111        stubInfo.accessType == access_get_by_id_self
112        || stubInfo.accessType == access_get_by_id_chain
113        || stubInfo.accessType == access_unset);
114
115    PolymorphicGetByIdList* result = new PolymorphicGetByIdList(stubInfo);
116
117    stubInfo.initGetByIdList(result);
118
119    return result;
120}
121
122PolymorphicGetByIdList::~PolymorphicGetByIdList() { }
123
124MacroAssemblerCodePtr PolymorphicGetByIdList::currentSlowPathTarget(
125    StructureStubInfo& stubInfo) const
126{
127    if (isEmpty())
128        return stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase);
129    return m_list.last().stubRoutine()->code().code();
130}
131
132void PolymorphicGetByIdList::addAccess(const GetByIdAccess& access)
133{
134    ASSERT(!isFull());
135    // Make sure that the resizing optimizes for space, not time.
136    m_list.resize(m_list.size() + 1);
137    m_list.last() = access;
138}
139
140bool PolymorphicGetByIdList::isFull() const
141{
142    ASSERT(size() <= POLYMORPHIC_LIST_CACHE_SIZE);
143    return size() == POLYMORPHIC_LIST_CACHE_SIZE;
144}
145
146bool PolymorphicGetByIdList::isAlmostFull() const
147{
148    ASSERT(size() <= POLYMORPHIC_LIST_CACHE_SIZE);
149    return size() >= POLYMORPHIC_LIST_CACHE_SIZE - 1;
150}
151
152bool PolymorphicGetByIdList::didSelfPatching() const
153{
154    for (unsigned i = size(); i--;) {
155        if (at(i).type() == GetByIdAccess::SimpleInline)
156            return true;
157    }
158    return false;
159}
160
161bool PolymorphicGetByIdList::visitWeak(RepatchBuffer& repatchBuffer) const
162{
163    for (unsigned i = size(); i--;) {
164        if (!at(i).visitWeak(repatchBuffer))
165            return false;
166    }
167    return true;
168}
169
170} // namespace JSC
171
172#endif // ENABLE(JIT)
173
174
175