/ runtime / ScriptExecutable.cpp
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