source: webkit/trunk/Source/JavaScriptCore/jsc.cpp@ 121381

Last change on this file since 121381 was 121381, checked in by [email protected], 13 years ago

JSLock should be per-JSGlobalData
https://bugs.webkit.org/show_bug.cgi?id=89123

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

  • API/APIShims.h:

(APIEntryShimWithoutLock):
(JSC::APIEntryShimWithoutLock::APIEntryShimWithoutLock): Added an extra parameter to the constructor to
determine whether we should ref the JSGlobalData or not. We want to ref all the time except for in the
HeapTimer class because timerDidFire could run after somebody has started to tear down that particular
JSGlobalData, so we wouldn't want to resurrect the ref count of that JSGlobalData from 0 back to 1 after
its destruction has begun.
(JSC::APIEntryShimWithoutLock::~APIEntryShimWithoutLock):
(JSC::APIEntryShim::APIEntryShim):
(APIEntryShim):
(JSC::APIEntryShim::~APIEntryShim):
(JSC::APIEntryShim::init): Factored out common initialization code for the various APIEntryShim constructors.
Also moved the timeoutChecker stop and start here because we need to start after we've grabbed the API lock
and before we've released it, which can only done in APIEntryShim.
(JSC::APICallbackShim::~APICallbackShim): We no longer need to synchronize here.

  • API/JSContextRef.cpp:

(JSGlobalContextCreate):
(JSGlobalContextCreateInGroup):
(JSGlobalContextRelease):
(JSContextCreateBacktrace):

  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
  • heap/CopiedSpace.cpp:

(JSC::CopiedSpace::tryAllocateSlowCase):

  • heap/Heap.cpp:

(JSC::Heap::protect):
(JSC::Heap::unprotect):
(JSC::Heap::collect):
(JSC::Heap::setActivityCallback):
(JSC::Heap::activityCallback):
(JSC::Heap::sweeper):

  • heap/Heap.h: Changed m_activityCallback and m_sweeper to be raw pointers rather than OwnPtrs because they

are now responsible for their own lifetime. Also changed the order of declaration of the GCActivityCallback
and the IncrementalSweeper to make sure they're the last things that get initialized during construction to
prevent any issues with uninitialized memory in the JSGlobalData/Heap they might care about.
(Heap):

  • heap/HeapTimer.cpp: Refactored to allow for thread-safe operation and shutdown.

(JSC::HeapTimer::~HeapTimer):
(JSC::HeapTimer::invalidate):
(JSC):
(JSC::HeapTimer::didStartVMShutdown): Called at the beginning of ~JSGlobalData. If we're on the same thread
that the HeapTimer is running on, we kill the HeapTimer ourselves. If not, then we set some state in the
HeapTimer and schedule it to fire immediately so that it can notice and kill itself.
(JSC::HeapTimer::timerDidFire): We grab our mutex and check our JSGlobalData pointer. If it has been zero-ed
out, then we know the VM has started to shutdown and we should kill ourselves. Otherwise, grab the APIEntryShim,
but without ref-ing the JSGlobalData (we don't want to bring the JSGlobalData's ref-count from 0 to 1) in case
we were interrupted between releasing our mutex and trying to grab the APILock.

  • heap/HeapTimer.h:

(HeapTimer):

  • heap/IncrementalSweeper.cpp:

(JSC::IncrementalSweeper::doWork): We no longer need the API shim here since HeapTimer::timerDidFire handles
all of that for us.
(JSC::IncrementalSweeper::create):

  • heap/IncrementalSweeper.h:

(IncrementalSweeper):

  • heap/MarkedAllocator.cpp:

(JSC::MarkedAllocator::allocateSlowCase):

  • heap/WeakBlock.cpp:

(JSC::WeakBlock::reap):

  • jsc.cpp:

(functionGC):
(functionReleaseExecutableMemory):
(jscmain):

  • runtime/Completion.cpp:

(JSC::checkSyntax):
(JSC::evaluate):

  • runtime/GCActivityCallback.h:

(DefaultGCActivityCallback):
(JSC::DefaultGCActivityCallback::create):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):
(JSC::JSGlobalData::~JSGlobalData): Signals to the two HeapTimers (GCActivityCallback and IncrementalSweeper)
that the VM has started shutting down. It then waits until the HeapTimer is done with whatever activity
it needs to do before continuing with any further destruction. Also asserts that we do not currently hold the
APILock because this could potentially cause deadlock when we try to signal to the HeapTimers using their mutexes.
(JSC::JSGlobalData::sharedInstance): Protect the initialization for the shared instance with the GlobalJSLock.
(JSC::JSGlobalData::sharedInstanceInternal):

  • runtime/JSGlobalData.h: Change to be ThreadSafeRefCounted so that we don't have to worry about refing and

de-refing JSGlobalDatas on separate threads since we don't do it that often anyways.
(JSGlobalData):
(JSC::JSGlobalData::apiLock):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::~JSGlobalObject):
(JSC::JSGlobalObject::init):

  • runtime/JSLock.cpp:

(JSC):
(JSC::GlobalJSLock::GlobalJSLock): For accessing the shared instance.
(JSC::GlobalJSLock::~GlobalJSLock):
(JSC::JSLockHolder::JSLockHolder): MutexLocker for JSLock. Also refs the JSGlobalData to keep it alive so that
it can successfully unlock it later without it disappearing from underneath it.
(JSC::JSLockHolder::~JSLockHolder):
(JSC::JSLock::JSLock):
(JSC::JSLock::~JSLock):
(JSC::JSLock::lock): Uses the spin lock for guarding the lock count and owner thread fields. Uses the mutex for
actually waiting for long periods.
(JSC::JSLock::unlock):
(JSC::JSLock::currentThreadIsHoldingLock):
(JSC::JSLock::dropAllLocks):
(JSC::JSLock::dropAllLocksUnconditionally):
(JSC::JSLock::grabAllLocks):
(JSC::JSLock::DropAllLocks::DropAllLocks):
(JSC::JSLock::DropAllLocks::~DropAllLocks):

  • runtime/JSLock.h:

(JSC):
(GlobalJSLock):
(JSLockHolder):
(JSLock):
(DropAllLocks):

  • runtime/WeakGCMap.h:

(JSC::WeakGCMap::set):

  • testRegExp.cpp:

(realMain):

Source/WebCore:

No new tests. Current regression tests are sufficient.

Changed all sites that used JSLock to instead use the new JSLockHolder
and pass in the correct JS context that the code is about to interact with that
needs protection. Also added a couple JSLocks to places that didn't already
have it that needed it.

  • bindings/js/GCController.cpp:

(WebCore::collect):
(WebCore::GCController::garbageCollectSoon):
(WebCore::GCController::garbageCollectNow):
(WebCore::GCController::discardAllCompiledCode):

  • bindings/js/JSCustomSQLStatementErrorCallback.cpp:

(WebCore::JSSQLStatementErrorCallback::handleEvent):

  • bindings/js/JSCustomVoidCallback.cpp:

(WebCore::JSCustomVoidCallback::handleEvent):

  • bindings/js/JSCustomXPathNSResolver.cpp:

(WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):

  • bindings/js/JSErrorHandler.cpp:

(WebCore::JSErrorHandler::handleEvent):

  • bindings/js/JSEventCustom.cpp:

(WebCore::toJS):

  • bindings/js/JSEventListener.cpp:

(WebCore::JSEventListener::handleEvent):

  • bindings/js/JSInjectedScriptHostCustom.cpp:

(WebCore::InjectedScriptHost::nodeAsScriptValue):
(WebCore::JSInjectedScriptHost::inspectedObject):

  • bindings/js/JSInjectedScriptManager.cpp:

(WebCore::InjectedScriptManager::createInjectedScript):
(WebCore::InjectedScriptManager::canAccessInspectedWindow):

  • bindings/js/JSLazyEventListener.cpp:

(WebCore::JSLazyEventListener::initializeJSFunction):

  • bindings/js/JSMainThreadExecState.h:

(WebCore::JSMainThreadExecState::evaluate):

  • bindings/js/JSMutationCallbackCustom.cpp:

(WebCore::JSMutationCallback::handleEvent):

  • bindings/js/JSNodeFilterCondition.cpp:

(WebCore::JSNodeFilterCondition::acceptNode):

  • bindings/js/JSRequestAnimationFrameCallbackCustom.cpp:

(WebCore::JSRequestAnimationFrameCallback::handleEvent):

  • bindings/js/JavaScriptCallFrame.cpp:

(WebCore::JavaScriptCallFrame::evaluate):

  • bindings/js/PageScriptDebugServer.cpp:

(WebCore::PageScriptDebugServer::recompileAllJSFunctions):

  • bindings/js/ScheduledAction.cpp:

(WebCore::ScheduledAction::executeFunctionInContext):

  • bindings/js/ScriptCachedFrameData.cpp:

(WebCore::ScriptCachedFrameData::ScriptCachedFrameData):
(WebCore::ScriptCachedFrameData::restore):
(WebCore::ScriptCachedFrameData::clear):

  • bindings/js/ScriptController.cpp:

(WebCore::ScriptController::evaluateInWorld):
(WebCore::ScriptController::clearWindowShell):
(WebCore::ScriptController::initScript):
(WebCore::ScriptController::updateDocument):
(WebCore::ScriptController::cacheableBindingRootObject):
(WebCore::ScriptController::bindingRootObject):
(WebCore::ScriptController::windowScriptNPObject):
(WebCore::ScriptController::jsObjectForPluginElement):
(WebCore::ScriptController::clearScriptObjects):

  • bindings/js/ScriptControllerMac.mm:

(WebCore::ScriptController::windowScriptObject):

  • bindings/js/ScriptDebugServer.cpp:

(WebCore::ScriptDebugServer::dispatchDidPause):

  • bindings/js/ScriptEventListener.cpp:

(WebCore::eventListenerHandlerBody):
(WebCore::eventListenerHandlerLocation):

  • bindings/js/ScriptFunctionCall.cpp:

(WebCore::ScriptCallArgumentHandler::appendArgument):
(WebCore::ScriptFunctionCall::call):
(WebCore::ScriptFunctionCall::construct):
(WebCore::ScriptCallback::call):

  • bindings/js/ScriptObject.cpp:

(WebCore::ScriptGlobalObject::set):
(WebCore::ScriptGlobalObject::get):
(WebCore::ScriptGlobalObject::remove):

  • bindings/js/ScriptValue.cpp:

(WebCore::ScriptValue::getString):
(WebCore::ScriptValue::toInspectorValue):

  • bindings/js/WorkerScriptController.cpp:

(WebCore::WorkerScriptController::~WorkerScriptController):
(WebCore::WorkerScriptController::initScript):
(WebCore::WorkerScriptController::evaluate):
(WebCore::WorkerScriptController::disableEval):

  • bindings/objc/WebScriptObject.mm:

(_didExecute):
(-[WebScriptObject callWebScriptMethod:withArguments:]):
(-[WebScriptObject evaluateWebScript:]):
(-[WebScriptObject setValue:forKey:]):
(-[WebScriptObject valueForKey:]):
(-[WebScriptObject removeWebScriptKey:]):
(-[WebScriptObject hasWebScriptKey:]):
(-[WebScriptObject stringRepresentation]):
(-[WebScriptObject webScriptValueAtIndex:]):
(-[WebScriptObject setWebScriptValueAtIndex:value:]):
(+[WebScriptObject _convertValueToObjcValue:originRootObject:rootObject:]):

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateCallbackImplementation):

  • bindings/scripts/test/JS/JSTestCallback.cpp:

(WebCore::JSTestCallback::callbackWithNoParam):
(WebCore::JSTestCallback::callbackWithClass1Param):
(WebCore::JSTestCallback::callbackWithClass2Param):
(WebCore::JSTestCallback::callbackWithStringList):
(WebCore::JSTestCallback::callbackWithBoolean):
(WebCore::JSTestCallback::callbackRequiresThisToPass):

  • bridge/NP_jsobject.cpp:

(_NPN_InvokeDefault):
(_NPN_Invoke):
(_NPN_Evaluate):
(_NPN_GetProperty):
(_NPN_SetProperty):
(_NPN_RemoveProperty):
(_NPN_HasProperty):
(_NPN_HasMethod):
(_NPN_Enumerate):
(_NPN_Construct):

  • bridge/c/c_class.cpp:

(JSC::Bindings::CClass::~CClass):
(JSC::Bindings::CClass::methodsNamed):
(JSC::Bindings::CClass::fieldNamed):

  • bridge/c/c_instance.cpp:

(JSC::Bindings::CInstance::moveGlobalExceptionToExecState):
(JSC::Bindings::CInstance::invokeMethod):
(JSC::Bindings::CInstance::invokeDefaultMethod):
(JSC::Bindings::CInstance::invokeConstruct):
(JSC::Bindings::CInstance::getPropertyNames):

  • bridge/c/c_runtime.cpp:

(JSC::Bindings::CField::valueFromInstance):
(JSC::Bindings::CField::setValueToInstance):

  • bridge/c/c_utility.cpp:

(JSC::Bindings::convertValueToNPVariant):
(JSC::Bindings::convertNPVariantToValue):

  • bridge/jni/jni_jsobject.mm:

(JavaJSObject::call):
(JavaJSObject::eval):
(JavaJSObject::getMember):
(JavaJSObject::setMember):
(JavaJSObject::removeMember):
(JavaJSObject::getSlot):
(JavaJSObject::setSlot):
(JavaJSObject::toString):
(JavaJSObject::convertValueToJObject):
(JavaJSObject::convertJObjectToValue):

  • bridge/jni/jni_objc.mm:

(JSC::Bindings::dispatchJNICall):

  • bridge/jni/jsc/JNIUtilityPrivate.cpp:

(JSC::Bindings::convertValueToJValue):

  • bridge/jni/jsc/JavaClassJSC.cpp:

(JavaClass::JavaClass):
(JavaClass::~JavaClass):

  • bridge/jni/jsc/JavaInstanceJSC.cpp:

(JavaInstance::stringValue):

  • bridge/jni/jsc/JavaMethodJSC.cpp:

(appendClassName):
(JavaMethod::signature):

  • bridge/jni/jsc/JavaStringJSC.h:

(JSC::Bindings::JavaString::JavaString):
(JSC::Bindings::JavaString::~JavaString):
(JSC::Bindings::JavaString::utf8):
(JSC::Bindings::JavaString::init):

  • bridge/jsc/BridgeJSC.cpp:

(JSC::Bindings::Instance::createRuntimeObject):
(JSC::Bindings::Instance::newRuntimeObject):

  • bridge/objc/objc_instance.mm:

(ObjcInstance::moveGlobalExceptionToExecState):
(ObjcInstance::invokeObjcMethod):
(ObjcInstance::invokeDefaultMethod):
(ObjcInstance::setValueOfUndefinedField):
(ObjcInstance::getValueOfUndefinedField):

  • bridge/objc/objc_runtime.mm:

(JSC::Bindings::ObjcField::valueFromInstance):
(JSC::Bindings::ObjcField::setValueToInstance):

  • bridge/objc/objc_utility.mm:

(JSC::Bindings::convertValueToObjcValue):
(JSC::Bindings::convertNSStringToString):
(JSC::Bindings::convertObjcValueToValue):

  • bridge/qt/qt_instance.cpp:

(JSC::Bindings::QtInstance::~QtInstance):
(JSC::Bindings::QtInstance::getQtInstance):
(JSC::Bindings::QtInstance::newRuntimeObject):

  • bridge/qt/qt_pixmapruntime.cpp:

(JSC::Bindings::QtPixmapInstance::createPixmapRuntimeObject):

  • bridge/qt/qt_runtime.cpp:

(JSC::Bindings::convertValueToQVariant):
(JSC::Bindings::convertQVariantToValue):
(JSC::Bindings::QtRuntimeMetaMethod::call):
(JSC::Bindings::QtRuntimeConnectionMethod::call):

  • bridge/qt/qt_runtime_qt4.cpp:

(JSC::Bindings::convertValueToQVariant):
(JSC::Bindings::convertQVariantToValue):
(JSC::Bindings::QtRuntimeMetaMethod::call):
(JSC::Bindings::QtRuntimeConnectionMethod::call):

  • bridge/runtime_root.cpp:

(JSC::Bindings::RootObject::gcProtect):
(JSC::Bindings::RootObject::gcUnprotect):

  • html/HTMLCanvasElement.cpp:

(WebCore::HTMLCanvasElement::createImageBuffer):

  • html/HTMLImageLoader.cpp:

(WebCore::HTMLImageLoader::notifyFinished):

  • plugins/PluginView.cpp:

(WebCore::PluginView::start):
(WebCore::PluginView::stop):
(WebCore::PluginView::performRequest):
(WebCore::PluginView::npObject):
(WebCore::PluginView::privateBrowsingStateChanged):

  • plugins/blackberry/PluginViewBlackBerry.cpp:

(WebCore::PluginView::dispatchNPEvent):
(WebCore::PluginView::setNPWindowIfNeeded):
(WebCore::PluginView::platformStart):
(WebCore::PluginView::getWindowInfo):

  • plugins/efl/PluginViewEfl.cpp:

(WebCore::PluginView::dispatchNPEvent):

  • plugins/gtk/PluginViewGtk.cpp:

(WebCore::PluginView::dispatchNPEvent):
(WebCore::PluginView::handleKeyboardEvent):
(WebCore::PluginView::handleMouseEvent):
(WebCore::PluginView::setNPWindowIfNeeded):
(WebCore::PluginView::platformStart):

  • plugins/mac/PluginViewMac.mm:

(WebCore::PluginView::setNPWindowIfNeeded):
(WebCore::PluginView::dispatchNPEvent):

  • plugins/qt/PluginViewQt.cpp:

(WebCore::PluginView::dispatchNPEvent):
(WebCore::PluginView::setNPWindowIfNeeded):
(WebCore::PluginView::platformStart):

  • plugins/win/PluginViewWin.cpp:

(WebCore::PluginView::dispatchNPEvent):
(WebCore::PluginView::handleKeyboardEvent):
(WebCore::PluginView::handleMouseEvent):
(WebCore::PluginView::setNPWindowRect):

  • testing/js/WebCoreTestSupport.cpp:

(WebCoreTestSupport::injectInternalsObject):
(WebCoreTestSupport::resetInternalsObject):

  • xml/XMLHttpRequest.cpp:

(WebCore::XMLHttpRequest::dropProtection):

Source/WebKit/blackberry:

Changed all sites that used JSLock to instead use the new JSLockHolder
and pass in the correct JS context that the code is about to interact with that
needs protection. Also added a couple JSLocks to places that didn't already
have it that needed it.

  • Api/BlackBerryGlobal.cpp:

(BlackBerry::WebKit::clearMemoryCaches):

  • WebCoreSupport/ClientExtension.cpp:
  • WebCoreSupport/PagePopupBlackBerry.cpp:

(WebCore::PagePopupBlackBerry::installDomFunction):

  • WebKitSupport/DumpRenderTreeSupport.cpp:

(DumpRenderTreeSupport::computedStyleIncludingVisitedInfo):

Source/WebKit/efl:

Changed all sites that used JSLock to instead use the new JSLockHolder
and pass in the correct JS context that the code is about to interact with that
needs protection. Also added a couple JSLocks to places that didn't already
have it that needed it.

  • ewk/ewk_frame.cpp:

(ewk_frame_script_execute):

  • ewk/ewk_view.cpp:

(ewk_view_js_object_add):

Source/WebKit/gtk:

Changed all sites that used JSLock to instead use the new JSLockHolder
and pass in the correct JS context that the code is about to interact with that
needs protection. Also added a couple JSLocks to places that didn't already
have it that needed it.

  • WebCoreSupport/DumpRenderTreeSupportGtk.cpp:

(DumpRenderTreeSupportGtk::gcCountJavascriptObjects):

Source/WebKit/mac:

Changed all sites that used JSLock to instead use the new JSLockHolder
and pass in the correct JS context that the code is about to interact with that
needs protection. Also added a couple JSLocks to places that didn't already
have it that needed it.

  • DOM/WebDOMOperations.mm:

(JSC):

  • Misc/WebCoreStatistics.mm:

(+[WebCoreStatistics javaScriptObjectsCount]):
(+[WebCoreStatistics javaScriptGlobalObjectsCount]):
(+[WebCoreStatistics javaScriptProtectedObjectsCount]):
(+[WebCoreStatistics javaScriptProtectedGlobalObjectsCount]):
(+[WebCoreStatistics javaScriptProtectedObjectTypeCounts]):
(+[WebCoreStatistics javaScriptObjectTypeCounts]):
(+[WebCoreStatistics shouldPrintExceptions]):
(+[WebCoreStatistics setShouldPrintExceptions:]):
(+[WebCoreStatistics memoryStatistics]):
(+[WebCoreStatistics javaScriptReferencedObjectsCount]):

  • Plugins/Hosted/NetscapePluginInstanceProxy.mm:

(WebKit::NetscapePluginInstanceProxy::evaluate):
(WebKit::NetscapePluginInstanceProxy::invoke):
(WebKit::NetscapePluginInstanceProxy::invokeDefault):
(WebKit::NetscapePluginInstanceProxy::construct):
(WebKit::NetscapePluginInstanceProxy::getProperty):
(WebKit::NetscapePluginInstanceProxy::setProperty):
(WebKit::NetscapePluginInstanceProxy::removeProperty):
(WebKit::NetscapePluginInstanceProxy::hasMethod):
(WebKit::NetscapePluginInstanceProxy::enumerate):
(WebKit::NetscapePluginInstanceProxy::addValueToArray):
(WebKit::NetscapePluginInstanceProxy::moveGlobalExceptionToExecState):

  • Plugins/WebNetscapePluginStream.mm:

(WebNetscapePluginStream::wantsAllStreams):

  • Plugins/WebNetscapePluginView.mm:

(-[WebNetscapePluginView sendEvent:isDrawRect:]):
(-[WebNetscapePluginView privateBrowsingModeDidChange]):
(-[WebNetscapePluginView setWindowIfNecessary]):
(-[WebNetscapePluginView createPluginScriptableObject]):
(-[WebNetscapePluginView getFormValue:]):
(-[WebNetscapePluginView evaluateJavaScriptPluginRequest:]):
(-[WebNetscapePluginView webFrame:didFinishLoadWithReason:]):
(-[WebNetscapePluginView loadPluginRequest:]):
(-[WebNetscapePluginView _printedPluginBitmap]):

  • Plugins/WebPluginController.mm:

(+[WebPluginController plugInViewWithArguments:fromPluginPackage:]):
(-[WebPluginController stopOnePlugin:]):
(-[WebPluginController destroyOnePlugin:]):
(-[WebPluginController startAllPlugins]):
(-[WebPluginController addPlugin:]):

  • WebView/WebFrame.mm:

(-[WebFrame _stringByEvaluatingJavaScriptFromString:forceUserGesture:]):
(-[WebFrame _stringByEvaluatingJavaScriptFromString:withGlobalObject:inScriptWorld:]):

  • WebView/WebScriptDebugDelegate.mm:

(-[WebScriptCallFrame scopeChain]):
(-[WebScriptCallFrame evaluateWebScript:]):

  • WebView/WebView.mm:

(+[WebView _reportException:inContext:]):
(-[WebView aeDescByEvaluatingJavaScriptFromString:]):
(-[WebView _computedStyleIncludingVisitedInfo:forElement:]):

Source/WebKit/qt:

Changed all sites that used JSLock to instead use the new JSLockHolder
and pass in the correct JS context that the code is about to interact with that
needs protection. Also added a couple JSLocks to places that didn't already
have it that needed it.

  • Api/qwebframe.cpp:

(QWebFramePrivate::addQtSenderToGlobalObject):
(QWebFrame::addToJavaScriptWindowObject):

  • WebCoreSupport/DumpRenderTreeSupportQt.cpp:

(DumpRenderTreeSupportQt::injectInternalsObject):
(DumpRenderTreeSupportQt::resetInternalsObject):

Source/WebKit/win:

Changed all sites that used JSLock to instead use the new JSLockHolder
and pass in the correct JS context that the code is about to interact with that
needs protection. Also added a couple JSLocks to places that didn't already
have it that needed it.

  • WebCoreStatistics.cpp:

(WebCoreStatistics::javaScriptObjectsCount):
(WebCoreStatistics::javaScriptGlobalObjectsCount):
(WebCoreStatistics::javaScriptProtectedObjectsCount):
(WebCoreStatistics::javaScriptProtectedGlobalObjectsCount):
(WebCoreStatistics::javaScriptProtectedObjectTypeCounts):

  • WebFrame.cpp:

(WebFrame::stringByEvaluatingJavaScriptInScriptWorld):

  • WebJavaScriptCollector.cpp:

(WebJavaScriptCollector::objectCount):

  • WebView.cpp:

(WebView::stringByEvaluatingJavaScriptFromString):
(WebView::reportException):
(WebView::elementFromJS):

Source/WebKit2:

Changed all sites that used JSLock to instead use the new JSLockHolder
and pass in the correct JS context that the code is about to interact with that
needs protection. Also added a couple JSLocks to places that didn't already
have it that needed it.

  • Shared/mac/WebMemorySampler.mac.mm:

(WebKit::WebMemorySampler::sampleWebKit):

  • WebProcess/InjectedBundle/InjectedBundle.cpp:

(WebKit::InjectedBundle::javaScriptObjectsCount):
(WebKit::InjectedBundle::reportException):

  • WebProcess/Plugins/Netscape/JSNPObject.cpp:

(WebKit::JSNPObject::callMethod):
(WebKit::JSNPObject::callObject):
(WebKit::JSNPObject::callConstructor):
(WebKit::JSNPObject::put):
(WebKit::JSNPObject::deleteProperty):
(WebKit::JSNPObject::getOwnPropertyNames):
(WebKit::JSNPObject::propertyGetter):

  • WebProcess/Plugins/Netscape/NPJSObject.cpp:

(WebKit::NPJSObject::hasMethod):
(WebKit::NPJSObject::invoke):
(WebKit::NPJSObject::invokeDefault):
(WebKit::NPJSObject::hasProperty):
(WebKit::NPJSObject::getProperty):
(WebKit::NPJSObject::setProperty):
(WebKit::NPJSObject::removeProperty):
(WebKit::NPJSObject::enumerate):
(WebKit::NPJSObject::construct):

  • WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:

(WebKit::NPRuntimeObjectMap::convertJSValueToNPVariant):
(WebKit::NPRuntimeObjectMap::evaluate):
(WebKit::NPRuntimeObjectMap::moveGlobalExceptionToExecState):

  • WebProcess/WebPage/WebFrame.cpp:

(WebKit::WebFrame::jsWrapperForWorld):
(WebKit::WebFrame::computedStyleIncludingVisitedInfo):

  • WebProcess/WebPage/WebPage.cpp:

(WebKit::WebPage::runJavaScriptInMainFrame):

  • WebProcess/WebProcess.cpp:

(WebKit::WebProcess::getWebCoreStatistics):

  • Property svn:eol-style set to native
File size: 23.2 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2006 Bjoern Graf ([email protected])
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24
25#include "BytecodeGenerator.h"
26#include "Completion.h"
27#include <wtf/CurrentTime.h>
28#include "ExceptionHelpers.h"
29#include "InitializeThreading.h"
30#include "Interpreter.h"
31#include "JSArray.h"
32#include "JSCTypedArrayStubs.h"
33#include "JSFunction.h"
34#include "JSLock.h"
35#include "JSString.h"
36#include <wtf/MainThread.h>
37#include "SamplingTool.h"
38#include <math.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42
43#if !OS(WINDOWS)
44#include <unistd.h>
45#endif
46
47#if HAVE(READLINE)
48// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
49// We #define it to something else to avoid this conflict.
50#define Function ReadlineFunction
51#include <readline/history.h>
52#include <readline/readline.h>
53#undef Function
54#endif
55
56#if HAVE(SYS_TIME_H)
57#include <sys/time.h>
58#endif
59
60#if HAVE(SIGNAL_H)
61#include <signal.h>
62#endif
63
64#if COMPILER(MSVC) && !OS(WINCE)
65#include <crtdbg.h>
66#include <mmsystem.h>
67#include <windows.h>
68#endif
69
70#if PLATFORM(QT)
71#include <QCoreApplication>
72#include <QDateTime>
73#endif
74
75#if PLATFORM(IOS)
76#include <fenv.h>
77#include <arm/arch.h>
78#endif
79
80using namespace JSC;
81using namespace WTF;
82
83static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer);
84
85static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
86static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
87static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
88static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
89#ifndef NDEBUG
90static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
91#endif
92static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
93static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
94static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
95static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
96static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
97static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
98static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
99
100#if ENABLE(SAMPLING_FLAGS)
101static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
102static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
103#endif
104
105struct Script {
106 bool isFile;
107 char* argument;
108
109 Script(bool isFile, char *argument)
110 : isFile(isFile)
111 , argument(argument)
112 {
113 }
114};
115
116struct CommandLine {
117 CommandLine()
118 : interactive(false)
119 , dump(false)
120 {
121 }
122
123 bool interactive;
124 bool dump;
125 Vector<Script> scripts;
126 Vector<UString> arguments;
127};
128
129static const char interactivePrompt[] = "> ";
130
131class StopWatch {
132public:
133 void start();
134 void stop();
135 long getElapsedMS(); // call stop() first
136
137private:
138 double m_startTime;
139 double m_stopTime;
140};
141
142void StopWatch::start()
143{
144 m_startTime = currentTime();
145}
146
147void StopWatch::stop()
148{
149 m_stopTime = currentTime();
150}
151
152long StopWatch::getElapsedMS()
153{
154 return static_cast<long>((m_stopTime - m_startTime) * 1000);
155}
156
157class GlobalObject : public JSGlobalObject {
158private:
159 GlobalObject(JSGlobalData&, Structure*);
160
161public:
162 typedef JSGlobalObject Base;
163
164 static GlobalObject* create(JSGlobalData& globalData, Structure* structure, const Vector<UString>& arguments)
165 {
166 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(globalData.heap)) GlobalObject(globalData, structure);
167 object->finishCreation(globalData, arguments);
168 return object;
169 }
170
171 static const ClassInfo s_info;
172 static const GlobalObjectMethodTable s_globalObjectMethodTable;
173
174 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
175 {
176 return Structure::create(globalData, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info);
177 }
178
179 static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return true; }
180
181protected:
182 void finishCreation(JSGlobalData& globalData, const Vector<UString>& arguments)
183 {
184 Base::finishCreation(globalData);
185
186 addFunction(globalData, "debug", functionDebug, 1);
187 addFunction(globalData, "print", functionPrint, 1);
188 addFunction(globalData, "quit", functionQuit, 0);
189 addFunction(globalData, "gc", functionGC, 0);
190#ifndef NDEBUG
191 addFunction(globalData, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
192#endif
193 addFunction(globalData, "version", functionVersion, 1);
194 addFunction(globalData, "run", functionRun, 1);
195 addFunction(globalData, "load", functionLoad, 1);
196 addFunction(globalData, "checkSyntax", functionCheckSyntax, 1);
197 addFunction(globalData, "jscStack", functionJSCStack, 1);
198 addFunction(globalData, "readline", functionReadline, 0);
199 addFunction(globalData, "preciseTime", functionPreciseTime, 0);
200#if ENABLE(SAMPLING_FLAGS)
201 addFunction(globalData, "setSamplingFlags", functionSetSamplingFlags, 1);
202 addFunction(globalData, "clearSamplingFlags", functionClearSamplingFlags, 1);
203#endif
204
205 addConstructableFunction(globalData, "Uint8Array", constructJSUint8Array, 1);
206 addConstructableFunction(globalData, "Uint8ClampedArray", constructJSUint8ClampedArray, 1);
207 addConstructableFunction(globalData, "Uint16Array", constructJSUint16Array, 1);
208 addConstructableFunction(globalData, "Uint32Array", constructJSUint32Array, 1);
209 addConstructableFunction(globalData, "Int8Array", constructJSInt8Array, 1);
210 addConstructableFunction(globalData, "Int16Array", constructJSInt16Array, 1);
211 addConstructableFunction(globalData, "Int32Array", constructJSInt32Array, 1);
212 addConstructableFunction(globalData, "Float32Array", constructJSFloat32Array, 1);
213 addConstructableFunction(globalData, "Float64Array", constructJSFloat64Array, 1);
214
215 JSArray* array = constructEmptyArray(globalExec());
216 for (size_t i = 0; i < arguments.size(); ++i)
217 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]), false);
218 putDirect(globalData, Identifier(globalExec(), "arguments"), array);
219 }
220
221 void addFunction(JSGlobalData& globalData, const char* name, NativeFunction function, unsigned arguments)
222 {
223 Identifier identifier(globalExec(), name);
224 putDirect(globalData, identifier, JSFunction::create(globalExec(), this, arguments, identifier.ustring(), function));
225 }
226
227 void addConstructableFunction(JSGlobalData& globalData, const char* name, NativeFunction function, unsigned arguments)
228 {
229 Identifier identifier(globalExec(), name);
230 putDirect(globalData, identifier, JSFunction::create(globalExec(), this, arguments, identifier.ustring(), function, NoIntrinsic, function));
231 }
232};
233COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
234ASSERT_CLASS_FITS_IN_CELL(GlobalObject);
235
236const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
237const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled };
238
239
240GlobalObject::GlobalObject(JSGlobalData& globalData, Structure* structure)
241 : JSGlobalObject(globalData, structure, &s_globalObjectMethodTable)
242{
243}
244
245static inline SourceCode jscSource(const char* utf8, const UString& filename)
246{
247 // Find the the first non-ascii character, or nul.
248 const char* pos = utf8;
249 while (*pos > 0)
250 pos++;
251 size_t asciiLength = pos - utf8;
252
253 // Fast case - string is all ascii.
254 if (!*pos)
255 return makeSource(UString(utf8, asciiLength), filename);
256
257 // Slow case - contains non-ascii characters, use fromUTF8WithLatin1Fallback.
258 ASSERT(*pos < 0);
259 ASSERT(strlen(utf8) == asciiLength + strlen(pos));
260 String source = String::fromUTF8WithLatin1Fallback(utf8, asciiLength + strlen(pos));
261 return makeSource(source.impl(), filename);
262}
263
264EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
265{
266 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
267 if (i)
268 putchar(' ');
269
270 printf("%s", exec->argument(i).toString(exec)->value(exec).utf8().data());
271 }
272
273 putchar('\n');
274 fflush(stdout);
275 return JSValue::encode(jsUndefined());
276}
277
278EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
279{
280 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
281 return JSValue::encode(jsUndefined());
282}
283
284EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
285{
286 String trace = "--> Stack trace:\n";
287 Vector<StackFrame> stackTrace;
288 Interpreter::getStackTrace(&exec->globalData(), stackTrace);
289 int i = 0;
290
291 for (Vector<StackFrame>::iterator iter = stackTrace.begin(); iter < stackTrace.end(); iter++) {
292 StackFrame level = *iter;
293 trace += String::format(" %i %s\n", i, level.toString(exec).utf8().data());
294 i++;
295 }
296 fprintf(stderr, "%s", trace.utf8().data());
297 return JSValue::encode(jsUndefined());
298}
299
300EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
301{
302 JSLockHolder lock(exec);
303 exec->heap()->collectAllGarbage();
304 return JSValue::encode(jsUndefined());
305}
306
307#ifndef NDEBUG
308EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
309{
310 JSLockHolder lock(exec);
311 exec->globalData().releaseExecutableMemory();
312 return JSValue::encode(jsUndefined());
313}
314#endif
315
316EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
317{
318 // We need this function for compatibility with the Mozilla JS tests but for now
319 // we don't actually do any version-specific handling
320 return JSValue::encode(jsUndefined());
321}
322
323EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
324{
325 UString fileName = exec->argument(0).toString(exec)->value(exec);
326 Vector<char> script;
327 if (!fillBufferWithContentsOfFile(fileName, script))
328 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
329
330 GlobalObject* globalObject = GlobalObject::create(exec->globalData(), GlobalObject::createStructure(exec->globalData(), jsNull()), Vector<UString>());
331
332 JSValue exception;
333 StopWatch stopWatch;
334 stopWatch.start();
335 evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script.data(), fileName), JSValue(), &exception);
336 stopWatch.stop();
337
338 if (!!exception) {
339 throwError(globalObject->globalExec(), exception);
340 return JSValue::encode(jsUndefined());
341 }
342
343 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
344}
345
346EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
347{
348 UString fileName = exec->argument(0).toString(exec)->value(exec);
349 Vector<char> script;
350 if (!fillBufferWithContentsOfFile(fileName, script))
351 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
352
353 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
354
355 JSValue evaluationException;
356 JSValue result = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
357 if (evaluationException)
358 throwError(exec, evaluationException);
359 return JSValue::encode(result);
360}
361
362EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
363{
364 UString fileName = exec->argument(0).toString(exec)->value(exec);
365 Vector<char> script;
366 if (!fillBufferWithContentsOfFile(fileName, script))
367 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
368
369 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
370
371 StopWatch stopWatch;
372 stopWatch.start();
373
374 JSValue syntaxException;
375 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
376 stopWatch.stop();
377
378 if (!validSyntax)
379 throwError(exec, syntaxException);
380 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
381}
382
383#if ENABLE(SAMPLING_FLAGS)
384EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
385{
386 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
387 unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
388 if ((flag >= 1) && (flag <= 32))
389 SamplingFlags::setFlag(flag);
390 }
391 return JSValue::encode(jsNull());
392}
393
394EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
395{
396 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
397 unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
398 if ((flag >= 1) && (flag <= 32))
399 SamplingFlags::clearFlag(flag);
400 }
401 return JSValue::encode(jsNull());
402}
403#endif
404
405EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
406{
407 Vector<char, 256> line;
408 int c;
409 while ((c = getchar()) != EOF) {
410 // FIXME: Should we also break on \r?
411 if (c == '\n')
412 break;
413 line.append(c);
414 }
415 line.append('\0');
416 return JSValue::encode(jsString(exec, line.data()));
417}
418
419EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
420{
421 return JSValue::encode(jsNumber(currentTime()));
422}
423
424EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
425{
426 exit(EXIT_SUCCESS);
427
428#if COMPILER(MSVC) && OS(WINCE)
429 // Without this, Visual Studio will complain that this method does not return a value.
430 return JSValue::encode(jsUndefined());
431#endif
432}
433
434// Use SEH for Release builds only to get rid of the crash report dialog
435// (luckily the same tests fail in Release and Debug builds so far). Need to
436// be in a separate main function because the jscmain function requires object
437// unwinding.
438
439#if COMPILER(MSVC) && !COMPILER(INTEL) && !defined(_DEBUG) && !OS(WINCE)
440#define TRY __try {
441#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
442#else
443#define TRY
444#define EXCEPT(x)
445#endif
446
447int jscmain(int argc, char** argv);
448
449int main(int argc, char** argv)
450{
451#if PLATFORM(IOS)
452 // Enabled IEEE754 denormal support.
453 fenv_t env;
454 fegetenv( &env );
455 env.__fpscr &= ~0x01000000u;
456 fesetenv( &env );
457#endif
458
459#if OS(WINDOWS)
460#if !OS(WINCE)
461 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
462 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
463 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
464 ::SetErrorMode(0);
465#endif
466
467#if defined(_DEBUG)
468 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
469 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
470 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
471 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
472 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
473 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
474#endif
475
476 timeBeginPeriod(1);
477#endif
478
479#if PLATFORM(QT)
480 QCoreApplication app(argc, argv);
481#endif
482
483 // Initialize JSC before getting JSGlobalData.
484#if ENABLE(SAMPLING_REGIONS)
485 WTF::initializeMainThread();
486#endif
487 JSC::initializeThreading();
488
489 // We can't use destructors in the following code because it uses Windows
490 // Structured Exception Handling
491 int res = 0;
492 TRY
493 res = jscmain(argc, argv);
494 EXCEPT(res = 3)
495 return res;
496}
497
498static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
499{
500 const char* script;
501 UString fileName;
502 Vector<char> scriptBuffer;
503
504 if (dump)
505 BytecodeGenerator::setDumpsGeneratedCode(true);
506
507 JSGlobalData& globalData = globalObject->globalData();
508
509#if ENABLE(SAMPLING_FLAGS)
510 SamplingFlags::start();
511#endif
512
513 bool success = true;
514 for (size_t i = 0; i < scripts.size(); i++) {
515 if (scripts[i].isFile) {
516 fileName = scripts[i].argument;
517 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
518 return false; // fail early so we can catch missing files
519 script = scriptBuffer.data();
520 } else {
521 script = scripts[i].argument;
522 fileName = "[Command Line]";
523 }
524
525 globalData.startSampling();
526
527 JSValue evaluationException;
528 JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script, fileName), JSValue(), &evaluationException);
529 success = success && !evaluationException;
530 if (dump && !evaluationException)
531 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
532 if (evaluationException) {
533 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
534 Identifier stackID(globalObject->globalExec(), "stack");
535 JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
536 if (!stackValue.isUndefinedOrNull())
537 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
538 }
539
540 globalData.stopSampling();
541 globalObject->globalExec()->clearException();
542 }
543
544#if ENABLE(SAMPLING_FLAGS)
545 SamplingFlags::stop();
546#endif
547#if ENABLE(SAMPLING_REGIONS)
548 SamplingRegion::dump();
549#endif
550 globalData.dumpSampleData(globalObject->globalExec());
551#if ENABLE(SAMPLING_COUNTERS)
552 AbstractSamplingCounter::dump();
553#endif
554#if ENABLE(REGEXP_TRACING)
555 globalData.dumpRegExpTrace();
556#endif
557 return success;
558}
559
560#define RUNNING_FROM_XCODE 0
561
562static void runInteractive(GlobalObject* globalObject)
563{
564 UString interpreterName("Interpreter");
565
566 while (true) {
567#if HAVE(READLINE) && !RUNNING_FROM_XCODE
568 char* line = readline(interactivePrompt);
569 if (!line)
570 break;
571 if (line[0])
572 add_history(line);
573 JSValue evaluationException;
574 JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(line, interpreterName), JSValue(), &evaluationException);
575 free(line);
576#else
577 printf("%s", interactivePrompt);
578 Vector<char, 256> line;
579 int c;
580 while ((c = getchar()) != EOF) {
581 // FIXME: Should we also break on \r?
582 if (c == '\n')
583 break;
584 line.append(c);
585 }
586 if (line.isEmpty())
587 break;
588 line.append('\0');
589
590 JSValue evaluationException;
591 JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
592#endif
593 if (evaluationException)
594 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
595 else
596 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
597
598 globalObject->globalExec()->clearException();
599 }
600 printf("\n");
601}
602
603static NO_RETURN void printUsageStatement(bool help = false)
604{
605 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
606 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
607 fprintf(stderr, " -e Evaluate argument as script code\n");
608 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
609 fprintf(stderr, " -h|--help Prints this help message\n");
610 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
611#if HAVE(SIGNAL_H)
612 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
613#endif
614
615 exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
616}
617
618static void parseArguments(int argc, char** argv, CommandLine& options)
619{
620 int i = 1;
621 for (; i < argc; ++i) {
622 const char* arg = argv[i];
623 if (!strcmp(arg, "-f")) {
624 if (++i == argc)
625 printUsageStatement();
626 options.scripts.append(Script(true, argv[i]));
627 continue;
628 }
629 if (!strcmp(arg, "-e")) {
630 if (++i == argc)
631 printUsageStatement();
632 options.scripts.append(Script(false, argv[i]));
633 continue;
634 }
635 if (!strcmp(arg, "-i")) {
636 options.interactive = true;
637 continue;
638 }
639 if (!strcmp(arg, "-d")) {
640 options.dump = true;
641 continue;
642 }
643 if (!strcmp(arg, "-s")) {
644#if HAVE(SIGNAL_H)
645 signal(SIGILL, _exit);
646 signal(SIGFPE, _exit);
647 signal(SIGBUS, _exit);
648 signal(SIGSEGV, _exit);
649#endif
650 continue;
651 }
652 if (!strcmp(arg, "--")) {
653 ++i;
654 break;
655 }
656 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
657 printUsageStatement(true);
658 options.scripts.append(Script(true, argv[i]));
659 }
660
661 if (options.scripts.isEmpty())
662 options.interactive = true;
663
664 for (; i < argc; ++i)
665 options.arguments.append(argv[i]);
666}
667
668int jscmain(int argc, char** argv)
669{
670
671 RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap);
672 JSLockHolder lock(globalData.get());
673
674 CommandLine options;
675 parseArguments(argc, argv, options);
676
677 GlobalObject* globalObject = GlobalObject::create(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.arguments);
678 bool success = runWithScripts(globalObject, options.scripts, options.dump);
679 if (options.interactive && success)
680 runInteractive(globalObject);
681
682 return success ? 0 : 3;
683}
684
685static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer)
686{
687 FILE* f = fopen(fileName.utf8().data(), "r");
688 if (!f) {
689 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
690 return false;
691 }
692
693 size_t bufferSize = 0;
694 size_t bufferCapacity = 1024;
695
696 buffer.resize(bufferCapacity);
697
698 while (!feof(f) && !ferror(f)) {
699 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
700 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
701 bufferCapacity *= 2;
702 buffer.resize(bufferCapacity);
703 }
704 }
705 fclose(f);
706 buffer[bufferSize] = '\0';
707
708 if (buffer[0] == '#' && buffer[1] == '!')
709 buffer[0] = buffer[1] = '/';
710
711 return true;
712}
Note: See TracBrowser for help on using the repository browser.