JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identifier&) { JSFunction* thisObj = asFunction(slotBase); ASSERT(!thisObj->isHostFunction()); JSValue caller = exec->interpreter()->retrieveCallerFromVMCode(exec, thisObj); // See ES5.1 15.3.5.4 - Function.caller may not be used to retrieve a strict caller. if (!caller.isObject() || !asObject(caller)->inherits(&JSFunction::s_info)) return caller; JSFunction* function = asFunction(caller); if (function->isHostFunction() || !function->jsExecutable()->isStrictMode()) return caller; return throwTypeError(exec, "Function.caller used to retrieve strict caller"); }
PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize) { Vector<ScriptCallFrame> frames; CallFrame* callFrame = exec; while (true) { ASSERT(callFrame); int signedLineNumber; intptr_t sourceID; UString urlString; JSValue function; exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function); UString functionName; if (function) functionName = asFunction(function)->name(exec); else { // Caller is unknown, but if frames is empty we should still add the frame, because // something called us, and gave us arguments. if (!frames.isEmpty()) break; } unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0; frames.append(ScriptCallFrame(ustringToString(functionName), ustringToString(urlString), lineNumber)); if (!function || frames.size() == maxStackSize) break; callFrame = callFrame->callerFrame(); } return ScriptCallStack::create(frames); }
JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* prototype) { JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); return createThis(exec, prototype, asFunction(exec->callee())); }
void JSGlobalData::releaseExecutableMemory() { if (dynamicGlobalObject) { StackPreservingRecompiler recompiler; HashSet<JSCell*> roots; heap.getConservativeRegisterRoots(roots); HashSet<JSCell*>::iterator end = roots.end(); for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) { ScriptExecutable* executable = 0; JSCell* cell = *ptr; if (cell->inherits(&ScriptExecutable::s_info)) executable = static_cast<ScriptExecutable*>(*ptr); else if (cell->inherits(&JSFunction::s_info)) { JSFunction* function = asFunction(*ptr); if (function->isHostFunction()) continue; executable = function->jsExecutable(); } else continue; ASSERT(executable->inherits(&ScriptExecutable::s_info)); executable->unlinkCalls(); if (executable->inherits(&FunctionExecutable::s_info)) recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable)); } heap.forEach(recompiler); } else recompileAllJSFunctions(); m_regExpCache->invalidateCode(); heap.collectAllGarbage(); }
JSObject* construct(ExecState* exec, JSValue object, ConstructType constructType, const ConstructData& constructData, const ArgList& args) { if (constructType == ConstructTypeHost) return constructData.native.function(exec, asObject(object), args); ASSERT(constructType == ConstructTypeJS); // FIXME: Can this be done more efficiently using the constructData? return asFunction(object)->construct(exec, args); }
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(); }
Runtime::ModuleInstance* instantiateModule( Runtime::Compartment* compartment, const Intrinsics::Module& moduleRef, std::string&& debugName, const HashMap<std::string,Runtime::Object*>& extraExports) { auto moduleInstance = new Runtime::ModuleInstance(compartment,{},{},{},{},{},std::move(debugName)); if(moduleRef.impl) { for(const auto& pair : moduleRef.impl->functionMap) { auto functionInstance = pair.value->instantiate(compartment); moduleInstance->functions.push_back(functionInstance); errorUnless(moduleInstance->exportMap.add(pair.key, functionInstance)); } for(const auto& pair : moduleRef.impl->tableMap) { auto tableInstance = pair.value->instantiate(compartment); moduleInstance->tables.push_back(tableInstance); errorUnless(moduleInstance->exportMap.add(pair.key, tableInstance)); } for(const auto& pair : moduleRef.impl->memoryMap) { auto memoryInstance = pair.value->instantiate(compartment); moduleInstance->memories.push_back(memoryInstance); errorUnless(moduleInstance->exportMap.add(pair.key, memoryInstance)); } for(const auto& pair : moduleRef.impl->globalMap) { auto globalInstance = pair.value->instantiate(compartment); moduleInstance->globals.push_back(globalInstance); errorUnless(moduleInstance->exportMap.add(pair.key, globalInstance)); } for(const auto& pair : extraExports) { Runtime::Object* object = pair.value; moduleInstance->exportMap.set(pair.key, object); switch(object->kind) { case Runtime::ObjectKind::function: moduleInstance->functions.push_back(asFunction(object)); break; case Runtime::ObjectKind::table: moduleInstance->tables.push_back(asTable(object)); break; case Runtime::ObjectKind::memory: moduleInstance->memories.push_back(asMemory(object)); break; case Runtime::ObjectKind::global: moduleInstance->globals.push_back(asGlobal(object)); break; case Runtime::ObjectKind::exceptionTypeInstance: moduleInstance->exceptionTypeInstances.push_back(asExceptionTypeInstance(object)); break; default: Errors::unreachable(); }; } } return moduleInstance; }
CallFrame* CallFrame::trueCallerFrameSlow() { // this -> The callee; this is either an inlined callee in which case it already has // a pointer to the true caller. Otherwise it contains current PC in the machine // caller. // // machineCaller -> The caller according to the machine, which may be zero or // more frames above the true caller due to inlining. // // trueCaller -> The real caller. // Am I an inline call frame? If so, we're done. if (isInlineCallFrame()) return callerFrame(); // I am a machine call frame, so the question is: is my caller a machine call frame // that has inlines or a machine call frame that doesn't? CallFrame* machineCaller = callerFrame()->removeHostCallFrameFlag(); if (!machineCaller) return 0; ASSERT(!machineCaller->isInlineCallFrame()); if (!machineCaller->codeBlock() || !machineCaller->codeBlock()->hasCodeOrigins()) return machineCaller; // No inlining, so machineCaller == trueCaller // Figure out where the caller frame would have gone relative to the machine // caller, and rematerialize it. Do so for the entire inline stack. CodeOrigin codeOrigin = machineCaller->codeBlock()->codeOriginForReturn(returnPC()); for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) { InlineCallFrame* nextInlineCallFrame = inlineCallFrame = inlineCallFrame->caller.inlineCallFrame; CallFrame* inlinedCaller = machineCaller + inlineCallFrame->stackOffset; JSObject* callee = machineCaller->registers()[inlineCallFrame->calleeVR].function(); JSCell* calleeAsFunctionCell = getJSFunction(callee); ASSERT(calleeAsFunctionCell); JSFunction* calleeAsFunction = asFunction(calleeAsFunctionCell); // Fill in the inlinedCaller inlinedCaller->setCodeBlock(machineCaller->codeBlock()); inlinedCaller->setScopeChain(calleeAsFunction->scope()); if (nextInlineCallFrame) inlinedCaller->setCallerFrame(machineCaller + nextInlineCallFrame->stackOffset); else inlinedCaller->setCallerFrame(machineCaller); inlinedCaller->setInlineCallFrame(inlineCallFrame); inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->numArgumentsIncludingThis); inlinedCaller->setCallee(callee); inlineCallFrame = nextInlineCallFrame; } return machineCaller + codeOrigin.inlineCallFrame->stackOffset; }
UString DebuggerCallFrame::calculatedFunctionName() const { if (!m_callFrame->codeBlock()) return 0; JSFunction* function = asFunction(m_callFrame->callee()); if (!function) return 0; return function->calculatedDisplayName(&m_callFrame->globalData()); }
const UString* DebuggerCallFrame::functionName() const { if (!m_callFrame->codeBlock()) return 0; JSFunction* function = asFunction(m_callFrame->callee()); if (!function) return 0; return &function->name(&m_callFrame->globalData()); }
bool CallFrame::isInlineCallFrameSlow() { if (!callee()) return false; JSCell* calleeAsFunctionCell = getJSFunction(callee()); if (!calleeAsFunctionCell) return false; JSFunction* calleeAsFunction = asFunction(calleeAsFunctionCell); return calleeAsFunction->executable() != codeBlock()->ownerExecutable(); }
BaseSamplerNode* SamplerApollo::willExecute(ExecState* exec, JSValue function, int32_t& lineNo) { ASSERT(lineNo == 0); if (!seenByProfiler(function)) return 0; JSObject* object = asObject(function); if (object->inherits(&JSFunction::info)) { JSFunction* jsFunction = asFunction(function); // we should take lineno only for non host functions // otherwise we end up with wrong line numbers for functions like // DOM functions, which should have 0 as line number // see bug 2587164 if (!jsFunction->isHostFunction()) lineNo = jsFunction->jsExecutable()->lineNo(); } BaseSamplerNode* samplerNode = getSamplerNodeFor(static_cast<JSCell*>(object)); if (!samplerNode) { // try to inject the object now // as it might have been created while sampling was disabled // this can happen when the sample buffer runs out of space ASSERT(exec->dynamicGlobalObject()); uint64_t globalObjectIdentifier = 0; JSGlobalObject* globalObject = exec->dynamicGlobalObject(); BaseSamplerNode* globalObjectSample = getSamplerNodeFor(globalObject); if (globalObjectSample) globalObjectIdentifier = globalObjectSample->identifier(); PassRefPtr<SamplerJSCellNode> samplerNodeRef = adoptRef(new SamplerJSCellNode(globalObjectIdentifier, static_cast<JSCell*>(object), sizeof(JSObject))); samplerNode = samplerNodeRef.get(); // the sampler might be stopped by the time we get here // and register node will not give an id // in this cases we just fail here if (!registerNode(samplerNodeRef)) return 0; } samplerDidEnterFunction(samplerNode->identifier(), lineNo); // do not increment invocationCount if sampling is paused // however, we called samplerDidEnterFunction because we need to keep the callstack in sync if (UNLIKELY(!samplingNow)) return samplerNode; samplerNode->willExecute(); return samplerNode; }
UString DebuggerCallFrame::calculatedFunctionName() const { if (!m_callFrame->codeBlock()) return UString(); JSObject* function = m_callFrame->callee(); if (!function || !function->inherits(&JSFunction::s_info)) return UString(); return asFunction(function)->calculatedDisplayName(m_callFrame); }
JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source) { JSGlobalData* globalData = &exec->globalData(); addErrorInfo(globalData, error, line, source); JSArray* stack = constructEmptyArray(exec); CallFrame* frame = exec; JSObject* stackFrame; CodeBlock* codeBlock; UString sourceURL; UString functionName; ReturnAddressPtr pc; while (!frame->hasHostCallFrameFlag()) { stackFrame = constructEmptyObject(exec); codeBlock = frame->codeBlock(); // sourceURL sourceURL = codeBlock->ownerExecutable()->sourceURL(); stackFrame->putWithAttributes( globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete ); // line if (frame != exec) { line = codeBlock->lineNumberForBytecodeOffset(codeBlock->bytecodeOffset(pc)); } stackFrame->putWithAttributes( globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete ); // function JSObject* function = frame->callee(); if (function && function->inherits(&JSFunction::s_info)) { functionName = asFunction(function)->calculatedDisplayName(exec); stackFrame->putWithAttributes( globalData, Identifier(globalData, functionPropertyName), jsString(globalData, functionName), ReadOnly | DontDelete ); } stack->push(exec, JSValue(stackFrame)); pc = frame->returnPC(); frame = frame->callerFrame(); } error->putWithAttributes(globalData, Identifier(globalData, stackPropertyName), stack, ReadOnly | DontDelete); return error; }
const UString* DebuggerCallFrame::functionName() const { if (!m_callFrame->codeBlock()) return 0; if (!m_callFrame->callee()) return 0; JSObject* function = m_callFrame->callee(); if (!function || !function->inherits(&JSFunction::s_info)) return 0; return &asFunction(function)->name(m_callFrame); }
AJValue PropertySlot::functionGetter(ExecState* exec) const { // Prevent getter functions from observing execution if an exception is pending. if (exec->hadException()) return exec->exception(); CallData callData; CallType callType = m_data.getterFunc->getCallData(callData); if (callType == CallTypeHost) return callData.native.function(exec, m_data.getterFunc, thisValue(), exec->emptyList()); ASSERT(callType == CallTypeJS); // FIXME: Can this be done more efficiently using the callData? return asFunction(m_data.getterFunc)->call(exec, thisValue(), exec->emptyList()); }
void ScriptCallStack::initialize() { if (!m_caller || m_initialized) return; JSValue func = m_exec->interpreter()->retrieveCaller(m_exec, m_caller); while (!func.isNull()) { JSFunction* jsFunction = asFunction(func); ArgList emptyArgList; m_frames.append(ScriptCallFrame(jsFunction->name(m_exec), UString(), 0, emptyArgList, 0)); func = m_exec->interpreter()->retrieveCaller(m_exec, jsFunction); } m_initialized = true; }
CallIdentifier Profiler::createCallIdentifier(TiExcState* exec, TiValue 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(&TiFunction::info)) { TiFunction* 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); }
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()); }
JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* prototype) { JSFunction* constructor = asFunction(exec->callee()); #if !ASSERT_DISABLED ConstructData constructData; ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); #endif JSGlobalData& globalData = exec->globalData(); Structure* structure; if (prototype->isObject()) structure = asObject(prototype)->inheritorID(globalData); else structure = constructor->scope()->globalObject->emptyObjectStructure(); return constructEmptyObject(exec, structure); }
EncodedTiValue JSC_HOST_CALL functionProtoFuncToString(TiExcState* exec) { TiValue thisValue = exec->hostThisValue(); if (thisValue.inherits(&TiFunction::s_info)) { TiFunction* function = asFunction(thisValue); if (function->isHostFunction()) return TiValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}")); FunctionExecutable* executable = function->jsExecutable(); UString sourceString = executable->source().toString(); insertSemicolonIfNeeded(sourceString); return TiValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "(", executable->paramString(), ") ", sourceString)); } if (thisValue.inherits(&InternalFunction::s_info)) { InternalFunction* function = asInternalFunction(thisValue); return TiValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}")); } return throwVMTypeError(exec); }
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(); }
bool isA(Object* object,const ObjectType& type) { if(type.kind != object->kind) { return false; } switch(type.kind) { case ObjectKind::function: return type.function == asFunction(object)->type; case ObjectKind::global: return type.global == asGlobal(object)->type; case ObjectKind::table: { auto table = asTable(object); return type.table.elementType == table->type.elementType && isSubset(type.table.size,table->type.size); } case ObjectKind::memory: { auto memory = asMemory(object); return isSubset(type.memory.size,memory->type.size); } default: Core::unreachable(); } }
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 = asFunction(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(); }
// - LuaValue::operator== --------------------------------------------------- bool LuaValue::operator== (const LuaValue& rhs) const { std::string lhsTypeName = typeName(); std::string rhsTypeName = rhs.typeName(); if (typeName() != rhs.typeName()) return false; else switch (type()) { case LUA_TNIL: return true; case LUA_TBOOLEAN: return asBoolean() == rhs.asBoolean(); case LUA_TNUMBER: return asNumber() == rhs.asNumber(); case LUA_TSTRING: return asString() == rhs.asString(); case LUA_TTABLE: return asTable() == rhs.asTable(); case LUA_TFUNCTION: return asFunction() == rhs.asFunction(); case LUA_TUSERDATA: return asUserData() == rhs.asUserData(); default: { assert( false && "Invalid type found in a call to 'LuaValue::operator==()'."); return 0; // make compilers happy } } }
void ScriptCallStack::initialize() { if (!m_caller || m_initialized) return; int signedLineNumber; intptr_t sourceID; UString urlString; JSValue function; // callFrame must exist if m_caller is not null. CallFrame* callFrame = m_exec->callerFrame(); while (true) { ASSERT(callFrame); m_exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function); if (!function) break; JSFunction* jsFunction = asFunction(function); unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0; m_frames.append(ScriptCallFrame(jsFunction->name(m_exec), urlString, lineNumber, m_exec, 0)); callFrame = callFrame->callerFrame(); } m_initialized = true; }
ScriptCallStack::ScriptCallStack(ExecState* exec, unsigned skipArgumentCount) : m_initialized(false) , m_exec(exec) , m_caller(0) { int signedLineNumber; intptr_t sourceID; UString urlString; JSValue function; exec->interpreter()->retrieveLastCaller(exec, signedLineNumber, sourceID, urlString, function); unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0; if (function) { m_caller = asFunction(function); m_frames.append(ScriptCallFrame(m_caller->name(m_exec), urlString, lineNumber, m_exec, skipArgumentCount)); } else { // Caller is unknown, but we should still add the frame, because // something called us, and gave us arguments. m_frames.append(ScriptCallFrame(UString(), urlString, lineNumber, m_exec, skipArgumentCount)); } }
JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { if (thisValue.inherits(&JSFunction::info)) { JSFunction* function = asFunction(thisValue); if (!function->isHostFunction()) { FunctionExecutable* executable = function->jsExecutable(); UString sourceString = executable->source().toString(); insertSemicolonIfNeeded(sourceString); return jsString(exec, makeString("function ", function->name(exec), "(", executable->paramString(), ") ", sourceString)); } } if (thisValue.inherits(&InternalFunction::info)) { InternalFunction* function = asInternalFunction(thisValue); return jsString(exec, makeString("function ", function->name(exec), "() {\n [native code]\n}")); } #ifdef QT_BUILD_SCRIPT_LIB //same error message as in the old engine, and in mozilla return throwError(exec, TypeError, "Function.prototype.toString called on incompatible object"); #else return throwError(exec, TypeError); #endif }
AJValue AJFunction::lengthGetter(ExecState* exec, AJValue slotBase, const Identifier&) { AJFunction* thisObj = asFunction(slotBase); ASSERT(!thisObj->isHostFunction()); return jsNumber(exec, thisObj->jsExecutable()->parameterCount()); }
AJValue AJFunction::callerGetter(ExecState* exec, AJValue slotBase, const Identifier&) { AJFunction* thisObj = asFunction(slotBase); ASSERT(!thisObj->isHostFunction()); return exec->interpreter()->retrieveCaller(exec, thisObj); }