1/* 2 * Copyright (C) 2009, 2010, 2013 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 "BatchedTransitionOptimizer.h" 30#include "BytecodeGenerator.h" 31#include "CodeBlock.h" 32#include "DFGDriver.h" 33#include "JIT.h" 34#include "LLIntEntrypoint.h" 35#include "JSCInlines.h" 36#include "Parser.h" 37#include "ProfilerDatabase.h" 38#include <wtf/CommaPrinter.h> 39#include <wtf/Vector.h> 40#include <wtf/text/StringBuilder.h> 41 42namespace JSC { 43 44const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; 45 46#if ENABLE(JIT) 47void ExecutableBase::destroy(JSCell* cell) 48{ 49 static_cast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase(); 50} 51#endif 52 53void ExecutableBase::clearCode() 54{ 55#if ENABLE(JIT) 56 m_jitCodeForCall.clear(); 57 m_jitCodeForConstruct.clear(); 58 m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); 59 m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); 60 m_jitCodeForCallWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); 61 m_jitCodeForConstructWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); 62#endif 63 m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED; 64 m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED; 65} 66 67#if ENABLE(DFG_JIT) 68Intrinsic ExecutableBase::intrinsic() const 69{ 70 if (const NativeExecutable* nativeExecutable = jsDynamicCast<const NativeExecutable*>(this)) 71 return nativeExecutable->intrinsic(); 72 return NoIntrinsic; 73} 74#else 75Intrinsic ExecutableBase::intrinsic() const 76{ 77 return NoIntrinsic; 78} 79#endif 80 81const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; 82 83#if ENABLE(JIT) 84void NativeExecutable::destroy(JSCell* cell) 85{ 86 static_cast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable(); 87} 88#endif 89 90#if ENABLE(DFG_JIT) 91Intrinsic NativeExecutable::intrinsic() const 92{ 93 return m_intrinsic; 94} 95#endif 96 97const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; 98 99#if ENABLE(JIT) 100void ScriptExecutable::destroy(JSCell* cell) 101{ 102 static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable(); 103} 104#endif 105 106void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) 107{ 108 RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this); 109 RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType())); 110 111 VM& vm = *genericCodeBlock->vm(); 112 113 if (vm.m_perBytecodeProfiler) 114 vm.m_perBytecodeProfiler->ensureBytecodesFor(genericCodeBlock); 115 116 ASSERT(vm.heap.isDeferred()); 117 118 CodeSpecializationKind kind = genericCodeBlock->specializationKind(); 119 120 RefPtr<CodeBlock> oldCodeBlock; 121 122 switch (kind) { 123 case CodeForCall: 124 m_jitCodeForCall = genericCodeBlock->jitCode(); 125 m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); 126 m_jitCodeForCallWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); 127 m_numParametersForCall = genericCodeBlock->numParameters(); 128 break; 129 case CodeForConstruct: 130 m_jitCodeForConstruct = genericCodeBlock->jitCode(); 131 m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); 132 m_jitCodeForConstructWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr(); 133 m_numParametersForConstruct = genericCodeBlock->numParameters(); 134 break; 135 } 136 137 switch (genericCodeBlock->codeType()) { 138 case GlobalCode: { 139 ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); 140 ProgramCodeBlock* codeBlock = static_cast<ProgramCodeBlock*>(genericCodeBlock); 141 142 ASSERT(kind == CodeForCall); 143 144 oldCodeBlock = executable->m_programCodeBlock; 145 executable->m_programCodeBlock = codeBlock; 146 break; 147 } 148 149 case EvalCode: { 150 EvalExecutable* executable = jsCast<EvalExecutable*>(this); 151 EvalCodeBlock* codeBlock = static_cast<EvalCodeBlock*>(genericCodeBlock); 152 153 ASSERT(kind == CodeForCall); 154 155 oldCodeBlock = executable->m_evalCodeBlock; 156 executable->m_evalCodeBlock = codeBlock; 157 break; 158 } 159 160 case FunctionCode: { 161 FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); 162 FunctionCodeBlock* codeBlock = static_cast<FunctionCodeBlock*>(genericCodeBlock); 163 164 switch (kind) { 165 case CodeForCall: 166 oldCodeBlock = executable->m_codeBlockForCall; 167 executable->m_codeBlockForCall = codeBlock; 168 break; 169 case CodeForConstruct: 170 oldCodeBlock = executable->m_codeBlockForConstruct; 171 executable->m_codeBlockForConstruct = codeBlock; 172 break; 173 } 174 break; 175 } } 176 177 if (oldCodeBlock) 178 oldCodeBlock->unlinkIncomingCalls(); 179 180 Debugger* debugger = genericCodeBlock->globalObject()->debugger(); 181 if (debugger) 182 debugger->registerCodeBlock(genericCodeBlock); 183 184 Heap::heap(this)->writeBarrier(this); 185} 186 187PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor( 188 CodeSpecializationKind kind, JSFunction* function, JSScope** scope, JSObject*& exception) 189{ 190 VM* vm = (*scope)->vm(); 191 192 ASSERT(vm->heap.isDeferred()); 193 ASSERT(startColumn() != UINT_MAX); 194 ASSERT(endColumn() != UINT_MAX); 195 196 if (classInfo() == EvalExecutable::info()) { 197 EvalExecutable* executable = jsCast<EvalExecutable*>(this); 198 RELEASE_ASSERT(kind == CodeForCall); 199 RELEASE_ASSERT(!executable->m_evalCodeBlock); 200 RELEASE_ASSERT(!function); 201 return adoptRef(new EvalCodeBlock( 202 executable, executable->m_unlinkedEvalCodeBlock.get(), *scope, 203 executable->source().provider())); 204 } 205 206 if (classInfo() == ProgramExecutable::info()) { 207 ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); 208 RELEASE_ASSERT(kind == CodeForCall); 209 RELEASE_ASSERT(!executable->m_programCodeBlock); 210 RELEASE_ASSERT(!function); 211 return adoptRef(new ProgramCodeBlock( 212 executable, executable->m_unlinkedProgramCodeBlock.get(), *scope, 213 executable->source().provider(), executable->source().startColumn())); 214 } 215 216 RELEASE_ASSERT(classInfo() == FunctionExecutable::info()); 217 RELEASE_ASSERT(function); 218 FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); 219 RELEASE_ASSERT(!executable->codeBlockFor(kind)); 220 JSGlobalObject* globalObject = (*scope)->globalObject(); 221 ParserError error; 222 DebuggerMode debuggerMode = globalObject->hasDebugger() ? DebuggerOn : DebuggerOff; 223 ProfilerMode profilerMode = globalObject->hasProfiler() ? ProfilerOn : ProfilerOff; 224 UnlinkedFunctionCodeBlock* unlinkedCodeBlock = 225 executable->m_unlinkedExecutable->codeBlockFor( 226 *vm, executable->m_source, kind, debuggerMode, profilerMode, executable->bodyIncludesBraces(), error); 227 recordParse(executable->m_unlinkedExecutable->features(), executable->m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine(), startColumn(), endColumn()); 228 if (!unlinkedCodeBlock) { 229 exception = vm->throwException( 230 globalObject->globalExec(), 231 error.toErrorObject(globalObject, executable->m_source)); 232 return 0; 233 } 234 235 // Parsing reveals whether our function uses features that require a separate function name object in the scope chain. 236 // Be sure to add this scope before linking the bytecode because this scope will change the resolution depth of non-local variables. 237 if (!executable->m_didParseForTheFirstTime) { 238 executable->m_didParseForTheFirstTime = true; 239 function->addNameScopeIfNeeded(*vm); 240 *scope = function->scope(); 241 } 242 243 SourceProvider* provider = executable->source().provider(); 244 unsigned sourceOffset = executable->source().startOffset(); 245 unsigned startColumn = executable->source().startColumn(); 246 247 return adoptRef(new FunctionCodeBlock( 248 executable, unlinkedCodeBlock, *scope, provider, sourceOffset, startColumn)); 249} 250 251PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor( 252 CodeSpecializationKind kind) 253{ 254 if (classInfo() == EvalExecutable::info()) { 255 RELEASE_ASSERT(kind == CodeForCall); 256 EvalExecutable* executable = jsCast<EvalExecutable*>(this); 257 EvalCodeBlock* baseline = static_cast<EvalCodeBlock*>( 258 executable->m_evalCodeBlock->baselineVersion()); 259 RefPtr<EvalCodeBlock> result = adoptRef(new EvalCodeBlock( 260 CodeBlock::CopyParsedBlock, *baseline)); 261 result->setAlternative(baseline); 262 return result; 263 } 264 265 if (classInfo() == ProgramExecutable::info()) { 266 RELEASE_ASSERT(kind == CodeForCall); 267 ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); 268 ProgramCodeBlock* baseline = static_cast<ProgramCodeBlock*>( 269 executable->m_programCodeBlock->baselineVersion()); 270 RefPtr<ProgramCodeBlock> result = adoptRef(new ProgramCodeBlock( 271 CodeBlock::CopyParsedBlock, *baseline)); 272 result->setAlternative(baseline); 273 return result; 274 } 275 276 RELEASE_ASSERT(classInfo() == FunctionExecutable::info()); 277 FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); 278 FunctionCodeBlock* baseline = static_cast<FunctionCodeBlock*>( 279 executable->codeBlockFor(kind)->baselineVersion()); 280 RefPtr<FunctionCodeBlock> result = adoptRef(new FunctionCodeBlock( 281 CodeBlock::CopyParsedBlock, *baseline)); 282 result->setAlternative(baseline); 283 return result; 284} 285 286static void setupLLInt(VM& vm, CodeBlock* codeBlock) 287{ 288 LLInt::setEntrypoint(vm, codeBlock); 289} 290 291static void setupJIT(VM& vm, CodeBlock* codeBlock) 292{ 293#if ENABLE(JIT) 294 CompilationResult result = JIT::compile(&vm, codeBlock, JITCompilationMustSucceed); 295 RELEASE_ASSERT(result == CompilationSuccessful); 296#else 297 UNUSED_PARAM(vm); 298 UNUSED_PARAM(codeBlock); 299 UNREACHABLE_FOR_PLATFORM(); 300#endif 301} 302 303JSObject* ScriptExecutable::prepareForExecutionImpl( 304 ExecState* exec, JSFunction* function, JSScope** scope, CodeSpecializationKind kind) 305{ 306 VM& vm = exec->vm(); 307 DeferGC deferGC(vm.heap); 308 309 JSObject* exception = 0; 310 RefPtr<CodeBlock> codeBlock = newCodeBlockFor(kind, function, scope, exception); 311 if (!codeBlock) { 312 RELEASE_ASSERT(exception); 313 return exception; 314 } 315 316 if (Options::validateBytecode()) 317 codeBlock->validate(); 318 319 if (Options::useLLInt()) 320 setupLLInt(vm, codeBlock.get()); 321 else 322 setupJIT(vm, codeBlock.get()); 323 324 installCode(codeBlock.get()); 325 return 0; 326} 327 328const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) }; 329 330EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext) 331{ 332 JSGlobalObject* globalObject = exec->lexicalGlobalObject(); 333 if (!globalObject->evalEnabled()) { 334 exec->vm().throwException(exec, createEvalError(exec, globalObject->evalDisabledErrorMessage())); 335 return 0; 336 } 337 338 EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext); 339 executable->finishCreation(exec->vm()); 340 341 UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable); 342 if (!unlinkedEvalCode) 343 return 0; 344 345 executable->m_unlinkedEvalCodeBlock.set(exec->vm(), executable, unlinkedEvalCode); 346 347 return executable; 348} 349 350EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) 351 : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext) 352{ 353} 354 355void EvalExecutable::destroy(JSCell* cell) 356{ 357 static_cast<EvalExecutable*>(cell)->EvalExecutable::~EvalExecutable(); 358} 359 360const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; 361 362ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) 363 : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec, source, false) 364{ 365} 366 367void ProgramExecutable::destroy(JSCell* cell) 368{ 369 static_cast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable(); 370} 371 372const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; 373 374FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, bool bodyIncludesBraces) 375 : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext()) 376 , m_unlinkedExecutable(vm, this, unlinkedExecutable) 377 , m_bodyIncludesBraces(bodyIncludesBraces) 378 , m_didParseForTheFirstTime(false) 379{ 380 RELEASE_ASSERT(!source.isNull()); 381 ASSERT(source.length()); 382 m_firstLine = firstLine; 383 m_lastLine = lastLine; 384 ASSERT(startColumn != UINT_MAX); 385 ASSERT(endColumn != UINT_MAX); 386 m_startColumn = startColumn; 387 m_endColumn = endColumn; 388} 389 390void FunctionExecutable::destroy(JSCell* cell) 391{ 392 static_cast<FunctionExecutable*>(cell)->FunctionExecutable::~FunctionExecutable(); 393} 394 395inline const char* samplingDescription(JITCode::JITType jitType) 396{ 397 switch (jitType) { 398 case JITCode::InterpreterThunk: 399 return "Interpreter Compilation (TOTAL)"; 400 case JITCode::BaselineJIT: 401 return "Baseline Compilation (TOTAL)"; 402 case JITCode::DFGJIT: 403 return "DFG Compilation (TOTAL)"; 404 case JITCode::FTLJIT: 405 return "FTL Compilation (TOTAL)"; 406 default: 407 RELEASE_ASSERT_NOT_REACHED(); 408 return 0; 409 } 410} 411 412void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) 413{ 414 EvalExecutable* thisObject = jsCast<EvalExecutable*>(cell); 415 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 416 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); 417 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); 418 ScriptExecutable::visitChildren(thisObject, visitor); 419 if (thisObject->m_evalCodeBlock) 420 thisObject->m_evalCodeBlock->visitAggregate(visitor); 421 visitor.append(&thisObject->m_unlinkedEvalCodeBlock); 422} 423 424void EvalExecutable::unlinkCalls() 425{ 426#if ENABLE(JIT) 427 if (!m_jitCodeForCall) 428 return; 429 RELEASE_ASSERT(m_evalCodeBlock); 430 m_evalCodeBlock->unlinkCalls(); 431#endif 432} 433 434void EvalExecutable::clearCode() 435{ 436 m_evalCodeBlock.clear(); 437 m_unlinkedEvalCodeBlock.clear(); 438 Base::clearCode(); 439} 440 441JSObject* ProgramExecutable::checkSyntax(ExecState* exec) 442{ 443 ParserError error; 444 VM* vm = &exec->vm(); 445 JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); 446 RefPtr<ProgramNode> programNode = parse<ProgramNode>(vm, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); 447 if (programNode) 448 return 0; 449 ASSERT(error.m_type != ParserError::ErrorNone); 450 return error.toErrorObject(lexicalGlobalObject, m_source); 451} 452 453void ProgramExecutable::unlinkCalls() 454{ 455#if ENABLE(JIT) 456 if (!m_jitCodeForCall) 457 return; 458 RELEASE_ASSERT(m_programCodeBlock); 459 m_programCodeBlock->unlinkCalls(); 460#endif 461} 462 463JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope) 464{ 465 RELEASE_ASSERT(scope); 466 JSGlobalObject* globalObject = scope->globalObject(); 467 RELEASE_ASSERT(globalObject); 468 ASSERT(&globalObject->vm() == &vm); 469 470 JSObject* exception = 0; 471 UnlinkedProgramCodeBlock* unlinkedCodeBlock = globalObject->createProgramCodeBlock(callFrame, this, &exception); 472 if (exception) 473 return exception; 474 475 m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock); 476 477 BatchedTransitionOptimizer optimizer(vm, globalObject); 478 479 const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); 480 const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCodeBlock->functionDeclarations(); 481 482 for (size_t i = 0; i < functionDeclarations.size(); ++i) { 483 UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get(); 484 JSValue value = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, m_source, lineNo()), scope); 485 globalObject->addFunction(callFrame, functionDeclarations[i].first, value); 486 } 487 488 for (size_t i = 0; i < variableDeclarations.size(); ++i) { 489 if (variableDeclarations[i].second & DeclarationStacks::IsConstant) 490 globalObject->addConst(callFrame, variableDeclarations[i].first); 491 else 492 globalObject->addVar(callFrame, variableDeclarations[i].first); 493 } 494 return 0; 495} 496 497void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) 498{ 499 ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell); 500 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 501 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); 502 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); 503 ScriptExecutable::visitChildren(thisObject, visitor); 504 visitor.append(&thisObject->m_unlinkedProgramCodeBlock); 505 if (thisObject->m_programCodeBlock) 506 thisObject->m_programCodeBlock->visitAggregate(visitor); 507} 508 509void ProgramExecutable::clearCode() 510{ 511 m_programCodeBlock.clear(); 512 m_unlinkedProgramCodeBlock.clear(); 513 Base::clearCode(); 514} 515 516FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind) 517{ 518 FunctionCodeBlock* result; 519 if (kind == CodeForCall) 520 result = m_codeBlockForCall.get(); 521 else { 522 RELEASE_ASSERT(kind == CodeForConstruct); 523 result = m_codeBlockForConstruct.get(); 524 } 525 if (!result) 526 return 0; 527 return static_cast<FunctionCodeBlock*>(result->baselineAlternative()); 528} 529 530void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) 531{ 532 FunctionExecutable* thisObject = jsCast<FunctionExecutable*>(cell); 533 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 534 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); 535 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); 536 ScriptExecutable::visitChildren(thisObject, visitor); 537 if (thisObject->m_codeBlockForCall) 538 thisObject->m_codeBlockForCall->visitAggregate(visitor); 539 if (thisObject->m_codeBlockForConstruct) 540 thisObject->m_codeBlockForConstruct->visitAggregate(visitor); 541 visitor.append(&thisObject->m_unlinkedExecutable); 542} 543 544SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind) 545{ 546 return codeBlockFor(kind)->symbolTable(); 547} 548 549void FunctionExecutable::clearCodeIfNotCompiling() 550{ 551 if (isCompiling()) 552 return; 553 clearCode(); 554} 555 556void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() 557{ 558 if (isCompiling()) 559 return; 560 m_unlinkedExecutable->clearCodeForRecompilation(); 561} 562 563void FunctionExecutable::clearCode() 564{ 565 m_codeBlockForCall.clear(); 566 m_codeBlockForConstruct.clear(); 567 Base::clearCode(); 568} 569 570void FunctionExecutable::unlinkCalls() 571{ 572#if ENABLE(JIT) 573 if (!!m_jitCodeForCall) { 574 RELEASE_ASSERT(m_codeBlockForCall); 575 m_codeBlockForCall->unlinkCalls(); 576 } 577 if (!!m_jitCodeForConstruct) { 578 RELEASE_ASSERT(m_codeBlockForConstruct); 579 m_codeBlockForConstruct->unlinkCalls(); 580 } 581#endif 582} 583 584FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) 585{ 586 UnlinkedFunctionExecutable* unlinkedExecutable = UnlinkedFunctionExecutable::fromGlobalCode(name, exec, debugger, source, exception); 587 if (!unlinkedExecutable) 588 return 0; 589 unsigned lineCount = unlinkedExecutable->lineCount(); 590 unsigned firstLine = source.firstLine() + unlinkedExecutable->firstLineOffset(); 591 unsigned startOffset = source.startOffset() + unlinkedExecutable->startOffset(); 592 593 // We don't have any owner executable. The source string is effectively like a global 594 // string (like in the handling of eval). Hence, the startColumn is always 1. 595 unsigned startColumn = 1; 596 unsigned sourceLength = unlinkedExecutable->sourceLength(); 597 bool endColumnIsOnStartLine = !lineCount; 598 // The unlinkedBodyEndColumn is based-0. Hence, we need to add 1 to it. But if the 599 // endColumn is on the startLine, then we need to subtract back the adjustment for 600 // the open brace resulting in an adjustment of 0. 601 unsigned endColumnExcludingBraces = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? 0 : 1); 602 unsigned startOffsetExcludingOpenBrace = startOffset + 1; 603 unsigned endOffsetExcludingCloseBrace = startOffset + sourceLength - 1; 604 SourceCode bodySource(source.provider(), startOffsetExcludingOpenBrace, endOffsetExcludingCloseBrace, firstLine, startColumn); 605 606 return FunctionExecutable::create(exec->vm(), bodySource, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumnExcludingBraces, false); 607} 608 609String FunctionExecutable::paramString() const 610{ 611 return m_unlinkedExecutable->paramString(); 612} 613 614void ExecutableBase::dump(PrintStream& out) const 615{ 616 ExecutableBase* realThis = const_cast<ExecutableBase*>(this); 617 618 if (classInfo() == NativeExecutable::info()) { 619 NativeExecutable* native = jsCast<NativeExecutable*>(realThis); 620 out.print("NativeExecutable:", RawPointer(bitwise_cast<void*>(native->function())), "/", RawPointer(bitwise_cast<void*>(native->constructor()))); 621 return; 622 } 623 624 if (classInfo() == EvalExecutable::info()) { 625 EvalExecutable* eval = jsCast<EvalExecutable*>(realThis); 626 if (CodeBlock* codeBlock = eval->codeBlock()) 627 out.print(*codeBlock); 628 else 629 out.print("EvalExecutable w/o CodeBlock"); 630 return; 631 } 632 633 if (classInfo() == ProgramExecutable::info()) { 634 ProgramExecutable* eval = jsCast<ProgramExecutable*>(realThis); 635 if (CodeBlock* codeBlock = eval->codeBlock()) 636 out.print(*codeBlock); 637 else 638 out.print("ProgramExecutable w/o CodeBlock"); 639 return; 640 } 641 642 FunctionExecutable* function = jsCast<FunctionExecutable*>(realThis); 643 if (!function->eitherCodeBlock()) 644 out.print("FunctionExecutable w/o CodeBlock"); 645 else { 646 CommaPrinter comma("/"); 647 if (function->codeBlockForCall()) 648 out.print(comma, *function->codeBlockForCall()); 649 if (function->codeBlockForConstruct()) 650 out.print(comma, *function->codeBlockForConstruct()); 651 } 652} 653 654CodeBlockHash ExecutableBase::hashFor(CodeSpecializationKind kind) const 655{ 656 if (this->classInfo() == NativeExecutable::info()) 657 return jsCast<const NativeExecutable*>(this)->hashFor(kind); 658 659 return jsCast<const ScriptExecutable*>(this)->hashFor(kind); 660} 661 662CodeBlockHash NativeExecutable::hashFor(CodeSpecializationKind kind) const 663{ 664 if (kind == CodeForCall) 665 return CodeBlockHash(static_cast<unsigned>(bitwise_cast<size_t>(m_function))); 666 667 RELEASE_ASSERT(kind == CodeForConstruct); 668 return CodeBlockHash(static_cast<unsigned>(bitwise_cast<size_t>(m_constructor))); 669} 670 671CodeBlockHash ScriptExecutable::hashFor(CodeSpecializationKind kind) const 672{ 673 return CodeBlockHash(source(), kind); 674} 675 676} 677