/* * The contents of this file are subject to the Mozilla Public License * Version 1.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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Initial Developer of this code is David Baum. * Portions created by David Baum are Copyright (C) 1998 David Baum. * All Rights Reserved. * * Portions created by John Hansen are Copyright (C) 2005 John Hansen. * All Rights Reserved. * */ #include #include "Bytecode.h" #include "RCX_Cmd.h" #include "RCX_Target.h" using std::memcpy; using std::memset; Bytecode::Bytecode(VarAllocator &varAllocator, const RCX_Target *target, RCX_Image *image) : fVarAllocator(varAllocator), fTarget(target), fImage(image) { fData.reserve(256); fLabels.reserve(50); for(int i=0; iGetNext()) { if (f->fLocation >= length) { f->fType = kNoFixup; } } } void Bytecode::AddJump(int label) { RCX_Cmd cmd; cmd.MakeJump(0); Add(cmd); AddFixup(kSignBitLongFixup, label, 1, kRCX_SJumpOp); } bool Bytecode::AddFlowJump(FlowCode code) { int label = GetFlowLabel(code); if (label == kIllegalLabel) return false; for(int i=0; ifType = type; f->fLocation = GetLength()-size; f->fLabel = label; f->fOpcodeOffset = opcodeOffset; f->fShortOpcode = shortOpcode; fFixups.InsertHead(f); } void Bytecode::OptimizeFixups() { Fixup *f; int codeLength = GetLength(); // the remap array initially is marked with bytes that // are to be deleted, then later it becomes the map // from old index to new one int *remap = new int[codeLength+1]; memset(remap, 0, (codeLength+1) * sizeof(int)); for(f=fFixups.GetHead(); f; f=f->GetNext()) { if (ShortenFixup(*f)) { // mark byte to be deleted remap[f->fLocation+1] = 1; // change the opcode fData[f->fLocation - f->fOpcodeOffset] = f->fShortOpcode; } } // trim the code and compute the remap array int offset = 0; for(int i=0; iGetNext()) { f->fLocation = remap[f->fLocation]; } // adjust source tags for(i=0; i<(int)fTags.size(); ++i) { fTags[i].fAddress = remap[fTags[i].fAddress]; } delete [] remap; } bool Bytecode::ShortenFixup(Fixup &f) { // cannot shorten if short opcode is 0 if (f.fShortOpcode == 0) return false; int offset = fLabels[f.fLabel] - f.fLocation; switch(f.fType) { case kSimpleLongFixup: if (offset >= 0 && offset <= 255) { f.fType = kSimpleShortFixup; return true; } break; case kSignBitLongFixup: if (offset >= -127 && offset <= 127) { f.fType = kSignBitShortFixup; return true; } break; } return false; } void Bytecode::ApplyFixups() { OptimizeFixups(); Fixup *f; while((f = fFixups.RemoveHead()) != nil) { int offset = fLabels[f->fLabel] - f->fLocation; switch(f->fType) { case kNoFixup: break; case kSimpleLongFixup: case kSimpleShortFixup: fData[f->fLocation] = (UByte)(offset & 0xff); if (f->fType == kSimpleLongFixup) { fData[f->fLocation+1] = (UByte)((offset >> 8) & 0xff); } break; case kSignBitLongFixup: case kSignBitShortFixup: UByte neg = 0; if (offset < 0) { neg = 0x80; offset = -offset; } fData[f->fLocation] = (UByte)(neg | (offset & 0x7f)); if (f->fType == kSignBitLongFixup) { fData[f->fLocation+1] = (UByte)((offset >> 7) & 0xff); } break; } delete f; } } int Bytecode::PushFlow(FlowCode code, bool legal) { int label = legal ? NewLabel() : kIllegalLabel; fFlowContexts[code].push_back(label); return label; } int Bytecode::GetFlowLabel(FlowCode code) { vector &v = fFlowContexts[code]; return v[v.size() - 1]; } /* void Bytecode::PushLoopContext(bool continueAllowed) { fLoopContexts.push_back(LoopContext( continueAllowed ? NewLabel() : kIllegalLabel, NewLabel())); } void Bytecode::PopLoopContext(int continueTarget, int breakTarget) { SetLabel(GetLoopLabel(kContinueLabel), continueTarget); SetLabel(GetLoopLabel(kBreakLabel), breakTarget); fLoopContexts.pop_back(); } int Bytecode::GetLoopLabel(int type) const { return fLoopContexts[GetLoopLevel() - 1].fLabels[type]; } void Bytecode::PushReturnLabel() { fReturnLabels.push_back(NewLabel()); fLoopContexts.push_back(LoopContext(kIllegalLabel, kIllegalLabel)); } void Bytecode::PopReturnLabel() { fReturnLabels.pop_back(); fLoopContexts.pop_back(); } */ bool Bytecode::BeginHandler(int type) { HandlerContext &h = fHandlerContexts[type]; if (h.fInUse) return false; for(int i=0; i(i)); } h.fInUse = true; return true; } void Bytecode::EndHandler(int type) { fHandlerContexts[type].fInUse = false; } int Bytecode::GetTempVar(bool canUseLocals) { return fVarAllocator.Allocate(true, canUseLocals, 1); } void Bytecode::ReleaseTempEA(RCX_Value ea) { if (RCX_VALUE_TYPE(ea) == kRCX_VariableType || ea & kRCX_ValueUsesTemp) { fVarAllocator.ReleaseTemp(RCX_VALUE_DATA(ea)); } } bool Bytecode::IsTempEA(RCX_Value ea) const { if (RCX_VALUE_TYPE(ea) != kRCX_VariableType) return false; int v = RCX_VALUE_DATA(ea); return fVarAllocator.IsTemp(v); } bool Bytecode::IsLocalEA(RCX_Value ea) const { if (RCX_VALUE_TYPE(ea) != kRCX_VariableType) return false; return RCX_VALUE_DATA(ea) >= fTarget->fMaxGlobalVars; } void Bytecode::AddSourceTag(int type, const LexLocation &loc) { if (loc.fIndex == kIllegalSrcIndex) return; int n = fTags.size(); fTags.resize(n+1); RCX_SourceTag &t = fTags[n]; t.fType = type; t.fSrcIndex = loc.fIndex; t.fSrcOffset = loc.fOffset + loc.fLength-1; t.fAddress = GetLength(); }