1/*
2 * Copyright (C) 2012, 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 "PolymorphicPutByIdList.h"
28
29#if ENABLE(JIT)
30
31#include "StructureStubInfo.h"
32
33namespace JSC {
34
35PutByIdAccess PutByIdAccess::fromStructureStubInfo(StructureStubInfo& stubInfo)
36{
37    MacroAssemblerCodePtr initialSlowPath =
38        stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase);
39
40    PutByIdAccess result;
41
42    switch (stubInfo.accessType) {
43    case access_put_by_id_replace:
44        result.m_type = Replace;
45        result.m_oldStructure.copyFrom(stubInfo.u.putByIdReplace.baseObjectStructure);
46        result.m_stubRoutine = JITStubRoutine::createSelfManagedRoutine(initialSlowPath);
47        break;
48
49    case access_put_by_id_transition_direct:
50    case access_put_by_id_transition_normal:
51        result.m_type = Transition;
52        result.m_oldStructure.copyFrom(stubInfo.u.putByIdTransition.previousStructure);
53        result.m_newStructure.copyFrom(stubInfo.u.putByIdTransition.structure);
54        result.m_chain.copyFrom(stubInfo.u.putByIdTransition.chain);
55        result.m_stubRoutine = stubInfo.stubRoutine;
56        break;
57
58    default:
59        RELEASE_ASSERT_NOT_REACHED();
60    }
61
62    return result;
63}
64
65bool PutByIdAccess::visitWeak(RepatchBuffer& repatchBuffer) const
66{
67    switch (m_type) {
68    case Replace:
69        if (!Heap::isMarked(m_oldStructure.get()))
70            return false;
71        break;
72    case Transition:
73        if (!Heap::isMarked(m_oldStructure.get()))
74            return false;
75        if (!Heap::isMarked(m_newStructure.get()))
76            return false;
77        if (!Heap::isMarked(m_chain.get()))
78            return false;
79        break;
80    case Setter:
81    case CustomSetter:
82        if (!Heap::isMarked(m_oldStructure.get()))
83            return false;
84        if (m_chain && !Heap::isMarked(m_chain.get()))
85            return false;
86        break;
87    default:
88        RELEASE_ASSERT_NOT_REACHED();
89        return false;
90    }
91    if (!m_stubRoutine->visitWeak(repatchBuffer))
92        return false;
93    return true;
94}
95
96PolymorphicPutByIdList::PolymorphicPutByIdList(
97    PutKind putKind, StructureStubInfo& stubInfo)
98    : m_kind(putKind)
99{
100    if (stubInfo.accessType != access_unset)
101        m_list.append(PutByIdAccess::fromStructureStubInfo(stubInfo));
102}
103
104PolymorphicPutByIdList* PolymorphicPutByIdList::from(
105    PutKind putKind, StructureStubInfo& stubInfo)
106{
107    if (stubInfo.accessType == access_put_by_id_list)
108        return stubInfo.u.putByIdList.list;
109
110    ASSERT(stubInfo.accessType == access_put_by_id_replace
111        || stubInfo.accessType == access_put_by_id_transition_normal
112        || stubInfo.accessType == access_put_by_id_transition_direct
113        || stubInfo.accessType == access_unset);
114
115    PolymorphicPutByIdList* result =
116        new PolymorphicPutByIdList(putKind, stubInfo);
117
118    stubInfo.initPutByIdList(result);
119
120    return result;
121}
122
123PolymorphicPutByIdList::~PolymorphicPutByIdList() { }
124
125bool PolymorphicPutByIdList::isFull() const
126{
127    ASSERT(size() <= POLYMORPHIC_LIST_CACHE_SIZE);
128    return size() == POLYMORPHIC_LIST_CACHE_SIZE;
129}
130
131bool PolymorphicPutByIdList::isAlmostFull() const
132{
133    ASSERT(size() <= POLYMORPHIC_LIST_CACHE_SIZE);
134    return size() >= POLYMORPHIC_LIST_CACHE_SIZE - 1;
135}
136
137void PolymorphicPutByIdList::addAccess(const PutByIdAccess& putByIdAccess)
138{
139    ASSERT(!isFull());
140    // Make sure that the resizing optimizes for space, not time.
141    m_list.resize(m_list.size() + 1);
142    m_list.last() = putByIdAccess;
143}
144
145bool PolymorphicPutByIdList::visitWeak(RepatchBuffer& repatchBuffer) const
146{
147    for (unsigned i = 0; i < size(); ++i) {
148        if (!at(i).visitWeak(repatchBuffer))
149            return false;
150    }
151    return true;
152}
153
154} // namespace JSC
155
156#endif // ENABLE(JIT)
157