int varcmp_offsets(const void *i1, const void *i2) { if (offsets.off(*((Ident *) i1)) < offsets.off(*((Ident *) i2))) return -1; else if (offsets.off(*((Ident *) i1)) > offsets.off(*((Ident *) i2))) return 1; else return 0; }
void st_dfa_replace_indices(DFA *a, IdentList *newvars, IdentList *oldvars, bool offnew, bool offold) { if (newvars && oldvars && newvars != oldvars) { invariant(newvars->size() == oldvars->size()); int *indexmap = new int[offsets.maxOffset()]; IdentList::iterator i, j; bool dif = false; for(i = newvars->begin(), j = oldvars->begin(); j != oldvars->end(); i++, j++) { int theold = offold ? offsets.off(*j) : *j; int thenew = offnew ? offsets.off(*i) : *i; indexmap[theold] = thenew; if (theold != thenew) dif = true; } if (dif) { Timer temp; if (options.time) { timer_replace_indices.start(); if (options.statistics) temp.start(); } if (options.statistics) cout << "Replacing indices\n"; dfaReplaceIndices(a, indexmap); num_replaces++; if (options.time) { timer_replace_indices.stop(); if (options.statistics) { temp.stop(); cout << " Time: "; temp.print(); } } } delete[] indexmap; if (options.intermediate) dfaPrintVerbose(a); } /*#warning update_largest(a);*/ }
Offsets DenseVectorN::getNonZeroOffsets() const { Offsets offsetList; for (int i = 0, sz = x.size(); i < sz; ++i) { if (x[i] != 0.0) { offsetList.push_back(Offset(i, x[i])); } } return offsetList; }
void st_gta_replace_indices(GTA *g, IdentList *newvars, IdentList *oldvars, bool offnew, bool offold) { if (newvars && oldvars && newvars != oldvars) { invariant(newvars->size() == oldvars->size()); unsigned *indexmap = new unsigned[offsets.maxOffset()]; IdentList::iterator i, j; bool dif = false; for(i = newvars->begin(), j = oldvars->begin(); j != oldvars->end(); i++, j++) { int theold = offold ? offsets.off(*j) : *j; int thenew = offnew ? offsets.off(*i) : *i; indexmap[theold] = thenew; if (theold != thenew) dif = true; } if (dif) { Timer temp; if (options.time) { timer_replace_indices.start(); if (options.statistics) temp.start(); } if (options.statistics) cout << "Replacing indices\n"; gtaReplaceIndices(g, indexmap); num_replaces++; if (options.time) { timer_replace_indices.stop(); if (options.statistics) { temp.stop(); cout << " Time: "; temp.print(); } } } delete[] indexmap; } update_largest(g); }
ColumnPtr ColumnArray::replicateNumber(const Offsets & replicate_offsets) const { size_t col_size = size(); if (col_size != replicate_offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); MutableColumnPtr res = cloneEmpty(); if (0 == col_size) return res; ColumnArray & res_ = typeid_cast<ColumnArray &>(*res); const typename ColumnVector<T>::Container & src_data = typeid_cast<const ColumnVector<T> &>(*data).getData(); const Offsets & src_offsets = getOffsets(); typename ColumnVector<T>::Container & res_data = typeid_cast<ColumnVector<T> &>(res_.getData()).getData(); Offsets & res_offsets = res_.getOffsets(); res_data.reserve(data->size() / col_size * replicate_offsets.back()); res_offsets.reserve(replicate_offsets.back()); Offset prev_replicate_offset = 0; Offset prev_data_offset = 0; Offset current_new_offset = 0; for (size_t i = 0; i < col_size; ++i) { size_t size_to_replicate = replicate_offsets[i] - prev_replicate_offset; size_t value_size = src_offsets[i] - prev_data_offset; for (size_t j = 0; j < size_to_replicate; ++j) { current_new_offset += value_size; res_offsets.push_back(current_new_offset); if (value_size) { res_data.resize(res_data.size() + value_size); memcpy(&res_data[res_data.size() - value_size], &src_data[prev_data_offset], value_size * sizeof(T)); } } prev_replicate_offset = replicate_offsets[i]; prev_data_offset = src_offsets[i]; } return res; }
void Signature::make(IdentList &idents) { size = idents.size(); int *tab1 = new int[size]; int *tab2 = new int[size]; IdentList::iterator i; unsigned int x,y,s; for (i = idents.begin(), x = 0; i != idents.end(); i++, x++) tab1[x] = tab2[x] = offsets.off(*i); qsort((int *) tab2, size, sizeof(int), sortcmp); sign = new int[size]; hashvalue = 0; for (x = 0; x < size; x++) { for (y = 0, s = 0; tab2[y] != tab1[x]; y++) if (y < size && tab2[y] != tab2[y+1]) s++; sign[x] = s; hashvalue = hashvalue*x+sign[x]; } delete[] tab1; delete[] tab2; }
// returns rebased addresses Offsets HexSearcher::FindOffsets(std::vector<unsigned char> const& pattern, size_t limit) { Offsets offsets; ADDRESS begin = GetModuleBegin(); ADDRESS end = GetModuleEnd(); // loop through every hex value in the binary for (ADDRESS i = begin; (i + pattern.size()) < end; ++i) { if (limit && offsets.size() >= limit) break; size_t matches = 0; for (size_t j = 0; j < pattern.size(); j++) { // 0x00, any val if (pattern[j] == 0) { matches++; continue; } //ADDRESS static_address = STATIC_REBASE(i + j); // pattern doesn't match, retry @ next hex val unsigned char ch = *(unsigned char*)(i + j); if (ch != pattern[j]) break; matches++; } if (matches == pattern.size()) { offsets.insert(i); i += matches; } } return offsets; }
ColumnPtr ColumnFixedString::replicate(const Offsets & offsets) const { size_t col_size = size(); if (col_size != offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); auto res = ColumnFixedString::create(n); if (0 == col_size) return std::move(res); Chars_t & res_chars = res->chars; res_chars.resize(n * offsets.back()); Offset curr_offset = 0; for (size_t i = 0; i < col_size; ++i) for (size_t next_offset = offsets[i]; curr_offset < next_offset; ++curr_offset) memcpySmallAllowReadWriteOverflow15(&res->chars[curr_offset * n], &chars[i * n], n); return std::move(res); }
DFA* st_dfa_allpos(DFA *dfa, Ident i) { DFA *t1, *t2; t1 = st_dfa_minimization(st_dfa_product(dfa, dfaAllPos(offsets.off(i)), dfaAND, dummyPos)); t2 = st_dfa_minimization(st_dfa_project(t1, i, dummyPos, false)); /*#warning update_largest(t2);*/ return t2; }
ColumnPtr ColumnArray::replicateConst(const Offsets & replicate_offsets) const { size_t col_size = size(); if (col_size != replicate_offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); if (0 == col_size) return cloneEmpty(); const Offsets & src_offsets = getOffsets(); auto res_column_offsets = ColumnOffsets::create(); Offsets & res_offsets = res_column_offsets->getData(); res_offsets.reserve(replicate_offsets.back()); Offset prev_replicate_offset = 0; Offset prev_data_offset = 0; Offset current_new_offset = 0; for (size_t i = 0; i < col_size; ++i) { size_t size_to_replicate = replicate_offsets[i] - prev_replicate_offset; size_t value_size = src_offsets[i] - prev_data_offset; for (size_t j = 0; j < size_to_replicate; ++j) { current_new_offset += value_size; res_offsets.push_back(current_new_offset); } prev_replicate_offset = replicate_offsets[i]; prev_data_offset = src_offsets[i]; } return ColumnArray::create(getData().cloneResized(current_new_offset), std::move(res_column_offsets)); }
MatrixOpDataRcPtr MatrixOpData::inverse() const { // Get the inverse matrix. MatrixArrayPtr invMatrixArray = m_array.inverse(); // MatrixArray::inverse() will throw for singular matrices. // Calculate the inverse offset. const Offsets& offsets = getOffsets(); Offsets invOffsets; if (offsets.isNotNull()) { invMatrixArray->inner(offsets, invOffsets); invOffsets.scale(-1); } MatrixOpDataRcPtr invOp = std::make_shared<MatrixOpData>(getOutputBitDepth(), getInputBitDepth()); invOp->setRGBA(&(invMatrixArray->getValues()[0])); invOp->setOffsets(invOffsets); // No need to call validate(), the invOp will have proper dimension, // bit-depths, matrix and offets values. return invOp; }
GTA * st_gta_allpos(GTA *gta, Ident i) { GTA *t1, *t2; IdentList *u = symbolTable.allRealUnivs(); SSSet set = stateSpaces(u); delete u; t1 = st_gta_minimization(st_gta_product(gta, gtaAllPos(offsets.off(i), set), gtaAND, dummyPos)); t2 = st_gta_minimization(st_gta_project(t1, i, dummyPos, false)); update_largest(t2); return t2; }
GTA * st_gta_project(GTA *g, Ident i, Pos &p, bool quotient) { Timer temp; if (options.time) { timer_project.start(); if (options.statistics) temp.start(); } if (options.statistics) { cout << "Right-quotient\n" << "Projecting #" << i; p.printsource(); cout << "\n "; print_stat(g); cout << " -> "; cout.flush(); } codeTable->begin(); GTA *result = gtaQuotientAndProject(g, offsets.off(i), quotient); codeTable->done(); num_projections++; num_right_quotients++; if (options.statistics) { print_stat(result); cout << "\n"; } if (options.time) { timer_project.stop(); if (options.statistics) { temp.stop(); cout << " Time: "; temp.print(); } } gtaFree(g); update_largest(result); return result; }
ColumnPtr ColumnArray::replicate(const Offsets & replicate_offsets) const { if (replicate_offsets.empty()) return cloneEmpty(); if (typeid_cast<const ColumnUInt8 *>(data.get())) return replicateNumber<UInt8>(replicate_offsets); if (typeid_cast<const ColumnUInt16 *>(data.get())) return replicateNumber<UInt16>(replicate_offsets); if (typeid_cast<const ColumnUInt32 *>(data.get())) return replicateNumber<UInt32>(replicate_offsets); if (typeid_cast<const ColumnUInt64 *>(data.get())) return replicateNumber<UInt64>(replicate_offsets); if (typeid_cast<const ColumnInt8 *>(data.get())) return replicateNumber<Int8>(replicate_offsets); if (typeid_cast<const ColumnInt16 *>(data.get())) return replicateNumber<Int16>(replicate_offsets); if (typeid_cast<const ColumnInt32 *>(data.get())) return replicateNumber<Int32>(replicate_offsets); if (typeid_cast<const ColumnInt64 *>(data.get())) return replicateNumber<Int64>(replicate_offsets); if (typeid_cast<const ColumnFloat32 *>(data.get())) return replicateNumber<Float32>(replicate_offsets); if (typeid_cast<const ColumnFloat64 *>(data.get())) return replicateNumber<Float64>(replicate_offsets); if (typeid_cast<const ColumnString *>(data.get())) return replicateString(replicate_offsets); if (typeid_cast<const ColumnConst *>(data.get())) return replicateConst(replicate_offsets); if (typeid_cast<const ColumnNullable *>(data.get())) return replicateNullable(replicate_offsets); if (typeid_cast<const ColumnTuple *>(data.get())) return replicateTuple(replicate_offsets); return replicateGeneric(replicate_offsets); }
ColumnPtr ColumnArray::replicateGeneric(const Offsets & replicate_offsets) const { size_t col_size = size(); if (col_size != replicate_offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); MutableColumnPtr res = cloneEmpty(); ColumnArray & res_concrete = static_cast<ColumnArray &>(*res); if (0 == col_size) return res; IColumn::Offset prev_offset = 0; for (size_t i = 0; i < col_size; ++i) { size_t size_to_replicate = replicate_offsets[i] - prev_offset; prev_offset = replicate_offsets[i]; for (size_t j = 0; j < size_to_replicate; ++j) res_concrete.insertFrom(*this, i); } return res; }
void Layer::drawPixmap() { if ((boundingRect().width() == 0) || (boundingRect().height() == 0)) return; // TODO Forward if (m_currentPixmap) delete m_currentPixmap; m_currentPixmap = new QPixmap(boundingRect().width() * m_areaToDraw, boundingRect().height()); QPainter p(m_currentPixmap); int xPoint = 0; for (int i = 0; i < m_offsets[m_columnOffset].size(); i++) { Offsets offset = m_offsets[m_columnOffset].at(i); if (((m_type == Quasi::MirroredType) && (i != 0) && (offset.point() - m_latestPoint < 0)) || m_shouldMirror) { m_drawingMirrored = !m_drawingMirrored; m_shouldMirror = false; } QPixmap pix = generatePartialPixmap(offset.point(), offset.size()); p.drawPixmap(xPoint, 0, pix); xPoint += pix.width(); m_latestPoint = offset.point(); if ((m_type == Quasi::MirroredType) && (i == m_offsets[m_columnOffset].size() - 1) && (offset.size() < m_numColumns)) m_shouldMirror = true; } if (m_direction == Quasi::ForwardDirection) m_columnOffset = (m_columnOffset - 1 < 0) ? m_offsets.size() - 1 : m_columnOffset - 1; else m_columnOffset = (m_columnOffset + 1) % m_offsets.size(); p.end(); }
ColumnPtr ColumnArray::replicateString(const Offsets & replicate_offsets) const { size_t col_size = size(); if (col_size != replicate_offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); MutableColumnPtr res = cloneEmpty(); if (0 == col_size) return res; ColumnArray & res_ = static_cast<ColumnArray &>(*res); const ColumnString & src_string = typeid_cast<const ColumnString &>(*data); const ColumnString::Chars & src_chars = src_string.getChars(); const Offsets & src_string_offsets = src_string.getOffsets(); const Offsets & src_offsets = getOffsets(); ColumnString::Chars & res_chars = typeid_cast<ColumnString &>(res_.getData()).getChars(); Offsets & res_string_offsets = typeid_cast<ColumnString &>(res_.getData()).getOffsets(); Offsets & res_offsets = res_.getOffsets(); res_chars.reserve(src_chars.size() / col_size * replicate_offsets.back()); res_string_offsets.reserve(src_string_offsets.size() / col_size * replicate_offsets.back()); res_offsets.reserve(replicate_offsets.back()); Offset prev_replicate_offset = 0; Offset prev_src_offset = 0; Offset prev_src_string_offset = 0; Offset current_res_offset = 0; Offset current_res_string_offset = 0; for (size_t i = 0; i < col_size; ++i) { /// How much to replicate the array. size_t size_to_replicate = replicate_offsets[i] - prev_replicate_offset; /// The number of rows in the array. size_t value_size = src_offsets[i] - prev_src_offset; /// Number of characters in rows of the array, including zero/null bytes. size_t sum_chars_size = value_size == 0 ? 0 : (src_string_offsets[prev_src_offset + value_size - 1] - prev_src_string_offset); for (size_t j = 0; j < size_to_replicate; ++j) { current_res_offset += value_size; res_offsets.push_back(current_res_offset); size_t prev_src_string_offset_local = prev_src_string_offset; for (size_t k = 0; k < value_size; ++k) { /// Size of one row. size_t chars_size = src_string_offsets[k + prev_src_offset] - prev_src_string_offset_local; current_res_string_offset += chars_size; res_string_offsets.push_back(current_res_string_offset); prev_src_string_offset_local += chars_size; } if (sum_chars_size) { /// Copies the characters of the array of rows. res_chars.resize(res_chars.size() + sum_chars_size); memcpySmallAllowReadWriteOverflow15( &res_chars[res_chars.size() - sum_chars_size], &src_chars[prev_src_string_offset], sum_chars_size); } } prev_replicate_offset = replicate_offsets[i]; prev_src_offset = src_offsets[i]; prev_src_string_offset += sum_chars_size; } return res; }
bool ModuleGenerator::finishCodegen(StaticLinkData* link) { uint32_t offsetInWhole = masm_.size(); // Generate stubs in a separate MacroAssembler since, otherwise, for modules // larger than the JumpImmediateRange, even local uses of Label will fail // due to the large absolute offsets temporarily stored by Label::bind(). Vector<Offsets> entries(cx_); Vector<ProfilingOffsets> interpExits(cx_); Vector<ProfilingOffsets> jitExits(cx_); EnumeratedArray<JumpTarget, JumpTarget::Limit, Offsets> jumpTargets; ProfilingOffsets badIndirectCallExit; Offsets interruptExit; { TempAllocator alloc(&lifo_); MacroAssembler masm(MacroAssembler::AsmJSToken(), alloc); if (!entries.resize(numExports())) return false; for (uint32_t i = 0; i < numExports(); i++) { uint32_t target = exportMap_->exportFuncIndices[i]; const Sig& sig = module_->exports[i].sig(); entries[i] = GenerateEntry(masm, target, sig, usesHeap()); } if (!interpExits.resize(numImports())) return false; if (!jitExits.resize(numImports())) return false; for (uint32_t i = 0; i < numImports(); i++) { interpExits[i] = GenerateInterpExit(masm, module_->imports[i], i); jitExits[i] = GenerateJitExit(masm, module_->imports[i], usesHeap()); } for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) jumpTargets[target] = GenerateJumpTarget(masm, target); badIndirectCallExit = GenerateBadIndirectCallExit(masm); interruptExit = GenerateInterruptStub(masm); if (masm.oom() || !masm_.asmMergeWith(masm)) return false; } // Adjust each of the resulting Offsets (to account for being merged into // masm_) and then create code ranges for all the stubs. for (uint32_t i = 0; i < numExports(); i++) { entries[i].offsetBy(offsetInWhole); module_->exports[i].initStubOffset(entries[i].begin); if (!module_->codeRanges.emplaceBack(CodeRange::Entry, entries[i])) return false; } for (uint32_t i = 0; i < numImports(); i++) { interpExits[i].offsetBy(offsetInWhole); module_->imports[i].initInterpExitOffset(interpExits[i].begin); if (!module_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExits[i])) return false; jitExits[i].offsetBy(offsetInWhole); module_->imports[i].initJitExitOffset(jitExits[i].begin); if (!module_->codeRanges.emplaceBack(CodeRange::ImportJitExit, jitExits[i])) return false; } for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) { jumpTargets[target].offsetBy(offsetInWhole); if (!module_->codeRanges.emplaceBack(CodeRange::Inline, jumpTargets[target])) return false; } badIndirectCallExit.offsetBy(offsetInWhole); if (!module_->codeRanges.emplaceBack(CodeRange::ErrorExit, badIndirectCallExit)) return false; interruptExit.offsetBy(offsetInWhole); if (!module_->codeRanges.emplaceBack(CodeRange::Inline, interruptExit)) return false; // Fill in StaticLinkData with the offsets of these stubs. link->pod.outOfBoundsOffset = jumpTargets[JumpTarget::OutOfBounds].begin; link->pod.interruptOffset = interruptExit.begin; for (uint32_t sigIndex = 0; sigIndex < numSigs_; sigIndex++) { const TableModuleGeneratorData& table = shared_->sigToTable[sigIndex]; if (table.elemFuncIndices.empty()) continue; Uint32Vector elemOffsets; if (!elemOffsets.resize(table.elemFuncIndices.length())) return false; for (size_t i = 0; i < table.elemFuncIndices.length(); i++) { uint32_t funcIndex = table.elemFuncIndices[i]; if (funcIndex == BadIndirectCall) elemOffsets[i] = badIndirectCallExit.begin; else elemOffsets[i] = funcEntry(funcIndex); } if (!link->funcPtrTables.emplaceBack(table.globalDataOffset, Move(elemOffsets))) return false; } // Only call convertOutOfRangeBranchesToThunks after all other codegen that may // emit new jumps to JumpTargets has finished. if (!convertOutOfRangeBranchesToThunks()) return false; // Now that all thunks have been generated, patch all the thunks. for (CallThunk& callThunk : module_->callThunks) { uint32_t funcIndex = callThunk.u.funcIndex; callThunk.u.codeRangeIndex = funcIndexToCodeRange_[funcIndex]; masm_.patchThunk(callThunk.offset, funcEntry(funcIndex)); } for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) { for (uint32_t thunkOffset : jumpThunks_[target]) masm_.patchThunk(thunkOffset, jumpTargets[target].begin); } // Code-generation is complete! masm_.finish(); return !masm_.oom(); }
bool ModuleGenerator::finishCodegen() { uint32_t offsetInWhole = masm_.size(); uint32_t numFuncExports = metadata_->funcExports.length(); MOZ_ASSERT(numFuncExports == exportedFuncs_.count()); // Generate stubs in a separate MacroAssembler since, otherwise, for modules // larger than the JumpImmediateRange, even local uses of Label will fail // due to the large absolute offsets temporarily stored by Label::bind(). OffsetVector entries; ProfilingOffsetVector interpExits; ProfilingOffsetVector jitExits; EnumeratedArray<JumpTarget, JumpTarget::Limit, Offsets> jumpTargets; Offsets interruptExit; { TempAllocator alloc(&lifo_); MacroAssembler masm(MacroAssembler::AsmJSToken(), alloc); if (!entries.resize(numFuncExports)) return false; for (uint32_t i = 0; i < numFuncExports; i++) entries[i] = GenerateEntry(masm, metadata_->funcExports[i]); if (!interpExits.resize(numFuncImports())) return false; if (!jitExits.resize(numFuncImports())) return false; for (uint32_t i = 0; i < numFuncImports(); i++) { interpExits[i] = GenerateInterpExit(masm, metadata_->funcImports[i], i); jitExits[i] = GenerateJitExit(masm, metadata_->funcImports[i]); } for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) jumpTargets[target] = GenerateJumpTarget(masm, target); interruptExit = GenerateInterruptStub(masm); if (masm.oom() || !masm_.asmMergeWith(masm)) return false; } // Adjust each of the resulting Offsets (to account for being merged into // masm_) and then create code ranges for all the stubs. for (uint32_t i = 0; i < numFuncExports; i++) { entries[i].offsetBy(offsetInWhole); metadata_->funcExports[i].initEntryOffset(entries[i].begin); if (!metadata_->codeRanges.emplaceBack(CodeRange::Entry, entries[i])) return false; } for (uint32_t i = 0; i < numFuncImports(); i++) { interpExits[i].offsetBy(offsetInWhole); metadata_->funcImports[i].initInterpExitOffset(interpExits[i].begin); if (!metadata_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExits[i])) return false; jitExits[i].offsetBy(offsetInWhole); metadata_->funcImports[i].initJitExitOffset(jitExits[i].begin); if (!metadata_->codeRanges.emplaceBack(CodeRange::ImportJitExit, jitExits[i])) return false; } for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) { jumpTargets[target].offsetBy(offsetInWhole); if (!metadata_->codeRanges.emplaceBack(CodeRange::Inline, jumpTargets[target])) return false; } interruptExit.offsetBy(offsetInWhole); if (!metadata_->codeRanges.emplaceBack(CodeRange::Inline, interruptExit)) return false; // Fill in LinkData with the offsets of these stubs. linkData_.interruptOffset = interruptExit.begin; linkData_.outOfBoundsOffset = jumpTargets[JumpTarget::OutOfBounds].begin; linkData_.unalignedAccessOffset = jumpTargets[JumpTarget::UnalignedAccess].begin; linkData_.badIndirectCallOffset = jumpTargets[JumpTarget::BadIndirectCall].begin; // Only call convertOutOfRangeBranchesToThunks after all other codegen that may // emit new jumps to JumpTargets has finished. if (!convertOutOfRangeBranchesToThunks()) return false; // Now that all thunks have been generated, patch all the thunks. for (CallThunk& callThunk : metadata_->callThunks) { uint32_t funcIndex = callThunk.u.funcIndex; callThunk.u.codeRangeIndex = funcIndexToCodeRange_[funcIndex]; masm_.patchThunk(callThunk.offset, funcCodeRange(funcIndex).funcNonProfilingEntry()); } for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) { for (uint32_t thunkOffset : jumpThunks_[target]) masm_.patchThunk(thunkOffset, jumpTargets[target].begin); } // Code-generation is complete! masm_.finish(); return !masm_.oom(); }
DFA* st_dfa_project(DFA *a, Ident i, Pos &p, bool quotient) { Timer temp1, temp2; int a_ns = a->ns; if (options.time) { timer_right_quotient.start(); if (options.statistics) temp1.start(); } if (options.statistics) cout << "Right-quotient\n"; if (quotient) { codeTable->begin(); dfaRightQuotient(a, offsets.off(i)); codeTable->done(); num_right_quotients++; } if (options.time) { timer_right_quotient.stop(); if (options.statistics) { temp1.stop(); cout << " Time: "; temp1.print(); } } if (options.time) { timer_project.start(); if (options.statistics) temp2.start(); } if (options.statistics) { cout << "Projecting #" << i; p.printsource(); cout << "\n (" << a_ns << "," << bdd_size(a->bddm) << ") -> "; cout.flush(); } codeTable->begin(); DFA *result = dfaProject(a, offsets.off(i)); codeTable->done(); num_projections++; if (options.statistics) cout << "(" << result->ns << "," << bdd_size(result->bddm) << ")\n"; if (options.time) { timer_project.stop(); if (options.statistics) { temp2.stop(); cout << " Time: "; temp2.print(); } } dfaFree(a); /*#warning update_largest(result);*/ return result; }
int main(int argc, char *argv[]) { std::set_new_handler(&mem_error); if (!ParseArguments(argc, argv)) { Usage(); exit(-1); } // Disable core dump struct rlimit r_core; r_core.rlim_cur = 0; r_core.rlim_max = 0; setrlimit(RLIMIT_CORE, &r_core); // Set demo limits if (options.demo) { struct rlimit r_cpu, r_as; memlimit = true; r_cpu.rlim_cur = 30; // max 30 secs. r_cpu.rlim_max = 30; setrlimit(RLIMIT_CPU, &r_cpu); r_as.rlim_cur = 20971520; // max 20MB r_as.rlim_max = 20971520; setrlimit(RLIMIT_DATA, &r_as); signal(SIGXCPU, &cpuLimit); } initTimer(); Timer timer_total; timer_total.start(); ///////// PARSING //////////////////////////////////////////////////////// if (options.printProgress) cout << "MONA v" << VERSION << "-" << RELEASE << " for WS1S/WS2S\n" "Copyright (C) 1997-2008 BRICS\n\n" "PARSING\n"; Timer timer_parsing; timer_parsing.start(); loadFile(inputFileName); yyparse(); MonaAST *ast = untypedAST->typeCheck(); lastPosVar = ast->lastPosVar; allPosVar = ast->allPosVar; timer_parsing.stop(); if (options.printProgress) { cout << "Time: "; timer_parsing.print(); } delete untypedAST; if (options.dump) { // Dump AST for main formula, verify formulas, and assertion cout << "Main formula:\n"; (ast->formula)->dump(); Deque<ASTForm *>::iterator vf; Deque<char *>::iterator vt; for (vf = ast->verifyformlist.begin(), vt = ast->verifytitlelist.begin(); vf != ast->verifyformlist.end(); vf++, vt++) { cout << "\n\nFormula " << *vt << ":\n"; (*vf)->dump(); } cout << "\n\nAssertions:\n"; (ast->assertion)->dump(); cout << "\n"; if (lastPosVar != -1) cout << "\nLastPos variable: " << symbolTable.lookupSymbol(lastPosVar) << "\n"; if (allPosVar != -1) cout << "\nAllPos variable: " << symbolTable.lookupSymbol(allPosVar) << "\n"; // Dump ASTs for predicates and macros PredLibEntry *pred = predicateLib.first(); while (pred != NULL) { if (pred->isMacro) cout << "\nMacro '"; else cout << "\nPredicate '"; cout << symbolTable.lookupSymbol(pred->name) << "':\n"; (pred->ast)->dump(); cout << "\n"; pred = predicateLib.next(); } // Dump restrictions if (symbolTable.defaultRestriction1) { cout << "\nDefault first-order restriction (" << symbolTable.lookupSymbol(symbolTable.defaultIdent1) << "):\n"; symbolTable.defaultRestriction1->dump(); cout << "\n"; } if (symbolTable.defaultRestriction2) { cout << "\nDefault second-order restriction (" << symbolTable.lookupSymbol(symbolTable.defaultIdent2) << "):\n"; symbolTable.defaultRestriction2->dump(); cout << "\n"; } Ident id; for (id = 0; id < (Ident) symbolTable.noIdents; id++) { Ident t; ASTForm *f = symbolTable.getRestriction(id, &t); if (f) { cout << "\nRestriction for #" << id << " (" << symbolTable.lookupSymbol(id) << "):"; if (t != -1) cout << " default\n"; else { cout << "\n"; f->dump(); cout << "\n"; } } } } if (options.mode != TREE && (options.graphvizSatisfyingEx || options.graphvizCounterEx || options.inheritedAcceptance)) cout << "Warning: options -gc, -gs, and -h are only used in tree mode\n"; if (options.mode == TREE && options.graphvizDFA) cout << "Warning: option -gw is only used in linear mode\n"; if (options.mode == TREE && (options.dump || options.whole) && !options.externalWhole) printGuide(); ///////// CODE GENERATION //////////////////////////////////////////////// if (options.printProgress) cout << "\nCODE GENERATION\n"; Timer timer_gencode; timer_gencode.start(); // Generate code codeTable = new CodeTable; VarCode formulaCode = ast->formula->makeCode(); VarCode assertionCode = ast->assertion->makeCode(); Deque<VarCode> verifyCode; /* #warning NEW: 'VERIFY' */ for (Deque<ASTForm *>::iterator i = ast->verifyformlist.begin(); i != ast->verifyformlist.end(); i++) verifyCode.push_back((*i)->makeCode()); // Implicitly assert restrictions for all global variables for (IdentList::iterator i = ast->globals.begin(); i != ast->globals.end(); i++) assertionCode = andList(assertionCode, getRestriction(*i, NULL)); // Restrict assertion if not trivial if (assertionCode.code->kind != cTrue) assertionCode = codeTable->insert (new Code_Restrict(assertionCode, assertionCode.code->pos)); // Add assertion to main formula and to all verify formulas for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) { assertionCode.code->refs++; *i = andList(*i, VarCode(copy(assertionCode.vars), assertionCode.code)); } formulaCode = andList(formulaCode, assertionCode); timer_gencode.stop(); if (options.printProgress) { codeTable->print_statistics(); /* if (options.dump && options.statistics) codeTable->print_sizes(); */ cout << "Time: "; timer_gencode.print(); } ///////// REORDER BDD OFFSETS //////////////////////////////////////////// if (options.reorder >= 1) { Timer timer_reorder; timer_reorder.start(); if (options.printProgress) cout << "\nREORDERING\n"; // reorder using heuristics offsets.reorder(); // regenerate DAG in new codetable CodeTable *oldCodeTable = codeTable, *newCodeTable = new CodeTable; IdentList emptylist; codeTable = newCodeTable; regenerate = true; // force making new nodes VarCode newcode = formulaCode.substCopy(&emptylist, &emptylist); Deque<VarCode> newverifycode; for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) newverifycode.push_back((*i).substCopy(&emptylist, &emptylist)); codeTable->clearSCTable(); regenerate = false; codeTable = oldCodeTable; formulaCode.remove(); for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) (*i).remove(); formulaCode = newcode; verifyCode.reset(); for (Deque<VarCode>::iterator i = newverifycode.begin(); i != newverifycode.end(); i++) verifyCode.push_back(*i); delete oldCodeTable; codeTable = newCodeTable; if (options.printProgress) { codeTable->print_statistics2(); cout << "Time: "; timer_reorder.print(); } } ///////// REDUCTION AND CODE DUMPING ///////////////////////////////////// if (options.optimize >= 1) { if (options.printProgress) cout << "\nREDUCTION\n"; Timer timer_reduction; timer_reduction.start(); // Reduce formulaCode.reduceAll(&verifyCode); timer_reduction.stop(); if (options.printProgress) { codeTable->print_reduction_statistics(); /* if (options.dump && options.statistics) codeTable->print_sizes(); */ cout << "Time: "; timer_reduction.print(); } } if (options.dump) { // Dump symboltable symbolTable.dump(); // Dump code cout << "\nMain formula:\n"; formulaCode.dump(); cout << "\n\n"; Deque<VarCode>::iterator i; Deque<char *>::iterator j; for (i = verifyCode.begin(), j = ast->verifytitlelist.begin(); i != verifyCode.end(); i++, j++) { cout << "Formula " << *j << ":\n"; (*i).dump(); cout << "\n\n"; } } if (options.graphvizDAG) { printf("digraph MONA_CODE_DAG {\n" " size = \"7.5,10.5\";\n" " main [shape = plaintext];\n" " main -> L%lx;\n", (unsigned long) formulaCode.code); formulaCode.code->viz(); Deque<VarCode>::iterator i; Deque<char *>::iterator j; for (i = verifyCode.begin(), j = ast->verifytitlelist.begin(); i != verifyCode.end(); i++, j++) { printf(" \"%s\" [shape = plaintext];\n" " \"%s\" -> L%lx;\n", *j, *j, (unsigned long) (*i).code); (*i).code->viz(); } formulaCode.unmark(); for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) (*i).unmark(); cout << "}\n"; } ///////// AUTOMATON CONSTRUCTION ///////////////////////////////////////// // Make variable lists Deque<char *> *verifytitlelist = ast->verifytitlelist.copy(); if (lastPosVar != -1) ast->globals.remove(lastPosVar); if (allPosVar != -1) ast->globals.remove(allPosVar); ast->globals.sort(); // sort by id (= index) int numVars = ast->globals.size(); int ix = 0; char **vnames = new char*[numVars]; unsigned *offs = new unsigned[numVars]; char *types = new char[numVars]; int **univs = new int*[numVars]; int *trees = new int[numVars]; SSSet *statespaces = new SSSet[numVars]; IdentList sign, freeVars; IdentList::iterator id; for (id = ast->globals.begin(); id != ast->globals.end(); id++, ix++) { statespaces[ix] = stateSpaces(*id); vnames[ix] = symbolTable.lookupSymbol(*id); offs[ix] = offsets.off(*id); sign.push_back(ix); freeVars.push_back(*id); switch (symbolTable.lookupType(*id)) { case VarnameTree: trees[ix] = 1; break; default: trees[ix] = 0; } IdentList *uu = symbolTable.lookupUnivs(*id); if (uu) { unsigned j; univs[ix] = new int[uu->size()+1]; for (j = 0; j < uu->size(); j++) univs[ix][j] = symbolTable.lookupUnivNumber(uu->get(j)); univs[ix][j] = -1; } else univs[ix] = 0; switch (symbolTable.lookupType(*id)) { case Varname0: types[ix] = 0; break; case Varname1: types[ix] = 1; break; default: types[ix] = 2; break; } } if (options.printProgress) cout << "\nAUTOMATON CONSTRUCTION\n"; Timer timer_automaton; timer_automaton.start(); DFA *dfa = 0; Deque<DFA *> dfalist; GTA *gta = 0; Deque<GTA *> gtalist; // Initialize bdd_init(); codeTable->init_print_progress(); if (options.mode != TREE) { // Generate DFAs dfa = formulaCode.DFATranslate(); if (lastPosVar != -1) dfa = st_dfa_lastpos(dfa, lastPosVar); if (allPosVar != -1) dfa = st_dfa_allpos(dfa, allPosVar); for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) { DFA *d = (*i).DFATranslate(); if (lastPosVar != -1) d = st_dfa_lastpos(d, lastPosVar); if (allPosVar != -1) d = st_dfa_allpos(d, allPosVar); dfalist.push_back(d); } } else { // Generate GTAs gta = formulaCode.GTATranslate(); if (allPosVar != -1) gta = st_gta_allpos(gta, allPosVar); for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) { GTA *g = (*i).GTATranslate(); if (allPosVar != -1) g = st_gta_allpos(g, allPosVar); gtalist.push_back(g); } } formulaCode.remove(); for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) (*i).remove(); timer_automaton.stop(); if (options.printProgress) { if (options.statistics) cout << "Total automaton construction time: "; else cout << "Time: "; timer_automaton.print(); } delete ast; delete codeTable; ///////// PRINT AUTOMATON //////////////////////////////////////////////// DFA *dfa2 = dfa; GTA *gta2 = gta; Deque<DFA *> *dfalist2 = &dfalist; Deque<GTA *> *gtalist2 = >alist; if (options.whole && !options.externalWhole) cout << "\n"; if (options.unrestrict) { // Unrestrict automata if (options.mode != TREE) { DFA *t = dfaCopy(dfa2); dfaUnrestrict(t); dfa2 = dfaMinimize(t); dfaFree(t); dfalist2 = new Deque<DFA *>; for (Deque<DFA *>::iterator i = dfalist.begin(); i != dfalist.end(); i++) { t = dfaCopy(*i); dfaUnrestrict(t); dfalist2->push_back(dfaMinimize(t)); dfaFree(t); } } else { GTA *t = gtaCopy(gta2); gtaUnrestrict(t); gta2 = gtaMinimize(t); gtaFree(t); gtalist2 = new Deque<GTA *>; for (Deque<GTA *>::iterator i = gtalist.begin(); i != gtalist.end(); i++) { t = gtaCopy(*i); gtaUnrestrict(t); gtalist2->push_back(gtaMinimize(t)); gtaFree(t); } } } if (options.whole) // Print whole automaton if (options.mode != TREE) { if (options.externalWhole) { if (!dfalist.empty()) cout << "Main formula:\n"; DFA *t = dfaCopy(dfa2); st_dfa_replace_indices(t, &sign, &freeVars, false, true); dfaExport(t, 0, numVars, vnames, types); dfaFree(t); Deque<DFA *>::iterator i; Deque<char *>::iterator j; for (i = dfalist2->begin(), j = verifytitlelist->begin(); i != dfalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; t = dfaCopy(*i); st_dfa_replace_indices(t, &sign, &freeVars, false, true); dfaExport(t, 0, numVars, vnames, types); dfaFree(t); } } else if (options.graphvizDFA) { dfaPrintGraphviz(dfa2, numVars, offs); for (Deque<DFA *>::iterator i = dfalist2->begin(); i != dfalist2->end(); i++) dfaPrintGraphviz(*i, numVars, offs); } else { if (!dfalist.empty()) cout << "Main formula:\n"; dfaPrint(dfa2, numVars, vnames, offs); Deque<DFA *>::iterator i; Deque<char *>::iterator j; for (i = dfalist2->begin(), j = verifytitlelist->begin(); i != dfalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; dfaPrint(*i, numVars, vnames, offs); } } } else { if (options.externalWhole) { if (!gtalist.empty()) cout << "Main formula:\n"; GTA *t = gtaCopy(gta2); st_gta_replace_indices(t, &sign, &freeVars, false, true); gtaExport(t, 0, numVars, vnames, types, statespaces, options.inheritedAcceptance); gtaFree(t); Deque<GTA *>::iterator i; Deque<char *>::iterator j; for (i = gtalist2->begin(), j = verifytitlelist->begin(); i != gtalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; t = gtaCopy(*i); st_gta_replace_indices(t, &sign, &freeVars, false, true); gtaExport(t, 0, numVars, vnames, types, statespaces, options.inheritedAcceptance); gtaFree(t); } } else { if (!gtalist.empty()) cout << "Main formula:\n"; gtaPrint(gta2, offs, numVars, vnames, options.inheritedAcceptance); Deque<GTA *>::iterator i; Deque<char *>::iterator j; for (i = gtalist2->begin(), j = verifytitlelist->begin(); i != gtalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; gtaPrint(*i, offs, numVars, vnames, options.inheritedAcceptance); } } } else if (options.analysis && !options.graphvizSatisfyingEx && !options.graphvizCounterEx && options.printProgress) { // Print summary only if (options.mode != TREE) { if (!dfalist.empty()) cout << "Main formula:"; dfaPrintVitals(dfa2); Deque<DFA *>::iterator i; Deque<char *>::iterator j; for (i = dfalist2->begin(), j = verifytitlelist->begin(); i != dfalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":"; dfaPrintVitals(*i); } } else { if (!gtalist.empty()) cout << "Main formula:"; gtaPrintTotalSize(gta2); Deque<GTA *>::iterator i; Deque<char *>::iterator j; for (i = gtalist2->begin(), j = verifytitlelist->begin(); i != gtalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":"; gtaPrintTotalSize(*i); } } } if (dfa2 != dfa) { dfaFree(dfa2); for (Deque<DFA *>::iterator i = dfalist2->begin(); i != dfalist2->end(); i++) dfaFree(*i); delete dfalist2; } if (gta2 != gta) { gtaFree(gta2); for (Deque<GTA *>::iterator i = gtalist2->begin(); i != gtalist2->end(); i++) gtaFree(*i); delete gtalist2; } ///////// AUTOMATON ANALYSIS ///////////////////////////////////////////// if (options.analysis) { if (options.printProgress) cout << "\nANALYSIS\n"; if (options.mode != TREE) { if (!dfalist.empty()) cout << "Main formula:\n"; dfaAnalyze(dfa, numVars, vnames, offs, types, options.treemodeOutput); Deque<DFA *>::iterator i; Deque<char *>::iterator j; for (i = dfalist.begin(), j = verifytitlelist->begin(); i != dfalist.end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; dfaAnalyze(*i, numVars, vnames, offs, types, options.treemodeOutput); } } else { if (numTypes == 0 || options.treemodeOutput) { if (!gtalist.empty()) cout << "Main formula:\n"; gtaAnalyze(gta, numVars, vnames, offs, options.graphvizSatisfyingEx, options.graphvizCounterEx); Deque<GTA *>::iterator i; Deque<char *>::iterator j; for (i = gtalist.begin(), j = verifytitlelist->begin(); i != gtalist.end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; gtaAnalyze(*i, numVars, vnames, offs, options.graphvizSatisfyingEx, options.graphvizCounterEx); } } else { if (options.graphvizSatisfyingEx || options.graphvizCounterEx) cout << "Graphviz output of typed trees not implemented.\n"; if (!gtalist.empty()) cout << "Main formula:\n"; gtaTypeAnalyze(gta, numVars, vnames, types, offs, univs, trees); Deque<GTA *>::iterator i; Deque<char *>::iterator j; for (i = gtalist.begin(), j = verifytitlelist->begin(); i != gtalist.end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; gtaTypeAnalyze(*i, numVars, vnames, types, offs, univs, trees); } } } } ///////// CLEAN UP /////////////////////////////////////////////////////// if (options.mode != TREE) { dfaFree(dfa); for (Deque<DFA *>::iterator i = dfalist.begin(); i != dfalist.end(); i++) dfaFree(*i); } else { gtaFree(gta); for (Deque<GTA *>::iterator i = gtalist.begin(); i != gtalist.end(); i++) gtaFree(*i); freeGuide(); } delete verifytitlelist; Deque<FileSource *>::iterator i; for (i = source.begin(); i != source.end(); i++) delete *i; for (ix = 0; ix < numVars; ix++) { delete[] univs[ix]; mem_free(statespaces[ix]); } delete[] statespaces; delete[] vnames; delete[] offs; delete[] types; delete[] univs; delete[] trees; freeTreetypes(); if (options.statistics) print_statistics(); if (options.time) { timer_total.stop(); cout << "\nTotal time: "; timer_total.print(); print_timing(); } else if (options.printProgress) { timer_total.stop(); cout << "\nTotal time: "; timer_total.print(); } #ifdef MAXALLOCATED cout << "Maximum space allocated: " << (maxallocated+524288)/1048576 << " MB\n"; #endif }
bool ModuleGenerator::finishCodegen() { masm_.haltingAlign(CodeAlignment); uint32_t offsetInWhole = masm_.size(); uint32_t numFuncExports = metadata_->funcExports.length(); MOZ_ASSERT(numFuncExports == exportedFuncs_.count()); // Generate stubs in a separate MacroAssembler since, otherwise, for modules // larger than the JumpImmediateRange, even local uses of Label will fail // due to the large absolute offsets temporarily stored by Label::bind(). OffsetVector entries; ProfilingOffsetVector interpExits; ProfilingOffsetVector jitExits; TrapExitOffsetArray trapExits; Offsets outOfBoundsExit; Offsets unalignedAccessExit; Offsets interruptExit; Offsets throwStub; { TempAllocator alloc(&lifo_); MacroAssembler masm(MacroAssembler::WasmToken(), alloc); Label throwLabel; if (!entries.resize(numFuncExports)) return false; for (uint32_t i = 0; i < numFuncExports; i++) entries[i] = GenerateEntry(masm, metadata_->funcExports[i]); if (!interpExits.resize(numFuncImports())) return false; if (!jitExits.resize(numFuncImports())) return false; for (uint32_t i = 0; i < numFuncImports(); i++) { interpExits[i] = GenerateImportInterpExit(masm, metadata_->funcImports[i], i, &throwLabel); jitExits[i] = GenerateImportJitExit(masm, metadata_->funcImports[i], &throwLabel); } for (Trap trap : MakeEnumeratedRange(Trap::Limit)) trapExits[trap] = GenerateTrapExit(masm, trap, &throwLabel); outOfBoundsExit = GenerateOutOfBoundsExit(masm, &throwLabel); unalignedAccessExit = GenerateUnalignedExit(masm, &throwLabel); interruptExit = GenerateInterruptExit(masm, &throwLabel); throwStub = GenerateThrowStub(masm, &throwLabel); if (masm.oom() || !masm_.asmMergeWith(masm)) return false; } // Adjust each of the resulting Offsets (to account for being merged into // masm_) and then create code ranges for all the stubs. for (uint32_t i = 0; i < numFuncExports; i++) { entries[i].offsetBy(offsetInWhole); metadata_->funcExports[i].initEntryOffset(entries[i].begin); if (!metadata_->codeRanges.emplaceBack(CodeRange::Entry, entries[i])) return false; } for (uint32_t i = 0; i < numFuncImports(); i++) { interpExits[i].offsetBy(offsetInWhole); metadata_->funcImports[i].initInterpExitOffset(interpExits[i].begin); if (!metadata_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExits[i])) return false; jitExits[i].offsetBy(offsetInWhole); metadata_->funcImports[i].initJitExitOffset(jitExits[i].begin); if (!metadata_->codeRanges.emplaceBack(CodeRange::ImportJitExit, jitExits[i])) return false; } for (Trap trap : MakeEnumeratedRange(Trap::Limit)) { trapExits[trap].offsetBy(offsetInWhole); if (!metadata_->codeRanges.emplaceBack(CodeRange::TrapExit, trapExits[trap])) return false; } outOfBoundsExit.offsetBy(offsetInWhole); if (!metadata_->codeRanges.emplaceBack(CodeRange::Inline, outOfBoundsExit)) return false; unalignedAccessExit.offsetBy(offsetInWhole); if (!metadata_->codeRanges.emplaceBack(CodeRange::Inline, unalignedAccessExit)) return false; interruptExit.offsetBy(offsetInWhole); if (!metadata_->codeRanges.emplaceBack(CodeRange::Inline, interruptExit)) return false; throwStub.offsetBy(offsetInWhole); if (!metadata_->codeRanges.emplaceBack(CodeRange::Inline, throwStub)) return false; // Fill in LinkData with the offsets of these stubs. linkData_.outOfBoundsOffset = outOfBoundsExit.begin; linkData_.interruptOffset = interruptExit.begin; // Now that all other code has been emitted, patch all remaining callsites. if (!patchCallSites(&trapExits)) return false; // Now that all code has been generated, patch far jumps to destinations. for (CallThunk& callThunk : metadata_->callThunks) { uint32_t funcIndex = callThunk.u.funcIndex; callThunk.u.codeRangeIndex = funcToCodeRange_[funcIndex]; CodeOffset farJump(callThunk.offset); masm_.patchFarJump(farJump, funcCodeRange(funcIndex).funcNonProfilingEntry()); } for (const TrapFarJump& farJump : masm_.trapFarJumps()) masm_.patchFarJump(farJump.jump, trapExits[farJump.trap].begin); // Code-generation is complete! masm_.finish(); return !masm_.oom(); }