1/*
2 * Copyright (C) 2008, 2012, 2013, 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 StructureStubInfo_h
27#define StructureStubInfo_h
28
29#include "CodeOrigin.h"
30#include "Instruction.h"
31#include "JITStubRoutine.h"
32#include "MacroAssembler.h"
33#include "Opcode.h"
34#include "PolymorphicAccessStructureList.h"
35#include "RegisterSet.h"
36#include "SpillRegistersMode.h"
37#include "Structure.h"
38#include "StructureStubClearingWatchpoint.h"
39#include <wtf/OwnPtr.h>
40
41namespace JSC {
42
43#if ENABLE(JIT)
44
45class PolymorphicGetByIdList;
46class PolymorphicPutByIdList;
47
48enum AccessType {
49    access_get_by_id_self,
50    access_get_by_id_chain,
51    access_get_by_id_list,
52    access_put_by_id_transition_normal,
53    access_put_by_id_transition_direct,
54    access_put_by_id_replace,
55    access_put_by_id_list,
56    access_unset,
57    access_in_list
58};
59
60inline bool isGetByIdAccess(AccessType accessType)
61{
62    switch (accessType) {
63    case access_get_by_id_self:
64    case access_get_by_id_chain:
65    case access_get_by_id_list:
66        return true;
67    default:
68        return false;
69    }
70}
71
72inline bool isPutByIdAccess(AccessType accessType)
73{
74    switch (accessType) {
75    case access_put_by_id_transition_normal:
76    case access_put_by_id_transition_direct:
77    case access_put_by_id_replace:
78    case access_put_by_id_list:
79        return true;
80    default:
81        return false;
82    }
83}
84
85inline bool isInAccess(AccessType accessType)
86{
87    switch (accessType) {
88    case access_in_list:
89        return true;
90    default:
91        return false;
92    }
93}
94
95struct StructureStubInfo {
96    StructureStubInfo()
97        : accessType(access_unset)
98        , seen(false)
99        , resetByGC(false)
100    {
101    }
102
103    void initGetByIdSelf(VM& vm, JSCell* owner, Structure* baseObjectStructure)
104    {
105        accessType = access_get_by_id_self;
106
107        u.getByIdSelf.baseObjectStructure.set(vm, owner, baseObjectStructure);
108    }
109
110    void initGetByIdChain(VM& vm, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain, unsigned count, bool isDirect)
111    {
112        accessType = access_get_by_id_chain;
113
114        u.getByIdChain.baseObjectStructure.set(vm, owner, baseObjectStructure);
115        u.getByIdChain.chain.set(vm, owner, chain);
116        u.getByIdChain.count = count;
117        u.getByIdChain.isDirect = isDirect;
118    }
119
120    void initGetByIdList(PolymorphicGetByIdList* list)
121    {
122        accessType = access_get_by_id_list;
123        u.getByIdList.list = list;
124    }
125
126    // PutById*
127
128    void initPutByIdTransition(VM& vm, JSCell* owner, Structure* previousStructure, Structure* structure, StructureChain* chain, bool isDirect)
129    {
130        if (isDirect)
131            accessType = access_put_by_id_transition_direct;
132        else
133            accessType = access_put_by_id_transition_normal;
134
135        u.putByIdTransition.previousStructure.set(vm, owner, previousStructure);
136        u.putByIdTransition.structure.set(vm, owner, structure);
137        u.putByIdTransition.chain.set(vm, owner, chain);
138    }
139
140    void initPutByIdReplace(VM& vm, JSCell* owner, Structure* baseObjectStructure)
141    {
142        accessType = access_put_by_id_replace;
143
144        u.putByIdReplace.baseObjectStructure.set(vm, owner, baseObjectStructure);
145    }
146
147    void initPutByIdList(PolymorphicPutByIdList* list)
148    {
149        accessType = access_put_by_id_list;
150        u.putByIdList.list = list;
151    }
152
153    void initInList(PolymorphicAccessStructureList* list, int listSize)
154    {
155        accessType = access_in_list;
156        u.inList.structureList = list;
157        u.inList.listSize = listSize;
158    }
159
160    void reset()
161    {
162        deref();
163        accessType = access_unset;
164        stubRoutine.clear();
165        watchpoints.clear();
166    }
167
168    void deref();
169
170    // Check if the stub has weak references that are dead. If there are dead ones that imply
171    // that the stub should be entirely reset, this should return false. If there are dead ones
172    // that can be handled internally by the stub and don't require a full reset, then this
173    // should reset them and return true. If there are no dead weak references, return true.
174    // If this method returns true it means that it has left the stub in a state where all
175    // outgoing GC pointers are known to point to currently marked objects; this method is
176    // allowed to accomplish this by either clearing those pointers somehow or by proving that
177    // they have already been marked. It is not allowed to mark new objects.
178    bool visitWeakReferences(RepatchBuffer&);
179
180    bool seenOnce()
181    {
182        return seen;
183    }
184
185    void setSeen()
186    {
187        seen = true;
188    }
189
190    StructureStubClearingWatchpoint* addWatchpoint(CodeBlock* codeBlock)
191    {
192        return WatchpointsOnStructureStubInfo::ensureReferenceAndAddWatchpoint(
193            watchpoints, codeBlock, this);
194    }
195
196    int8_t accessType;
197    bool seen : 1;
198    bool resetByGC : 1;
199
200    CodeOrigin codeOrigin;
201
202    struct {
203        unsigned spillMode : 8;
204        int8_t baseGPR;
205#if USE(JSVALUE32_64)
206        int8_t valueTagGPR;
207#endif
208        int8_t valueGPR;
209        RegisterSet usedRegisters;
210        int32_t deltaCallToDone;
211        int32_t deltaCallToStorageLoad;
212        int32_t deltaCallToJump;
213        int32_t deltaCallToSlowCase;
214        int32_t deltaCheckImmToCall;
215#if USE(JSVALUE64)
216        int32_t deltaCallToLoadOrStore;
217#else
218        int32_t deltaCallToTagLoadOrStore;
219        int32_t deltaCallToPayloadLoadOrStore;
220#endif
221    } patch;
222
223    union {
224        struct {
225            // It would be unwise to put anything here, as it will surely be overwritten.
226        } unset;
227        struct {
228            WriteBarrierBase<Structure> baseObjectStructure;
229        } getByIdSelf;
230        struct {
231            WriteBarrierBase<Structure> baseObjectStructure;
232            WriteBarrierBase<Structure> prototypeStructure;
233            bool isDirect;
234        } getByIdProto;
235        struct {
236            WriteBarrierBase<Structure> baseObjectStructure;
237            WriteBarrierBase<StructureChain> chain;
238            unsigned count : 31;
239            bool isDirect : 1;
240        } getByIdChain;
241        struct {
242            PolymorphicGetByIdList* list;
243        } getByIdList;
244        struct {
245            WriteBarrierBase<Structure> previousStructure;
246            WriteBarrierBase<Structure> structure;
247            WriteBarrierBase<StructureChain> chain;
248        } putByIdTransition;
249        struct {
250            WriteBarrierBase<Structure> baseObjectStructure;
251        } putByIdReplace;
252        struct {
253            PolymorphicPutByIdList* list;
254        } putByIdList;
255        struct {
256            PolymorphicAccessStructureList* structureList;
257            int listSize;
258        } inList;
259    } u;
260
261    RefPtr<JITStubRoutine> stubRoutine;
262    CodeLocationCall callReturnLocation;
263    RefPtr<WatchpointsOnStructureStubInfo> watchpoints;
264};
265
266inline CodeOrigin getStructureStubInfoCodeOrigin(StructureStubInfo& structureStubInfo)
267{
268    return structureStubInfo.codeOrigin;
269}
270
271typedef HashMap<CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash> StubInfoMap;
272
273#else
274
275typedef HashMap<int, void*> StubInfoMap;
276
277#endif // ENABLE(JIT)
278
279} // namespace JSC
280
281#endif // StructureStubInfo_h
282