| 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 | |
| 49 | using namespace JSC; |
| 50 | |
| 51 | JSValueRef 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 | |
| 84 | JSValueRef 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 | |
| 102 | bool 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 | |
| 133 | void 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 | |
| 150 | void (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 | |
| 163 | extern "C" JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef); |
| 164 | extern "C" JS_EXPORT void JSSynchronousEdenCollectForDebugging(JSContextRef); |
| 165 | |
| 166 | void 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 | |
| 177 | void 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 | |
| 188 | void 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. |
| 197 | JS_EXPORT extern const char iosInstallName43 __asm("$ld$install_name$os4.3$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore" ); |
| 198 | JS_EXPORT extern const char iosInstallName50 __asm("$ld$install_name$os5.0$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore" ); |
| 199 | JS_EXPORT extern const char iosInstallName51 __asm("$ld$install_name$os5.1$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore" ); |
| 200 | JS_EXPORT extern const char iosInstallName60 __asm("$ld$install_name$os6.0$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore" ); |
| 201 | JS_EXPORT extern const char iosInstallName61 __asm("$ld$install_name$os6.1$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore" ); |
| 202 | |
| 203 | const char iosInstallName43 = 0; |
| 204 | const char iosInstallName50 = 0; |
| 205 | const char iosInstallName51 = 0; |
| 206 | const char iosInstallName60 = 0; |
| 207 | const char iosInstallName61 = 0; |
| 208 | #endif |
| 209 | |