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