1/*
2 * Copyright (C) 2006, 2007, 2013, 2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JSBase.h"
28#include "JSBaseInternal.h"
29#include "JSBasePrivate.h"
30
31#include "APICast.h"
32#include "CallFrame.h"
33#include "Completion.h"
34#include "Exception.h"
35#include "GCActivityCallback.h"
36#include "InitializeThreading.h"
37#include "JSGlobalObject.h"
38#include "JSLock.h"
39#include "JSObject.h"
40#include "OpaqueJSString.h"
41#include "JSCInlines.h"
42#include "SourceCode.h"
43#include <wtf/text/StringHash.h>
44
45#if ENABLE(REMOTE_INSPECTOR)
46#include "JSGlobalObjectInspectorController.h"
47#endif
48
49using namespace JSC;
50
51JSValueRef JSEvaluateScriptInternal(const JSLockHolder&, ExecState* exec, JSContextRef ctx, JSObjectRef thisObject, const SourceCode& source, JSValueRef* exception)
52{
53 UNUSED_PARAM(ctx);
54
55 JSObject* jsThisObject = toJS(thisObject);
56
57 // evaluate sets "this" to the global object if it is NULL
58 VM& vm = exec->vm();
59 JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec);
60 NakedPtr<Exception> evaluationException;
61 JSValue returnValue = profiledEvaluate(globalObject->globalExec(), ProfilingReason::API, source, jsThisObject, evaluationException);
62
63 if (evaluationException) {
64 if (exception)
65 *exception = toRef(exec, evaluationException->value());
66#if ENABLE(REMOTE_INSPECTOR)
67 // FIXME: If we have a debugger attached we could learn about ParseError exceptions through
68 // ScriptDebugServer::sourceParsed and this path could produce a duplicate warning. The
69 // Debugger path is currently ignored by inspector.
70 // NOTE: If we don't have a debugger, this SourceCode will be forever lost to the inspector.
71 // We could stash it in the inspector in case an inspector is ever opened.
72 globalObject->inspectorController().reportAPIException(exec, evaluationException);
73#endif
74 return nullptr;
75 }
76
77 if (returnValue)
78 return toRef(exec, returnValue);
79
80 // happens, for example, when the only statement is an empty (';') statement
81 return toRef(exec, jsUndefined());
82}
83
84JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef thisObject, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
85{
86 if (!ctx) {
87 ASSERT_NOT_REACHED();
88 return nullptr;
89 }
90 ExecState* exec = toJS(ctx);
91 VM& vm = exec->vm();
92 JSLockHolder locker(vm);
93
94 startingLineNumber = std::max(1, startingLineNumber);
95
96 auto sourceURLString = sourceURL ? sourceURL->string() : String();
97 SourceCode source = makeSource(script->string(), SourceOrigin { sourceURLString }, URL({ }, sourceURLString), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber()));
98
99 return JSEvaluateScriptInternal(locker, exec, ctx, thisObject, source, exception);
100}
101
102bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
103{
104 if (!ctx) {
105 ASSERT_NOT_REACHED();
106 return false;
107 }
108 ExecState* exec = toJS(ctx);
109 VM& vm = exec->vm();
110 JSLockHolder locker(vm);
111
112 startingLineNumber = std::max(1, startingLineNumber);
113
114 auto sourceURLString = sourceURL ? sourceURL->string() : String();
115 SourceCode source = makeSource(script->string(), SourceOrigin { sourceURLString }, URL({ }, sourceURLString), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber()));
116
117 JSValue syntaxException;
118 bool isValidSyntax = checkSyntax(vm.vmEntryGlobalObject(exec)->globalExec(), source, &syntaxException);
119
120 if (!isValidSyntax) {
121 if (exception)
122 *exception = toRef(exec, syntaxException);
123#if ENABLE(REMOTE_INSPECTOR)
124 Exception* exception = Exception::create(vm, syntaxException);
125 vm.vmEntryGlobalObject(exec)->inspectorController().reportAPIException(exec, exception);
126#endif
127 return false;
128 }
129
130 return true;
131}
132
133void JSGarbageCollect(JSContextRef ctx)
134{
135 // We used to recommend passing NULL as an argument here, which caused the only heap to be collected.
136 // As there is no longer a shared heap, the previously recommended usage became a no-op (but the GC
137 // will happen when the context group is destroyed).
138 // Because the function argument was originally ignored, some clients may pass their released context here,
139 // in which case there is a risk of crashing if another thread performs GC on the same heap in between.
140 if (!ctx)
141 return;
142
143 ExecState* exec = toJS(ctx);
144 VM& vm = exec->vm();
145 JSLockHolder locker(vm);
146
147 vm.heap.reportAbandonedObjectGraph();
148}
149
150void JSReportExtraMemoryCost(JSContextRef ctx, size_t size)
151{
152 if (!ctx) {
153 ASSERT_NOT_REACHED();
154 return;
155 }
156 ExecState* exec = toJS(ctx);
157 VM& vm = exec->vm();
158 JSLockHolder locker(vm);
159
160 vm.heap.deprecatedReportExtraMemory(size);
161}
162
163extern "C" JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef);
164extern "C" JS_EXPORT void JSSynchronousEdenCollectForDebugging(JSContextRef);
165
166void JSSynchronousGarbageCollectForDebugging(JSContextRef ctx)
167{
168 if (!ctx)
169 return;
170
171 ExecState* exec = toJS(ctx);
172 VM& vm = exec->vm();
173 JSLockHolder locker(vm);
174 vm.heap.collectNow(Sync, CollectionScope::Full);
175}
176
177void JSSynchronousEdenCollectForDebugging(JSContextRef ctx)
178{
179 if (!ctx)
180 return;
181
182 ExecState* exec = toJS(ctx);
183 VM& vm = exec->vm();
184 JSLockHolder locker(vm);
185 vm.heap.collectSync(CollectionScope::Eden);
186}
187
188void JSDisableGCTimer(void)
189{
190 GCActivityCallback::s_shouldCreateGCTimer = false;
191}
192
193#if PLATFORM(IOS_FAMILY) && TARGET_OS_IOS
194// FIXME: Expose symbols to tell dyld where to find JavaScriptCore on older versions of
195// iOS (< 7.0). We should remove these symbols once we no longer need to support such
196// versions of iOS. See <rdar://problem/13696872> for more details.
197JS_EXPORT extern const char iosInstallName43 __asm("$ld$install_name$os4.3$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore");
198JS_EXPORT extern const char iosInstallName50 __asm("$ld$install_name$os5.0$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore");
199JS_EXPORT extern const char iosInstallName51 __asm("$ld$install_name$os5.1$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore");
200JS_EXPORT extern const char iosInstallName60 __asm("$ld$install_name$os6.0$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore");
201JS_EXPORT extern const char iosInstallName61 __asm("$ld$install_name$os6.1$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore");
202
203const char iosInstallName43 = 0;
204const char iosInstallName50 = 0;
205const char iosInstallName51 = 0;
206const char iosInstallName60 = 0;
207const char iosInstallName61 = 0;
208#endif
209