summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/interpreter
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2015-10-15 09:45:50 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2015-10-15 09:45:50 +0000
commite15dd966d523731101f70ccf768bba12435a0208 (patch)
treeae9cb828a24ded2585a41af3f21411523b47897d /Source/JavaScriptCore/interpreter
downloadWebKitGtk-tarball-e15dd966d523731101f70ccf768bba12435a0208.tar.gz
webkitgtk-2.10.2webkitgtk-2.10.2
Diffstat (limited to 'Source/JavaScriptCore/interpreter')
-rw-r--r--Source/JavaScriptCore/interpreter/AbstractPC.cpp51
-rw-r--r--Source/JavaScriptCore/interpreter/AbstractPC.h75
-rw-r--r--Source/JavaScriptCore/interpreter/CachedCall.h73
-rw-r--r--Source/JavaScriptCore/interpreter/CallFrame.cpp208
-rw-r--r--Source/JavaScriptCore/interpreter/CallFrame.h320
-rw-r--r--Source/JavaScriptCore/interpreter/CallFrameClosure.h56
-rw-r--r--Source/JavaScriptCore/interpreter/CallFrameInlines.h158
-rw-r--r--Source/JavaScriptCore/interpreter/Interpreter.cpp1248
-rw-r--r--Source/JavaScriptCore/interpreter/Interpreter.h285
-rw-r--r--Source/JavaScriptCore/interpreter/JSStack.cpp183
-rw-r--r--Source/JavaScriptCore/interpreter/JSStack.h154
-rw-r--r--Source/JavaScriptCore/interpreter/JSStackInlines.h94
-rw-r--r--Source/JavaScriptCore/interpreter/ProtoCallFrame.cpp53
-rw-r--r--Source/JavaScriptCore/interpreter/ProtoCallFrame.h76
-rw-r--r--Source/JavaScriptCore/interpreter/Register.h221
-rw-r--r--Source/JavaScriptCore/interpreter/StackVisitor.cpp418
-rw-r--r--Source/JavaScriptCore/interpreter/StackVisitor.h177
-rw-r--r--Source/JavaScriptCore/interpreter/VMEntryRecord.h54
18 files changed, 3904 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/interpreter/AbstractPC.cpp b/Source/JavaScriptCore/interpreter/AbstractPC.cpp
new file mode 100644
index 000000000..09b24d5dc
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/AbstractPC.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AbstractPC.h"
+
+#include "CallFrame.h"
+#include "JSObject.h"
+#include "JSCInlines.h"
+#include "VM.h"
+
+namespace JSC {
+
+AbstractPC::AbstractPC(VM& vm, ExecState* exec)
+{
+ UNUSED_PARAM(vm);
+ UNUSED_PARAM(exec);
+
+#if ENABLE(JIT)
+ if (vm.canUseJIT()) {
+ m_pointer = exec->returnPC().value();
+ m_mode = JIT;
+ return;
+ }
+#endif
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/interpreter/AbstractPC.h b/Source/JavaScriptCore/interpreter/AbstractPC.h
new file mode 100644
index 000000000..ac2aaa7ad
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/AbstractPC.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AbstractPC_h
+#define AbstractPC_h
+
+#include "MacroAssemblerCodeRef.h"
+
+namespace JSC {
+
+class VM;
+class ExecState;
+struct Instruction;
+
+class AbstractPC {
+public:
+ AbstractPC()
+ : m_pointer(0)
+ , m_mode(None)
+ {
+ }
+
+ AbstractPC(VM&, ExecState*);
+
+#if ENABLE(JIT)
+ AbstractPC(ReturnAddressPtr ptr)
+ : m_pointer(ptr.value())
+ , m_mode(JIT)
+ {
+ }
+
+ bool hasJITReturnAddress() const { return m_mode == JIT; }
+ ReturnAddressPtr jitReturnAddress() const
+ {
+ ASSERT(hasJITReturnAddress());
+ return ReturnAddressPtr(m_pointer);
+ }
+#endif
+
+ bool isSet() const { return m_mode != None; }
+ bool operator!() const { return !isSet(); }
+
+private:
+ void* m_pointer;
+
+ enum Mode { None, JIT, Interpreter };
+ Mode m_mode;
+};
+
+} // namespace JSC
+
+#endif // AbstractPC_h
+
diff --git a/Source/JavaScriptCore/interpreter/CachedCall.h b/Source/JavaScriptCore/interpreter/CachedCall.h
new file mode 100644
index 000000000..30cad2a14
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/CachedCall.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009, 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CachedCall_h
+#define CachedCall_h
+
+#include "CallFrameClosure.h"
+#include "ExceptionHelpers.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "Interpreter.h"
+#include "ProtoCallFrame.h"
+#include "VMEntryScope.h"
+
+namespace JSC {
+ class CachedCall {
+ WTF_MAKE_NONCOPYABLE(CachedCall); WTF_MAKE_FAST_ALLOCATED;
+ public:
+ CachedCall(CallFrame* callFrame, JSFunction* function, int argumentCount)
+ : m_valid(false)
+ , m_interpreter(callFrame->interpreter())
+ , m_entryScope(callFrame->vm(), function->scope()->globalObject())
+ {
+ ASSERT(!function->isHostFunctionNonInline());
+ if (callFrame->vm().isSafeToRecurse()) {
+ m_arguments.resize(argumentCount);
+ m_closure = m_interpreter->prepareForRepeatCall(function->jsExecutable(), callFrame, &m_protoCallFrame, function, argumentCount + 1, function->scope(), m_arguments.data());
+ } else
+ throwStackOverflowError(callFrame);
+ m_valid = !callFrame->hadException();
+ }
+
+ JSValue call()
+ {
+ ASSERT(m_valid);
+ return m_interpreter->execute(m_closure);
+ }
+ void setThis(JSValue v) { m_protoCallFrame.setThisValue(v); }
+ void setArgument(int n, JSValue v) { m_protoCallFrame.setArgument(n, v); }
+
+ private:
+ bool m_valid;
+ Interpreter* m_interpreter;
+ VMEntryScope m_entryScope;
+ ProtoCallFrame m_protoCallFrame;
+ Vector<JSValue> m_arguments;
+ CallFrameClosure m_closure;
+ };
+}
+
+#endif
diff --git a/Source/JavaScriptCore/interpreter/CallFrame.cpp b/Source/JavaScriptCore/interpreter/CallFrame.cpp
new file mode 100644
index 000000000..259061df4
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/CallFrame.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2008, 2013, 2014 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CallFrame.h"
+
+#include "CallFrameInlines.h"
+#include "CodeBlock.h"
+#include "Interpreter.h"
+#include "JSLexicalEnvironment.h"
+#include "JSCInlines.h"
+#include "VMEntryScope.h"
+#include <wtf/StringPrintStream.h>
+
+namespace JSC {
+
+#ifndef NDEBUG
+JSStack* CallFrame::stack()
+{
+ return &interpreter()->stack();
+}
+
+#endif
+
+#if USE(JSVALUE32_64)
+unsigned CallFrame::locationAsBytecodeOffset() const
+{
+ ASSERT(codeBlock());
+ ASSERT(hasLocationAsBytecodeOffset());
+ return currentVPC() - codeBlock()->instructions().begin();
+}
+
+void CallFrame::setLocationAsBytecodeOffset(unsigned offset)
+{
+ ASSERT(codeBlock());
+ setCurrentVPC(codeBlock()->instructions().begin() + offset);
+ ASSERT(hasLocationAsBytecodeOffset());
+}
+#else
+Instruction* CallFrame::currentVPC() const
+{
+ return codeBlock()->instructions().begin() + locationAsBytecodeOffset();
+}
+void CallFrame::setCurrentVPC(Instruction* vpc)
+{
+ setLocationAsBytecodeOffset(vpc - codeBlock()->instructions().begin());
+}
+#endif
+
+#if ENABLE(DFG_JIT)
+unsigned CallFrame::bytecodeOffsetFromCodeOriginIndex()
+{
+ ASSERT(hasLocationAsCodeOriginIndex());
+ CodeBlock* codeBlock = this->codeBlock();
+ ASSERT(codeBlock);
+
+ CodeOrigin codeOrigin;
+ unsigned index = locationAsCodeOriginIndex();
+ ASSERT(codeBlock->canGetCodeOrigin(index));
+ codeOrigin = codeBlock->codeOrigin(index);
+
+ for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
+ if (inlineCallFrame->baselineCodeBlock() == codeBlock)
+ return codeOrigin.bytecodeIndex;
+
+ codeOrigin = inlineCallFrame->caller;
+ inlineCallFrame = codeOrigin.inlineCallFrame;
+ }
+ return codeOrigin.bytecodeIndex;
+}
+
+#endif // ENABLE(DFG_JIT)
+
+unsigned CallFrame::bytecodeOffset()
+{
+ if (!codeBlock())
+ return 0;
+#if ENABLE(DFG_JIT)
+ if (hasLocationAsCodeOriginIndex())
+ return bytecodeOffsetFromCodeOriginIndex();
+#endif
+ return locationAsBytecodeOffset();
+}
+
+CodeOrigin CallFrame::codeOrigin()
+{
+ if (!codeBlock())
+ return CodeOrigin(0);
+#if ENABLE(DFG_JIT)
+ if (hasLocationAsCodeOriginIndex()) {
+ unsigned index = locationAsCodeOriginIndex();
+ ASSERT(codeBlock()->canGetCodeOrigin(index));
+ return codeBlock()->codeOrigin(index);
+ }
+#endif
+ return CodeOrigin(locationAsBytecodeOffset());
+}
+
+Register* CallFrame::topOfFrameInternal()
+{
+ CodeBlock* codeBlock = this->codeBlock();
+ ASSERT(codeBlock);
+ return registers() + codeBlock->stackPointerOffset();
+}
+
+JSGlobalObject* CallFrame::vmEntryGlobalObject()
+{
+ if (this == lexicalGlobalObject()->globalExec())
+ return lexicalGlobalObject();
+
+ // For any ExecState that's not a globalExec, the
+ // dynamic global object must be set since code is running
+ ASSERT(vm().entryScope);
+ return vm().entryScope->globalObject();
+}
+
+CallFrame* CallFrame::callerFrame(VMEntryFrame*& currVMEntryFrame)
+{
+ if (callerFrameOrVMEntryFrame() == currVMEntryFrame) {
+ VMEntryRecord* currVMEntryRecord = vmEntryRecord(currVMEntryFrame);
+ currVMEntryFrame = currVMEntryRecord->prevTopVMEntryFrame();
+ return currVMEntryRecord->prevTopCallFrame();
+ }
+ return static_cast<CallFrame*>(callerFrameOrVMEntryFrame());
+}
+
+JSLexicalEnvironment* CallFrame::lexicalEnvironment() const
+{
+ CodeBlock* codeBlock = this->codeBlock();
+ RELEASE_ASSERT(codeBlock->needsActivation());
+ VirtualRegister activationRegister = codeBlock->activationRegister();
+ return registers()[activationRegister.offset()].Register::lexicalEnvironment();
+}
+
+JSLexicalEnvironment* CallFrame::lexicalEnvironmentOrNullptr() const
+{
+ CodeBlock* codeBlock = this->codeBlock();
+ return codeBlock->needsActivation() ? lexicalEnvironment() : nullptr;
+}
+
+void CallFrame::setActivation(JSLexicalEnvironment* lexicalEnvironment)
+{
+ CodeBlock* codeBlock = this->codeBlock();
+ RELEASE_ASSERT(codeBlock->needsActivation());
+ VirtualRegister activationRegister = codeBlock->activationRegister();
+ registers()[activationRegister.offset()] = lexicalEnvironment;
+}
+
+void CallFrame::dump(PrintStream& out)
+{
+ if (CodeBlock* codeBlock = this->codeBlock()) {
+ out.print(codeBlock->inferredName(), "#", codeBlock->hashAsStringIfPossible(), " [", codeBlock->jitType(), "]");
+
+ out.print("(");
+ thisValue().dumpForBacktrace(out);
+
+ for (size_t i = 0; i < argumentCount(); ++i) {
+ out.print(", ");
+ JSValue value = argument(i);
+ value.dumpForBacktrace(out);
+ }
+
+ out.print(")");
+
+ return;
+ }
+
+ out.print(returnPC());
+}
+
+const char* CallFrame::describeFrame()
+{
+ const size_t bufferSize = 200;
+ static char buffer[bufferSize + 1];
+
+ WTF::StringPrintStream stringStream;
+
+ dump(stringStream);
+
+ strncpy(buffer, stringStream.toCString().data(), bufferSize);
+ buffer[bufferSize] = '\0';
+
+ return buffer;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/interpreter/CallFrame.h b/Source/JavaScriptCore/interpreter/CallFrame.h
new file mode 100644
index 000000000..afa8d3ca7
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/CallFrame.h
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2007, 2008, 2011, 2013, 2014 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CallFrame_h
+#define CallFrame_h
+
+#include "AbstractPC.h"
+#include "JSStack.h"
+#include "MacroAssemblerCodeRef.h"
+#include "Register.h"
+#include "StackVisitor.h"
+#include "VM.h"
+#include "VMEntryRecord.h"
+
+namespace JSC {
+
+ class Arguments;
+ class JSLexicalEnvironment;
+ class Interpreter;
+ class JSScope;
+
+ // Represents the current state of script execution.
+ // Passed as the first argument to most functions.
+ class ExecState : private Register {
+ public:
+ JSValue calleeAsValue() const { return this[JSStack::Callee].jsValue(); }
+ JSObject* callee() const { return this[JSStack::Callee].object(); }
+ CodeBlock* codeBlock() const { return this[JSStack::CodeBlock].Register::codeBlock(); }
+ JSScope* scope(int scopeRegisterOffset) const
+ {
+ ASSERT(this[scopeRegisterOffset].Register::scope());
+ return this[scopeRegisterOffset].Register::scope();
+ }
+
+ bool hasActivation() const;
+ JSLexicalEnvironment* lexicalEnvironment() const;
+ JSLexicalEnvironment* lexicalEnvironmentOrNullptr() const;
+ JSValue uncheckedActivation() const;
+
+ // Global object in which execution began.
+ JS_EXPORT_PRIVATE JSGlobalObject* vmEntryGlobalObject();
+
+ // Global object in which the currently executing code was defined.
+ // Differs from vmEntryGlobalObject() during function calls across web browser frames.
+ JSGlobalObject* lexicalGlobalObject() const;
+
+ // Differs from lexicalGlobalObject because this will have DOM window shell rather than
+ // the actual DOM window, which can't be "this" for security reasons.
+ JSObject* globalThisValue() const;
+
+ VM& vm() const;
+
+ // Convenience functions for access to global data.
+ // It takes a few memory references to get from a call frame to the global data
+ // pointer, so these are inefficient, and should be used sparingly in new code.
+ // But they're used in many places in legacy code, so they're not going away any time soon.
+
+ void clearException() { vm().clearException(); }
+
+ Exception* exception() const { return vm().exception(); }
+ bool hadException() const { return !!vm().exception(); }
+
+ Exception* lastException() const { return vm().lastException(); }
+ void clearLastException() { vm().clearLastException(); }
+
+ AtomicStringTable* atomicStringTable() const { return vm().atomicStringTable(); }
+ const CommonIdentifiers& propertyNames() const { return *vm().propertyNames; }
+ const MarkedArgumentBuffer& emptyList() const { return *vm().emptyList; }
+ Interpreter* interpreter() { return vm().interpreter; }
+ Heap* heap() { return &vm().heap; }
+
+
+ static CallFrame* create(Register* callFrameBase) { return static_cast<CallFrame*>(callFrameBase); }
+ Register* registers() { return this; }
+ const Register* registers() const { return this; }
+
+ CallFrame& operator=(const Register& r) { *static_cast<Register*>(this) = r; return *this; }
+
+ CallFrame* callerFrame() const { return static_cast<CallFrame*>(callerFrameOrVMEntryFrame()); }
+
+ JS_EXPORT_PRIVATE CallFrame* callerFrame(VMEntryFrame*&);
+
+ static ptrdiff_t callerFrameOffset() { return OBJECT_OFFSETOF(CallerFrameAndPC, callerFrame); }
+
+ ReturnAddressPtr returnPC() const { return ReturnAddressPtr(callerFrameAndPC().pc); }
+ bool hasReturnPC() const { return !!callerFrameAndPC().pc; }
+ void clearReturnPC() { callerFrameAndPC().pc = 0; }
+ static ptrdiff_t returnPCOffset() { return OBJECT_OFFSETOF(CallerFrameAndPC, pc); }
+ AbstractPC abstractReturnPC(VM& vm) { return AbstractPC(vm, this); }
+
+ class Location {
+ public:
+ static inline uint32_t decode(uint32_t bits);
+
+ static inline bool isBytecodeLocation(uint32_t bits);
+#if USE(JSVALUE64)
+ static inline uint32_t encodeAsBytecodeOffset(uint32_t bits);
+#else
+ static inline uint32_t encodeAsBytecodeInstruction(Instruction*);
+#endif
+
+ static inline bool isCodeOriginIndex(uint32_t bits);
+ static inline uint32_t encodeAsCodeOriginIndex(uint32_t bits);
+
+ private:
+ enum TypeTag {
+ BytecodeLocationTag = 0,
+ CodeOriginIndexTag = 1,
+ };
+
+ static inline uint32_t encode(TypeTag, uint32_t bits);
+
+ static const uint32_t s_mask = 0x1;
+#if USE(JSVALUE64)
+ static const uint32_t s_shift = 31;
+ static const uint32_t s_shiftedMask = s_mask << s_shift;
+#else
+ static const uint32_t s_shift = 1;
+#endif
+ };
+
+ bool hasLocationAsBytecodeOffset() const;
+ bool hasLocationAsCodeOriginIndex() const;
+
+ unsigned locationAsRawBits() const;
+ unsigned locationAsBytecodeOffset() const;
+ unsigned locationAsCodeOriginIndex() const;
+
+ void setLocationAsRawBits(unsigned);
+ void setLocationAsBytecodeOffset(unsigned);
+
+#if ENABLE(DFG_JIT)
+ unsigned bytecodeOffsetFromCodeOriginIndex();
+#endif
+
+ // This will try to get you the bytecode offset, but you should be aware that
+ // this bytecode offset may be bogus in the presence of inlining. This will
+ // also return 0 if the call frame has no notion of bytecode offsets (for
+ // example if it's native code).
+ // https://bugs.webkit.org/show_bug.cgi?id=121754
+ unsigned bytecodeOffset();
+
+ // This will get you a CodeOrigin. It will always succeed. May return
+ // CodeOrigin(0) if we're in native code.
+ CodeOrigin codeOrigin();
+
+ Register* topOfFrame()
+ {
+ if (!codeBlock())
+ return registers();
+ return topOfFrameInternal();
+ }
+
+#if USE(JSVALUE32_64)
+ Instruction* currentVPC() const
+ {
+ return bitwise_cast<Instruction*>(this[JSStack::ArgumentCount].tag());
+ }
+ void setCurrentVPC(Instruction* vpc)
+ {
+ this[JSStack::ArgumentCount].tag() = bitwise_cast<int32_t>(vpc);
+ }
+#else
+ Instruction* currentVPC() const;
+ void setCurrentVPC(Instruction* vpc);
+#endif
+
+ void setCallerFrame(CallFrame* frame) { callerFrameAndPC().callerFrame = frame; }
+ void setScope(int scopeRegisterOffset, JSScope* scope) { static_cast<Register*>(this)[scopeRegisterOffset] = scope; }
+ void setActivation(JSLexicalEnvironment*);
+
+ ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC,
+ CallFrame* callerFrame, int argc, JSObject* callee)
+ {
+ ASSERT(callerFrame == noCaller() || callerFrame->stack()->containsAddress(this));
+
+ setCodeBlock(codeBlock);
+ setCallerFrame(callerFrame);
+ setReturnPC(vPC); // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
+ setArgumentCountIncludingThis(argc); // original argument count (for the sake of the "arguments" object)
+ setCallee(callee);
+ }
+
+ // Read a register from the codeframe (or constant from the CodeBlock).
+ Register& r(int);
+ Register& r(VirtualRegister);
+ // Read a register for a non-constant
+ Register& uncheckedR(int);
+ Register& uncheckedR(VirtualRegister);
+
+ // Access to arguments as passed. (After capture, arguments may move to a different location.)
+ size_t argumentCount() const { return argumentCountIncludingThis() - 1; }
+ size_t argumentCountIncludingThis() const { return this[JSStack::ArgumentCount].payload(); }
+ static int argumentOffset(int argument) { return (JSStack::FirstArgument + argument); }
+ static int argumentOffsetIncludingThis(int argument) { return (JSStack::ThisArgument + argument); }
+
+ // In the following (argument() and setArgument()), the 'argument'
+ // parameter is the index of the arguments of the target function of
+ // this frame. The index starts at 0 for the first arg, 1 for the
+ // second, etc.
+ //
+ // The arguments (in this case) do not include the 'this' value.
+ // arguments(0) will not fetch the 'this' value. To get/set 'this',
+ // use thisValue() and setThisValue() below.
+
+ JSValue argument(size_t argument)
+ {
+ if (argument >= argumentCount())
+ return jsUndefined();
+ return getArgumentUnsafe(argument);
+ }
+ JSValue uncheckedArgument(size_t argument)
+ {
+ ASSERT(argument < argumentCount());
+ return getArgumentUnsafe(argument);
+ }
+ void setArgument(size_t argument, JSValue value)
+ {
+ this[argumentOffset(argument)] = value;
+ }
+
+ JSValue getArgumentUnsafe(size_t argIndex)
+ {
+ // User beware! This method does not verify that there is a valid
+ // argument at the specified argIndex. This is used for debugging
+ // and verification code only. The caller is expected to know what
+ // he/she is doing when calling this method.
+ return this[argumentOffset(argIndex)].jsValue();
+ }
+
+ static int thisArgumentOffset() { return argumentOffsetIncludingThis(0); }
+ JSValue thisValue() { return this[thisArgumentOffset()].jsValue(); }
+ void setThisValue(JSValue value) { this[thisArgumentOffset()] = value; }
+
+ // Under the constructor implemented in C++, thisValue holds the newTarget instead of the automatically constructed value.
+ // The result of this function is only effective under the "construct" context.
+ JSValue newTarget() { return thisValue(); }
+
+ JSValue argumentAfterCapture(size_t argument);
+
+ static int offsetFor(size_t argumentCountIncludingThis) { return argumentCountIncludingThis + JSStack::ThisArgument - 1; }
+
+ static CallFrame* noCaller() { return 0; }
+
+ void setArgumentCountIncludingThis(int count) { static_cast<Register*>(this)[JSStack::ArgumentCount].payload() = count; }
+ void setCallee(JSObject* callee) { static_cast<Register*>(this)[JSStack::Callee] = callee; }
+ void setCodeBlock(CodeBlock* codeBlock) { static_cast<Register*>(this)[JSStack::CodeBlock] = codeBlock; }
+ void setReturnPC(void* value) { callerFrameAndPC().pc = reinterpret_cast<Instruction*>(value); }
+
+ // CallFrame::iterate() expects a Functor that implements the following method:
+ // StackVisitor::Status operator()(StackVisitor&);
+
+ template <typename Functor> void iterate(Functor& functor)
+ {
+ StackVisitor::visit<Functor>(this, functor);
+ }
+
+ void dump(PrintStream&);
+ JS_EXPORT_PRIVATE const char* describeFrame();
+
+ private:
+
+#ifndef NDEBUG
+ JSStack* stack();
+#endif
+ ExecState();
+ ~ExecState();
+
+ Register* topOfFrameInternal();
+
+ // The following are for internal use in debugging and verification
+ // code only and not meant as an API for general usage:
+
+ size_t argIndexForRegister(Register* reg)
+ {
+ // The register at 'offset' number of slots from the frame pointer
+ // i.e.
+ // reg = frame[offset];
+ // ==> reg = frame + offset;
+ // ==> offset = reg - frame;
+ int offset = reg - this->registers();
+
+ // The offset is defined (based on argumentOffset()) to be:
+ // offset = JSStack::FirstArgument - argIndex;
+ // Hence:
+ // argIndex = JSStack::FirstArgument - offset;
+ size_t argIndex = offset - JSStack::FirstArgument;
+ return argIndex;
+ }
+
+ void* callerFrameOrVMEntryFrame() const { return callerFrameAndPC().callerFrame; }
+
+ CallerFrameAndPC& callerFrameAndPC() { return *reinterpret_cast<CallerFrameAndPC*>(this); }
+ const CallerFrameAndPC& callerFrameAndPC() const { return *reinterpret_cast<const CallerFrameAndPC*>(this); }
+
+ friend class JSStack;
+ };
+
+} // namespace JSC
+
+#endif // CallFrame_h
diff --git a/Source/JavaScriptCore/interpreter/CallFrameClosure.h b/Source/JavaScriptCore/interpreter/CallFrameClosure.h
new file mode 100644
index 000000000..2c03b7452
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/CallFrameClosure.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009, 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CallFrameClosure_h
+#define CallFrameClosure_h
+
+#include "ProtoCallFrame.h"
+
+namespace JSC {
+
+struct CallFrameClosure {
+ CallFrame* oldCallFrame;
+ ProtoCallFrame* protoCallFrame;
+ JSFunction* function;
+ FunctionExecutable* functionExecutable;
+ VM* vm;
+ JSScope* scope;
+ int parameterCountIncludingThis;
+ int argumentCountIncludingThis;
+
+ void setThis(JSValue value)
+ {
+ protoCallFrame->setThisValue(value);
+ }
+
+ void setArgument(int argument, JSValue value)
+ {
+ protoCallFrame->setArgument(argument, value);
+ }
+};
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/interpreter/CallFrameInlines.h b/Source/JavaScriptCore/interpreter/CallFrameInlines.h
new file mode 100644
index 000000000..3f430ec31
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/CallFrameInlines.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CallFrameInlines_h
+#define CallFrameInlines_h
+
+#include "CallFrame.h"
+#include "CodeBlock.h"
+
+namespace JSC {
+
+inline uint32_t CallFrame::Location::encode(CallFrame::Location::TypeTag tag, uint32_t bits)
+{
+#if USE(JSVALUE64)
+ ASSERT(!(bits & s_shiftedMask));
+ ASSERT(!(tag & ~s_mask));
+ return bits | (tag << s_shift);
+#else
+ ASSERT(!(tag & ~s_mask));
+ if (tag & CodeOriginIndexTag)
+ bits = (bits << s_shift);
+ ASSERT(!(bits & s_mask));
+ bits |= tag;
+ return bits;
+#endif
+}
+
+inline uint32_t CallFrame::Location::decode(uint32_t bits)
+{
+#if USE(JSVALUE64)
+ return bits & ~s_shiftedMask;
+#else
+ if (isCodeOriginIndex(bits))
+ return bits >> s_shift;
+ return bits & ~s_mask;
+#endif
+}
+
+#if USE(JSVALUE64)
+inline uint32_t CallFrame::Location::encodeAsBytecodeOffset(uint32_t bits)
+{
+ uint32_t encodedBits = encode(BytecodeLocationTag, bits);
+ ASSERT(isBytecodeLocation(encodedBits));
+ return encodedBits;
+}
+#else
+inline uint32_t CallFrame::Location::encodeAsBytecodeInstruction(Instruction* instruction)
+{
+ uint32_t encodedBits = encode(BytecodeLocationTag, reinterpret_cast<uint32_t>(instruction));
+ ASSERT(isBytecodeLocation(encodedBits));
+ return encodedBits;
+}
+#endif
+
+inline uint32_t CallFrame::Location::encodeAsCodeOriginIndex(uint32_t bits)
+{
+ uint32_t encodedBits = encode(CodeOriginIndexTag, bits);
+ ASSERT(isCodeOriginIndex(encodedBits));
+ return encodedBits;
+}
+
+inline bool CallFrame::Location::isBytecodeLocation(uint32_t bits)
+{
+ return !isCodeOriginIndex(bits);
+}
+
+inline bool CallFrame::Location::isCodeOriginIndex(uint32_t bits)
+{
+#if USE(JSVALUE64)
+ TypeTag tag = static_cast<TypeTag>(bits >> s_shift);
+ return !!(tag & CodeOriginIndexTag);
+#else
+ return !!(bits & CodeOriginIndexTag);
+#endif
+}
+
+inline bool CallFrame::hasLocationAsBytecodeOffset() const
+{
+ return Location::isBytecodeLocation(locationAsRawBits());
+}
+
+inline bool CallFrame::hasLocationAsCodeOriginIndex() const
+{
+ return Location::isCodeOriginIndex(locationAsRawBits());
+}
+
+inline unsigned CallFrame::locationAsRawBits() const
+{
+ return this[JSStack::ArgumentCount].tag();
+}
+
+inline void CallFrame::setLocationAsRawBits(unsigned bits)
+{
+ this[JSStack::ArgumentCount].tag() = static_cast<int32_t>(bits);
+}
+
+#if USE(JSVALUE64)
+inline unsigned CallFrame::locationAsBytecodeOffset() const
+{
+ ASSERT(hasLocationAsBytecodeOffset());
+ ASSERT(codeBlock());
+ return Location::decode(locationAsRawBits());
+}
+
+inline void CallFrame::setLocationAsBytecodeOffset(unsigned offset)
+{
+ ASSERT(codeBlock());
+ setLocationAsRawBits(Location::encodeAsBytecodeOffset(offset));
+ ASSERT(hasLocationAsBytecodeOffset());
+}
+#endif // USE(JSVALUE64)
+
+inline unsigned CallFrame::locationAsCodeOriginIndex() const
+{
+ ASSERT(hasLocationAsCodeOriginIndex());
+ ASSERT(codeBlock());
+ return Location::decode(locationAsRawBits());
+}
+
+inline bool CallFrame::hasActivation() const
+{
+ JSValue activation = uncheckedActivation();
+ return !!activation && activation.isCell();
+}
+
+inline JSValue CallFrame::uncheckedActivation() const
+{
+ CodeBlock* codeBlock = this->codeBlock();
+ RELEASE_ASSERT(codeBlock->needsActivation());
+ VirtualRegister activationRegister = codeBlock->activationRegister();
+ return registers()[activationRegister.offset()].jsValue();
+}
+
+} // namespace JSC
+
+#endif // CallFrameInlines_h
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
new file mode 100644
index 000000000..518fc0b76
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -0,0 +1,1248 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Interpreter.h"
+
+#include "BatchedTransitionOptimizer.h"
+#include "CallFrameClosure.h"
+#include "CallFrameInlines.h"
+#include "ClonedArguments.h"
+#include "CodeBlock.h"
+#include "DirectArguments.h"
+#include "Heap.h"
+#include "Debugger.h"
+#include "DebuggerCallFrame.h"
+#include "ErrorInstance.h"
+#include "EvalCodeCache.h"
+#include "Exception.h"
+#include "ExceptionHelpers.h"
+#include "GetterSetter.h"
+#include "JSArray.h"
+#include "JSBoundFunction.h"
+#include "JSCInlines.h"
+#include "JSLexicalEnvironment.h"
+#include "JSNotAnObject.h"
+#include "JSStackInlines.h"
+#include "JSString.h"
+#include "JSWithScope.h"
+#include "LLIntCLoop.h"
+#include "LLIntThunks.h"
+#include "LegacyProfiler.h"
+#include "LiteralParser.h"
+#include "ObjectPrototype.h"
+#include "Parser.h"
+#include "ProtoCallFrame.h"
+#include "RegExpObject.h"
+#include "RegExpPrototype.h"
+#include "Register.h"
+#include "SamplingTool.h"
+#include "ScopedArguments.h"
+#include "StackAlignment.h"
+#include "StackVisitor.h"
+#include "StrictEvalActivation.h"
+#include "StrongInlines.h"
+#include "Symbol.h"
+#include "VMEntryScope.h"
+#include "VMInlines.h"
+#include "VirtualRegister.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <wtf/StackStats.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/StringPrintStream.h>
+#include <wtf/Threading.h>
+#include <wtf/WTFThreadData.h>
+#include <wtf/text/StringBuilder.h>
+
+#if ENABLE(JIT)
+#include "JIT.h"
+#endif
+
+using namespace std;
+
+namespace JSC {
+
+String StackFrame::friendlySourceURL() const
+{
+ String traceLine;
+
+ switch (codeType) {
+ case StackFrameEvalCode:
+ case StackFrameFunctionCode:
+ case StackFrameGlobalCode:
+ if (!sourceURL.isEmpty())
+ traceLine = sourceURL.impl();
+ break;
+ case StackFrameNativeCode:
+ traceLine = "[native code]";
+ break;
+ }
+ return traceLine.isNull() ? emptyString() : traceLine;
+}
+
+String StackFrame::friendlyFunctionName(CallFrame* callFrame) const
+{
+ String traceLine;
+ JSObject* stackFrameCallee = callee.get();
+
+ switch (codeType) {
+ case StackFrameEvalCode:
+ traceLine = "eval code";
+ break;
+ case StackFrameNativeCode:
+ if (callee)
+ traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
+ break;
+ case StackFrameFunctionCode:
+ traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
+ break;
+ case StackFrameGlobalCode:
+ traceLine = "global code";
+ break;
+ }
+ return traceLine.isNull() ? emptyString() : traceLine;
+}
+
+JSValue eval(CallFrame* callFrame)
+{
+ if (!callFrame->argumentCount())
+ return jsUndefined();
+
+ JSValue program = callFrame->argument(0);
+ if (!program.isString())
+ return program;
+
+ TopCallFrameSetter topCallFrame(callFrame->vm(), callFrame);
+ String programSource = asString(program)->value(callFrame);
+ if (callFrame->hadException())
+ return JSValue();
+
+ CallFrame* callerFrame = callFrame->callerFrame();
+ CodeBlock* callerCodeBlock = callerFrame->codeBlock();
+ JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister().offset()).Register::scope();
+ EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), programSource, callerScopeChain);
+
+ if (!eval) {
+ if (!callerCodeBlock->isStrictMode()) {
+ if (programSource.is8Bit()) {
+ LiteralParser<LChar> preparser(callFrame, programSource.characters8(), programSource.length(), NonStrictJSON);
+ if (JSValue parsedObject = preparser.tryLiteralParse())
+ return parsedObject;
+ } else {
+ LiteralParser<UChar> preparser(callFrame, programSource.characters16(), programSource.length(), NonStrictJSON);
+ if (JSValue parsedObject = preparser.tryLiteralParse())
+ return parsedObject;
+ }
+ }
+
+ // If the literal parser bailed, it should not have thrown exceptions.
+ ASSERT(!callFrame->vm().exception());
+
+ ThisTDZMode thisTDZMode = callerCodeBlock->unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded;
+ eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock->ownerExecutable(), callerCodeBlock->isStrictMode(), thisTDZMode, programSource, callerScopeChain);
+ if (!eval)
+ return jsUndefined();
+ }
+
+ JSValue thisValue = callerFrame->thisValue();
+ Interpreter* interpreter = callFrame->vm().interpreter;
+ return interpreter->execute(eval, callFrame, thisValue, callerScopeChain);
+}
+
+unsigned sizeOfVarargs(CallFrame* callFrame, JSValue arguments, uint32_t firstVarArgOffset)
+{
+ if (UNLIKELY(!arguments.isCell())) {
+ if (arguments.isUndefinedOrNull())
+ return 0;
+
+ callFrame->vm().throwException(callFrame, createInvalidFunctionApplyParameterError(callFrame, arguments));
+ return 0;
+ }
+
+ JSCell* cell = arguments.asCell();
+ unsigned length;
+ switch (cell->type()) {
+ case DirectArgumentsType:
+ length = jsCast<DirectArguments*>(cell)->length(callFrame);
+ break;
+ case ScopedArgumentsType:
+ length =jsCast<ScopedArguments*>(cell)->length(callFrame);
+ break;
+ case StringType:
+ callFrame->vm().throwException(callFrame, createInvalidFunctionApplyParameterError(callFrame, arguments));
+ return 0;
+ default:
+ ASSERT(arguments.isObject());
+ if (isJSArray(cell))
+ length = jsCast<JSArray*>(cell)->length();
+ else
+ length = jsCast<JSObject*>(cell)->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
+ break;
+ }
+
+ if (length >= firstVarArgOffset)
+ length -= firstVarArgOffset;
+ else
+ length = 0;
+
+ return length;
+}
+
+unsigned sizeFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset)
+{
+ unsigned length = sizeOfVarargs(callFrame, arguments, firstVarArgOffset);
+
+ CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1);
+ if (length > maxArguments || !stack->ensureCapacityFor(calleeFrame->registers())) {
+ throwStackOverflowError(callFrame);
+ return 0;
+ }
+
+ return length;
+}
+
+void loadVarargs(CallFrame* callFrame, VirtualRegister firstElementDest, JSValue arguments, uint32_t offset, uint32_t length)
+{
+ if (UNLIKELY(!arguments.isCell()))
+ return;
+
+ JSCell* cell = arguments.asCell();
+ switch (cell->type()) {
+ case DirectArgumentsType:
+ jsCast<DirectArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length);
+ return;
+ case ScopedArgumentsType:
+ jsCast<ScopedArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length);
+ return;
+ default: {
+ ASSERT(arguments.isObject());
+ JSObject* object = jsCast<JSObject*>(cell);
+ if (isJSArray(object)) {
+ jsCast<JSArray*>(object)->copyToArguments(callFrame, firstElementDest, offset, length);
+ return;
+ }
+ unsigned i;
+ for (i = 0; i < length && object->canGetIndexQuickly(i + offset); ++i)
+ callFrame->r(firstElementDest + i) = object->getIndexQuickly(i + offset);
+ for (; i < length; ++i)
+ callFrame->r(firstElementDest + i) = object->get(callFrame, i + offset);
+ return;
+ } }
+}
+
+void setupVarargsFrame(CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t offset, uint32_t length)
+{
+ VirtualRegister calleeFrameOffset(newCallFrame - callFrame);
+
+ loadVarargs(
+ callFrame,
+ calleeFrameOffset + CallFrame::argumentOffset(0),
+ arguments, offset, length);
+
+ newCallFrame->setArgumentCountIncludingThis(length + 1);
+}
+
+void setupVarargsFrameAndSetThis(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length)
+{
+ setupVarargsFrame(callFrame, newCallFrame, arguments, firstVarArgOffset, length);
+ newCallFrame->setThisValue(thisValue);
+}
+
+Interpreter::Interpreter(VM& vm)
+ : m_sampleEntryDepth(0)
+ , m_vm(vm)
+ , m_stack(vm)
+ , m_errorHandlingModeReentry(0)
+#if !ASSERT_DISABLED
+ , m_initialized(false)
+#endif
+{
+}
+
+Interpreter::~Interpreter()
+{
+}
+
+void Interpreter::initialize(bool canUseJIT)
+{
+ UNUSED_PARAM(canUseJIT);
+
+#if ENABLE(COMPUTED_GOTO_OPCODES)
+ m_opcodeTable = LLInt::opcodeMap();
+ for (int i = 0; i < numOpcodeIDs; ++i)
+ m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
+#endif
+
+#if !ASSERT_DISABLED
+ m_initialized = true;
+#endif
+
+#if ENABLE(OPCODE_SAMPLING)
+ enableSampler();
+#endif
+}
+
+#ifdef NDEBUG
+
+void Interpreter::dumpCallFrame(CallFrame*)
+{
+}
+
+#else
+
+void Interpreter::dumpCallFrame(CallFrame* callFrame)
+{
+ callFrame->codeBlock()->dumpBytecode();
+ dumpRegisters(callFrame);
+}
+
+class DumpRegisterFunctor {
+public:
+ DumpRegisterFunctor(const Register*& it)
+ : m_hasSkippedFirstFrame(false)
+ , m_it(it)
+ {
+ }
+
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ if (!m_hasSkippedFirstFrame) {
+ m_hasSkippedFirstFrame = true;
+ return StackVisitor::Continue;
+ }
+
+ unsigned line = 0;
+ unsigned unusedColumn = 0;
+ visitor->computeLineAndColumn(line, unusedColumn);
+ dataLogF("[ReturnVPC] | %10p | %d (line %d)\n", m_it, visitor->bytecodeOffset(), line);
+ --m_it;
+ return StackVisitor::Done;
+ }
+
+private:
+ bool m_hasSkippedFirstFrame;
+ const Register*& m_it;
+};
+
+void Interpreter::dumpRegisters(CallFrame* callFrame)
+{
+ dataLogF("Register frame: \n\n");
+ dataLogF("-----------------------------------------------------------------------------\n");
+ dataLogF(" use | address | value \n");
+ dataLogF("-----------------------------------------------------------------------------\n");
+
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ const Register* it;
+ const Register* end;
+
+ it = callFrame->registers() + JSStack::ThisArgument + callFrame->argumentCount();
+ end = callFrame->registers() + JSStack::ThisArgument - 1;
+ while (it > end) {
+ JSValue v = it->jsValue();
+ int registerNumber = it - callFrame->registers();
+ String name = codeBlock->nameForRegister(VirtualRegister(registerNumber));
+ dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, toCString(v).data(), (long long)JSValue::encode(v));
+ --it;
+ }
+
+ dataLogF("-----------------------------------------------------------------------------\n");
+ dataLogF("[ArgumentCount] | %10p | %lu \n", it, (unsigned long) callFrame->argumentCount());
+ --it;
+ dataLogF("[CallerFrame] | %10p | %p \n", it, callFrame->callerFrame());
+ --it;
+ dataLogF("[Callee] | %10p | %p \n", it, callFrame->callee());
+ --it;
+ // FIXME: Remove the next decrement when the ScopeChain slot is removed from the call header
+ --it;
+#if ENABLE(JIT)
+ AbstractPC pc = callFrame->abstractReturnPC(callFrame->vm());
+ if (pc.hasJITReturnAddress())
+ dataLogF("[ReturnJITPC] | %10p | %p \n", it, pc.jitReturnAddress().value());
+#endif
+
+ DumpRegisterFunctor functor(it);
+ callFrame->iterate(functor);
+
+ dataLogF("[CodeBlock] | %10p | %p \n", it, callFrame->codeBlock());
+ --it;
+ dataLogF("-----------------------------------------------------------------------------\n");
+
+ end = it - codeBlock->m_numVars;
+ if (it != end) {
+ do {
+ JSValue v = it->jsValue();
+ int registerNumber = it - callFrame->registers();
+ String name = codeBlock->nameForRegister(VirtualRegister(registerNumber));
+ dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, toCString(v).data(), (long long)JSValue::encode(v));
+ --it;
+ } while (it != end);
+ }
+ dataLogF("-----------------------------------------------------------------------------\n");
+
+ end = it - codeBlock->m_numCalleeRegisters + codeBlock->m_numVars;
+ if (it != end) {
+ do {
+ JSValue v = (*it).jsValue();
+ int registerNumber = it - callFrame->registers();
+ dataLogF("[r% 3d] | %10p | %-16s 0x%lld \n", registerNumber, it, toCString(v).data(), (long long)JSValue::encode(v));
+ --it;
+ } while (it != end);
+ }
+ dataLogF("-----------------------------------------------------------------------------\n");
+}
+
+#endif
+
+bool Interpreter::isOpcode(Opcode opcode)
+{
+#if ENABLE(COMPUTED_GOTO_OPCODES)
+ return opcode != HashTraits<Opcode>::emptyValue()
+ && !HashTraits<Opcode>::isDeletedValue(opcode)
+ && m_opcodeIDTable.contains(opcode);
+#else
+ return opcode >= 0 && opcode <= op_end;
+#endif
+}
+
+static bool unwindCallFrame(StackVisitor& visitor)
+{
+ CallFrame* callFrame = visitor->callFrame();
+ if (Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger()) {
+ SuspendExceptionScope scope(&callFrame->vm());
+ if (jsDynamicCast<JSFunction*>(callFrame->callee()))
+ debugger->returnEvent(callFrame);
+ else
+ debugger->didExecuteProgram(callFrame);
+ ASSERT(!callFrame->hadException());
+ }
+
+ return !visitor->callerIsVMEntryFrame();
+}
+
+static StackFrameCodeType getStackFrameCodeType(StackVisitor& visitor)
+{
+ switch (visitor->codeType()) {
+ case StackVisitor::Frame::Eval:
+ return StackFrameEvalCode;
+ case StackVisitor::Frame::Function:
+ return StackFrameFunctionCode;
+ case StackVisitor::Frame::Global:
+ return StackFrameGlobalCode;
+ case StackVisitor::Frame::Native:
+ ASSERT_NOT_REACHED();
+ return StackFrameNativeCode;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return StackFrameGlobalCode;
+}
+
+void StackFrame::computeLineAndColumn(unsigned& line, unsigned& column)
+{
+ if (!codeBlock) {
+ line = 0;
+ column = 0;
+ return;
+ }
+
+ int divot = 0;
+ int unusedStartOffset = 0;
+ int unusedEndOffset = 0;
+ unsigned divotLine = 0;
+ unsigned divotColumn = 0;
+ expressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn);
+
+ line = divotLine + lineOffset;
+ column = divotColumn + (divotLine ? 1 : firstLineColumnOffset);
+
+ if (executable->hasOverrideLineNumber())
+ line = executable->overrideLineNumber();
+}
+
+void StackFrame::expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
+{
+ codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column);
+ divot += characterOffset;
+}
+
+String StackFrame::toString(CallFrame* callFrame)
+{
+ StringBuilder traceBuild;
+ String functionName = friendlyFunctionName(callFrame);
+ String sourceURL = friendlySourceURL();
+ traceBuild.append(functionName);
+ if (!sourceURL.isEmpty()) {
+ if (!functionName.isEmpty())
+ traceBuild.append('@');
+ traceBuild.append(sourceURL);
+ if (codeType != StackFrameNativeCode) {
+ unsigned line;
+ unsigned column;
+ computeLineAndColumn(line, column);
+
+ traceBuild.append(':');
+ traceBuild.appendNumber(line);
+ traceBuild.append(':');
+ traceBuild.appendNumber(column);
+ }
+ }
+ return traceBuild.toString().impl();
+}
+
+class GetStackTraceFunctor {
+public:
+ GetStackTraceFunctor(VM& vm, Vector<StackFrame>& results, size_t remainingCapacity)
+ : m_vm(vm)
+ , m_results(results)
+ , m_remainingCapacityForFrameCapture(remainingCapacity)
+ {
+ }
+
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ VM& vm = m_vm;
+ if (m_remainingCapacityForFrameCapture) {
+ if (visitor->isJSFrame() && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) {
+ CodeBlock* codeBlock = visitor->codeBlock();
+ StackFrame s = {
+ Strong<JSObject>(vm, visitor->callee()),
+ getStackFrameCodeType(visitor),
+ Strong<ScriptExecutable>(vm, codeBlock->ownerExecutable()),
+ Strong<UnlinkedCodeBlock>(vm, codeBlock->unlinkedCodeBlock()),
+ codeBlock->source(),
+ codeBlock->ownerExecutable()->firstLine(),
+ codeBlock->firstLineColumnOffset(),
+ codeBlock->sourceOffset(),
+ visitor->bytecodeOffset(),
+ visitor->sourceURL()
+ };
+ m_results.append(s);
+ } else {
+ StackFrame s = { Strong<JSObject>(vm, visitor->callee()), StackFrameNativeCode, Strong<ScriptExecutable>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()};
+ m_results.append(s);
+ }
+
+ m_remainingCapacityForFrameCapture--;
+ return StackVisitor::Continue;
+ }
+ return StackVisitor::Done;
+ }
+
+private:
+ VM& m_vm;
+ Vector<StackFrame>& m_results;
+ size_t m_remainingCapacityForFrameCapture;
+};
+
+void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t maxStackSize)
+{
+ VM& vm = m_vm;
+ CallFrame* callFrame = vm.topCallFrame;
+ if (!callFrame)
+ return;
+
+ GetStackTraceFunctor functor(vm, results, maxStackSize);
+ callFrame->iterate(functor);
+}
+
+JSString* Interpreter::stackTraceAsString(ExecState* exec, Vector<StackFrame> stackTrace)
+{
+ // FIXME: JSStringJoiner could be more efficient than StringBuilder here.
+ StringBuilder builder;
+ for (unsigned i = 0; i < stackTrace.size(); i++) {
+ builder.append(String(stackTrace[i].toString(exec)));
+ if (i != stackTrace.size() - 1)
+ builder.append('\n');
+ }
+ return jsString(&exec->vm(), builder.toString());
+}
+
+class GetCatchHandlerFunctor {
+public:
+ GetCatchHandlerFunctor()
+ : m_handler(0)
+ {
+ }
+
+ HandlerInfo* handler() { return m_handler; }
+
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ CodeBlock* codeBlock = visitor->codeBlock();
+ if (!codeBlock)
+ return StackVisitor::Continue;
+
+ unsigned bytecodeOffset = visitor->bytecodeOffset();
+ m_handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset, CodeBlock::RequiredHandler::CatchHandler);
+ if (m_handler)
+ return StackVisitor::Done;
+
+ return StackVisitor::Continue;
+ }
+
+private:
+ HandlerInfo* m_handler;
+};
+
+class UnwindFunctor {
+public:
+ UnwindFunctor(VMEntryFrame*& vmEntryFrame, CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler)
+ : m_vmEntryFrame(vmEntryFrame)
+ , m_callFrame(callFrame)
+ , m_isTermination(isTermination)
+ , m_codeBlock(codeBlock)
+ , m_handler(handler)
+ {
+ }
+
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ VM& vm = m_callFrame->vm();
+ m_vmEntryFrame = visitor->vmEntryFrame();
+ m_callFrame = visitor->callFrame();
+ m_codeBlock = visitor->codeBlock();
+ unsigned bytecodeOffset = visitor->bytecodeOffset();
+
+ if (m_isTermination || !(m_handler = m_codeBlock ? m_codeBlock->handlerForBytecodeOffset(bytecodeOffset) : nullptr)) {
+ if (!unwindCallFrame(visitor)) {
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->exceptionUnwind(m_callFrame);
+ return StackVisitor::Done;
+ }
+ } else
+ return StackVisitor::Done;
+
+ return StackVisitor::Continue;
+ }
+
+private:
+ VMEntryFrame*& m_vmEntryFrame;
+ CallFrame*& m_callFrame;
+ bool m_isTermination;
+ CodeBlock*& m_codeBlock;
+ HandlerInfo*& m_handler;
+};
+
+NEVER_INLINE HandlerInfo* Interpreter::unwind(VMEntryFrame*& vmEntryFrame, CallFrame*& callFrame, Exception* exception)
+{
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ bool isTermination = false;
+
+ JSValue exceptionValue = exception->value();
+ ASSERT(!exceptionValue.isEmpty());
+ ASSERT(!exceptionValue.isCell() || exceptionValue.asCell());
+ // This shouldn't be possible (hence the assertions), but we're already in the slowest of
+ // slow cases, so let's harden against it anyway to be safe.
+ if (exceptionValue.isEmpty() || (exceptionValue.isCell() && !exceptionValue.asCell()))
+ exceptionValue = jsNull();
+
+ if (exceptionValue.isObject())
+ isTermination = isTerminatedExecutionException(exception);
+
+ ASSERT(callFrame->vm().exception() && callFrame->vm().exception()->stack().size());
+
+ Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger();
+ if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) {
+ // We need to clear the exception here in order to see if a new exception happens.
+ // Afterwards, the values are put back to continue processing this error.
+ SuspendExceptionScope scope(&callFrame->vm());
+ // This code assumes that if the debugger is enabled then there is no inlining.
+ // If that assumption turns out to be false then we'll ignore the inlined call
+ // frames.
+ // https://bugs.webkit.org/show_bug.cgi?id=121754
+
+ bool hasCatchHandler;
+ if (isTermination)
+ hasCatchHandler = false;
+ else {
+ GetCatchHandlerFunctor functor;
+ callFrame->iterate(functor);
+ HandlerInfo* handler = functor.handler();
+ ASSERT(!handler || handler->isCatchHandler());
+ hasCatchHandler = !!handler;
+ }
+
+ debugger->exception(callFrame, exceptionValue, hasCatchHandler);
+ ASSERT(!callFrame->hadException());
+ }
+ exception->setDidNotifyInspectorOfThrow();
+
+ // Calculate an exception handler vPC, unwinding call frames as necessary.
+ HandlerInfo* handler = 0;
+ VM& vm = callFrame->vm();
+ ASSERT(callFrame == vm.topCallFrame);
+ UnwindFunctor functor(vmEntryFrame, callFrame, isTermination, codeBlock, handler);
+ callFrame->iterate(functor);
+ if (!handler)
+ return 0;
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->exceptionUnwind(callFrame);
+
+ return handler;
+}
+
+static inline JSValue checkedReturn(JSValue returnValue)
+{
+ ASSERT(returnValue);
+ return returnValue;
+}
+
+static inline JSObject* checkedReturn(JSObject* returnValue)
+{
+ ASSERT(returnValue);
+ return returnValue;
+}
+
+class SamplingScope {
+public:
+ SamplingScope(Interpreter* interpreter)
+ : m_interpreter(interpreter)
+ {
+ interpreter->startSampling();
+ }
+ ~SamplingScope()
+ {
+ m_interpreter->stopSampling();
+ }
+private:
+ Interpreter* m_interpreter;
+};
+
+JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, JSObject* thisObj)
+{
+ SamplingScope samplingScope(this);
+
+ JSScope* scope = thisObj->globalObject();
+ VM& vm = *scope->vm();
+
+ ASSERT(!vm.exception());
+ ASSERT(!vm.isCollectorBusy());
+ RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
+ if (vm.isCollectorBusy())
+ return jsNull();
+
+ if (!vm.isSafeToRecurse())
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ // First check if the "program" is actually just a JSON object. If so,
+ // we'll handle the JSON object here. Else, we'll handle real JS code
+ // below at failedJSONP.
+
+ Vector<JSONPData> JSONPData;
+ bool parseResult;
+ const String programSource = program->source().toString();
+ if (programSource.isNull())
+ return jsUndefined();
+ if (programSource.is8Bit()) {
+ LiteralParser<LChar> literalParser(callFrame, programSource.characters8(), programSource.length(), JSONP);
+ parseResult = literalParser.tryJSONPParse(JSONPData, scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject()));
+ } else {
+ LiteralParser<UChar> literalParser(callFrame, programSource.characters16(), programSource.length(), JSONP);
+ parseResult = literalParser.tryJSONPParse(JSONPData, scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject()));
+ }
+
+ if (parseResult) {
+ JSGlobalObject* globalObject = scope->globalObject();
+ JSValue result;
+ for (unsigned entry = 0; entry < JSONPData.size(); entry++) {
+ Vector<JSONPPathEntry> JSONPPath;
+ JSONPPath.swap(JSONPData[entry].m_path);
+ JSValue JSONPValue = JSONPData[entry].m_value.get();
+ if (JSONPPath.size() == 1 && JSONPPath[0].m_type == JSONPPathEntryTypeDeclare) {
+ globalObject->addVar(callFrame, JSONPPath[0].m_pathEntryName);
+ PutPropertySlot slot(globalObject);
+ globalObject->methodTable()->put(globalObject, callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot);
+ result = jsUndefined();
+ continue;
+ }
+ JSValue baseObject(globalObject);
+ for (unsigned i = 0; i < JSONPPath.size() - 1; i++) {
+ ASSERT(JSONPPath[i].m_type != JSONPPathEntryTypeDeclare);
+ switch (JSONPPath[i].m_type) {
+ case JSONPPathEntryTypeDot: {
+ if (i == 0) {
+ PropertySlot slot(globalObject);
+ if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot)) {
+ if (entry)
+ return callFrame->vm().throwException(callFrame, createUndefinedVariableError(callFrame, JSONPPath[i].m_pathEntryName));
+ goto failedJSONP;
+ }
+ baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName);
+ } else
+ baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathEntryName);
+ if (callFrame->hadException())
+ return jsUndefined();
+ continue;
+ }
+ case JSONPPathEntryTypeLookup: {
+ baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathIndex);
+ if (callFrame->hadException())
+ return jsUndefined();
+ continue;
+ }
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return jsUndefined();
+ }
+ }
+ PutPropertySlot slot(baseObject);
+ switch (JSONPPath.last().m_type) {
+ case JSONPPathEntryTypeCall: {
+ JSValue function = baseObject.get(callFrame, JSONPPath.last().m_pathEntryName);
+ if (callFrame->hadException())
+ return jsUndefined();
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return callFrame->vm().throwException(callFrame, createNotAFunctionError(callFrame, function));
+ MarkedArgumentBuffer jsonArg;
+ jsonArg.append(JSONPValue);
+ JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined(): baseObject;
+ JSONPValue = JSC::call(callFrame, function, callType, callData, thisValue, jsonArg);
+ if (callFrame->hadException())
+ return jsUndefined();
+ break;
+ }
+ case JSONPPathEntryTypeDot: {
+ baseObject.put(callFrame, JSONPPath.last().m_pathEntryName, JSONPValue, slot);
+ if (callFrame->hadException())
+ return jsUndefined();
+ break;
+ }
+ case JSONPPathEntryTypeLookup: {
+ baseObject.putByIndex(callFrame, JSONPPath.last().m_pathIndex, JSONPValue, slot.isStrictMode());
+ if (callFrame->hadException())
+ return jsUndefined();
+ break;
+ }
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return jsUndefined();
+ }
+ result = JSONPValue;
+ }
+ return result;
+ }
+failedJSONP:
+ // If we get here, then we have already proven that the script is not a JSON
+ // object.
+
+ VMEntryScope entryScope(vm, scope->globalObject());
+
+ // Compile source to bytecode if necessary:
+ if (JSObject* error = program->initializeGlobalProperties(vm, callFrame, scope))
+ return checkedReturn(callFrame->vm().throwException(callFrame, error));
+
+ if (JSObject* error = program->prepareForExecution(callFrame, nullptr, scope, CodeForCall))
+ return checkedReturn(callFrame->vm().throwException(callFrame, error));
+
+ ProgramCodeBlock* codeBlock = program->codeBlock();
+
+ if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
+ return throwTerminatedExecutionException(callFrame);
+
+ ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
+
+ ProtoCallFrame protoCallFrame;
+ protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisObj, 1);
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->willExecute(callFrame, program->sourceURL(), program->firstLine(), program->startColumn());
+
+ // Execute the code:
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get());
+ result = program->generatedJITCode()->execute(&vm, &protoCallFrame);
+ }
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->didExecute(callFrame, program->sourceURL(), program->firstLine(), program->startColumn());
+
+ return checkedReturn(result);
+}
+
+JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
+{
+ VM& vm = callFrame->vm();
+ ASSERT(!callFrame->hadException());
+ ASSERT(!vm.isCollectorBusy());
+ if (vm.isCollectorBusy())
+ return jsNull();
+
+ bool isJSCall = (callType == CallTypeJS);
+ JSScope* scope = nullptr;
+ CodeBlock* newCodeBlock;
+ size_t argsCount = 1 + args.size(); // implicit "this" parameter
+
+ JSGlobalObject* globalObject;
+
+ if (isJSCall) {
+ scope = callData.js.scope;
+ globalObject = scope->globalObject();
+ } else {
+ ASSERT(callType == CallTypeHost);
+ globalObject = function->globalObject();
+ }
+
+ VMEntryScope entryScope(vm, globalObject);
+ if (!vm.isSafeToRecurse())
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ if (isJSCall) {
+ // Compile the callee:
+ JSObject* compileError = callData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(function), scope, CodeForCall);
+ if (UNLIKELY(!!compileError)) {
+ return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
+ }
+ newCodeBlock = callData.js.functionExecutable->codeBlockForCall();
+ ASSERT(!!newCodeBlock);
+ newCodeBlock->m_shouldAlwaysBeInlined = false;
+ } else
+ newCodeBlock = 0;
+
+ if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
+ return throwTerminatedExecutionException(callFrame);
+
+ ProtoCallFrame protoCallFrame;
+ protoCallFrame.init(newCodeBlock, function, thisValue, argsCount, args.data());
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->willExecute(callFrame, function);
+
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSCall);
+
+ // Execute the code:
+ if (isJSCall)
+ result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame);
+ else {
+ result = JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(callData.native.function), &vm, &protoCallFrame));
+ if (callFrame->hadException())
+ result = jsNull();
+ }
+ }
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->didExecute(callFrame, function);
+
+ return checkedReturn(result);
+}
+
+JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget)
+{
+ VM& vm = callFrame->vm();
+ ASSERT(!callFrame->hadException());
+ ASSERT(!vm.isCollectorBusy());
+ // We throw in this case because we have to return something "valid" but we're
+ // already in an invalid state.
+ if (vm.isCollectorBusy())
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ bool isJSConstruct = (constructType == ConstructTypeJS);
+ JSScope* scope = nullptr;
+ CodeBlock* newCodeBlock;
+ size_t argsCount = 1 + args.size(); // implicit "this" parameter
+
+ JSGlobalObject* globalObject;
+
+ if (isJSConstruct) {
+ scope = constructData.js.scope;
+ globalObject = scope->globalObject();
+ } else {
+ ASSERT(constructType == ConstructTypeHost);
+ globalObject = constructor->globalObject();
+ }
+
+ VMEntryScope entryScope(vm, globalObject);
+ if (!vm.isSafeToRecurse())
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ if (isJSConstruct) {
+ // Compile the callee:
+ JSObject* compileError = constructData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(constructor), scope, CodeForConstruct);
+ if (UNLIKELY(!!compileError)) {
+ return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
+ }
+ newCodeBlock = constructData.js.functionExecutable->codeBlockForConstruct();
+ ASSERT(!!newCodeBlock);
+ newCodeBlock->m_shouldAlwaysBeInlined = false;
+ } else
+ newCodeBlock = 0;
+
+ if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
+ return throwTerminatedExecutionException(callFrame);
+
+ ProtoCallFrame protoCallFrame;
+ protoCallFrame.init(newCodeBlock, constructor, newTarget, argsCount, args.data());
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->willExecute(callFrame, constructor);
+
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSConstruct);
+
+ // Execute the code.
+ if (isJSConstruct)
+ result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame);
+ else {
+ result = JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(constructData.native.function), &vm, &protoCallFrame));
+
+ if (!callFrame->hadException())
+ RELEASE_ASSERT(result.isObject());
+ }
+ }
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->didExecute(callFrame, constructor);
+
+ if (callFrame->hadException())
+ return 0;
+ ASSERT(result.isObject());
+ return checkedReturn(asObject(result));
+}
+
+CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, ProtoCallFrame* protoCallFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope, JSValue* args)
+{
+ VM& vm = *scope->vm();
+ ASSERT(!vm.exception());
+
+ if (vm.isCollectorBusy())
+ return CallFrameClosure();
+
+ // Compile the callee:
+ JSObject* error = functionExecutable->prepareForExecution(callFrame, function, scope, CodeForCall);
+ if (error) {
+ callFrame->vm().throwException(callFrame, error);
+ return CallFrameClosure();
+ }
+ CodeBlock* newCodeBlock = functionExecutable->codeBlockForCall();
+ newCodeBlock->m_shouldAlwaysBeInlined = false;
+
+ size_t argsCount = argumentCountIncludingThis;
+
+ protoCallFrame->init(newCodeBlock, function, jsUndefined(), argsCount, args);
+ // Return the successful closure:
+ CallFrameClosure result = { callFrame, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis };
+ return result;
+}
+
+JSValue Interpreter::execute(CallFrameClosure& closure)
+{
+ VM& vm = *closure.vm;
+ SamplingScope samplingScope(this);
+
+ ASSERT(!vm.isCollectorBusy());
+ RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
+ if (vm.isCollectorBusy())
+ return jsNull();
+
+ StackStats::CheckPoint stackCheckPoint;
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->willExecute(closure.oldCallFrame, closure.function);
+
+ if (UNLIKELY(vm.shouldTriggerTermination(closure.oldCallFrame)))
+ return throwTerminatedExecutionException(closure.oldCallFrame);
+
+ // Execute the code:
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get());
+ result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.protoCallFrame);
+ }
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->didExecute(closure.oldCallFrame, closure.function);
+
+ return checkedReturn(result);
+}
+
+JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, JSScope* scope)
+{
+ VM& vm = *scope->vm();
+ SamplingScope samplingScope(this);
+
+ ASSERT(scope->vm() == &callFrame->vm());
+ ASSERT(!vm.exception());
+ ASSERT(!vm.isCollectorBusy());
+ RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
+ if (vm.isCollectorBusy())
+ return jsNull();
+
+ VMEntryScope entryScope(vm, scope->globalObject());
+ if (!vm.isSafeToRecurse())
+ return checkedReturn(throwStackOverflowError(callFrame));
+
+ unsigned numVariables = eval->numVariables();
+ int numFunctions = eval->numberOfFunctionDecls();
+
+ JSScope* variableObject;
+ if ((numVariables || numFunctions) && eval->isStrictMode()) {
+ scope = StrictEvalActivation::create(callFrame, scope);
+ variableObject = scope;
+ } else {
+ for (JSScope* node = scope; ; node = node->next()) {
+ RELEASE_ASSERT(node);
+ if (node->isGlobalObject()) {
+ variableObject = node;
+ break;
+ }
+ if (JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(node)) {
+ if (lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::VarScope) {
+ variableObject = node;
+ break;
+ }
+ }
+ }
+ ASSERT(!variableObject->isNameScopeObject());
+ }
+
+ JSObject* compileError = eval->prepareForExecution(callFrame, nullptr, scope, CodeForCall);
+ if (UNLIKELY(!!compileError))
+ return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
+ EvalCodeBlock* codeBlock = eval->codeBlock();
+
+ if (numVariables || numFunctions) {
+ BatchedTransitionOptimizer optimizer(vm, variableObject);
+ if (variableObject->next())
+ variableObject->globalObject()->varInjectionWatchpoint()->fireAll("Executed eval, fired VarInjection watchpoint");
+
+ for (unsigned i = 0; i < numVariables; ++i) {
+ const Identifier& ident = codeBlock->variable(i);
+ if (!variableObject->hasProperty(callFrame, ident)) {
+ PutPropertySlot slot(variableObject);
+ variableObject->methodTable()->put(variableObject, callFrame, ident, jsUndefined(), slot);
+ }
+ }
+
+ for (int i = 0; i < numFunctions; ++i) {
+ FunctionExecutable* function = codeBlock->functionDecl(i);
+ PutPropertySlot slot(variableObject);
+ variableObject->methodTable()->put(variableObject, callFrame, function->name(), JSFunction::create(vm, function, scope), slot);
+ }
+ }
+
+ if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
+ return throwTerminatedExecutionException(callFrame);
+
+ ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
+
+ ProtoCallFrame protoCallFrame;
+ protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisValue, 1);
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->willExecute(callFrame, eval->sourceURL(), eval->firstLine(), eval->startColumn());
+
+ // Execute the code:
+ JSValue result;
+ {
+ SamplingTool::CallRecord callRecord(m_sampler.get());
+ result = eval->generatedJITCode()->execute(&vm, &protoCallFrame);
+ }
+
+ if (LegacyProfiler* profiler = vm.enabledProfiler())
+ profiler->didExecute(callFrame, eval->sourceURL(), eval->firstLine(), eval->startColumn());
+
+ return checkedReturn(result);
+}
+
+NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID)
+{
+ Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger();
+ if (!debugger)
+ return;
+
+ ASSERT(callFrame->codeBlock()->hasDebuggerRequests());
+ ASSERT(!callFrame->hadException());
+
+ switch (debugHookID) {
+ case DidEnterCallFrame:
+ debugger->callEvent(callFrame);
+ break;
+ case WillLeaveCallFrame:
+ debugger->returnEvent(callFrame);
+ break;
+ case WillExecuteStatement:
+ debugger->atStatement(callFrame);
+ break;
+ case WillExecuteProgram:
+ debugger->willExecuteProgram(callFrame);
+ break;
+ case DidExecuteProgram:
+ debugger->didExecuteProgram(callFrame);
+ break;
+ case DidReachBreakpoint:
+ debugger->didReachBreakpoint(callFrame);
+ break;
+ }
+ ASSERT(!callFrame->hadException());
+}
+
+void Interpreter::enableSampler()
+{
+#if ENABLE(OPCODE_SAMPLING)
+ if (!m_sampler) {
+ m_sampler = std::make_unique<SamplingTool>(this);
+ m_sampler->setup();
+ }
+#endif
+}
+void Interpreter::dumpSampleData(ExecState* exec)
+{
+#if ENABLE(OPCODE_SAMPLING)
+ if (m_sampler)
+ m_sampler->dump(exec);
+#else
+ UNUSED_PARAM(exec);
+#endif
+}
+void Interpreter::startSampling()
+{
+#if ENABLE(SAMPLING_THREAD)
+ if (!m_sampleEntryDepth)
+ SamplingThread::start();
+
+ m_sampleEntryDepth++;
+#endif
+}
+void Interpreter::stopSampling()
+{
+#if ENABLE(SAMPLING_THREAD)
+ m_sampleEntryDepth--;
+ if (!m_sampleEntryDepth)
+ SamplingThread::stop();
+#endif
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.h b/Source/JavaScriptCore/interpreter/Interpreter.h
new file mode 100644
index 000000000..ad9df6fc7
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/Interpreter.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2008, 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Interpreter_h
+#define Interpreter_h
+
+#include "ArgList.h"
+#include "JSCJSValue.h"
+#include "JSCell.h"
+#include "JSObject.h"
+#include "JSStack.h"
+#include "LLIntData.h"
+#include "Opcode.h"
+#include "SourceProvider.h"
+#include "StackAlignment.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace JSC {
+
+ class CodeBlock;
+ class EvalExecutable;
+ class ExecutableBase;
+ class FunctionExecutable;
+ class VM;
+ class JSFunction;
+ class JSGlobalObject;
+ class LLIntOffsetsExtractor;
+ class ProgramExecutable;
+ class Register;
+ class JSScope;
+ class SamplingTool;
+ struct CallFrameClosure;
+ struct HandlerInfo;
+ struct Instruction;
+ struct ProtoCallFrame;
+
+ enum DebugHookID {
+ WillExecuteProgram,
+ DidExecuteProgram,
+ DidEnterCallFrame,
+ DidReachBreakpoint,
+ WillLeaveCallFrame,
+ WillExecuteStatement
+ };
+
+ enum StackFrameCodeType {
+ StackFrameGlobalCode,
+ StackFrameEvalCode,
+ StackFrameFunctionCode,
+ StackFrameNativeCode
+ };
+
+ struct StackFrame {
+ Strong<JSObject> callee;
+ StackFrameCodeType codeType;
+ Strong<ScriptExecutable> executable;
+ Strong<UnlinkedCodeBlock> codeBlock;
+ RefPtr<SourceProvider> code;
+ int lineOffset;
+ unsigned firstLineColumnOffset;
+ unsigned characterOffset;
+ unsigned bytecodeOffset;
+ String sourceURL;
+ JS_EXPORT_PRIVATE String toString(CallFrame*);
+ String friendlySourceURL() const;
+ String friendlyFunctionName(CallFrame*) const;
+ JS_EXPORT_PRIVATE void computeLineAndColumn(unsigned& line, unsigned& column);
+
+ private:
+ void expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column);
+ };
+
+ class SuspendExceptionScope {
+ public:
+ SuspendExceptionScope(VM* vm)
+ : m_vm(vm)
+ {
+ oldException = vm->exception();
+ vm->clearException();
+ }
+ ~SuspendExceptionScope()
+ {
+ m_vm->setException(oldException);
+ }
+ private:
+ Exception* oldException;
+ VM* m_vm;
+ };
+
+ class TopCallFrameSetter {
+ public:
+ TopCallFrameSetter(VM& currentVM, CallFrame* callFrame)
+ : vm(currentVM)
+ , oldCallFrame(currentVM.topCallFrame)
+ {
+ currentVM.topCallFrame = callFrame;
+ }
+
+ ~TopCallFrameSetter()
+ {
+ vm.topCallFrame = oldCallFrame;
+ }
+ private:
+ VM& vm;
+ CallFrame* oldCallFrame;
+ };
+
+ class NativeCallFrameTracer {
+ public:
+ ALWAYS_INLINE NativeCallFrameTracer(VM* vm, CallFrame* callFrame)
+ {
+ ASSERT(vm);
+ ASSERT(callFrame);
+ vm->topCallFrame = callFrame;
+ }
+ };
+
+ class NativeCallFrameTracerWithRestore {
+ public:
+ ALWAYS_INLINE NativeCallFrameTracerWithRestore(VM* vm, VMEntryFrame* vmEntryFrame, CallFrame* callFrame)
+ : m_vm(vm)
+ {
+ ASSERT(vm);
+ ASSERT(callFrame);
+ m_savedTopVMEntryFrame = vm->topVMEntryFrame;
+ m_savedTopCallFrame = vm->topCallFrame;
+ vm->topVMEntryFrame = vmEntryFrame;
+ vm->topCallFrame = callFrame;
+ }
+
+ ALWAYS_INLINE ~NativeCallFrameTracerWithRestore()
+ {
+ m_vm->topVMEntryFrame = m_savedTopVMEntryFrame;
+ m_vm->topCallFrame = m_savedTopCallFrame;
+ }
+
+ private:
+ VM* m_vm;
+ VMEntryFrame* m_savedTopVMEntryFrame;
+ CallFrame* m_savedTopCallFrame;
+ };
+
+ class Interpreter {
+ WTF_MAKE_FAST_ALLOCATED;
+ friend class CachedCall;
+ friend class LLIntOffsetsExtractor;
+ friend class JIT;
+ friend class VM;
+
+ public:
+ Interpreter(VM &);
+ ~Interpreter();
+
+ void initialize(bool canUseJIT);
+
+ JSStack& stack() { return m_stack; }
+
+ Opcode getOpcode(OpcodeID id)
+ {
+ ASSERT(m_initialized);
+#if ENABLE(COMPUTED_GOTO_OPCODES)
+ return m_opcodeTable[id];
+#else
+ return id;
+#endif
+ }
+
+ OpcodeID getOpcodeID(Opcode opcode)
+ {
+ ASSERT(m_initialized);
+#if ENABLE(COMPUTED_GOTO_OPCODES)
+ ASSERT(isOpcode(opcode));
+ return m_opcodeIDTable.get(opcode);
+#else
+ return opcode;
+#endif
+ }
+
+ bool isOpcode(Opcode);
+
+ JSValue execute(ProgramExecutable*, CallFrame*, JSObject* thisObj);
+ JSValue executeCall(CallFrame*, JSObject* function, CallType, const CallData&, JSValue thisValue, const ArgList&);
+ JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
+ JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, JSScope*);
+
+ void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
+
+ SamplingTool* sampler() { return m_sampler.get(); }
+
+ NEVER_INLINE HandlerInfo* unwind(VMEntryFrame*&, CallFrame*&, Exception*);
+ NEVER_INLINE void debug(CallFrame*, DebugHookID);
+ JSString* stackTraceAsString(ExecState*, Vector<StackFrame>);
+
+ static EncodedJSValue JSC_HOST_CALL constructWithErrorConstructor(ExecState*);
+ static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState*);
+ static EncodedJSValue JSC_HOST_CALL constructWithNativeErrorConstructor(ExecState*);
+ static EncodedJSValue JSC_HOST_CALL callNativeErrorConstructor(ExecState*);
+
+ void dumpSampleData(ExecState* exec);
+ void startSampling();
+ void stopSampling();
+
+ JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*);
+
+ void getStackTrace(Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
+
+ private:
+ enum ExecutionFlag { Normal, InitializeAndReturn };
+
+ CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, ProtoCallFrame*, JSFunction*, int argumentCountIncludingThis, JSScope*, JSValue*);
+
+ JSValue execute(CallFrameClosure&);
+
+
+
+ void dumpRegisters(CallFrame*);
+
+ bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); }
+
+ void enableSampler();
+ int m_sampleEntryDepth;
+ std::unique_ptr<SamplingTool> m_sampler;
+
+ VM& m_vm;
+ JSStack m_stack;
+ int m_errorHandlingModeReentry;
+
+#if ENABLE(COMPUTED_GOTO_OPCODES)
+ Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling
+ HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
+#endif
+
+#if !ASSERT_DISABLED
+ bool m_initialized;
+#endif
+ };
+
+ JSValue eval(CallFrame*);
+
+ inline CallFrame* calleeFrameForVarargs(CallFrame* callFrame, unsigned numUsedStackSlots, unsigned argumentCountIncludingThis)
+ {
+ unsigned paddedCalleeFrameOffset = WTF::roundUpToMultipleOf(
+ stackAlignmentRegisters(),
+ numUsedStackSlots + argumentCountIncludingThis + JSStack::CallFrameHeaderSize);
+ return CallFrame::create(callFrame->registers() - paddedCalleeFrameOffset);
+ }
+
+ unsigned sizeOfVarargs(CallFrame* exec, JSValue arguments, uint32_t firstVarArgOffset);
+ static const unsigned maxArguments = 0x10000;
+ unsigned sizeFrameForVarargs(CallFrame* exec, JSStack*, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset);
+ void loadVarargs(CallFrame* execCaller, VirtualRegister firstElementDest, JSValue source, uint32_t offset, uint32_t length);
+ void setupVarargsFrame(CallFrame* execCaller, CallFrame* execCallee, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length);
+ void setupVarargsFrameAndSetThis(CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length);
+
+} // namespace JSC
+
+#endif // Interpreter_h
diff --git a/Source/JavaScriptCore/interpreter/JSStack.cpp b/Source/JavaScriptCore/interpreter/JSStack.cpp
new file mode 100644
index 000000000..d755aaa7d
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/JSStack.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2008, 2013, 2014, 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSStackInlines.h"
+
+#include "ConservativeRoots.h"
+#include "Interpreter.h"
+#include "JSCInlines.h"
+#include "Options.h"
+#include <wtf/Lock.h>
+
+namespace JSC {
+
+#if !ENABLE(JIT)
+static size_t committedBytesCount = 0;
+
+static StaticLock stackStatisticsMutex;
+#endif // !ENABLE(JIT)
+
+JSStack::JSStack(VM& vm)
+ : m_vm(vm)
+ , m_topCallFrame(vm.topCallFrame)
+#if !ENABLE(JIT)
+ , m_end(0)
+ , m_reservedZoneSizeInRegisters(0)
+#endif
+{
+#if !ENABLE(JIT)
+ size_t capacity = Options::maxPerThreadStackUsage();
+ ASSERT(capacity && isPageAligned(capacity));
+
+ m_reservation = PageReservation::reserve(WTF::roundUpToMultipleOf(commitSize, capacity), OSAllocator::JSVMStackPages);
+ setStackLimit(highAddress());
+ m_commitTop = highAddress();
+
+ m_lastStackTop = baseOfStack();
+#endif // !ENABLE(JIT)
+
+ m_topCallFrame = 0;
+}
+
+#if !ENABLE(JIT)
+JSStack::~JSStack()
+{
+ ptrdiff_t sizeToDecommit = reinterpret_cast<char*>(highAddress()) - reinterpret_cast<char*>(m_commitTop);
+ m_reservation.decommit(reinterpret_cast<void*>(m_commitTop), sizeToDecommit);
+ addToCommittedByteCount(-sizeToDecommit);
+ m_reservation.deallocate();
+}
+
+bool JSStack::growSlowCase(Register* newTopOfStack)
+{
+ Register* newTopOfStackWithReservedZone = newTopOfStack - m_reservedZoneSizeInRegisters;
+
+ // If we have already committed enough memory to satisfy this request,
+ // just update the end pointer and return.
+ if (newTopOfStackWithReservedZone >= m_commitTop) {
+ setStackLimit(newTopOfStack);
+ return true;
+ }
+
+ // Compute the chunk size of additional memory to commit, and see if we
+ // have it is still within our budget. If not, we'll fail to grow and
+ // return false.
+ ptrdiff_t delta = reinterpret_cast<char*>(m_commitTop) - reinterpret_cast<char*>(newTopOfStackWithReservedZone);
+ delta = WTF::roundUpToMultipleOf(commitSize, delta);
+ Register* newCommitTop = m_commitTop - (delta / sizeof(Register));
+ if (newCommitTop < reservationTop())
+ return false;
+
+ // Otherwise, the growth is still within our budget. Commit it and return true.
+ m_reservation.commit(newCommitTop, delta);
+ addToCommittedByteCount(delta);
+ m_commitTop = newCommitTop;
+ setStackLimit(newTopOfStack);
+ return true;
+}
+
+void JSStack::gatherConservativeRoots(ConservativeRoots& conservativeRoots)
+{
+ conservativeRoots.add(topOfStack() + 1, highAddress());
+}
+
+void JSStack::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks)
+{
+ conservativeRoots.add(topOfStack() + 1, highAddress(), jitStubRoutines, codeBlocks);
+}
+
+void JSStack::sanitizeStack()
+{
+#if !ASAN_ENABLED
+ ASSERT(topOfStack() <= baseOfStack());
+
+ if (m_lastStackTop < topOfStack()) {
+ char* begin = reinterpret_cast<char*>(m_lastStackTop + 1);
+ char* end = reinterpret_cast<char*>(topOfStack() + 1);
+ memset(begin, 0, end - begin);
+ }
+
+ m_lastStackTop = topOfStack();
+#endif
+}
+
+void JSStack::releaseExcessCapacity()
+{
+ Register* highAddressWithReservedZone = highAddress() - m_reservedZoneSizeInRegisters;
+ ptrdiff_t delta = reinterpret_cast<char*>(highAddressWithReservedZone) - reinterpret_cast<char*>(m_commitTop);
+ m_reservation.decommit(m_commitTop, delta);
+ addToCommittedByteCount(-delta);
+ m_commitTop = highAddressWithReservedZone;
+}
+
+void JSStack::addToCommittedByteCount(long byteCount)
+{
+ LockHolder locker(stackStatisticsMutex);
+ ASSERT(static_cast<long>(committedBytesCount) + byteCount > -1);
+ committedBytesCount += byteCount;
+}
+
+void JSStack::setReservedZoneSize(size_t reservedZoneSize)
+{
+ m_reservedZoneSizeInRegisters = reservedZoneSize / sizeof(Register);
+ if (m_commitTop >= (m_end + 1) - m_reservedZoneSizeInRegisters)
+ growSlowCase(m_end + 1);
+}
+#endif // !ENABLE(JIT)
+
+#if ENABLE(JIT)
+Register* JSStack::lowAddress() const
+{
+ ASSERT(wtfThreadData().stack().isGrowingDownward());
+ return reinterpret_cast<Register*>(m_vm.stackLimit());
+}
+
+Register* JSStack::highAddress() const
+{
+ ASSERT(wtfThreadData().stack().isGrowingDownward());
+ return reinterpret_cast<Register*>(wtfThreadData().stack().origin());
+}
+#endif // ENABLE(JIT)
+
+size_t JSStack::committedByteCount()
+{
+#if !ENABLE(JIT)
+ LockHolder locker(stackStatisticsMutex);
+ return committedBytesCount;
+#else
+ // When using the C stack, we don't know how many stack pages are actually
+ // committed. So, we use the current stack usage as an estimate.
+ ASSERT(wtfThreadData().stack().isGrowingDownward());
+ int8_t* current = reinterpret_cast<int8_t*>(&current);
+ int8_t* high = reinterpret_cast<int8_t*>(wtfThreadData().stack().origin());
+ return high - current;
+#endif
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/interpreter/JSStack.h b/Source/JavaScriptCore/interpreter/JSStack.h
new file mode 100644
index 000000000..07cbbe69b
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/JSStack.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2008, 2009, 2013, 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSStack_h
+#define JSStack_h
+
+#include "ExecutableAllocator.h"
+#include "Register.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/PageReservation.h>
+#include <wtf/VMTags.h>
+
+namespace JSC {
+
+ class CodeBlockSet;
+ class ConservativeRoots;
+ class ExecState;
+ class JITStubRoutineSet;
+ class VM;
+ class LLIntOffsetsExtractor;
+
+ struct Instruction;
+ typedef ExecState CallFrame;
+
+ struct CallerFrameAndPC {
+ CallFrame* callerFrame;
+ Instruction* pc;
+ };
+
+ class JSStack {
+ WTF_MAKE_NONCOPYABLE(JSStack);
+ public:
+ enum CallFrameHeaderEntry {
+ CallerFrameAndPCSize = sizeof(CallerFrameAndPC) / sizeof(Register),
+ CodeBlock = CallerFrameAndPCSize,
+ Callee,
+ ArgumentCount,
+ CallFrameHeaderSize,
+
+ // The following entries are not part of the CallFrameHeader but are provided here as a convenience:
+ ThisArgument = CallFrameHeaderSize,
+ FirstArgument,
+ };
+
+ static const size_t commitSize = 16 * 1024;
+ // Allow 8k of excess registers before we start trying to reap the stack
+ static const ptrdiff_t maxExcessCapacity = 8 * 1024;
+
+ JSStack(VM&);
+
+ bool ensureCapacityFor(Register* newTopOfStack);
+
+ bool containsAddress(Register* address) { return (lowAddress() <= address && address < highAddress()); }
+ static size_t committedByteCount();
+
+#if ENABLE(JIT)
+ void gatherConservativeRoots(ConservativeRoots&) { }
+ void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&) { }
+ void sanitizeStack() { }
+#else
+ ~JSStack();
+
+ void gatherConservativeRoots(ConservativeRoots&);
+ void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&);
+ void sanitizeStack();
+
+ Register* baseOfStack() const
+ {
+ return highAddress() - 1;
+ }
+
+ size_t size() const { return highAddress() - lowAddress(); }
+
+ void setReservedZoneSize(size_t);
+
+ inline Register* topOfStack();
+#endif // ENABLE(JIT)
+
+ private:
+
+#if !ENABLE(JIT)
+ Register* lowAddress() const
+ {
+ return m_end + 1;
+ }
+
+ Register* highAddress() const
+ {
+ return reinterpret_cast_ptr<Register*>(static_cast<char*>(m_reservation.base()) + m_reservation.size());
+ }
+#else
+ Register* lowAddress() const;
+ Register* highAddress() const;
+#endif // !ENABLE(JIT)
+
+#if !ENABLE(JIT)
+ inline Register* topOfFrameFor(CallFrame*);
+
+ Register* reservationTop() const
+ {
+ char* reservationTop = static_cast<char*>(m_reservation.base());
+ return reinterpret_cast_ptr<Register*>(reservationTop);
+ }
+
+ bool grow(Register* newTopOfStack);
+ bool growSlowCase(Register* newTopOfStack);
+ void shrink(Register* newTopOfStack);
+ void releaseExcessCapacity();
+ void addToCommittedByteCount(long);
+
+ void setStackLimit(Register* newTopOfStack);
+#endif // !ENABLE(JIT)
+
+ VM& m_vm;
+ CallFrame*& m_topCallFrame;
+#if !ENABLE(JIT)
+ Register* m_end;
+ Register* m_commitTop;
+ PageReservation m_reservation;
+ Register* m_lastStackTop;
+ ptrdiff_t m_reservedZoneSizeInRegisters;
+#endif // !ENABLE(JIT)
+
+ friend class LLIntOffsetsExtractor;
+ };
+
+} // namespace JSC
+
+#endif // JSStack_h
diff --git a/Source/JavaScriptCore/interpreter/JSStackInlines.h b/Source/JavaScriptCore/interpreter/JSStackInlines.h
new file mode 100644
index 000000000..69508ab5d
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/JSStackInlines.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSStackInlines_h
+#define JSStackInlines_h
+
+#include "CallFrame.h"
+#include "CodeBlock.h"
+#include "JSStack.h"
+#include "VM.h"
+
+namespace JSC {
+
+inline bool JSStack::ensureCapacityFor(Register* newTopOfStack)
+{
+#if !ENABLE(JIT)
+ return grow(newTopOfStack);
+#else
+ ASSERT(wtfThreadData().stack().isGrowingDownward());
+ return newTopOfStack >= m_vm.stackLimit();
+#endif
+}
+
+#if !ENABLE(JIT)
+
+inline Register* JSStack::topOfFrameFor(CallFrame* frame)
+{
+ if (UNLIKELY(!frame))
+ return baseOfStack();
+ return frame->topOfFrame() - 1;
+}
+
+inline Register* JSStack::topOfStack()
+{
+ return topOfFrameFor(m_topCallFrame);
+}
+
+inline void JSStack::shrink(Register* newTopOfStack)
+{
+ Register* newEnd = newTopOfStack - 1;
+ if (newEnd >= m_end)
+ return;
+ setStackLimit(newTopOfStack);
+ // Note: Clang complains of an unresolved linkage to maxExcessCapacity if
+ // invoke std::max() with it as an argument. To work around this, we first
+ // assign the constant to a local variable, and use the local instead.
+ ptrdiff_t maxExcessCapacity = JSStack::maxExcessCapacity;
+ ptrdiff_t maxExcessInRegisters = std::max(maxExcessCapacity, m_reservedZoneSizeInRegisters);
+ if (m_end == baseOfStack() && (highAddress() - m_commitTop) >= maxExcessInRegisters)
+ releaseExcessCapacity();
+}
+
+inline bool JSStack::grow(Register* newTopOfStack)
+{
+ Register* newEnd = newTopOfStack - 1;
+ if (newEnd >= m_end)
+ return true;
+ return growSlowCase(newTopOfStack);
+}
+
+inline void JSStack::setStackLimit(Register* newTopOfStack)
+{
+ Register* newEnd = newTopOfStack - 1;
+ m_end = newEnd;
+ m_vm.setJSStackLimit(newTopOfStack);
+}
+
+#endif // !ENABLE(JIT)
+
+} // namespace JSC
+
+#endif // JSStackInlines_h
diff --git a/Source/JavaScriptCore/interpreter/ProtoCallFrame.cpp b/Source/JavaScriptCore/interpreter/ProtoCallFrame.cpp
new file mode 100644
index 000000000..eb80b2c23
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/ProtoCallFrame.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ProtoCallFrame.h"
+
+#include "CodeBlock.h"
+#include "JSCInlines.h"
+#include "StackAlignment.h"
+
+namespace JSC {
+
+void ProtoCallFrame::init(CodeBlock* codeBlock, JSObject* callee, JSValue thisValue, int argCountIncludingThis, JSValue* otherArgs)
+{
+ this->args = otherArgs;
+ this->setCodeBlock(codeBlock);
+ this->setCallee(callee);
+ this->setArgumentCountIncludingThis(argCountIncludingThis);
+ if (codeBlock && argCountIncludingThis < codeBlock->numParameters())
+ this->arityMissMatch = true;
+ else
+ this->arityMissMatch = false;
+
+ // Round up argCountIncludingThis to keep the stack frame size aligned.
+ size_t paddedArgsCount = roundArgumentCountToAlignFrame(argCountIncludingThis);
+ this->setPaddedArgCount(paddedArgsCount);
+ this->clearCurrentVPC();
+ this->setThisValue(thisValue);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/interpreter/ProtoCallFrame.h b/Source/JavaScriptCore/interpreter/ProtoCallFrame.h
new file mode 100644
index 000000000..af33a3072
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/ProtoCallFrame.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ProtoCallFrame_h
+#define ProtoCallFrame_h
+
+#include "Register.h"
+
+namespace JSC {
+
+struct ProtoCallFrame {
+ Register codeBlockValue;
+ Register calleeValue;
+ Register argCountAndCodeOriginValue;
+ Register thisArg;
+ uint32_t paddedArgCount;
+ bool arityMissMatch;
+ JSValue *args;
+
+ void init(CodeBlock*, JSObject*, JSValue, int, JSValue* otherArgs = 0);
+
+ CodeBlock* codeBlock() const { return codeBlockValue.Register::codeBlock(); }
+ void setCodeBlock(CodeBlock* codeBlock) { codeBlockValue = codeBlock; }
+
+ JSObject* callee() const { return calleeValue.Register::object(); }
+ void setCallee(JSObject* callee) { calleeValue = callee; }
+
+ int argumentCountIncludingThis() const { return argCountAndCodeOriginValue.payload(); }
+ int argumentCount() const { return argumentCountIncludingThis() - 1; }
+ void setArgumentCountIncludingThis(int count) { argCountAndCodeOriginValue.payload() = count; }
+ void setPaddedArgCount(uint32_t argCount) { paddedArgCount = argCount; }
+
+ void clearCurrentVPC() { argCountAndCodeOriginValue.tag() = 0; }
+
+ JSValue thisValue() const { return thisArg.Register::jsValue(); }
+ void setThisValue(JSValue value) { thisArg = value; }
+
+ bool needArityCheck() { return arityMissMatch; }
+
+ JSValue argument(size_t argumentIndex)
+ {
+ ASSERT(static_cast<int>(argumentIndex) < argumentCount());
+ return args[argumentIndex];
+ }
+ void setArgument(size_t argumentIndex, JSValue value)
+ {
+ ASSERT(static_cast<int>(argumentIndex) < argumentCount());
+ args[argumentIndex] = value;
+ }
+};
+
+} // namespace JSC
+
+#endif // ProtoCallFrame_h
diff --git a/Source/JavaScriptCore/interpreter/Register.h b/Source/JavaScriptCore/interpreter/Register.h
new file mode 100644
index 000000000..71ead7d2f
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/Register.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Register_h
+#define Register_h
+
+#include "JSCJSValue.h"
+#include <wtf/Assertions.h>
+#include <wtf/VectorTraits.h>
+
+namespace JSC {
+
+ class CodeBlock;
+ class ExecState;
+ class JSLexicalEnvironment;
+ class JSObject;
+ class JSScope;
+
+ typedef ExecState CallFrame;
+
+ class Register {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ Register();
+
+ Register(const JSValue&);
+ Register& operator=(const JSValue&);
+ JSValue jsValue() const;
+ JSValue asanUnsafeJSValue() const;
+ EncodedJSValue encodedJSValue() const;
+
+ Register& operator=(CallFrame*);
+ Register& operator=(CodeBlock*);
+ Register& operator=(JSScope*);
+ Register& operator=(JSObject*);
+
+ int32_t i() const;
+ JSLexicalEnvironment* lexicalEnvironment() const;
+ CallFrame* callFrame() const;
+ CodeBlock* codeBlock() const;
+ JSObject* object() const;
+ JSScope* scope() const;
+ int32_t unboxedInt32() const;
+ int64_t unboxedInt52() const;
+ int64_t unboxedStrictInt52() const;
+ bool unboxedBoolean() const;
+ double unboxedDouble() const;
+ JSCell* unboxedCell() const;
+ int32_t payload() const;
+ int32_t tag() const;
+ int32_t& payload();
+ int32_t& tag();
+
+ static Register withInt(int32_t i)
+ {
+ Register r = jsNumber(i);
+ return r;
+ }
+
+ private:
+ union {
+ EncodedJSValue value;
+ CallFrame* callFrame;
+ CodeBlock* codeBlock;
+ EncodedValueDescriptor encodedValue;
+ double number;
+ int64_t integer;
+ } u;
+ };
+
+ ALWAYS_INLINE Register::Register()
+ {
+#ifndef NDEBUG
+ *this = JSValue();
+#endif
+ }
+
+ ALWAYS_INLINE Register::Register(const JSValue& v)
+ {
+ u.value = JSValue::encode(v);
+ }
+
+ ALWAYS_INLINE Register& Register::operator=(const JSValue& v)
+ {
+ u.value = JSValue::encode(v);
+ return *this;
+ }
+
+ // FIXME (rdar://problem/19379214): ASan only needs to be suppressed for Register::jsValue() when called from prepareOSREntry(), but there is currently no way to express this short of adding a separate copy of the function.
+ SUPPRESS_ASAN ALWAYS_INLINE JSValue Register::asanUnsafeJSValue() const
+ {
+ return JSValue::decode(u.value);
+ }
+
+ ALWAYS_INLINE JSValue Register::jsValue() const
+ {
+ return JSValue::decode(u.value);
+ }
+
+ ALWAYS_INLINE EncodedJSValue Register::encodedJSValue() const
+ {
+ return u.value;
+ }
+
+ // Interpreter functions
+
+ ALWAYS_INLINE Register& Register::operator=(CallFrame* callFrame)
+ {
+ u.callFrame = callFrame;
+ return *this;
+ }
+
+ ALWAYS_INLINE Register& Register::operator=(CodeBlock* codeBlock)
+ {
+ u.codeBlock = codeBlock;
+ return *this;
+ }
+
+ ALWAYS_INLINE int32_t Register::i() const
+ {
+ return jsValue().asInt32();
+ }
+
+ ALWAYS_INLINE CallFrame* Register::callFrame() const
+ {
+ return u.callFrame;
+ }
+
+ ALWAYS_INLINE CodeBlock* Register::codeBlock() const
+ {
+ return u.codeBlock;
+ }
+
+ ALWAYS_INLINE int32_t Register::unboxedInt32() const
+ {
+ return payload();
+ }
+
+ ALWAYS_INLINE int64_t Register::unboxedInt52() const
+ {
+ return u.integer >> JSValue::int52ShiftAmount;
+ }
+
+ ALWAYS_INLINE int64_t Register::unboxedStrictInt52() const
+ {
+ return u.integer;
+ }
+
+ ALWAYS_INLINE bool Register::unboxedBoolean() const
+ {
+ return !!payload();
+ }
+
+ ALWAYS_INLINE double Register::unboxedDouble() const
+ {
+ return u.number;
+ }
+
+ ALWAYS_INLINE JSCell* Register::unboxedCell() const
+ {
+#if USE(JSVALUE64)
+ return u.encodedValue.ptr;
+#else
+ return bitwise_cast<JSCell*>(payload());
+#endif
+ }
+
+ ALWAYS_INLINE int32_t Register::payload() const
+ {
+ return u.encodedValue.asBits.payload;
+ }
+
+ ALWAYS_INLINE int32_t Register::tag() const
+ {
+ return u.encodedValue.asBits.tag;
+ }
+
+ ALWAYS_INLINE int32_t& Register::payload()
+ {
+ return u.encodedValue.asBits.payload;
+ }
+
+ ALWAYS_INLINE int32_t& Register::tag()
+ {
+ return u.encodedValue.asBits.tag;
+ }
+
+} // namespace JSC
+
+namespace WTF {
+
+ template<> struct VectorTraits<JSC::Register> : VectorTraitsBase<true, JSC::Register> { };
+
+} // namespace WTF
+
+#endif // Register_h
diff --git a/Source/JavaScriptCore/interpreter/StackVisitor.cpp b/Source/JavaScriptCore/interpreter/StackVisitor.cpp
new file mode 100644
index 000000000..6fe792b7e
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/StackVisitor.cpp
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StackVisitor.h"
+
+#include "CallFrameInlines.h"
+#include "ClonedArguments.h"
+#include "Executable.h"
+#include "Interpreter.h"
+#include "JSCInlines.h"
+#include <wtf/DataLog.h>
+
+namespace JSC {
+
+StackVisitor::StackVisitor(CallFrame* startFrame)
+{
+ m_frame.m_index = 0;
+ CallFrame* topFrame;
+ if (startFrame) {
+ m_frame.m_VMEntryFrame = startFrame->vm().topVMEntryFrame;
+ topFrame = startFrame->vm().topCallFrame;
+ } else {
+ m_frame.m_VMEntryFrame = 0;
+ topFrame = 0;
+ }
+ m_frame.m_callerIsVMEntryFrame = false;
+ readFrame(topFrame);
+
+ // Find the frame the caller wants to start unwinding from.
+ while (m_frame.callFrame() && m_frame.callFrame() != startFrame)
+ gotoNextFrame();
+}
+
+void StackVisitor::gotoNextFrame()
+{
+#if ENABLE(DFG_JIT)
+ if (m_frame.isInlinedFrame()) {
+ InlineCallFrame* inlineCallFrame = m_frame.inlineCallFrame();
+ CodeOrigin* callerCodeOrigin = &inlineCallFrame->caller;
+ readInlinedFrame(m_frame.callFrame(), callerCodeOrigin);
+ return;
+ }
+#endif // ENABLE(DFG_JIT)
+ m_frame.m_VMEntryFrame = m_frame.m_CallerVMEntryFrame;
+ readFrame(m_frame.callerFrame());
+}
+
+void StackVisitor::readFrame(CallFrame* callFrame)
+{
+ if (!callFrame) {
+ m_frame.setToEnd();
+ return;
+ }
+
+#if !ENABLE(DFG_JIT)
+ readNonInlinedFrame(callFrame);
+
+#else // !ENABLE(DFG_JIT)
+ // If the frame doesn't have a code block, then it's not a DFG frame.
+ // Hence, we're not at an inlined frame.
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ if (!codeBlock) {
+ readNonInlinedFrame(callFrame);
+ return;
+ }
+
+ // If the code block does not have any code origins, then there's no
+ // inlining. Hence, we're not at an inlined frame.
+ if (!codeBlock->hasCodeOrigins()) {
+ readNonInlinedFrame(callFrame);
+ return;
+ }
+
+ unsigned index = callFrame->locationAsCodeOriginIndex();
+ ASSERT(codeBlock->canGetCodeOrigin(index));
+ if (!codeBlock->canGetCodeOrigin(index)) {
+ // See assertion above. In release builds, we try to protect ourselves
+ // from crashing even though stack walking will be goofed up.
+ m_frame.setToEnd();
+ return;
+ }
+
+ CodeOrigin codeOrigin = codeBlock->codeOrigin(index);
+ if (!codeOrigin.inlineCallFrame) {
+ readNonInlinedFrame(callFrame, &codeOrigin);
+ return;
+ }
+
+ readInlinedFrame(callFrame, &codeOrigin);
+#endif // !ENABLE(DFG_JIT)
+}
+
+void StackVisitor::readNonInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
+{
+ m_frame.m_callFrame = callFrame;
+ m_frame.m_argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
+ m_frame.m_CallerVMEntryFrame = m_frame.m_VMEntryFrame;
+ m_frame.m_callerFrame = callFrame->callerFrame(m_frame.m_CallerVMEntryFrame);
+ m_frame.m_callerIsVMEntryFrame = m_frame.m_CallerVMEntryFrame != m_frame.m_VMEntryFrame;
+ m_frame.m_callee = callFrame->callee();
+ m_frame.m_codeBlock = callFrame->codeBlock();
+ m_frame.m_bytecodeOffset = !m_frame.codeBlock() ? 0
+ : codeOrigin ? codeOrigin->bytecodeIndex
+ : callFrame->locationAsBytecodeOffset();
+#if ENABLE(DFG_JIT)
+ m_frame.m_inlineCallFrame = 0;
+#endif
+}
+
+#if ENABLE(DFG_JIT)
+static int inlinedFrameOffset(CodeOrigin* codeOrigin)
+{
+ InlineCallFrame* inlineCallFrame = codeOrigin->inlineCallFrame;
+ int frameOffset = inlineCallFrame ? inlineCallFrame->stackOffset : 0;
+ return frameOffset;
+}
+
+void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
+{
+ ASSERT(codeOrigin);
+
+ int frameOffset = inlinedFrameOffset(codeOrigin);
+ bool isInlined = !!frameOffset;
+ if (isInlined) {
+ InlineCallFrame* inlineCallFrame = codeOrigin->inlineCallFrame;
+
+ m_frame.m_callFrame = callFrame;
+ m_frame.m_inlineCallFrame = inlineCallFrame;
+ if (inlineCallFrame->argumentCountRegister.isValid())
+ m_frame.m_argumentCountIncludingThis = callFrame->r(inlineCallFrame->argumentCountRegister.offset()).unboxedInt32();
+ else
+ m_frame.m_argumentCountIncludingThis = inlineCallFrame->arguments.size();
+ m_frame.m_codeBlock = inlineCallFrame->baselineCodeBlock();
+ m_frame.m_bytecodeOffset = codeOrigin->bytecodeIndex;
+
+ JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame);
+ m_frame.m_callee = callee;
+ ASSERT(m_frame.callee());
+
+ // The callerFrame just needs to be non-null to indicate that we
+ // haven't reached the last frame yet. Setting it to the root
+ // frame (i.e. the callFrame that this inlined frame is called from)
+ // would work just fine.
+ m_frame.m_callerFrame = callFrame;
+ return;
+ }
+
+ readNonInlinedFrame(callFrame, codeOrigin);
+}
+#endif // ENABLE(DFG_JIT)
+
+StackVisitor::Frame::CodeType StackVisitor::Frame::codeType() const
+{
+ if (!isJSFrame())
+ return CodeType::Native;
+
+ switch (codeBlock()->codeType()) {
+ case EvalCode:
+ return CodeType::Eval;
+ case FunctionCode:
+ return CodeType::Function;
+ case GlobalCode:
+ return CodeType::Global;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return CodeType::Global;
+}
+
+String StackVisitor::Frame::functionName()
+{
+ String traceLine;
+ JSObject* callee = this->callee();
+
+ switch (codeType()) {
+ case CodeType::Eval:
+ traceLine = ASCIILiteral("eval code");
+ break;
+ case CodeType::Native:
+ if (callee)
+ traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
+ break;
+ case CodeType::Function:
+ traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
+ break;
+ case CodeType::Global:
+ traceLine = ASCIILiteral("global code");
+ break;
+ }
+ return traceLine.isNull() ? emptyString() : traceLine;
+}
+
+String StackVisitor::Frame::sourceURL()
+{
+ String traceLine;
+
+ switch (codeType()) {
+ case CodeType::Eval:
+ case CodeType::Function:
+ case CodeType::Global: {
+ String sourceURL = codeBlock()->ownerExecutable()->sourceURL();
+ if (!sourceURL.isEmpty())
+ traceLine = sourceURL.impl();
+ break;
+ }
+ case CodeType::Native:
+ traceLine = ASCIILiteral("[native code]");
+ break;
+ }
+ return traceLine.isNull() ? emptyString() : traceLine;
+}
+
+String StackVisitor::Frame::toString()
+{
+ StringBuilder traceBuild;
+ String functionName = this->functionName();
+ String sourceURL = this->sourceURL();
+ traceBuild.append(functionName);
+ if (!sourceURL.isEmpty()) {
+ if (!functionName.isEmpty())
+ traceBuild.append('@');
+ traceBuild.append(sourceURL);
+ if (isJSFrame()) {
+ unsigned line = 0;
+ unsigned column = 0;
+ computeLineAndColumn(line, column);
+ traceBuild.append(':');
+ traceBuild.appendNumber(line);
+ traceBuild.append(':');
+ traceBuild.appendNumber(column);
+ }
+ }
+ return traceBuild.toString().impl();
+}
+
+ClonedArguments* StackVisitor::Frame::createArguments()
+{
+ ASSERT(m_callFrame);
+ CallFrame* physicalFrame = m_callFrame;
+ ClonedArguments* arguments;
+ ArgumentsMode mode;
+ if (Options::enableFunctionDotArguments())
+ mode = ArgumentsMode::Cloned;
+ else
+ mode = ArgumentsMode::FakeValues;
+#if ENABLE(DFG_JIT)
+ if (isInlinedFrame()) {
+ ASSERT(m_inlineCallFrame);
+ arguments = ClonedArguments::createWithInlineFrame(physicalFrame, physicalFrame, m_inlineCallFrame, mode);
+ } else
+#endif
+ arguments = ClonedArguments::createWithMachineFrame(physicalFrame, physicalFrame, mode);
+ return arguments;
+}
+
+void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column)
+{
+ CodeBlock* codeBlock = this->codeBlock();
+ if (!codeBlock) {
+ line = 0;
+ column = 0;
+ return;
+ }
+
+ int divot = 0;
+ int unusedStartOffset = 0;
+ int unusedEndOffset = 0;
+ unsigned divotLine = 0;
+ unsigned divotColumn = 0;
+ retrieveExpressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn);
+
+ line = divotLine + codeBlock->ownerExecutable()->firstLine();
+ column = divotColumn + (divotLine ? 1 : codeBlock->firstLineColumnOffset());
+
+ if (codeBlock->ownerExecutable()->hasOverrideLineNumber())
+ line = codeBlock->ownerExecutable()->overrideLineNumber();
+}
+
+void StackVisitor::Frame::retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
+{
+ CodeBlock* codeBlock = this->codeBlock();
+ codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeOffset(bytecodeOffset(), divot, startOffset, endOffset, line, column);
+ divot += codeBlock->sourceOffset();
+}
+
+void StackVisitor::Frame::setToEnd()
+{
+ m_callFrame = 0;
+#if ENABLE(DFG_JIT)
+ m_inlineCallFrame = 0;
+#endif
+}
+
+static void printIndents(int levels)
+{
+ while (levels--)
+ dataLogFString(" ");
+}
+
+template<typename... Types>
+void log(unsigned indent, const Types&... values)
+{
+ printIndents(indent);
+ dataLog(values...);
+}
+
+template<typename... Types>
+void logF(unsigned indent, const char* format, const Types&... values)
+{
+ printIndents(indent);
+
+#if COMPILER(GCC_OR_CLANG)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
+#endif
+
+ dataLogF(format, values...);
+
+#if COMPILER(GCC_OR_CLANG)
+#pragma GCC diagnostic pop
+#endif
+}
+
+void StackVisitor::Frame::print(int indent)
+{
+ if (!this->callFrame()) {
+ log(indent, "frame 0x0\n");
+ return;
+ }
+
+ CodeBlock* codeBlock = this->codeBlock();
+ logF(indent, "frame %p {\n", this->callFrame());
+
+ {
+ indent++;
+
+ CallFrame* callFrame = m_callFrame;
+ CallFrame* callerFrame = this->callerFrame();
+ void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;
+
+ log(indent, "name: ", functionName(), "\n");
+ log(indent, "sourceURL: ", sourceURL(), "\n");
+
+ bool isInlined = false;
+#if ENABLE(DFG_JIT)
+ isInlined = isInlinedFrame();
+ log(indent, "isInlinedFrame: ", isInlinedFrame(), "\n");
+ if (isInlinedFrame())
+ logF(indent, "InlineCallFrame: %p\n", m_inlineCallFrame);
+#endif
+
+ logF(indent, "callee: %p\n", callee());
+ logF(indent, "returnPC: %p\n", returnPC);
+ logF(indent, "callerFrame: %p\n", callerFrame);
+ unsigned locationRawBits = callFrame->locationAsRawBits();
+ logF(indent, "rawLocationBits: %u 0x%x\n", locationRawBits, locationRawBits);
+ logF(indent, "codeBlock: %p ", codeBlock);
+ if (codeBlock)
+ dataLog(*codeBlock);
+ dataLog("\n");
+ if (codeBlock && !isInlined) {
+ indent++;
+
+ if (callFrame->hasLocationAsBytecodeOffset()) {
+ unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset();
+ log(indent, "bytecodeOffset: ", bytecodeOffset, " of ", codeBlock->instructions().size(), "\n");
+#if ENABLE(DFG_JIT)
+ } else {
+ log(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n");
+ if (codeBlock->hasCodeOrigins()) {
+ unsigned codeOriginIndex = callFrame->locationAsCodeOriginIndex();
+ log(indent, "codeOriginIndex: ", codeOriginIndex, " of ", codeBlock->codeOrigins().size(), "\n");
+
+ JITCode::JITType jitType = codeBlock->jitType();
+ if (jitType != JITCode::FTLJIT) {
+ JITCode* jitCode = codeBlock->jitCode().get();
+ logF(indent, "jitCode: %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end());
+ }
+ }
+#endif
+ }
+ unsigned line = 0;
+ unsigned column = 0;
+ computeLineAndColumn(line, column);
+ log(indent, "line: ", line, "\n");
+ log(indent, "column: ", column, "\n");
+
+ indent--;
+ }
+ indent--;
+ }
+ log(indent, "}\n");
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/interpreter/StackVisitor.h b/Source/JavaScriptCore/interpreter/StackVisitor.h
new file mode 100644
index 000000000..0036a789c
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/StackVisitor.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StackVisitor_h
+#define StackVisitor_h
+
+#include "VMEntryRecord.h"
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+struct CodeOrigin;
+struct InlineCallFrame;
+
+class CodeBlock;
+class ExecState;
+class JSFunction;
+class JSObject;
+class JSScope;
+class ClonedArguments;
+class Register;
+
+typedef ExecState CallFrame;
+
+class StackVisitor {
+public:
+ class Frame {
+ public:
+ enum CodeType {
+ Global,
+ Eval,
+ Function,
+ Native
+ };
+
+ size_t index() const { return m_index; }
+ size_t argumentCountIncludingThis() const { return m_argumentCountIncludingThis; }
+ bool callerIsVMEntryFrame() const { return m_callerIsVMEntryFrame; }
+ CallFrame* callerFrame() const { return m_callerFrame; }
+ JSObject* callee() const { return m_callee; }
+ CodeBlock* codeBlock() const { return m_codeBlock; }
+ unsigned bytecodeOffset() const { return m_bytecodeOffset; }
+#if ENABLE(DFG_JIT)
+ InlineCallFrame* inlineCallFrame() const { return m_inlineCallFrame; }
+#endif
+
+ bool isJSFrame() const { return !!codeBlock(); }
+#if ENABLE(DFG_JIT)
+ bool isInlinedFrame() const { return !!m_inlineCallFrame; }
+#endif
+
+ JS_EXPORT_PRIVATE String functionName();
+ JS_EXPORT_PRIVATE String sourceURL();
+ JS_EXPORT_PRIVATE String toString();
+
+ CodeType codeType() const;
+ JS_EXPORT_PRIVATE void computeLineAndColumn(unsigned& line, unsigned& column);
+
+ ClonedArguments* createArguments();
+ VMEntryFrame* vmEntryFrame() const { return m_VMEntryFrame; }
+ CallFrame* callFrame() const { return m_callFrame; }
+
+ JS_EXPORT_PRIVATE void print(int indentLevel);
+
+ private:
+ Frame() { }
+ ~Frame() { }
+
+ void retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column);
+ void setToEnd();
+
+ size_t m_index;
+ size_t m_argumentCountIncludingThis;
+ VMEntryFrame* m_VMEntryFrame;
+ VMEntryFrame* m_CallerVMEntryFrame;
+ CallFrame* m_callerFrame;
+ JSObject* m_callee;
+ CodeBlock* m_codeBlock;
+ unsigned m_bytecodeOffset;
+ bool m_callerIsVMEntryFrame;
+#if ENABLE(DFG_JIT)
+ InlineCallFrame* m_inlineCallFrame;
+#endif
+ CallFrame* m_callFrame;
+
+ friend class StackVisitor;
+ };
+
+ enum Status {
+ Continue = 0,
+ Done = 1
+ };
+
+ // StackVisitor::visit() expects a Functor that implements the following method:
+ // Status operator()(StackVisitor&);
+
+ template <typename Functor>
+ static void visit(CallFrame* startFrame, Functor& functor)
+ {
+ StackVisitor visitor(startFrame);
+ while (visitor->callFrame()) {
+ Status status = functor(visitor);
+ if (status != Continue)
+ break;
+ visitor.gotoNextFrame();
+ }
+ }
+
+ Frame& operator*() { return m_frame; }
+ ALWAYS_INLINE Frame* operator->() { return &m_frame; }
+
+private:
+ JS_EXPORT_PRIVATE StackVisitor(CallFrame* startFrame);
+
+ JS_EXPORT_PRIVATE void gotoNextFrame();
+
+ void readFrame(CallFrame*);
+ void readNonInlinedFrame(CallFrame*, CodeOrigin* = 0);
+#if ENABLE(DFG_JIT)
+ void readInlinedFrame(CallFrame*, CodeOrigin*);
+#endif
+
+ Frame m_frame;
+};
+
+class CallerFunctor {
+public:
+ CallerFunctor()
+ : m_hasSkippedFirstFrame(false)
+ , m_callerFrame(0)
+ {
+ }
+
+ CallFrame* callerFrame() const { return m_callerFrame; }
+
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ if (!m_hasSkippedFirstFrame) {
+ m_hasSkippedFirstFrame = true;
+ return StackVisitor::Continue;
+ }
+
+ m_callerFrame = visitor->callFrame();
+ return StackVisitor::Done;
+ }
+
+private:
+ bool m_hasSkippedFirstFrame;
+ CallFrame* m_callerFrame;
+};
+
+} // namespace JSC
+
+#endif // StackVisitor_h
+
diff --git a/Source/JavaScriptCore/interpreter/VMEntryRecord.h b/Source/JavaScriptCore/interpreter/VMEntryRecord.h
new file mode 100644
index 000000000..50ac65f78
--- /dev/null
+++ b/Source/JavaScriptCore/interpreter/VMEntryRecord.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VMEntryRecord_h
+#define VMEntryRecord_h
+
+namespace JSC {
+
+typedef void VMEntryFrame;
+
+class ExecState;
+class VM;
+
+struct VMEntryRecord {
+ /*
+ * This record stored in a vmEntryTo{JavaScript,Host} allocated frame. It is allocated on the stack
+ * after callee save registers where local variables would go.
+ */
+ VM* m_vm;
+ ExecState* m_prevTopCallFrame;
+ VMEntryFrame* m_prevTopVMEntryFrame;
+
+ ExecState* prevTopCallFrame() { return m_prevTopCallFrame; }
+
+ VMEntryFrame* prevTopVMEntryFrame() { return m_prevTopVMEntryFrame; }
+};
+
+extern "C" VMEntryRecord* vmEntryRecord(VMEntryFrame*);
+
+} // namespace JSC
+
+#endif // VMEntryRecord_h