Home | History | Annotate | Download | only in runtime
      1 /*
      2  *  Copyright (C) 2011 Apple Inc. All rights reserved.
      3  *
      4  *  This library is free software; you can redistribute it and/or
      5  *  modify it under the terms of the GNU Lesser General Public
      6  *  License as published by the Free Software Foundation; either
      7  *  version 2 of the License, or (at your option) any later version.
      8  *
      9  *  This library is distributed in the hope that it will be useful,
     10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  *  Lesser General Public License for more details.
     13  *
     14  *  You should have received a copy of the GNU Lesser General Public
     15  *  License along with this library; if not, write to the Free Software
     16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     17  *
     18  */
     19 
     20 #ifndef StringRecursionChecker_h
     21 #define StringRecursionChecker_h
     22 
     23 #include "Interpreter.h"
     24 
     25 namespace JSC {
     26 
     27 class StringRecursionChecker {
     28     WTF_MAKE_NONCOPYABLE(StringRecursionChecker);
     29 
     30 public:
     31     StringRecursionChecker(ExecState*, JSObject* thisObject);
     32     ~StringRecursionChecker();
     33 
     34     EncodedJSValue earlyReturnValue() const; // 0 if everything is OK, value to return for failure cases
     35 
     36 private:
     37     EncodedJSValue throwStackOverflowError();
     38     EncodedJSValue emptyString();
     39     EncodedJSValue performCheck();
     40 
     41     ExecState* m_exec;
     42     JSObject* m_thisObject;
     43     EncodedJSValue m_earlyReturnValue;
     44 };
     45 
     46 inline EncodedJSValue StringRecursionChecker::performCheck()
     47 {
     48     int size = m_exec->globalData().stringRecursionCheckVisitedObjects.size();
     49     if (size >= MaxSmallThreadReentryDepth && size >= m_exec->globalData().maxReentryDepth)
     50         return throwStackOverflowError();
     51     bool alreadyVisited = !m_exec->globalData().stringRecursionCheckVisitedObjects.add(m_thisObject).second;
     52     if (alreadyVisited)
     53         return emptyString(); // Return empty string to avoid infinite recursion.
     54     return 0; // Indicate success.
     55 }
     56 
     57 inline StringRecursionChecker::StringRecursionChecker(ExecState* exec, JSObject* thisObject)
     58     : m_exec(exec)
     59     , m_thisObject(thisObject)
     60     , m_earlyReturnValue(performCheck())
     61 {
     62 }
     63 
     64 inline EncodedJSValue StringRecursionChecker::earlyReturnValue() const
     65 {
     66     return m_earlyReturnValue;
     67 }
     68 
     69 inline StringRecursionChecker::~StringRecursionChecker()
     70 {
     71     if (m_earlyReturnValue)
     72         return;
     73     ASSERT(m_exec->globalData().stringRecursionCheckVisitedObjects.contains(m_thisObject));
     74     m_exec->globalData().stringRecursionCheckVisitedObjects.remove(m_thisObject);
     75 }
     76 
     77 }
     78 
     79 #endif
     80