diff options
author | Jocelyn Turcotte <jocelyn.turcotte@nokia.com> | 2009-09-18 08:35:59 (GMT) |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@nokia.com> | 2009-09-18 08:38:07 (GMT) |
commit | ef310719ef42cd09e2542fce96c529b5657bf167 (patch) | |
tree | c691bab10518e479ce40d4cac6c79daa312fce87 /src/3rdparty/webkit/JavaScriptCore/jit/JITOpcodes.cpp | |
parent | 5b828316abb0ad1a33cdc11ebac0999d9b79576a (diff) | |
download | Qt-ef310719ef42cd09e2542fce96c529b5657bf167.zip Qt-ef310719ef42cd09e2542fce96c529b5657bf167.tar.gz Qt-ef310719ef42cd09e2542fce96c529b5657bf167.tar.bz2 |
Updated WebKit from /home/joce/dev/qtwebkit/ to qtwebkit-4.6-snapshot-18092009 ( 15c07fb8d7fa5e93c939aa7eb21c06e19c754cee )
Changes in WebKit/qt since the last update:
++ b/WebKit/qt/ChangeLog
2009-09-17 Janne Koskinen <janne.p.koskinen@digia.com>
Reviewed by Simon Hausmann.
Symbian build fix.
Moved the #ifdefs around _q_cleanupLeakMessages() into the function
definition.
QMake is not being able to distinguish between release and debug builds
in Symbian build. This is a Symbian toolchain issue.
* Api/qwebpage.cpp:
(QWebPagePrivate::_q_cleanupLeakMessages):
* Api/qwebpage.h:
* Api/qwebpage_p.h:
2009-09-17 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
Reviewed by Simon Hausmann.
Small cosmetic documentation fixlet in the QWebInspector.
* Api/qwebinspector.cpp:
2009-09-16 Benjamin C Meyer <benjamin.meyer@torchmobile.com>
Reviewed by Eric Seidel.
Detect and add Windows7 properly to the user agent.
* Api/qwebpage.cpp:
(QWebPage::userAgentForUrl):
2009-09-16 Andras Becsi <andrewbecsi@yahoo.co.uk>
Rubberstamped by Kenneth Christiansen.
[Qt] Build fix for previous changes.
* QGVLauncher/main.cpp:
(MainView::flip):
2009-09-16 Kenneth Rohde Christiansen <kenneth@webkit.org>
Unreviewed potential Qt < 4.6 build fix.
* QGVLauncher/main.cpp:
(MainView::flip):
2009-09-16 Kenneth Rohde Christiansen <kenneth@webkit.org>
Reviewed by Simon Hausmann.
Add a "Flip effect" to our GraphicsView based launcher.
* QGVLauncher/main.cpp:
(MainView::resizeEvent):
(MainView::flip):
(MainWindow::flip):
(MainWindow::buildUI):
2009-09-16 Zoltan Herczeg <zherczeg@inf.u-szeged.hu>
Rubber-stamped by Simon Hausmann.
[Qt] Typo fix. Pass the window object to the Format
menu. In this way Qt can free its internal graphical
objects during exit.
* QtLauncher/main.cpp:
(MainWindow::setupUI):
2009-09-16 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
Reviewed by Tor Arne Vestbø.
[Qt] Build break fix on gcc ARM.
* Api/qwebgraphicsitem.cpp:
(QWebGraphicsItemPrivate::_q_doLoadProgress):
2009-09-16 Warwick Allison <warwick.allison@nokia.com>
Reviewed by Simon Hausmann.
Fix a crash in QWebFrame::hasFocus() with a simple null pointer check
when the focused frame is null. We do the same check in other places
where we call kit().
* Api/qwebframe.cpp:
(QWebFrame::hasFocus):
2009-09-16 Jure Repinc <jlp@holodeck1.com>
Reviewed by Simon Hausmann.
Fixed a typo found during translation.
* WebCoreSupport/FrameLoaderClientQt.cpp:
(WebCore::FrameLoaderClientQt::interruptForPolicyChangeError):
2009-09-14 Jakub Wieczorek <faw217@gmail.com>
Reviewed by Simon Hausmann.
[Qt] QWebGraphicsItem should check for null QWebPage.
https://bugs.webkit.org/show_bug.cgi?id=29185
Don't crash in QWebGraphicsItem when the page is still null, by
either checking if it's the case or constructing the default one.
* Api/qwebgraphicsitem.cpp:
(QWebGraphicsItem::icon):
(QWebGraphicsItem::setZoomFactor):
(QWebGraphicsItem::zoomFactor):
(QWebGraphicsItem::setGeometry):
(QWebGraphicsItem::load):
(QWebGraphicsItem::setHtml):
(QWebGraphicsItem::toHtml):
(QWebGraphicsItem::setContent):
(QWebGraphicsItem::history):
(QWebGraphicsItem::settings):
2009-09-11 David Boddie <dboddie@trolltech.com>
Reviewed by Simon Hausmann.
Doc: Note that Netscape plugins are only available on desktop platforms.
* docs/qtwebkit.qdoc:
2009-09-11 Martin Smith <msmith@trolltech.com>
Reviewed by Simon Hausmann.
Adjust the name of the contentspage for the documentation
to the new name used in Qt 4.6.
* docs/qtwebkit.qdoc:
2009-09-11 Ariya Hidayat <ariya.hidayat@nokia.com>
Reviewed by Simon Hausmann.
Changed URLs from qtsoftware.com to qt.nokia.com, as part of a general
renaming.
* Api/qwebpluginfactory.cpp:
* docs/webkitsnippets/simple/main.cpp:
(main):
* docs/webkitsnippets/webpage/main.cpp:
(main):
2009-09-11 Volker Hilsheimer <volker.hilsheimer@nokia.com>
Reviewed by Simon Hausmann.
Restructure the documentation, both on a file and on a content level.
* Api/qwebdatabase.cpp:
* Api/qwebelement.cpp:
* Api/qwebframe.cpp:
* Api/qwebhistory.cpp:
* Api/qwebhistoryinterface.cpp:
* Api/qwebpage.cpp:
* Api/qwebpluginfactory.cpp:
* Api/qwebsecurityorigin.cpp:
* Api/qwebsettings.cpp:
* Api/qwebview.cpp:
* docs/qtwebkit.qdoc:
2009-09-11 Yongjun Zhang <yongjun.zhang@nokia.com>
Reviewed by Simon Hausmann.
https://bugs.webkit.org/show_bug.cgi?id=29136
[Qt] emit microFocusChanged() signal when no QWidget-based view is present.
emit microFocusChange() signal regardless of view.
* WebCoreSupport/EditorClientQt.cpp:
(WebCore::EditorClientQt::setInputMethodState):
2009-09-11 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
Reviewed by Simon Hausmann.
https://bugs.webkit.org/show_bug.cgi?id=28806
[Qt] Make the WebInspector available as a QWidget.
* Api/headers.pri:
* Api/qwebelement.cpp:
(QWebElement::enclosingElement):
* Api/qwebelement.h:
* Api/qwebinspector.cpp: Added.
* Api/qwebinspector.h: Added.
* Api/qwebinspector_p.h: Added.
* Api/qwebpage.cpp:
(QWebPagePrivate::QWebPagePrivate):
(QWebPagePrivate::setInspector):
(QWebPagePrivate::getOrCreateInspector):
(QWebPagePrivate::inspectorController):
(QWebPage::~QWebPage):
(QWebPage::triggerAction):
* Api/qwebpage.h:
* Api/qwebpage_p.h:
* Api/qwebsettings.cpp:
* QtLauncher/main.cpp:
(MainWindow::MainWindow):
* WebCoreSupport/InspectorClientQt.cpp:
(WebCore::InspectorClientWebPage::InspectorClientWebPage):
(WebCore::InspectorClientWebPage::createWindow):
(WebCore::InspectorClientQt::createPage):
(WebCore::InspectorClientQt::showWindow):
(WebCore::InspectorClientQt::closeWindow):
(WebCore::InspectorClientQt::attachWindow):
(WebCore::InspectorClientQt::detachWindow):
(WebCore::InspectorClientQt::updateWindowTitle):
* WebCoreSupport/InspectorClientQt.h:
* docs/webkitsnippets/qtwebkit_qwebinspector_snippet.cpp: Added.
2009-09-10 Laszlo Gombos <laszlo.1.gombos@nokia.com>
Reviewed by Eric Seidel.
[Qt] Fix comparison between signed and unsigned integer warnings
https://bugs.webkit.org/show_bug.cgi?id=29162
No functional change.
* Api/qwebelement.cpp:
(QWebElement::findAll):
* Api/qwebhistory.cpp:
(QWebHistory::items):
(QWebHistory::backItems):
(QWebHistory::forwardItems):
(QWebHistory::saveState):
* Api/qwebplugindatabase.cpp:
(QWebPluginDatabase::setSearchPaths):
* WebCoreSupport/ChromeClientQt.cpp:
(WebCore::ChromeClientQt::runOpenPanel):
* WebCoreSupport/FrameLoaderClientQt.cpp:
(WebCore::FrameLoaderClientQt::createPlugin):
2009-09-10 Simon Hausmann <hausmann@webkit.org>
Rubber-stamped by Ariya Hidayat.
Fix a bunch of qdoc warnings: Invalid references, non-standard
wording, etc.
* Api/qwebelement.cpp:
* Api/qwebgraphicsitem.cpp:
* Api/qwebsecurityorigin.cpp:
2009-09-10 Simon Hausmann <hausmann@webkit.org>
Reviewed by Ariya Hidayat.
Fix context menu event delivery with QWebGraphicsItem.
Re-implement the correct context menu virtual function using
a QGraphicsSceneContextMenuEvent and forward & handle it in
QWebPage.
* Api/qwebgraphicsitem.cpp:
(QWebGraphicsItem::contextMenuEvent):
* Api/qwebgraphicsitem.h:
* Api/qwebpage.cpp:
(QWebPagePrivate::contextMenuEvent):
(QWebPage::event):
* Api/qwebpage_p.h:
2009-09-10 Laszlo Gombos <laszlo.1.gombos@nokia.com>
Unreviewed.
Build fix for QtWebKit for Mac after r48219.
qevent and qstyleoption are QtGui interfaces.
* Api/qwebgraphicsitem.cpp:
* Api/qwebgraphicsitem.h:
2009-09-09 Simon Hausmann <hausmann@webkit.org>
Reviewed by Tor Arne Vestbø.
Call the right base class function QGraphicsWidget::event() instead
of skipping it and using QObject::event() instead.
* Api/qwebgraphicsitem.cpp:
(QWebGraphicsItem::event):
2009-09-09 Kenneth Rohde Christiansen <kenneth@webkit.org>
Unreviewed.
Fix comment at Tor Arne Vestbø's request.
* Api/qwebgraphicsitem.cpp:
(QWebGraphicsItem::sceneEvent):
(QWebGraphicsItem::event):
2009-09-09 Kenneth Rohde Christiansen <kenneth@webkit.org>
Reviewed by Tor Arne Vestbø.
Implement some virtual event methods so that we can fix
event-related bugs in Qt patch releases.
* Api/qwebgraphicsitem.cpp:
(QWebGraphicsItem::sceneEvent):
(QWebGraphicsItem::event):
* Api/qwebgraphicsitem.h:
2009-09-09 Kenneth Rohde Christiansen <kenneth@webkit.org>, Antonio Gomes <antonio.gomes@openbossa.org>
Reviewed by Simon Hausmann.
Add a new QGraphicsWidget based version of the "QWebView"
under the name "QWebGraphicsItem".
https://bugs.webkit.org/show_bug.cgi?id=28862
Includes an alternative Qt launcher using the QGraphicsView.
* Api/headers.pri:
* Api/qwebgraphicsitem.cpp: Added.
* Api/qwebgraphicsitem.h: Added.
* Api/qwebpage.h:
* QGVLauncher/QGVLauncher.pro: Copied from WebKit/qt/QtLauncher/QtLauncher.pro.
* QGVLauncher/main.cpp: Added.
* WebCoreSupport/ChromeClientQt.cpp:
(WebCore::ChromeClientQt::repaint):
(WebCore::ChromeClientQt::scroll):
2009-09-08 Kenneth Rohde Christiansen <kenneth@webkit.org>
Unreviewed build fix.
Potential build fix for Qt 4.5
* Api/qwebpage.cpp:
(QWebPagePrivate::mousePressEvent):
2009-09-08 Benjamin Poulain <benjamin.poulain@nokia.com>
Reviewed by Simon Hausmann.
https://bugs.webkit.org/show_bug.cgi?id=29007
Add a test for the signal QWebFrame::javaScriptWindowObjectCleared()
* tests/qwebframe/tst_qwebframe.cpp:
2009-09-08 Laszlo Gombos <laszlo.1.gombos@nokia.com>
Reviewed by Simon Hausmann.
[Qt] Fix unused variable warnings
https://bugs.webkit.org/show_bug.cgi?id=29018
* Api/qwebpage.cpp:
(QWebPagePrivate::keyPressEvent):
* WebCoreSupport/FrameLoaderClientQt.cpp:
(WebCore::FrameLoaderClientQt::startDownload):
(WebCore::FrameLoaderClientQt::createFrame):
2009-09-08 Laszlo Gombos <laszlo.1.gombos@nokia.com>
Reviewed by Ariya Hidayat.
[Qt] Use the declaration order in initializer lists
https://bugs.webkit.org/show_bug.cgi?id=29017
* Api/qwebframe_p.h:
2009-09-08 Kenneth Rohde Christiansen <kenneth@webkit.org>
Reviewed by Simon Hausmann.
Add support for handling QGraphicsScene events.
* Api/qwebpage.cpp:
(QWebPagePrivate::mouseMoveEvent):
(QWebPagePrivate::mousePressEvent):
(QWebPagePrivate::mouseDoubleClickEvent):
(QWebPagePrivate::mouseTripleClickEvent):
(QWebPagePrivate::handleClipboard):
(QWebPagePrivate::mouseReleaseEvent):
(QWebPagePrivate::wheelEvent):
(QWebPagePrivate::dragEnterEvent):
(QWebPagePrivate::dragLeaveEvent):
(QWebPagePrivate::dragMoveEvent):
(QWebPagePrivate::dropEvent):
(QWebPage::event):
* Api/qwebpage_p.h:
2009-09-08 Kenneth Rohde Christiansen <kenneth@webkit.org>
Reviewed by Simon Hausmann.
[Qt] Make cursor set cleaner in QtWebKit Api: eliminate SetCursorEvent hack.
https://bugs.webkit.org/show_bug.cgi?id=28865
Clean up the unserCursor hack to use the QCursor set
as a property of the QWidget by WebCore::WidgetQt.
Remove all code that are no longer necessary for getting
cursor change events.
Patch by Kenneth Rohde Christiansen <kenneth@webkit.org> and
Antonio Gomes <antonio.gomes@openbossa.org> on 2009-09-07
* Api/qwebpage.cpp:
* Api/qwebpage_p.h:
* Api/qwebview.cpp:
(QWebViewPrivate::QWebViewPrivate):
(QWebView::event):
2009-09-08 Laszlo Gombos <laszlo.1.gombos@nokia.com>
Reviewed by Simon Hausmann.
[Qt] QtWebKit single API to enable persistency
https://bugs.webkit.org/show_bug.cgi?id=28682
Disable LocalStorage, ApplicationCache, HTML5 offline storage by
default.
If persistency is enabled the default directory for LocalStorage and
ApplicationCache is now based on QDesktopServices::DataLocation and not
QDesktopServices::CacheLocation (as it is expected to keep this data
around after a reboot).
If persistency is enabled initialize HTML5 offline storage as well - this
fixed offline Storage for QtLauncher.
* Api/qwebpage.cpp:
(QWebPagePrivate::QWebPagePrivate):
* Api/qwebsettings.cpp:
(QWebSettings::QWebSettings):
(QWebSettings::enablePersistentStorage):
* Api/qwebsettings.h: Add a new API called enablePersistentStorage
* QtLauncher/main.cpp: Use the new enablePersistentStorage API
(main):
2009-09-07 Jakub Wieczorek <faw217@gmail.com>
Reviewed by Simon Hausmann.
Speed up the QWebPluginInfo::supportsMimeType() function.
https://bugs.webkit.org/show_bug.cgi?id=27651
Instead of going through the MIME types list constructed with
mimeTypes() function, look up the internal mimeToDescriptions map.
* Api/qwebplugindatabase.cpp:
(QWebPluginInfo::supportsMimeType):
2009-09-07 Jakub Wieczorek <faw217@gmail.com>
Reviewed by Simon Hausmann.
Speed up the QWebPluginInfo::mimeTypes() function.
https://bugs.webkit.org/show_bug.cgi?id=27651
Instead of constructing a list of MIME types every time it is called,
do this only once.
* Api/qwebplugindatabase.cpp:
(QWebPluginInfo::mimeTypes):
(QWebPluginInfo::operator=):
* Api/qwebplugindatabase.h:
* tests/qwebplugindatabase/tst_qwebplugindatabase.cpp:
(tst_QWebPluginDatabase::operatorassign_data):
(tst_QWebPluginDatabase::operatorassign):
2009-09-07 Jakub Wieczorek <faw217@gmail.com>
Reviewed by Simon Hausmann.
Remove the private classes from QWebPluginDatabase.
https://bugs.webkit.org/show_bug.cgi?id=27651
Instead, hold the PluginDatabase and PluginPackage objects as class
members and take care of refcounting on our own instead of using RefPtr.
This way we not only made the code cleaner but also got rid of
redundant allocations when constructing null QWebPluginInfo objects.
The private classes have been forward-declared and the d-pointers left
to be on the safe side.
* Api/qwebplugindatabase.cpp:
(QWebPluginInfo::QWebPluginInfo):
(QWebPluginInfo::~QWebPluginInfo):
(QWebPluginInfo::name):
(QWebPluginInfo::description):
(QWebPluginInfo::mimeTypes):
(QWebPluginInfo::path):
(QWebPluginInfo::isNull):
(QWebPluginInfo::setEnabled):
(QWebPluginInfo::isEnabled):
(QWebPluginInfo::operator==):
(QWebPluginInfo::operator!=):
(QWebPluginInfo::operator=):
(QWebPluginDatabase::QWebPluginDatabase):
(QWebPluginDatabase::~QWebPluginDatabase):
(QWebPluginDatabase::plugins):
(QWebPluginDatabase::searchPaths):
(QWebPluginDatabase::setSearchPaths):
(QWebPluginDatabase::addSearchPath):
(QWebPluginDatabase::refresh):
(QWebPluginDatabase::pluginForMimeType):
(QWebPluginDatabase::setPreferredPluginForMimeType):
* Api/qwebplugindatabase.h:
* Api/qwebplugindatabase_p.h: Removed.
2009-09-05 Jakub Wieczorek <faw217@gmail.com>
Reviewed by Eric Seidel.
[Qt] r47424 broke binary compatibility
https://bugs.webkit.org/show_bug.cgi?id=28996
Append the new DnsPrefetchEnabled attribute at the end of the enum.
* Api/qwebsettings.h:
2009-09-04 Mark Mentovai <mark@chromium.org>
Reviewed by Dave Hyatt.
https://bugs.webkit.org/show_bug.cgi?id=28614
Account for scrollbar state changes that occur during layout.
* Api/qwebframe.cpp:
(QWebFrame::setScrollBarPolicy):
Eliminate duplicated (and incorrect) scrollbar mode tracking between
FrameView and ScrollView.
2009-09-04 Laszlo Gombos <laszlo.1.gombos@nokia.com>
Reviewed by Eric Seidel.
[Qt] Fix tst_QWebPage::database autotest failure
https://bugs.webkit.org/show_bug.cgi?id=28961
Make sure that the test case enables the feature before
the feature gets tested
* tests/qwebpage/tst_qwebpage.cpp:
(tst_QWebPage::database):
2009-09-04 Benjamin C Meyer <benjamin.meyer@torchmobile.com>
Reviewed by Eric Seidel.
Any QtWebKit application crashes on exit if the inspector is
used during the session rather then exiting.
If a QWebView has a QWebPage that is destroyed the QWebView
does not update its pointer and will crash the next time
it access the page pointers (such as in its destructor).
InspectorClientView should not call deleteLater when the page
is destroyed because it does not have a parent and is a top
level widget. close() needs to be called so that QApplication
can exit the application if quitOnLastWindowClosed is set
and a InspectorClientView is the last window, otherwise
the application will never exit.
* Api/qwebview.cpp:
(QWebViewPrivate::_q_pageDestroyed):
(QWebView::setPage):
* Api/qwebview.h:
* WebCoreSupport/InspectorClientQt.cpp:
(WebCore::InspectorClientView::InspectorClientView):
2009-09-03 Adam Barth <abarth@webkit.org>
Reviewed by eric@webkit.org.
https://bugs.webkit.org/show_bug.cgi?id=24696
Stub implementations of mixed content methods of FrameLoaderClient.
* WebCoreSupport/FrameLoaderClientQt.cpp:
(WebCore::FrameLoaderClientQt::didDisplayInsecureContent):
(WebCore::FrameLoaderClientQt::didRunInsecureContent):
* WebCoreSupport/FrameLoaderClientQt.h:
2009-09-03 Laszlo Gombos <laszlo.1.gombos@nokia.com>
Reviewed by Eric Seidel.
[Qt] Add a setting to turn SessionStorage on/off
https://bugs.webkit.org/show_bug.cgi?id=28836
* Api/qwebsettings.cpp:
(QWebSettingsPrivate::apply):
(QWebSettings::QWebSettings):
* Api/qwebsettings.h:
* tests/qwebpage/tst_qwebpage.cpp:
(testFlag):
(tst_QWebPage::testOptionalJSObjects):
2009-09-02 Richard Moore <rich@kde.org>
Reviewed by Tor Arne Vestbø.
[Qt] Make sure we relayout the page after evaluating JS
https://bugs.webkit.org/show_bug.cgi?id=28235
QtWebKit does not always seem to reflow the page when evaluating
javascript. This patch changes the way evaluateJavaScript works to
use the frameloader which ensures that this is done properly.
* Api/qwebframe.cpp:
(QWebFrame::evaluateJavaScript):
* tests/qwebframe/tst_qwebframe.cpp:
2009-08-28 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
Reviewed by Holger Freyther.
https://bugs.webkit.org/show_bug.cgi?id=25889
[GTK] scrollbar policy for main frame is not implementable
Add empty implementation for new ChromeClient method.
* WebCoreSupport/ChromeClientQt.h:
(WebCore::ChromeClientQt::scrollbarsModeDidChange):
2009-08-27 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
Reviewed by Ariya Hidayat.
QWebHistory::clear() modifications.
Clear() method was changed. If QWebHistory is empty (there is no
elements even current) clear() do nothing. If there at least one
element clear() will delete everything apart of current.
New autotests in QWebHistory
New autotests were added to QWebHistory. They should check some crashes
in save and restore state process and clear() method and general
behavior on where QWebHistory::count() == 0 or QWebHistory::count() == 1
Bugzilla: https://bugs.webkit.org/show_bug.cgi?id=28711
* Api/qwebhistory.cpp:
(QWebHistory::clear):
* tests/qwebhistory/tst_qwebhistory.cpp:
(tst_QWebHistory::back):
(tst_QWebHistory::forward):
(tst_QWebHistory::saveAndRestore_crash_1):
(tst_QWebHistory::saveAndRestore_crash_2):
(tst_QWebHistory::saveAndRestore_crash_3):
(tst_QWebHistory::clear):
2009-08-27 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
Reviewed by Ariya Hidayat.
[Qt] Cleanup, old and commented part of source code was removed.
Fix some formatting problems.
https://bugs.webkit.org/show_bug.cgi?id=28712
* Api/qwebhistory_p.h:
(QWebHistoryPrivate::QWebHistoryPrivate):
2009-08-26 Adam Barth <abarth@webkit.org>
Reviewed by Oliver Hunt.
Don't let local files access web URLs
https://bugs.webkit.org/show_bug.cgi?id=28480
* Api/qwebsettings.cpp:
(QWebSettings::QWebSettings):
2009-08-25 Antonio Gomes <antonio.gomes@openbossa.org>
Reviewed by Ariya Hidayat.
Bug 28708 - Make possible to better use ResourceError in FrameLoaderClientQt class.
* Api/qwebframe.cpp:
(QWebFrame::requestedUrl):
* WebCoreSupport/FrameLoaderClientQt.cpp:
(WebCore::FrameLoaderClientQt::FrameLoaderClientQt):
(WebCore::FrameLoaderClientQt::dispatchDidFinishLoad):
(WebCore::FrameLoaderClientQt::postProgressFinishedNotification):
(WebCore::FrameLoaderClientQt::dispatchDidFailProvisionalLoad):
(WebCore::FrameLoaderClientQt::dispatchDidFailLoad):
* WebCoreSupport/FrameLoaderClientQt.h:
2009-08-22 Adam Barth <abarth@webkit.org>
Revert 47684. We're going to do this later once clients have had a
chance to opt into the setting they like.
* Api/qwebsettings.cpp:
(QWebSettings::QWebSettings):
2009-08-22 Adam Barth <abarth@webkit.org>
Reviewed by Eric Seidel.
Don't let local files access web URLs
https://bugs.webkit.org/show_bug.cgi?id=28480
* Api/qwebsettings.cpp:
(QWebSettings::QWebSettings):
2009-08-19 Aaron Boodman <aa@chromium.org>
Speculative build break fix for qt.
* Api/qwebsecurityorigin.cpp:
(QWebSecurityOrigin::whiteListAccessFromOrigin):
* Api/qwebsecurityorigin.h:
2009-08-19 Aaron Boodman <aa@chromium.org>
Reviewed by David Levin.
https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
specify a more granular policy for cross-origin XHR access.
* Api/qwebsecurityorigin.cpp: Add API to manipulate origin access whitelists.
(QWebSecurityOrigin::whiteListAccessFromOrigin): Ditto.
(QWebSecurityOrigin::resetOriginAccessWhiteLists): Ditto.
* Api/qwebsecurityorigin.h: Ditto.
2009-08-18 Markus Goetz <Markus.Goetz@nokia.com>
Reviwed by Ariya Hidayat.
[Qt] For prefecthDNS, the pre-fetching has to be enabled in the
WebSettings.
* Api/qwebsettings.cpp:
(QWebSettings::QWebSettings):
* Api/qwebsettings.h:
2009-08-17 Darin Adler <darin@apple.com>
Try to fix Qt build again.
* WebCoreSupport/EditorClientQt.cpp: Move "using namespace".
2009-08-17 Darin Adler <darin@apple.com>
Try to fix Qt build.
* WebCoreSupport/EditorClientQt.cpp:
(WebCore::EditorClientQt::shouldShowDeleteInterface):
Use getAttribute(classAttr) instead of className() function.
2009-08-14 Yongjun Zhang <yongjun.zhang@nokia.com>
Reviewed by Simon Hausmann.
RVCT elftran fails to resolve QPainter::staticMetaObject coming with
QWebView::RenderHints property.
This is a temporary fix and will be revereted when the right symbols
exported from Qt lib in S60.
https://bugs.webkit.org/show_bug.cgi?id=28181
* Api/qwebview.h:
2009-08-14 Laszlo Gombos <laszlo.1.gombos@nokia.com>
Reviewed by Simon Hausmann.
[Qt] Public API to configure the storage path for HTML5 localStorage
https://bugs.webkit.org/show_bug.cgi?id=28036
Disables LocalStorage for QtWebKit by default by setting
QWebSettings::LocalStorageEnabled to false.
Sets up a default for the LocalStorage path so that clients would only
need to enable the LocalStorageEnabled setting to turn on LocalStoragre
support.
Turn on LocalStorage support for QtLauncher and the relevant test
since LocalStorage is now disabled by default for QtWebkit.
* Api/qwebpage.cpp:
(defaultCachePath):
(initializeApplicationCachePathIfNecessary):
(QWebPagePrivate::QWebPagePrivate):
* Api/qwebsettings.cpp:
(QWebSettingsPrivate::apply):
(QWebSettings::QWebSettings):
(QWebSettings::setLocalStoragePath):
(QWebSettings::localStoragePath):
* Api/qwebsettings.h:
* QtLauncher/main.cpp:
(main):
* tests/qwebpage/tst_qwebpage.cpp:
(tst_QWebPage::multiplePageGroupsAndLocalStorage):
2009-08-14 Yael Aharon <yael.aharon@nokia.com>
Reviewed by Simon Hausmann.
[Qt] Allow applications to register their own local URL scheme.
https://bugs.webkit.org/show_bug.cgi?id=28240
* Api/qwebsecurityorigin.cpp:
(QWebSecurityOrigin::addLocalScheme):
(QWebSecurityOrigin::removeLocalScheme):
(QWebSecurityOrigin::localSchemes):
* Api/qwebsecurityorigin.h:
* tests/qwebpage/tst_qwebpage.cpp:
(tst_QWebPage::localURLSchemes):
2009-08-13 Mark Rowe <mrowe@apple.com>
Try and fix the Qt build.
* Api/qwebelement.cpp:
2009-08-13 Kavindra Devi Palaraja <kavindra.palaraja@nokia.com>
Reviewed by Simon Hausmann.
Doc - Some cleanup on the documentation of QWebElement
* Api/qwebelement.cpp:
2009-08-13 Norbert Leser <norbert.leser@nokia.com>
Reviewed by Simon Hausmann.
Symbian target components (library and executable files)
require Unique Identifiers (i.e., UID3).
These identifiers are defined in the respective project
files, conditionally for "symbian" platform.
* QtLauncher/QtLauncher.pro:
* tests/qwebelement/qwebelement.pro:
* tests/qwebframe/qwebframe.pro:
* tests/qwebhistory/qwebhistory.pro:
* tests/qwebhistoryinterface/qwebhistoryinterface.pro:
* tests/qwebpage/qwebpage.pro:
* tests/qwebview/qwebview.pro:
2009-08-12 George Wright <george.wright@torchmobile.com>
Reviewed by Adam Treat.
Initialise zoom levels independent of whether a URL is valid or not to
fix https://bugs.webkit.org/show_bug.cgi?id=28162
* QtLauncher/main.cpp:
(MainWindow::MainWindow):
2009-08-12 Joerg Bornemann <joerg.bornemann@trolltech.com>
Reviewed by Simon Hausmann.
QtWebKit compile fix for Windows CE
There's no getenv on Windows CE, use qgetenv instead.
* Api/qwebpage.cpp:
(qt_drt_overwritePluginDirectories):
2009-08-10 Kavindra Palaraja <kavindra.palaraja@nokia.com>
Reviewed by Simon Hausmann.
Various fixes and improvements to the QWebPluginInfo, QWebPluginDatabase and QWebSettings documentation.
* Api/qwebplugindatabase.cpp:
* Api/qwebsettings.cpp:
2009-08-08 Volker Hilsheimer <volker.hilsheimer@nokia.com>
Reviewed by Simon Hausmann.
Doc: there is no group of explicitly shared classes, only one class uses this.
Explain the implications in the QWebHistoryItem documentation, and get rid
of the "group".
* Api/qwebhistory.cpp:
2009-08-05 Csaba Osztrogonac <oszi@inf.u-szeged.hu>
Reviewed by Simon Hausmann.
[Qt] Fix build error caused by http://trac.webkit.org/changeset/46763
* Api/qwebpluginfactory.h: Export macro added.
2009-08-04 Antonio Gomes <antonio.gomes@openbossa.org>
Reviewed by Simon Hausmann.
[Qt] QWebFrame::requestedUrl method can mis-behave in case of unhandled sslErrors.
https://bugs.webkit.org/show_bug.cgi?id=27804
* Api/qwebframe.cpp:
(QWebFrame::requestedUrl):
* tests/qwebframe/tst_qwebframe.cpp:
2009-08-04 Simon Hausmann <simon.hausmann@nokia.com>
Reviewed by Tor Arne Vestbø.
Rename QWebPlugin to QWebPluginInfo, as discussed on IRC.
* Api/qwebplugindatabase.cpp:
(QWebPluginInfoPrivate::QWebPluginInfoPrivate):
(QWebPluginInfo::QWebPluginInfo):
(QWebPluginInfo::~QWebPluginInfo):
(QWebPluginInfo::name):
(QWebPluginInfo::description):
(QWebPluginInfo::mimeTypes):
(QWebPluginInfo::supportsMimeType):
(QWebPluginInfo::path):
(QWebPluginInfo::isNull):
(QWebPluginInfo::setEnabled):
(QWebPluginInfo::isEnabled):
(QWebPluginInfo::operator==):
(QWebPluginInfo::operator!=):
(QWebPluginInfo::operator=):
(QWebPluginDatabase::plugins):
(QWebPluginDatabase::pluginForMimeType):
(QWebPluginDatabase::setPreferredPluginForMimeType):
* Api/qwebplugindatabase.h:
* Api/qwebplugindatabase_p.h:
* tests/qwebplugindatabase/tst_qwebplugindatabase.cpp:
(tst_QWebPluginDatabase::installedPlugins):
(tst_QWebPluginDatabase::searchPaths):
(tst_QWebPluginDatabase::null_data):
(tst_QWebPluginDatabase::null):
(tst_QWebPluginDatabase::pluginForMimeType):
(tst_QWebPluginDatabase::enabled):
(tst_QWebPluginDatabase::operatorequal_data):
(tst_QWebPluginDatabase::operatorequal):
(tst_QWebPluginDatabase::preferredPlugin):
2009-08-04 Simon Hausmann <simon.hausmann@nokia.com>
Reviewed by Adam Treat.
Replace QWebPlugin::MimeType with a typedef to
QWebPluginFactory::MimeType.
* Api/qwebplugindatabase.cpp:
* Api/qwebplugindatabase.h:
* Api/qwebpluginfactory.cpp:
(QWebPluginFactory::MimeType::operator==):
* Api/qwebpluginfactory.h:
2009-08-04 Jakub Wieczorek <faw217@gmail.com>
Reviewed by Simon Hausmann.
Add QWebPluginDatabase API to the Qt API.
https://bugs.webkit.org/show_bug.cgi?id=27651
* Api/headers.pri:
* Api/qwebplugindatabase.cpp: Added.
(QWebPluginPrivate::QWebPluginPrivate):
(QWebPluginDatabasePrivate::QWebPluginDatabasePrivate):
(QWebPlugin::MimeType::operator==):
(QWebPlugin::QWebPlugin):
(QWebPlugin::~QWebPlugin):
(QWebPlugin::name):
(QWebPlugin::description):
(QWebPlugin::mimeTypes):
(QWebPlugin::supportsMimeType):
(QWebPlugin::path):
(QWebPlugin::isNull):
(QWebPlugin::setEnabled):
(QWebPlugin::isEnabled):
(QWebPlugin::operator==):
(QWebPlugin::operator!=):
(QWebPlugin::operator=):
(QWebPluginDatabase::QWebPluginDatabase):
(QWebPluginDatabase::~QWebPluginDatabase):
(QWebPluginDatabase::plugins):
(QWebPluginDatabase::defaultSearchPaths):
(QWebPluginDatabase::searchPaths):
(QWebPluginDatabase::setSearchPaths):
(QWebPluginDatabase::addSearchPath):
(QWebPluginDatabase::refresh):
(QWebPluginDatabase::pluginForMimeType):
(QWebPluginDatabase::setPreferredPluginForMimeType):
* Api/qwebplugindatabase.h: Added.
* Api/qwebplugindatabase_p.h: Added.
* Api/qwebsettings.cpp:
(QWebSettings::pluginDatabase):
* Api/qwebsettings.h:
* tests/qwebplugindatabase/qwebplugindatabase.pro: Added.
* tests/qwebplugindatabase/tst_qwebplugindatabase.cpp: Added.
(tst_QWebPluginDatabase::installedPlugins):
(tst_QWebPluginDatabase::searchPaths):
(tst_QWebPluginDatabase::null_data):
(tst_QWebPluginDatabase::null):
(tst_QWebPluginDatabase::pluginForMimeType):
(tst_QWebPluginDatabase::enabled):
(tst_QWebPluginDatabase::operatorequal_data):
(tst_QWebPluginDatabase::operatorequal):
(tst_QWebPluginDatabase::preferredPlugin):
* tests/tests.pro:
2009-08-03 Balazs Kelemen <kelemen.balazs.3@stud.u-szeged.hu>
Reviewed by Simon Hausmann.
Do memory cleanup when running robotized QtLauncher in debug as well.
* QtLauncher/main.cpp:
(launcherMain):
(main):
2009-07-30 Laszlo Gombos <laszlo.1.gombos@nokia.com>
Reviewed by Tor Arne Vestbø.
[Qt] Initialize HTML5 Application Cache for QtWebKit to a sensible default
https://bugs.webkit.org/show_bug.cgi?id=27866
* Api/qwebpage.cpp:
(initializeApplicationCachePathIfNecessary):
(QWebPagePrivate::QWebPagePrivate):
2009-07-31 Jakob Petsovits <jakob.petsovits@torchmobile.com>
Reviewed by Adam Treat.
Build QtWebKit without benchmark tests for Qt < 4.5.
https://bugs.webkit.org/show_bug.cgi?id=27886
The QBENCHMARK macro is only available from 4.5 on,
so builds for Qt < 4.5 shouldn't try to build those.
* tests/tests.pro:
2009-07-31 Kenneth Rohde Christiansen <kenneth@webkit.org>
Reviewed by Adam Treat.
Fix warning by migrating use of QString.sprintf(...) to
QString.arg().arg()...
* WebCoreSupport/EditorClientQt.cpp:
(dumpRange):
2009-07-31 Kenneth Rohde Christiansen <kenneth@webkit.org>
Reviewed by Tor Arne Vestbø.
Expose the Offline Web Application Cache in the Qt API.
* Api/qwebsettings.cpp:
(QWebSettings::QWebSettings):
(QWebSettings::setOfflineWebApplicationCachePath):
(QWebSettings::offlineWebApplicationCachePath):
(QWebSettings::setOfflineWebApplicationCacheQuota):
(QWebSettings::offlineWebApplicationCacheQuota):
* Api/qwebsettings.h:
2009-07-30 Kenneth Rohde Christiansen <kenneth@webkit.org>
Reviewed by Adam Treat.
Add missing Q_OBJECT to class inheriting from QObject.
* tests/qwebframe/tst_qwebframe.cpp:
2009-07-30 Kenneth Rohde Christiansen <kenneth@webkit.org>
Reviewed by Adam Treat.
Fix indentation.
* tests/qwebframe/tst_qwebframe.cpp:
2009-07-30 Volker Hilsheimer <volker.hilsheimer@nokia.com>
Reviewed by Simon Hausmann.
Fix documentation links to examples.
* Api/qwebview.cpp:
2009-07-30 Balazs Kelemen <kelemen.balazs.3@stud.u-szeged.hu>
Reviewed by Simon Hausmann.
Allocate MainWindow on heap in robotized QtLauncher as well.
* QtLauncher/main.cpp:
(main):
2009-07-29 Kevin McCullough <kmccullough@apple.com>
Reviewed by Darin Adler.
Added foundation work to allow a testing infrastructure for the Web
Inspector.
* WebCoreSupport/InspectorClientQt.cpp:
(WebCore::InspectorClientQt::inspectorWindowObjectCleared):
* WebCoreSupport/InspectorClientQt.h:
2009-07-29 Zoltan Herczeg <zherczeg@inf.u-szeged.hu>
Reviewed by Simon Hausmann.
[Qt] In debug mode, this fix frees cached resources
and other unreferenced objects (by calling the
garbage collector) to remove the LEAK messages.
https://bugs.webkit.org/show_bug.cgi?id=27767
* Api/qwebframe.cpp:
(qt_drt_cache_clear):
* QtLauncher/main.cpp:
(main):
2009-07-28 Kenneth Rohde Christiansen <kenneth@webkit.org>
Fix the Qt build by adapting to the changes of ScriptObject.
* Api/qwebelement.cpp:
(setupScriptObject):
2009-07-28 Robert Hogan <robert@roberthogan.net>
Reviewed by Simon Hausmann.
Add WebKit version API to Qt.
Get the current version of WebKit from WebKit/mac/Configurations/Version.xcconfig
at compile time and make it available to Qt applications through
qWebKitVersion().
Also amend the User Agent string to place the Safari clause outside
the final bracket and to the end of the UA string.
https://bugs.webkit.org/show_bug.cgi?id=27158
Minor build tweak by Simon Hausmann (adding export macros to new functions).
* Api/headers.pri:
* Api/qwebkitversion.cpp: Added.
(webKitVersion):
(webKitMajorVersion):
(webKitMinorVersion):
* Api/qwebkitversion.h: Added.
* Api/qwebpage.cpp:
(QWebPage::userAgentForUrl):
* tests/qwebview/tst_qwebview.cpp:
(tst_QWebView::getWebKitVersion):
http://qt.nokia.com/developer/task-tracker/index_html?id=238391&method=entry
http://qt.nokia.com/developer/task-tracker/index_html?id=219344&method=entry
http://qt.nokia.com/developer/task-tracker/index_html?id=241144&method=entry
Diffstat (limited to 'src/3rdparty/webkit/JavaScriptCore/jit/JITOpcodes.cpp')
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/jit/JITOpcodes.cpp | 1935 |
1 files changed, 1851 insertions, 84 deletions
diff --git a/src/3rdparty/webkit/JavaScriptCore/jit/JITOpcodes.cpp b/src/3rdparty/webkit/JavaScriptCore/jit/JITOpcodes.cpp index da541c5..1c9cd7e 100644 --- a/src/3rdparty/webkit/JavaScriptCore/jit/JITOpcodes.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/jit/JITOpcodes.cpp @@ -32,12 +32,1764 @@ #include "JITStubCall.h" #include "JSArray.h" #include "JSCell.h" +#include "JSFunction.h" +#include "LinkBuffer.h" namespace JSC { +#if USE(JSVALUE32_64) + +void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* globalData, CodePtr* ctiStringLengthTrampoline, CodePtr* ctiVirtualCallLink, CodePtr* ctiVirtualCall, CodePtr* ctiNativeCallThunk) +{ +#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) + // (1) This function provides fast property access for string length + Label stringLengthBegin = align(); + + // regT0 holds payload, regT1 holds tag + + Jump string_failureCases1 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); + Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr)); + + // Checks out okay! - get the length from the Ustring. + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSString, m_value) + OBJECT_OFFSETOF(UString, m_rep)), regT2); + load32(Address(regT2, OBJECT_OFFSETOF(UString::Rep, len)), regT2); + + Jump string_failureCases3 = branch32(Above, regT2, Imm32(INT_MAX)); + move(regT2, regT0); + move(Imm32(JSValue::Int32Tag), regT1); + + ret(); +#endif + + // (2) Trampolines for the slow cases of op_call / op_call_eval / op_construct. + +#if ENABLE(JIT_OPTIMIZE_CALL) + // VirtualCallLink Trampoline + // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. + Label virtualCallLinkBegin = align(); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + + Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + + Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + preserveReturnAddressAfterCall(regT3); + restoreArgumentReference(); + Call callJSFunction2 = call(); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); + hasCodeBlock2.link(this); + + // Check argCount matches callee arity. + Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); + preserveReturnAddressAfterCall(regT3); + emitPutJITStubArg(regT3, 1); // return address + restoreArgumentReference(); + Call callArityCheck2 = call(); + move(regT1, callFrameRegister); + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); + arityCheckOkay2.link(this); + + isNativeFunc2.link(this); + + compileOpCallInitializeCallFrame(); + + preserveReturnAddressAfterCall(regT3); + emitPutJITStubArg(regT3, 1); // return address + restoreArgumentReference(); + Call callLazyLinkCall = call(); + restoreReturnAddressBeforeReturn(regT3); + jump(regT0); +#endif // ENABLE(JIT_OPTIMIZE_CALL) + + // VirtualCall Trampoline + // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. + Label virtualCallBegin = align(); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + + Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + + Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + preserveReturnAddressAfterCall(regT3); + restoreArgumentReference(); + Call callJSFunction1 = call(); + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + hasCodeBlock3.link(this); + + // Check argCount matches callee arity. + Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); + preserveReturnAddressAfterCall(regT3); + emitPutJITStubArg(regT3, 1); // return address + restoreArgumentReference(); + Call callArityCheck1 = call(); + move(regT1, callFrameRegister); + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + arityCheckOkay3.link(this); + + isNativeFunc3.link(this); + + compileOpCallInitializeCallFrame(); + loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCode)), regT0); + jump(regT0); + +#if PLATFORM(X86) + Label nativeCallThunk = align(); + preserveReturnAddressAfterCall(regT0); + emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address + + // Load caller frame's scope chain into this callframe so that whatever we call can + // get to its global data. + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT1); + emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT1); + emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); + + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); + + /* We have two structs that we use to describe the stackframe we set up for our + * call to native code. NativeCallFrameStructure describes the how we set up the stack + * in advance of the call. NativeFunctionCalleeSignature describes the callframe + * as the native code expects it. We do this as we are using the fastcall calling + * convention which results in the callee popping its arguments off the stack, but + * not the rest of the callframe so we need a nice way to ensure we increment the + * stack pointer by the right amount after the call. + */ + +#if COMPILER(MSVC) || PLATFORM(LINUX) +#if COMPILER(MSVC) +#pragma pack(push) +#pragma pack(4) +#endif // COMPILER(MSVC) + struct NativeCallFrameStructure { + // CallFrame* callFrame; // passed in EDX + JSObject* callee; + JSValue thisValue; + ArgList* argPointer; + ArgList args; + JSValue result; + }; + struct NativeFunctionCalleeSignature { + JSObject* callee; + JSValue thisValue; + ArgList* argPointer; + }; +#if COMPILER(MSVC) +#pragma pack(pop) +#endif // COMPILER(MSVC) +#else + struct NativeCallFrameStructure { + // CallFrame* callFrame; // passed in ECX + // JSObject* callee; // passed in EDX + JSValue thisValue; + ArgList* argPointer; + ArgList args; + }; + struct NativeFunctionCalleeSignature { + JSValue thisValue; + ArgList* argPointer; + }; +#endif + + const int NativeCallFrameSize = (sizeof(NativeCallFrameStructure) + 15) & ~15; + // Allocate system stack frame + subPtr(Imm32(NativeCallFrameSize), stackPointerRegister); + + // Set up arguments + subPtr(Imm32(1), regT0); // Don't include 'this' in argcount + + // push argcount + storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_argCount))); + + // Calculate the start of the callframe header, and store in regT1 + addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int)sizeof(Register)), callFrameRegister, regT1); + + // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT0) + mul32(Imm32(sizeof(Register)), regT0, regT0); + subPtr(regT0, regT1); + storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_args))); + + // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register) + addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, args)), stackPointerRegister, regT0); + storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, argPointer))); + + // regT1 currently points to the first argument, regT1 - sizeof(Register) points to 'this' + loadPtr(Address(regT1, -(int)sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); + loadPtr(Address(regT1, -(int)sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT3); + storePtr(regT2, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + storePtr(regT3, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + +#if COMPILER(MSVC) || PLATFORM(LINUX) + // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register) + addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx); + + // Plant callee + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax); + storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee))); + + // Plant callframe + move(callFrameRegister, X86Registers::edx); + + call(Address(X86Registers::eax, OBJECT_OFFSETOF(JSFunction, m_data))); + + // JSValue is a non-POD type, so eax points to it + emitLoad(0, regT1, regT0, X86Registers::eax); +#else + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx); // callee + move(callFrameRegister, X86Registers::ecx); // callFrame + call(Address(X86Registers::edx, OBJECT_OFFSETOF(JSFunction, m_data))); +#endif + + // We've put a few temporaries on the stack in addition to the actual arguments + // so pull them off now + addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister); + + // Check for an exception + // FIXME: Maybe we can optimize this comparison to JSValue(). + move(ImmPtr(&globalData->exception), regT2); + Jump sawException1 = branch32(NotEqual, tagFor(0, regT2), Imm32(JSValue::CellTag)); + Jump sawException2 = branch32(NonZero, payloadFor(0, regT2), Imm32(0)); + + // Grab the return address. + emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT3); + + // Restore our caller's "r". + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); + + // Return. + restoreReturnAddressBeforeReturn(regT3); + ret(); + + // Handle an exception + sawException1.link(this); + sawException2.link(this); + // Grab the return address. + emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); + move(ImmPtr(&globalData->exceptionLocation), regT2); + storePtr(regT1, regT2); + move(ImmPtr(reinterpret_cast<void*>(ctiVMThrowTrampoline)), regT2); + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); + poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); + restoreReturnAddressBeforeReturn(regT2); + ret(); + +#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL) +#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform." +#else + breakpoint(); +#endif + +#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) + Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1); + Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2); + Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3); +#endif + + // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. + LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size())); + +#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) + patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail)); + patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail)); + patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail)); +#endif + patchBuffer.link(callArityCheck1, FunctionPtr(cti_op_call_arityCheck)); + patchBuffer.link(callJSFunction1, FunctionPtr(cti_op_call_JSFunction)); +#if ENABLE(JIT_OPTIMIZE_CALL) + patchBuffer.link(callArityCheck2, FunctionPtr(cti_op_call_arityCheck)); + patchBuffer.link(callJSFunction2, FunctionPtr(cti_op_call_JSFunction)); + patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall)); +#endif + + CodeRef finalCode = patchBuffer.finalizeCode(); + *executablePool = finalCode.m_executablePool; + + *ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin); + *ctiNativeCallThunk = trampolineAt(finalCode, nativeCallThunk); +#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) + *ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin); +#else + UNUSED_PARAM(ctiStringLengthTrampoline); +#endif +#if ENABLE(JIT_OPTIMIZE_CALL) + *ctiVirtualCallLink = trampolineAt(finalCode, virtualCallLinkBegin); +#else + UNUSED_PARAM(ctiVirtualCallLink); +#endif +} + +void JIT::emit_op_mov(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src = currentInstruction[2].u.operand; + + if (m_codeBlock->isConstantRegisterIndex(src)) + emitStore(dst, getConstantOperand(src)); + else { + emitLoad(src, regT1, regT0); + emitStore(dst, regT1, regT0); + map(m_bytecodeIndex + OPCODE_LENGTH(op_mov), dst, regT1, regT0); + } +} + +void JIT::emit_op_end(Instruction* currentInstruction) +{ + if (m_codeBlock->needsFullScopeChain()) + JITStubCall(this, cti_op_end).call(); + ASSERT(returnValueRegister != callFrameRegister); + emitLoad(currentInstruction[1].u.operand, regT1, regT0); + restoreReturnAddressBeforeReturn(Address(callFrameRegister, RegisterFile::ReturnPC * static_cast<int>(sizeof(Register)))); + ret(); +} + +void JIT::emit_op_jmp(Instruction* currentInstruction) +{ + unsigned target = currentInstruction[1].u.operand; + addJump(jump(), target + 1); +} + +void JIT::emit_op_loop(Instruction* currentInstruction) +{ + unsigned target = currentInstruction[1].u.operand; + emitTimeoutCheck(); + addJump(jump(), target + 1); +} + +void JIT::emit_op_loop_if_less(Instruction* currentInstruction) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + emitTimeoutCheck(); + + if (isOperandConstantImmediateInt(op1)) { + emitLoad(op2, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addJump(branch32(GreaterThan, regT0, Imm32(getConstantOperand(op1).asInt32())), target + 3); + return; + } + + if (isOperandConstantImmediateInt(op2)) { + emitLoad(op1, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addJump(branch32(LessThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target + 3); + return; + } + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + addJump(branch32(LessThan, regT0, regT2), target + 3); +} + +void JIT::emitSlow_op_loop_if_less(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + + JITStubCall stubCall(this, cti_op_loop_if_less); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 3); +} + +void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + emitTimeoutCheck(); + + if (isOperandConstantImmediateInt(op1)) { + emitLoad(op2, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op1).asInt32())), target + 3); + return; + } + + if (isOperandConstantImmediateInt(op2)) { + emitLoad(op1, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addJump(branch32(LessThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target + 3); + return; + } + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + addJump(branch32(LessThanOrEqual, regT0, regT2), target + 3); +} + +void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + + JITStubCall stubCall(this, cti_op_loop_if_lesseq); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 3); +} + +void JIT::emit_op_new_object(Instruction* currentInstruction) +{ + JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_instanceof(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned value = currentInstruction[2].u.operand; + unsigned baseVal = currentInstruction[3].u.operand; + unsigned proto = currentInstruction[4].u.operand; + + // Load the operands (baseVal, proto, and value respectively) into registers. + // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result. + emitLoadPayload(proto, regT1); + emitLoadPayload(baseVal, regT0); + emitLoadPayload(value, regT2); + + // Check that baseVal & proto are cells. + emitJumpSlowCaseIfNotJSCell(proto); + emitJumpSlowCaseIfNotJSCell(baseVal); + + // Check that baseVal is an object, that it 'ImplementsHasInstance' but that it does not 'OverridesHasInstance'. + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); + addSlowCase(branch32(NotEqual, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); // FIXME: Maybe remove this test. + addSlowCase(branchTest32(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsHasInstance))); // FIXME: TOT checks ImplementsDefaultHasInstance. + + // If value is not an Object, return false. + emitLoadTag(value, regT0); + Jump valueIsImmediate = branch32(NotEqual, regT0, Imm32(JSValue::CellTag)); + loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); + Jump valueIsNotObject = branch32(NotEqual, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)); // FIXME: Maybe remove this test. + + // Check proto is object. + loadPtr(Address(regT1, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); + addSlowCase(branch32(NotEqual, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); + + // Optimistically load the result true, and start looping. + // Initially, regT1 still contains proto and regT2 still contains value. + // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain. + move(Imm32(JSValue::TrueTag), regT0); + Label loop(this); + + // Load the prototype of the object in regT2. If this is equal to regT1 - WIN! + // Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again. + loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + load32(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); + Jump isInstance = branchPtr(Equal, regT2, regT1); + branch32(NotEqual, regT2, Imm32(0), loop); + + // We get here either by dropping out of the loop, or if value was not an Object. Result is false. + valueIsImmediate.link(this); + valueIsNotObject.link(this); + move(Imm32(JSValue::FalseTag), regT0); + + // isInstance jumps right down to here, to skip setting the result to false (it has already set true). + isInstance.link(this); + emitStoreBool(dst, regT0); +} + +void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned value = currentInstruction[2].u.operand; + unsigned baseVal = currentInstruction[3].u.operand; + unsigned proto = currentInstruction[4].u.operand; + + linkSlowCaseIfNotJSCell(iter, baseVal); + linkSlowCaseIfNotJSCell(iter, proto); + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_instanceof); + stubCall.addArgument(value); + stubCall.addArgument(baseVal); + stubCall.addArgument(proto); + stubCall.call(dst); +} + +void JIT::emit_op_new_func(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_new_func); + stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand))); + stubCall.call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_get_global_var(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(currentInstruction[2].u.jsCell); + ASSERT(globalObject->isGlobalObject()); + int index = currentInstruction[3].u.operand; + + loadPtr(&globalObject->d()->registers, regT2); + + emitLoad(index, regT1, regT0, regT2); + emitStore(dst, regT1, regT0); + map(m_bytecodeIndex + OPCODE_LENGTH(op_get_global_var), dst, regT1, regT0); +} + +void JIT::emit_op_put_global_var(Instruction* currentInstruction) +{ + JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(currentInstruction[1].u.jsCell); + ASSERT(globalObject->isGlobalObject()); + int index = currentInstruction[2].u.operand; + int value = currentInstruction[3].u.operand; + + emitLoad(value, regT1, regT0); + + loadPtr(&globalObject->d()->registers, regT2); + emitStore(index, regT1, regT0, regT2); + map(m_bytecodeIndex + OPCODE_LENGTH(op_put_global_var), value, regT1, regT0); +} + +void JIT::emit_op_get_scoped_var(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int index = currentInstruction[2].u.operand; + int skip = currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain(); + + emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2); + while (skip--) + loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2); + + loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2); + loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, d)), regT2); + loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject::JSVariableObjectData, registers)), regT2); + + emitLoad(index, regT1, regT0, regT2); + emitStore(dst, regT1, regT0); + map(m_bytecodeIndex + OPCODE_LENGTH(op_get_scoped_var), dst, regT1, regT0); +} + +void JIT::emit_op_put_scoped_var(Instruction* currentInstruction) +{ + int index = currentInstruction[1].u.operand; + int skip = currentInstruction[2].u.operand + m_codeBlock->needsFullScopeChain(); + int value = currentInstruction[3].u.operand; + + emitLoad(value, regT1, regT0); + + emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2); + while (skip--) + loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2); + + loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2); + loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, d)), regT2); + loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject::JSVariableObjectData, registers)), regT2); + + emitStore(index, regT1, regT0, regT2); + map(m_bytecodeIndex + OPCODE_LENGTH(op_put_scoped_var), value, regT1, regT0); +} + +void JIT::emit_op_tear_off_activation(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_tear_off_activation); + stubCall.addArgument(currentInstruction[1].u.operand); + stubCall.call(); +} + +void JIT::emit_op_tear_off_arguments(Instruction*) +{ + JITStubCall(this, cti_op_tear_off_arguments).call(); +} + +void JIT::emit_op_new_array(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_new_array); + stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); + stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); + stubCall.call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_resolve(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_resolve); + stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); + stubCall.call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_to_primitive(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int src = currentInstruction[2].u.operand; + + emitLoad(src, regT1, regT0); + + Jump isImm = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); + addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr))); + isImm.link(this); + + if (dst != src) + emitStore(dst, regT1, regT0); + map(m_bytecodeIndex + OPCODE_LENGTH(op_to_primitive), dst, regT1, regT0); +} + +void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + int dst = currentInstruction[1].u.operand; + + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_to_primitive); + stubCall.addArgument(regT1, regT0); + stubCall.call(dst); +} + +void JIT::emit_op_strcat(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_strcat); + stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); + stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); + stubCall.call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_loop_if_true(Instruction* currentInstruction) +{ + unsigned cond = currentInstruction[1].u.operand; + unsigned target = currentInstruction[2].u.operand; + + emitTimeoutCheck(); + + emitLoad(cond, regT1, regT0); + + Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); + addJump(branch32(NotEqual, regT0, Imm32(0)), target + 2); + Jump isNotZero = jump(); + + isNotInteger.link(this); + + addJump(branch32(Equal, regT1, Imm32(JSValue::TrueTag)), target + 2); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::FalseTag))); + + isNotZero.link(this); +} + +void JIT::emitSlow_op_loop_if_true(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned cond = currentInstruction[1].u.operand; + unsigned target = currentInstruction[2].u.operand; + + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_jtrue); + stubCall.addArgument(cond); + stubCall.call(); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 2); +} + +void JIT::emit_op_resolve_base(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_resolve_base); + stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); + stubCall.call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_resolve_skip(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_resolve_skip); + stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); + stubCall.addArgument(Imm32(currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain())); + stubCall.call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_resolve_global(Instruction* currentInstruction) +{ + // FIXME: Optimize to use patching instead of so many memory accesses. + + unsigned dst = currentInstruction[1].u.operand; + void* globalObject = currentInstruction[2].u.jsCell; + + unsigned currentIndex = m_globalResolveInfoIndex++; + void* structureAddress = &(m_codeBlock->globalResolveInfo(currentIndex).structure); + void* offsetAddr = &(m_codeBlock->globalResolveInfo(currentIndex).offset); + + // Verify structure. + move(ImmPtr(globalObject), regT0); + loadPtr(structureAddress, regT1); + addSlowCase(branchPtr(NotEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)))); + + // Load property. + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_externalStorage)), regT2); + load32(offsetAddr, regT3); + load32(BaseIndex(regT2, regT3, TimesEight), regT0); // payload + load32(BaseIndex(regT2, regT3, TimesEight, 4), regT1); // tag + emitStore(dst, regT1, regT0); + map(m_bytecodeIndex + OPCODE_LENGTH(op_resolve_global), dst, regT1, regT0); +} + +void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + void* globalObject = currentInstruction[2].u.jsCell; + Identifier* ident = &m_codeBlock->identifier(currentInstruction[3].u.operand); + + unsigned currentIndex = m_globalResolveInfoIndex++; + + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_resolve_global); + stubCall.addArgument(ImmPtr(globalObject)); + stubCall.addArgument(ImmPtr(ident)); + stubCall.addArgument(Imm32(currentIndex)); + stubCall.call(dst); +} + +void JIT::emit_op_not(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src = currentInstruction[2].u.operand; + + emitLoadTag(src, regT0); + + xor32(Imm32(JSValue::FalseTag), regT0); + addSlowCase(branchTest32(NonZero, regT0, Imm32(~1))); + xor32(Imm32(JSValue::TrueTag), regT0); + + emitStoreBool(dst, regT0, (dst == src)); +} + +void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src = currentInstruction[2].u.operand; + + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_not); + stubCall.addArgument(src); + stubCall.call(dst); +} + +void JIT::emit_op_jfalse(Instruction* currentInstruction) +{ + unsigned cond = currentInstruction[1].u.operand; + unsigned target = currentInstruction[2].u.operand; + + emitLoad(cond, regT1, regT0); + + Jump isTrue = branch32(Equal, regT1, Imm32(JSValue::TrueTag)); + addJump(branch32(Equal, regT1, Imm32(JSValue::FalseTag)), target + 2); + + Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); + Jump isTrue2 = branch32(NotEqual, regT0, Imm32(0)); + addJump(jump(), target + 2); + + isNotInteger.link(this); + + addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + + zeroDouble(fpRegT0); + emitLoadDouble(cond, fpRegT1); + addJump(branchDouble(DoubleEqual, fpRegT0, fpRegT1), target + 2); + + isTrue.link(this); + isTrue2.link(this); +} + +void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned cond = currentInstruction[1].u.operand; + unsigned target = currentInstruction[2].u.operand; + + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_jtrue); + stubCall.addArgument(cond); + stubCall.call(); + emitJumpSlowToHot(branchTest32(Zero, regT0), target + 2); // Inverted. +} + +void JIT::emit_op_jtrue(Instruction* currentInstruction) +{ + unsigned cond = currentInstruction[1].u.operand; + unsigned target = currentInstruction[2].u.operand; + + emitLoad(cond, regT1, regT0); + + Jump isFalse = branch32(Equal, regT1, Imm32(JSValue::FalseTag)); + addJump(branch32(Equal, regT1, Imm32(JSValue::TrueTag)), target + 2); + + Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); + Jump isFalse2 = branch32(Equal, regT0, Imm32(0)); + addJump(jump(), target + 2); + + isNotInteger.link(this); + + addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + + zeroDouble(fpRegT0); + emitLoadDouble(cond, fpRegT1); + addJump(branchDouble(DoubleNotEqual, fpRegT0, fpRegT1), target + 2); + + isFalse.link(this); + isFalse2.link(this); +} + +void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned cond = currentInstruction[1].u.operand; + unsigned target = currentInstruction[2].u.operand; + + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_jtrue); + stubCall.addArgument(cond); + stubCall.call(); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 2); +} + +void JIT::emit_op_jeq_null(Instruction* currentInstruction) +{ + unsigned src = currentInstruction[1].u.operand; + unsigned target = currentInstruction[2].u.operand; + + emitLoad(src, regT1, regT0); + + Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); + + // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + addJump(branchTest32(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target + 2); + + Jump wasNotImmediate = jump(); + + // Now handle the immediate cases - undefined & null + isImmediate.link(this); + + set32(Equal, regT1, Imm32(JSValue::NullTag), regT2); + set32(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1); + or32(regT2, regT1); + + addJump(branchTest32(NonZero, regT1), target + 2); + + wasNotImmediate.link(this); +} + +void JIT::emit_op_jneq_null(Instruction* currentInstruction) +{ + unsigned src = currentInstruction[1].u.operand; + unsigned target = currentInstruction[2].u.operand; + + emitLoad(src, regT1, regT0); + + Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); + + // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + addJump(branchTest32(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target + 2); + + Jump wasNotImmediate = jump(); + + // Now handle the immediate cases - undefined & null + isImmediate.link(this); + + set32(Equal, regT1, Imm32(JSValue::NullTag), regT2); + set32(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1); + or32(regT2, regT1); + + addJump(branchTest32(Zero, regT1), target + 2); + + wasNotImmediate.link(this); +} + +void JIT::emit_op_jneq_ptr(Instruction* currentInstruction) +{ + unsigned src = currentInstruction[1].u.operand; + JSCell* ptr = currentInstruction[2].u.jsCell; + unsigned target = currentInstruction[3].u.operand; + + emitLoad(src, regT1, regT0); + addJump(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)), target + 3); + addJump(branchPtr(NotEqual, regT0, ImmPtr(ptr)), target + 3); +} + +void JIT::emit_op_jsr(Instruction* currentInstruction) +{ + int retAddrDst = currentInstruction[1].u.operand; + int target = currentInstruction[2].u.operand; + DataLabelPtr storeLocation = storePtrWithPatch(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst)); + addJump(jump(), target + 2); + m_jsrSites.append(JSRInfo(storeLocation, label())); +} + +void JIT::emit_op_sret(Instruction* currentInstruction) +{ + jump(Address(callFrameRegister, sizeof(Register) * currentInstruction[1].u.operand)); +} + +void JIT::emit_op_eq(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src1 = currentInstruction[2].u.operand; + unsigned src2 = currentInstruction[3].u.operand; + + emitLoad2(src1, regT1, regT0, src2, regT3, regT2); + addSlowCase(branch32(NotEqual, regT1, regT3)); + addSlowCase(branch32(Equal, regT1, Imm32(JSValue::CellTag))); + addSlowCase(branch32(Below, regT1, Imm32(JSValue::LowestTag))); + + set8(Equal, regT0, regT2, regT0); + or32(Imm32(JSValue::FalseTag), regT0); + + emitStoreBool(dst, regT0); +} + +void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + JumpList storeResult; + JumpList genericCase; + + genericCase.append(getSlowCase(iter)); // tags not equal + + linkSlowCase(iter); // tags equal and JSCell + genericCase.append(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr))); + genericCase.append(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsStringVPtr))); + + // String case. + JITStubCall stubCallEqStrings(this, cti_op_eq_strings); + stubCallEqStrings.addArgument(regT0); + stubCallEqStrings.addArgument(regT2); + stubCallEqStrings.call(); + storeResult.append(jump()); + + // Generic case. + genericCase.append(getSlowCase(iter)); // doubles + genericCase.link(this); + JITStubCall stubCallEq(this, cti_op_eq); + stubCallEq.addArgument(op1); + stubCallEq.addArgument(op2); + stubCallEq.call(regT0); + + storeResult.link(this); + or32(Imm32(JSValue::FalseTag), regT0); + emitStoreBool(dst, regT0); +} + +void JIT::emit_op_neq(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src1 = currentInstruction[2].u.operand; + unsigned src2 = currentInstruction[3].u.operand; + + emitLoad2(src1, regT1, regT0, src2, regT3, regT2); + addSlowCase(branch32(NotEqual, regT1, regT3)); + addSlowCase(branch32(Equal, regT1, Imm32(JSValue::CellTag))); + addSlowCase(branch32(Below, regT1, Imm32(JSValue::LowestTag))); + + set8(NotEqual, regT0, regT2, regT0); + or32(Imm32(JSValue::FalseTag), regT0); + + emitStoreBool(dst, regT0); +} + +void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + + JumpList storeResult; + JumpList genericCase; + + genericCase.append(getSlowCase(iter)); // tags not equal + + linkSlowCase(iter); // tags equal and JSCell + genericCase.append(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr))); + genericCase.append(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsStringVPtr))); + + // String case. + JITStubCall stubCallEqStrings(this, cti_op_eq_strings); + stubCallEqStrings.addArgument(regT0); + stubCallEqStrings.addArgument(regT2); + stubCallEqStrings.call(regT0); + storeResult.append(jump()); + + // Generic case. + genericCase.append(getSlowCase(iter)); // doubles + genericCase.link(this); + JITStubCall stubCallEq(this, cti_op_eq); + stubCallEq.addArgument(regT1, regT0); + stubCallEq.addArgument(regT3, regT2); + stubCallEq.call(regT0); + + storeResult.link(this); + xor32(Imm32(0x1), regT0); + or32(Imm32(JSValue::FalseTag), regT0); + emitStoreBool(dst, regT0); +} + +void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqType type) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src1 = currentInstruction[2].u.operand; + unsigned src2 = currentInstruction[3].u.operand; + + emitLoadTag(src1, regT0); + emitLoadTag(src2, regT1); + + // Jump to a slow case if either operand is double, or if both operands are + // cells and/or Int32s. + move(regT0, regT2); + and32(regT1, regT2); + addSlowCase(branch32(Below, regT2, Imm32(JSValue::LowestTag))); + addSlowCase(branch32(AboveOrEqual, regT2, Imm32(JSValue::CellTag))); + + if (type == OpStrictEq) + set8(Equal, regT0, regT1, regT0); + else + set8(NotEqual, regT0, regT1, regT0); + + or32(Imm32(JSValue::FalseTag), regT0); + + emitStoreBool(dst, regT0); +} + +void JIT::emit_op_stricteq(Instruction* currentInstruction) +{ + compileOpStrictEq(currentInstruction, OpStrictEq); +} + +void JIT::emitSlow_op_stricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src1 = currentInstruction[2].u.operand; + unsigned src2 = currentInstruction[3].u.operand; + + linkSlowCase(iter); + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_stricteq); + stubCall.addArgument(src1); + stubCall.addArgument(src2); + stubCall.call(dst); +} + +void JIT::emit_op_nstricteq(Instruction* currentInstruction) +{ + compileOpStrictEq(currentInstruction, OpNStrictEq); +} + +void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src1 = currentInstruction[2].u.operand; + unsigned src2 = currentInstruction[3].u.operand; + + linkSlowCase(iter); + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_nstricteq); + stubCall.addArgument(src1); + stubCall.addArgument(src2); + stubCall.call(dst); +} + +void JIT::emit_op_eq_null(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src = currentInstruction[2].u.operand; + + emitLoad(src, regT1, regT0); + Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); + + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1); + setTest8(NonZero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined), regT1); + + Jump wasNotImmediate = jump(); + + isImmediate.link(this); + + set8(Equal, regT1, Imm32(JSValue::NullTag), regT2); + set8(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1); + or32(regT2, regT1); + + wasNotImmediate.link(this); + + or32(Imm32(JSValue::FalseTag), regT1); + + emitStoreBool(dst, regT1); +} + +void JIT::emit_op_neq_null(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src = currentInstruction[2].u.operand; + + emitLoad(src, regT1, regT0); + Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); + + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1); + setTest8(Zero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined), regT1); + + Jump wasNotImmediate = jump(); + + isImmediate.link(this); + + set8(NotEqual, regT1, Imm32(JSValue::NullTag), regT2); + set8(NotEqual, regT1, Imm32(JSValue::UndefinedTag), regT1); + and32(regT2, regT1); + + wasNotImmediate.link(this); + + or32(Imm32(JSValue::FalseTag), regT1); + + emitStoreBool(dst, regT1); +} + +void JIT::emit_op_resolve_with_base(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_resolve_with_base); + stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); + stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); + stubCall.call(currentInstruction[2].u.operand); +} + +void JIT::emit_op_new_func_exp(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_new_func_exp); + stubCall.addArgument(ImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand))); + stubCall.call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_new_regexp(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_new_regexp); + stubCall.addArgument(ImmPtr(m_codeBlock->regexp(currentInstruction[2].u.operand))); + stubCall.call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_throw(Instruction* currentInstruction) +{ + unsigned exception = currentInstruction[1].u.operand; + JITStubCall stubCall(this, cti_op_throw); + stubCall.addArgument(exception); + stubCall.call(); + +#ifndef NDEBUG + // cti_op_throw always changes it's return address, + // this point in the code should never be reached. + breakpoint(); +#endif +} + +void JIT::emit_op_next_pname(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int iter = currentInstruction[2].u.operand; + int target = currentInstruction[3].u.operand; + + load32(Address(callFrameRegister, (iter * sizeof(Register))), regT0); + + JITStubCall stubCall(this, cti_op_next_pname); + stubCall.addArgument(regT0); + stubCall.call(); + + Jump endOfIter = branchTestPtr(Zero, regT0); + emitStore(dst, regT1, regT0); + map(m_bytecodeIndex + OPCODE_LENGTH(op_next_pname), dst, regT1, regT0); + addJump(jump(), target + 3); + endOfIter.link(this); +} + +void JIT::emit_op_push_scope(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_push_scope); + stubCall.addArgument(currentInstruction[1].u.operand); + stubCall.call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_pop_scope(Instruction*) +{ + JITStubCall(this, cti_op_pop_scope).call(); +} + +void JIT::emit_op_to_jsnumber(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int src = currentInstruction[2].u.operand; + + emitLoad(src, regT1, regT0); + + Jump isInt32 = branch32(Equal, regT1, Imm32(JSValue::Int32Tag)); + addSlowCase(branch32(AboveOrEqual, regT1, Imm32(JSValue::DeletedValueTag))); + isInt32.link(this); + + if (src != dst) + emitStore(dst, regT1, regT0); + map(m_bytecodeIndex + OPCODE_LENGTH(op_to_jsnumber), dst, regT1, regT0); +} + +void JIT::emitSlow_op_to_jsnumber(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + int dst = currentInstruction[1].u.operand; + + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_to_jsnumber); + stubCall.addArgument(regT1, regT0); + stubCall.call(dst); +} + +void JIT::emit_op_push_new_scope(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_push_new_scope); + stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); + stubCall.addArgument(currentInstruction[3].u.operand); + stubCall.call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_catch(Instruction* currentInstruction) +{ + unsigned exception = currentInstruction[1].u.operand; + + // This opcode only executes after a return from cti_op_throw. + + // cti_op_throw may have taken us to a call frame further up the stack; reload + // the call frame pointer to adjust. + peek(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); + + // Now store the exception returned by cti_op_throw. + emitStore(exception, regT1, regT0); + map(m_bytecodeIndex + OPCODE_LENGTH(op_catch), exception, regT1, regT0); +} + +void JIT::emit_op_jmp_scopes(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_jmp_scopes); + stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); + stubCall.call(); + addJump(jump(), currentInstruction[2].u.operand + 2); +} + +void JIT::emit_op_switch_imm(Instruction* currentInstruction) +{ + unsigned tableIndex = currentInstruction[1].u.operand; + unsigned defaultOffset = currentInstruction[2].u.operand; + unsigned scrutinee = currentInstruction[3].u.operand; + + // create jump table for switch destinations, track this switch statement. + SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTable(tableIndex); + m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Immediate)); + jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); + + JITStubCall stubCall(this, cti_op_switch_imm); + stubCall.addArgument(scrutinee); + stubCall.addArgument(Imm32(tableIndex)); + stubCall.call(); + jump(regT0); +} + +void JIT::emit_op_switch_char(Instruction* currentInstruction) +{ + unsigned tableIndex = currentInstruction[1].u.operand; + unsigned defaultOffset = currentInstruction[2].u.operand; + unsigned scrutinee = currentInstruction[3].u.operand; + + // create jump table for switch destinations, track this switch statement. + SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTable(tableIndex); + m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Character)); + jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); + + JITStubCall stubCall(this, cti_op_switch_char); + stubCall.addArgument(scrutinee); + stubCall.addArgument(Imm32(tableIndex)); + stubCall.call(); + jump(regT0); +} + +void JIT::emit_op_switch_string(Instruction* currentInstruction) +{ + unsigned tableIndex = currentInstruction[1].u.operand; + unsigned defaultOffset = currentInstruction[2].u.operand; + unsigned scrutinee = currentInstruction[3].u.operand; + + // create jump table for switch destinations, track this switch statement. + StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTable(tableIndex); + m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset)); + + JITStubCall stubCall(this, cti_op_switch_string); + stubCall.addArgument(scrutinee); + stubCall.addArgument(Imm32(tableIndex)); + stubCall.call(); + jump(regT0); +} + +void JIT::emit_op_new_error(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned type = currentInstruction[2].u.operand; + unsigned message = currentInstruction[3].u.operand; + + JITStubCall stubCall(this, cti_op_new_error); + stubCall.addArgument(Imm32(type)); + stubCall.addArgument(m_codeBlock->getConstant(message)); + stubCall.addArgument(Imm32(m_bytecodeIndex)); + stubCall.call(dst); +} + +void JIT::emit_op_debug(Instruction* currentInstruction) +{ + JITStubCall stubCall(this, cti_op_debug); + stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); + stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); + stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); + stubCall.call(); +} + + +void JIT::emit_op_enter(Instruction*) +{ + // Even though JIT code doesn't use them, we initialize our constant + // registers to zap stale pointers, to avoid unnecessarily prolonging + // object lifetime and increasing GC pressure. + for (int i = 0; i < m_codeBlock->m_numVars; ++i) + emitStore(i, jsUndefined()); +} + +void JIT::emit_op_enter_with_activation(Instruction* currentInstruction) +{ + emit_op_enter(currentInstruction); + + JITStubCall(this, cti_op_push_activation).call(currentInstruction[1].u.operand); +} + +void JIT::emit_op_create_arguments(Instruction*) +{ + Jump argsNotCell = branch32(NotEqual, tagFor(RegisterFile::ArgumentsRegister, callFrameRegister), Imm32(JSValue::CellTag)); + Jump argsNotNull = branchTestPtr(NonZero, payloadFor(RegisterFile::ArgumentsRegister, callFrameRegister)); + + // If we get here the arguments pointer is a null cell - i.e. arguments need lazy creation. + if (m_codeBlock->m_numParameters == 1) + JITStubCall(this, cti_op_create_arguments_no_params).call(); + else + JITStubCall(this, cti_op_create_arguments).call(); + + argsNotCell.link(this); + argsNotNull.link(this); +} + +void JIT::emit_op_init_arguments(Instruction*) +{ + emitStore(RegisterFile::ArgumentsRegister, JSValue(), callFrameRegister); +} + +void JIT::emit_op_convert_this(Instruction* currentInstruction) +{ + unsigned thisRegister = currentInstruction[1].u.operand; + + emitLoad(thisRegister, regT1, regT0); + + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); + + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + addSlowCase(branchTest32(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(NeedsThisConversion))); + + map(m_bytecodeIndex + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0); +} + +void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned thisRegister = currentInstruction[1].u.operand; + + linkSlowCase(iter); + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_convert_this); + stubCall.addArgument(regT1, regT0); + stubCall.call(thisRegister); +} + +void JIT::emit_op_profile_will_call(Instruction* currentInstruction) +{ + peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof (void*)); + Jump noProfiler = branchTestPtr(Zero, Address(regT2)); + + JITStubCall stubCall(this, cti_op_profile_will_call); + stubCall.addArgument(currentInstruction[1].u.operand); + stubCall.call(); + noProfiler.link(this); +} + +void JIT::emit_op_profile_did_call(Instruction* currentInstruction) +{ + peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof (void*)); + Jump noProfiler = branchTestPtr(Zero, Address(regT2)); + + JITStubCall stubCall(this, cti_op_profile_did_call); + stubCall.addArgument(currentInstruction[1].u.operand); + stubCall.call(); + noProfiler.link(this); +} + +#else // USE(JSVALUE32_64) + #define RECORD_JUMP_TARGET(targetOffset) \ do { m_labels[m_bytecodeIndex + (targetOffset)].used(); } while (false) +void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* globalData, CodePtr* ctiStringLengthTrampoline, CodePtr* ctiVirtualCallLink, CodePtr* ctiVirtualCall, CodePtr* ctiNativeCallThunk) +{ +#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) + // (2) The second function provides fast property access for string length + Label stringLengthBegin = align(); + + // Check eax is a string + Jump string_failureCases1 = emitJumpIfNotJSCell(regT0); + Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr)); + + // Checks out okay! - get the length from the Ustring. + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSString, m_value) + OBJECT_OFFSETOF(UString, m_rep)), regT0); + load32(Address(regT0, OBJECT_OFFSETOF(UString::Rep, len)), regT0); + + Jump string_failureCases3 = branch32(Above, regT0, Imm32(JSImmediate::maxImmediateInt)); + + // regT0 contains a 64 bit value (is positive, is zero extended) so we don't need sign extend here. + emitFastArithIntToImmNoCheck(regT0, regT0); + + ret(); +#endif + + // (3) Trampolines for the slow cases of op_call / op_call_eval / op_construct. + COMPILE_ASSERT(sizeof(CodeType) == 4, CodeTypeEnumMustBe32Bit); + + // VirtualCallLink Trampoline + // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. + Label virtualCallLinkBegin = align(); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + + Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + + Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + preserveReturnAddressAfterCall(regT3); + restoreArgumentReference(); + Call callJSFunction2 = call(); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); + hasCodeBlock2.link(this); + + // Check argCount matches callee arity. + Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); + preserveReturnAddressAfterCall(regT3); + emitPutJITStubArg(regT3, 1); // return address + restoreArgumentReference(); + Call callArityCheck2 = call(); + move(regT1, callFrameRegister); + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); + arityCheckOkay2.link(this); + + isNativeFunc2.link(this); + + compileOpCallInitializeCallFrame(); + preserveReturnAddressAfterCall(regT3); + emitPutJITStubArg(regT3, 1); // return address + restoreArgumentReference(); + Call callLazyLinkCall = call(); + restoreReturnAddressBeforeReturn(regT3); + jump(regT0); + + // VirtualCall Trampoline + // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. + Label virtualCallBegin = align(); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + + Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + + Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + preserveReturnAddressAfterCall(regT3); + restoreArgumentReference(); + Call callJSFunction1 = call(); + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + hasCodeBlock3.link(this); + + // Check argCount matches callee arity. + Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); + preserveReturnAddressAfterCall(regT3); + emitPutJITStubArg(regT3, 1); // return address + restoreArgumentReference(); + Call callArityCheck1 = call(); + move(regT1, callFrameRegister); + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + arityCheckOkay3.link(this); + + isNativeFunc3.link(this); + + compileOpCallInitializeCallFrame(); + loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCode)), regT0); + jump(regT0); + + Label nativeCallThunk = align(); + preserveReturnAddressAfterCall(regT0); + emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address + + // Load caller frame's scope chain into this callframe so that whatever we call can + // get to its global data. + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT1); + emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT1); + emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); + + +#if PLATFORM(X86_64) + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, X86Registers::ecx); + + // Allocate stack space for our arglist + subPtr(Imm32(sizeof(ArgList)), stackPointerRegister); + COMPILE_ASSERT((sizeof(ArgList) & 0xf) == 0, ArgList_should_by_16byte_aligned); + + // Set up arguments + subPtr(Imm32(1), X86Registers::ecx); // Don't include 'this' in argcount + + // Push argcount + storePtr(X86Registers::ecx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount))); + + // Calculate the start of the callframe header, and store in edx + addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), callFrameRegister, X86Registers::edx); + + // Calculate start of arguments as callframe header - sizeof(Register) * argcount (ecx) + mul32(Imm32(sizeof(Register)), X86Registers::ecx, X86Registers::ecx); + subPtr(X86Registers::ecx, X86Registers::edx); + + // push pointer to arguments + storePtr(X86Registers::edx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args))); + + // ArgList is passed by reference so is stackPointerRegister + move(stackPointerRegister, X86Registers::ecx); + + // edx currently points to the first argument, edx-sizeof(Register) points to 'this' + loadPtr(Address(X86Registers::edx, -(int32_t)sizeof(Register)), X86Registers::edx); + + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::esi); + + move(callFrameRegister, X86Registers::edi); + + call(Address(X86Registers::esi, OBJECT_OFFSETOF(JSFunction, m_data))); + + addPtr(Imm32(sizeof(ArgList)), stackPointerRegister); +#elif PLATFORM(X86) + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); + + /* We have two structs that we use to describe the stackframe we set up for our + * call to native code. NativeCallFrameStructure describes the how we set up the stack + * in advance of the call. NativeFunctionCalleeSignature describes the callframe + * as the native code expects it. We do this as we are using the fastcall calling + * convention which results in the callee popping its arguments off the stack, but + * not the rest of the callframe so we need a nice way to ensure we increment the + * stack pointer by the right amount after the call. + */ +#if COMPILER(MSVC) || PLATFORM(LINUX) + struct NativeCallFrameStructure { + // CallFrame* callFrame; // passed in EDX + JSObject* callee; + JSValue thisValue; + ArgList* argPointer; + ArgList args; + JSValue result; + }; + struct NativeFunctionCalleeSignature { + JSObject* callee; + JSValue thisValue; + ArgList* argPointer; + }; +#else + struct NativeCallFrameStructure { + // CallFrame* callFrame; // passed in ECX + // JSObject* callee; // passed in EDX + JSValue thisValue; + ArgList* argPointer; + ArgList args; + }; + struct NativeFunctionCalleeSignature { + JSValue thisValue; + ArgList* argPointer; + }; +#endif + const int NativeCallFrameSize = (sizeof(NativeCallFrameStructure) + 15) & ~15; + // Allocate system stack frame + subPtr(Imm32(NativeCallFrameSize), stackPointerRegister); + + // Set up arguments + subPtr(Imm32(1), regT0); // Don't include 'this' in argcount + + // push argcount + storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_argCount))); + + // Calculate the start of the callframe header, and store in regT1 + addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int)sizeof(Register)), callFrameRegister, regT1); + + // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT0) + mul32(Imm32(sizeof(Register)), regT0, regT0); + subPtr(regT0, regT1); + storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_args))); + + // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register) + addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, args)), stackPointerRegister, regT0); + storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, argPointer))); + + // regT1 currently points to the first argument, regT1 - sizeof(Register) points to 'this' + loadPtr(Address(regT1, -(int)sizeof(Register)), regT1); + storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue))); + +#if COMPILER(MSVC) || PLATFORM(LINUX) + // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register) + addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx); + + // Plant callee + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax); + storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee))); + + // Plant callframe + move(callFrameRegister, X86Registers::edx); + + call(Address(X86Registers::eax, OBJECT_OFFSETOF(JSFunction, m_data))); + + // JSValue is a non-POD type + loadPtr(Address(X86Registers::eax), X86Registers::eax); +#else + // Plant callee + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx); + + // Plant callframe + move(callFrameRegister, X86Registers::ecx); + call(Address(X86Registers::edx, OBJECT_OFFSETOF(JSFunction, m_data))); +#endif + + // We've put a few temporaries on the stack in addition to the actual arguments + // so pull them off now + addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister); + +#elif PLATFORM(ARM) && !PLATFORM_ARM_ARCH(7) + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); + + // Allocate stack space for our arglist + COMPILE_ASSERT((sizeof(ArgList) & 0x7) == 0, ArgList_should_by_8byte_aligned); + subPtr(Imm32(sizeof(ArgList)), stackPointerRegister); + + // Set up arguments + subPtr(Imm32(1), regT0); // Don't include 'this' in argcount + + // Push argcount + storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount))); + + // Calculate the start of the callframe header, and store in regT1 + move(callFrameRegister, regT1); + sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1); + + // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1) + mul32(Imm32(sizeof(Register)), regT0, regT0); + subPtr(regT0, regT1); + + // push pointer to arguments + storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args))); + + // Setup arg3: regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this' + loadPtr(Address(regT1, -(int32_t)sizeof(Register)), regT2); + + // Setup arg2: + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT1); + + // Setup arg1: + move(callFrameRegister, regT0); + + // Setup arg4: This is a plain hack + move(stackPointerRegister, ARMRegisters::S0); + + move(ctiReturnRegister, ARMRegisters::lr); + call(Address(regT1, OBJECT_OFFSETOF(JSFunction, m_data))); + + addPtr(Imm32(sizeof(ArgList)), stackPointerRegister); + +#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL) +#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform." +#else + breakpoint(); +#endif + + // Check for an exception + loadPtr(&(globalData->exception), regT2); + Jump exceptionHandler = branchTestPtr(NonZero, regT2); + + // Grab the return address. + emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); + + // Restore our caller's "r". + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); + + // Return. + restoreReturnAddressBeforeReturn(regT1); + ret(); + + // Handle an exception + exceptionHandler.link(this); + // Grab the return address. + emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); + move(ImmPtr(&globalData->exceptionLocation), regT2); + storePtr(regT1, regT2); + move(ImmPtr(reinterpret_cast<void*>(ctiVMThrowTrampoline)), regT2); + emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); + poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); + restoreReturnAddressBeforeReturn(regT2); + ret(); + + +#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) + Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1); + Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2); + Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3); +#endif + + // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. + LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size())); + +#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) + patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail)); + patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail)); + patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail)); +#endif + patchBuffer.link(callArityCheck1, FunctionPtr(cti_op_call_arityCheck)); + patchBuffer.link(callJSFunction1, FunctionPtr(cti_op_call_JSFunction)); +#if ENABLE(JIT_OPTIMIZE_CALL) + patchBuffer.link(callArityCheck2, FunctionPtr(cti_op_call_arityCheck)); + patchBuffer.link(callJSFunction2, FunctionPtr(cti_op_call_JSFunction)); + patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall)); +#endif + + CodeRef finalCode = patchBuffer.finalizeCode(); + *executablePool = finalCode.m_executablePool; + + *ctiVirtualCallLink = trampolineAt(finalCode, virtualCallLinkBegin); + *ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin); + *ctiNativeCallThunk = trampolineAt(finalCode, nativeCallThunk); +#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) + *ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin); +#else + UNUSED_PARAM(ctiStringLengthTrampoline); +#endif +} + void JIT::emit_op_mov(Instruction* currentInstruction) { int dst = currentInstruction[1].u.operand; @@ -62,7 +1814,7 @@ void JIT::emit_op_mov(Instruction* currentInstruction) void JIT::emit_op_end(Instruction* currentInstruction) { if (m_codeBlock->needsFullScopeChain()) - JITStubCall(this, JITStubs::cti_op_end).call(); + JITStubCall(this, cti_op_end).call(); ASSERT(returnValueRegister != callFrameRegister); emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueRegister); restoreReturnAddressBeforeReturn(Address(callFrameRegister, RegisterFile::ReturnPC * static_cast<int>(sizeof(Register)))); @@ -94,7 +1846,7 @@ void JIT::emit_op_loop_if_less(Instruction* currentInstruction) if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); -#if USE(ALTERNATE_JSIMMEDIATE) +#if USE(JSVALUE64) int32_t op2imm = getConstantOperandImmediateInt(op2); #else int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2))); @@ -103,7 +1855,7 @@ void JIT::emit_op_loop_if_less(Instruction* currentInstruction) } else if (isOperandConstantImmediateInt(op1)) { emitGetVirtualRegister(op2, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); -#if USE(ALTERNATE_JSIMMEDIATE) +#if USE(JSVALUE64) int32_t op1imm = getConstantOperandImmediateInt(op1); #else int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1))); @@ -127,7 +1879,7 @@ void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction) if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); -#if USE(ALTERNATE_JSIMMEDIATE) +#if USE(JSVALUE64) int32_t op2imm = getConstantOperandImmediateInt(op2); #else int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2))); @@ -143,7 +1895,7 @@ void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction) void JIT::emit_op_new_object(Instruction* currentInstruction) { - JITStubCall(this, JITStubs::cti_op_new_object).call(currentInstruction[1].u.operand); + JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand); } void JIT::emit_op_instanceof(Instruction* currentInstruction) @@ -197,8 +1949,8 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) void JIT::emit_op_new_func(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_new_func); - stubCall.addArgument(ImmPtr(m_codeBlock->function(currentInstruction[2].u.operand))); + JITStubCall stubCall(this, cti_op_new_func); + stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand))); stubCall.call(currentInstruction[1].u.operand); } @@ -214,9 +1966,14 @@ void JIT::emit_op_call_eval(Instruction* currentInstruction) void JIT::emit_op_load_varargs(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_load_varargs); - stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); - stubCall.call(currentInstruction[1].u.operand); + int argCountDst = currentInstruction[1].u.operand; + int argsOffset = currentInstruction[2].u.operand; + + JITStubCall stubCall(this, cti_op_load_varargs); + stubCall.addArgument(Imm32(argsOffset)); + stubCall.call(); + // Stores a naked int32 in the register file. + store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register))); } void JIT::emit_op_call_varargs(Instruction* currentInstruction) @@ -273,26 +2030,21 @@ void JIT::emit_op_put_scoped_var(Instruction* currentInstruction) void JIT::emit_op_tear_off_activation(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_tear_off_activation); + JITStubCall stubCall(this, cti_op_tear_off_activation); stubCall.addArgument(currentInstruction[1].u.operand, regT2); stubCall.call(); } void JIT::emit_op_tear_off_arguments(Instruction*) { - JITStubCall(this, JITStubs::cti_op_tear_off_arguments).call(); + JITStubCall(this, cti_op_tear_off_arguments).call(); } void JIT::emit_op_ret(Instruction* currentInstruction) { -#ifdef QT_BUILD_SCRIPT_LIB - JITStubCall stubCall(this, JITStubs::cti_op_debug_return); - stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.call(); -#endif // We could JIT generate the deref, only calling out to C when the refcount hits zero. if (m_codeBlock->needsFullScopeChain()) - JITStubCall(this, JITStubs::cti_op_ret_scopeChain).call(); + JITStubCall(this, cti_op_ret_scopeChain).call(); ASSERT(callFrameRegister != regT1); ASSERT(regT1 != returnValueRegister); @@ -314,7 +2066,7 @@ void JIT::emit_op_ret(Instruction* currentInstruction) void JIT::emit_op_new_array(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_new_array); + JITStubCall stubCall(this, cti_op_new_array); stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); stubCall.call(currentInstruction[1].u.operand); @@ -322,7 +2074,7 @@ void JIT::emit_op_new_array(Instruction* currentInstruction) void JIT::emit_op_resolve(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_resolve); + JITStubCall stubCall(this, cti_op_resolve); stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); stubCall.call(currentInstruction[1].u.operand); } @@ -355,20 +2107,12 @@ void JIT::emit_op_to_primitive(Instruction* currentInstruction) void JIT::emit_op_strcat(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_strcat); + JITStubCall stubCall(this, cti_op_strcat); stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); stubCall.call(currentInstruction[1].u.operand); } -void JIT::emit_op_resolve_func(Instruction* currentInstruction) -{ - JITStubCall stubCall(this, JITStubs::cti_op_resolve_func); - stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); - stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.call(currentInstruction[2].u.operand); -} - void JIT::emit_op_loop_if_true(Instruction* currentInstruction) { emitTimeoutCheck(); @@ -386,14 +2130,14 @@ void JIT::emit_op_loop_if_true(Instruction* currentInstruction) }; void JIT::emit_op_resolve_base(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_resolve_base); + JITStubCall stubCall(this, cti_op_resolve_base); stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); stubCall.call(currentInstruction[1].u.operand); } void JIT::emit_op_resolve_skip(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_resolve_skip); + JITStubCall stubCall(this, cti_op_resolve_skip); stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); stubCall.addArgument(Imm32(currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain())); stubCall.call(currentInstruction[1].u.operand); @@ -424,7 +2168,7 @@ void JIT::emit_op_resolve_global(Instruction* currentInstruction) // Slow case noMatch.link(this); - JITStubCall stubCall(this, JITStubs::cti_op_resolve_global); + JITStubCall stubCall(this, cti_op_resolve_global); stubCall.addArgument(ImmPtr(globalObject)); stubCall.addArgument(ImmPtr(ident)); stubCall.addArgument(Imm32(currentIndex)); @@ -540,7 +2284,7 @@ void JIT::emit_op_bitnot(Instruction* currentInstruction) { emitGetVirtualRegister(currentInstruction[2].u.operand, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); -#if USE(ALTERNATE_JSIMMEDIATE) +#if USE(JSVALUE64) not32(regT0); emitFastArithIntToImmNoCheck(regT0, regT0); #else @@ -551,7 +2295,7 @@ void JIT::emit_op_bitnot(Instruction* currentInstruction) void JIT::emit_op_resolve_with_base(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_resolve_with_base); + JITStubCall stubCall(this, cti_op_resolve_with_base); stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); stubCall.call(currentInstruction[2].u.operand); @@ -559,8 +2303,8 @@ void JIT::emit_op_resolve_with_base(Instruction* currentInstruction) void JIT::emit_op_new_func_exp(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_new_func_exp); - stubCall.addArgument(ImmPtr(m_codeBlock->functionExpression(currentInstruction[2].u.operand))); + JITStubCall stubCall(this, cti_op_new_func_exp); + stubCall.addArgument(ImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand))); stubCall.call(currentInstruction[1].u.operand); } @@ -601,7 +2345,7 @@ void JIT::emit_op_bitxor(Instruction* currentInstruction) void JIT::emit_op_new_regexp(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_new_regexp); + JITStubCall stubCall(this, cti_op_new_regexp); stubCall.addArgument(ImmPtr(m_codeBlock->regexp(currentInstruction[2].u.operand))); stubCall.call(currentInstruction[1].u.operand); } @@ -616,7 +2360,7 @@ void JIT::emit_op_bitor(Instruction* currentInstruction) void JIT::emit_op_throw(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_throw); + JITStubCall stubCall(this, cti_op_throw); stubCall.addArgument(currentInstruction[1].u.operand, regT2); stubCall.call(); ASSERT(regT0 == returnValueRegister); @@ -629,7 +2373,7 @@ void JIT::emit_op_throw(Instruction* currentInstruction) void JIT::emit_op_next_pname(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_next_pname); + JITStubCall stubCall(this, cti_op_next_pname); stubCall.addArgument(currentInstruction[2].u.operand, regT2); stubCall.call(); Jump endOfIter = branchTestPtr(Zero, regT0); @@ -640,14 +2384,37 @@ void JIT::emit_op_next_pname(Instruction* currentInstruction) void JIT::emit_op_push_scope(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_push_scope); + JITStubCall stubCall(this, cti_op_push_scope); stubCall.addArgument(currentInstruction[1].u.operand, regT2); stubCall.call(currentInstruction[1].u.operand); } void JIT::emit_op_pop_scope(Instruction*) { - JITStubCall(this, JITStubs::cti_op_pop_scope).call(); + JITStubCall(this, cti_op_pop_scope).call(); +} + +void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqType type) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src1 = currentInstruction[2].u.operand; + unsigned src2 = currentInstruction[3].u.operand; + + emitGetVirtualRegisters(src1, regT0, src2, regT1); + + // Jump to a slow case if either operand is a number, or if both are JSCell*s. + move(regT0, regT2); + orPtr(regT1, regT2); + addSlowCase(emitJumpIfJSCell(regT2)); + addSlowCase(emitJumpIfImmediateNumber(regT2)); + + if (type == OpStrictEq) + set32(Equal, regT1, regT0, regT0); + else + set32(NotEqual, regT1, regT0, regT0); + emitTagAsBoolImmediate(regT0); + + emitPutVirtualRegister(dst); } void JIT::emit_op_stricteq(Instruction* currentInstruction) @@ -678,7 +2445,7 @@ void JIT::emit_op_to_jsnumber(Instruction* currentInstruction) void JIT::emit_op_push_new_scope(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_push_new_scope); + JITStubCall stubCall(this, cti_op_push_new_scope); stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); stubCall.addArgument(currentInstruction[3].u.operand, regT2); stubCall.call(currentInstruction[1].u.operand); @@ -689,16 +2456,11 @@ void JIT::emit_op_catch(Instruction* currentInstruction) killLastResultRegister(); // FIXME: Implicitly treat op_catch as a labeled statement, and remove this line of code. peek(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); emitPutVirtualRegister(currentInstruction[1].u.operand); -#ifdef QT_BUILD_SCRIPT_LIB - JITStubCall stubCall(this, JITStubs::cti_op_debug_catch); - stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.call(); -#endif } void JIT::emit_op_jmp_scopes(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_jmp_scopes); + JITStubCall stubCall(this, cti_op_jmp_scopes); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); stubCall.call(); addJump(jump(), currentInstruction[2].u.operand + 2); @@ -716,7 +2478,7 @@ void JIT::emit_op_switch_imm(Instruction* currentInstruction) m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Immediate)); jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); - JITStubCall stubCall(this, JITStubs::cti_op_switch_imm); + JITStubCall stubCall(this, cti_op_switch_imm); stubCall.addArgument(scrutinee, regT2); stubCall.addArgument(Imm32(tableIndex)); stubCall.call(); @@ -734,7 +2496,7 @@ void JIT::emit_op_switch_char(Instruction* currentInstruction) m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Character)); jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); - JITStubCall stubCall(this, JITStubs::cti_op_switch_char); + JITStubCall stubCall(this, cti_op_switch_char); stubCall.addArgument(scrutinee, regT2); stubCall.addArgument(Imm32(tableIndex)); stubCall.call(); @@ -751,7 +2513,7 @@ void JIT::emit_op_switch_string(Instruction* currentInstruction) StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTable(tableIndex); m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset)); - JITStubCall stubCall(this, JITStubs::cti_op_switch_string); + JITStubCall stubCall(this, cti_op_switch_string); stubCall.addArgument(scrutinee, regT2); stubCall.addArgument(Imm32(tableIndex)); stubCall.call(); @@ -760,7 +2522,7 @@ void JIT::emit_op_switch_string(Instruction* currentInstruction) void JIT::emit_op_new_error(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_new_error); + JITStubCall stubCall(this, cti_op_new_error); stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); stubCall.addArgument(ImmPtr(JSValue::encode(m_codeBlock->getConstant(currentInstruction[3].u.operand)))); stubCall.addArgument(Imm32(m_bytecodeIndex)); @@ -769,11 +2531,10 @@ void JIT::emit_op_new_error(Instruction* currentInstruction) void JIT::emit_op_debug(Instruction* currentInstruction) { - JITStubCall stubCall(this, JITStubs::cti_op_debug); + JITStubCall stubCall(this, cti_op_debug); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); - stubCall.addArgument(Imm32(currentInstruction[4].u.operand)); stubCall.call(); } @@ -847,16 +2608,16 @@ void JIT::emit_op_enter_with_activation(Instruction* currentInstruction) for (size_t j = 0; j < count; ++j) emitInitRegister(j); - JITStubCall(this, JITStubs::cti_op_push_activation).call(currentInstruction[1].u.operand); + JITStubCall(this, cti_op_push_activation).call(currentInstruction[1].u.operand); } void JIT::emit_op_create_arguments(Instruction*) { Jump argsCreated = branchTestPtr(NonZero, Address(callFrameRegister, sizeof(Register) * RegisterFile::ArgumentsRegister)); if (m_codeBlock->m_numParameters == 1) - JITStubCall(this, JITStubs::cti_op_create_arguments_no_params).call(); + JITStubCall(this, cti_op_create_arguments_no_params).call(); else - JITStubCall(this, JITStubs::cti_op_create_arguments).call(); + JITStubCall(this, cti_op_create_arguments).call(); argsCreated.link(this); } @@ -880,7 +2641,7 @@ void JIT::emit_op_profile_will_call(Instruction* currentInstruction) peek(regT1, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof (void*)); Jump noProfiler = branchTestPtr(Zero, Address(regT1)); - JITStubCall stubCall(this, JITStubs::cti_op_profile_will_call); + JITStubCall stubCall(this, cti_op_profile_will_call); stubCall.addArgument(currentInstruction[1].u.operand, regT1); stubCall.call(); noProfiler.link(this); @@ -892,7 +2653,7 @@ void JIT::emit_op_profile_did_call(Instruction* currentInstruction) peek(regT1, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof (void*)); Jump noProfiler = branchTestPtr(Zero, Address(regT1)); - JITStubCall stubCall(this, JITStubs::cti_op_profile_did_call); + JITStubCall stubCall(this, cti_op_profile_did_call); stubCall.addArgument(currentInstruction[1].u.operand, regT1); stubCall.call(); noProfiler.link(this); @@ -905,7 +2666,7 @@ void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowC { linkSlowCase(iter); linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_convert_this); + JITStubCall stubCall(this, cti_op_convert_this); stubCall.addArgument(regT0); stubCall.call(currentInstruction[1].u.operand); } @@ -922,7 +2683,7 @@ void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowC { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_to_primitive); + JITStubCall stubCall(this, cti_op_to_primitive); stubCall.addArgument(regT0); stubCall.call(currentInstruction[1].u.operand); } @@ -938,7 +2699,7 @@ void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCas emitFastArithIntToImmNoCheck(regT1, regT1); notImm.link(this); - JITStubCall stubCall(this, JITStubs::cti_op_get_by_val); + JITStubCall stubCall(this, cti_op_get_by_val); stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(currentInstruction[1].u.operand); @@ -964,14 +2725,14 @@ void JIT::emitSlow_op_loop_if_less(Instruction* currentInstruction, Vector<SlowC unsigned target = currentInstruction[3].u.operand; if (isOperandConstantImmediateInt(op2)) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_loop_if_less); + JITStubCall stubCall(this, cti_op_loop_if_less); stubCall.addArgument(regT0); stubCall.addArgument(op2, regT2); stubCall.call(); emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 3); } else if (isOperandConstantImmediateInt(op1)) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_loop_if_less); + JITStubCall stubCall(this, cti_op_loop_if_less); stubCall.addArgument(op1, regT2); stubCall.addArgument(regT0); stubCall.call(); @@ -979,7 +2740,7 @@ void JIT::emitSlow_op_loop_if_less(Instruction* currentInstruction, Vector<SlowC } else { linkSlowCase(iter); linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_loop_if_less); + JITStubCall stubCall(this, cti_op_loop_if_less); stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(); @@ -993,7 +2754,7 @@ void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<Slo unsigned target = currentInstruction[3].u.operand; if (isOperandConstantImmediateInt(op2)) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_loop_if_lesseq); + JITStubCall stubCall(this, cti_op_loop_if_lesseq); stubCall.addArgument(regT0); stubCall.addArgument(currentInstruction[2].u.operand, regT2); stubCall.call(); @@ -1001,7 +2762,7 @@ void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<Slo } else { linkSlowCase(iter); linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_loop_if_lesseq); + JITStubCall stubCall(this, cti_op_loop_if_lesseq); stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(); @@ -1018,7 +2779,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas emitFastArithIntToImmNoCheck(regT1, regT1); notImm.link(this); { - JITStubCall stubCall(this, JITStubs::cti_op_put_by_val); + JITStubCall stubCall(this, cti_op_put_by_val); stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.addArgument(currentInstruction[3].u.operand, regT2); @@ -1029,7 +2790,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas // slow cases for immediate int accesses to arrays linkSlowCase(iter); linkSlowCase(iter); { - JITStubCall stubCall(this, JITStubs::cti_op_put_by_val_array); + JITStubCall stubCall(this, cti_op_put_by_val_array); stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.addArgument(currentInstruction[3].u.operand, regT2); @@ -1040,7 +2801,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas void JIT::emitSlow_op_loop_if_true(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_jtrue); + JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(regT0); stubCall.call(); emitJumpSlowToHot(branchTest32(NonZero, regT0), currentInstruction[2].u.operand + 2); @@ -1050,7 +2811,7 @@ void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry> { linkSlowCase(iter); xorPtr(Imm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool)), regT0); - JITStubCall stubCall(this, JITStubs::cti_op_not); + JITStubCall stubCall(this, cti_op_not); stubCall.addArgument(regT0); stubCall.call(currentInstruction[1].u.operand); } @@ -1058,7 +2819,7 @@ void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry> void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_jtrue); + JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(regT0); stubCall.call(); emitJumpSlowToHot(branchTest32(Zero, regT0), currentInstruction[2].u.operand + 2); // inverted! @@ -1067,7 +2828,7 @@ void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEnt void JIT::emitSlow_op_bitnot(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_bitnot); + JITStubCall stubCall(this, cti_op_bitnot); stubCall.addArgument(regT0); stubCall.call(currentInstruction[1].u.operand); } @@ -1075,7 +2836,7 @@ void JIT::emitSlow_op_bitnot(Instruction* currentInstruction, Vector<SlowCaseEnt void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_jtrue); + JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(regT0); stubCall.call(); emitJumpSlowToHot(branchTest32(NonZero, regT0), currentInstruction[2].u.operand + 2); @@ -1084,7 +2845,7 @@ void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntr void JIT::emitSlow_op_bitxor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_bitxor); + JITStubCall stubCall(this, cti_op_bitxor); stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(currentInstruction[1].u.operand); @@ -1093,7 +2854,7 @@ void JIT::emitSlow_op_bitxor(Instruction* currentInstruction, Vector<SlowCaseEnt void JIT::emitSlow_op_bitor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_bitor); + JITStubCall stubCall(this, cti_op_bitor); stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(currentInstruction[1].u.operand); @@ -1102,26 +2863,31 @@ void JIT::emitSlow_op_bitor(Instruction* currentInstruction, Vector<SlowCaseEntr void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_eq); + JITStubCall stubCall(this, cti_op_eq); stubCall.addArgument(regT0); stubCall.addArgument(regT1); - stubCall.call(currentInstruction[1].u.operand); + stubCall.call(); + emitTagAsBoolImmediate(regT0); + emitPutVirtualRegister(currentInstruction[1].u.operand); } void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_neq); + JITStubCall stubCall(this, cti_op_eq); stubCall.addArgument(regT0); stubCall.addArgument(regT1); - stubCall.call(currentInstruction[1].u.operand); + stubCall.call(); + xor32(Imm32(0x1), regT0); + emitTagAsBoolImmediate(regT0); + emitPutVirtualRegister(currentInstruction[1].u.operand); } void JIT::emitSlow_op_stricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { linkSlowCase(iter); linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_stricteq); + JITStubCall stubCall(this, cti_op_stricteq); stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(currentInstruction[1].u.operand); @@ -1131,7 +2897,7 @@ void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCase { linkSlowCase(iter); linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_nstricteq); + JITStubCall stubCall(this, cti_op_nstricteq); stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(currentInstruction[1].u.operand); @@ -1144,7 +2910,7 @@ void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCas linkSlowCase(iter); linkSlowCase(iter); linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_instanceof); + JITStubCall stubCall(this, cti_op_instanceof); stubCall.addArgument(currentInstruction[2].u.operand, regT2); stubCall.addArgument(currentInstruction[3].u.operand, regT2); stubCall.addArgument(currentInstruction[4].u.operand, regT2); @@ -1176,11 +2942,12 @@ void JIT::emitSlow_op_to_jsnumber(Instruction* currentInstruction, Vector<SlowCa linkSlowCaseIfNotJSCell(iter, currentInstruction[2].u.operand); linkSlowCase(iter); - JITStubCall stubCall(this, JITStubs::cti_op_to_jsnumber); + JITStubCall stubCall(this, cti_op_to_jsnumber); stubCall.addArgument(regT0); stubCall.call(currentInstruction[1].u.operand); } +#endif // USE(JSVALUE32_64) } // namespace JSC |