From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- js/src/jit/BaselineFrameInfo.cpp | 239 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 js/src/jit/BaselineFrameInfo.cpp (limited to 'js/src/jit/BaselineFrameInfo.cpp') diff --git a/js/src/jit/BaselineFrameInfo.cpp b/js/src/jit/BaselineFrameInfo.cpp new file mode 100644 index 0000000000..d641ace2ab --- /dev/null +++ b/js/src/jit/BaselineFrameInfo.cpp @@ -0,0 +1,239 @@ +/* -*- 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/BaselineFrameInfo.h" + +#include + +#include "jit/BaselineIC.h" +#ifdef DEBUG +# include "jit/BytecodeAnalysis.h" +#endif + +#include "jit/BaselineFrameInfo-inl.h" +#include "jit/JitFrames.h" +#include "jit/MacroAssembler-inl.h" + +using namespace js; +using namespace js::jit; + +bool CompilerFrameInfo::init(TempAllocator& alloc) { + // An extra slot is needed for global scopes because INITGLEXICAL (stack + // depth 1) is compiled as a SETPROP (stack depth 2) on the global lexical + // scope. + size_t extra = script->isGlobalCode() ? 1 : 0; + size_t nstack = + std::max(script->nslots() - script->nfixed(), size_t(MinJITStackSize)) + + extra; + if (!stack.init(alloc, nstack)) { + return false; + } + + return true; +} + +void CompilerFrameInfo::sync(StackValue* val) { + switch (val->kind()) { + case StackValue::Stack: + break; + case StackValue::LocalSlot: + masm.pushValue(addressOfLocal(val->localSlot())); + break; + case StackValue::ArgSlot: + masm.pushValue(addressOfArg(val->argSlot())); + break; + case StackValue::ThisSlot: + masm.pushValue(addressOfThis()); + break; + case StackValue::Register: + masm.pushValue(val->reg()); + break; + case StackValue::Constant: + masm.pushValue(val->constant()); + break; + default: + MOZ_CRASH("Invalid kind"); + } + + val->setStack(); +} + +void CompilerFrameInfo::syncStack(uint32_t uses) { + MOZ_ASSERT(uses <= stackDepth()); + + uint32_t depth = stackDepth() - uses; + + for (uint32_t i = 0; i < depth; i++) { + StackValue* current = &stack[i]; + sync(current); + } +} + +uint32_t CompilerFrameInfo::numUnsyncedSlots() { + // Start at the bottom, find the first value that's not synced. + uint32_t i = 0; + for (; i < stackDepth(); i++) { + if (peek(-int32_t(i + 1))->kind() == StackValue::Stack) { + break; + } + } + return i; +} + +void CompilerFrameInfo::popValue(ValueOperand dest) { + StackValue* val = peek(-1); + + switch (val->kind()) { + case StackValue::Constant: + masm.moveValue(val->constant(), dest); + break; + case StackValue::LocalSlot: + masm.loadValue(addressOfLocal(val->localSlot()), dest); + break; + case StackValue::ArgSlot: + masm.loadValue(addressOfArg(val->argSlot()), dest); + break; + case StackValue::ThisSlot: + masm.loadValue(addressOfThis(), dest); + break; + case StackValue::Stack: + masm.popValue(dest); + break; + case StackValue::Register: + masm.moveValue(val->reg(), dest); + break; + default: + MOZ_CRASH("Invalid kind"); + } + + // masm.popValue already adjusted the stack pointer, don't do it twice. + pop(DontAdjustStack); +} + +void CompilerFrameInfo::popRegsAndSync(uint32_t uses) { + // x86 has only 3 Value registers. Only support 2 regs here for now, + // so that there's always a scratch Value register for reg -> reg + // moves. + MOZ_ASSERT(uses > 0); + MOZ_ASSERT(uses <= 2); + MOZ_ASSERT(uses <= stackDepth()); + + syncStack(uses); + + switch (uses) { + case 1: + popValue(R0); + break; + case 2: { + // If the second value is in R1, move it to R2 so that it's not + // clobbered by the first popValue. + StackValue* val = peek(-2); + if (val->kind() == StackValue::Register && val->reg() == R1) { + masm.moveValue(R1, ValueOperand(R2)); + val->setRegister(R2); + } + popValue(R1); + popValue(R0); + break; + } + default: + MOZ_CRASH("Invalid uses"); + } + // On arm64, SP may be < PSP now (that's OK). + // eg testcase: tests/bug1580246.js +} + +void InterpreterFrameInfo::popRegsAndSync(uint32_t uses) { + switch (uses) { + case 1: + popValue(R0); + break; + case 2: { + popValue(R1); + popValue(R0); + break; + } + default: + MOZ_CRASH("Invalid uses"); + } + // On arm64, SP may be < PSP now (that's OK). + // eg testcase: tests/backup-point-bug1315634.js +} + +void InterpreterFrameInfo::bumpInterpreterICEntry() { + masm.addPtr(Imm32(sizeof(ICEntry)), addressOfInterpreterICEntry()); +} + +void CompilerFrameInfo::storeStackValue(int32_t depth, const Address& dest, + const ValueOperand& scratch) { + const StackValue* source = peek(depth); + switch (source->kind()) { + case StackValue::Constant: + masm.storeValue(source->constant(), dest); + break; + case StackValue::Register: + masm.storeValue(source->reg(), dest); + break; + case StackValue::LocalSlot: + masm.loadValue(addressOfLocal(source->localSlot()), scratch); + masm.storeValue(scratch, dest); + break; + case StackValue::ArgSlot: + masm.loadValue(addressOfArg(source->argSlot()), scratch); + masm.storeValue(scratch, dest); + break; + case StackValue::ThisSlot: + masm.loadValue(addressOfThis(), scratch); + masm.storeValue(scratch, dest); + break; + case StackValue::Stack: + masm.loadValue(addressOfStackValue(depth), scratch); + masm.storeValue(scratch, dest); + break; + default: + MOZ_CRASH("Invalid kind"); + } +} + +#ifdef DEBUG +void CompilerFrameInfo::assertValidState(const BytecodeInfo& info) { + // Check stack depth. + MOZ_ASSERT(stackDepth() == info.stackDepth); + + // Start at the bottom, find the first value that's not synced. + uint32_t i = 0; + for (; i < stackDepth(); i++) { + if (stack[i].kind() != StackValue::Stack) { + break; + } + } + + // Assert all values on top of it are also not synced. + for (; i < stackDepth(); i++) { + MOZ_ASSERT(stack[i].kind() != StackValue::Stack); + } + + // Assert every Value register is used by at most one StackValue. + // R2 is used as scratch register by the compiler and FrameInfo, + // so it shouldn't be used for StackValues. + bool usedR0 = false, usedR1 = false; + + for (i = 0; i < stackDepth(); i++) { + if (stack[i].kind() == StackValue::Register) { + ValueOperand reg = stack[i].reg(); + if (reg == R0) { + MOZ_ASSERT(!usedR0); + usedR0 = true; + } else if (reg == R1) { + MOZ_ASSERT(!usedR1); + usedR1 = true; + } else { + MOZ_CRASH("Invalid register"); + } + } + } +} +#endif -- cgit v1.2.3