1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/WasmRealm.h"
20
21 #include "vm/Realm.h"
22 #include "wasm/WasmInstance.h"
23
24 #include "debugger/DebugAPI-inl.h"
25
26 using namespace js;
27 using namespace wasm;
28
Realm(JSRuntime * rt)29 wasm::Realm::Realm(JSRuntime* rt) : runtime_(rt) {}
30
~Realm()31 wasm::Realm::~Realm() { MOZ_ASSERT(instances_.empty()); }
32
33 struct InstanceComparator {
34 const Instance& target;
InstanceComparatorInstanceComparator35 explicit InstanceComparator(const Instance& target) : target(target) {}
36
operator ()InstanceComparator37 int operator()(const Instance* instance) const {
38 if (instance == &target) {
39 return 0;
40 }
41
42 // Instances can share code, so the segments can be equal (though they
43 // can't partially overlap). If the codeBases are equal, we sort by
44 // Instance address. Thus a Code may map to many instances.
45
46 // Compare by the first tier, always.
47
48 Tier instanceTier = instance->code().stableTier();
49 Tier targetTier = target.code().stableTier();
50
51 if (instance->codeBase(instanceTier) == target.codeBase(targetTier)) {
52 return instance < &target ? -1 : 1;
53 }
54
55 return target.codeBase(targetTier) < instance->codeBase(instanceTier) ? -1
56 : 1;
57 }
58 };
59
registerInstance(JSContext * cx,HandleWasmInstanceObject instanceObj)60 bool wasm::Realm::registerInstance(JSContext* cx,
61 HandleWasmInstanceObject instanceObj) {
62 MOZ_ASSERT(runtime_ == cx->runtime());
63
64 Instance& instance = instanceObj->instance();
65 MOZ_ASSERT(this == &instance.realm()->wasm);
66
67 instance.ensureProfilingLabels(cx->runtime()->geckoProfiler().enabled());
68
69 if (instance.debugEnabled() &&
70 instance.realm()->debuggerObservesAllExecution()) {
71 instance.debug().ensureEnterFrameTrapsState(cx, true);
72 }
73
74 {
75 if (!instances_.reserve(instances_.length() + 1)) {
76 return false;
77 }
78
79 auto runtimeInstances = cx->runtime()->wasmInstances.lock();
80 if (!runtimeInstances->reserve(runtimeInstances->length() + 1)) {
81 return false;
82 }
83
84 // To avoid implementing rollback, do not fail after mutations start.
85
86 InstanceComparator cmp(instance);
87 size_t index;
88
89 MOZ_ALWAYS_FALSE(
90 BinarySearchIf(instances_, 0, instances_.length(), cmp, &index));
91 MOZ_ALWAYS_TRUE(instances_.insert(instances_.begin() + index, &instance));
92
93 MOZ_ALWAYS_FALSE(BinarySearchIf(runtimeInstances.get(), 0,
94 runtimeInstances->length(), cmp, &index));
95 MOZ_ALWAYS_TRUE(
96 runtimeInstances->insert(runtimeInstances->begin() + index, &instance));
97 }
98
99 // Notify the debugger after wasmInstances is unlocked.
100 DebugAPI::onNewWasmInstance(cx, instanceObj);
101 return true;
102 }
103
unregisterInstance(Instance & instance)104 void wasm::Realm::unregisterInstance(Instance& instance) {
105 InstanceComparator cmp(instance);
106 size_t index;
107
108 if (BinarySearchIf(instances_, 0, instances_.length(), cmp, &index)) {
109 instances_.erase(instances_.begin() + index);
110 }
111
112 auto runtimeInstances = runtime_->wasmInstances.lock();
113 if (BinarySearchIf(runtimeInstances.get(), 0, runtimeInstances->length(), cmp,
114 &index)) {
115 runtimeInstances->erase(runtimeInstances->begin() + index);
116 }
117 }
118
ensureProfilingLabels(bool profilingEnabled)119 void wasm::Realm::ensureProfilingLabels(bool profilingEnabled) {
120 for (Instance* instance : instances_) {
121 instance->ensureProfilingLabels(profilingEnabled);
122 }
123 }
124
addSizeOfExcludingThis(MallocSizeOf mallocSizeOf,size_t * realmTables)125 void wasm::Realm::addSizeOfExcludingThis(MallocSizeOf mallocSizeOf,
126 size_t* realmTables) {
127 *realmTables += instances_.sizeOfExcludingThis(mallocSizeOf);
128 }
129
InterruptRunningCode(JSContext * cx)130 void wasm::InterruptRunningCode(JSContext* cx) {
131 auto runtimeInstances = cx->runtime()->wasmInstances.lock();
132 for (Instance* instance : runtimeInstances.get()) {
133 instance->tlsData()->setInterrupt();
134 }
135 }
136
ResetInterruptState(JSContext * cx)137 void wasm::ResetInterruptState(JSContext* cx) {
138 auto runtimeInstances = cx->runtime()->wasmInstances.lock();
139 for (Instance* instance : runtimeInstances.get()) {
140 instance->tlsData()->resetInterrupt(cx);
141 }
142 }
143