summaryrefslogtreecommitdiffstats
path: root/js/src/jit/WarpBuilderShared.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/WarpBuilderShared.cpp')
-rw-r--r--js/src/jit/WarpBuilderShared.cpp151
1 files changed, 151 insertions, 0 deletions
diff --git a/js/src/jit/WarpBuilderShared.cpp b/js/src/jit/WarpBuilderShared.cpp
new file mode 100644
index 0000000000..e060dc9af6
--- /dev/null
+++ b/js/src/jit/WarpBuilderShared.cpp
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jit/WarpBuilderShared.h"
+
+#include "jit/MIRGenerator.h"
+#include "jit/MIRGraph.h"
+
+using namespace js;
+using namespace js::jit;
+
+WarpBuilderShared::WarpBuilderShared(WarpSnapshot& snapshot,
+ MIRGenerator& mirGen,
+ MBasicBlock* current_)
+ : snapshot_(snapshot),
+ mirGen_(mirGen),
+ alloc_(mirGen.alloc()),
+ current(current_) {}
+
+bool WarpBuilderShared::resumeAfter(MInstruction* ins, BytecodeLocation loc) {
+ // resumeAfter should only be used with effectful instructions. The only
+ // exception is MInt64ToBigInt, it's used to convert the result of a call into
+ // Wasm code so we attach the resume point to that instead of to the call.
+ MOZ_ASSERT(ins->isEffectful() || ins->isInt64ToBigInt());
+ MOZ_ASSERT(!ins->isMovable());
+
+ MResumePoint* resumePoint = MResumePoint::New(
+ alloc(), ins->block(), loc.toRawBytecode(), MResumePoint::ResumeAfter);
+ if (!resumePoint) {
+ return false;
+ }
+
+ ins->setResumePoint(resumePoint);
+ return true;
+}
+
+MConstant* WarpBuilderShared::constant(const Value& v) {
+ MOZ_ASSERT_IF(v.isString(), v.toString()->isAtom());
+ MOZ_ASSERT_IF(v.isGCThing(), !IsInsideNursery(v.toGCThing()));
+
+ MConstant* cst = MConstant::New(alloc(), v);
+ current->add(cst);
+ return cst;
+}
+
+void WarpBuilderShared::pushConstant(const Value& v) {
+ MConstant* cst = constant(v);
+ current->push(cst);
+}
+
+MCall* WarpBuilderShared::makeCall(CallInfo& callInfo, bool needsThisCheck,
+ WrappedFunction* target, bool isDOMCall) {
+ MOZ_ASSERT(callInfo.argFormat() == CallInfo::ArgFormat::Standard);
+ MOZ_ASSERT_IF(needsThisCheck, !target);
+ MOZ_ASSERT_IF(isDOMCall, target->jitInfo()->type() == JSJitInfo::Method);
+
+ DOMObjectKind objKind = DOMObjectKind::Unknown;
+ if (isDOMCall) {
+ const JSClass* clasp = callInfo.thisArg()->toGuardToClass()->getClass();
+ MOZ_ASSERT(clasp->isDOMClass());
+ if (clasp->isNative()) {
+ objKind = DOMObjectKind::Native;
+ } else {
+ MOZ_ASSERT(clasp->isProxy());
+ objKind = DOMObjectKind::Proxy;
+ }
+ }
+
+ uint32_t targetArgs = callInfo.argc();
+
+ // Collect number of missing arguments provided that the target is
+ // scripted. Native functions are passed an explicit 'argc' parameter.
+ if (target && target->hasJitEntry()) {
+ targetArgs = std::max<uint32_t>(target->nargs(), callInfo.argc());
+ }
+
+ MCall* call =
+ MCall::New(alloc(), target, targetArgs + 1 + callInfo.constructing(),
+ callInfo.argc(), callInfo.constructing(),
+ callInfo.ignoresReturnValue(), isDOMCall, objKind);
+ if (!call) {
+ return nullptr;
+ }
+
+ if (callInfo.constructing()) {
+ // Note: setThis should have been done by the caller of makeCall.
+ if (needsThisCheck) {
+ call->setNeedsThisCheck();
+ }
+
+ // Pass |new.target|
+ call->addArg(targetArgs + 1, callInfo.getNewTarget());
+ }
+
+ // Explicitly pad any missing arguments with |undefined|.
+ // This permits skipping the argumentsRectifier.
+ MOZ_ASSERT_IF(target && targetArgs > callInfo.argc(), target->hasJitEntry());
+ for (uint32_t i = targetArgs; i > callInfo.argc(); i--) {
+ MConstant* undef = constant(UndefinedValue());
+ if (!alloc().ensureBallast()) {
+ return nullptr;
+ }
+ call->addArg(i, undef);
+ }
+
+ // Add explicit arguments.
+ // Skip addArg(0) because it is reserved for |this|.
+ for (int32_t i = callInfo.argc() - 1; i >= 0; i--) {
+ call->addArg(i + 1, callInfo.getArg(i));
+ }
+
+ if (isDOMCall) {
+ // Now that we've told it about all the args, compute whether it's movable
+ call->computeMovable();
+ }
+
+ // Pass |this| and callee.
+ call->addArg(0, callInfo.thisArg());
+ call->initCallee(callInfo.callee());
+
+ if (target) {
+ // The callee must be a JSFunction so we don't need a Class check.
+ call->disableClassCheck();
+ }
+
+ return call;
+}
+
+MInstruction* WarpBuilderShared::makeSpreadCall(CallInfo& callInfo,
+ bool isSameRealm,
+ WrappedFunction* target) {
+ // TODO: support SpreadNew and SpreadSuperCall
+ MOZ_ASSERT(!callInfo.constructing());
+
+ // Load dense elements of the argument array.
+ MElements* elements = MElements::New(alloc(), callInfo.arrayArg());
+ current->add(elements);
+
+ auto* apply = MApplyArray::New(alloc(), target, callInfo.callee(), elements,
+ callInfo.thisArg());
+ if (callInfo.ignoresReturnValue()) {
+ apply->setIgnoresReturnValue();
+ }
+ if (isSameRealm) {
+ apply->setNotCrossRealm();
+ }
+ return apply;
+}