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 ExecState* exec = globalObject->globalExec();
260
261 if (classInfo(*vm) == EvalExecutable::info()) {
262 EvalExecutable* executable = jsCast<EvalExecutable*>(this);
263 RELEASE_ASSERT(kind == CodeForCall);
264 RELEASE_ASSERT(!executable->m_evalCodeBlock);
265 RELEASE_ASSERT(!function);
266 auto codeBlock = EvalCodeBlock::create(vm,
267 executable, executable->m_unlinkedEvalCodeBlock.get(), scope);
268 EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
269 if (!codeBlock) {
270 exception = throwException(
271 exec, throwScope,
272 createOutOfMemoryError(exec));
273 return nullptr;
274 }
275 return codeBlock;
276 }
277
278 if (classInfo(*vm) == ProgramExecutable::info()) {
279 ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
280 RELEASE_ASSERT(kind == CodeForCall);
281 RELEASE_ASSERT(!executable->m_programCodeBlock);
282 RELEASE_ASSERT(!function);
283 auto codeBlock = ProgramCodeBlock::create(vm,
284 executable, executable->m_unlinkedProgramCodeBlock.get(), scope);
285 EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
286 if (!codeBlock) {
287 exception = throwException(
288 exec, throwScope,
289 createOutOfMemoryError(exec));
290 return nullptr;
291 }
292 return codeBlock;
293 }
294
295 if (classInfo(*vm) == ModuleProgramExecutable::info()) {
296 ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
297 RELEASE_ASSERT(kind == CodeForCall);
298 RELEASE_ASSERT(!executable->m_moduleProgramCodeBlock);
299 RELEASE_ASSERT(!function);
300 auto codeBlock = ModuleProgramCodeBlock::create(vm,
301 executable, executable->m_unlinkedModuleProgramCodeBlock.get(), scope);
302 EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
303 if (!codeBlock) {
304 exception = throwException(
305 exec, throwScope,
306 createOutOfMemoryError(exec));
307 return nullptr;
308 }
309 return codeBlock;
310 }
311
312 RELEASE_ASSERT(classInfo(*vm) == FunctionExecutable::info());
313 RELEASE_ASSERT(function);
314 FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
315 RELEASE_ASSERT(!executable->codeBlockFor(kind));
316 ParserError error;
317 OptionSet<CodeGenerationMode> codeGenerationMode = globalObject->defaultCodeGenerationMode();
318 // We continue using the same CodeGenerationMode for Generators because live generator objects can
319 // keep the state which is only valid with the CodeBlock compiled with the same CodeGenerationMode.
320 if (isGeneratorOrAsyncFunctionBodyParseMode(executable->parseMode())) {
321 if (!m_codeForGeneratorBodyWasGenerated) {
322 m_codeGenerationModeForGeneratorBody = codeGenerationMode;
323 m_codeForGeneratorBodyWasGenerated = true;
324 } else
325 codeGenerationMode = m_codeGenerationModeForGeneratorBody;
326 }
327 UnlinkedFunctionCodeBlock* unlinkedCodeBlock =
328 executable->m_unlinkedExecutable->unlinkedCodeBlockFor(
329 *vm, executable->source(), kind, codeGenerationMode, error,
330 executable->parseMode());
331 recordParse(
332 executable->m_unlinkedExecutable->features(),
333 executable->m_unlinkedExecutable->hasCapturedVariables(),
334 lastLine(), endColumn());
335 if (!unlinkedCodeBlock) {
336 exception = throwException(
337 globalObject->globalExec(), throwScope,
338 error.toErrorObject(globalObject, executable->source()));
339 return nullptr;
340 }
341
342 RELEASE_AND_RETURN(throwScope, FunctionCodeBlock::create(vm, executable, unlinkedCodeBlock, scope));
343}
344
345CodeBlock* ScriptExecutable::newReplacementCodeBlockFor(
346 CodeSpecializationKind kind)
347{
348 VM& vm = *this->vm();
349 if (classInfo(vm) == EvalExecutable::info()) {
350 RELEASE_ASSERT(kind == CodeForCall);
351 EvalExecutable* executable = jsCast<EvalExecutable*>(this);
352 EvalCodeBlock* baseline = static_cast<EvalCodeBlock*>(
353 executable->codeBlock()->baselineVersion());
354 EvalCodeBlock* result = EvalCodeBlock::create(&vm,
355 CodeBlock::CopyParsedBlock, *baseline);
356 result->setAlternative(vm, baseline);
357 return result;
358 }
359
360 if (classInfo(vm) == ProgramExecutable::info()) {
361 RELEASE_ASSERT(kind == CodeForCall);
362 ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
363 ProgramCodeBlock* baseline = static_cast<ProgramCodeBlock*>(
364 executable->codeBlock()->baselineVersion());
365 ProgramCodeBlock* result = ProgramCodeBlock::create(&vm,
366 CodeBlock::CopyParsedBlock, *baseline);
367 result->setAlternative(vm, baseline);
368 return result;
369 }
370
371 if (classInfo(vm) == ModuleProgramExecutable::info()) {
372 RELEASE_ASSERT(kind == CodeForCall);
373 ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
374 ModuleProgramCodeBlock* baseline = static_cast<ModuleProgramCodeBlock*>(
375 executable->codeBlock()->baselineVersion());
376 ModuleProgramCodeBlock* result = ModuleProgramCodeBlock::create(&vm,
377 CodeBlock::CopyParsedBlock, *baseline);
378 result->setAlternative(vm, baseline);
379 return result;
380 }
381
382 RELEASE_ASSERT(classInfo(vm) == FunctionExecutable::info());
383 FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
384 FunctionCodeBlock* baseline = static_cast<FunctionCodeBlock*>(
385 executable->codeBlockFor(kind)->baselineVersion());
386 FunctionCodeBlock* result = FunctionCodeBlock::create(&vm,
387 CodeBlock::CopyParsedBlock, *baseline);
388 result->setAlternative(vm, baseline);
389 return result;
390}
391
392static void setupLLInt(CodeBlock* codeBlock)
393{
394 LLInt::setEntrypoint(codeBlock);
395}
396
397static void setupJIT(VM& vm, CodeBlock* codeBlock)
398{
399#if ENABLE(JIT)
400 CompilationResult result = JIT::compile(&vm, codeBlock, JITCompilationMustSucceed);
401 RELEASE_ASSERT(result == CompilationSuccessful);
402#else
403 UNUSED_PARAM(vm);
404 UNUSED_PARAM(codeBlock);
405 UNREACHABLE_FOR_PLATFORM();
406#endif
407}
408
409Exception* ScriptExecutable::prepareForExecutionImpl(
410 VM& vm, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock)
411{
412 auto throwScope = DECLARE_THROW_SCOPE(vm);
413 DeferGCForAWhile deferGC(vm.heap);
414
415 if (UNLIKELY(vm.getAndClearFailNextNewCodeBlock())) {
416 auto& state = *scope->globalObject(vm)->globalExec();
417 return throwException(&state, throwScope, createError(&state, "Forced Failure"_s));
418 }
419
420 Exception* exception = nullptr;
421 CodeBlock* codeBlock = newCodeBlockFor(kind, function, scope, exception);
422 resultCodeBlock = codeBlock;
423 EXCEPTION_ASSERT(!!throwScope.exception() == !codeBlock);
424 if (UNLIKELY(!codeBlock))
425 return exception;
426
427 if (Options::validateBytecode())
428 codeBlock->validate();
429
430 if (Options::useLLInt())
431 setupLLInt(codeBlock);
432 else
433 setupJIT(vm, codeBlock);
434
435 installCode(vm, codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
436 return nullptr;
437}
438
439ScriptExecutable* ScriptExecutable::topLevelExecutable()
440{
441 switch (type()) {
442 case FunctionExecutableType:
443 return jsCast<FunctionExecutable*>(this)->topLevelExecutable();
444 default:
445 return this;
446 }
447}
448
449JSArray* ScriptExecutable::createTemplateObject(ExecState* exec, JSTemplateObjectDescriptor* descriptor)
450{
451 VM& vm = exec->vm();
452 auto scope = DECLARE_THROW_SCOPE(vm);
453
454 TemplateObjectMap& templateObjectMap = ensureTemplateObjectMap(vm);
455 TemplateObjectMap::AddResult result;
456 {
457 auto locker = holdLock(cellLock());
458 result = templateObjectMap.add(descriptor->endOffset(), WriteBarrier<JSArray>());
459 }
460 if (JSArray* array = result.iterator->value.get())
461 return array;
462 JSArray* templateObject = descriptor->createTemplateObject(exec);
463 RETURN_IF_EXCEPTION(scope, nullptr);
464 result.iterator->value.set(vm, this, templateObject);
465 return templateObject;
466}
467
468auto ScriptExecutable::ensureTemplateObjectMapImpl(std::unique_ptr<TemplateObjectMap>& dest) -> TemplateObjectMap&
469{
470 if (dest)
471 return *dest;
472 auto result = std::make_unique<TemplateObjectMap>();
473 WTF::storeStoreFence();
474 dest = WTFMove(result);
475 return *dest;
476}
477
478auto ScriptExecutable::ensureTemplateObjectMap(VM& vm) -> TemplateObjectMap&
479{
480 switch (type()) {
481 case FunctionExecutableType:
482 return static_cast<FunctionExecutable*>(this)->ensureTemplateObjectMap(vm);
483 case EvalExecutableType:
484 return static_cast<EvalExecutable*>(this)->ensureTemplateObjectMap(vm);
485 case ProgramExecutableType:
486 return static_cast<ProgramExecutable*>(this)->ensureTemplateObjectMap(vm);
487 case ModuleProgramExecutableType:
488 default:
489 ASSERT(type() == ModuleProgramExecutableType);
490 return static_cast<ModuleProgramExecutable*>(this)->ensureTemplateObjectMap(vm);
491 }
492}
493
494CodeBlockHash ScriptExecutable::hashFor(CodeSpecializationKind kind) const
495{
496 return CodeBlockHash(source(), kind);
497}
498
499Optional<int> ScriptExecutable::overrideLineNumber(VM& vm) const
500{
501 if (inherits<FunctionExecutable>(vm))
502 return jsCast<const FunctionExecutable*>(this)->overrideLineNumber();
503 return WTF::nullopt;
504}
505
506unsigned ScriptExecutable::typeProfilingStartOffset(VM& vm) const
507{
508 if (inherits<FunctionExecutable>(vm))
509 return jsCast<const FunctionExecutable*>(this)->typeProfilingStartOffset(vm);
510 if (inherits<EvalExecutable>(vm))
511 return UINT_MAX;
512 return 0;
513}
514
515unsigned ScriptExecutable::typeProfilingEndOffset(VM& vm) const
516{
517 if (inherits<FunctionExecutable>(vm))
518 return jsCast<const FunctionExecutable*>(this)->typeProfilingEndOffset(vm);
519 if (inherits<EvalExecutable>(vm))
520 return UINT_MAX;
521 return source().length() - 1;
522}
523
524void ScriptExecutable::recordParse(CodeFeatures features, bool hasCapturedVariables, int lastLine, unsigned endColumn)
525{
526 switch (type()) {
527 case FunctionExecutableType:
528 // Since UnlinkedFunctionExecutable holds the information to calculate lastLine and endColumn, we do not need to remember them in ScriptExecutable's fields.
529 jsCast<FunctionExecutable*>(this)->recordParse(features, hasCapturedVariables);
530 return;
531 default:
532 jsCast<GlobalExecutable*>(this)->recordParse(features, hasCapturedVariables, lastLine, endColumn);
533 return;
534 }
535}
536
537int ScriptExecutable::lastLine() const
538{
539 switch (type()) {
540 case FunctionExecutableType:
541 return jsCast<const FunctionExecutable*>(this)->lastLine();
542 default:
543 return jsCast<const GlobalExecutable*>(this)->lastLine();
544 }
545 return 0;
546}
547
548unsigned ScriptExecutable::endColumn() const
549{
550 switch (type()) {
551 case FunctionExecutableType:
552 return jsCast<const FunctionExecutable*>(this)->endColumn();
553 default:
554 return jsCast<const GlobalExecutable*>(this)->endColumn();
555 }
556 return 0;
557}
558
559} // namespace JSC
560