1/*
2 * Copyright (C) 2017 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 "JSMarkingConstraintPrivate.h"
28
29#include "APICast.h"
30#include "JSCInlines.h"
31#include "SimpleMarkingConstraint.h"
32
33using namespace JSC;
34
35namespace {
36
37Atomic<unsigned> constraintCounter;
38
39struct Marker : JSMarker {
40 SlotVisitor* visitor;
41};
42
43bool isMarked(JSMarkerRef markerRef, JSObjectRef objectRef)
44{
45 if (!objectRef)
46 return true; // Null is an immortal object.
47
48 return static_cast<Marker*>(markerRef)->visitor->vm().heap.isMarked(toJS(objectRef));
49}
50
51void mark(JSMarkerRef markerRef, JSObjectRef objectRef)
52{
53 if (!objectRef)
54 return;
55
56 static_cast<Marker*>(markerRef)->visitor->appendHiddenUnbarriered(toJS(objectRef));
57}
58
59} // anonymous namespace
60
61void JSContextGroupAddMarkingConstraint(JSContextGroupRef group, JSMarkingConstraint constraintCallback, void *userData)
62{
63 VM& vm = *toJS(group);
64 JSLockHolder locker(vm);
65
66 unsigned constraintIndex = constraintCounter.exchangeAdd(1);
67
68 // This is a guess. The algorithm should be correct no matter what we pick. This means
69 // that we expect this constraint to mark things even during a stop-the-world full GC, but
70 // we don't expect it to be able to mark anything at the very start of a GC before anything
71 // else gets marked.
72 ConstraintVolatility volatility = ConstraintVolatility::GreyedByMarking;
73
74 auto constraint = makeUnique<SimpleMarkingConstraint>(
75 toCString("Amc", constraintIndex, "(", RawPointer(bitwise_cast<void*>(constraintCallback)), ")"),
76 toCString("API Marking Constraint #", constraintIndex, " (", RawPointer(bitwise_cast<void*>(constraintCallback)), ", ", RawPointer(userData), ")"),
77 [constraintCallback, userData]
78 (SlotVisitor& slotVisitor) {
79 Marker marker;
80 marker.IsMarked = isMarked;
81 marker.Mark = mark;
82 marker.visitor = &slotVisitor;
83
84 constraintCallback(&marker, userData);
85 },
86 volatility,
87 ConstraintConcurrency::Sequential);
88
89 vm.heap.addMarkingConstraint(WTFMove(constraint));
90}
91