Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "Executable.h"
     28 
     29 #include "BytecodeGenerator.h"
     30 #include "CodeBlock.h"
     31 #include "JIT.h"
     32 #include "Parser.h"
     33 #include "UStringBuilder.h"
     34 #include "Vector.h"
     35 
     36 #if ENABLE(DFG_JIT)
     37 #include "DFGByteCodeParser.h"
     38 #include "DFGJITCompiler.h"
     39 #endif
     40 
     41 namespace JSC {
     42 
     43 const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0 };
     44 
     45 const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0 };
     46 
     47 NativeExecutable::~NativeExecutable()
     48 {
     49 }
     50 
     51 const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0 };
     52 
     53 EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext)
     54     : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext)
     55 {
     56 }
     57 
     58 EvalExecutable::~EvalExecutable()
     59 {
     60 }
     61 
     62 const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0 };
     63 
     64 ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source)
     65     : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false)
     66 {
     67 }
     68 
     69 ProgramExecutable::~ProgramExecutable()
     70 {
     71 }
     72 
     73 const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0 };
     74 
     75 FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine)
     76     : ScriptExecutable(globalData->functionExecutableStructure.get(), globalData, source, inStrictContext)
     77     , m_numCapturedVariables(0)
     78     , m_forceUsesArguments(forceUsesArguments)
     79     , m_parameters(parameters)
     80     , m_name(name)
     81     , m_symbolTable(0)
     82 {
     83     m_firstLine = firstLine;
     84     m_lastLine = lastLine;
     85 }
     86 
     87 FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine)
     88     : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext)
     89     , m_numCapturedVariables(0)
     90     , m_forceUsesArguments(forceUsesArguments)
     91     , m_parameters(parameters)
     92     , m_name(name)
     93     , m_symbolTable(0)
     94 {
     95     m_firstLine = firstLine;
     96     m_lastLine = lastLine;
     97 }
     98 
     99 
    100 JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
    101 {
    102     JSObject* exception = 0;
    103     JSGlobalData* globalData = &exec->globalData();
    104     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    105     RefPtr<EvalNode> evalNode = globalData->parser->parse<EvalNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
    106     if (!evalNode) {
    107         ASSERT(exception);
    108         return exception;
    109     }
    110     recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine());
    111 
    112     JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
    113 
    114     ASSERT(!m_evalCodeBlock);
    115     m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChainNode->localDepth()));
    116     OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get())));
    117     if ((exception = generator->generate())) {
    118         m_evalCodeBlock.clear();
    119         evalNode->destroyData();
    120         return exception;
    121     }
    122 
    123     evalNode->destroyData();
    124 
    125 #if ENABLE(JIT)
    126     if (exec->globalData().canUseJIT()) {
    127         m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_evalCodeBlock.get());
    128 #if !ENABLE(OPCODE_SAMPLING)
    129         if (!BytecodeGenerator::dumpsGeneratedCode())
    130             m_evalCodeBlock->discardBytecode();
    131 #endif
    132     }
    133 #endif
    134 
    135     return 0;
    136 }
    137 
    138 void EvalExecutable::markChildren(MarkStack& markStack)
    139 {
    140     ScriptExecutable::markChildren(markStack);
    141     if (m_evalCodeBlock)
    142         m_evalCodeBlock->markAggregate(markStack);
    143 }
    144 
    145 JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
    146 {
    147     JSObject* exception = 0;
    148     JSGlobalData* globalData = &exec->globalData();
    149     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    150     RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, JSParseNormal, &exception);
    151     if (programNode)
    152         return 0;
    153     ASSERT(exception);
    154     return exception;
    155 }
    156 
    157 JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
    158 {
    159     ASSERT(!m_programCodeBlock);
    160 
    161     JSObject* exception = 0;
    162     JSGlobalData* globalData = &exec->globalData();
    163     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    164     RefPtr<ProgramNode> programNode = globalData->parser->parse<ProgramNode>(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
    165     if (!programNode) {
    166         ASSERT(exception);
    167         return exception;
    168     }
    169     recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine());
    170 
    171     JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
    172 
    173     m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider()));
    174     OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get())));
    175     if ((exception = generator->generate())) {
    176         m_programCodeBlock.clear();
    177         programNode->destroyData();
    178         return exception;
    179     }
    180 
    181     programNode->destroyData();
    182 
    183 #if ENABLE(JIT)
    184     if (exec->globalData().canUseJIT()) {
    185         m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get());
    186 #if !ENABLE(OPCODE_SAMPLING)
    187         if (!BytecodeGenerator::dumpsGeneratedCode())
    188             m_programCodeBlock->discardBytecode();
    189 #endif
    190     }
    191 #endif
    192 
    193    return 0;
    194 }
    195 
    196 #if ENABLE(JIT)
    197 static bool tryDFGCompile(JSGlobalData* globalData, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck)
    198 {
    199 #if ENABLE(DFG_JIT)
    200 #if ENABLE(DFG_JIT_RESTRICTIONS)
    201     // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets.
    202     // FIXME: temporarily disable property accesses until we fix regressions.
    203     if (codeBlock->numberOfJumpTargets() || codeBlock->numberOfStructureStubInfos())
    204         return false;
    205 #endif
    206 
    207     DFG::Graph dfg;
    208     if (!parse(dfg, globalData, codeBlock))
    209         return false;
    210 
    211     DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock);
    212     dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck);
    213     return true;
    214 #else
    215     UNUSED_PARAM(globalData);
    216     UNUSED_PARAM(codeBlock);
    217     UNUSED_PARAM(jitCode);
    218     UNUSED_PARAM(jitCodeWithArityCheck);
    219     return false;
    220 #endif
    221 }
    222 #endif
    223 
    224 void ProgramExecutable::markChildren(MarkStack& markStack)
    225 {
    226     ScriptExecutable::markChildren(markStack);
    227     if (m_programCodeBlock)
    228         m_programCodeBlock->markAggregate(markStack);
    229 }
    230 
    231 JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
    232 {
    233     JSObject* exception = 0;
    234     JSGlobalData* globalData = scopeChainNode->globalData;
    235     RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
    236     if (!body) {
    237         ASSERT(exception);
    238         return exception;
    239     }
    240     if (m_forceUsesArguments)
    241         body->setUsesArguments();
    242     body->finishParsing(m_parameters, m_name);
    243     recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
    244 
    245     JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
    246 
    247     ASSERT(!m_codeBlockForCall);
    248     m_codeBlockForCall = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), false));
    249     OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForCall->symbolTable(), m_codeBlockForCall.get())));
    250     if ((exception = generator->generate())) {
    251         m_codeBlockForCall.clear();
    252         body->destroyData();
    253         return exception;
    254     }
    255 
    256     m_numParametersForCall = m_codeBlockForCall->m_numParameters;
    257     ASSERT(m_numParametersForCall);
    258     m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars;
    259     m_symbolTable = m_codeBlockForCall->sharedSymbolTable();
    260 
    261     body->destroyData();
    262 
    263 #if ENABLE(JIT)
    264     if (exec->globalData().canUseJIT()) {
    265         bool dfgCompiled = tryDFGCompile(&exec->globalData(), m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck);
    266         if (!dfgCompiled)
    267             m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck);
    268 
    269 #if !ENABLE(OPCODE_SAMPLING)
    270         if (!BytecodeGenerator::dumpsGeneratedCode())
    271             m_codeBlockForCall->discardBytecode();
    272 #endif
    273     }
    274 #endif
    275 
    276     return 0;
    277 }
    278 
    279 JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode)
    280 {
    281     JSObject* exception = 0;
    282     JSGlobalData* globalData = scopeChainNode->globalData;
    283     RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception);
    284     if (!body) {
    285         ASSERT(exception);
    286         return exception;
    287     }
    288     if (m_forceUsesArguments)
    289         body->setUsesArguments();
    290     body->finishParsing(m_parameters, m_name);
    291     recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
    292 
    293     JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
    294 
    295     ASSERT(!m_codeBlockForConstruct);
    296     m_codeBlockForConstruct = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), true));
    297     OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct.get())));
    298     if ((exception = generator->generate())) {
    299         m_codeBlockForConstruct.clear();
    300         body->destroyData();
    301         return exception;
    302     }
    303 
    304     m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters;
    305     ASSERT(m_numParametersForConstruct);
    306     m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars;
    307     m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable();
    308 
    309     body->destroyData();
    310 
    311 #if ENABLE(JIT)
    312     if (exec->globalData().canUseJIT()) {
    313         m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, m_codeBlockForConstruct.get(), &m_jitCodeForConstructWithArityCheck);
    314 #if !ENABLE(OPCODE_SAMPLING)
    315         if (!BytecodeGenerator::dumpsGeneratedCode())
    316             m_codeBlockForConstruct->discardBytecode();
    317 #endif
    318     }
    319 #endif
    320 
    321     return 0;
    322 }
    323 
    324 void FunctionExecutable::markChildren(MarkStack& markStack)
    325 {
    326     ScriptExecutable::markChildren(markStack);
    327     if (m_codeBlockForCall)
    328         m_codeBlockForCall->markAggregate(markStack);
    329     if (m_codeBlockForConstruct)
    330         m_codeBlockForConstruct->markAggregate(markStack);
    331 }
    332 
    333 void FunctionExecutable::discardCode()
    334 {
    335     m_codeBlockForCall.clear();
    336     m_codeBlockForConstruct.clear();
    337     m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED;
    338     m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED;
    339 #if ENABLE(JIT)
    340     m_jitCodeForCall = JITCode();
    341     m_jitCodeForConstruct = JITCode();
    342 #endif
    343 }
    344 
    345 FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
    346 {
    347     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    348     RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(lexicalGlobalObject, debugger, exec, source, 0, JSParseNormal, exception);
    349     if (!program) {
    350         ASSERT(*exception);
    351         return 0;
    352     }
    353 
    354     // Uses of this function that would not result in a single function expression are invalid.
    355     StatementNode* exprStatement = program->singleStatement();
    356     ASSERT(exprStatement);
    357     ASSERT(exprStatement->isExprStatement());
    358     ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr();
    359     ASSERT(funcExpr);
    360     ASSERT(funcExpr->isFuncExprNode());
    361     FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
    362     ASSERT(body);
    363 
    364     return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
    365 }
    366 
    367 UString FunctionExecutable::paramString() const
    368 {
    369     FunctionParameters& parameters = *m_parameters;
    370     UStringBuilder builder;
    371     for (size_t pos = 0; pos < parameters.size(); ++pos) {
    372         if (!builder.isEmpty())
    373             builder.append(", ");
    374         builder.append(parameters[pos].ustring());
    375     }
    376     return builder.toUString();
    377 }
    378 
    379 }
    380