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#ifndef PolymorphicPutByIdList_h
27#define PolymorphicPutByIdList_h
28
29#if ENABLE(JIT)
30
31#include "CodeOrigin.h"
32#include "MacroAssembler.h"
33#include "Opcode.h"
34#include "PutKind.h"
35#include "PutPropertySlot.h"
36#include "Structure.h"
37#include <wtf/Vector.h>
38
39namespace JSC {
40
41class CodeBlock;
42struct StructureStubInfo;
43
44class PutByIdAccess {
45public:
46    enum AccessType {
47        Invalid,
48        Transition,
49        Replace,
50        Setter,
51        CustomSetter
52    };
53
54    PutByIdAccess()
55        : m_type(Invalid)
56    {
57    }
58
59    static PutByIdAccess transition(
60        VM& vm,
61        JSCell* owner,
62        Structure* oldStructure,
63        Structure* newStructure,
64        StructureChain* chain,
65        PassRefPtr<JITStubRoutine> stubRoutine)
66    {
67        PutByIdAccess result;
68        result.m_type = Transition;
69        result.m_oldStructure.set(vm, owner, oldStructure);
70        result.m_newStructure.set(vm, owner, newStructure);
71        result.m_chain.set(vm, owner, chain);
72        result.m_customSetter = 0;
73        result.m_stubRoutine = stubRoutine;
74        return result;
75    }
76
77    static PutByIdAccess replace(
78        VM& vm,
79        JSCell* owner,
80        Structure* structure,
81        PassRefPtr<JITStubRoutine> stubRoutine)
82    {
83        PutByIdAccess result;
84        result.m_type = Replace;
85        result.m_oldStructure.set(vm, owner, structure);
86        result.m_customSetter = 0;
87        result.m_stubRoutine = stubRoutine;
88        return result;
89    }
90
91
92    static PutByIdAccess setter(
93        VM& vm,
94        JSCell* owner,
95        AccessType accessType,
96        Structure* structure,
97        StructureChain* chain,
98        PutPropertySlot::PutValueFunc customSetter,
99        PassRefPtr<JITStubRoutine> stubRoutine)
100    {
101        RELEASE_ASSERT(accessType == Setter || accessType == CustomSetter);
102        PutByIdAccess result;
103        result.m_oldStructure.set(vm, owner, structure);
104        result.m_type = accessType;
105        if (chain)
106            result.m_chain.set(vm, owner, chain);
107        result.m_customSetter = customSetter;
108        result.m_stubRoutine = stubRoutine;
109        return result;
110    }
111
112    static PutByIdAccess fromStructureStubInfo(StructureStubInfo&);
113
114    bool isSet() const { return m_type != Invalid; }
115    bool operator!() const { return !isSet(); }
116
117    AccessType type() const { return m_type; }
118
119    bool isTransition() const { return m_type == Transition; }
120    bool isReplace() const { return m_type == Replace; }
121    bool isSetter() const { return m_type == Setter; }
122    bool isCustom() const { return m_type == CustomSetter; }
123
124    Structure* oldStructure() const
125    {
126        // Using this instead of isSet() to make this assertion robust against the possibility
127        // of additional access types being added.
128        ASSERT(isTransition() || isReplace() || isSetter() || isCustom());
129
130        return m_oldStructure.get();
131    }
132
133    Structure* structure() const
134    {
135        ASSERT(isReplace());
136        return m_oldStructure.get();
137    }
138
139    Structure* newStructure() const
140    {
141        ASSERT(isTransition());
142        return m_newStructure.get();
143    }
144
145    StructureChain* chain() const
146    {
147        ASSERT(isTransition() || isSetter() || isCustom());
148        return m_chain.get();
149    }
150
151    JITStubRoutine* stubRoutine() const
152    {
153        ASSERT(isTransition() || isReplace() || isSetter() || isCustom());
154        return m_stubRoutine.get();
155    }
156
157    PutPropertySlot::PutValueFunc customSetter() const
158    {
159        ASSERT(isCustom());
160        return m_customSetter;
161    }
162
163    bool visitWeak(RepatchBuffer&) const;
164
165private:
166    friend class CodeBlock;
167
168    AccessType m_type;
169    WriteBarrier<Structure> m_oldStructure;
170    WriteBarrier<Structure> m_newStructure;
171    WriteBarrier<StructureChain> m_chain;
172    PutPropertySlot::PutValueFunc m_customSetter;
173    RefPtr<JITStubRoutine> m_stubRoutine;
174};
175
176class PolymorphicPutByIdList {
177    WTF_MAKE_FAST_ALLOCATED;
178public:
179    // Either creates a new polymorphic put list, or returns the one that is already
180    // in place.
181    static PolymorphicPutByIdList* from(PutKind, StructureStubInfo&);
182
183    ~PolymorphicPutByIdList();
184
185    MacroAssemblerCodePtr currentSlowPathTarget() const
186    {
187        return m_list.last().stubRoutine()->code().code();
188    }
189
190    void addAccess(const PutByIdAccess&);
191
192    bool isEmpty() const { return m_list.isEmpty(); }
193    unsigned size() const { return m_list.size(); }
194    bool isFull() const;
195    bool isAlmostFull() const; // True if adding an element would make isFull() true.
196    const PutByIdAccess& at(unsigned i) const { return m_list[i]; }
197    const PutByIdAccess& operator[](unsigned i) const { return m_list[i]; }
198
199    PutKind kind() const { return m_kind; }
200
201    bool visitWeak(RepatchBuffer&) const;
202
203private:
204    friend class CodeBlock;
205
206    // Initialize from a stub info; this will place one element in the list and it will
207    // be created by converting the stub info's put by id access information into our
208    // PutByIdAccess.
209    PolymorphicPutByIdList(PutKind, StructureStubInfo&);
210
211    Vector<PutByIdAccess, 2> m_list;
212    PutKind m_kind;
213};
214
215} // namespace JSC
216
217#endif // ENABLE(JIT)
218
219#endif // PolymorphicPutByIdList_h
220
221