ScriptExecutable.cpp
1 /* 2 * Copyright (C) 2009-2019 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 28 #include "CodeBlock.h" 29 #include "Debugger.h" 30 #include "EvalCodeBlock.h" 31 #include "FunctionCodeBlock.h" 32 #include "GlobalExecutable.h" 33 #include "IsoCellSetInlines.h" 34 #include "JIT.h" 35 #include "JSCellInlines.h" 36 #include "JSGlobalObjectInlines.h" 37 #include "JSObjectInlines.h" 38 #include "JSTemplateObjectDescriptor.h" 39 #include "LLIntEntrypoint.h" 40 #include "ModuleProgramCodeBlock.h" 41 #include "ParserError.h" 42 #include "ProgramCodeBlock.h" 43 #include "VMInlines.h" 44 45 namespace JSC { 46 47 const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ScriptExecutable) }; 48 49 ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, bool isInArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType evalContextType, Intrinsic intrinsic) 50 : ExecutableBase(vm, structure) 51 , m_source(source) 52 , m_intrinsic(intrinsic) 53 , m_features(isInStrictContext ? StrictModeFeature : 0) 54 , m_hasCapturedVariables(false) 55 , m_neverInline(false) 56 , m_neverOptimize(false) 57 , m_neverFTLOptimize(false) 58 , m_isArrowFunctionContext(isInArrowFunctionContext) 59 , m_canUseOSRExitFuzzing(true) 60 , m_codeForGeneratorBodyWasGenerated(false) 61 , m_isInsideOrdinaryFunction(isInsideOrdinaryFunction) 62 , m_derivedContextType(static_cast<unsigned>(derivedContextType)) 63 , m_evalContextType(static_cast<unsigned>(evalContextType)) 64 { 65 } 66 67 void ScriptExecutable::destroy(JSCell* cell) 68 { 69 static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable(); 70 } 71 72 void ScriptExecutable::clearCode(IsoCellSet& clearableCodeSet) 73 { 74 m_jitCodeForCall = nullptr; 75 m_jitCodeForConstruct = nullptr; 76 m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr<JSEntryPtrTag>(); 77 m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr<JSEntryPtrTag>(); 78 79 switch (type()) { 80 case FunctionExecutableType: { 81 FunctionExecutable* executable = static_cast<FunctionExecutable*>(this); 82 executable->m_codeBlockForCall.clear(); 83 executable->m_codeBlockForConstruct.clear(); 84 break; 85 } 86 case EvalExecutableType: { 87 EvalExecutable* executable = static_cast<EvalExecutable*>(this); 88 executable->m_evalCodeBlock.clear(); 89 executable->m_unlinkedEvalCodeBlock.clear(); 90 break; 91 } 92 case ProgramExecutableType: { 93 ProgramExecutable* executable = static_cast<ProgramExecutable*>(this); 94 executable->m_programCodeBlock.clear(); 95 executable->m_unlinkedProgramCodeBlock.clear(); 96 break; 97 } 98 case ModuleProgramExecutableType: { 99 ModuleProgramExecutable* executable = static_cast<ModuleProgramExecutable*>(this); 100 executable->m_moduleProgramCodeBlock.clear(); 101 executable->m_unlinkedModuleProgramCodeBlock.clear(); 102 executable->m_moduleEnvironmentSymbolTable.clear(); 103 break; 104 } 105 default: 106 RELEASE_ASSERT_NOT_REACHED(); 107 break; 108 } 109 110 ASSERT(&VM::SpaceAndSet::setFor(*subspace()) == &clearableCodeSet); 111 clearableCodeSet.remove(this); 112 } 113 114 void ScriptExecutable::installCode(CodeBlock* codeBlock) 115 { 116 installCode(codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind()); 117 } 118 119 void ScriptExecutable::installCode(VM& vm, CodeBlock* genericCodeBlock, CodeType codeType, CodeSpecializationKind kind) 120 { 121 if (genericCodeBlock) 122 CODEBLOCK_LOG_EVENT(genericCodeBlock, "installCode", ()); 123 124 CodeBlock* oldCodeBlock = nullptr; 125 126 switch (codeType) { 127 case GlobalCode: { 128 ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); 129 ProgramCodeBlock* codeBlock = static_cast<ProgramCodeBlock*>(genericCodeBlock); 130 131 ASSERT(kind == CodeForCall); 132 133 oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_programCodeBlock.get()); 134 executable->m_programCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock)); 135 break; 136 } 137 138 case ModuleCode: { 139 ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this); 140 ModuleProgramCodeBlock* codeBlock = static_cast<ModuleProgramCodeBlock*>(genericCodeBlock); 141 142 ASSERT(kind == CodeForCall); 143 144 oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_moduleProgramCodeBlock.get()); 145 executable->m_moduleProgramCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(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 = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_evalCodeBlock.get()); 156 executable->m_evalCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(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 = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForCall.get()); 167 executable->m_codeBlockForCall.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock)); 168 break; 169 case CodeForConstruct: 170 oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForConstruct.get()); 171 executable->m_codeBlockForConstruct.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock)); 172 break; 173 } 174 break; 175 } 176 } 177 178 switch (kind) { 179 case CodeForCall: 180 m_jitCodeForCall = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr; 181 m_jitCodeForCallWithArityCheck = nullptr; 182 break; 183 case CodeForConstruct: 184 m_jitCodeForConstruct = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr; 185 m_jitCodeForConstructWithArityCheck = nullptr; 186 break; 187 } 188 189 auto& clearableCodeSet = VM::SpaceAndSet::setFor(*subspace()); 190 if (hasClearableCode(vm)) 191 clearableCodeSet.add(this); 192 else 193 clearableCodeSet.remove(this); 194 195 if (genericCodeBlock) { 196 RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this); 197 RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType())); 198 199 dataLogLnIf(Options::verboseOSR(), "Installing ", *genericCodeBlock); 200 201 if (UNLIKELY(vm.m_perBytecodeProfiler)) 202 vm.m_perBytecodeProfiler->ensureBytecodesFor(genericCodeBlock); 203 204 Debugger* debugger = genericCodeBlock->globalObject()->debugger(); 205 if (UNLIKELY(debugger)) 206 debugger->registerCodeBlock(genericCodeBlock); 207 } 208 209 if (oldCodeBlock) 210 oldCodeBlock->unlinkIncomingCalls(); 211 212 vm.heap.writeBarrier(this); 213 } 214 215 bool ScriptExecutable::hasClearableCode(VM& vm) const 216 { 217 if (m_jitCodeForCall 218 || m_jitCodeForConstruct 219 || m_jitCodeForCallWithArityCheck 220 || m_jitCodeForConstructWithArityCheck) 221 return true; 222 223 if (structure(vm)->classInfo() == FunctionExecutable::info()) { 224 auto* executable = static_cast<const FunctionExecutable*>(this); 225 if (executable->m_codeBlockForCall || executable->m_codeBlockForConstruct) 226 return true; 227 228 } else if (structure(vm)->classInfo() == EvalExecutable::info()) { 229 auto* executable = static_cast<const EvalExecutable*>(this); 230 if (executable->m_evalCodeBlock || executable->m_unlinkedEvalCodeBlock) 231 return true; 232 233 } else if (structure(vm)->classInfo() == ProgramExecutable::info()) { 234 auto* executable = static_cast<const ProgramExecutable*>(this); 235 if (executable->m_programCodeBlock || executable->m_unlinkedProgramCodeBlock) 236 return true; 237 238 } else if (structure(vm)->classInfo() == ModuleProgramExecutable::info()) { 239 auto* executable = static_cast<const ModuleProgramExecutable*>(this); 240 if (executable->m_moduleProgramCodeBlock 241 || executable->m_unlinkedModuleProgramCodeBlock 242 || executable->m_moduleEnvironmentSymbolTable) 243 return true; 244 } 245 return false; 246 } 247 248 CodeBlock* ScriptExecutable::newCodeBlockFor( 249 CodeSpecializationKind kind, JSFunction* function, JSScope* scope, Exception*& exception) 250 { 251 VM& vm = scope->vm(); 252 auto throwScope = DECLARE_THROW_SCOPE(vm); 253 254 ASSERT(vm.heap.isDeferred()); 255 ASSERT(endColumn() != UINT_MAX); 256 257 JSGlobalObject* globalObject = scope->globalObject(vm); 258 259 if (classInfo(vm) == EvalExecutable::info()) { 260 EvalExecutable* executable = jsCast<EvalExecutable*>(this); 261 RELEASE_ASSERT(kind == CodeForCall); 262 RELEASE_ASSERT(!executable->m_evalCodeBlock); 263 RELEASE_ASSERT(!function); 264 auto* codeBlock = EvalCodeBlock::create(vm, 265 executable, executable->m_unlinkedEvalCodeBlock.get(), scope); 266 EXCEPTION_ASSERT(throwScope.exception() || codeBlock); 267 if (!codeBlock) { 268 exception = throwException( 269 globalObject, throwScope, 270 createOutOfMemoryError(globalObject)); 271 return nullptr; 272 } 273 return codeBlock; 274 } 275 276 if (classInfo(vm) == ProgramExecutable::info()) { 277 ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); 278 RELEASE_ASSERT(kind == CodeForCall); 279 RELEASE_ASSERT(!executable->m_programCodeBlock); 280 RELEASE_ASSERT(!function); 281 auto* codeBlock = ProgramCodeBlock::create(vm, 282 executable, executable->m_unlinkedProgramCodeBlock.get(), scope); 283 EXCEPTION_ASSERT(throwScope.exception() || codeBlock); 284 if (!codeBlock) { 285 exception = throwException( 286 globalObject, throwScope, 287 createOutOfMemoryError(globalObject)); 288 return nullptr; 289 } 290 return codeBlock; 291 } 292 293 if (classInfo(vm) == ModuleProgramExecutable::info()) { 294 ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this); 295 RELEASE_ASSERT(kind == CodeForCall); 296 RELEASE_ASSERT(!executable->m_moduleProgramCodeBlock); 297 RELEASE_ASSERT(!function); 298 auto* codeBlock = ModuleProgramCodeBlock::create(vm, 299 executable, executable->m_unlinkedModuleProgramCodeBlock.get(), scope); 300 EXCEPTION_ASSERT(throwScope.exception() || codeBlock); 301 if (!codeBlock) { 302 exception = throwException( 303 globalObject, throwScope, 304 createOutOfMemoryError(globalObject)); 305 return nullptr; 306 } 307 return codeBlock; 308 } 309 310 RELEASE_ASSERT(classInfo(vm) == FunctionExecutable::info()); 311 RELEASE_ASSERT(function); 312 FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); 313 RELEASE_ASSERT(!executable->codeBlockFor(kind)); 314 ParserError error; 315 OptionSet<CodeGenerationMode> codeGenerationMode = globalObject->defaultCodeGenerationMode(); 316 // We continue using the same CodeGenerationMode for Generators because live generator objects can 317 // keep the state which is only valid with the CodeBlock compiled with the same CodeGenerationMode. 318 if (isGeneratorOrAsyncFunctionBodyParseMode(executable->parseMode())) { 319 if (!m_codeForGeneratorBodyWasGenerated) { 320 m_codeGenerationModeForGeneratorBody = codeGenerationMode; 321 m_codeForGeneratorBodyWasGenerated = true; 322 } else 323 codeGenerationMode = m_codeGenerationModeForGeneratorBody; 324 } 325 UnlinkedFunctionCodeBlock* unlinkedCodeBlock = 326 executable->m_unlinkedExecutable->unlinkedCodeBlockFor( 327 vm, executable->source(), kind, codeGenerationMode, error, 328 executable->parseMode()); 329 recordParse( 330 executable->m_unlinkedExecutable->features(), 331 executable->m_unlinkedExecutable->hasCapturedVariables(), 332 lastLine(), endColumn()); 333 if (!unlinkedCodeBlock) { 334 exception = throwException( 335 globalObject, throwScope, 336 error.toErrorObject(globalObject, executable->source())); 337 return nullptr; 338 } 339 340 auto* codeBlock = FunctionCodeBlock::create(vm, executable, unlinkedCodeBlock, scope); 341 if (throwScope.exception()) 342 exception = throwScope.exception(); 343 return codeBlock; 344 } 345 346 CodeBlock* ScriptExecutable::newReplacementCodeBlockFor( 347 CodeSpecializationKind kind) 348 { 349 VM& vm = this->vm(); 350 if (classInfo(vm) == EvalExecutable::info()) { 351 RELEASE_ASSERT(kind == CodeForCall); 352 EvalExecutable* executable = jsCast<EvalExecutable*>(this); 353 EvalCodeBlock* baseline = static_cast<EvalCodeBlock*>( 354 executable->codeBlock()->baselineVersion()); 355 EvalCodeBlock* result = EvalCodeBlock::create(vm, 356 CodeBlock::CopyParsedBlock, *baseline); 357 result->setAlternative(vm, baseline); 358 return result; 359 } 360 361 if (classInfo(vm) == ProgramExecutable::info()) { 362 RELEASE_ASSERT(kind == CodeForCall); 363 ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); 364 ProgramCodeBlock* baseline = static_cast<ProgramCodeBlock*>( 365 executable->codeBlock()->baselineVersion()); 366 ProgramCodeBlock* result = ProgramCodeBlock::create(vm, 367 CodeBlock::CopyParsedBlock, *baseline); 368 result->setAlternative(vm, baseline); 369 return result; 370 } 371 372 if (classInfo(vm) == ModuleProgramExecutable::info()) { 373 RELEASE_ASSERT(kind == CodeForCall); 374 ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this); 375 ModuleProgramCodeBlock* baseline = static_cast<ModuleProgramCodeBlock*>( 376 executable->codeBlock()->baselineVersion()); 377 ModuleProgramCodeBlock* result = ModuleProgramCodeBlock::create(vm, 378 CodeBlock::CopyParsedBlock, *baseline); 379 result->setAlternative(vm, baseline); 380 return result; 381 } 382 383 RELEASE_ASSERT(classInfo(vm) == FunctionExecutable::info()); 384 FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); 385 FunctionCodeBlock* baseline = static_cast<FunctionCodeBlock*>( 386 executable->codeBlockFor(kind)->baselineVersion()); 387 FunctionCodeBlock* result = FunctionCodeBlock::create(vm, 388 CodeBlock::CopyParsedBlock, *baseline); 389 result->setAlternative(vm, baseline); 390 return result; 391 } 392 393 static void setupLLInt(CodeBlock* codeBlock) 394 { 395 LLInt::setEntrypoint(codeBlock); 396 } 397 398 static void setupJIT(VM& vm, CodeBlock* codeBlock) 399 { 400 #if ENABLE(JIT) 401 CompilationResult result = JIT::compile(vm, codeBlock, JITCompilationMustSucceed); 402 RELEASE_ASSERT(result == CompilationSuccessful); 403 #else 404 UNUSED_PARAM(vm); 405 UNUSED_PARAM(codeBlock); 406 UNREACHABLE_FOR_PLATFORM(); 407 #endif 408 } 409 410 Exception* ScriptExecutable::prepareForExecutionImpl( 411 VM& vm, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock) 412 { 413 auto throwScope = DECLARE_THROW_SCOPE(vm); 414 DeferGCForAWhile deferGC(vm.heap); 415 416 if (UNLIKELY(vm.getAndClearFailNextNewCodeBlock())) { 417 JSGlobalObject* globalObject = scope->globalObject(vm); 418 return throwException(globalObject, throwScope, createError(globalObject, "Forced Failure"_s)); 419 } 420 421 Exception* exception = nullptr; 422 CodeBlock* codeBlock = newCodeBlockFor(kind, function, scope, exception); 423 resultCodeBlock = codeBlock; 424 EXCEPTION_ASSERT(!!throwScope.exception() == !codeBlock); 425 if (UNLIKELY(!codeBlock)) 426 return exception; 427 428 if (Options::validateBytecode()) 429 codeBlock->validate(); 430 431 if (Options::useLLInt()) 432 setupLLInt(codeBlock); 433 else 434 setupJIT(vm, codeBlock); 435 436 installCode(vm, codeBlock, codeBlock->codeType(), codeBlock->specializationKind()); 437 return nullptr; 438 } 439 440 ScriptExecutable* ScriptExecutable::topLevelExecutable() 441 { 442 switch (type()) { 443 case FunctionExecutableType: 444 return jsCast<FunctionExecutable*>(this)->topLevelExecutable(); 445 default: 446 return this; 447 } 448 } 449 450 JSArray* ScriptExecutable::createTemplateObject(JSGlobalObject* globalObject, JSTemplateObjectDescriptor* descriptor) 451 { 452 VM& vm = globalObject->vm(); 453 auto scope = DECLARE_THROW_SCOPE(vm); 454 455 TemplateObjectMap& templateObjectMap = ensureTemplateObjectMap(vm); 456 TemplateObjectMap::AddResult result; 457 { 458 auto locker = holdLock(cellLock()); 459 result = templateObjectMap.add(descriptor->endOffset(), WriteBarrier<JSArray>()); 460 } 461 if (JSArray* array = result.iterator->value.get()) 462 return array; 463 JSArray* templateObject = descriptor->createTemplateObject(globalObject); 464 RETURN_IF_EXCEPTION(scope, nullptr); 465 result.iterator->value.set(vm, this, templateObject); 466 return templateObject; 467 } 468 469 auto ScriptExecutable::ensureTemplateObjectMapImpl(std::unique_ptr<TemplateObjectMap>& dest) -> TemplateObjectMap& 470 { 471 if (dest) 472 return *dest; 473 auto result = makeUnique<TemplateObjectMap>(); 474 WTF::storeStoreFence(); 475 dest = WTFMove(result); 476 return *dest; 477 } 478 479 auto ScriptExecutable::ensureTemplateObjectMap(VM& vm) -> TemplateObjectMap& 480 { 481 switch (type()) { 482 case FunctionExecutableType: 483 return static_cast<FunctionExecutable*>(this)->ensureTemplateObjectMap(vm); 484 case EvalExecutableType: 485 return static_cast<EvalExecutable*>(this)->ensureTemplateObjectMap(vm); 486 case ProgramExecutableType: 487 return static_cast<ProgramExecutable*>(this)->ensureTemplateObjectMap(vm); 488 case ModuleProgramExecutableType: 489 default: 490 ASSERT(type() == ModuleProgramExecutableType); 491 return static_cast<ModuleProgramExecutable*>(this)->ensureTemplateObjectMap(vm); 492 } 493 } 494 495 CodeBlockHash ScriptExecutable::hashFor(CodeSpecializationKind kind) const 496 { 497 return CodeBlockHash(source(), kind); 498 } 499 500 Optional<int> ScriptExecutable::overrideLineNumber(VM& vm) const 501 { 502 if (inherits<FunctionExecutable>(vm)) 503 return jsCast<const FunctionExecutable*>(this)->overrideLineNumber(); 504 return WTF::nullopt; 505 } 506 507 unsigned ScriptExecutable::typeProfilingStartOffset(VM& vm) const 508 { 509 if (inherits<FunctionExecutable>(vm)) 510 return jsCast<const FunctionExecutable*>(this)->typeProfilingStartOffset(vm); 511 if (inherits<EvalExecutable>(vm)) 512 return UINT_MAX; 513 return 0; 514 } 515 516 unsigned ScriptExecutable::typeProfilingEndOffset(VM& vm) const 517 { 518 if (inherits<FunctionExecutable>(vm)) 519 return jsCast<const FunctionExecutable*>(this)->typeProfilingEndOffset(vm); 520 if (inherits<EvalExecutable>(vm)) 521 return UINT_MAX; 522 return source().length() - 1; 523 } 524 525 void ScriptExecutable::recordParse(CodeFeatures features, bool hasCapturedVariables, int lastLine, unsigned endColumn) 526 { 527 switch (type()) { 528 case FunctionExecutableType: 529 // Since UnlinkedFunctionExecutable holds the information to calculate lastLine and endColumn, we do not need to remember them in ScriptExecutable's fields. 530 jsCast<FunctionExecutable*>(this)->recordParse(features, hasCapturedVariables); 531 return; 532 default: 533 jsCast<GlobalExecutable*>(this)->recordParse(features, hasCapturedVariables, lastLine, endColumn); 534 return; 535 } 536 } 537 538 int ScriptExecutable::lastLine() const 539 { 540 switch (type()) { 541 case FunctionExecutableType: 542 return jsCast<const FunctionExecutable*>(this)->lastLine(); 543 default: 544 return jsCast<const GlobalExecutable*>(this)->lastLine(); 545 } 546 return 0; 547 } 548 549 unsigned ScriptExecutable::endColumn() const 550 { 551 switch (type()) { 552 case FunctionExecutableType: 553 return jsCast<const FunctionExecutable*>(this)->endColumn(); 554 default: 555 return jsCast<const GlobalExecutable*>(this)->endColumn(); 556 } 557 return 0; 558 } 559 560 } // namespace JSC