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#include "config.h"
27#include "JITStubRoutineSet.h"
28
29#if ENABLE(JIT)
30
31#include "GCAwareJITStubRoutine.h"
32#include "JSCInlines.h"
33#include "SlotVisitor.h"
34
35namespace JSC {
36
37JITStubRoutineSet::JITStubRoutineSet() { }
38JITStubRoutineSet::~JITStubRoutineSet()
39{
40 for (auto& entry : m_routines) {
41 GCAwareJITStubRoutine* routine = entry.routine;
42 routine->m_mayBeExecuting = false;
43
44 if (!routine->m_isJettisoned) {
45 // Inform the deref() routine that it should delete this guy as soon
46 // as the ref count reaches zero.
47 routine->m_isJettisoned = true;
48 continue;
49 }
50
51 routine->deleteFromGC();
52 }
53}
54
55void JITStubRoutineSet::add(GCAwareJITStubRoutine* routine)
56{
57 ASSERT(!routine->m_isJettisoned);
58
59 m_routines.append(Routine {
60 routine->startAddress(),
61 routine
62 });
63}
64
65void JITStubRoutineSet::prepareForConservativeScan()
66{
67 if (m_routines.isEmpty()) {
68 m_range = Range<uintptr_t> { 0, 0 };
69 return;
70 }
71 std::sort(
72 m_routines.begin(), m_routines.end(),
73 [&] (const Routine& a, const Routine& b) {
74 return a.startAddress < b.startAddress;
75 });
76 m_range = Range<uintptr_t> {
77 m_routines.first().startAddress,
78 m_routines.last().routine->endAddress()
79 };
80}
81
82void JITStubRoutineSet::clearMarks()
83{
84 for (auto& entry : m_routines)
85 entry.routine->m_mayBeExecuting = false;
86}
87
88void JITStubRoutineSet::markSlow(uintptr_t address)
89{
90 ASSERT(isJITPC(bitwise_cast<void*>(address)));
91 ASSERT(!m_routines.isEmpty());
92
93 Routine* result = approximateBinarySearch<Routine>(
94 m_routines.begin(), m_routines.size(), address,
95 [] (const Routine* routine) -> uintptr_t { return routine->startAddress; });
96 if (result) {
97 auto markIfContained = [&] (const Routine& routine, uintptr_t address) {
98 if (routine.startAddress <= address && address < routine.routine->endAddress()) {
99 routine.routine->m_mayBeExecuting = true;
100 return true;
101 }
102 return false;
103 };
104
105 if (result > m_routines.begin()) {
106 if (markIfContained(result[-1], address))
107 return;
108 }
109 if (markIfContained(result[0], address))
110 return;
111 if (result + 1 < m_routines.end()) {
112 if (markIfContained(result[1], address))
113 return;
114 }
115 }
116}
117
118void JITStubRoutineSet::deleteUnmarkedJettisonedStubRoutines()
119{
120 unsigned srcIndex = 0;
121 unsigned dstIndex = srcIndex;
122 while (srcIndex < m_routines.size()) {
123 Routine routine = m_routines[srcIndex++];
124 if (!routine.routine->m_isJettisoned || routine.routine->m_mayBeExecuting) {
125 m_routines[dstIndex++] = routine;
126 continue;
127 }
128 routine.routine->deleteFromGC();
129 }
130 m_routines.shrink(dstIndex);
131}
132
133void JITStubRoutineSet::traceMarkedStubRoutines(SlotVisitor& visitor)
134{
135 for (auto& entry : m_routines) {
136 GCAwareJITStubRoutine* routine = entry.routine;
137 if (!routine->m_mayBeExecuting)
138 continue;
139
140 routine->markRequiredObjects(visitor);
141 }
142}
143
144} // namespace JSC
145
146#endif // ENABLE(JIT)
147
148