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 41namespace JSC { 42 43const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0 }; 44 45const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0 }; 46 47NativeExecutable::~NativeExecutable() 48{ 49} 50 51const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0 }; 52 53EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) 54 : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext) 55{ 56} 57 58EvalExecutable::~EvalExecutable() 59{ 60} 61 62const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0 }; 63 64ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) 65 : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false) 66{ 67} 68 69ProgramExecutable::~ProgramExecutable() 70{ 71} 72 73const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0 }; 74 75FunctionExecutable::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 87FunctionExecutable::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 100JSObject* 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 138void EvalExecutable::markChildren(MarkStack& markStack) 139{ 140 ScriptExecutable::markChildren(markStack); 141 if (m_evalCodeBlock) 142 m_evalCodeBlock->markAggregate(markStack); 143} 144 145JSObject* 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 157JSObject* 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) 197static 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 224void ProgramExecutable::markChildren(MarkStack& markStack) 225{ 226 ScriptExecutable::markChildren(markStack); 227 if (m_programCodeBlock) 228 m_programCodeBlock->markAggregate(markStack); 229} 230 231JSObject* 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 279JSObject* 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 324void 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 333void 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 345FunctionExecutable* 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 367UString 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