///---------------------------------------------------------------------------- /// /// Encoder::Encode /// /// Main entrypoint of encoder. Encode each IR instruction into the /// appropriate machine encoding. /// ///---------------------------------------------------------------------------- void Encoder::Encode() { NoRecoverMemoryArenaAllocator localAlloc(_u("BE-Encoder"), m_func->m_alloc->GetPageAllocator(), Js::Throw::OutOfMemory); m_tempAlloc = &localAlloc; uint32 instrCount = m_func->GetInstrCount(); size_t totalJmpTableSizeInBytes = 0; JmpTableList * jumpTableListForSwitchStatement = nullptr; m_encoderMD.Init(this); m_encodeBufferSize = UInt32Math::Mul(instrCount, MachMaxInstrSize); m_encodeBufferSize += m_func->m_totalJumpTableSizeInBytesForSwitchStatements; m_encodeBuffer = AnewArray(m_tempAlloc, BYTE, m_encodeBufferSize); #if DBG_DUMP m_instrNumber = 0; m_offsetBuffer = AnewArray(m_tempAlloc, uint, instrCount); #endif m_pragmaInstrToRecordMap = Anew(m_tempAlloc, PragmaInstrList, m_tempAlloc); if (DoTrackAllStatementBoundary()) { // Create a new list, if we are tracking all statement boundaries. m_pragmaInstrToRecordOffset = Anew(m_tempAlloc, PragmaInstrList, m_tempAlloc); } else { // Set the list to the same as the throw map list, so that processing of the list // of pragma are done on those only. m_pragmaInstrToRecordOffset = m_pragmaInstrToRecordMap; } #if defined(_M_IX86) || defined(_M_X64) // for BR shortening m_inlineeFrameRecords = Anew(m_tempAlloc, InlineeFrameRecords, m_tempAlloc); #endif m_pc = m_encodeBuffer; m_inlineeFrameMap = Anew(m_tempAlloc, InlineeFrameMap, m_tempAlloc); m_bailoutRecordMap = Anew(m_tempAlloc, BailoutRecordMap, m_tempAlloc); IR::PragmaInstr* pragmaInstr = nullptr; uint32 pragmaOffsetInBuffer = 0; #ifdef _M_X64 bool inProlog = false; #endif bool isCallInstr = false; FOREACH_INSTR_IN_FUNC(instr, m_func) { Assert(Lowerer::ValidOpcodeAfterLower(instr, m_func)); if (GetCurrentOffset() + MachMaxInstrSize < m_encodeBufferSize) { ptrdiff_t count; #if DBG_DUMP AssertMsg(m_instrNumber < instrCount, "Bad instr count?"); __analysis_assume(m_instrNumber < instrCount); m_offsetBuffer[m_instrNumber++] = GetCurrentOffset(); #endif if (instr->IsPragmaInstr()) { switch(instr->m_opcode) { #ifdef _M_X64 case Js::OpCode::PrologStart: m_func->m_prologEncoder.Begin(m_pc - m_encodeBuffer); inProlog = true; continue; case Js::OpCode::PrologEnd: m_func->m_prologEncoder.End(); inProlog = false; continue; #endif case Js::OpCode::StatementBoundary: pragmaOffsetInBuffer = GetCurrentOffset(); pragmaInstr = instr->AsPragmaInstr(); pragmaInstr->m_offsetInBuffer = pragmaOffsetInBuffer; // will record after BR shortening with adjusted offsets if (DoTrackAllStatementBoundary()) { m_pragmaInstrToRecordOffset->Add(pragmaInstr); } break; default: continue; } } else if (instr->IsBranchInstr() && instr->AsBranchInstr()->IsMultiBranch()) { Assert(instr->GetSrc1() && instr->GetSrc1()->IsRegOpnd()); IR::MultiBranchInstr * multiBranchInstr = instr->AsBranchInstr()->AsMultiBrInstr(); if (multiBranchInstr->m_isSwitchBr && (multiBranchInstr->m_kind == IR::MultiBranchInstr::IntJumpTable || multiBranchInstr->m_kind == IR::MultiBranchInstr::SingleCharStrJumpTable)) { BranchJumpTableWrapper * branchJumpTableWrapper = multiBranchInstr->GetBranchJumpTable(); if (jumpTableListForSwitchStatement == nullptr) { jumpTableListForSwitchStatement = Anew(m_tempAlloc, JmpTableList, m_tempAlloc); } jumpTableListForSwitchStatement->Add(branchJumpTableWrapper); totalJmpTableSizeInBytes += (branchJumpTableWrapper->tableSize * sizeof(void*)); } else { //Reloc Records EncoderMD * encoderMD = &(this->m_encoderMD); multiBranchInstr->MapMultiBrTargetByAddress([=](void ** offset) -> void { #if defined(_M_ARM32_OR_ARM64) encoderMD->AddLabelReloc((byte*) offset); #else encoderMD->AppendRelocEntry(RelocTypeLabelUse, (void*) (offset)); #endif }); } } else { isCallInstr = LowererMD::IsCall(instr); if (pragmaInstr && (instr->isInlineeEntryInstr || isCallInstr)) { // will record throw map after BR shortening with adjusted offsets m_pragmaInstrToRecordMap->Add(pragmaInstr); pragmaInstr = nullptr; // Only once per pragma instr -- do we need to make this record? } if (instr->HasBailOutInfo()) { Assert(this->m_func->hasBailout); Assert(LowererMD::IsCall(instr)); instr->GetBailOutInfo()->FinalizeBailOutRecord(this->m_func); } if (instr->isInlineeEntryInstr) { m_encoderMD.EncodeInlineeCallInfo(instr, GetCurrentOffset()); } if (instr->m_opcode == Js::OpCode::InlineeStart) { Assert(!instr->isInlineeEntryInstr); if (pragmaInstr) { m_pragmaInstrToRecordMap->Add(pragmaInstr); pragmaInstr = nullptr; } Func* inlinee = instr->m_func; if (inlinee->frameInfo && inlinee->frameInfo->record) { inlinee->frameInfo->record->Finalize(inlinee, GetCurrentOffset()); #if defined(_M_IX86) || defined(_M_X64) // Store all records to be adjusted for BR shortening m_inlineeFrameRecords->Add(inlinee->frameInfo->record); #endif } continue; } } count = m_encoderMD.Encode(instr, m_pc, m_encodeBuffer); #if DBG_DUMP if (PHASE_TRACE(Js::EncoderPhase, this->m_func)) { instr->Dump((IRDumpFlags)(IRDumpFlags_SimpleForm | IRDumpFlags_SkipEndLine | IRDumpFlags_SkipByteCodeOffset)); Output::SkipToColumn(80); for (BYTE * current = m_pc; current < m_pc + count; current++) { Output::Print(_u("%02X "), *current); } Output::Print(_u("\n")); Output::Flush(); } #endif #ifdef _M_X64 if (inProlog) m_func->m_prologEncoder.EncodeInstr(instr, count & 0xFF); #endif m_pc += count; #if defined(_M_IX86) || defined(_M_X64) // for BR shortening. if (instr->isInlineeEntryInstr) m_encoderMD.AppendRelocEntry(RelocType::RelocTypeInlineeEntryOffset, (void*) (m_pc - MachPtr)); #endif if (isCallInstr) { isCallInstr = false; this->RecordInlineeFrame(instr->m_func, GetCurrentOffset()); } if (instr->HasBailOutInfo() && Lowerer::DoLazyBailout(this->m_func)) { this->RecordBailout(instr, (uint32)(m_pc - m_encodeBuffer)); } } else { Fatal(); } }
//***************************************************************************** // Read data from the storage source. This will handle all types of backing // storage from mmf, streams, and file handles. No read ahead or MRU // caching is done. //***************************************************************************** HRESULT StgIO::Read( // Return code. void *pbBuff, // Write buffer here. ULONG cbBuff, // How much to read. ULONG *pcbRead) // How much read. { ULONG cbCopy; // For boundary checks. void *pbData; // Data buffer for mem read. HRESULT hr = S_OK; // Validate arguments, don't call if you don't need to. _ASSERTE(pbBuff != 0); _ASSERTE(cbBuff > 0); // Get the data based on type. switch (m_iType) { // For data on file, there are two possiblities: // (1) We have an in memory backing store we should use, or // (2) We just need to read from the file. case STGIO_HFILE: case STGIO_HMODULE: { _ASSERTE((m_hFile != INVALID_HANDLE_VALUE) || (m_hModule != NULL)); // Backing store does its own paging. if (IsBackingStore() || IsMemoryMapped()) { // Force the data into memory. if (FAILED(hr = GetPtrForMem(GetCurrentOffset(), cbBuff, pbData))) goto ErrExit; // Copy it back for the user and save the size. memcpy(pbBuff, pbData, cbBuff); if (pcbRead) *pcbRead = cbBuff; } // If there is no backing store, this is just a read operation. else { _ASSERTE((m_iType == STGIO_HFILE) && (m_hFile != INVALID_HANDLE_VALUE)); _ASSERTE(m_hModule == NULL); ULONG cbTemp = 0; if (!pcbRead) pcbRead = &cbTemp; hr = ReadFromDisk(pbBuff, cbBuff, pcbRead); m_cbOffset += *pcbRead; } } break; // Data in a stream is always just read. case STGIO_STREAM: { _ASSERTE((IStream *) m_pIStream); if (!pcbRead) pcbRead = &cbCopy; *pcbRead = 0; hr = m_pIStream->Read(pbBuff, cbBuff, pcbRead); if (SUCCEEDED(hr)) m_cbOffset += *pcbRead; } break; // Simply copy the data from our data. case STGIO_MEM: case STGIO_SHAREDMEM: case STGIO_HFILEMEM: { _ASSERTE(m_pData && m_cbData); // Check for read past end of buffer and adjust. if (GetCurrentOffset() + cbBuff > m_cbData) cbCopy = m_cbData - GetCurrentOffset(); else cbCopy = cbBuff; // Copy the data into the callers buffer. memcpy(pbBuff, (void *) ((DWORD_PTR)m_pData + GetCurrentOffset()), cbCopy); if (pcbRead) *pcbRead = cbCopy; // Save a logical offset. m_cbOffset += cbCopy; } break; case STGIO_NODATA: default: _ASSERTE(0); break; } ErrExit: return (hr); }