Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : *
4 : * Copyright 2016 Mozilla Foundation
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #include "wasm/WasmCompartment.h"
20 :
21 : #include "jscompartment.h"
22 :
23 : #include "wasm/WasmInstance.h"
24 :
25 : #include "vm/Debugger-inl.h"
26 :
27 : using namespace js;
28 : using namespace wasm;
29 :
30 : // With tiering, instances can have one or two code segments, and code that
31 : // searches the instance list will change. Search for Tier::TBD below.
32 :
33 315 : Compartment::Compartment(Zone* zone)
34 315 : : mutatingInstances_(false)
35 315 : {}
36 :
37 0 : Compartment::~Compartment()
38 : {
39 0 : MOZ_ASSERT(instances_.empty());
40 0 : MOZ_ASSERT(!mutatingInstances_);
41 0 : }
42 :
43 : struct InstanceComparator
44 : {
45 : const Instance& target;
46 0 : explicit InstanceComparator(const Instance& target) : target(target) {}
47 :
48 0 : int operator()(const Instance* instance) const {
49 0 : if (instance == &target)
50 0 : return 0;
51 :
52 : // Instances can share code, so the segments can be equal (though they
53 : // can't partially overlap). If the codeBases are equal, we sort by
54 : // Instance address. Thus a Code may map to many instances.
55 0 : if (instance->codeBase(Tier::TBD) == target.codeBase(Tier::TBD))
56 0 : return instance < &target ? -1 : 1;
57 :
58 0 : return target.codeBase(Tier::TBD) < instance->codeBase(Tier::TBD) ? -1 : 1;
59 : }
60 : };
61 :
62 : bool
63 0 : Compartment::registerInstance(JSContext* cx, HandleWasmInstanceObject instanceObj)
64 : {
65 0 : Instance& instance = instanceObj->instance();
66 0 : MOZ_ASSERT(this == &instance.compartment()->wasm);
67 :
68 0 : instance.ensureProfilingLabels(cx->runtime()->geckoProfiler().enabled());
69 :
70 0 : if (instance.debugEnabled() &&
71 0 : instance.compartment()->debuggerObservesAllExecution())
72 : {
73 0 : instance.ensureEnterFrameTrapsState(cx, true);
74 : }
75 :
76 : size_t index;
77 0 : if (BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index))
78 0 : MOZ_CRASH("duplicate registration");
79 :
80 : {
81 0 : AutoMutateInstances guard(*this);
82 0 : if (!instances_.insert(instances_.begin() + index, &instance)) {
83 0 : ReportOutOfMemory(cx);
84 0 : return false;
85 : }
86 : }
87 :
88 0 : Debugger::onNewWasmInstance(cx, instanceObj);
89 0 : return true;
90 : }
91 :
92 : void
93 0 : Compartment::unregisterInstance(Instance& instance)
94 : {
95 : size_t index;
96 0 : if (!BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index))
97 0 : return;
98 :
99 0 : AutoMutateInstances guard(*this);
100 0 : instances_.erase(instances_.begin() + index);
101 : }
102 :
103 : struct PCComparator
104 : {
105 : const void* pc;
106 0 : explicit PCComparator(const void* pc) : pc(pc) {}
107 :
108 0 : int operator()(const Instance* instance) const {
109 0 : if (instance->codeSegment(Tier::TBD).containsCodePC(pc))
110 0 : return 0;
111 0 : return pc < instance->codeBase(Tier::TBD) ? -1 : 1;
112 : }
113 : };
114 :
115 : const Code*
116 0 : Compartment::lookupCode(const void* pc, const CodeSegment** segmentp) const
117 : {
118 : // lookupCode() can be called asynchronously from the interrupt signal
119 : // handler. In that case, the signal handler is just asking whether the pc
120 : // is in wasm code. If instances_ is being mutated then we can't be
121 : // executing wasm code so returning nullptr is fine.
122 0 : if (mutatingInstances_)
123 0 : return nullptr;
124 :
125 : size_t index;
126 0 : if (!BinarySearchIf(instances_, 0, instances_.length(), PCComparator(pc), &index))
127 0 : return nullptr;
128 :
129 0 : const Code& code = instances_[index]->code();
130 0 : if (segmentp)
131 0 : *segmentp = &code.segment(Tier::TBD);
132 0 : return &code;
133 : }
134 :
135 : void
136 0 : Compartment::ensureProfilingLabels(bool profilingEnabled)
137 : {
138 0 : for (Instance* instance : instances_)
139 0 : instance->ensureProfilingLabels(profilingEnabled);
140 0 : }
141 :
142 : void
143 0 : Compartment::addSizeOfExcludingThis(MallocSizeOf mallocSizeOf, size_t* compartmentTables)
144 : {
145 0 : *compartmentTables += instances_.sizeOfExcludingThis(mallocSizeOf);
146 0 : }
|