IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *bailout) : IonFrameIterator(activations), machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); uint8_t *fp = sp + bailout->frameSize(); current_ = fp; type_ = IonFrame_OptimizedJS; topFrameSize_ = current_ - sp; topIonScript_ = script()->ionScript(); if (bailout->frameClass() == FrameSizeClass::None()) { snapshotOffset_ = bailout->snapshotOffset(); return; } // Compute the snapshot offset from the bailout ID. JitActivation *activation = activations.activation()->asJit(); JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); IonCode *code = rt->ionRuntime()->getBailoutTable(bailout->frameClass()); uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw()); JS_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; JS_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId); }
static bool HandleException(PEXCEPTION_POINTERS exception) { EXCEPTION_RECORD *record = exception->ExceptionRecord; CONTEXT *context = exception->ContextRecord; if (record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) return false; uint8_t **ppc = ContextToPC(context); uint8_t *pc = *ppc; JS_ASSERT(pc == record->ExceptionAddress); if (record->NumberParameters < 2) return false; void *faultingAddress = (void*)record->ExceptionInformation[1]; JSRuntime *rt = RuntimeForCurrentThread(); // Don't allow recursive handling of signals, see AutoSetHandlingSignal. if (!rt || rt->handlingSignal) return false; AutoSetHandlingSignal handling(rt); if (rt->ionRuntime() && rt->ionRuntime()->handleAccessViolation(rt, faultingAddress)) return true; AsmJSActivation *activation = InnermostAsmJSActivation(); if (!activation) return false; const AsmJSModule &module = activation->module(); if (!module.containsPC(pc)) return false; // If we faulted trying to execute code in 'module', this must be an // operation callback (see TriggerOperationCallbackForAsmJSCode). Redirect // execution to a trampoline which will call js_HandleExecutionInterrupt. // The trampoline will jump to activation->resumePC if execution isn't // interrupted. if (module.containsPC(faultingAddress)) { activation->setResumePC(pc); *ppc = module.operationCallbackExit(); DWORD oldProtect; if (!VirtualProtect(module.functionCode(), module.functionBytes(), PAGE_EXECUTE, &oldProtect)) MOZ_CRASH(); return true; } # if defined(JS_CPU_X64) // These checks aren't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. if (!module.maybeHeap() || faultingAddress < module.maybeHeap() || faultingAddress >= module.maybeHeap() + AsmJSBufferProtectedSize) { return false; } const AsmJSHeapAccess *heapAccess = LookupHeapAccess(module, pc); if (!heapAccess) return false; // Also not necessary, but, since we can, do. if (heapAccess->isLoad() != !record->ExceptionInformation[0]) return false; // We now know that this is an out-of-bounds access made by an asm.js // load/store that we should handle. If this is a load, assign the // JS-defined result value to the destination register (ToInt32(undefined) // or ToNumber(undefined), determined by the type of the destination // register) and set the PC to the next op. Upon return from the handler, // execution will resume at this next PC. if (heapAccess->isLoad()) SetRegisterToCoercedUndefined(context, heapAccess->isFloat32Load(), heapAccess->loadedReg()); *ppc += heapAccess->opLength(); return true; # else return false; # endif }
// Be very cautious and default to not handling; we don't want to accidentally // silence real crashes from real bugs. static bool HandleSignal(int signum, siginfo_t *info, void *ctx) { CONTEXT *context = (CONTEXT *)ctx; uint8_t **ppc = ContextToPC(context); uint8_t *pc = *ppc; void *faultingAddress = info->si_addr; JSRuntime *rt = RuntimeForCurrentThread(); // Don't allow recursive handling of signals, see AutoSetHandlingSignal. if (!rt || rt->handlingSignal) return false; AutoSetHandlingSignal handling(rt); if (rt->ionRuntime() && rt->ionRuntime()->handleAccessViolation(rt, faultingAddress)) return true; AsmJSActivation *activation = InnermostAsmJSActivation(); if (!activation) return false; const AsmJSModule &module = activation->module(); if (!module.containsPC(pc)) return false; // If we faulted trying to execute code in 'module', this must be an // operation callback (see TriggerOperationCallbackForAsmJSCode). Redirect // execution to a trampoline which will call js_HandleExecutionInterrupt. // The trampoline will jump to activation->resumePC if execution isn't // interrupted. if (module.containsPC(faultingAddress)) { activation->setResumePC(pc); *ppc = module.operationCallbackExit(); mprotect(module.functionCode(), module.functionBytes(), PROT_EXEC); return true; } # if defined(JS_CPU_X64) // These checks aren't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. if (!module.maybeHeap() || faultingAddress < module.maybeHeap() || faultingAddress >= module.maybeHeap() + AsmJSBufferProtectedSize) { return false; } const AsmJSHeapAccess *heapAccess = LookupHeapAccess(module, pc); if (!heapAccess) return false; // We now know that this is an out-of-bounds access made by an asm.js // load/store that we should handle. If this is a load, assign the // JS-defined result value to the destination register (ToInt32(undefined) // or ToNumber(undefined), determined by the type of the destination // register) and set the PC to the next op. Upon return from the handler, // execution will resume at this next PC. if (heapAccess->isLoad()) SetRegisterToCoercedUndefined(context, heapAccess->isFloat32Load(), heapAccess->loadedReg()); *ppc += heapAccess->opLength(); return true; # else return false; # endif }