/* * Copyright (C) 2019 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include "BytecodeGeneratorBase.h" #include "RegisterID.h" #include "StackAlignment.h" namespace JSC { template static inline void shrinkToFit(T& segmentedVector) { while (segmentedVector.size() && !segmentedVector.last().refCount()) segmentedVector.removeLast(); } template BytecodeGeneratorBase::BytecodeGeneratorBase(typename Traits::CodeBlock codeBlock, uint32_t virtualRegisterCountForCalleeSaves) : m_codeBlock(WTFMove(codeBlock)) { allocateCalleeSaveSpace(virtualRegisterCountForCalleeSaves); } template Ref> BytecodeGeneratorBase::newLabel() { shrinkToFit(m_labels); // Allocate new label ID. m_labels.append(); return m_labels.last(); } template Ref> BytecodeGeneratorBase::newEmittedLabel() { auto label = newLabel(); emitLabel(label.get()); return label; } template void BytecodeGeneratorBase::reclaimFreeRegisters() { shrinkToFit(m_calleeLocals); } template void BytecodeGeneratorBase::emitLabel(GenericLabel& label) { unsigned newLabelIndex = m_writer.position(); label.setLocation(*this, newLabelIndex); if (m_codeBlock->numberOfJumpTargets()) { unsigned lastLabelIndex = m_codeBlock->lastJumpTarget(); ASSERT(lastLabelIndex <= newLabelIndex); if (newLabelIndex == lastLabelIndex) { // Peephole optimizations have already been disabled by emitting the last label return; } } m_codeBlock->addJumpTarget(newLabelIndex); m_lastOpcodeID = Traits::opcodeForDisablingOptimizations; } template void BytecodeGeneratorBase::recordOpcode(typename Traits::OpcodeID opcodeID) { ASSERT(m_lastOpcodeID == Traits::opcodeForDisablingOptimizations || (m_lastOpcodeID == m_lastInstruction->opcodeID() && m_writer.position() == m_lastInstruction.offset() + m_lastInstruction->size())); m_lastInstruction = m_writer.ref(); m_lastOpcodeID = opcodeID; } template void BytecodeGeneratorBase::alignWideOpcode16() { #if CPU(NEEDS_ALIGNED_ACCESS) size_t opcodeSize = 1; size_t prefixAndOpcodeSize = opcodeSize + PaddingBySize::value; while ((m_writer.position() + prefixAndOpcodeSize) % OpcodeSize::Wide16) Traits::OpNop::template emit(this); #endif } template void BytecodeGeneratorBase::alignWideOpcode32() { #if CPU(NEEDS_ALIGNED_ACCESS) size_t opcodeSize = 1; size_t prefixAndOpcodeSize = opcodeSize + PaddingBySize::value; while ((m_writer.position() + prefixAndOpcodeSize) % OpcodeSize::Wide32) Traits::OpNop::template emit(this); #endif } template void BytecodeGeneratorBase::write(uint8_t b) { m_writer.write(b); } template void BytecodeGeneratorBase::write(uint16_t h) { m_writer.write(h); } template void BytecodeGeneratorBase::write(uint32_t i) { m_writer.write(i); } template void BytecodeGeneratorBase::write(int8_t b) { m_writer.write(static_cast(b)); } template void BytecodeGeneratorBase::write(int16_t h) { m_writer.write(static_cast(h)); } template void BytecodeGeneratorBase::write(int32_t i) { m_writer.write(static_cast(i)); } template RegisterID* BytecodeGeneratorBase::newRegister() { m_calleeLocals.append(virtualRegisterForLocal(m_calleeLocals.size())); size_t numCalleeLocals = std::max(m_codeBlock->numCalleeLocals(), m_calleeLocals.size()); numCalleeLocals = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numCalleeLocals); m_codeBlock->setNumCalleeLocals(static_cast(numCalleeLocals)); RELEASE_ASSERT(numCalleeLocals == m_codeBlock->numCalleeLocals()); return &m_calleeLocals.last(); } template RegisterID* BytecodeGeneratorBase::newTemporary() { reclaimFreeRegisters(); RegisterID* result = newRegister(); result->setTemporary(); return result; } // Adds an anonymous local var slot. To give this slot a name, add it to symbolTable(). template RegisterID* BytecodeGeneratorBase::addVar() { int numVars = m_codeBlock->numVars(); m_codeBlock->setNumVars(numVars + 1); RegisterID* result = newRegister(); ASSERT(VirtualRegister(result->index()).toLocal() == numVars); result->ref(); // We should never free this slot. return result; } template void BytecodeGeneratorBase::allocateCalleeSaveSpace(uint32_t virtualRegisterCountForCalleeSaves) { for (size_t i = 0; i < virtualRegisterCountForCalleeSaves; i++) addVar(); } } // namespace JSC