/ interpreter / CallFrame.cpp
CallFrame.cpp
  1  /*
  2   * Copyright (C) 2008-2018 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 "CallFrame.h"
 28  
 29  #include "CodeBlock.h"
 30  #include "ExecutableAllocator.h"
 31  #include "InlineCallFrame.h"
 32  #include "JSCInlines.h"
 33  #include "JSWebAssemblyInstance.h"
 34  #include "LLIntPCRanges.h"
 35  #include "VMEntryRecord.h"
 36  #include "WasmContextInlines.h"
 37  #include "WasmInstance.h"
 38  #include <wtf/StringPrintStream.h>
 39  
 40  namespace JSC {
 41  
 42  void CallFrame::initDeprecatedCallFrameForDebugger(CallFrame* globalExec, JSCallee* globalCallee)
 43  {
 44      globalExec->setCodeBlock(nullptr);
 45      globalExec->setCallerFrame(noCaller());
 46      globalExec->setReturnPC(nullptr);
 47      globalExec->setArgumentCountIncludingThis(0);
 48      globalExec->setCallee(globalCallee);
 49      ASSERT(globalExec->isDeprecatedCallFrameForDebugger());
 50  }
 51  
 52  bool CallFrame::callSiteBitsAreBytecodeOffset() const
 53  {
 54      ASSERT(codeBlock());
 55      switch (codeBlock()->jitType()) {
 56      case JITType::InterpreterThunk:
 57      case JITType::BaselineJIT:
 58          return true;
 59      case JITType::None:
 60      case JITType::HostCallThunk:
 61          RELEASE_ASSERT_NOT_REACHED();
 62          return false;
 63      default:
 64          return false;
 65      }
 66  
 67      RELEASE_ASSERT_NOT_REACHED();
 68      return false;
 69  }
 70  
 71  bool CallFrame::callSiteBitsAreCodeOriginIndex() const
 72  {
 73      ASSERT(codeBlock());
 74      switch (codeBlock()->jitType()) {
 75      case JITType::DFGJIT:
 76      case JITType::FTLJIT:
 77          return true;
 78      case JITType::None:
 79      case JITType::HostCallThunk:
 80          RELEASE_ASSERT_NOT_REACHED();
 81          return false;
 82      default:
 83          return false;
 84      }
 85  
 86      RELEASE_ASSERT_NOT_REACHED();
 87      return false;
 88  }
 89  
 90  unsigned CallFrame::callSiteAsRawBits() const
 91  {
 92      return this[static_cast<int>(CallFrameSlot::argumentCountIncludingThis)].tag();
 93  }
 94  
 95  SUPPRESS_ASAN unsigned CallFrame::unsafeCallSiteAsRawBits() const
 96  {
 97      return this[static_cast<int>(CallFrameSlot::argumentCountIncludingThis)].unsafeTag();
 98  }
 99  
100  CallSiteIndex CallFrame::callSiteIndex() const
101  {
102      return CallSiteIndex::fromBits(callSiteAsRawBits());
103  }
104  
105  SUPPRESS_ASAN CallSiteIndex CallFrame::unsafeCallSiteIndex() const
106  {
107      return CallSiteIndex::fromBits(unsafeCallSiteAsRawBits());
108  }
109  
110  const Instruction* CallFrame::currentVPC() const
111  {
112      ASSERT(callSiteBitsAreBytecodeOffset());
113      return codeBlock()->instructions().at(callSiteBitsAsBytecodeOffset()).ptr();
114  }
115  
116  void CallFrame::setCurrentVPC(const Instruction* vpc)
117  {
118      CallSiteIndex callSite(codeBlock()->bytecodeIndex(vpc));
119      this[static_cast<int>(CallFrameSlot::argumentCountIncludingThis)].tag() = callSite.bits();
120      ASSERT(currentVPC() == vpc);
121  }
122  
123  unsigned CallFrame::callSiteBitsAsBytecodeOffset() const
124  {
125      ASSERT(codeBlock());
126      ASSERT(callSiteBitsAreBytecodeOffset());
127      return callSiteIndex().bits();
128  }
129  
130  BytecodeIndex CallFrame::bytecodeIndex() const
131  {
132      ASSERT(!callee().isWasm());
133      if (!codeBlock())
134          return BytecodeIndex(0);
135  #if ENABLE(DFG_JIT)
136      if (callSiteBitsAreCodeOriginIndex()) {
137          ASSERT(codeBlock());
138          CodeOrigin codeOrigin = this->codeOrigin();
139          for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame(); inlineCallFrame;) {
140              codeOrigin = inlineCallFrame->directCaller;
141              inlineCallFrame = codeOrigin.inlineCallFrame();
142          }
143          return codeOrigin.bytecodeIndex();
144      }
145  #endif
146      ASSERT(callSiteBitsAreBytecodeOffset());
147      return callSiteIndex().bytecodeIndex();
148  }
149  
150  CodeOrigin CallFrame::codeOrigin() const
151  {
152      if (!codeBlock())
153          return CodeOrigin(BytecodeIndex(0));
154  #if ENABLE(DFG_JIT)
155      if (callSiteBitsAreCodeOriginIndex()) {
156          CallSiteIndex index = callSiteIndex();
157          ASSERT(codeBlock()->canGetCodeOrigin(index));
158          return codeBlock()->codeOrigin(index);
159      }
160  #endif
161      return CodeOrigin(callSiteIndex().bytecodeIndex());
162  }
163  
164  Register* CallFrame::topOfFrameInternal()
165  {
166      CodeBlock* codeBlock = this->codeBlock();
167      ASSERT(codeBlock);
168      return registers() + codeBlock->stackPointerOffset();
169  }
170  
171  bool CallFrame::isAnyWasmCallee()
172  {
173      CalleeBits callee = this->callee();
174      if (callee.isWasm())
175          return true;
176  
177      ASSERT(callee.isCell());
178      if (!!callee.rawPtr() && isWebAssemblyModule(callee.asCell()))
179          return true;
180  
181      return false;
182  }
183  
184  CallFrame* CallFrame::callerFrame(EntryFrame*& currEntryFrame) const
185  {
186      if (callerFrameOrEntryFrame() == currEntryFrame) {
187          VMEntryRecord* currVMEntryRecord = vmEntryRecord(currEntryFrame);
188          currEntryFrame = currVMEntryRecord->prevTopEntryFrame();
189          return currVMEntryRecord->prevTopCallFrame();
190      }
191      return static_cast<CallFrame*>(callerFrameOrEntryFrame());
192  }
193  
194  SUPPRESS_ASAN CallFrame* CallFrame::unsafeCallerFrame(EntryFrame*& currEntryFrame) const
195  {
196      if (unsafeCallerFrameOrEntryFrame() == currEntryFrame) {
197          VMEntryRecord* currVMEntryRecord = vmEntryRecord(currEntryFrame);
198          currEntryFrame = currVMEntryRecord->unsafePrevTopEntryFrame();
199          return currVMEntryRecord->unsafePrevTopCallFrame();
200      }
201      return static_cast<CallFrame*>(unsafeCallerFrameOrEntryFrame());
202  }
203  
204  SourceOrigin CallFrame::callerSourceOrigin(VM& vm)
205  {
206      RELEASE_ASSERT(callee().isCell());
207      SourceOrigin sourceOrigin;
208      bool haveSkippedFirstFrame = false;
209      StackVisitor::visit(this, vm, [&](StackVisitor& visitor) {
210          if (!std::exchange(haveSkippedFirstFrame, true))
211              return StackVisitor::Status::Continue;
212  
213          switch (visitor->codeType()) {
214          case StackVisitor::Frame::CodeType::Function:
215              // Skip the builtin functions since they should not pass the source origin to the dynamic code generation calls.
216              // Consider the following code.
217              //
218              // [ "42 + 44" ].forEach(eval);
219              //
220              // In the above case, the eval function will be interpreted as the indirect call to eval inside forEach function.
221              // At that time, the generated eval code should have the source origin to the original caller of the forEach function
222              // instead of the source origin of the forEach function.
223              if (static_cast<FunctionExecutable*>(visitor->codeBlock()->ownerExecutable())->isBuiltinFunction())
224                  return StackVisitor::Status::Continue;
225              FALLTHROUGH;
226  
227          case StackVisitor::Frame::CodeType::Eval:
228          case StackVisitor::Frame::CodeType::Module:
229          case StackVisitor::Frame::CodeType::Global:
230              sourceOrigin = visitor->codeBlock()->ownerExecutable()->sourceOrigin();
231              return StackVisitor::Status::Done;
232  
233          case StackVisitor::Frame::CodeType::Native:
234              return StackVisitor::Status::Continue;
235  
236          case StackVisitor::Frame::CodeType::Wasm:
237              // FIXME: Should return the source origin for WASM.
238              return StackVisitor::Status::Done;
239          }
240  
241          RELEASE_ASSERT_NOT_REACHED();
242          return StackVisitor::Status::Done;
243      });
244      return sourceOrigin;
245  }
246  
247  String CallFrame::friendlyFunctionName()
248  {
249      CodeBlock* codeBlock = this->codeBlock();
250      if (!codeBlock)
251          return emptyString();
252  
253      switch (codeBlock->codeType()) {
254      case EvalCode:
255          return "eval code"_s;
256      case ModuleCode:
257          return "module code"_s;
258      case GlobalCode:
259          return "global code"_s;
260      case FunctionCode:
261          if (jsCallee())
262              return getCalculatedDisplayName(codeBlock->vm(), jsCallee());
263          return emptyString();
264      }
265  
266      ASSERT_NOT_REACHED();
267      return emptyString();
268  }
269  
270  void CallFrame::dump(PrintStream& out) const
271  {
272      if (CodeBlock* codeBlock = this->codeBlock()) {
273          out.print(codeBlock->inferredName(), "#", codeBlock->hashAsStringIfPossible(), " [", codeBlock->jitType(), " ", bytecodeIndex(), "]");
274  
275          out.print("(");
276          thisValue().dumpForBacktrace(out);
277  
278          for (size_t i = 0; i < argumentCount(); ++i) {
279              out.print(", ");
280              JSValue value = argument(i);
281              value.dumpForBacktrace(out);
282          }
283  
284          out.print(")");
285  
286          return;
287      }
288  
289      out.print(returnPC());
290  }
291  
292  const char* CallFrame::describeFrame()
293  {
294      constexpr size_t bufferSize = 200;
295      static char* buffer = nullptr;
296      static std::once_flag onceKey;
297      std::call_once(onceKey, [&] {
298          buffer = static_cast<char*>(fastZeroedMalloc(bufferSize + 1));
299      });
300  
301      WTF::StringPrintStream stringStream;
302  
303      dump(stringStream);
304  
305      strncpy(buffer, stringStream.toCString().data(), bufferSize);
306      buffer[bufferSize] = '\0';
307  
308      return buffer;
309  }
310  
311  void CallFrame::convertToStackOverflowFrame(VM& vm, CodeBlock* codeBlockToKeepAliveUntilFrameIsUnwound)
312  {
313      ASSERT(!isDeprecatedCallFrameForDebugger());
314      ASSERT(codeBlockToKeepAliveUntilFrameIsUnwound->inherits<CodeBlock>(vm));
315  
316      EntryFrame* entryFrame = vm.topEntryFrame;
317      CallFrame* throwOriginFrame = this;
318      do {
319          throwOriginFrame = throwOriginFrame->callerFrame(entryFrame);
320      } while (throwOriginFrame && throwOriginFrame->callee().isWasm());
321  
322      JSObject* originCallee = throwOriginFrame ? throwOriginFrame->jsCallee() : vmEntryRecord(vm.topEntryFrame)->callee();
323      JSObject* stackOverflowCallee = originCallee->globalObject()->stackOverflowFrameCallee();
324  
325      setCodeBlock(codeBlockToKeepAliveUntilFrameIsUnwound);
326      setCallee(stackOverflowCallee);
327      setArgumentCountIncludingThis(0);
328  }
329  
330  #if ENABLE(WEBASSEMBLY)
331  JSGlobalObject* CallFrame::lexicalGlobalObjectFromWasmCallee(VM& vm) const
332  {
333      return vm.wasmContext.load()->owner<JSWebAssemblyInstance>()->globalObject();
334  }
335  #endif
336  
337  bool isFromJSCode(void* returnAddress)
338  {
339      UNUSED_PARAM(returnAddress);
340  #if ENABLE(JIT)
341      if (isJITPC(returnAddress))
342          return true;
343  #endif
344  #if ENABLE(C_LOOP)
345      return true;
346  #else
347      return LLInt::isLLIntPC(returnAddress);
348  #endif
349  }
350  
351  } // namespace JSC