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