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