static void StaticallyLink(CodeSegment& cs, const LinkData& linkData, ExclusiveContext* cx) { for (LinkData::InternalLink link : linkData.internalLinks) { uint8_t* patchAt = cs.base() + link.patchAtOffset; void* target = cs.base() + link.targetOffset; if (link.isRawPointerPatch()) *(void**)(patchAt) = target; else Assembler::PatchInstructionImmediate(patchAt, PatchedImmPtr(target)); } for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) { const Uint32Vector& offsets = linkData.symbolicLinks[imm]; for (size_t i = 0; i < offsets.length(); i++) { uint8_t* patchAt = cs.base() + offsets[i]; void* target = AddressOf(imm, cx); Assembler::PatchDataWithValueCheck(CodeLocationLabel(patchAt), PatchedImmPtr(target), PatchedImmPtr((void*)-1)); } } // These constants are logically part of the code: *(double*)(cs.globalData() + NaN64GlobalDataOffset) = GenericNaN(); *(float*)(cs.globalData() + NaN32GlobalDataOffset) = GenericNaN(); }
static void SpecializeToMemory(uint8_t* prevMemoryBase, CodeSegment& cs, const Metadata& metadata, ArrayBufferObjectMaybeShared& buffer) { #ifdef WASM_HUGE_MEMORY MOZ_RELEASE_ASSERT(metadata.boundsChecks.empty()); #else uint32_t limit = buffer.wasmBoundsCheckLimit(); MOZ_RELEASE_ASSERT(IsValidBoundsCheckImmediate(limit)); for (const BoundsCheck& check : metadata.boundsChecks) MacroAssembler::wasmPatchBoundsCheck(check.patchAt(cs.base()), limit); #endif #if defined(JS_CODEGEN_X86) uint8_t* memoryBase = buffer.dataPointerEither().unwrap(/* code patching */); if (prevMemoryBase != memoryBase) { for (MemoryPatch patch : metadata.memoryPatches) { void* patchAt = cs.base() + patch.offset; uint8_t* prevImm = (uint8_t*)X86Encoding::GetPointer(patchAt); MOZ_ASSERT(prevImm >= prevMemoryBase); uint32_t offset = prevImm - prevMemoryBase; MOZ_ASSERT(offset <= INT32_MAX); X86Encoding::SetPointer(patchAt, memoryBase + offset); } } #else MOZ_RELEASE_ASSERT(metadata.memoryPatches.empty()); #endif }
static void SpecializeToMemory(CodeSegment& cs, const Metadata& metadata, HandleWasmMemoryObject memory) { if (!metadata.boundsChecks.empty()) { uint32_t length = memory->buffer().wasmBoundsCheckLimit(); MOZ_RELEASE_ASSERT(length == LegalizeMapLength(length)); MOZ_RELEASE_ASSERT(length >= memory->buffer().wasmActualByteLength()); for (const BoundsCheck& check : metadata.boundsChecks) Assembler::UpdateBoundsCheck(check.patchAt(cs.base()), length); } #if defined(JS_CODEGEN_X86) uint8_t* base = memory->buffer().dataPointerEither().unwrap(); for (const MemoryAccess& access : metadata.memoryAccesses) { // Patch memory pointer immediate. void* addr = access.patchMemoryPtrImmAt(cs.base()); uint32_t disp = reinterpret_cast<uint32_t>(X86Encoding::GetPointer(addr)); MOZ_ASSERT(disp <= INT32_MAX); X86Encoding::SetPointer(addr, (void*)(base + disp)); } #endif }
static void SendCodeRangesToProfiler(CodeSegment& cs, const Bytes& bytecode, const Metadata& metadata) { bool enabled = false; #ifdef JS_ION_PERF enabled |= PerfFuncEnabled(); #endif #ifdef MOZ_VTUNE enabled |= IsVTuneProfilingActive(); #endif if (!enabled) return; for (const CodeRange& codeRange : metadata.codeRanges) { if (!codeRange.isFunction()) continue; uintptr_t start = uintptr_t(cs.base() + codeRange.begin()); uintptr_t end = uintptr_t(cs.base() + codeRange.end()); uintptr_t size = end - start; UTF8Bytes name; if (!metadata.getFuncName(&bytecode, codeRange.funcIndex(), &name)) return; if (!name.append('\0')) return; // Avoid "unused" warnings (void)start; (void)size; #ifdef JS_ION_PERF if (PerfFuncEnabled()) { const char* file = metadata.filename.get(); unsigned line = codeRange.funcLineOrBytecode(); unsigned column = 0; writePerfSpewerAsmJSFunctionMap(start, size, file, line, column, name.begin()); } #endif #ifdef MOZ_VTUNE if (IsVTuneProfilingActive()) { unsigned method_id = iJIT_GetNewMethodID(); if (method_id == 0) return; iJIT_Method_Load method; method.method_id = method_id; method.method_name = name.begin(); method.method_load_address = (void*)start; method.method_size = size; method.line_number_size = 0; method.line_number_table = nullptr; method.class_id = 0; method.class_file_name = nullptr; method.source_file_name = nullptr; iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&method); } #endif } return; }