X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/b80e619319b1def83d1e8b4f84042b661be1be7f..14957cd040308e3eeec43d26bae5d76da13fcd85:/runtime/Executable.cpp diff --git a/runtime/Executable.cpp b/runtime/Executable.cpp index 765bd99..5fa560e 100644 --- a/runtime/Executable.cpp +++ b/runtime/Executable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,270 +30,471 @@ #include "CodeBlock.h" #include "JIT.h" #include "Parser.h" -#include "StringBuilder.h" +#include "UStringBuilder.h" #include "Vector.h" +#if ENABLE(DFG_JIT) +#include "DFGByteCodeParser.h" +#include "DFGJITCompiler.h" +#endif + namespace JSC { +const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0 }; + #if ENABLE(JIT) -NativeExecutable::~NativeExecutable() +class ExecutableFinalizer : public WeakHandleOwner { + virtual void finalize(Handle handle, void*) + { + Weak executable(Weak::Adopt, handle); + executable->clearExecutableCode(); + } +}; + +WeakHandleOwner* ExecutableBase::executableFinalizer() { + DEFINE_STATIC_LOCAL(ExecutableFinalizer, finalizer, ()); + return &finalizer; } #endif + +const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0 }; -VPtrHackExecutable::~VPtrHackExecutable() +NativeExecutable::~NativeExecutable() +{ +} + +const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0 }; + +const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0 }; + +EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) + : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext) { } EvalExecutable::~EvalExecutable() { - delete m_evalCodeBlock; +} + +const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0 }; + +ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) + : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false) +{ } ProgramExecutable::~ProgramExecutable() { - delete m_programCodeBlock; } -FunctionExecutable::~FunctionExecutable() +const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0 }; + +FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine) + : ScriptExecutable(globalData->functionExecutableStructure.get(), globalData, source, inStrictContext) + , m_numCapturedVariables(0) + , m_forceUsesArguments(forceUsesArguments) + , m_parameters(parameters) + , m_name(name) + , m_symbolTable(0) { - delete m_codeBlock; + m_firstLine = firstLine; + m_lastLine = lastLine; } -JSObject* EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode) +FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine) + : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext) + , m_numCapturedVariables(0) + , m_forceUsesArguments(forceUsesArguments) + , m_parameters(parameters) + , m_name(name) + , m_symbolTable(0) { - int errLine; - UString errMsg; - RefPtr evalNode = exec->globalData().parser->parse(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); - if (!evalNode) - return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); - recordParse(evalNode->features(), evalNode->lineNo(), evalNode->lastLine()); + m_firstLine = firstLine; + m_lastLine = lastLine; +} - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + +JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + JSObject* exception = 0; + JSGlobalData* globalData = &exec->globalData(); + JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); + if (!lexicalGlobalObject->isEvalEnabled()) + return throwError(exec, createEvalError(exec, "Eval is disabled")); + RefPtr evalNode = globalData->parser->parse(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception); + if (!evalNode) { + ASSERT(exception); + return exception; + } + recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine()); + + JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); ASSERT(!m_evalCodeBlock); - m_evalCodeBlock = new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth()); - OwnPtr generator(new BytecodeGenerator(evalNode.get(), globalObject->debugger(), scopeChain, m_evalCodeBlock->symbolTable(), m_evalCodeBlock)); - generator->generate(); - + m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChainNode->localDepth())); + OwnPtr generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get()))); + if ((exception = generator->generate())) { + m_evalCodeBlock.clear(); + evalNode->destroyData(); + return exception; + } + evalNode->destroyData(); + +#if ENABLE(JIT) + if (exec->globalData().canUseJIT()) { + m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_evalCodeBlock.get()); +#if !ENABLE(OPCODE_SAMPLING) + if (!BytecodeGenerator::dumpsGeneratedCode()) + m_evalCodeBlock->discardBytecode(); +#endif + } +#endif + +#if ENABLE(JIT) +#if ENABLE(INTERPRETER) + if (!m_jitCodeForCall) + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock)); + else +#endif + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock) + m_jitCodeForCall.size()); +#else + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock)); +#endif + return 0; } -JSObject* ProgramExecutable::checkSyntax(ExecState* exec) +void EvalExecutable::visitChildren(SlotVisitor& visitor) { - int errLine; - UString errMsg; - RefPtr programNode = exec->globalData().parser->parse(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); - if (!programNode) - return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); - return 0; + ASSERT_GC_OBJECT_INHERITS(this, &s_info); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(structure()->typeInfo().overridesVisitChildren()); + ScriptExecutable::visitChildren(visitor); + if (m_evalCodeBlock) + m_evalCodeBlock->visitAggregate(visitor); } -JSObject* ProgramExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode) +void EvalExecutable::unlinkCalls() { - int errLine; - UString errMsg; - RefPtr programNode = exec->globalData().parser->parse(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); - if (!programNode) - return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); - recordParse(programNode->features(), programNode->lineNo(), programNode->lastLine()); - - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); - - ASSERT(!m_programCodeBlock); - m_programCodeBlock = new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider()); - OwnPtr generator(new BytecodeGenerator(programNode.get(), globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_programCodeBlock)); - generator->generate(); +#if ENABLE(JIT) + if (!m_jitCodeForCall) + return; + ASSERT(m_evalCodeBlock); + m_evalCodeBlock->unlinkCalls(); +#endif +} - programNode->destroyData(); - return 0; +JSObject* ProgramExecutable::checkSyntax(ExecState* exec) +{ + JSObject* exception = 0; + JSGlobalData* globalData = &exec->globalData(); + JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); + RefPtr programNode = globalData->parser->parse(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, JSParseNormal, &exception); + if (programNode) + return 0; + ASSERT(exception); + return exception; } -void FunctionExecutable::compile(ExecState*, ScopeChainNode* scopeChainNode) +JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode) { - JSGlobalData* globalData = scopeChainNode->globalData; - RefPtr body = globalData->parser->parse(globalData, 0, 0, m_source); - if (m_forceUsesArguments) - body->setUsesArguments(); - body->finishParsing(m_parameters, m_name); - recordParse(body->features(), body->lineNo(), body->lastLine()); + ASSERT(!m_programCodeBlock); - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + JSObject* exception = 0; + JSGlobalData* globalData = &exec->globalData(); + JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); + RefPtr programNode = globalData->parser->parse(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception); + if (!programNode) { + ASSERT(exception); + return exception; + } + recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine()); - ASSERT(!m_codeBlock); - m_codeBlock = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset()); - OwnPtr generator(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlock->symbolTable(), m_codeBlock)); - generator->generate(); - m_numParameters = m_codeBlock->m_numParameters; - ASSERT(m_numParameters); - m_numVariables = m_codeBlock->m_numVars; + JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); + + m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider())); + OwnPtr generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get()))); + if ((exception = generator->generate())) { + m_programCodeBlock.clear(); + programNode->destroyData(); + return exception; + } - body->destroyData(); -} + programNode->destroyData(); #if ENABLE(JIT) + if (exec->globalData().canUseJIT()) { + m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get()); +#if !ENABLE(OPCODE_SAMPLING) + if (!BytecodeGenerator::dumpsGeneratedCode()) + m_programCodeBlock->discardBytecode(); +#endif + } +#endif -void EvalExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) -{ +#if ENABLE(JIT) #if ENABLE(INTERPRETER) - ASSERT(scopeChainNode->globalData->canUseJIT()); + if (!m_jitCodeForCall) + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock)); + else #endif - CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); - -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - codeBlock->discardBytecode(); + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock) + m_jitCodeForCall.size()); +#else + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock)); #endif + + return 0; } -void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +void ProgramExecutable::unlinkCalls() { -#if ENABLE(INTERPRETER) - ASSERT(scopeChainNode->globalData->canUseJIT()); -#endif - CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); - -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - codeBlock->discardBytecode(); +#if ENABLE(JIT) + if (!m_jitCodeForCall) + return; + ASSERT(m_programCodeBlock); + m_programCodeBlock->unlinkCalls(); #endif } -void FunctionExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +#if ENABLE(JIT) +static bool tryDFGCompile(JSGlobalData* globalData, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck) { -#if ENABLE(INTERPRETER) - ASSERT(scopeChainNode->globalData->canUseJIT()); +#if ENABLE(DFG_JIT) +#if ENABLE(DFG_JIT_RESTRICTIONS) + // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets. + // FIXME: temporarily disable property accesses until we fix regressions. + if (codeBlock->numberOfJumpTargets() || codeBlock->numberOfStructureStubInfos()) + return false; #endif - CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - codeBlock->discardBytecode(); + DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars); + if (!parse(dfg, globalData, codeBlock)) + return false; + + DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock); + dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck); + return true; +#else + UNUSED_PARAM(globalData); + UNUSED_PARAM(codeBlock); + UNUSED_PARAM(jitCode); + UNUSED_PARAM(jitCodeWithArityCheck); + return false; #endif } - #endif -void FunctionExecutable::markAggregate(MarkStack& markStack) +void ProgramExecutable::visitChildren(SlotVisitor& visitor) { - if (m_codeBlock) - m_codeBlock->markAggregate(markStack); + ASSERT_GC_OBJECT_INHERITS(this, &s_info); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(structure()->typeInfo().overridesVisitChildren()); + ScriptExecutable::visitChildren(visitor); + if (m_programCodeBlock) + m_programCodeBlock->visitAggregate(visitor); } -ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) +JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode) { - RefPtr newFunctionBody = globalData->parser->parse(globalData, 0, 0, m_source); + JSObject* exception = 0; + JSGlobalData* globalData = scopeChainNode->globalData; + RefPtr body = globalData->parser->parse(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception); + if (!body) { + ASSERT(exception); + return exception; + } if (m_forceUsesArguments) - newFunctionBody->setUsesArguments(); - newFunctionBody->finishParsing(m_parameters, m_name); + body->setUsesArguments(); + body->finishParsing(m_parameters, m_name); + recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); - OwnPtr newCodeBlock(new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset())); - globalData->functionCodeBlockBeingReparsed = newCodeBlock.get(); + ASSERT(!m_codeBlockForCall); + m_codeBlockForCall = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), false)); + OwnPtr generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForCall->symbolTable(), m_codeBlockForCall.get()))); + if ((exception = generator->generate())) { + m_codeBlockForCall.clear(); + body->destroyData(); + return exception; + } - OwnPtr generator(new BytecodeGenerator(newFunctionBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); - generator->setRegeneratingForExceptionInfo(static_cast(codeBlock)); - generator->generate(); + m_numParametersForCall = m_codeBlockForCall->m_numParameters; + ASSERT(m_numParametersForCall); + m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars; + m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); - ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount()); + body->destroyData(); #if ENABLE(JIT) -#if ENABLE(INTERPRETER) - if (globalData->canUseJIT()) + if (exec->globalData().canUseJIT()) { + bool dfgCompiled = tryDFGCompile(&exec->globalData(), m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck); + if (!dfgCompiled) + m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck); + +#if !ENABLE(OPCODE_SAMPLING) + if (!BytecodeGenerator::dumpsGeneratedCode()) + m_codeBlockForCall->discardBytecode(); #endif - { - JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get(), generatedJITCode().start()); - ASSERT(newJITCode.size() == generatedJITCode().size()); } #endif - globalData->functionCodeBlockBeingReparsed = 0; +#if ENABLE(JIT) +#if ENABLE(INTERPRETER) + if (!m_jitCodeForCall) + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); + else +#endif + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall) + m_jitCodeForCall.size()); +#else + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); +#endif - return newCodeBlock->extractExceptionInfo(); + return 0; } -ExceptionInfo* EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) +JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode) { - RefPtr newEvalBody = globalData->parser->parse(globalData, 0, 0, m_source); + JSObject* exception = 0; + JSGlobalData* globalData = scopeChainNode->globalData; + RefPtr body = globalData->parser->parse(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception); + if (!body) { + ASSERT(exception); + return exception; + } + if (m_forceUsesArguments) + body->setUsesArguments(); + body->finishParsing(m_parameters, m_name); + recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); - OwnPtr newCodeBlock(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth())); + ASSERT(!m_codeBlockForConstruct); + m_codeBlockForConstruct = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), true)); + OwnPtr generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct.get()))); + if ((exception = generator->generate())) { + m_codeBlockForConstruct.clear(); + body->destroyData(); + return exception; + } - OwnPtr generator(new BytecodeGenerator(newEvalBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); - generator->setRegeneratingForExceptionInfo(static_cast(codeBlock)); - generator->generate(); + m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters; + ASSERT(m_numParametersForConstruct); + m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars; + m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); - ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount()); + body->destroyData(); #if ENABLE(JIT) -#if ENABLE(INTERPRETER) - if (globalData->canUseJIT()) + if (exec->globalData().canUseJIT()) { + m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, m_codeBlockForConstruct.get(), &m_jitCodeForConstructWithArityCheck); +#if !ENABLE(OPCODE_SAMPLING) + if (!BytecodeGenerator::dumpsGeneratedCode()) + m_codeBlockForConstruct->discardBytecode(); #endif - { - JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get(), generatedJITCode().start()); - ASSERT(newJITCode.size() == generatedJITCode().size()); } #endif - return newCodeBlock->extractExceptionInfo(); +#if ENABLE(JIT) +#if ENABLE(INTERPRETER) + if (!m_jitCodeForConstruct) + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct)); + else +#endif + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct) + m_jitCodeForConstruct.size()); +#else + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct)); +#endif + + return 0; +} + +void FunctionExecutable::visitChildren(SlotVisitor& visitor) +{ + ASSERT_GC_OBJECT_INHERITS(this, &s_info); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(structure()->typeInfo().overridesVisitChildren()); + ScriptExecutable::visitChildren(visitor); + if (m_codeBlockForCall) + m_codeBlockForCall->visitAggregate(visitor); + if (m_codeBlockForConstruct) + m_codeBlockForConstruct->visitAggregate(visitor); } -void FunctionExecutable::recompile() +void FunctionExecutable::discardCode() { - delete m_codeBlock; - m_codeBlock = 0; - m_numParameters = NUM_PARAMETERS_NOT_COMPILED; #if ENABLE(JIT) - m_jitCode = JITCode(); + // These first two checks are to handle the rare case where + // we are trying to evict code for a function during its + // codegen. + if (!m_jitCodeForCall && m_codeBlockForCall) + return; + if (!m_jitCodeForConstruct && m_codeBlockForConstruct) + return; + m_jitCodeForCall = JITCode(); + m_jitCodeForConstruct = JITCode(); + m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); + m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); #endif + if (m_codeBlockForCall) + m_codeBlockForCall->clearEvalCache(); + m_codeBlockForCall.clear(); + if (m_codeBlockForConstruct) + m_codeBlockForConstruct->clearEvalCache(); + m_codeBlockForConstruct.clear(); + m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED; + m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED; + } -PassRefPtr FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg) +void FunctionExecutable::unlinkCalls() { - RefPtr program = exec->globalData().parser->parse(&exec->globalData(), debugger, exec, source, errLine, errMsg); - if (!program) +#if ENABLE(JIT) + if (!!m_jitCodeForCall) { + ASSERT(m_codeBlockForCall); + m_codeBlockForCall->unlinkCalls(); + } + if (!!m_jitCodeForConstruct) { + ASSERT(m_codeBlockForConstruct); + m_codeBlockForConstruct->unlinkCalls(); + } +#endif +} + +FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) +{ + JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); + RefPtr program = exec->globalData().parser->parse(lexicalGlobalObject, debugger, exec, source, 0, JSParseNormal, exception); + if (!program) { + ASSERT(*exception); return 0; + } + // Uses of this function that would not result in a single function expression are invalid. StatementNode* exprStatement = program->singleStatement(); ASSERT(exprStatement); ASSERT(exprStatement->isExprStatement()); - if (!exprStatement || !exprStatement->isExprStatement()) - return 0; - ExpressionNode* funcExpr = static_cast(exprStatement)->expr(); ASSERT(funcExpr); ASSERT(funcExpr->isFuncExprNode()); - if (!funcExpr || !funcExpr->isFuncExprNode()) - return 0; - FunctionBodyNode* body = static_cast(funcExpr)->body(); ASSERT(body); - return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine()); + + return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); } UString FunctionExecutable::paramString() const { FunctionParameters& parameters = *m_parameters; - StringBuilder builder; + UStringBuilder builder; for (size_t pos = 0; pos < parameters.size(); ++pos) { if (!builder.isEmpty()) builder.append(", "); builder.append(parameters[pos].ustring()); } - return builder.build(); + return builder.toUString(); } -}; - - +}