| /* |
| * Copyright (C) 2011 Apple Inc. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser 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 |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| */ |
| |
| #ifndef StringRecursionChecker_h |
| #define StringRecursionChecker_h |
| |
| #include "Interpreter.h" |
| |
| namespace JSC { |
| |
| class StringRecursionChecker { |
| WTF_MAKE_NONCOPYABLE(StringRecursionChecker); |
| |
| public: |
| StringRecursionChecker(ExecState*, JSObject* thisObject); |
| ~StringRecursionChecker(); |
| |
| EncodedJSValue earlyReturnValue() const; // 0 if everything is OK, value to return for failure cases |
| |
| private: |
| EncodedJSValue throwStackOverflowError(); |
| EncodedJSValue emptyString(); |
| EncodedJSValue performCheck(); |
| |
| ExecState* m_exec; |
| JSObject* m_thisObject; |
| EncodedJSValue m_earlyReturnValue; |
| }; |
| |
| inline EncodedJSValue StringRecursionChecker::performCheck() |
| { |
| int size = m_exec->globalData().stringRecursionCheckVisitedObjects.size(); |
| if (size >= MaxSmallThreadReentryDepth && size >= m_exec->globalData().maxReentryDepth) |
| return throwStackOverflowError(); |
| bool alreadyVisited = !m_exec->globalData().stringRecursionCheckVisitedObjects.add(m_thisObject).second; |
| if (alreadyVisited) |
| return emptyString(); // Return empty string to avoid infinite recursion. |
| return 0; // Indicate success. |
| } |
| |
| inline StringRecursionChecker::StringRecursionChecker(ExecState* exec, JSObject* thisObject) |
| : m_exec(exec) |
| , m_thisObject(thisObject) |
| , m_earlyReturnValue(performCheck()) |
| { |
| } |
| |
| inline EncodedJSValue StringRecursionChecker::earlyReturnValue() const |
| { |
| return m_earlyReturnValue; |
| } |
| |
| inline StringRecursionChecker::~StringRecursionChecker() |
| { |
| if (m_earlyReturnValue) |
| return; |
| ASSERT(m_exec->globalData().stringRecursionCheckVisitedObjects.contains(m_thisObject)); |
| m_exec->globalData().stringRecursionCheckVisitedObjects.remove(m_thisObject); |
| } |
| |
| } |
| |
| #endif |