We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / runtime / StringRecursionChecker.h
1 /*
2  *  Copyright (C) 2011, 2016 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 #pragma once
21
22 #include "CallFrame.h"
23 #include "VMInlines.h"
24 #include <wtf/StackStats.h>
25
26 namespace JSC {
27
28 class StringRecursionChecker {
29     WTF_MAKE_NONCOPYABLE(StringRecursionChecker);
30
31 public:
32     StringRecursionChecker(ExecState*, JSObject* thisObject);
33     ~StringRecursionChecker();
34
35     JSValue earlyReturnValue() const; // 0 if everything is OK, value to return for failure cases
36
37 private:
38     JSValue throwStackOverflowError();
39     JSValue emptyString();
40     JSValue performCheck();
41
42     ExecState* m_exec;
43     JSObject* m_thisObject;
44     JSValue m_earlyReturnValue;
45
46     StackStats::CheckPoint stackCheckpoint;
47 };
48
49 inline JSValue StringRecursionChecker::performCheck()
50 {
51     VM& vm = m_exec->vm();
52     if (UNLIKELY(!vm.isSafeToRecurseSoft()))
53         return throwStackOverflowError();
54
55     bool alreadyVisited = false;
56     if (!vm.stringRecursionCheckFirstObject)
57         vm.stringRecursionCheckFirstObject = m_thisObject;
58     else if (vm.stringRecursionCheckFirstObject == m_thisObject)
59         alreadyVisited = true;
60     else
61         alreadyVisited = !vm.stringRecursionCheckVisitedObjects.add(m_thisObject).isNewEntry;
62
63     if (alreadyVisited)
64         return emptyString(); // Return empty string to avoid infinite recursion.
65     return JSValue(); // Indicate success.
66 }
67
68 inline StringRecursionChecker::StringRecursionChecker(ExecState* exec, JSObject* thisObject)
69     : m_exec(exec)
70     , m_thisObject(thisObject)
71     , m_earlyReturnValue(performCheck())
72 {
73 }
74
75 inline JSValue StringRecursionChecker::earlyReturnValue() const
76 {
77     return m_earlyReturnValue;
78 }
79
80 inline StringRecursionChecker::~StringRecursionChecker()
81 {
82     if (m_earlyReturnValue)
83         return;
84
85     VM& vm = m_exec->vm();
86     if (vm.stringRecursionCheckFirstObject == m_thisObject)
87         vm.stringRecursionCheckFirstObject = nullptr;
88     else {
89         ASSERT(vm.stringRecursionCheckVisitedObjects.contains(m_thisObject));
90         vm.stringRecursionCheckVisitedObjects.remove(m_thisObject);
91     }
92 }
93
94 } // namespace JSC