summaryrefslogtreecommitdiffstats
path: root/js/src/wasm/WasmCompartment.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/wasm/WasmCompartment.cpp')
-rw-r--r--js/src/wasm/WasmCompartment.cpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/js/src/wasm/WasmCompartment.cpp b/js/src/wasm/WasmCompartment.cpp
new file mode 100644
index 000000000..46b2b23b2
--- /dev/null
+++ b/js/src/wasm/WasmCompartment.cpp
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ *
+ * Copyright 2016 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wasm/WasmCompartment.h"
+
+#include "jscompartment.h"
+
+#include "wasm/WasmInstance.h"
+
+#include "vm/Debugger-inl.h"
+
+using namespace js;
+using namespace wasm;
+
+Compartment::Compartment(Zone* zone)
+ : mutatingInstances_(false),
+ activationCount_(0),
+ profilingEnabled_(false)
+{}
+
+Compartment::~Compartment()
+{
+ MOZ_ASSERT(activationCount_ == 0);
+ MOZ_ASSERT(instances_.empty());
+ MOZ_ASSERT(!mutatingInstances_);
+}
+
+struct InstanceComparator
+{
+ const Instance& target;
+ explicit InstanceComparator(const Instance& target) : target(target) {}
+
+ int operator()(const Instance* instance) const {
+ if (instance == &target)
+ return 0;
+ MOZ_ASSERT(!target.codeSegment().containsCodePC(instance->codeBase()));
+ MOZ_ASSERT(!instance->codeSegment().containsCodePC(target.codeBase()));
+ return target.codeBase() < instance->codeBase() ? -1 : 1;
+ }
+};
+
+void
+Compartment::trace(JSTracer* trc)
+{
+ // A WasmInstanceObject that was initially reachable when called can become
+ // unreachable while executing on the stack. Since wasm does not otherwise
+ // scan the stack during GC to identify live instances, we mark all instance
+ // objects live if there is any running wasm in the compartment.
+ if (activationCount_) {
+ for (Instance* i : instances_)
+ i->trace(trc);
+ }
+}
+
+bool
+Compartment::registerInstance(JSContext* cx, HandleWasmInstanceObject instanceObj)
+{
+ Instance& instance = instanceObj->instance();
+ MOZ_ASSERT(this == &instance.compartment()->wasm);
+
+ if (!instance.ensureProfilingState(cx, profilingEnabled_))
+ return false;
+
+ size_t index;
+ if (BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index))
+ MOZ_CRASH("duplicate registration");
+
+ {
+ AutoMutateInstances guard(*this);
+ if (!instances_.insert(instances_.begin() + index, &instance)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ Debugger::onNewWasmInstance(cx, instanceObj);
+ return true;
+}
+
+void
+Compartment::unregisterInstance(Instance& instance)
+{
+ size_t index;
+ if (!BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index))
+ return;
+
+ AutoMutateInstances guard(*this);
+ instances_.erase(instances_.begin() + index);
+}
+
+struct PCComparator
+{
+ const void* pc;
+ explicit PCComparator(const void* pc) : pc(pc) {}
+
+ int operator()(const Instance* instance) const {
+ if (instance->codeSegment().containsCodePC(pc))
+ return 0;
+ return pc < instance->codeBase() ? -1 : 1;
+ }
+};
+
+Code*
+Compartment::lookupCode(const void* pc) const
+{
+ Instance* instance = lookupInstanceDeprecated(pc);
+ return instance ? &instance->code() : nullptr;
+}
+
+Instance*
+Compartment::lookupInstanceDeprecated(const void* pc) const
+{
+ // lookupInstanceDeprecated can be called asynchronously from the interrupt
+ // signal handler. In that case, the signal handler is just asking whether
+ // the pc is in wasm code. If instances_ is being mutated then we can't be
+ // executing wasm code so returning nullptr is fine.
+ if (mutatingInstances_)
+ return nullptr;
+
+ size_t index;
+ if (!BinarySearchIf(instances_, 0, instances_.length(), PCComparator(pc), &index))
+ return nullptr;
+
+ return instances_[index];
+}
+
+bool
+Compartment::ensureProfilingState(JSContext* cx)
+{
+ bool newProfilingEnabled = cx->spsProfiler.enabled();
+ if (profilingEnabled_ == newProfilingEnabled)
+ return true;
+
+ // Since one Instance can call another Instance in the same compartment
+ // directly without calling through Instance::callExport(), when profiling
+ // is enabled, enable it for the entire compartment at once. It is only safe
+ // to enable profiling when the wasm is not on the stack, so delay enabling
+ // profiling until there are no live WasmActivations in this compartment.
+
+ if (activationCount_ > 0)
+ return true;
+
+ for (Instance* instance : instances_) {
+ if (!instance->ensureProfilingState(cx, newProfilingEnabled))
+ return false;
+ }
+
+ profilingEnabled_ = newProfilingEnabled;
+ return true;
+}
+
+bool
+Compartment::profilingEnabled() const
+{
+ // Profiling can asynchronously interrupt the mutation of the instances_
+ // vector which is used by lookupCode() during stack-walking. To handle
+ // this rare case, disable profiling during mutation.
+ return profilingEnabled_ && !mutatingInstances_;
+}
+
+void
+Compartment::addSizeOfExcludingThis(MallocSizeOf mallocSizeOf, size_t* compartmentTables)
+{
+ *compartmentTables += instances_.sizeOfExcludingThis(mallocSizeOf);
+}