CallLinkStatus CallLinkStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex) { ConcurrentJITLocker locker(profiledBlock->m_lock); UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); #if ENABLE(JIT) && ENABLE(VALUE_PROFILER) if (!profiledBlock->hasBaselineJITProfiling()) return computeFromLLInt(profiledBlock, bytecodeIndex); if (profiledBlock->couldTakeSlowCase(bytecodeIndex)) return CallLinkStatus::takesSlowPath(); CallLinkInfo& callLinkInfo = profiledBlock->getCallLinkInfo(bytecodeIndex); if (callLinkInfo.stub) return CallLinkStatus(callLinkInfo.stub->executable(), callLinkInfo.stub->structure()); JSFunction* target = callLinkInfo.lastSeenCallee.get(); if (!target) return computeFromLLInt(profiledBlock, bytecodeIndex); if (callLinkInfo.hasSeenClosure) return CallLinkStatus(target->executable(), target->structure()); return CallLinkStatus(target); #else return CallLinkStatus(); #endif }
CallLinkStatus CallLinkStatus::computeFor(const ConcurrentJITLocker&, CallLinkInfo& callLinkInfo) { // Note that despite requiring that the locker is held, this code is racy with respect // to the CallLinkInfo: it may get cleared while this code runs! This is because // CallLinkInfo::unlink() may be called from a different CodeBlock than the one that owns // the CallLinkInfo and currently we save space by not having CallLinkInfos know who owns // them. So, there is no way for either the caller of CallLinkInfo::unlock() or unlock() // itself to figure out which lock to lock. // // Fortunately, that doesn't matter. The only things we ask of CallLinkInfo - the slow // path count, the stub, and the target - can all be asked racily. Stubs and targets can // only be deleted at next GC, so if we load a non-null one, then it must contain data // that is still marginally valid (i.e. the pointers ain't stale). This kind of raciness // is probably OK for now. if (callLinkInfo.slowPathCount >= Options::couldTakeSlowCaseMinimumCount()) return takesSlowPath(); if (ClosureCallStubRoutine* stub = callLinkInfo.stub.get()) return CallLinkStatus(stub->executable(), stub->structure()); JSFunction* target = callLinkInfo.lastSeenCallee.get(); if (!target) return CallLinkStatus(); if (callLinkInfo.hasSeenClosure) return CallLinkStatus(target->executable(), target->structure()); return CallLinkStatus(target); }
static bool attemptToOptimizeClosureCall(ExecState* execCallee, JSCell* calleeAsFunctionCell, CallLinkInfo& callLinkInfo) { if (!calleeAsFunctionCell) return false; JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); JSFunction* oldCallee = callLinkInfo.callee.get(); if (!oldCallee || oldCallee->structure() != callee->structure() || oldCallee->executable() != callee->executable()) return false; ASSERT(callee->executable()->hasJITCodeForCall()); MacroAssemblerCodePtr codePtr = callee->executable()->generatedJITCodeForCall()->addressForCall(); CodeBlock* codeBlock; if (callee->executable()->isHostFunction()) codeBlock = 0; else { codeBlock = jsCast<FunctionExecutable*>(callee->executable())->codeBlockForCall(); if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) return false; } linkClosureCall( execCallee, callLinkInfo, codeBlock, callee->structure(), callee->executable(), codePtr); return true; }
inline void Recompiler::operator()(JSCell* cell) { if (!cell->inherits(&JSFunction::s_info)) return; JSFunction* function = asFunction(cell); if (function->executable()->isHostFunction()) return; function->jsExecutable()->discardCode(); }
bool CallFrame::isInlineCallFrameSlow() { if (!callee()) return false; JSCell* calleeAsFunctionCell = getJSFunction(callee()); if (!calleeAsFunctionCell) return false; JSFunction* calleeAsFunction = asFunction(calleeAsFunctionCell); return calleeAsFunction->executable() != codeBlock()->ownerExecutable(); }
FunctionExecutable* getExecutableForFunction(JSValue theFunctionValue) { JSFunction* theFunction = jsDynamicCast<JSFunction*>(theFunctionValue); if (!theFunction) return 0; FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>( theFunction->executable()); return executable; }
JSValue JITCode::execute(VM* vm, ProtoCallFrame* protoCallFrame) { void* entryAddress; JSFunction* function = jsDynamicCast<JSFunction*>(protoCallFrame->callee()); if (!function || !protoCallFrame->needArityCheck()) { ASSERT(!protoCallFrame->needArityCheck()); entryAddress = executableAddress(); } else entryAddress = addressForCall(*vm, function->executable(), MustCheckArity, RegisterPreservationNotRequired).executableAddress(); JSValue result = JSValue::decode(vmEntryToJavaScript(entryAddress, vm, protoCallFrame)); return vm->exception() ? jsNull() : result; }
static FunctionExecutable* getExecutable(JSContextRef context, JSValueRef theFunctionValueRef) { ExecState* exec = toJS(context); JSValue theFunctionValue = toJS(exec, theFunctionValueRef); JSFunction* theFunction = jsDynamicCast<JSFunction*>(theFunctionValue); if (!theFunction) return 0; FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>( theFunction->executable()); return executable; }
CallIdentifier Profiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const UString& defaultSourceURL, int defaultLineNumber) { if (!functionValue) return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber); if (!functionValue.isObject()) return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber); if (asObject(functionValue)->inherits(&JSFunction::info)) { JSFunction* function = asFunction(functionValue); if (!function->executable()->isHostFunction()) return createCallIdentifierFromFunctionImp(exec, function); } if (asObject(functionValue)->inherits(&InternalFunction::info)) return CallIdentifier(static_cast<InternalFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber); return CallIdentifier(makeString("(", asObject(functionValue)->className(), " object)"), defaultSourceURL, defaultLineNumber); }
CallLinkStatus CallLinkStatus::computeFor(const ConcurrentJITLocker&, CallLinkInfo& callLinkInfo) { if (callLinkInfo.slowPathCount >= Options::couldTakeSlowCaseMinimumCount()) return takesSlowPath(); if (callLinkInfo.stub) return CallLinkStatus(callLinkInfo.stub->executable(), callLinkInfo.stub->structure()); JSFunction* target = callLinkInfo.lastSeenCallee.get(); if (!target) return CallLinkStatus(); if (callLinkInfo.hasSeenClosure) return CallLinkStatus(target->executable(), target->structure()); return CallLinkStatus(target); }
void Debugger::recompileAllJSFunctions(JSGlobalData* globalData) { // If JavaScript is running, it's not safe to recompile, since we'll end // up throwing away code that is live on the stack. ASSERT(!globalData->dynamicGlobalObject); if (globalData->dynamicGlobalObject) return; typedef HashSet<FunctionExecutable*> FunctionExecutableSet; typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap; FunctionExecutableSet functionExecutables; SourceProviderMap sourceProviders; LiveObjectIterator it = globalData->heap.primaryHeapBegin(); LiveObjectIterator heapEnd = globalData->heap.primaryHeapEnd(); for ( ; it != heapEnd; ++it) { if (!(*it)->inherits(&JSFunction::info)) continue; JSFunction* function = asFunction(*it); if (function->executable()->isHostFunction()) continue; FunctionExecutable* executable = function->jsExecutable(); // Check if the function is already in the set - if so, // we've already retranslated it, nothing to do here. if (!functionExecutables.add(executable).second) continue; ExecState* exec = function->scope().globalObject()->JSGlobalObject::globalExec(); executable->recompile(exec); if (function->scope().globalObject()->debugger() == this) sourceProviders.add(executable->source().provider(), exec); } // Call sourceParsed() after reparsing all functions because it will execute // JavaScript in the inspector. SourceProviderMap::const_iterator end = sourceProviders.end(); for (SourceProviderMap::const_iterator iter = sourceProviders.begin(); iter != end; ++iter) sourceParsed(iter->second, SourceCode(iter->first), -1, UString()); }
EncodedJSValue JSC_HOST_CALL boundThisNoArgsFunctionCall(ExecState* exec) { JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->jsCallee()); MarkedArgumentBuffer args; for (unsigned i = 0; i < exec->argumentCount(); ++i) args.append(exec->uncheckedArgument(i)); JSFunction* targetFunction = jsCast<JSFunction*>(boundFunction->targetFunction()); ExecutableBase* executable = targetFunction->executable(); if (executable->hasJITCodeForCall()) { // Force the executable to cache its arity entrypoint. executable->entrypointFor(CodeForCall, MustCheckArity); } CallData callData; CallType callType = getCallData(targetFunction, callData); ASSERT(callType != CallType::None); return JSValue::encode(call(exec, targetFunction, callType, callData, boundFunction->boundThis(), args)); }
inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); if (UNLIKELY(!calleeAsFunctionCell)) return handleHostCall(execCallee, calleeAsValue, kind); JSFunction* function = asFunction(calleeAsFunctionCell); execCallee->setScopeChain(function->scopeUnchecked()); ExecutableBase* executable = function->executable(); if (UNLIKELY(!executable->hasJITCodeFor(kind))) { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); JSObject* error = functionExecutable->compileFor(execCallee, function->scope(), kind); if (error) { exec->globalData().exception = error; return 0; } } return executable->generatedJITCodeWithArityCheckFor(kind).executableAddress(); }
inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); if (!calleeAsFunctionCell) return handleHostCall(execCallee, calleeAsValue, kind); JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); execCallee->setScopeChain(callee->scopeUnchecked()); ExecutableBase* executable = callee->executable(); MacroAssemblerCodePtr codePtr; CodeBlock* codeBlock = 0; if (executable->isHostFunction()) codePtr = executable->generatedJITCodeFor(kind).addressForCall(); else { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); JSObject* error = functionExecutable->compileFor(execCallee, callee->scope(), kind); if (error) { globalData->exception = createStackOverflowError(exec); return 0; } codeBlock = &functionExecutable->generatedBytecodeFor(kind); if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind); else codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall(); } CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(returnAddress); if (!callLinkInfo.seenOnce()) callLinkInfo.setSeen(); else dfgLinkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind); return codePtr.executableAddress(); }
inline char* linkFor(ExecState* execCallee, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); if (!calleeAsFunctionCell) return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); execCallee->setScope(callee->scopeUnchecked()); ExecutableBase* executable = callee->executable(); MacroAssemblerCodePtr codePtr; CodeBlock* codeBlock = 0; if (executable->isHostFunction()) codePtr = executable->generatedJITCodeFor(kind)->addressForCall(); else { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); JSObject* error = functionExecutable->prepareForExecution(execCallee, callee->scope(), kind); if (error) { vm->throwException(exec, createStackOverflowError(exec)); return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); } codeBlock = functionExecutable->codeBlockFor(kind); if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind); else codePtr = functionExecutable->generatedJITCodeFor(kind)->addressForCall(); } CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(execCallee->returnPC()); if (!callLinkInfo.seenOnce()) callLinkInfo.setSeen(); else linkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind); return reinterpret_cast<char*>(codePtr.executableAddress()); }
inline char* virtualForWithFunction(ExecState* execCallee, CodeSpecializationKind kind, JSCell*& calleeAsFunctionCell) { ExecState* exec = execCallee->callerFrame(); VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); JSValue calleeAsValue = execCallee->calleeAsValue(); calleeAsFunctionCell = getJSFunction(calleeAsValue); if (UNLIKELY(!calleeAsFunctionCell)) return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell); execCallee->setScope(function->scopeUnchecked()); ExecutableBase* executable = function->executable(); if (UNLIKELY(!executable->hasJITCodeFor(kind))) { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); JSObject* error = functionExecutable->prepareForExecution(execCallee, function->scope(), kind); if (error) { exec->vm().throwException(execCallee, error); return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); } } return reinterpret_cast<char*>(executable->generatedJITCodeWithArityCheckFor(kind).executableAddress()); }