X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/2d39b0e377c0896910ee49ae70082ba665faf986..refs/heads/master:/runtime/Executable.cpp?ds=sidebyside diff --git a/runtime/Executable.cpp b/runtime/Executable.cpp index ff9f614..55240fd 100644 --- a/runtime/Executable.cpp +++ b/runtime/Executable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010, 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,34 +27,33 @@ #include "Executable.h" #include "BatchedTransitionOptimizer.h" -#include "BytecodeGenerator.h" #include "CodeBlock.h" #include "DFGDriver.h" #include "JIT.h" -#include "LLIntEntrypoint.h" #include "JSCInlines.h" +#include "JSFunctionNameScope.h" +#include "LLIntEntrypoint.h" #include "Parser.h" #include "ProfilerDatabase.h" +#include "TypeProfiler.h" #include #include #include namespace JSC { -const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; +const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; -#if ENABLE(JIT) void ExecutableBase::destroy(JSCell* cell) { static_cast(cell)->ExecutableBase::~ExecutableBase(); } -#endif void ExecutableBase::clearCode() { #if ENABLE(JIT) - m_jitCodeForCall.clear(); - m_jitCodeForConstruct.clear(); + m_jitCodeForCall = nullptr; + m_jitCodeForConstruct = nullptr; m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); m_jitCodeForCallWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); @@ -78,14 +77,12 @@ Intrinsic ExecutableBase::intrinsic() const } #endif -const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; +const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(NativeExecutable) }; -#if ENABLE(JIT) void NativeExecutable::destroy(JSCell* cell) { static_cast(cell)->NativeExecutable::~NativeExecutable(); } -#endif #if ENABLE(DFG_JIT) Intrinsic NativeExecutable::intrinsic() const @@ -94,20 +91,38 @@ Intrinsic NativeExecutable::intrinsic() const } #endif -const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; +const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; + +ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext) + : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED) + , m_source(source) + , m_features(isInStrictContext ? StrictModeFeature : 0) + , m_hasCapturedVariables(false) + , m_neverInline(false) + , m_didTryToEnterInLoop(false) + , m_overrideLineNumber(-1) + , m_firstLine(-1) + , m_lastLine(-1) + , m_startColumn(UINT_MAX) + , m_endColumn(UINT_MAX) + , m_typeProfilingStartOffset(UINT_MAX) + , m_typeProfilingEndOffset(UINT_MAX) +{ +} -#if ENABLE(JIT) void ScriptExecutable::destroy(JSCell* cell) { static_cast(cell)->ScriptExecutable::~ScriptExecutable(); } -#endif void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) { RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this); RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType())); + if (Options::verboseOSR()) + dataLog("Installing ", *genericCodeBlock, "\n"); + VM& vm = *genericCodeBlock->vm(); if (vm.m_perBytecodeProfiler) @@ -184,10 +199,10 @@ void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) Heap::heap(this)->writeBarrier(this); } -PassRefPtr ScriptExecutable::newCodeBlockFor( - CodeSpecializationKind kind, JSFunction* function, JSScope** scope, JSObject*& exception) +RefPtr ScriptExecutable::newCodeBlockFor( + CodeSpecializationKind kind, JSFunction* function, JSScope* scope, JSObject*& exception) { - VM* vm = (*scope)->vm(); + VM* vm = scope->vm(); ASSERT(vm->heap.isDeferred()); ASSERT(startColumn() != UINT_MAX); @@ -199,7 +214,7 @@ PassRefPtr ScriptExecutable::newCodeBlockFor( RELEASE_ASSERT(!executable->m_evalCodeBlock); RELEASE_ASSERT(!function); return adoptRef(new EvalCodeBlock( - executable, executable->m_unlinkedEvalCodeBlock.get(), *scope, + executable, executable->m_unlinkedEvalCodeBlock.get(), scope, executable->source().provider())); } @@ -209,7 +224,7 @@ PassRefPtr ScriptExecutable::newCodeBlockFor( RELEASE_ASSERT(!executable->m_programCodeBlock); RELEASE_ASSERT(!function); return adoptRef(new ProgramCodeBlock( - executable, executable->m_unlinkedProgramCodeBlock.get(), *scope, + executable, executable->m_unlinkedProgramCodeBlock.get(), scope, executable->source().provider(), executable->source().startColumn())); } @@ -217,27 +232,32 @@ PassRefPtr ScriptExecutable::newCodeBlockFor( RELEASE_ASSERT(function); FunctionExecutable* executable = jsCast(this); RELEASE_ASSERT(!executable->codeBlockFor(kind)); - JSGlobalObject* globalObject = (*scope)->globalObject(); + JSGlobalObject* globalObject = scope->globalObject(); ParserError error; DebuggerMode debuggerMode = globalObject->hasDebugger() ? DebuggerOn : DebuggerOff; ProfilerMode profilerMode = globalObject->hasProfiler() ? ProfilerOn : ProfilerOff; UnlinkedFunctionCodeBlock* unlinkedCodeBlock = executable->m_unlinkedExecutable->codeBlockFor( - *vm, executable->m_source, kind, debuggerMode, profilerMode, executable->bodyIncludesBraces(), error); - recordParse(executable->m_unlinkedExecutable->features(), executable->m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine(), startColumn(), endColumn()); + *vm, executable->m_source, kind, debuggerMode, profilerMode, error); + recordParse(executable->m_unlinkedExecutable->features(), executable->m_unlinkedExecutable->hasCapturedVariables(), firstLine(), lastLine(), startColumn(), endColumn()); if (!unlinkedCodeBlock) { exception = vm->throwException( globalObject->globalExec(), error.toErrorObject(globalObject, executable->m_source)); - return 0; + return nullptr; } // Parsing reveals whether our function uses features that require a separate function name object in the scope chain. // Be sure to add this scope before linking the bytecode because this scope will change the resolution depth of non-local variables. - if (!executable->m_didParseForTheFirstTime) { - executable->m_didParseForTheFirstTime = true; - function->addNameScopeIfNeeded(*vm); - *scope = function->scope(); + if (functionNameIsInScope(executable->name(), executable->functionMode()) + && functionNameScopeIsDynamic(executable->usesEval(), executable->isStrictMode())) { + // We shouldn't have to do this. But we do, because bytecode linking requires a real scope + // chain. + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=141885 + SymbolTable* symbolTable = + SymbolTable::createNameScopeTable(*vm, executable->name(), ReadOnly | DontDelete); + scope = JSFunctionNameScope::create( + *vm, scope->globalObject(), scope, symbolTable, function); } SourceProvider* provider = executable->source().provider(); @@ -245,7 +265,7 @@ PassRefPtr ScriptExecutable::newCodeBlockFor( unsigned startColumn = executable->source().startColumn(); return adoptRef(new FunctionCodeBlock( - executable, unlinkedCodeBlock, *scope, provider, sourceOffset, startColumn)); + executable, unlinkedCodeBlock, scope, provider, sourceOffset, startColumn)); } PassRefPtr ScriptExecutable::newReplacementCodeBlockFor( @@ -301,7 +321,7 @@ static void setupJIT(VM& vm, CodeBlock* codeBlock) } JSObject* ScriptExecutable::prepareForExecutionImpl( - ExecState* exec, JSFunction* function, JSScope** scope, CodeSpecializationKind kind) + ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind) { VM& vm = exec->vm(); DeferGC deferGC(vm.heap); @@ -325,9 +345,9 @@ JSObject* ScriptExecutable::prepareForExecutionImpl( return 0; } -const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) }; +const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(EvalExecutable) }; -EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext) +EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext, ThisTDZMode thisTDZMode) { JSGlobalObject* globalObject = exec->lexicalGlobalObject(); if (!globalObject->evalEnabled()) { @@ -338,7 +358,7 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source EvalExecutable* executable = new (NotNull, allocateCell(*exec->heap())) EvalExecutable(exec, source, isInStrictContext); executable->finishCreation(exec->vm()); - UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable); + UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable, thisTDZMode); if (!unlinkedEvalCode) return 0; @@ -348,7 +368,7 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source } EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) - : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext) + : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec->vm(), source, inStrictContext) { } @@ -357,11 +377,15 @@ void EvalExecutable::destroy(JSCell* cell) static_cast(cell)->EvalExecutable::~EvalExecutable(); } -const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; +const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec, source, false) + : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec->vm(), source, false) { + m_typeProfilingStartOffset = 0; + m_typeProfilingEndOffset = source.length() - 1; + if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler()) + exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset); } void ProgramExecutable::destroy(JSCell* cell) @@ -369,13 +393,13 @@ void ProgramExecutable::destroy(JSCell* cell) static_cast(cell)->ProgramExecutable::~ProgramExecutable(); } -const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; +const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; -FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, bool bodyIncludesBraces) +FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, + UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, + unsigned lastLine, unsigned startColumn, unsigned endColumn) : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext()) , m_unlinkedExecutable(vm, this, unlinkedExecutable) - , m_bodyIncludesBraces(bodyIncludesBraces) - , m_didParseForTheFirstTime(false) { RELEASE_ASSERT(!source.isNull()); ASSERT(source.length()); @@ -385,6 +409,15 @@ FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, Unlinke ASSERT(endColumn != UINT_MAX); m_startColumn = startColumn; m_endColumn = endColumn; + m_parametersStartOffset = unlinkedExecutable->parametersStartOffset(); + m_typeProfilingStartOffset = unlinkedExecutable->typeProfilingStartOffset(); + m_typeProfilingEndOffset = unlinkedExecutable->typeProfilingEndOffset(); +} + +void FunctionExecutable::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + m_singletonFunction.set(vm, this, InferredValue::create(vm)); } void FunctionExecutable::destroy(JSCell* cell) @@ -413,8 +446,6 @@ void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { EvalExecutable* thisObject = jsCast(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); if (thisObject->m_evalCodeBlock) thisObject->m_evalCodeBlock->visitAggregate(visitor); @@ -433,7 +464,7 @@ void EvalExecutable::unlinkCalls() void EvalExecutable::clearCode() { - m_evalCodeBlock.clear(); + m_evalCodeBlock = nullptr; m_unlinkedEvalCodeBlock.clear(); Base::clearCode(); } @@ -443,10 +474,12 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec) ParserError error; VM* vm = &exec->vm(); JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - RefPtr programNode = parse(vm, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); + std::unique_ptr programNode = parse( + vm, m_source, 0, Identifier(), JSParserBuiltinMode::NotBuiltin, + JSParserStrictMode::NotStrict, JSParserCodeType::Program, error); if (programNode) return 0; - ASSERT(error.m_type != ParserError::ErrorNone); + ASSERT(error.isValid()); return error.toErrorObject(lexicalGlobalObject, m_source); } @@ -477,12 +510,16 @@ JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callF BatchedTransitionOptimizer optimizer(vm, globalObject); const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); - const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCodeBlock->functionDeclarations(); - for (size_t i = 0; i < functionDeclarations.size(); ++i) { - UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get(); - JSValue value = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, m_source, lineNo()), scope); - globalObject->addFunction(callFrame, functionDeclarations[i].first, value); + for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) { + UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i); + ASSERT(!unlinkedFunctionExecutable->name().isEmpty()); + globalObject->addFunction(callFrame, unlinkedFunctionExecutable->name()); + if (vm.typeProfiler() || vm.controlFlowProfiler()) { + vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), + unlinkedFunctionExecutable->typeProfilingStartOffset(), + unlinkedFunctionExecutable->typeProfilingEndOffset()); + } } for (size_t i = 0; i < variableDeclarations.size(); ++i) { @@ -498,8 +535,6 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { ProgramExecutable* thisObject = jsCast(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_unlinkedProgramCodeBlock); if (thisObject->m_programCodeBlock) @@ -508,7 +543,7 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) void ProgramExecutable::clearCode() { - m_programCodeBlock.clear(); + m_programCodeBlock = nullptr; m_unlinkedProgramCodeBlock.clear(); Base::clearCode(); } @@ -531,14 +566,13 @@ void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { FunctionExecutable* thisObject = jsCast(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); if (thisObject->m_codeBlockForCall) thisObject->m_codeBlockForCall->visitAggregate(visitor); if (thisObject->m_codeBlockForConstruct) thisObject->m_codeBlockForConstruct->visitAggregate(visitor); visitor.append(&thisObject->m_unlinkedExecutable); + visitor.append(&thisObject->m_singletonFunction); } SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind) @@ -546,24 +580,15 @@ SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind) return codeBlockFor(kind)->symbolTable(); } -void FunctionExecutable::clearCodeIfNotCompiling() -{ - if (isCompiling()) - return; - clearCode(); -} - -void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() +void FunctionExecutable::clearUnlinkedCodeForRecompilation() { - if (isCompiling()) - return; m_unlinkedExecutable->clearCodeForRecompilation(); } void FunctionExecutable::clearCode() { - m_codeBlockForCall.clear(); - m_codeBlockForConstruct.clear(); + m_codeBlockForCall = nullptr; + m_codeBlockForConstruct = nullptr; Base::clearCode(); } @@ -581,34 +606,17 @@ void FunctionExecutable::unlinkCalls() #endif } -FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) +FunctionExecutable* FunctionExecutable::fromGlobalCode( + const Identifier& name, ExecState& exec, const SourceCode& source, + JSObject*& exception, int overrideLineNumber) { - UnlinkedFunctionExecutable* unlinkedExecutable = UnlinkedFunctionExecutable::fromGlobalCode(name, exec, debugger, source, exception); + UnlinkedFunctionExecutable* unlinkedExecutable = + UnlinkedFunctionExecutable::fromGlobalCode( + name, exec, source, exception, overrideLineNumber); if (!unlinkedExecutable) - return 0; - unsigned lineCount = unlinkedExecutable->lineCount(); - unsigned firstLine = source.firstLine() + unlinkedExecutable->firstLineOffset(); - unsigned startOffset = source.startOffset() + unlinkedExecutable->startOffset(); - - // We don't have any owner executable. The source string is effectively like a global - // string (like in the handling of eval). Hence, the startColumn is always 1. - unsigned startColumn = 1; - unsigned sourceLength = unlinkedExecutable->sourceLength(); - bool endColumnIsOnStartLine = !lineCount; - // The unlinkedBodyEndColumn is based-0. Hence, we need to add 1 to it. But if the - // endColumn is on the startLine, then we need to subtract back the adjustment for - // the open brace resulting in an adjustment of 0. - unsigned endColumnExcludingBraces = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? 0 : 1); - unsigned startOffsetExcludingOpenBrace = startOffset + 1; - unsigned endOffsetExcludingCloseBrace = startOffset + sourceLength - 1; - SourceCode bodySource(source.provider(), startOffsetExcludingOpenBrace, endOffsetExcludingCloseBrace, firstLine, startColumn); + return nullptr; - return FunctionExecutable::create(exec->vm(), bodySource, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumnExcludingBraces, false); -} - -String FunctionExecutable::paramString() const -{ - return m_unlinkedExecutable->paramString(); + return unlinkedExecutable->link(exec.vm(), source, overrideLineNumber); } void ExecutableBase::dump(PrintStream& out) const