diff --git a/test-app/app/src/main/java/com/tns/RuntimeHelper.java b/test-app/app/src/main/java/com/tns/RuntimeHelper.java index 19021a4ac..1fa2cbd7c 100644 --- a/test-app/app/src/main/java/com/tns/RuntimeHelper.java +++ b/test-app/app/src/main/java/com/tns/RuntimeHelper.java @@ -163,41 +163,41 @@ public static Runtime initRuntime(Context context) { runtime = Runtime.initializeRuntimeWithConfiguration(config); if (isDebuggable) { -// try { -// v8Inspector = new AndroidJsV8Inspector(context.getFilesDir().getAbsolutePath(), context.getPackageName()); -// v8Inspector.start(); -// -// // the following snippet is used as means to notify the VSCode extension -// // debugger that the debugger agent has started -// File debuggerStartedFile = new File("/data/local/tmp", context.getPackageName() + "-debugger-started"); -// if (debuggerStartedFile.exists() && !debuggerStartedFile.isDirectory() && debuggerStartedFile.length() == 0) { -// java.io.FileWriter fileWriter = new java.io.FileWriter(debuggerStartedFile); -// fileWriter.write("started"); -// fileWriter.close(); -// } -// -// // check if --debug-brk flag has been set. If positive: -// // write to the file to invalidate the flag -// // inform the v8Inspector to pause the main thread -// File debugBreakFile = new File("/data/local/tmp", context.getPackageName() + "-debugbreak"); -// boolean shouldBreak = false; -// if (debugBreakFile.exists() && !debugBreakFile.isDirectory() && debugBreakFile.length() == 0) { -// java.io.FileWriter fileWriter = new java.io.FileWriter(debugBreakFile); -// fileWriter.write("started"); -// fileWriter.close(); -// -// shouldBreak = true; -// } -// -// v8Inspector.waitForDebugger(shouldBreak); -// } catch (IOException e) { -// if (Util.isDebuggableApp(context)) { -// e.printStackTrace(); -// } -// } -// -// // if app is in debuggable mode run livesync service -// // runtime needs to be initialized before the NativeScriptSyncService is enabled because it uses runtime.runScript(...) + try { + v8Inspector = new AndroidJsV8Inspector(context.getFilesDir().getAbsolutePath(), context.getPackageName()); + v8Inspector.start(); + + // the following snippet is used as means to notify the VSCode extension + // debugger that the debugger agent has started + File debuggerStartedFile = new File("/data/local/tmp", context.getPackageName() + "-debugger-started"); + if (debuggerStartedFile.exists() && !debuggerStartedFile.isDirectory() && debuggerStartedFile.length() == 0) { + java.io.FileWriter fileWriter = new java.io.FileWriter(debuggerStartedFile); + fileWriter.write("started"); + fileWriter.close(); + } + + // check if --debug-brk flag has been set. If positive: + // write to the file to invalidate the flag + // inform the v8Inspector to pause the main thread + File debugBreakFile = new File("/data/local/tmp", context.getPackageName() + "-debugbreak"); + boolean shouldBreak = false; + if (debugBreakFile.exists() && !debugBreakFile.isDirectory() && debugBreakFile.length() == 0) { + java.io.FileWriter fileWriter = new java.io.FileWriter(debugBreakFile); + fileWriter.write("started"); + fileWriter.close(); + + shouldBreak = true; + } + + v8Inspector.waitForDebugger(shouldBreak); + } catch (IOException e) { + if (Util.isDebuggableApp(context)) { + e.printStackTrace(); + } + } + + // if app is in debuggable mode run livesync service + // runtime needs to be initialized before the NativeScriptSyncService is enabled because it uses runtime.runScript(...) initLiveSync(runtime, logger, context); waitForLiveSync(context); diff --git a/test-app/runtime/CMakeLists.txt b/test-app/runtime/CMakeLists.txt index 81dad374b..57087dbbf 100644 --- a/test-app/runtime/CMakeLists.txt +++ b/test-app/runtime/CMakeLists.txt @@ -18,7 +18,7 @@ endif (CCACHE_FOUND AND (USE_CCACHE)) # "-DANDROID_STL=c++_static" is just not enough for clang++ to find some libraries in the ndk MESSAGE(STATUS "## ANDROID_NDK_ROOT: " ${ANDROID_NDK_ROOT}) -set(COMMON_CMAKE_ARGUMENTS "-std=c++14 -Werror -Wno-unused-result -mstackrealign -fexceptions -fno-builtin-stpcpy -fno-rtti -DV8_31BIT_SMIS_ON_64BIT_ARCH -DV8_31BIT_SMIS_ON_64BIT_ARCH -DV8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -DV8_EMBEDDED_BUILTINS") +set(COMMON_CMAKE_ARGUMENTS "-std=c++17 -Werror -Wno-unused-result -mstackrealign -fexceptions -fno-builtin-stpcpy -fno-rtti -DV8_31BIT_SMIS_ON_64BIT_ARCH -DV8_31BIT_SMIS_ON_64BIT_ARCH -DV8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -DV8_EMBEDDED_BUILTINS") if("${ANDROID_ABI}" MATCHES "arm64-v8a$" OR "${ANDROID_ABI}" MATCHES "x86_64$") # Enable pointer compression on 64 bit platforms @@ -63,6 +63,21 @@ else () # set(CMAKE_CXX_FLAGS "${COMMON_CMAKE_ARGUMENTS} -O3 -fvisibility=hidden -ffunction-sections -fno-data-sections") endif () +if (NOT OPTIMIZED_BUILD OR OPTIMIZED_WITH_INSPECTOR_BUILD) + # Debug builds will include the V8 inspector sources + add_definitions(-DAPPLICATION_IN_DEBUG) + + set( + INSPECTOR_SOURCES + + src/main/cpp/com_tns_AndroidJsV8Inspector.cpp + src/main/cpp/JsV8InspectorClient.cpp + ) +else () + # When building in Release mode we do not include the V8 inspector sources + set(INSPECTOR_SOURCES) +endif () + # Command info: https://cmake.org/cmake/help/v3.4/command/add_library.html # Creates(shared static) and names a library given relative sources # Gradle automatically packages shared libraries with your APK. diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-css-agent-impl.cpp b/test-app/runtime/src/main/cpp/CSSAgentImpl.cpp similarity index 71% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-css-agent-impl.cpp rename to test-app/runtime/src/main/cpp/CSSAgentImpl.cpp index 66f7278f8..184112161 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-css-agent-impl.cpp +++ b/test-app/runtime/src/main/cpp/CSSAgentImpl.cpp @@ -4,21 +4,20 @@ #include #include -#include #include -#include "v8-css-agent-impl.h" -namespace v8_inspector { +#include "CSSAgentImpl.h" +#include "utils/InspectorCommon.h" -using tns::ArgConverter; +namespace tns { namespace CSSAgentState { static const char cssEnabled[] = "cssEnabled"; } -V8CSSAgentImpl::V8CSSAgentImpl(V8InspectorSessionImpl* session, - protocol::FrontendChannel* frontendChannel, - protocol::DictionaryValue* state) +CSSAgentImpl::CSSAgentImpl(V8InspectorSessionImpl* session, + protocol::FrontendChannel* frontendChannel, + protocol::DictionaryValue* state) : m_session(session), m_frontend(frontendChannel), m_state(state), @@ -26,9 +25,9 @@ V8CSSAgentImpl::V8CSSAgentImpl(V8InspectorSessionImpl* session, Instance = this; } -V8CSSAgentImpl::~V8CSSAgentImpl() { } +CSSAgentImpl::~CSSAgentImpl() { } -void V8CSSAgentImpl::enable(std::unique_ptr callback) { +void CSSAgentImpl::enable(std::unique_ptr callback) { if (m_enabled) { callback->sendSuccess(); return; @@ -40,7 +39,7 @@ void V8CSSAgentImpl::enable(std::unique_ptr callback) { callback->sendSuccess(); } -DispatchResponse V8CSSAgentImpl::disable() { +DispatchResponse CSSAgentImpl::disable() { if (!m_enabled) { return DispatchResponse::Success(); } @@ -53,7 +52,7 @@ DispatchResponse V8CSSAgentImpl::disable() { } // Not supported -DispatchResponse V8CSSAgentImpl::getMatchedStylesForNode(int in_nodeId, Maybe* out_inlineStyle, Maybe* out_attributesStyle, Maybe>* out_matchedCSSRules, Maybe>* out_pseudoElements, Maybe>* out_inherited, Maybe>* out_cssKeyframesRules) { +DispatchResponse CSSAgentImpl::getMatchedStylesForNode(int in_nodeId, Maybe* out_inlineStyle, Maybe* out_attributesStyle, Maybe>* out_matchedCSSRules, Maybe>* out_pseudoElements, Maybe>* out_inherited, Maybe>* out_cssKeyframesRules) { //// out_inlineStyle // auto cssPropsArr = protocol::Array::create(); // auto shorthandPropArr = protocol::Array::create(); @@ -114,7 +113,7 @@ DispatchResponse V8CSSAgentImpl::getMatchedStylesForNode(int in_nodeId, Maybe* out_inlineStyle, Maybe* out_attributesStyle) { +DispatchResponse CSSAgentImpl::getInlineStylesForNode(int in_nodeId, Maybe* out_inlineStyle, Maybe* out_attributesStyle) { //// out_inlineStyle // auto cssPropsArr = protocol::Array::create(); // auto shorthandPropArr = protocol::Array::create(); @@ -137,7 +136,7 @@ DispatchResponse V8CSSAgentImpl::getInlineStylesForNode(int in_nodeId, Maybe>* out_computedStyle) { +DispatchResponse CSSAgentImpl::getComputedStyleForNode(int in_nodeId, std::unique_ptr>* out_computedStyle) { auto computedStylePropertyArr = std::make_unique>(); std::string getComputedStylesForNodeString = "getComputedStylesForNode"; @@ -169,7 +168,7 @@ DispatchResponse V8CSSAgentImpl::getComputedStyleForNode(int in_nodeId, std::uni if (maybeResult.ToLocal(&outResult)) { auto resultString = outResult->ToString(context).ToLocalChecked(); - String16 resultProtocolString = toProtocolString(isolate, resultString); + v8_inspector::String16 resultProtocolString = v8_inspector::toProtocolString(isolate, resultString); std::vector cbor; v8_crdtp::json::ConvertJSONToCBOR(v8_crdtp::span(resultProtocolString.characters16(), resultProtocolString.length()), &cbor); std::unique_ptr resultJson = protocol::Value::parseBinary(cbor.data(), cbor.size()); @@ -178,7 +177,7 @@ DispatchResponse V8CSSAgentImpl::getComputedStyleForNode(int in_nodeId, std::uni std::vector json; v8_crdtp::json::ConvertCBORToJSON(errorSupport.Errors(), &json); - auto errorSupportString = String16(reinterpret_cast(json.data()), json.size()).utf8(); + auto errorSupportString = v8_inspector::String16(reinterpret_cast(json.data()), json.size()).utf8(); if (!errorSupportString.empty()) { auto errorMessage = "Error while parsing CSSComputedStyleProperty object. "; DEBUG_WRITE_FORCE("%s Error: %s", errorMessage, errorSupportString.c_str()); @@ -197,7 +196,7 @@ DispatchResponse V8CSSAgentImpl::getComputedStyleForNode(int in_nodeId, std::uni return DispatchResponse::Success(); } -DispatchResponse V8CSSAgentImpl::getPlatformFontsForNode(int in_nodeId, std::unique_ptr>* out_fonts) { +DispatchResponse CSSAgentImpl::getPlatformFontsForNode(int in_nodeId, std::unique_ptr>* out_fonts) { auto fontsArr = std::make_unique>(); auto defaultFont = "System Font"; fontsArr->emplace_back(std::move(protocol::CSS::PlatformFontUsage::create() @@ -210,71 +209,71 @@ DispatchResponse V8CSSAgentImpl::getPlatformFontsForNode(int in_nodeId, std::uni return DispatchResponse::Success(); } -DispatchResponse V8CSSAgentImpl::getStyleSheetText(const String& in_styleSheetId, String* out_text) { +DispatchResponse CSSAgentImpl::getStyleSheetText(const String& in_styleSheetId, String* out_text) { *out_text = ""; return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::addRule(const String& in_styleSheetId, const String& in_ruleText, std::unique_ptr in_location, std::unique_ptr* out_rule) { +DispatchResponse CSSAgentImpl::addRule(const String& in_styleSheetId, const String& in_ruleText, std::unique_ptr in_location, std::unique_ptr* out_rule) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::collectClassNames(const String& in_styleSheetId, std::unique_ptr>* out_classNames) { +DispatchResponse CSSAgentImpl::collectClassNames(const String& in_styleSheetId, std::unique_ptr>* out_classNames) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::createStyleSheet(const String& in_frameId, String* out_styleSheetId) { +DispatchResponse CSSAgentImpl::createStyleSheet(const String& in_frameId, String* out_styleSheetId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::forcePseudoState(int in_nodeId, std::unique_ptr> in_forcedPseudoClasses) { +DispatchResponse CSSAgentImpl::forcePseudoState(int in_nodeId, std::unique_ptr> in_forcedPseudoClasses) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::getBackgroundColors(int in_nodeId, Maybe>* out_backgroundColors, Maybe* out_computedFontSize, Maybe* out_computedFontWeight) { +DispatchResponse CSSAgentImpl::getBackgroundColors(int in_nodeId, Maybe>* out_backgroundColors, Maybe* out_computedFontSize, Maybe* out_computedFontWeight) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::getMediaQueries(std::unique_ptr>* out_medias) { +DispatchResponse CSSAgentImpl::getMediaQueries(std::unique_ptr>* out_medias) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::setEffectivePropertyValueForNode(int in_nodeId, const String& in_propertyName, const String& in_value) { +DispatchResponse CSSAgentImpl::setEffectivePropertyValueForNode(int in_nodeId, const String& in_propertyName, const String& in_value) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::setKeyframeKey(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_keyText, std::unique_ptr* out_keyText) { +DispatchResponse CSSAgentImpl::setKeyframeKey(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_keyText, std::unique_ptr* out_keyText) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::setMediaText(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_text, std::unique_ptr* out_media) { +DispatchResponse CSSAgentImpl::setMediaText(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_text, std::unique_ptr* out_media) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::setRuleSelector(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_selector, std::unique_ptr* out_selectorList) { +DispatchResponse CSSAgentImpl::setRuleSelector(const String& in_styleSheetId, std::unique_ptr in_range, const String& in_selector, std::unique_ptr* out_selectorList) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::setStyleSheetText(const String& in_styleSheetId, const String& in_text, Maybe* out_sourceMapURL) { +DispatchResponse CSSAgentImpl::setStyleSheetText(const String& in_styleSheetId, const String& in_text, Maybe* out_sourceMapURL) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::setStyleTexts(std::unique_ptr> in_edits, std::unique_ptr>* out_styles) { +DispatchResponse CSSAgentImpl::setStyleTexts(std::unique_ptr> in_edits, std::unique_ptr>* out_styles) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::startRuleUsageTracking() { +DispatchResponse CSSAgentImpl::startRuleUsageTracking() { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::stopRuleUsageTracking(std::unique_ptr>* out_ruleUsage) { +DispatchResponse CSSAgentImpl::stopRuleUsageTracking(std::unique_ptr>* out_ruleUsage) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8CSSAgentImpl::takeCoverageDelta(std::unique_ptr>* out_coverage) { +DispatchResponse CSSAgentImpl::takeCoverageDelta(std::unique_ptr>* out_coverage) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -V8CSSAgentImpl* V8CSSAgentImpl::Instance = 0; -} \ No newline at end of file +CSSAgentImpl* CSSAgentImpl::Instance = 0; +} // namespace tns diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-css-agent-impl.h b/test-app/runtime/src/main/cpp/CSSAgentImpl.h similarity index 89% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-css-agent-impl.h rename to test-app/runtime/src/main/cpp/CSSAgentImpl.h index 2bae09cb9..3438a377f 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-css-agent-impl.h +++ b/test-app/runtime/src/main/cpp/CSSAgentImpl.h @@ -9,20 +9,23 @@ #include namespace v8_inspector { - class V8InspectorSessionImpl; +} + +namespace tns { +namespace protocol = v8_inspector::protocol; using v8_inspector::protocol::Maybe; using String = v8_inspector::String16; using protocol::DispatchResponse; +using v8_inspector::V8InspectorSessionImpl; - -class V8CSSAgentImpl : public protocol::CSS::Backend { +class CSSAgentImpl : public protocol::CSS::Backend { public: - V8CSSAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, - protocol::DictionaryValue* state); + CSSAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, + protocol::DictionaryValue* state); - ~V8CSSAgentImpl() override; + ~CSSAgentImpl() override; void enable(std::unique_ptr callback) override; DispatchResponse disable() override; @@ -47,7 +50,7 @@ class V8CSSAgentImpl : public protocol::CSS::Backend { DispatchResponse stopRuleUsageTracking(std::unique_ptr>* out_ruleUsage) override; DispatchResponse takeCoverageDelta(std::unique_ptr>* out_coverage) override; - static V8CSSAgentImpl* Instance; + static CSSAgentImpl* Instance; protocol::CSS::Frontend m_frontend; private: @@ -55,9 +58,10 @@ class V8CSSAgentImpl : public protocol::CSS::Backend { protocol::DictionaryValue* m_state; bool m_enabled; - DISALLOW_COPY_AND_ASSIGN(V8CSSAgentImpl); + CSSAgentImpl(const CSSAgentImpl&) = delete; + CSSAgentImpl& operator=(const CSSAgentImpl&) = delete; }; -} +} // namespace tns #endif //V8_CSS_AGENT_IMPL_H diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-dom-agent-impl.cpp b/test-app/runtime/src/main/cpp/DOMAgentImpl.cpp similarity index 67% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-dom-agent-impl.cpp rename to test-app/runtime/src/main/cpp/DOMAgentImpl.cpp index 294341252..d9bde478d 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-dom-agent-impl.cpp +++ b/test-app/runtime/src/main/cpp/DOMAgentImpl.cpp @@ -3,24 +3,22 @@ // #include -#include "v8-dom-agent-impl.h" #include -#include +#include #include -#include -namespace v8_inspector { +#include "DOMAgentImpl.h" +#include "utils/InspectorCommon.h" -using tns::Runtime; -using tns::ArgConverter; +namespace tns { namespace DOMAgentState { static const char domEnabled[] = "domEnabled"; } -V8DOMAgentImpl::V8DOMAgentImpl(V8InspectorSessionImpl* session, - protocol::FrontendChannel* frontendChannel, - protocol::DictionaryValue* state) +DOMAgentImpl::DOMAgentImpl(V8InspectorSessionImpl* session, + protocol::FrontendChannel* frontendChannel, + protocol::DictionaryValue* state) : m_session(session), m_frontend(frontendChannel), m_state(state), @@ -28,9 +26,9 @@ V8DOMAgentImpl::V8DOMAgentImpl(V8InspectorSessionImpl* session, Instance = this; } -V8DOMAgentImpl::~V8DOMAgentImpl() { } +DOMAgentImpl::~DOMAgentImpl() { } -DispatchResponse V8DOMAgentImpl::enable() { +DispatchResponse DOMAgentImpl::enable() { if (m_enabled) { return DispatchResponse::Success(); } @@ -42,7 +40,7 @@ DispatchResponse V8DOMAgentImpl::enable() { return DispatchResponse::Success(); } -DispatchResponse V8DOMAgentImpl::disable() { +DispatchResponse DOMAgentImpl::disable() { if (!m_enabled) { return DispatchResponse::Success(); } @@ -54,11 +52,11 @@ DispatchResponse V8DOMAgentImpl::disable() { return DispatchResponse::Success(); } -DispatchResponse V8DOMAgentImpl::getContentQuads(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, std::unique_ptr>>* out_quads) { +DispatchResponse DOMAgentImpl::getContentQuads(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, std::unique_ptr>>* out_quads) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::getDocument(Maybe in_depth, Maybe in_pierce, std::unique_ptr* out_root) { +DispatchResponse DOMAgentImpl::getDocument(Maybe in_depth, Maybe in_pierce, std::unique_ptr* out_root) { std::unique_ptr defaultNode = protocol::DOM::Node::create() .setNodeId(0) .setBackendNodeId(0) @@ -105,7 +103,7 @@ DispatchResponse V8DOMAgentImpl::getDocument(Maybe in_depth, Maybe in } auto resultUtf16Data = resultString.data(); - String16 resultProtocolString = String16((const uint16_t*) resultUtf16Data); + v8_inspector::String16 resultProtocolString = v8_inspector::String16((const uint16_t*) resultUtf16Data); std::vector cbor; v8_crdtp::json::ConvertJSONToCBOR(v8_crdtp::span(resultProtocolString.characters16(), resultProtocolString.length()), &cbor); std::unique_ptr resultJson = protocol::Value::parseBinary(cbor.data(), cbor.size()); @@ -114,7 +112,7 @@ DispatchResponse V8DOMAgentImpl::getDocument(Maybe in_depth, Maybe in std::vector json; v8_crdtp::json::ConvertCBORToJSON(errorSupport.Errors(), &json); - auto errorSupportString = String16(reinterpret_cast(json.data()), json.size()).utf8(); + auto errorSupportString = v8_inspector::String16(reinterpret_cast(json.data()), json.size()).utf8(); if (!errorSupportString.empty()) { auto errorMessage = "Error while parsing debug `DOM Node` object. "; DEBUG_WRITE_FORCE("JS Error: %s, Error support: %s", errorMessage, errorSupportString.c_str()); @@ -134,7 +132,7 @@ DispatchResponse V8DOMAgentImpl::getDocument(Maybe in_depth, Maybe in return DispatchResponse::ServerError("Error getting DOM tree."); } -DispatchResponse V8DOMAgentImpl::removeNode(int in_nodeId) { +DispatchResponse DOMAgentImpl::removeNode(int in_nodeId) { std::string removeNodeFunctionString = "removeNode"; // TODO: Pete: Find a better way to get a hold of the isolate @@ -167,11 +165,11 @@ DispatchResponse V8DOMAgentImpl::removeNode(int in_nodeId) { return DispatchResponse::ServerError("Couldn't remove the selected DOMNode from the visual tree. Global Inspector object not found."); } -DispatchResponse V8DOMAgentImpl::setAttributeValue(int in_nodeId, const String& in_name, const String& in_value) { +DispatchResponse DOMAgentImpl::setAttributeValue(int in_nodeId, const String& in_name, const String& in_value) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::setAttributesAsText(int in_nodeId, const String& in_text, Maybe in_name) { +DispatchResponse DOMAgentImpl::setAttributesAsText(int in_nodeId, const String& in_text, Maybe in_name) { // call modules' View class methods to modify view's attribute // TODO: Pete: Find a better way to get a hold of the isolate std::string setAttributeAsTextFunctionString = "setAttributeAsText"; @@ -209,23 +207,23 @@ DispatchResponse V8DOMAgentImpl::setAttributesAsText(int in_nodeId, const String return DispatchResponse::ServerError("Couldn't change selected DOM node's attribute. Global Inspector object not found."); } -DispatchResponse V8DOMAgentImpl::removeAttribute(int in_nodeId, const String& in_name) { +DispatchResponse DOMAgentImpl::removeAttribute(int in_nodeId, const String& in_name) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::performSearch(const String& in_query, Maybe in_includeUserAgentShadowDOM, String* out_searchId, int* out_resultCount) { +DispatchResponse DOMAgentImpl::performSearch(const String& in_query, Maybe in_includeUserAgentShadowDOM, String* out_searchId, int* out_resultCount) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::getSearchResults(const String& in_searchId, int in_fromIndex, int in_toIndex, std::unique_ptr>* out_nodeIds) { +DispatchResponse DOMAgentImpl::getSearchResults(const String& in_searchId, int in_fromIndex, int in_toIndex, std::unique_ptr>* out_nodeIds) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::discardSearchResults(const String& in_searchId) { +DispatchResponse DOMAgentImpl::discardSearchResults(const String& in_searchId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::resolveNode(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectGroup, Maybe in_executionContextId, std::unique_ptr* out_object) { +DispatchResponse DOMAgentImpl::resolveNode(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectGroup, Maybe in_executionContextId, std::unique_ptr* out_object) { auto resolvedNode = protocol::Runtime::RemoteObject::create() .setType("View") .build(); @@ -235,115 +233,115 @@ DispatchResponse V8DOMAgentImpl::resolveNode(Maybe in_nodeId, Maybe in return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::collectClassNamesFromSubtree(int in_nodeId, std::unique_ptr>* out_classNames) { +DispatchResponse DOMAgentImpl::collectClassNamesFromSubtree(int in_nodeId, std::unique_ptr>* out_classNames) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::copyTo(int in_nodeId, int in_targetNodeId, Maybe in_insertBeforeNodeId, int* out_nodeId) { +DispatchResponse DOMAgentImpl::copyTo(int in_nodeId, int in_targetNodeId, Maybe in_insertBeforeNodeId, int* out_nodeId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::describeNode(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, Maybe in_depth, Maybe in_pierce, std::unique_ptr* out_node) { +DispatchResponse DOMAgentImpl::describeNode(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, Maybe in_depth, Maybe in_pierce, std::unique_ptr* out_node) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::focus(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId) { +DispatchResponse DOMAgentImpl::focus(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::getAttributes(int in_nodeId, std::unique_ptr>* out_attributes) { +DispatchResponse DOMAgentImpl::getAttributes(int in_nodeId, std::unique_ptr>* out_attributes) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::getBoxModel(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, std::unique_ptr* out_model) { +DispatchResponse DOMAgentImpl::getBoxModel(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, std::unique_ptr* out_model) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::getFlattenedDocument(Maybe in_depth, Maybe in_pierce, std::unique_ptr>* out_nodes) { +DispatchResponse DOMAgentImpl::getFlattenedDocument(Maybe in_depth, Maybe in_pierce, std::unique_ptr>* out_nodes) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::getNodeForLocation(int in_x, int in_y, Maybe in_includeUserAgentShadowDOM, int* out_backendNodeId, Maybe* out_nodeId) { +DispatchResponse DOMAgentImpl::getNodeForLocation(int in_x, int in_y, Maybe in_includeUserAgentShadowDOM, int* out_backendNodeId, Maybe* out_nodeId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::getOuterHTML(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, String* out_outerHTML) { +DispatchResponse DOMAgentImpl::getOuterHTML(Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, String* out_outerHTML) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::getRelayoutBoundary(int in_nodeId, int* out_nodeId) { +DispatchResponse DOMAgentImpl::getRelayoutBoundary(int in_nodeId, int* out_nodeId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::markUndoableState() { +DispatchResponse DOMAgentImpl::markUndoableState() { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::moveTo(int in_nodeId, int in_targetNodeId, Maybe in_insertBeforeNodeId, int* out_nodeId) { +DispatchResponse DOMAgentImpl::moveTo(int in_nodeId, int in_targetNodeId, Maybe in_insertBeforeNodeId, int* out_nodeId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::pushNodeByPathToFrontend(const String& in_path, int* out_nodeId) { +DispatchResponse DOMAgentImpl::pushNodeByPathToFrontend(const String& in_path, int* out_nodeId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::pushNodesByBackendIdsToFrontend(std::unique_ptr> in_backendNodeIds, std::unique_ptr>* out_nodeIds) { +DispatchResponse DOMAgentImpl::pushNodesByBackendIdsToFrontend(std::unique_ptr> in_backendNodeIds, std::unique_ptr>* out_nodeIds) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::querySelector(int in_nodeId, const String& in_selector, int* out_nodeId) { +DispatchResponse DOMAgentImpl::querySelector(int in_nodeId, const String& in_selector, int* out_nodeId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::querySelectorAll(int in_nodeId, const String& in_selector, std::unique_ptr>* out_nodeIds) { +DispatchResponse DOMAgentImpl::querySelectorAll(int in_nodeId, const String& in_selector, std::unique_ptr>* out_nodeIds) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::redo() { +DispatchResponse DOMAgentImpl::redo() { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::requestChildNodes(int in_nodeId, Maybe in_depth, Maybe in_pierce) { +DispatchResponse DOMAgentImpl::requestChildNodes(int in_nodeId, Maybe in_depth, Maybe in_pierce) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::requestNode(const String& in_objectId, int* out_nodeId) { +DispatchResponse DOMAgentImpl::requestNode(const String& in_objectId, int* out_nodeId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::setFileInputFiles(std::unique_ptr> in_files, Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId) { +DispatchResponse DOMAgentImpl::setFileInputFiles(std::unique_ptr> in_files, Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::getFileInfo(const String& in_objectId, String* out_path) { +DispatchResponse DOMAgentImpl::getFileInfo(const String& in_objectId, String* out_path) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::setInspectedNode(int in_nodeId) { +DispatchResponse DOMAgentImpl::setInspectedNode(int in_nodeId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::setNodeName(int in_nodeId, const String& in_name, int* out_nodeId) { +DispatchResponse DOMAgentImpl::setNodeName(int in_nodeId, const String& in_name, int* out_nodeId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::setNodeValue(int in_nodeId, const String& in_value) { +DispatchResponse DOMAgentImpl::setNodeValue(int in_nodeId, const String& in_value) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::setOuterHTML(int in_nodeId, const String& in_outerHTML) { +DispatchResponse DOMAgentImpl::setOuterHTML(int in_nodeId, const String& in_outerHTML) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::undo() { +DispatchResponse DOMAgentImpl::undo() { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8DOMAgentImpl::getFrameOwner(const String& in_frameId, int* out_backendNodeId, Maybe* out_nodeId) { +DispatchResponse DOMAgentImpl::getFrameOwner(const String& in_frameId, int* out_backendNodeId, Maybe* out_nodeId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -std::u16string V8DOMAgentImpl::AddBackendNodeIdProperty(v8::Isolate* isolate, v8::Local jsonInput) { +std::u16string DOMAgentImpl::AddBackendNodeIdProperty(v8::Isolate* isolate, v8::Local jsonInput) { auto scriptSource = "(function () {" " function addBackendNodeId(node) {" @@ -384,5 +382,5 @@ std::u16string V8DOMAgentImpl::AddBackendNodeIdProperty(v8::Isolate* isolate, v8 return resultString; } -V8DOMAgentImpl* V8DOMAgentImpl::Instance = 0; -} +DOMAgentImpl* DOMAgentImpl::Instance = 0; +} // namespace tns diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-dom-agent-impl.h b/test-app/runtime/src/main/cpp/DOMAgentImpl.h similarity index 91% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-dom-agent-impl.h rename to test-app/runtime/src/main/cpp/DOMAgentImpl.h index 8d83a3e75..a09b591f0 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-dom-agent-impl.h +++ b/test-app/runtime/src/main/cpp/DOMAgentImpl.h @@ -9,19 +9,23 @@ #include namespace v8_inspector { - class V8InspectorSessionImpl; +} + +namespace tns { using v8_inspector::protocol::Maybe; using String = v8_inspector::String16; using v8_inspector::protocol::DispatchResponse; +using v8_inspector::V8InspectorSessionImpl; +namespace protocol = v8_inspector::protocol; -class V8DOMAgentImpl : public protocol::DOM::Backend { +class DOMAgentImpl : public protocol::DOM::Backend { public: - V8DOMAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, - protocol::DictionaryValue* state); + DOMAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, + protocol::DictionaryValue* state); - ~V8DOMAgentImpl() override; + ~DOMAgentImpl() override; virtual DispatchResponse enable() override; virtual DispatchResponse disable() override; @@ -68,7 +72,7 @@ class V8DOMAgentImpl : public protocol::DOM::Backend { return m_enabled; }; - static V8DOMAgentImpl* Instance; + static DOMAgentImpl* Instance; protocol::DOM::Frontend m_frontend; static std::u16string AddBackendNodeIdProperty(v8::Isolate* isolate, v8::Local jsonInput); @@ -78,8 +82,9 @@ class V8DOMAgentImpl : public protocol::DOM::Backend { bool m_enabled; - DISALLOW_COPY_AND_ASSIGN(V8DOMAgentImpl); + DOMAgentImpl(const DOMAgentImpl&) = delete; + DOMAgentImpl& operator=(const DOMAgentImpl&) = delete; }; -} +} // namespace tns #endif //V8_DOM_AGENT_IMPL_H \ No newline at end of file diff --git a/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp b/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp index f77e86634..77d204dc8 100644 --- a/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp +++ b/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.cpp @@ -5,13 +5,18 @@ #include #include #include + +#include +#include +#include #include + #include "DOMDomainCallbackHandlers.h" using namespace tns; void DOMDomainCallbackHandlers::DocumentUpdatedCallback(const v8::FunctionCallbackInfo& args) { - auto domAgentInstance = V8DOMAgentImpl::Instance; + auto domAgentInstance = DOMAgentImpl::Instance; if (!domAgentInstance) { return; @@ -22,7 +27,7 @@ void DOMDomainCallbackHandlers::DocumentUpdatedCallback(const v8::FunctionCallba void DOMDomainCallbackHandlers::ChildNodeInsertedCallback(const v8::FunctionCallbackInfo& args) { try { - auto domAgentInstance = V8DOMAgentImpl::Instance; + auto domAgentInstance = DOMAgentImpl::Instance; if (!domAgentInstance) { return; @@ -41,14 +46,14 @@ void DOMDomainCallbackHandlers::ChildNodeInsertedCallback(const v8::FunctionCall auto lastId = args[1]->ToNumber(context).ToLocalChecked(); auto node = args[2]->ToString(context).ToLocalChecked(); - auto resultString = V8DOMAgentImpl::AddBackendNodeIdProperty(isolate, node); + auto resultString = DOMAgentImpl::AddBackendNodeIdProperty(isolate, node); auto nodeUtf16Data = resultString.data(); - const String16& nodeString16 = String16((const uint16_t*) nodeUtf16Data); + const v8_inspector::String16& nodeString16 = v8_inspector::String16((const uint16_t*) nodeUtf16Data); std::vector cbor; v8_crdtp::json::ConvertJSONToCBOR(v8_crdtp::span(nodeString16.characters16(), nodeString16.length()), &cbor); std::unique_ptr protocolNodeJson = protocol::Value::parseBinary(cbor.data(), cbor.size()); - protocol::ErrorSupport errorSupport; + v8_crdtp::ErrorSupport errorSupport; auto domNode = protocol::DOM::Node::fromValue(protocolNodeJson.get(), &errorSupport); std::vector json; @@ -76,7 +81,7 @@ void DOMDomainCallbackHandlers::ChildNodeInsertedCallback(const v8::FunctionCall void DOMDomainCallbackHandlers::ChildNodeRemovedCallback(const v8::FunctionCallbackInfo& args) { try { - auto domAgentInstance = V8DOMAgentImpl::Instance; + auto domAgentInstance = DOMAgentImpl::Instance; if (!domAgentInstance) { return; @@ -110,7 +115,7 @@ void DOMDomainCallbackHandlers::ChildNodeRemovedCallback(const v8::FunctionCallb void DOMDomainCallbackHandlers::AttributeModifiedCallback(const v8::FunctionCallbackInfo& args) { try { - auto domAgentInstance = V8DOMAgentImpl::Instance; + auto domAgentInstance = DOMAgentImpl::Instance; if (!domAgentInstance) { return; @@ -147,7 +152,7 @@ void DOMDomainCallbackHandlers::AttributeModifiedCallback(const v8::FunctionCall void DOMDomainCallbackHandlers::AttributeRemovedCallback(const v8::FunctionCallbackInfo& args) { try { - auto domAgentInstance = V8DOMAgentImpl::Instance; + auto domAgentInstance = DOMAgentImpl::Instance; if (!domAgentInstance) { return; diff --git a/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.h b/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.h index b4e2a50cb..bd54aff99 100644 --- a/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.h +++ b/test-app/runtime/src/main/cpp/DOMDomainCallbackHandlers.h @@ -6,7 +6,7 @@ #define DOMDOMAINCALLBACKHANDLERS_H #include -#include +#include "DOMAgentImpl.h" #include "JsV8InspectorClient.h" #include "NativeScriptException.h" diff --git a/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp b/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp index fb11caf80..e702750c0 100644 --- a/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp +++ b/test-app/runtime/src/main/cpp/JsV8InspectorClient.cpp @@ -1,13 +1,18 @@ #include "JsV8InspectorClient.h" #include #include +#include +#include +#include +#include +#include + #include "Runtime.h" #include "NativeScriptException.h" -#include #include "ArgConverter.h" -#include "DOMDomainCallbackHandlers.h" -#include "NetworkDomainCallbackHandlers.h" +// #include "DOMDomainCallbackHandlers.h" +// #include "NetworkDomainCallbackHandlers.h" using namespace std; using namespace tns; @@ -15,33 +20,55 @@ using namespace v8; using namespace v8_inspector; +// Utility functions for converting between inspector StringView and UTF8 string + +static inline v8_inspector::StringView stringToStringView(const std::string &str) { + auto* chars = reinterpret_cast(str.c_str()); + return { chars, str.length() }; +} + +static inline std::string stringViewToString(v8::Isolate* isolate, const v8_inspector::StringView& stringView) { + int length = static_cast(stringView.length()); + if (!length) { + return ""; + } + v8::Local message = ( + stringView.is8Bit() ? + v8::String::NewFromOneByte(isolate, reinterpret_cast(stringView.characters8()), v8::NewStringType::kNormal, length) : + v8::String::NewFromTwoByte(isolate, reinterpret_cast(stringView.characters16()), v8::NewStringType::kNormal, length) + ) .ToLocalChecked(); + v8::String::Utf8Value result(isolate, message); + return *result; +} + JsV8InspectorClient::JsV8InspectorClient(v8::Isolate* isolate) : isolate_(isolate), inspector_(nullptr), session_(nullptr), - connection(nullptr), + connection_(nullptr), context_(), + terminated_(true), running_nested_loop_(false), - isConnected(false) { + isConnected_(false) { JEnv env; - inspectorClass = env.FindClass("com/tns/AndroidJsV8Inspector"); - assert(inspectorClass != nullptr); + inspectorClass_ = env.FindClass("com/tns/AndroidJsV8Inspector"); + assert(inspectorClass_ != nullptr); - sendMethod = env.GetStaticMethodID(inspectorClass, "send", "(Ljava/lang/Object;Ljava/lang/String;)V"); - assert(sendMethod != nullptr); + sendMethod_ = env.GetStaticMethodID(inspectorClass_, "send", "(Ljava/lang/Object;Ljava/lang/String;)V"); + assert(sendMethod_ != nullptr); - sendToDevToolsConsoleMethod = env.GetStaticMethodID(inspectorClass, "sendToDevToolsConsole", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V"); - assert(sendToDevToolsConsoleMethod != nullptr); + sendToDevToolsConsoleMethod_ = env.GetStaticMethodID(inspectorClass_, "sendToDevToolsConsole", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V"); + assert(sendToDevToolsConsoleMethod_ != nullptr); - getInspectorMessageMethod = env.GetStaticMethodID(inspectorClass, "getInspectorMessage", "(Ljava/lang/Object;)Ljava/lang/String;"); - assert(getInspectorMessageMethod != nullptr); + getInspectorMessageMethod_ = env.GetStaticMethodID(inspectorClass_, "getInspectorMessage", "(Ljava/lang/Object;)Ljava/lang/String;"); + assert(getInspectorMessageMethod_ != nullptr); } void JsV8InspectorClient::connect(jobject connection) { JEnv env; - this->connection = env.NewGlobalRef(connection); - this->isConnected = true; + connection_ = env.NewGlobalRef(connection); + isConnected_ = true; } void JsV8InspectorClient::scheduleBreak() { @@ -51,15 +78,15 @@ void JsV8InspectorClient::scheduleBreak() { auto context = Runtime::GetRuntime(isolate_)->GetContext(); Context::Scope context_scope(context); - this->session_->schedulePauseOnNextStatement(v8_inspector::StringView(), v8_inspector::StringView()); + session_->schedulePauseOnNextStatement({}, {}); } -void JsV8InspectorClient::createInspectorSession(v8::Isolate* isolate, const v8::Local& context) { - session_ = inspector_->connect(JsV8InspectorClient::contextGroupId, this, v8_inspector::StringView()); +void JsV8InspectorClient::createInspectorSession() { + session_ = inspector_->connect(JsV8InspectorClient::contextGroupId, this, {}); } void JsV8InspectorClient::disconnect() { - if (this->connection == nullptr) { + if (connection_ == nullptr) { return; } @@ -71,11 +98,11 @@ void JsV8InspectorClient::disconnect() { session_.reset(); JEnv env; - env.DeleteGlobalRef(this->connection); - this->connection = nullptr; - this->isConnected = false; + env.DeleteGlobalRef(connection_); + connection_ = nullptr; + isConnected_ = false; - this->createInspectorSession(isolate_, JsV8InspectorClient::PersistentToLocal(isolate_, context_)); + createInspectorSession(); } @@ -86,7 +113,7 @@ void JsV8InspectorClient::dispatchMessage(const std::string& message) { auto context = Runtime::GetRuntime(isolate_)->GetContext(); Context::Scope context_scope(context); - this->doDispatchMessage(isolate_, message); + doDispatchMessage(message); } void JsV8InspectorClient::runMessageLoopOnPause(int context_group_id) { @@ -99,10 +126,10 @@ void JsV8InspectorClient::runMessageLoopOnPause(int context_group_id) { terminated_ = false; running_nested_loop_ = true; while (!terminated_) { - JniLocalRef msg(env.CallStaticObjectMethod(inspectorClass, getInspectorMessageMethod, this->connection)); + JniLocalRef msg(env.CallStaticObjectMethod(inspectorClass_, getInspectorMessageMethod_, connection_)); if (!msg.IsNull()) { auto inspectorMessage = ArgConverter::jstringToString(msg); - this->doDispatchMessage(this->isolate_, inspectorMessage); + doDispatchMessage(inspectorMessage); } while (v8::platform::PumpMessageLoop(Runtime::platform, isolate_)) { @@ -117,17 +144,15 @@ void JsV8InspectorClient::quitMessageLoopOnPause() { } v8::Local JsV8InspectorClient::ensureDefaultContextInGroup(int contextGroupId) { - v8::Local context = PersistentToLocal(isolate_, context_); - return context; + return context_.Get(isolate_); } -void JsV8InspectorClient::doDispatchMessage(v8::Isolate* isolate, const std::string& message) { +void JsV8InspectorClient::doDispatchMessage(const std::string& message) { if (session_ == nullptr) { return; } - const v8_inspector::String16 msg = v8_inspector::String16::fromUTF8(message.c_str(), message.length()); - v8_inspector::StringView message_view = toStringView(msg); + v8_inspector::StringView message_view = stringToStringView(message); session_->dispatchProtocolMessage(message_view); } @@ -135,49 +160,22 @@ void JsV8InspectorClient::sendResponse(int callId, std::unique_ptr sendNotification(std::move(message)); } -static v8_inspector::String16 ToString16(const v8_inspector::StringView& string) { - if (string.is8Bit()) { - return v8_inspector::String16(reinterpret_cast(string.characters8()), string.length()); - } - - return v8_inspector::String16(reinterpret_cast(string.characters16()), string.length()); -} - void JsV8InspectorClient::sendNotification(std::unique_ptr message) { - if (inspectorClass == nullptr || this->connection == nullptr) { + if (connection_ == nullptr) { return; } - v8_inspector::String16 msg = ToString16(message->string()); + const std::string msg = stringViewToString(isolate_, message->string()); JEnv env; // TODO: Pete: Check if we can use a wide (utf 16) string here - JniLocalRef str(env.NewStringUTF(msg.utf8().c_str())); - env.CallStaticVoidMethod(inspectorClass, sendMethod, this->connection, (jstring) str); + JniLocalRef str(env.NewStringUTF(msg.c_str())); + env.CallStaticVoidMethod(inspectorClass_, sendMethod_, connection_, (jstring) str); } void JsV8InspectorClient::flushProtocolNotifications() { } -template -inline v8::Local StrongPersistentToLocal(const v8::Persistent& persistent) { - return *reinterpret_cast *>(const_cast *>(&persistent)); -} - -template -inline v8::Local WeakPersistentToLocal(v8::Isolate* isolate, const v8::Persistent& persistent) { - return v8::Local::New(isolate, persistent); -} - -template -inline v8::Local JsV8InspectorClient::PersistentToLocal(v8::Isolate* isolate, const v8::Persistent& persistent) { - if (persistent.IsWeak()) { - return WeakPersistentToLocal(isolate, persistent); - } else { - return StrongPersistentToLocal(persistent); - } -} - void JsV8InspectorClient::init() { if (inspector_ != nullptr) { return; @@ -190,12 +188,11 @@ void JsV8InspectorClient::init() { inspector_ = V8Inspector::create(isolate_, this); - inspector_->contextCreated(v8_inspector::V8ContextInfo(context, JsV8InspectorClient::contextGroupId, v8_inspector::StringView())); + inspector_->contextCreated(v8_inspector::V8ContextInfo(context, JsV8InspectorClient::contextGroupId, {})); - v8::Persistent persistentContext(context->GetIsolate(), JsV8InspectorClient::PersistentToLocal(isolate_, context_)); - context_.Reset(isolate_, persistentContext); + context_.Reset(isolate_, context); - this->createInspectorSession(isolate_, context); + createInspectorSession(); } JsV8InspectorClient* JsV8InspectorClient::GetInstance() { @@ -207,7 +204,7 @@ JsV8InspectorClient* JsV8InspectorClient::GetInstance() { } void JsV8InspectorClient::sendToFrontEndCallback(const v8::FunctionCallbackInfo& args) { - if ((instance == nullptr) || (instance->connection == nullptr)) { + if ((instance == nullptr) || (instance->connection_ == nullptr)) { return; } @@ -225,7 +222,7 @@ void JsV8InspectorClient::sendToFrontEndCallback(const v8::FunctionCallbackInfo< JEnv env; JniLocalRef str(env.NewStringUTF(message.c_str())); JniLocalRef lev(env.NewStringUTF(level.c_str())); - env.CallStaticVoidMethod(inspectorClass, sendToDevToolsConsoleMethod, instance->connection, (jstring) str, (jstring)lev); + env.CallStaticVoidMethod(instance->inspectorClass_, instance->sendToDevToolsConsoleMethod_, instance->connection_, (jstring) str, (jstring)lev); } } catch (NativeScriptException& e) { e.ReThrowToV8(); @@ -240,52 +237,26 @@ void JsV8InspectorClient::sendToFrontEndCallback(const v8::FunctionCallbackInfo< } } -void JsV8InspectorClient::consoleLogCallback(Isolate* isolate, const string& message, const string& logLevel) { +void JsV8InspectorClient::consoleLogCallback(Isolate* isolate, ConsoleAPIType method, const std::vector>& args) { if (!inspectorIsConnected()) { return; } - auto stack = v8::StackTrace::CurrentStackTrace(isolate, 1, v8::StackTrace::StackTraceOptions::kDetailed); + // Note, here we access private V8 API + auto* impl = reinterpret_cast(instance->inspector_.get()); + auto* session = reinterpret_cast(instance->session_.get()); - auto frame = stack->GetFrame(isolate, 0); + std::unique_ptr stack = impl->debugger()->captureStackTrace(false); - // will be no-op in non-debuggable builds - v8_inspector::V8LogAgentImpl::EntryAdded(message, logLevel, ArgConverter::ConvertToString(frame->GetScriptNameOrSourceURL()), frame->GetLineNumber()); -} + v8::Local context = instance->context_.Get(instance->isolate_); + const int contextId = V8ContextInfo::executionContextId(context); + + std::unique_ptr msg = + v8_inspector::V8ConsoleMessage::createForConsoleAPI( + context, contextId, contextGroupId, impl, instance->currentTimeMS(), + method, args, String16{}, std::move(stack)); -void MessageHandler(v8::Local message, v8::Local exception) { -// v8::Isolate *isolate = v8::Isolate::GetCurrent(); -// v8::Local context = isolate->GetEnteredContext(); -// if (context.IsEmpty()) return; -// v8_inspector::V8Inspector *inspector = InspectorClientImpl::InspectorFromContext(context); -// -// v8::Local stack = message->GetStackTrace(); -// int script_id = message->GetScriptOrigin().ScriptID()->Value(); -// if (!stack.IsEmpty() && stack->GetFrameCount() > 0) -// { -// int top_script_id = stack->GetFrame(0)->GetScriptId(); -// if (top_script_id == script_id) script_id = 0; -// } -// int line_number = message->GetLineNumber(context).FromMaybe(0); -// int column_number = 0; -// if (message->GetStartColumn(context).IsJust()) -// column_number = message->GetStartColumn(context).FromJust() + 1; -// -// v8_inspector::StringView detailed_message; -// v8_inspector::String16 message_text_string = ToString16(message->Get()); -// v8_inspector::StringView message_text(message_text_string.characters16(), -// message_text_string.length()); -// v8_inspector::String16 url_string; -// if (message->GetScriptOrigin().ResourceName()->IsString()) -// { -// url_string = -// ToString16(message->GetScriptOrigin().ResourceName().As()); -// } -// v8_inspector::StringView url(url_string.characters16(), url_string.length()); -// -// inspector->exceptionThrown(context, message_text, exception, detailed_message, -// url, line_number, column_number, -// inspector->createStackTrace(stack), script_id); + session->runtimeAgent()->messageAdded(msg.get()); } void JsV8InspectorClient::attachInspectorCallbacks(Isolate* isolate, @@ -294,28 +265,23 @@ void JsV8InspectorClient::attachInspectorCallbacks(Isolate* isolate, auto inspectorJSObject = ObjectTemplate::New(isolate); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "responseReceived"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::ResponseReceivedCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "requestWillBeSent"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::RequestWillBeSentCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "dataForRequestId"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::DataForRequestIdCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "loadingFinished"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::LoadingFinishedCallback)); + // inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "responseReceived"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::ResponseReceivedCallback)); + // inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "requestWillBeSent"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::RequestWillBeSentCallback)); + // inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "dataForRequestId"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::DataForRequestIdCallback)); + // inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "loadingFinished"), FunctionTemplate::New(isolate, NetworkDomainCallbackHandlers::LoadingFinishedCallback)); inspectorJSObject->SetAccessor(ArgConverter::ConvertToV8String(isolate, "isConnected"), JsV8InspectorClient::InspectorIsConnectedGetterCallback); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "documentUpdated"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::DocumentUpdatedCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "childNodeInserted"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::ChildNodeInsertedCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "childNodeRemoved"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::ChildNodeRemovedCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "attributeModified"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::AttributeModifiedCallback)); - inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "attributeRemoved"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::AttributeRemovedCallback)); + // inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "documentUpdated"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::DocumentUpdatedCallback)); + // inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "childNodeInserted"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::ChildNodeInsertedCallback)); + // inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "childNodeRemoved"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::ChildNodeRemovedCallback)); + // inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "attributeModified"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::AttributeModifiedCallback)); + // inspectorJSObject->Set(ArgConverter::ConvertToV8String(isolate, "attributeRemoved"), FunctionTemplate::New(isolate, DOMDomainCallbackHandlers::AttributeRemovedCallback)); globalObjectTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__inspector"), inspectorJSObject); } void JsV8InspectorClient::InspectorIsConnectedGetterCallback(v8::Local property, const v8::PropertyCallbackInfo& info) { - info.GetReturnValue().Set(JsV8InspectorClient::GetInstance()->isConnected); + info.GetReturnValue().Set(JsV8InspectorClient::GetInstance()->isConnected_); } JsV8InspectorClient* JsV8InspectorClient::instance = nullptr; -jclass JsV8InspectorClient::inspectorClass = nullptr; -jmethodID JsV8InspectorClient::sendMethod = nullptr; -jmethodID JsV8InspectorClient::sendToDevToolsConsoleMethod = nullptr; -jmethodID JsV8InspectorClient::getInspectorMessageMethod = nullptr; -int JsV8InspectorClient::contextGroupId = 1; diff --git a/test-app/runtime/src/main/cpp/JsV8InspectorClient.h b/test-app/runtime/src/main/cpp/JsV8InspectorClient.h index fd774fbbd..96707f77f 100644 --- a/test-app/runtime/src/main/cpp/JsV8InspectorClient.h +++ b/test-app/runtime/src/main/cpp/JsV8InspectorClient.h @@ -2,13 +2,11 @@ #define JSV8INSPECTORCLIENT_H_ #include +#include +#include #include "v8.h" #include "JEnv.h" -#include "src/inspector/v8-inspector-impl.h" -#include "src/inspector/v8-inspector-session-impl.h" #include "v8-inspector.h" -#include "src/inspector/protocol/Forward.h" -#include "src/inspector/string-16.h" using namespace v8_inspector; @@ -17,53 +15,55 @@ class JsV8InspectorClient : V8InspectorClient, v8_inspector::V8Inspector::Channe public: static JsV8InspectorClient* GetInstance(); - template - static v8::Local PersistentToLocal(v8::Isolate* isolate, const v8::Persistent& persistent); - void init(); void connect(jobject connection); void scheduleBreak(); - void createInspectorSession(v8::Isolate* isolate, const v8::Local& context); void disconnect(); void dispatchMessage(const std::string& message); - void doDispatchMessage(v8::Isolate* isolate, const std::string& message); + // Overrides of V8Inspector::Channel void sendResponse(int callId, std::unique_ptr message) override; void sendNotification(const std::unique_ptr message) override; void flushProtocolNotifications() override; static void sendToFrontEndCallback(const v8::FunctionCallbackInfo& args); - static void consoleLogCallback(v8::Isolate* isolate, const std::string& message, const std::string& logLevel); + static void consoleLogCallback(v8::Isolate* isolate, ConsoleAPIType method, const std::vector>& args); + // Overrides of V8InspectorClient void runMessageLoopOnPause(int context_group_id) override; void quitMessageLoopOnPause() override; - v8::Local ensureDefaultContextInGroup(int contextGroupId) override; static void attachInspectorCallbacks(v8::Isolate* isolate, v8::Local& globalObjectTemplate); - static void InspectorIsConnectedGetterCallback(v8::Local property, const v8::PropertyCallbackInfo& info); static bool inspectorIsConnected() { - return JsV8InspectorClient::GetInstance()->isConnected; + return JsV8InspectorClient::GetInstance()->isConnected_; } - std::unique_ptr inspector_; - v8::Isolate* isolate_; - bool isConnected; - private: JsV8InspectorClient(v8::Isolate* isolate); + // Override of V8InspectorClient + v8::Local ensureDefaultContextInGroup(int contextGroupId) override; + + void createInspectorSession(); + void doDispatchMessage(const std::string& message); + + static void InspectorIsConnectedGetterCallback(v8::Local property, const v8::PropertyCallbackInfo& info); + static JsV8InspectorClient* instance; - static jclass inspectorClass; - static jmethodID sendMethod; - static jmethodID getInspectorMessageMethod; - static jmethodID sendToDevToolsConsoleMethod; - static int contextGroupId; + static constexpr int contextGroupId = 1; + v8::Isolate* isolate_; + std::unique_ptr inspector_; v8::Persistent context_; std::unique_ptr session_; - jobject connection; - bool running_nested_loop_; - bool terminated_; + jclass inspectorClass_; + jmethodID sendMethod_; + jmethodID getInspectorMessageMethod_; + jmethodID sendToDevToolsConsoleMethod_; + jobject connection_; + bool running_nested_loop_ : 1; + bool terminated_ : 1; + bool isConnected_ : 1; }; } diff --git a/test-app/runtime/src/main/cpp/NSV8DebuggerAgentImpl.h b/test-app/runtime/src/main/cpp/NSV8DebuggerAgentImpl.h index c06604200..b879ad374 100644 --- a/test-app/runtime/src/main/cpp/NSV8DebuggerAgentImpl.h +++ b/test-app/runtime/src/main/cpp/NSV8DebuggerAgentImpl.h @@ -20,7 +20,9 @@ namespace v8_inspector { Maybe end, Maybe restrictToFunction, std::unique_ptr> * locations) override; - DISALLOW_COPY_AND_ASSIGN(NSV8DebuggerAgentImpl); + + NSV8DebuggerAgentImpl(const NSV8DebuggerAgentImpl&) = delete; + NSV8DebuggerAgentImpl& operator=(const NSV8DebuggerAgentImpl&) = delete; private: tns::JEnv m_env; bool m_lineBreakpointsEnabled; diff --git a/test-app/runtime/src/main/cpp/NetworkAgentImpl.cpp b/test-app/runtime/src/main/cpp/NetworkAgentImpl.cpp new file mode 100644 index 000000000..bc96e13ac --- /dev/null +++ b/test-app/runtime/src/main/cpp/NetworkAgentImpl.cpp @@ -0,0 +1,119 @@ +// +// Created by pkanev on 2/22/2017. +// + +#include + +#include "utils/InspectorCommon.h" +#include "NetworkAgentImpl.h" + +namespace tns { + +namespace NetworkAgentState { +static const char networkEnabled[] = "networkEnabled"; +} + +NetworkAgentImpl::NetworkAgentImpl(V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, + protocol::DictionaryValue* state) + : m_responses(), + m_session(session), + m_frontend(frontendChannel), + m_state(state), + m_enabled(false) { + Instance = this; +} + +NetworkAgentImpl::~NetworkAgentImpl() {} + +/////// + +DispatchResponse NetworkAgentImpl::enable(Maybe in_maxTotalBufferSize, Maybe in_maxResourceBufferSize, Maybe in_maxPostDataSize) { + if (m_enabled) { + return DispatchResponse::Success(); + } + + m_state->setBoolean(NetworkAgentState::networkEnabled, true); + + m_enabled = true; + + return DispatchResponse::Success(); +} + +DispatchResponse NetworkAgentImpl::disable() { + if (!m_enabled) { + return DispatchResponse::Success(); + } + + m_state->setBoolean(NetworkAgentState::networkEnabled, false); + + m_enabled = false; + + return DispatchResponse::Success(); +} + +DispatchResponse NetworkAgentImpl::setExtraHTTPHeaders(std::unique_ptr in_headers) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +void NetworkAgentImpl::getResponseBody(const String& in_requestId, std::unique_ptr callback) { + auto it = m_responses.find(in_requestId.utf8()); + + if (it == m_responses.end()) { + auto error = "Response not found for requestId = " + in_requestId; + callback->sendFailure(DispatchResponse::ServerError(error.utf8())); + return; + } + + utils::NetworkRequestData* response = it->second; + auto body = v8_inspector::String16((const uint16_t*) response->getData()); + auto base64Encoded = !response->hasTextContent(); + callback->sendSuccess(body, base64Encoded); +} + +DispatchResponse NetworkAgentImpl::setCacheDisabled(bool in_cacheDisabled) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +DispatchResponse NetworkAgentImpl::canClearBrowserCache(bool* out_result) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +DispatchResponse NetworkAgentImpl::canClearBrowserCookies(bool* out_result) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +DispatchResponse NetworkAgentImpl::emulateNetworkConditions(bool in_offline, double in_latency, double in_downloadThroughput, double in_uploadThroughput, Maybe in_connectionType) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +DispatchResponse NetworkAgentImpl::getCertificate(const String& in_origin, std::unique_ptr>* out_tableNames) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +void NetworkAgentImpl::getRequestPostData(const String& in_requestId, std::unique_ptr callback) { +} + +DispatchResponse NetworkAgentImpl::replayXHR(const String& in_requestId) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +DispatchResponse NetworkAgentImpl::searchInResponseBody(const String& in_requestId, const String& in_query, Maybe in_caseSensitive, Maybe in_isRegex, std::unique_ptr>* out_result) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +DispatchResponse NetworkAgentImpl::setBlockedURLs(std::unique_ptr> in_urls) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +DispatchResponse NetworkAgentImpl::setBypassServiceWorker(bool in_bypass) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +DispatchResponse NetworkAgentImpl::setDataSizeLimitsForTest(int in_maxTotalSize, int in_maxResourceSize) { + return utils::Common::protocolCommandNotSupportedDispatchResponse(); +} + +////// + +NetworkAgentImpl* NetworkAgentImpl::Instance = 0; +} // namespace tns diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-network-agent-impl.h b/test-app/runtime/src/main/cpp/NetworkAgentImpl.h similarity index 80% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-network-agent-impl.h rename to test-app/runtime/src/main/cpp/NetworkAgentImpl.h index a7b50d4c0..68bdd5194 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-network-agent-impl.h +++ b/test-app/runtime/src/main/cpp/NetworkAgentImpl.h @@ -6,23 +6,28 @@ #define V8_NETWORK_AGENT_IMPL_H #include -#include #include #include -namespace v8_inspector { +#include "utils/NetworkRequestData.h" +namespace v8_inspector { class V8InspectorSessionImpl; +} + +namespace tns { using v8_inspector::protocol::Maybe; using String = v8_inspector::String16; using v8_inspector::protocol::DispatchResponse; +using v8_inspector::V8InspectorSessionImpl; +namespace protocol = v8_inspector::protocol; -class V8NetworkAgentImpl : public protocol::Network::Backend { +class NetworkAgentImpl : public protocol::Network::Backend { public: - V8NetworkAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, - protocol::DictionaryValue* state); - ~V8NetworkAgentImpl() override; + NetworkAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, + protocol::DictionaryValue* state); + ~NetworkAgentImpl() override; DispatchResponse enable(Maybe in_maxTotalBufferSize, Maybe in_maxResourceBufferSize, Maybe in_maxPostDataSize) override; DispatchResponse disable() override; @@ -53,17 +58,18 @@ class V8NetworkAgentImpl : public protocol::Network::Backend { return m_enabled; }; - static V8NetworkAgentImpl* Instance; + static NetworkAgentImpl* Instance; protocol::Network::Frontend m_frontend; - std::map m_responses; + std::map m_responses; private: V8InspectorSessionImpl* m_session; protocol::DictionaryValue* m_state; bool m_enabled; - DISALLOW_COPY_AND_ASSIGN(V8NetworkAgentImpl); + NetworkAgentImpl(const NetworkAgentImpl&) = delete; + NetworkAgentImpl& operator=(const NetworkAgentImpl&) = delete; }; -} +} // namespace tns #endif //V8_NETWORK_AGENT_IMPL_H diff --git a/test-app/runtime/src/main/cpp/NetworkDomainCallbackHandlers.cpp b/test-app/runtime/src/main/cpp/NetworkDomainCallbackHandlers.cpp index a341f9bc0..a36c17b38 100644 --- a/test-app/runtime/src/main/cpp/NetworkDomainCallbackHandlers.cpp +++ b/test-app/runtime/src/main/cpp/NetworkDomainCallbackHandlers.cpp @@ -3,15 +3,20 @@ // #include + +#include +#include +#include #include #include "NetworkDomainCallbackHandlers.h" #include "NativeScriptAssert.h" +#include "utils/NetworkRequestData.h" using namespace tns; void NetworkDomainCallbackHandlers::ResponseReceivedCallback(const v8::FunctionCallbackInfo& args) { try { - auto networkAgentInstance = V8NetworkAgentImpl::Instance; + auto networkAgentInstance = NetworkAgentImpl::Instance; const std::string wrongParametersError = "Not all parameters are present in the object argument in the call to ResponseReceived! Required params: 'requestId', `timestamp`, `type`, `response`"; if (!networkAgentInstance) { @@ -66,12 +71,12 @@ void NetworkDomainCallbackHandlers::ResponseReceivedCallback(const v8::FunctionC throw NativeScriptException("`response` parameter not in the correct format."); } - const String16 responseJsonString = toProtocolString(isolate, responseJson); + const v8_inspector::String16 responseJsonString = v8_inspector::toProtocolString(isolate, responseJson); std::vector cbor; v8_crdtp::json::ConvertJSONToCBOR(v8_crdtp::span(responseJsonString.characters16(), responseJsonString.length()), &cbor); std::unique_ptr protocolResponseJson = protocol::Value::parseBinary(cbor.data(), cbor.size()); - protocol::ErrorSupport errorSupport; + v8_crdtp::ErrorSupport errorSupport; auto protocolResponseObj = protocol::Network::Response::fromValue(protocolResponseJson.get(), &errorSupport); std::vector json; @@ -86,7 +91,7 @@ void NetworkDomainCallbackHandlers::ResponseReceivedCallback(const v8::FunctionC } auto requestIdString = ArgConverter::ConvertToString(requestId); - auto networkRequestData = new v8_inspector::utils::NetworkRequestData(); + auto networkRequestData = new utils::NetworkRequestData(); networkAgentInstance->m_responses.insert(std::make_pair(requestIdString, networkRequestData)); auto id = ArgConverter::ConvertToV8String(isolate, FrameId); @@ -114,7 +119,7 @@ void NetworkDomainCallbackHandlers::ResponseReceivedCallback(const v8::FunctionC void NetworkDomainCallbackHandlers::RequestWillBeSentCallback(const v8::FunctionCallbackInfo& args) { try { - auto networkAgentInstance = V8NetworkAgentImpl::Instance; + auto networkAgentInstance = NetworkAgentImpl::Instance; const std::string wrongParametersError = "Not all parameters are present in the object argument in the call to RequestWillBeSent! Required params: 'requestId', `url`, `timestamp`, `type`, `request`, `timestamps`"; if (!networkAgentInstance) { @@ -217,7 +222,7 @@ void NetworkDomainCallbackHandlers::RequestWillBeSentCallback(const v8::Function void NetworkDomainCallbackHandlers::DataForRequestIdCallback(const v8::FunctionCallbackInfo& args) { try { - auto networkAgentInstance = V8NetworkAgentImpl::Instance; + auto networkAgentInstance = NetworkAgentImpl::Instance; const std::string wrongParametersError = "Not all parameters are present in the object argument in the call to DataForRequestId! Required params: 'requestId', `data`, `hasTextContent`"; if (!networkAgentInstance) { @@ -256,7 +261,7 @@ void NetworkDomainCallbackHandlers::DataForRequestIdCallback(const v8::FunctionC if (it == responses.end()) { throw NativeScriptException("Response not found for requestId = " + requestIdString); } else { - v8_inspector::utils::NetworkRequestData* response = it->second; + utils::NetworkRequestData* response = it->second; response->setData(dataString); @@ -277,7 +282,7 @@ void NetworkDomainCallbackHandlers::DataForRequestIdCallback(const v8::FunctionC void NetworkDomainCallbackHandlers::LoadingFinishedCallback(const v8::FunctionCallbackInfo& args) { try { - auto networkAgentInstance = V8NetworkAgentImpl::Instance; + auto networkAgentInstance = NetworkAgentImpl::Instance; const std::string wrongParametersError = "Not all parameters are present in the object argument in the call to LoadingFinished! Required params: 'requestId', `timeStamp`"; if (!networkAgentInstance) { diff --git a/test-app/runtime/src/main/cpp/NetworkDomainCallbackHandlers.h b/test-app/runtime/src/main/cpp/NetworkDomainCallbackHandlers.h index 827371257..662b4fdbb 100644 --- a/test-app/runtime/src/main/cpp/NetworkDomainCallbackHandlers.h +++ b/test-app/runtime/src/main/cpp/NetworkDomainCallbackHandlers.h @@ -8,8 +8,8 @@ #include #ifdef APPLICATION_IN_DEBUG -#include #include "JsV8InspectorClient.h" +#include "NetworkAgentImpl.h" #endif #include "ArgConverter.h" #include "NativeScriptException.h" diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-overlay-agent-impl.cpp b/test-app/runtime/src/main/cpp/OverlayAgentImpl.cpp similarity index 53% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-overlay-agent-impl.cpp rename to test-app/runtime/src/main/cpp/OverlayAgentImpl.cpp index 1bcbb6176..a7031104c 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-overlay-agent-impl.cpp +++ b/test-app/runtime/src/main/cpp/OverlayAgentImpl.cpp @@ -3,27 +3,25 @@ // #include -#include -#include "v8-overlay-agent-impl.h" +#include "utils/InspectorCommon.h" +#include "OverlayAgentImpl.h" -namespace v8_inspector { - -using tns::ArgConverter; +namespace tns { namespace OverlayAgentState { static const char overlayEnabled[] = "overlayEnabled"; } -V8OverlayAgentImpl::V8OverlayAgentImpl(V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, - protocol::DictionaryValue* state) +OverlayAgentImpl::OverlayAgentImpl(V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, + protocol::DictionaryValue* state) : m_session(session), m_frontend(frontendChannel), m_state(state), m_enabled(false) {} -V8OverlayAgentImpl::~V8OverlayAgentImpl() { } +OverlayAgentImpl::~OverlayAgentImpl() { } -DispatchResponse V8OverlayAgentImpl::enable() { +DispatchResponse OverlayAgentImpl::enable() { if (m_enabled) { return DispatchResponse::ServerError("Overlay Agent already enabled!"); } @@ -34,7 +32,7 @@ DispatchResponse V8OverlayAgentImpl::enable() { return DispatchResponse::Success(); } -DispatchResponse V8OverlayAgentImpl::disable() { +DispatchResponse OverlayAgentImpl::disable() { if (!m_enabled) { return DispatchResponse::Success(); } @@ -46,19 +44,19 @@ DispatchResponse V8OverlayAgentImpl::disable() { return DispatchResponse::Success(); } -DispatchResponse V8OverlayAgentImpl::setShowFPSCounter(bool in_show) { +DispatchResponse OverlayAgentImpl::setShowFPSCounter(bool in_show) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::setPausedInDebuggerMessage(const Maybe in_message) { +DispatchResponse OverlayAgentImpl::setPausedInDebuggerMessage(const Maybe in_message) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::setShowAdHighlights(bool in_show) { +DispatchResponse OverlayAgentImpl::setShowAdHighlights(bool in_show) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::highlightNode(std::unique_ptr in_highlightConfig, +DispatchResponse OverlayAgentImpl::highlightNode(std::unique_ptr in_highlightConfig, Maybe in_nodeId, Maybe in_backendNodeId, Maybe in_objectId, @@ -66,55 +64,55 @@ DispatchResponse V8OverlayAgentImpl::highlightNode(std::unique_ptr in_contentColor, Maybe in_contentOutlineColor) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::hideHighlight() { +DispatchResponse OverlayAgentImpl::hideHighlight() { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::getHighlightObjectForTest(int in_nodeId, +DispatchResponse OverlayAgentImpl::getHighlightObjectForTest(int in_nodeId, std::unique_ptr* out_highlight) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::highlightQuad(std::unique_ptr> in_quad, Maybe in_color, Maybe in_outlineColor) { +DispatchResponse OverlayAgentImpl::highlightQuad(std::unique_ptr> in_quad, Maybe in_color, Maybe in_outlineColor) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::highlightRect(int in_x, int in_y, int in_width, int in_height, Maybe in_color, Maybe in_outlineColor) { +DispatchResponse OverlayAgentImpl::highlightRect(int in_x, int in_y, int in_width, int in_height, Maybe in_color, Maybe in_outlineColor) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::setInspectMode(const String& in_mode, Maybe in_highlightConfig) { +DispatchResponse OverlayAgentImpl::setInspectMode(const String& in_mode, Maybe in_highlightConfig) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::setShowDebugBorders(bool in_show) { +DispatchResponse OverlayAgentImpl::setShowDebugBorders(bool in_show) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::setShowPaintRects(bool in_result) { +DispatchResponse OverlayAgentImpl::setShowPaintRects(bool in_result) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::setShowScrollBottleneckRects(bool in_show) { +DispatchResponse OverlayAgentImpl::setShowScrollBottleneckRects(bool in_show) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::setShowHitTestBorders(bool in_show) { +DispatchResponse OverlayAgentImpl::setShowHitTestBorders(bool in_show) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::setShowViewportSizeOnResize(bool in_show) { +DispatchResponse OverlayAgentImpl::setShowViewportSizeOnResize(bool in_show) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8OverlayAgentImpl::setSuspended(bool in_suspended) { +DispatchResponse OverlayAgentImpl::setSuspended(bool in_suspended) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -} +} // namespace tns diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-overlay-agent-impl.h b/test-app/runtime/src/main/cpp/OverlayAgentImpl.h similarity index 83% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-overlay-agent-impl.h rename to test-app/runtime/src/main/cpp/OverlayAgentImpl.h index 707acc0b7..da8d0a721 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-overlay-agent-impl.h +++ b/test-app/runtime/src/main/cpp/OverlayAgentImpl.h @@ -6,23 +6,26 @@ #define V8_OVERLAY_AGENT_IMPL_H #include +#include #include namespace v8_inspector { - class V8InspectorSessionImpl; +} +namespace tns { using v8_inspector::protocol::Maybe; using String = v8_inspector::String16; using v8_inspector::protocol::DispatchResponse; + using v8_inspector::V8InspectorSessionImpl; + namespace protocol = v8_inspector::protocol; - - class V8OverlayAgentImpl : public protocol::Overlay::Backend { + class OverlayAgentImpl : public protocol::Overlay::Backend { public: - V8OverlayAgentImpl(V8InspectorSessionImpl *, protocol::FrontendChannel *, - protocol::DictionaryValue *state); + OverlayAgentImpl(V8InspectorSessionImpl *, protocol::FrontendChannel *, + protocol::DictionaryValue *state); - ~V8OverlayAgentImpl() override; + ~OverlayAgentImpl() override; DispatchResponse enable() override; DispatchResponse disable() override; DispatchResponse setShowFPSCounter(bool in_show) override; @@ -68,7 +71,8 @@ namespace v8_inspector { protocol::DictionaryValue *m_state; bool m_enabled; - DISALLOW_COPY_AND_ASSIGN(V8OverlayAgentImpl); + OverlayAgentImpl(const OverlayAgentImpl&) = delete; + OverlayAgentImpl& operator=(const OverlayAgentImpl&) = delete; }; } diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-page-agent-impl.cpp b/test-app/runtime/src/main/cpp/PageAgentImpl.cpp similarity index 59% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-page-agent-impl.cpp rename to test-app/runtime/src/main/cpp/PageAgentImpl.cpp index 1724fbab7..56e27cc41 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-page-agent-impl.cpp +++ b/test-app/runtime/src/main/cpp/PageAgentImpl.cpp @@ -2,18 +2,19 @@ // Created by pkanev on 1/31/2017. // -#include -#include -#include "v8-page-agent-impl.h" -#include "search-util.h" +#include -namespace v8_inspector { +#include "PageAgentImpl.h" +#include "utils/SearchUtilsPublic.h" +#include "utils/InspectorCommon.h" + +namespace tns { namespace PageAgentState { static const char pageEnabled[] = "pageEnabled"; } -V8PageAgentImpl::V8PageAgentImpl( +PageAgentImpl::PageAgentImpl( V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, protocol::DictionaryValue* state) : m_session(session), @@ -23,11 +24,11 @@ V8PageAgentImpl::V8PageAgentImpl( m_frameIdentifier(""), m_frameUrl("file://") {} -V8PageAgentImpl::~V8PageAgentImpl() {} +PageAgentImpl::~PageAgentImpl() {} //////////////// -DispatchResponse V8PageAgentImpl::enable() { +DispatchResponse PageAgentImpl::enable() { if (m_enabled) { return DispatchResponse::Success(); } @@ -39,7 +40,7 @@ DispatchResponse V8PageAgentImpl::enable() { return DispatchResponse::Success(); } -DispatchResponse V8PageAgentImpl::disable() { +DispatchResponse PageAgentImpl::disable() { if (!m_enabled) { return DispatchResponse::Success(); } @@ -51,19 +52,19 @@ DispatchResponse V8PageAgentImpl::disable() { return DispatchResponse::Success(); } -DispatchResponse V8PageAgentImpl::addScriptToEvaluateOnLoad(const String& in_scriptSource, String* out_identifier) { +DispatchResponse PageAgentImpl::addScriptToEvaluateOnLoad(const String& in_scriptSource, String* out_identifier) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::removeScriptToEvaluateOnLoad(const String& in_identifier) { +DispatchResponse PageAgentImpl::removeScriptToEvaluateOnLoad(const String& in_identifier) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::reload(Maybe in_ignoreCache, Maybe in_scriptToEvaluateOnLoad) { +DispatchResponse PageAgentImpl::reload(Maybe in_ignoreCache, Maybe in_scriptToEvaluateOnLoad) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::getResourceTree(std::unique_ptr* out_frameTree) { +DispatchResponse PageAgentImpl::getResourceTree(std::unique_ptr* out_frameTree) { std::unique_ptr frameObject = protocol::Page::Frame::create() .setId(m_frameIdentifier.c_str()) .setLoaderId("NSLoaderIdentifier") @@ -74,7 +75,7 @@ DispatchResponse V8PageAgentImpl::getResourceTree(std::unique_ptr>(); - auto resources = v8_inspector::utils::PageResource::getPageResources(); + auto resources = utils::PageResource::getPageResources(); for (auto const& resource : resources) { auto pageResource = resource.second; @@ -95,7 +96,7 @@ DispatchResponse V8PageAgentImpl::getResourceTree(std::unique_ptr callback) { +void PageAgentImpl::getResourceContent(const String& in_frameId, const String& in_url, std::unique_ptr callback) { if (in_url.utf8().compare(m_frameUrl) == 0) { auto content = ""; auto base64Encoded = false; @@ -104,7 +105,7 @@ void V8PageAgentImpl::getResourceContent(const String& in_frameId, const String& return; } - std::map cachedPageResources = utils::PageResource::s_cachedPageResources; + std::map cachedPageResources = utils::PageResource::s_cachedPageResources; if (utils::PageResource::s_cachedPageResources.size() == 0) { cachedPageResources = utils::PageResource::getPageResources(); } @@ -119,7 +120,7 @@ void V8PageAgentImpl::getResourceContent(const String& in_frameId, const String& auto base64Encoded = !resource.hasTextContent(); - auto errorString = new String16(); + auto errorString = new v8_inspector::String16(); auto content = resource.getContent(errorString); @@ -131,11 +132,11 @@ void V8PageAgentImpl::getResourceContent(const String& in_frameId, const String& callback->sendSuccess(content, base64Encoded); } -void V8PageAgentImpl::searchInResource(const String& in_frameId, const String& in_url, const String& in_query, Maybe in_caseSensitive, Maybe in_isRegex, std::unique_ptr callback) { +void PageAgentImpl::searchInResource(const String& in_frameId, const String& in_url, const String& in_query, Maybe in_caseSensitive, Maybe in_isRegex, std::unique_ptr callback) { bool isRegex = in_isRegex.fromMaybe(false); bool isCaseSensitive = in_caseSensitive.fromMaybe(false); - std::map cachedPageResources = utils::PageResource::s_cachedPageResources; + std::map cachedPageResources = utils::PageResource::s_cachedPageResources; if (utils::PageResource::s_cachedPageResources.size() == 0) { cachedPageResources = utils::PageResource::getPageResources(); } @@ -149,10 +150,10 @@ void V8PageAgentImpl::searchInResource(const String& in_frameId, const String& i } auto resource = it->second; - auto errorString = new String16(); + auto errorString = new v8_inspector::String16(); auto content = resource.getContent(errorString); if (errorString->isEmpty()) { - auto matches = v8_inspector::utils::ResourceContentSearchUtils::searchInTextByLinesImpl(m_session, content, in_query, isCaseSensitive, isRegex); + auto matches = utils::ResourceContentSearchUtils::searchInTextByLinesImpl(m_session, content, in_query, isCaseSensitive, isRegex); for (auto& match : matches) { result->emplace_back(std::move(match)); } @@ -164,7 +165,7 @@ void V8PageAgentImpl::searchInResource(const String& in_frameId, const String& i callback->sendFailure(DispatchResponse::ServerError(errorString->utf8())); } -void V8PageAgentImpl::restore() { +void PageAgentImpl::restore() { if (!m_state->booleanProperty(PageAgentState::pageEnabled, false)) { return; } @@ -172,84 +173,84 @@ void V8PageAgentImpl::restore() { enable(); } -void V8PageAgentImpl::reset() { +void PageAgentImpl::reset() { } -DispatchResponse V8PageAgentImpl::setDocumentContent(const String& in_frameId, const String& in_html) { +DispatchResponse PageAgentImpl::setDocumentContent(const String& in_frameId, const String& in_html) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::addScriptToEvaluateOnNewDocument(const String& in_source, Maybe in_worldName, String* out_identifier) { +DispatchResponse PageAgentImpl::addScriptToEvaluateOnNewDocument(const String& in_source, Maybe in_worldName, String* out_identifier) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::createIsolatedWorld(const String& in_frameId, Maybe in_worldName, Maybe in_grantUniveralAccess, int* out_executionContextId) { +DispatchResponse PageAgentImpl::createIsolatedWorld(const String& in_frameId, Maybe in_worldName, Maybe in_grantUniveralAccess, int* out_executionContextId) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::getFrameTree(std::unique_ptr* out_frameTree) { +DispatchResponse PageAgentImpl::getFrameTree(std::unique_ptr* out_frameTree) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::getLayoutMetrics(std::unique_ptr* out_layoutViewport, std::unique_ptr* out_visualViewport, std::unique_ptr* out_contentSize) { +DispatchResponse PageAgentImpl::getLayoutMetrics(std::unique_ptr* out_layoutViewport, std::unique_ptr* out_visualViewport, std::unique_ptr* out_contentSize) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::removeScriptToEvaluateOnNewDocument(const String& in_identifier) { +DispatchResponse PageAgentImpl::removeScriptToEvaluateOnNewDocument(const String& in_identifier) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::setAdBlockingEnabled(bool in_enabled) { +DispatchResponse PageAgentImpl::setAdBlockingEnabled(bool in_enabled) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::setBypassCSP(bool in_enabled) { +DispatchResponse PageAgentImpl::setBypassCSP(bool in_enabled) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::setFontFamilies(std::unique_ptr in_fontFamilies) { +DispatchResponse PageAgentImpl::setFontFamilies(std::unique_ptr in_fontFamilies) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::setFontSizes(std::unique_ptr in_fontSizes) { +DispatchResponse PageAgentImpl::setFontSizes(std::unique_ptr in_fontSizes) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::setLifecycleEventsEnabled(bool in_enabled) { +DispatchResponse PageAgentImpl::setLifecycleEventsEnabled(bool in_enabled) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::startScreencast(Maybe in_format, Maybe in_quality, Maybe in_maxWidth, Maybe in_maxHeight, Maybe in_everyNthFrame) { +DispatchResponse PageAgentImpl::startScreencast(Maybe in_format, Maybe in_quality, Maybe in_maxWidth, Maybe in_maxHeight, Maybe in_everyNthFrame) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::stopLoading() { +DispatchResponse PageAgentImpl::stopLoading() { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::stopScreencast() { +DispatchResponse PageAgentImpl::stopScreencast() { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::setProduceCompilationCache(bool in_enabled) { +DispatchResponse PageAgentImpl::setProduceCompilationCache(bool in_enabled) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::addCompilationCache(const String& in_url, const protocol::Binary& in_data) { +DispatchResponse PageAgentImpl::addCompilationCache(const String& in_url, const protocol::Binary& in_data) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::clearCompilationCache() { +DispatchResponse PageAgentImpl::clearCompilationCache() { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::generateTestReport(const String& in_message, Maybe in_group) { +DispatchResponse PageAgentImpl::generateTestReport(const String& in_message, Maybe in_group) { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -DispatchResponse V8PageAgentImpl::waitForDebugger() { +DispatchResponse PageAgentImpl::waitForDebugger() { return utils::Common::protocolCommandNotSupportedDispatchResponse(); } -} \ No newline at end of file +} // namespace tns diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-page-agent-impl.h b/test-app/runtime/src/main/cpp/PageAgentImpl.h similarity index 88% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-page-agent-impl.h rename to test-app/runtime/src/main/cpp/PageAgentImpl.h index a16626516..e1d7fdc1c 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/v8-page-agent-impl.h +++ b/test-app/runtime/src/main/cpp/PageAgentImpl.h @@ -12,18 +12,22 @@ #include namespace v8_inspector { - class V8InspectorSessionImpl; +} + +namespace tns { using v8_inspector::protocol::Maybe; using String = v8_inspector::String16; -using protocol::DispatchResponse; +using v8_inspector::protocol::DispatchResponse; +using v8_inspector::V8InspectorSessionImpl; +namespace protocol = v8_inspector::protocol; -class V8PageAgentImpl : public protocol::Page::Backend { +class PageAgentImpl : public protocol::Page::Backend { public: - V8PageAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, - protocol::DictionaryValue* state); - ~V8PageAgentImpl() override; + PageAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*, + protocol::DictionaryValue* state); + ~PageAgentImpl() override; DispatchResponse enable() override; DispatchResponse disable() override; @@ -67,7 +71,8 @@ class V8PageAgentImpl : public protocol::Page::Backend { const std::string m_frameIdentifier; bool m_enabled; - DISALLOW_COPY_AND_ASSIGN(V8PageAgentImpl); + PageAgentImpl(const PageAgentImpl&) = delete; + PageAgentImpl& operator=(const PageAgentImpl&) = delete; }; } diff --git a/test-app/runtime/src/main/cpp/Runtime.cpp b/test-app/runtime/src/main/cpp/Runtime.cpp index 5fd3ee3f3..515f92dd3 100644 --- a/test-app/runtime/src/main/cpp/Runtime.cpp +++ b/test-app/runtime/src/main/cpp/Runtime.cpp @@ -33,9 +33,8 @@ #include "File.h" #ifdef APPLICATION_IN_DEBUG -#include "NetworkDomainCallbackHandlers.h" +// #include "NetworkDomainCallbackHandlers.h" #include "JsV8InspectorClient.h" -#include "v8_inspector/src/inspector/v8-inspector-platform.h" #endif using namespace v8; @@ -467,18 +466,7 @@ void Runtime::ClearStartupData(JNIEnv* env, jobject obj) { } static void InitializeV8() { - Runtime::platform = -#ifdef APPLICATION_IN_DEBUG - // The default V8 platform isn't Chrome DevTools compatible. The frontend uses the - // Runtime.evaluate protocol command with timeout flag for every execution in the console. - // The default platform doesn't implement executing delayed javascript code from a background - // thread. To avoid implementing a full blown scheduler, we use the default platform with a - // timeout=0 flag. - V8InspectorPlatform::CreateDefaultPlatform(); -#else - v8::platform::NewDefaultPlatform().release(); -#endif - + Runtime::platform = v8::platform::NewDefaultPlatform().release(); V8::InitializePlatform(Runtime::platform); V8::Initialize(); } diff --git a/test-app/runtime/src/main/cpp/console/Console.cpp b/test-app/runtime/src/main/cpp/console/Console.cpp index d79c57913..1e1f6f373 100644 --- a/test-app/runtime/src/main/cpp/console/Console.cpp +++ b/test-app/runtime/src/main/cpp/console/Console.cpp @@ -9,8 +9,12 @@ #include #include #include +#include +#include #include #include + +#include "ArgConverter.h" #include "Console.h" namespace tns { @@ -66,10 +70,27 @@ void Console::sendToADBLogcat(const std::string& message, android_LogPriority lo } } -void Console::sendToDevToolsFrontEnd(v8::Isolate* isolate, const std::string& message, const std::string& logLevel) { - if (m_callback != nullptr) { - m_callback(isolate, message, logLevel); +void Console::sendToDevToolsFrontEnd(v8::Isolate* isolate, ConsoleAPIType method, const v8::FunctionCallbackInfo& args) { + if (!m_callback) { + return; } + + std::vector> arg_vector; + unsigned nargs = args.Length(); + arg_vector.reserve(nargs); + for (unsigned ix = 0; ix < nargs; ix++) + arg_vector.push_back(args[ix]); + + m_callback(isolate, method, arg_vector); +} + +void Console::sendToDevToolsFrontEnd(v8::Isolate* isolate, ConsoleAPIType method, const std::string& message) { + if (!m_callback) { + return; + } + + std::vector> args{ArgConverter::ConvertToV8String(isolate, message)}; + m_callback(isolate, method, args); } std::string transformJSObject(v8::Isolate* isolate, v8::Local object) { @@ -170,7 +191,7 @@ void Console::assertCallback(const v8::FunctionCallbackInfo& info) { std::string log = assertionError.str(); sendToADBLogcat(log, ANDROID_LOG_ERROR); - sendToDevToolsFrontEnd(isolate, log, "error"); + sendToDevToolsFrontEnd(isolate, ConsoleAPIType::kAssert, info); } } catch (NativeScriptException& e) { e.ReThrowToV8(); @@ -191,7 +212,7 @@ void Console::errorCallback(const v8::FunctionCallbackInfo & info) { log += buildLogString(info); sendToADBLogcat(log, ANDROID_LOG_ERROR); - sendToDevToolsFrontEnd(info.GetIsolate(), log, "error"); + sendToDevToolsFrontEnd(info.GetIsolate(), ConsoleAPIType::kError, info); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { @@ -211,7 +232,7 @@ void Console::infoCallback(const v8::FunctionCallbackInfo& info) { log += buildLogString(info); sendToADBLogcat(log, ANDROID_LOG_INFO); - sendToDevToolsFrontEnd(info.GetIsolate(), log, "info"); + sendToDevToolsFrontEnd(info.GetIsolate(), ConsoleAPIType::kInfo, info); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { @@ -231,7 +252,7 @@ void Console::logCallback(const v8::FunctionCallbackInfo& info) { log += buildLogString(info); sendToADBLogcat(log, ANDROID_LOG_INFO); - sendToDevToolsFrontEnd(info.GetIsolate(), log, "info"); + sendToDevToolsFrontEnd(info.GetIsolate(), ConsoleAPIType::kLog, info); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { @@ -251,7 +272,7 @@ void Console::warnCallback(const v8::FunctionCallbackInfo& info) { log += buildLogString(info); sendToADBLogcat(log, ANDROID_LOG_WARN); - sendToDevToolsFrontEnd(info.GetIsolate(), log, "warning"); + sendToDevToolsFrontEnd(info.GetIsolate(), ConsoleAPIType::kWarning, info); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { @@ -325,7 +346,7 @@ void Console::dirCallback(const v8::FunctionCallbackInfo& info) { std::string log = ss.str(); sendToADBLogcat(log, ANDROID_LOG_INFO); - sendToDevToolsFrontEnd(isolate, log, "info"); + sendToDevToolsFrontEnd(isolate, ConsoleAPIType::kDir, info); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { @@ -406,7 +427,7 @@ void Console::traceCallback(const v8::FunctionCallbackInfo& info) { std::string log = ss.str(); __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, log.c_str()); - sendToDevToolsFrontEnd(isolate, log, "error"); + sendToDevToolsFrontEnd(isolate, ConsoleAPIType::kTrace, info); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { @@ -480,7 +501,7 @@ void Console::timeEndCallback(const v8::FunctionCallbackInfo& info) { std::string warning = std::string("No such label '" + label + "' for console.timeEnd()"); __android_log_write(ANDROID_LOG_WARN, LOG_TAG, warning.c_str()); - sendToDevToolsFrontEnd(isolate, warning, "warning"); + sendToDevToolsFrontEnd(isolate, ConsoleAPIType::kWarning, warning); return; } @@ -499,7 +520,7 @@ void Console::timeEndCallback(const v8::FunctionCallbackInfo& info) { std::string log = ss.str(); __android_log_write(ANDROID_LOG_INFO, LOG_TAG, log.c_str()); - sendToDevToolsFrontEnd(isolate, log, "info"); + sendToDevToolsFrontEnd(isolate, ConsoleAPIType::kTimeEnd, log); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { diff --git a/test-app/runtime/src/main/cpp/console/Console.h b/test-app/runtime/src/main/cpp/console/Console.h index 81aa28c08..174fa0892 100644 --- a/test-app/runtime/src/main/cpp/console/Console.h +++ b/test-app/runtime/src/main/cpp/console/Console.h @@ -7,12 +7,15 @@ #include #include +#include #include #include +#include + namespace tns { -typedef void (*ConsoleCallback)(v8::Isolate* isolate, const std::string& message, const std::string& logLevel); +typedef void (*ConsoleCallback)(v8::Isolate* isolate, v8_inspector::ConsoleAPIType method, const std::vector>& args); class Console { public: @@ -31,6 +34,8 @@ class Console { static void onDisposeIsolate(v8::Isolate* isolate); private: + using ConsoleAPIType = v8_inspector::ConsoleAPIType; + static int m_maxLogcatObjectSize; static ConsoleCallback m_callback; static const char* LOG_TAG; @@ -54,7 +59,8 @@ class Console { } static void sendToADBLogcat(const std::string& log, android_LogPriority logPriority); - static void sendToDevToolsFrontEnd(v8::Isolate* isolate, const std::string& message, const std::string& logLevel); + static void sendToDevToolsFrontEnd(v8::Isolate* isolate, ConsoleAPIType method, const v8::FunctionCallbackInfo& args); + static void sendToDevToolsFrontEnd(v8::Isolate* isolate, ConsoleAPIType method, const std::string& args); }; } diff --git a/test-app/runtime/src/main/cpp/include/inspector/Debugger.h b/test-app/runtime/src/main/cpp/include/inspector/Debugger.h new file mode 100644 index 000000000..d984c6a4a --- /dev/null +++ b/test-app/runtime/src/main/cpp/include/inspector/Debugger.h @@ -0,0 +1,59 @@ +// This file is generated by Exported_h.template. + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_inspector_protocol_Debugger_api_h +#define v8_inspector_protocol_Debugger_api_h + +#include "v8-inspector.h" + +namespace v8_inspector { +namespace protocol { + +#ifndef v8_inspector_protocol_exported_api_h +#define v8_inspector_protocol_exported_api_h +class V8_EXPORT Exported { +public: + virtual void AppendSerialized(std::vector* out) const = 0; + + virtual ~Exported() { } +}; +#endif // !defined(v8_inspector_protocol_exported_api_h) + +namespace Debugger { +namespace API { + +// ------------- Enums. + +namespace Paused { +namespace ReasonEnum { +V8_EXPORT extern const char* Ambiguous; +V8_EXPORT extern const char* Assert; +V8_EXPORT extern const char* CSPViolation; +V8_EXPORT extern const char* DebugCommand; +V8_EXPORT extern const char* DOM; +V8_EXPORT extern const char* EventListener; +V8_EXPORT extern const char* Exception; +V8_EXPORT extern const char* Instrumentation; +V8_EXPORT extern const char* OOM; +V8_EXPORT extern const char* Other; +V8_EXPORT extern const char* PromiseRejection; +V8_EXPORT extern const char* XHR; +} // ReasonEnum +} // Paused + +// ------------- Types. + +class V8_EXPORT SearchMatch : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +} // namespace API +} // namespace Debugger +} // namespace v8_inspector +} // namespace protocol + +#endif // !defined(v8_inspector_protocol_Debugger_api_h) diff --git a/test-app/runtime/src/main/cpp/include/inspector/Runtime.h b/test-app/runtime/src/main/cpp/include/inspector/Runtime.h new file mode 100644 index 000000000..f9d515ba7 --- /dev/null +++ b/test-app/runtime/src/main/cpp/include/inspector/Runtime.h @@ -0,0 +1,52 @@ +// This file is generated by Exported_h.template. + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_inspector_protocol_Runtime_api_h +#define v8_inspector_protocol_Runtime_api_h + +#include "v8-inspector.h" + +namespace v8_inspector { +namespace protocol { + +#ifndef v8_inspector_protocol_exported_api_h +#define v8_inspector_protocol_exported_api_h +class V8_EXPORT Exported { +public: + virtual void AppendSerialized(std::vector* out) const = 0; + + virtual ~Exported() { } +}; +#endif // !defined(v8_inspector_protocol_exported_api_h) + +namespace Runtime { +namespace API { + +// ------------- Enums. + +// ------------- Types. + +class V8_EXPORT RemoteObject : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +class V8_EXPORT StackTrace : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +class V8_EXPORT StackTraceId : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +} // namespace API +} // namespace Runtime +} // namespace v8_inspector +} // namespace protocol + +#endif // !defined(v8_inspector_protocol_Runtime_api_h) diff --git a/test-app/runtime/src/main/cpp/include/inspector/Schema.h b/test-app/runtime/src/main/cpp/include/inspector/Schema.h new file mode 100644 index 000000000..03a76fa9c --- /dev/null +++ b/test-app/runtime/src/main/cpp/include/inspector/Schema.h @@ -0,0 +1,42 @@ +// This file is generated by Exported_h.template. + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_inspector_protocol_Schema_api_h +#define v8_inspector_protocol_Schema_api_h + +#include "v8-inspector.h" + +namespace v8_inspector { +namespace protocol { + +#ifndef v8_inspector_protocol_exported_api_h +#define v8_inspector_protocol_exported_api_h +class V8_EXPORT Exported { +public: + virtual void AppendSerialized(std::vector* out) const = 0; + + virtual ~Exported() { } +}; +#endif // !defined(v8_inspector_protocol_exported_api_h) + +namespace Schema { +namespace API { + +// ------------- Enums. + +// ------------- Types. + +class V8_EXPORT Domain : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +} // namespace API +} // namespace Schema +} // namespace v8_inspector +} // namespace protocol + +#endif // !defined(v8_inspector_protocol_Schema_api_h) diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-inspector-common.cpp b/test-app/runtime/src/main/cpp/utils/InspectorCommon.cpp similarity index 93% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-inspector-common.cpp rename to test-app/runtime/src/main/cpp/utils/InspectorCommon.cpp index 9e2ea8a3b..40b46727f 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-inspector-common.cpp +++ b/test-app/runtime/src/main/cpp/utils/InspectorCommon.cpp @@ -2,15 +2,13 @@ // Created by pkanev on 6/5/2017. // -#include +#include "utils/InspectorCommon.h" #include #include #include #include -using tns::ArgConverter; - -namespace v8_inspector { +namespace tns { namespace utils { v8::Local Common::getGlobalInspectorObject(v8::Isolate* isolate) { auto context = isolate->GetCurrentContext(); diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-inspector-common.h b/test-app/runtime/src/main/cpp/utils/InspectorCommon.h similarity index 96% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-inspector-common.h rename to test-app/runtime/src/main/cpp/utils/InspectorCommon.h index 3fb672a2e..a7d78299a 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-inspector-common.h +++ b/test-app/runtime/src/main/cpp/utils/InspectorCommon.h @@ -9,7 +9,9 @@ #include #include -namespace v8_inspector { +namespace protocol = v8_inspector::protocol; + +namespace tns { namespace utils { class Common { public: diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-network-request-data.cpp b/test-app/runtime/src/main/cpp/utils/NetworkRequestData.cpp similarity index 81% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-network-request-data.cpp rename to test-app/runtime/src/main/cpp/utils/NetworkRequestData.cpp index 611391182..d13ab5d86 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-network-request-data.cpp +++ b/test-app/runtime/src/main/cpp/utils/NetworkRequestData.cpp @@ -2,9 +2,9 @@ // Created by pkanev on 3/10/2017. // -#include "v8-network-request-data.h" +#include "NetworkRequestData.h" -namespace v8_inspector { +namespace tns { namespace utils { NetworkRequestData::NetworkRequestData() : m_data(), @@ -13,4 +13,4 @@ NetworkRequestData::NetworkRequestData(std::u16string data, bool hasTextContent) : m_data(data), m_hasTextContent(hasTextContent) { } } -} \ No newline at end of file +} // namespace tns diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-network-request-data.h b/test-app/runtime/src/main/cpp/utils/NetworkRequestData.h similarity index 95% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-network-request-data.h rename to test-app/runtime/src/main/cpp/utils/NetworkRequestData.h index 684863580..70d45766a 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-network-request-data.h +++ b/test-app/runtime/src/main/cpp/utils/NetworkRequestData.h @@ -5,9 +5,11 @@ #ifndef V8_NETWORK_REQUEST_DATA_H #define V8_NETWORK_REQUEST_DATA_H +#include + #include -namespace v8_inspector { +namespace tns { namespace utils { class NetworkRequestData { diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-page-resources.cpp b/test-app/runtime/src/main/cpp/utils/PageResources.cpp similarity index 90% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-page-resources.cpp rename to test-app/runtime/src/main/cpp/utils/PageResources.cpp index 76d12766f..165a9dc1f 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-page-resources.cpp +++ b/test-app/runtime/src/main/cpp/utils/PageResources.cpp @@ -11,11 +11,11 @@ #include #include #include "base64.h" -#include "v8_inspector/src/inspector/utils/v8-page-resources.h" +#include "PageResources.h" #include "JEnv.h" #include "ArgConverter.h" -namespace v8_inspector { +namespace tns { namespace utils { PageResource::PageResource(std::string filePath, std::string mimeType) : m_filePath(filePath), @@ -25,8 +25,8 @@ PageResource::PageResource(std::string filePath, std::string mimeType) m_type = PageResource::resourceTypeByMimeType(m_mimeType); } -std::map PageResource::getPageResources() { - auto result = std::map(); +std::map PageResource::getPageResources() { + auto result = std::map(); tns::JEnv env; jclass inspectorClass = env.FindClass("com/tns/AndroidJsV8Inspector"); assert(inspectorClass != nullptr); @@ -62,7 +62,7 @@ std::map PageResource::getPageRe return result; } -String16 PageResource::getContent(protocol::String* errorString) { +v8_inspector::String16 PageResource::getContent(protocol::String* errorString) { if (m_content.empty()) { auto filePath = m_filePath; auto shouldEncode = !hasTextContent(); @@ -93,7 +93,7 @@ String16 PageResource::getContent(protocol::String* errorString) { free(buff); } - return String16((const uint16_t*) m_content.data()); + return v8_inspector::String16((const uint16_t*) m_content.data()); } const char* PageResource::resourceTypeByMimeType(std::string mimeType) { @@ -124,6 +124,6 @@ std::map PageResource::s_mimeTypeMap = { { "application/binary", v8_inspector::protocol::Network::ResourceTypeEnum::Other } }; -std::map PageResource::s_cachedPageResources; +std::map PageResource::s_cachedPageResources; } -} \ No newline at end of file +} // namespace tns diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-page-resources.h b/test-app/runtime/src/main/cpp/utils/PageResources.h similarity index 80% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-page-resources.h rename to test-app/runtime/src/main/cpp/utils/PageResources.h index c9e1ff244..8cb2cc7f6 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-page-resources.h +++ b/test-app/runtime/src/main/cpp/utils/PageResources.h @@ -6,11 +6,17 @@ #define V8_PAGE_RESOURCES_H #include +#include + +#include #include +#include -namespace v8_inspector { +namespace tns { namespace utils { +namespace protocol = v8_inspector::protocol; + class PageResource { public: PageResource(std::string filePath, std::string mimeType); @@ -33,14 +39,14 @@ class PageResource { * Get string representation of the resource (file) contents * String is base64-encoded if the resource's MIME type isn't a Document | Stylesheet | Script */ - String16 getContent(protocol::String*); + v8_inspector::String16 getContent(protocol::String*); /* * Gets all file paths available in the application's files/app directory * Java returns an array of pairs containing the file url and its MIME type */ - static std::map getPageResources(); - static std::map s_cachedPageResources; + static std::map getPageResources(); + static std::map s_cachedPageResources; private: std::string m_filePath; diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-search-utils-public.h b/test-app/runtime/src/main/cpp/utils/SearchUtilsPublic.h similarity index 87% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-search-utils-public.h rename to test-app/runtime/src/main/cpp/utils/SearchUtilsPublic.h index 21557b4ef..aa19c51d3 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/v8-search-utils-public.h +++ b/test-app/runtime/src/main/cpp/utils/SearchUtilsPublic.h @@ -5,21 +5,26 @@ #ifndef V8_SEARCH_UTILS_PUBLIC_H #define V8_SEARCH_UTILS_PUBLIC_H -#include +#include #include #include #include -#include "v8-page-resources.h" -namespace v8_inspector { +#include "PageResources.h" + +namespace tns { namespace utils { namespace ResourceContentSearchUtils { + +using v8_inspector::String16; +using v8_inspector::V8Regex; + // Implementation taken from v8_inspector/src/inspector/search-util String16 createSearchRegexSource(const String16& text) { - String16Builder result; + v8_inspector::String16Builder result; for (size_t i = 0; i < text.length(); i++) { - UChar c = text[i]; + v8_inspector::UChar c = text[i]; if (c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '+' || c == '-' || c == '*' || c == '.' || c == ',' || c == '?' || c == '\\' || c == '^' || c == '$' || c == '|') { @@ -80,7 +85,7 @@ const V8Regex& regex, const String16& text) { } // Implementation taken from v8_inspector/src/inspector/search-util -std::unique_ptr createSearchRegex(V8InspectorImpl* inspector, +std::unique_ptr createSearchRegex(v8_inspector::V8InspectorImpl* inspector, const String16& query, bool caseSensitive, bool isRegex) { String16 regexSource = isRegex ? query : createSearchRegexSource(query); @@ -99,11 +104,11 @@ std::unique_ptr buildObjectForSearchMatch( // Implementation taken from v8_inspector/src/inspector/search-util std::vector> - searchInTextByLinesImpl(V8InspectorSession* session, const String16& text, + searchInTextByLinesImpl(v8_inspector::V8InspectorSession* session, const String16& text, const String16& query, const bool caseSensitive, const bool isRegex) { std::unique_ptr regex = createSearchRegex( - static_cast(session)->inspector(), query, + static_cast(session)->inspector(), query, caseSensitive, isRegex); std::vector> matches = scriptRegexpMatchesByLines(*regex.get(), text); @@ -116,6 +121,6 @@ const bool isRegex) { } } } -} +} // namespace tns #endif //V8_SEARCH_UTILS_PUBLIC_H diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/base64.cpp b/test-app/runtime/src/main/cpp/utils/base64.cpp similarity index 100% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/base64.cpp rename to test-app/runtime/src/main/cpp/utils/base64.cpp diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/base64.h b/test-app/runtime/src/main/cpp/utils/base64.h similarity index 100% rename from test-app/runtime/src/main/cpp/v8_inspector/src/inspector/utils/base64.h rename to test-app/runtime/src/main/cpp/utils/base64.h diff --git a/test-app/runtime/src/main/cpp/v8_inspector/base/trace_event/common/trace_event_common.h b/test-app/runtime/src/main/cpp/v8_inspector/base/trace_event/common/trace_event_common.h deleted file mode 100644 index a7bffbdbe..000000000 --- a/test-app/runtime/src/main/cpp/v8_inspector/base/trace_event/common/trace_event_common.h +++ /dev/null @@ -1,1131 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TRACE_EVENT_COMMON_TRACE_EVENT_COMMON_H_ -#define BASE_TRACE_EVENT_COMMON_TRACE_EVENT_COMMON_H_ - -// This header file defines the set of trace_event macros without specifying -// how the events actually get collected and stored. If you need to expose trace -// events to some other universe, you can copy-and-paste this file as well as -// trace_event.h, modifying the macros contained there as necessary for the -// target platform. The end result is that multiple libraries can funnel events -// through to a shared trace event collector. - -// IMPORTANT: To avoid conflicts, if you need to modify this file for a library, -// land your change in base/ first, and then copy-and-paste it. - -// Trace events are for tracking application performance and resource usage. -// Macros are provided to track: -// Begin and end of function calls -// Counters -// -// Events are issued against categories. Whereas LOG's -// categories are statically defined, TRACE categories are created -// implicitly with a string. For example: -// TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent", -// TRACE_EVENT_SCOPE_THREAD) -// -// It is often the case that one trace may belong in multiple categories at the -// same time. The first argument to the trace can be a comma-separated list of -// categories, forming a category group, like: -// -// TRACE_EVENT_INSTANT0("input,views", "OnMouseOver", TRACE_EVENT_SCOPE_THREAD) -// -// We can enable/disable tracing of OnMouseOver by enabling/disabling either -// category. -// -// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope: -// TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly") -// doSomethingCostly() -// TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly") -// Note: our tools can't always determine the correct BEGIN/END pairs unless -// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you -// need them to be in separate scopes. -// -// A common use case is to trace entire function scopes. This -// issues a trace BEGIN and END automatically: -// void doSomethingCostly() { -// TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly"); -// ... -// } -// -// Additional parameters can be associated with an event: -// void doSomethingCostly2(int howMuch) { -// TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly", -// "howMuch", howMuch); -// ... -// } -// -// The trace system will automatically add to this information the -// current process id, thread id, and a timestamp in microseconds. -// -// To trace an asynchronous procedure such as an IPC send/receive, use -// NESTABLE_ASYNC_BEGIN and NESTABLE_ASYNC_END: -// [single threaded sender code] -// static int send_count = 0; -// ++send_count; -// TRACE_EVENT_NESTABLE_ASYNC_BEGIN0( -// "ipc", "message", TRACE_ID_LOCAL(send_count)); -// Send(new MyMessage(send_count)); -// [receive code] -// void OnMyMessage(send_count) { -// TRACE_NESTABLE_EVENT_ASYNC_END0( -// "ipc", "message", TRACE_ID_LOCAL(send_count)); -// } -// The third parameter is a unique ID to match NESTABLE_ASYNC_BEGIN/ASYNC_END -// pairs. NESTABLE_ASYNC_BEGIN and ASYNC_END can occur on any thread of any -// traced process. // Pointers can be used for the ID parameter, and they will -// be annotated internally so that the same pointer on two different processes -// will not match. For example: -// class MyTracedClass { -// public: -// MyTracedClass() { -// TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("category", "MyTracedClass", this); -// } -// ~MyTracedClass() { -// TRACE_EVENT_NESTABLE_ASYNC_END0("category", "MyTracedClass", this); -// } -// } -// -// Trace event also supports counters, which is a way to track a quantity -// as it varies over time. Counters are created with the following macro: -// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue); -// -// Counters are process-specific. The macro itself can be issued from any -// thread, however. -// -// Sometimes, you want to track two counters at once. You can do this with two -// counter macros: -// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]); -// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]); -// Or you can do it with a combined macro: -// TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter", -// "bytesPinned", g_myCounterValue[0], -// "bytesAllocated", g_myCounterValue[1]); -// This indicates to the tracing UI that these counters should be displayed -// in a single graph, as a summed area chart. -// -// Since counters are in a global namespace, you may want to disambiguate with a -// unique ID, by using the TRACE_COUNTER_ID* variations. -// -// By default, trace collection is compiled in, but turned off at runtime. -// Collecting trace data is the responsibility of the embedding -// application. In Chrome's case, navigating to about:tracing will turn on -// tracing and display data collected across all active processes. -// -// -// Memory scoping note: -// Tracing copies the pointers, not the string content, of the strings passed -// in for category_group, name, and arg_names. Thus, the following code will -// cause problems: -// char* str = strdup("importantName"); -// TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD! -// free(str); // Trace system now has dangling pointer -// -// To avoid this issue with the |name| and |arg_name| parameters, use the -// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead. -// Notes: The category must always be in a long-lived char* (i.e. static const). -// The |arg_values|, when used, are always deep copied with the _COPY -// macros. -// -// When are string argument values copied: -// const char* arg_values are only referenced by default: -// TRACE_EVENT1("category", "name", -// "arg1", "literal string is only referenced"); -// Use TRACE_STR_COPY to force copying of a const char*: -// TRACE_EVENT1("category", "name", -// "arg1", TRACE_STR_COPY("string will be copied")); -// std::string arg_values are always copied: -// TRACE_EVENT1("category", "name", -// "arg1", std::string("string will be copied")); -// -// -// Convertable notes: -// Converting a large data type to a string can be costly. To help with this, -// the trace framework provides an interface ConvertableToTraceFormat. If you -// inherit from it and implement the AppendAsTraceFormat method the trace -// framework will call back to your object to convert a trace output time. This -// means, if the category for the event is disabled, the conversion will not -// happen. -// -// class MyData : public base::trace_event::ConvertableToTraceFormat { -// public: -// MyData() {} -// void AppendAsTraceFormat(std::string* out) const override { -// out->append("{\"foo\":1}"); -// } -// private: -// ~MyData() override {} -// DISALLOW_COPY_AND_ASSIGN(MyData); -// }; -// -// TRACE_EVENT1("foo", "bar", "data", -// std::unique_ptr(new MyData())); -// -// The trace framework will take ownership if the passed pointer and it will -// be free'd when the trace buffer is flushed. -// -// Note, we only do the conversion when the buffer is flushed, so the provided -// data object should not be modified after it's passed to the trace framework. -// -// -// Thread Safety: -// A thread safe singleton and mutex are used for thread safety. Category -// enabled flags are used to limit the performance impact when the system -// is not enabled. -// -// TRACE_EVENT macros first cache a pointer to a category. The categories are -// statically allocated and safe at all times, even after exit. Fetching a -// category is protected by the TraceLog::lock_. Multiple threads initializing -// the static variable is safe, as they will be serialized by the lock and -// multiple calls will return the same pointer to the category. -// -// Then the category_group_enabled flag is checked. This is a unsigned char, and -// not intended to be multithread safe. It optimizes access to AddTraceEvent -// which is threadsafe internally via TraceLog::lock_. The enabled flag may -// cause some threads to incorrectly call or skip calling AddTraceEvent near -// the time of the system being enabled or disabled. This is acceptable as -// we tolerate some data loss while the system is being enabled/disabled and -// because AddTraceEvent is threadsafe internally and checks the enabled state -// again under lock. -// -// Without the use of these static category pointers and enabled flags all -// trace points would carry a significant performance cost of acquiring a lock -// and resolving the category. - -// Check that nobody includes this file directly. Clients are supposed to -// include the surrounding "trace_event.h" of their project instead. -#if defined(TRACE_EVENT0) -#error "Another copy of this file has already been included." -#endif - -// This will mark the trace event as disabled by default. The user will need -// to explicitly enable the event. -#define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name - -// Records a pair of begin and end events called "name" for the current -// scope, with 0, 1 or 2 associated arguments. If the category is not -// enabled, then this does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_EVENT0(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name) -#define TRACE_EVENT_WITH_FLOW0(category_group, name, bind_id, flow_flags) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \ - flow_flags) -#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val) -#define TRACE_EVENT_WITH_FLOW1(category_group, name, bind_id, flow_flags, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \ - flow_flags, arg1_name, arg1_val) -#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, \ - arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) -#define TRACE_EVENT_WITH_FLOW2(category_group, name, bind_id, flow_flags, \ - arg1_name, arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \ - flow_flags, arg1_name, arg1_val, \ - arg2_name, arg2_val) - -// Records a single event called "name" immediately, with 0, 1 or 2 -// associated arguments. If the category is not enabled, then this -// does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_EVENT_INSTANT0(category_group, name, scope) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \ - TRACE_EVENT_FLAG_NONE | scope) -#define TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \ - TRACE_EVENT_FLAG_NONE | scope, arg1_name, arg1_val) -#define TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \ - TRACE_EVENT_FLAG_NONE | scope, arg1_name, arg1_val, \ - arg2_name, arg2_val) -#define TRACE_EVENT_COPY_INSTANT0(category_group, name, scope) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \ - TRACE_EVENT_FLAG_COPY | scope) -#define TRACE_EVENT_COPY_INSTANT1(category_group, name, scope, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \ - TRACE_EVENT_FLAG_COPY | scope, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_INSTANT2(category_group, name, scope, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \ - TRACE_EVENT_FLAG_COPY | scope, arg1_name, arg1_val, \ - arg2_name, arg2_val) -#define TRACE_EVENT_INSTANT_WITH_FLAGS0(category_group, name, scope_and_flags) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \ - scope_and_flags) -#define TRACE_EVENT_INSTANT_WITH_FLAGS1(category_group, name, scope_and_flags, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \ - scope_and_flags, arg1_name, arg1_val) - -#define TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(category_group, name, scope, \ - timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \ - TRACE_EVENT_PHASE_INSTANT, category_group, name, timestamp, \ - TRACE_EVENT_FLAG_NONE | scope) - -#define TRACE_EVENT_INSTANT_WITH_TIMESTAMP1(category_group, name, scope, \ - timestamp, arg_name, arg_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \ - TRACE_EVENT_PHASE_INSTANT, category_group, name, timestamp, \ - TRACE_EVENT_FLAG_NONE | scope, arg_name, arg_val) - -// Records a single BEGIN event called "name" immediately, with 0, 1 or 2 -// associated arguments. If the category is not enabled, then this -// does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_EVENT_BEGIN0(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_BEGIN1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_BEGIN2(category_group, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ - arg2_name, arg2_val) -#define TRACE_EVENT_BEGIN_WITH_FLAGS0(category_group, name, flags) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, flags) -#define TRACE_EVENT_BEGIN_WITH_FLAGS1(category_group, name, flags, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \ - flags, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_BEGIN2(category_group, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ - arg2_name, arg2_val) - -// Similar to TRACE_EVENT_BEGINx but with a custom |at| timestamp provided. -// - |id| is used to match the _BEGIN event with the _END event. -// Events are considered to match if their category_group, name and id values -// all match. |id| must either be a pointer or an integer value up to 64 bits. -// If it's a pointer, the bits will be xored with a hash of the process ID so -// that the same pointer on two different processes will not collide. -#define TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category_group, name, id, \ - thread_id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0( \ - category_group, name, id, thread_id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1( \ - category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2( \ - category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, \ - arg2_val) - -// Records a single END event for "name" immediately. If the category -// is not enabled, then this does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_EVENT_END0(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_END1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_END2(category_group, name, arg1_name, arg1_val, arg2_name, \ - arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ - arg2_name, arg2_val) -#define TRACE_EVENT_END_WITH_FLAGS0(category_group, name, flags) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, flags) -#define TRACE_EVENT_END_WITH_FLAGS1(category_group, name, flags, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, flags, \ - arg1_name, arg1_val) -#define TRACE_EVENT_COPY_END2(category_group, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ - arg2_name, arg2_val) - -#define TRACE_EVENT_MARK_WITH_TIMESTAMP0(category_group, name, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \ - TRACE_EVENT_PHASE_MARK, category_group, name, timestamp, \ - TRACE_EVENT_FLAG_NONE) - -#define TRACE_EVENT_MARK_WITH_TIMESTAMP1(category_group, name, timestamp, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \ - TRACE_EVENT_PHASE_MARK, category_group, name, timestamp, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) - -#define TRACE_EVENT_MARK_WITH_TIMESTAMP2( \ - category_group, name, timestamp, arg1_name, arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \ - TRACE_EVENT_PHASE_MARK, category_group, name, timestamp, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val) - -#define TRACE_EVENT_COPY_MARK(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_MARK, category_group, name, \ - TRACE_EVENT_FLAG_COPY) - -#define TRACE_EVENT_COPY_MARK1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_MARK, category_group, name, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) - -#define TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(category_group, name, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \ - TRACE_EVENT_PHASE_MARK, category_group, name, timestamp, \ - TRACE_EVENT_FLAG_COPY) - -// Similar to TRACE_EVENT_ENDx but with a custom |at| timestamp provided. -// - |id| is used to match the _BEGIN event with the _END event. -// Events are considered to match if their category_group, name and id values -// all match. |id| must either be a pointer or an integer value up to 64 bits. -// If it's a pointer, the bits will be xored with a hash of the process ID so -// that the same pointer on two different processes will not collide. -#define TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(category_group, name, id, \ - thread_id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0( \ - category_group, name, id, thread_id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1( \ - category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2( \ - category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, \ - arg2_val) - -// Records the value of a counter called "name" immediately. Value -// must be representable as a 32 bit integer. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_COUNTER1(category_group, name, value) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \ - TRACE_EVENT_FLAG_NONE, "value", \ - static_cast(value)) -#define TRACE_COUNTER_WITH_FLAG1(category_group, name, flag, value) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \ - flag, "value", static_cast(value)) -#define TRACE_COPY_COUNTER1(category_group, name, value) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \ - TRACE_EVENT_FLAG_COPY, "value", \ - static_cast(value)) - -// Records the values of a multi-parted counter called "name" immediately. -// The UI will treat value1 and value2 as parts of a whole, displaying their -// values as a stacked-bar chart. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_COUNTER2(category_group, name, value1_name, value1_val, \ - value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \ - TRACE_EVENT_FLAG_NONE, value1_name, \ - static_cast(value1_val), value2_name, \ - static_cast(value2_val)) -#define TRACE_COPY_COUNTER2(category_group, name, value1_name, value1_val, \ - value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \ - TRACE_EVENT_FLAG_COPY, value1_name, \ - static_cast(value1_val), value2_name, \ - static_cast(value2_val)) - -// Similar to TRACE_COUNTERx, but with a custom |timestamp| provided. -#define TRACE_COUNTER_WITH_TIMESTAMP1(category_group, name, timestamp, value) \ - INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \ - TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp, \ - TRACE_EVENT_FLAG_NONE, "value", static_cast(value)) - -#define TRACE_COUNTER_WITH_TIMESTAMP2(category_group, name, timestamp, \ - value1_name, value1_val, value2_name, \ - value2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \ - TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp, \ - TRACE_EVENT_FLAG_NONE, value1_name, static_cast(value1_val), \ - value2_name, static_cast(value2_val)) - -// Records the value of a counter called "name" immediately. Value -// must be representable as a 32 bit integer. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -// - |id| is used to disambiguate counters with the same name. It must either -// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits -// will be xored with a hash of the process ID so that the same pointer on -// two different processes will not collide. -#define TRACE_COUNTER_ID1(category_group, name, id, value) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \ - name, id, TRACE_EVENT_FLAG_NONE, "value", \ - static_cast(value)) -#define TRACE_COPY_COUNTER_ID1(category_group, name, id, value) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \ - name, id, TRACE_EVENT_FLAG_COPY, "value", \ - static_cast(value)) - -// Records the values of a multi-parted counter called "name" immediately. -// The UI will treat value1 and value2 as parts of a whole, displaying their -// values as a stacked-bar chart. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -// - |id| is used to disambiguate counters with the same name. It must either -// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits -// will be xored with a hash of the process ID so that the same pointer on -// two different processes will not collide. -#define TRACE_COUNTER_ID2(category_group, name, id, value1_name, value1_val, \ - value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \ - name, id, TRACE_EVENT_FLAG_NONE, \ - value1_name, static_cast(value1_val), \ - value2_name, static_cast(value2_val)) -#define TRACE_COPY_COUNTER_ID2(category_group, name, id, value1_name, \ - value1_val, value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \ - name, id, TRACE_EVENT_FLAG_COPY, \ - value1_name, static_cast(value1_val), \ - value2_name, static_cast(value2_val)) - -#define TRACE_EVENT_SAMPLE_WITH_ID1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_SAMPLE, category_group, \ - name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ - arg1_val) - -// -- TRACE_EVENT_ASYNC is DEPRECATED! -- -// -// TRACE_EVENT_ASYNC_* APIs should be only used by legacy code. New code should -// use TRACE_EVENT_NESTABLE_ASYNC_* APIs instead. -// -// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2 -// associated arguments. If the category is not enabled, then this -// does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC -// events are considered to match if their category_group, name and id values -// all match. |id| must either be a pointer or an integer value up to 64 bits. -// If it's a pointer, the bits will be xored with a hash of the process ID so -// that the same pointer on two different processes will not collide. -// -// An asynchronous operation can consist of multiple phases. The first phase is -// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the -// ASYNC_STEP_INTO or ASYNC_STEP_PAST macros. The ASYNC_STEP_INTO macro will -// annotate the block following the call. The ASYNC_STEP_PAST macro will -// annotate the block prior to the call. Note that any particular event must use -// only STEP_INTO or STEP_PAST macros; they can not mix and match. When the -// operation completes, call ASYNC_END. -// -// An ASYNC trace typically occurs on a single thread (if not, they will only be -// drawn on the thread defined in the ASYNC_BEGIN event), but all events in that -// operation must use the same |name| and |id|. Each step can have its own -// args. -#define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_ASYNC_BEGIN1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_ASYNC_BEGIN2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val) - -// Similar to TRACE_EVENT_ASYNC_BEGINx but with a custom |at| timestamp -// provided. -#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, id, \ - timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1( \ - category_group, name, id, timestamp, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val) -#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP2(category_group, name, id, \ - timestamp, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, id, \ - timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY) - -// Records a single ASYNC_STEP_INTO event for |step| immediately. If the -// category is not enabled, then this does nothing. The |name| and |id| must -// match the ASYNC_BEGIN event above. The |step| param identifies this step -// within the async event. This should be called at the beginning of the next -// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any -// ASYNC_STEP_PAST events. -#define TRACE_EVENT_ASYNC_STEP_INTO0(category_group, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, "step", step) -#define TRACE_EVENT_ASYNC_STEP_INTO1(category_group, name, id, step, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, "step", step, arg1_name, arg1_val) - -// Similar to TRACE_EVENT_ASYNC_STEP_INTOx but with a custom |at| timestamp -// provided. -#define TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category_group, name, id, \ - step, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \ - "step", step) - -// Records a single ASYNC_STEP_PAST event for |step| immediately. If the -// category is not enabled, then this does nothing. The |name| and |id| must -// match the ASYNC_BEGIN event above. The |step| param identifies this step -// within the async event. This should be called at the beginning of the next -// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any -// ASYNC_STEP_INTO events. -#define TRACE_EVENT_ASYNC_STEP_PAST0(category_group, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, "step", step) -#define TRACE_EVENT_ASYNC_STEP_PAST1(category_group, name, id, step, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_ASYNC_STEP_PAST, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, "step", step, arg1_name, arg1_val) - -// Records a single ASYNC_END event for "name" immediately. If the category -// is not enabled, then this does nothing. -#define TRACE_EVENT_ASYNC_END0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_ASYNC_END1(category_group, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_ASYNC_END2(category_group, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_ASYNC_END0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_ASYNC_END1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_ASYNC_END2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val) - -// Similar to TRACE_EVENT_ASYNC_ENDx but with a custom |at| timestamp provided. -#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(category_group, name, id, \ - timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP1(category_group, name, id, \ - timestamp, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val) -#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP2(category_group, name, id, \ - timestamp, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_ASYNC_END_WITH_TIMESTAMP0(category_group, name, id, \ - timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY) - -// NESTABLE_ASYNC_* APIs are used to describe an async operation, which can -// be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC -// events. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -// - A pair of NESTABLE_ASYNC_BEGIN event and NESTABLE_ASYNC_END event is -// considered as a match if their category_group, name and id all match. -// - |id| must either be a pointer or an integer value up to 64 bits. -// If it's a pointer, the bits will be xored with a hash of the process ID so -// that the same pointer on two different processes will not collide. -// - |id| is used to match a child NESTABLE_ASYNC event with its parent -// NESTABLE_ASYNC event. Therefore, events in the same nested event tree must -// be logged using the same id and category_group. -// -// Unmatched NESTABLE_ASYNC_END event will be parsed as an event that starts -// at the first NESTABLE_ASYNC event of that id, and unmatched -// NESTABLE_ASYNC_BEGIN event will be parsed as an event that ends at the last -// NESTABLE_ASYNC event of that id. Corresponding warning messages for -// unmatched events will be shown in the analysis view. - -// Records a single NESTABLE_ASYNC_BEGIN event called "name" immediately, with -// 0, 1 or 2 associated arguments. If the category is not enabled, then this -// does nothing. -#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_FLAGS0(category_group, name, id, \ - flags) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \ - category_group, name, id, flags) -// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 0 -// or 2 associated arguments. If the category is not enabled, then this does -// nothing. -#define TRACE_EVENT_NESTABLE_ASYNC_END0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE) -// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 1 -// associated argument. If the category is not enabled, then this does nothing. -#define TRACE_EVENT_NESTABLE_ASYNC_END1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_FLAGS0(category_group, name, id, \ - flags) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \ - category_group, name, id, flags) - -// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately, -// with none, one or two associated argument. If the category is not enabled, -// then this does nothing. -#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE) - -#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(category_group, name, id, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) - -#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT2( \ - category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val) - -#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2( \ - category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ - arg2_name, arg2_val) -#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2( \ - category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ - arg2_name, arg2_val) - -// Similar to TRACE_EVENT_NESTABLE_ASYNC_{BEGIN,END}x but with a custom -// |timestamp| provided. -#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, \ - id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1( \ - category_group, name, id, timestamp, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val) -#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP_AND_FLAGS0( \ - category_group, name, id, timestamp, flags) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, flags) -#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(category_group, name, \ - id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP1( \ - category_group, name, id, timestamp, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val) -#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP2( \ - category_group, name, id, timestamp, arg1_name, arg1_val, arg2_name, \ - arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP_AND_FLAGS0( \ - category_group, name, id, timestamp, flags) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, flags) -#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT_WITH_TIMESTAMP0( \ - category_group, name, id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0( \ - category_group, name, id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0( \ - category_group, name, id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \ - TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END1(category_group, name, id, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) - -// Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2 -// associated arguments. If the category is not enabled, then this -// does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -// - |id| is used to match the FLOW_BEGIN event with the FLOW_END event. FLOW -// events are considered to match if their category_group, name and id values -// all match. |id| must either be a pointer or an integer value up to 64 bits. -// If it's a pointer, the bits will be xored with a hash of the process ID so -// that the same pointer on two different processes will not collide. -// FLOW events are different from ASYNC events in how they are drawn by the -// tracing UI. A FLOW defines asynchronous data flow, such as posting a task -// (FLOW_BEGIN) and later executing that task (FLOW_END). Expect FLOWs to be -// drawn as lines or arrows from FLOW_BEGIN scopes to FLOW_END scopes. Similar -// to ASYNC, a FLOW can consist of multiple phases. The first phase is defined -// by the FLOW_BEGIN calls. Additional phases can be defined using the FLOW_STEP -// macros. When the operation completes, call FLOW_END. An async operation can -// span threads and processes, but all events in that operation must use the -// same |name| and |id|. Each event can have its own args. -#define TRACE_EVENT_FLOW_BEGIN0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_FLOW_BEGIN1(category_group, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_FLOW_BEGIN2(category_group, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_FLOW_BEGIN, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_FLOW_BEGIN0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_FLOW_BEGIN1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_FLOW_BEGIN2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_FLOW_BEGIN, category_group, name, id, \ - TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val) - -// Records a single FLOW_STEP event for |step| immediately. If the category -// is not enabled, then this does nothing. The |name| and |id| must match the -// FLOW_BEGIN event above. The |step| param identifies this step within the -// async event. This should be called at the beginning of the next phase of an -// asynchronous operation. -#define TRACE_EVENT_FLOW_STEP0(category_group, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, "step", step) -#define TRACE_EVENT_FLOW_STEP1(category_group, name, id, step, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_FLOW_STEP, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE, "step", step, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_FLOW_STEP0(category_group, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ - category_group, name, id, \ - TRACE_EVENT_FLAG_COPY, "step", step) -#define TRACE_EVENT_COPY_FLOW_STEP1(category_group, name, id, step, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_FLOW_STEP, category_group, name, id, \ - TRACE_EVENT_FLAG_COPY, "step", step, arg1_name, arg1_val) - -// Records a single FLOW_END event for "name" immediately. If the category -// is not enabled, then this does nothing. -#define TRACE_EVENT_FLOW_END0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \ - name, id, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \ - name, id, \ - TRACE_EVENT_FLAG_BIND_TO_ENCLOSING) -#define TRACE_EVENT_FLOW_END1(category_group, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \ - name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ - arg1_val) -#define TRACE_EVENT_FLOW_END2(category_group, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \ - name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \ - arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_FLOW_END0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \ - name, id, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_FLOW_END1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \ - name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ - arg1_val) -#define TRACE_EVENT_COPY_FLOW_END2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \ - name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \ - arg1_val, arg2_name, arg2_val) - -// Special trace event macro to trace task execution with the location where it -// was posted from. -#define TRACE_TASK_EXECUTION(run_function, task) \ - INTERNAL_TRACE_TASK_EXECUTION(run_function, task) - -#define TRACE_LOG_MESSAGE(file, message, line) \ - INTERNAL_TRACE_LOG_MESSAGE(file, message, line) - -// TRACE_EVENT_METADATA* events are information related to other -// injected events, not events in their own right. -#define TRACE_EVENT_METADATA1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_METADATA_ADD(category_group, name, arg1_name, arg1_val) - -// Records a clock sync event. -#define TRACE_EVENT_CLOCK_SYNC_RECEIVER(sync_id) \ - INTERNAL_TRACE_EVENT_ADD( \ - TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata", "clock_sync", \ - TRACE_EVENT_FLAG_NONE, "sync_id", sync_id) -#define TRACE_EVENT_CLOCK_SYNC_ISSUER(sync_id, issue_ts, issue_end_ts) \ - INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \ - TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata", "clock_sync", \ - issue_end_ts, TRACE_EVENT_FLAG_NONE, \ - "sync_id", sync_id, "issue_ts", issue_ts) - -// Macros to track the life time and value of arbitrary client objects. -// See also TraceTrackableObject. -#define TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_CREATE_OBJECT, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE) - -#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category_group, name, id, \ - snapshot) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name, \ - id, TRACE_EVENT_FLAG_NONE, "snapshot", snapshot) - -#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP( \ - category_group, name, id, timestamp, snapshot) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name, \ - id, TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \ - "snapshot", snapshot) - -#define TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_DELETE_OBJECT, category_group, name, id, \ - TRACE_EVENT_FLAG_NONE) - -// Records entering and leaving trace event contexts. |category_group| and -// |name| specify the context category and type. |context| is a -// snapshotted context object id. -#define TRACE_EVENT_ENTER_CONTEXT(category_group, name, context) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_ENTER_CONTEXT, category_group, name, context, \ - TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_LEAVE_CONTEXT(category_group, name, context) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID( \ - TRACE_EVENT_PHASE_LEAVE_CONTEXT, category_group, name, context, \ - TRACE_EVENT_FLAG_NONE) - -// Macro to efficiently determine if a given category group is enabled. -#define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret) \ - do { \ - INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ - if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \ - *ret = true; \ - } else { \ - *ret = false; \ - } \ - } while (0) - -// Macro to efficiently determine, through polling, if a new trace has begun. -#define TRACE_EVENT_IS_NEW_TRACE(ret) \ - do { \ - static int INTERNAL_TRACE_EVENT_UID(lastRecordingNumber) = 0; \ - int num_traces_recorded = TRACE_EVENT_API_GET_NUM_TRACES_RECORDED(); \ - if (num_traces_recorded != -1 && \ - num_traces_recorded != \ - INTERNAL_TRACE_EVENT_UID(lastRecordingNumber)) { \ - INTERNAL_TRACE_EVENT_UID(lastRecordingNumber) = num_traces_recorded; \ - *ret = true; \ - } else { \ - *ret = false; \ - } \ - } while (0) - -// Macro for getting the real base::TimeTicks::Now() which can be overridden in -// headless when VirtualTime is enabled. -#define TRACE_TIME_TICKS_NOW() INTERNAL_TRACE_TIME_TICKS_NOW() - -// Macro for getting the real base::Time::Now() which can be overridden in -// headless when VirtualTime is enabled. -#define TRACE_TIME_NOW() INTERNAL_TRACE_TIME_NOW() - -// Notes regarding the following definitions: -// New values can be added and propagated to third party libraries, but existing -// definitions must never be changed, because third party libraries may use old -// definitions. - -// Phase indicates the nature of an event entry. E.g. part of a begin/end pair. -#define TRACE_EVENT_PHASE_BEGIN ('B') -#define TRACE_EVENT_PHASE_END ('E') -#define TRACE_EVENT_PHASE_COMPLETE ('X') -#define TRACE_EVENT_PHASE_INSTANT ('I') -#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S') -#define TRACE_EVENT_PHASE_ASYNC_STEP_INTO ('T') -#define TRACE_EVENT_PHASE_ASYNC_STEP_PAST ('p') -#define TRACE_EVENT_PHASE_ASYNC_END ('F') -#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN ('b') -#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_END ('e') -#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT ('n') -#define TRACE_EVENT_PHASE_FLOW_BEGIN ('s') -#define TRACE_EVENT_PHASE_FLOW_STEP ('t') -#define TRACE_EVENT_PHASE_FLOW_END ('f') -#define TRACE_EVENT_PHASE_METADATA ('M') -#define TRACE_EVENT_PHASE_COUNTER ('C') -#define TRACE_EVENT_PHASE_SAMPLE ('P') -#define TRACE_EVENT_PHASE_CREATE_OBJECT ('N') -#define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O') -#define TRACE_EVENT_PHASE_DELETE_OBJECT ('D') -#define TRACE_EVENT_PHASE_MEMORY_DUMP ('v') -#define TRACE_EVENT_PHASE_MARK ('R') -#define TRACE_EVENT_PHASE_CLOCK_SYNC ('c') -#define TRACE_EVENT_PHASE_ENTER_CONTEXT ('(') -#define TRACE_EVENT_PHASE_LEAVE_CONTEXT (')') - -// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT. -#define TRACE_EVENT_FLAG_NONE (static_cast(0)) -#define TRACE_EVENT_FLAG_COPY (static_cast(1 << 0)) -#define TRACE_EVENT_FLAG_HAS_ID (static_cast(1 << 1)) -#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast(1 << 2)) -#define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast(1 << 3)) -#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast(1 << 4)) -#define TRACE_EVENT_FLAG_ASYNC_TTS (static_cast(1 << 5)) -#define TRACE_EVENT_FLAG_BIND_TO_ENCLOSING (static_cast(1 << 6)) -#define TRACE_EVENT_FLAG_FLOW_IN (static_cast(1 << 7)) -#define TRACE_EVENT_FLAG_FLOW_OUT (static_cast(1 << 8)) -#define TRACE_EVENT_FLAG_HAS_CONTEXT_ID (static_cast(1 << 9)) -#define TRACE_EVENT_FLAG_HAS_PROCESS_ID (static_cast(1 << 10)) -#define TRACE_EVENT_FLAG_HAS_LOCAL_ID (static_cast(1 << 11)) -#define TRACE_EVENT_FLAG_HAS_GLOBAL_ID (static_cast(1 << 12)) -// TODO(eseckler): Remove once we have native support for typed proto events in -// TRACE_EVENT macros. -#define TRACE_EVENT_FLAG_TYPED_PROTO_ARGS (static_cast(1 << 15)) -#define TRACE_EVENT_FLAG_JAVA_STRING_LITERALS \ - (static_cast(1 << 16)) - -#define TRACE_EVENT_FLAG_SCOPE_MASK \ - (static_cast(TRACE_EVENT_FLAG_SCOPE_OFFSET | \ - TRACE_EVENT_FLAG_SCOPE_EXTRA)) - -// Type values for identifying types in the TraceValue union. -#define TRACE_VALUE_TYPE_BOOL (static_cast(1)) -#define TRACE_VALUE_TYPE_UINT (static_cast(2)) -#define TRACE_VALUE_TYPE_INT (static_cast(3)) -#define TRACE_VALUE_TYPE_DOUBLE (static_cast(4)) -#define TRACE_VALUE_TYPE_POINTER (static_cast(5)) -#define TRACE_VALUE_TYPE_STRING (static_cast(6)) -#define TRACE_VALUE_TYPE_COPY_STRING (static_cast(7)) -#define TRACE_VALUE_TYPE_CONVERTABLE (static_cast(8)) - -// Enum reflecting the scope of an INSTANT event. Must fit within -// TRACE_EVENT_FLAG_SCOPE_MASK. -#define TRACE_EVENT_SCOPE_GLOBAL (static_cast(0 << 2)) -#define TRACE_EVENT_SCOPE_PROCESS (static_cast(1 << 2)) -#define TRACE_EVENT_SCOPE_THREAD (static_cast(2 << 2)) - -#define TRACE_EVENT_SCOPE_NAME_GLOBAL ('g') -#define TRACE_EVENT_SCOPE_NAME_PROCESS ('p') -#define TRACE_EVENT_SCOPE_NAME_THREAD ('t') - -#endif // BASE_TRACE_EVENT_COMMON_TRACE_EVENT_COMMON_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/address-region.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/address-region.h index 9ef6160d2..010a123dc 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/address-region.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/address-region.h @@ -15,11 +15,19 @@ namespace base { // Helper class representing an address region of certain size. class AddressRegion { public: + // Function object that compares the start address of two regions. Usable as + // compare function on std data structures and algorithms. + struct StartAddressLess { + bool operator()(base::AddressRegion a, base::AddressRegion b) const { + return a.begin() < b.begin(); + } + }; + using Address = uintptr_t; - AddressRegion() = default; + constexpr AddressRegion() = default; - AddressRegion(Address address, size_t size) + constexpr AddressRegion(Address address, size_t size) : address_(address), size_(size) {} Address begin() const { return address_; } diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomic-utils.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomic-utils.h index 5d51510e3..76fc6449b 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomic-utils.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomic-utils.h @@ -6,6 +6,8 @@ #define V8_BASE_ATOMIC_UTILS_H_ #include + +#include #include #include "src/base/atomicops.h" @@ -64,6 +66,13 @@ class AsAtomicImpl { public: using AtomicStorageType = TAtomicStorageType; + template + static T SeqCst_Load(T* addr) { + STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType)); + return cast_helper::to_return_type( + base::SeqCst_Load(to_storage_addr(addr))); + } + template static T Acquire_Load(T* addr) { STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType)); @@ -78,6 +87,14 @@ class AsAtomicImpl { base::Relaxed_Load(to_storage_addr(addr))); } + template + static void SeqCst_Store(T* addr, + typename std::remove_reference::type new_value) { + STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType)); + base::SeqCst_Store(to_storage_addr(addr), + cast_helper::to_storage_type(new_value)); + } + template static void Release_Store(T* addr, typename std::remove_reference::type new_value) { @@ -94,6 +111,14 @@ class AsAtomicImpl { cast_helper::to_storage_type(new_value)); } + template + static T SeqCst_Swap(T* addr, + typename std::remove_reference::type new_value) { + STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType)); + return base::SeqCst_AtomicExchange( + to_storage_addr(addr), cast_helper::to_storage_type(new_value)); + } + template static T Release_CompareAndSwap( T* addr, typename std::remove_reference::type old_value, @@ -173,9 +198,31 @@ class AsAtomicImpl { }; using AsAtomic8 = AsAtomicImpl; +using AsAtomic16 = AsAtomicImpl; using AsAtomic32 = AsAtomicImpl; using AsAtomicWord = AsAtomicImpl; +template +struct AtomicTypeFromByteWidth {}; +template <> +struct AtomicTypeFromByteWidth<1> { + using type = base::Atomic8; +}; +template <> +struct AtomicTypeFromByteWidth<2> { + using type = base::Atomic16; +}; +template <> +struct AtomicTypeFromByteWidth<4> { + using type = base::Atomic32; +}; +#if V8_HOST_ARCH_64_BIT +template <> +struct AtomicTypeFromByteWidth<8> { + using type = base::Atomic64; +}; +#endif + // This is similar to AsAtomicWord but it explicitly deletes functionality // provided atomic access to bit representation of stored values. template @@ -189,27 +236,35 @@ using AsAtomicPointer = AsAtomicPointerImpl; template ::value>::type> -inline void CheckedIncrement(std::atomic* number, T amount) { - const T old = number->fetch_add(amount); +inline void CheckedIncrement( + std::atomic* number, T amount, + std::memory_order order = std::memory_order_seq_cst) { + const T old = number->fetch_add(amount, order); DCHECK_GE(old + amount, old); USE(old); } template ::value>::type> -inline void CheckedDecrement(std::atomic* number, T amount) { - const T old = number->fetch_sub(amount); +inline void CheckedDecrement( + std::atomic* number, T amount, + std::memory_order order = std::memory_order_seq_cst) { + const T old = number->fetch_sub(amount, order); DCHECK_GE(old, amount); USE(old); } template V8_INLINE std::atomic* AsAtomicPtr(T* t) { + STATIC_ASSERT(sizeof(T) == sizeof(std::atomic)); + STATIC_ASSERT(alignof(T) >= alignof(std::atomic)); return reinterpret_cast*>(t); } template V8_INLINE const std::atomic* AsAtomicPtr(const T* t) { + STATIC_ASSERT(sizeof(T) == sizeof(std::atomic)); + STATIC_ASSERT(alignof(T) >= alignof(std::atomic)); return reinterpret_cast*>(t); } diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomicops.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomicops.h index 11c41545a..93a390380 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomicops.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomicops.h @@ -27,6 +27,8 @@ #include +#include + // Small C++ header which defines implementation specific macros used to // identify the STL implementation. // - libc++: captures __config for _LIBCPP_VERSION @@ -35,10 +37,23 @@ #include "src/base/base-export.h" #include "src/base/build_config.h" +#include "src/base/macros.h" + +#if defined(V8_OS_STARBOARD) +#include "starboard/atomic.h" +#endif // V8_OS_STARBOARD namespace v8 { namespace base { +#ifdef V8_OS_STARBOARD +using Atomic8 = SbAtomic8; +using Atomic16 = int16_t; +using Atomic32 = SbAtomic32; +#if SB_IS_64_BIT +using Atomic64 = SbAtomic64; +#endif +#else using Atomic8 = char; using Atomic16 = int16_t; using Atomic32 = int32_t; @@ -51,10 +66,31 @@ using Atomic64 = int64_t; using Atomic64 = intptr_t; #endif // defined(__ILP32__) #endif // defined(V8_HOST_ARCH_64_BIT) +#endif // V8_OS_STARBOARD -// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or +// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or // Atomic64 routines below, depending on your architecture. -using AtomicWord = intptr_t; +#if defined(V8_HOST_ARCH_64_BIT) +using AtomicWord = Atomic64; +#else +using AtomicWord = Atomic32; +#endif +STATIC_ASSERT(sizeof(void*) == sizeof(AtomicWord)); + +namespace helper { +template +volatile std::atomic* to_std_atomic(volatile T* ptr) { + return reinterpret_cast*>(ptr); +} +template +volatile const std::atomic* to_std_atomic_const(volatile const T* ptr) { + return reinterpret_cast*>(ptr); +} +} // namespace helper + +inline void SeqCst_MemoryFence() { + std::atomic_thread_fence(std::memory_order_seq_cst); +} // Atomically execute: // result = *ptr; @@ -65,77 +101,370 @@ using AtomicWord = intptr_t; // I.e. replace |*ptr| with |new_value| if |*ptr| used to be |old_value|. // Always return the value of |*ptr| before the operation. // Acquire, Relaxed, Release correspond to standard C++ memory orders. -Atomic16 Relaxed_CompareAndSwap(volatile Atomic16* ptr, Atomic16 old_value, - Atomic16 new_value); -Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, - Atomic32 new_value); -Atomic32 AcquireRelease_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, Atomic32 new_value); -Atomic32 Relaxed_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, - Atomic32 new_value); -Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, - Atomic32 new_value); -#ifdef V8_HOST_ARCH_64_BIT -Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, - Atomic64 new_value); -Atomic64 AcquireRelease_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, Atomic64 new_value); -Atomic64 Relaxed_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, - Atomic64 new_value); -Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, - Atomic64 new_value); -#endif // V8_HOST_ARCH_64_BIT - -// Atomically store new_value into |*ptr|, returning the previous value held in -// |*ptr|. -Atomic32 Relaxed_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value); -#ifdef V8_HOST_ARCH_64_BIT -Atomic64 Relaxed_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value); -#endif // V8_HOST_ARCH_64_BIT - -// Atomically increment |*ptr| by |increment|. Returns the new value of -// |*ptr| with the increment applied. -Atomic32 Relaxed_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment); - -#ifdef V8_HOST_ARCH_64_BIT -Atomic64 Relaxed_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); -#endif // V8_HOST_ARCH_64_BIT - -void SeqCst_MemoryFence(); - -void Relaxed_Store(volatile Atomic8* ptr, Atomic8 value); -void Relaxed_Store(volatile Atomic16* ptr, Atomic16 value); -void Relaxed_Store(volatile Atomic32* ptr, Atomic32 value); -void Release_Store(volatile Atomic32* ptr, Atomic32 value); -#ifdef V8_HOST_ARCH_64_BIT -void Relaxed_Store(volatile Atomic64* ptr, Atomic64 value); -void Release_Store(volatile Atomic64* ptr, Atomic64 value); -#endif // V8_HOST_ARCH_64_BIT - -Atomic8 Relaxed_Load(volatile const Atomic8* ptr); -Atomic16 Relaxed_Load(volatile const Atomic16* ptr); -Atomic32 Relaxed_Load(volatile const Atomic32* ptr); -Atomic32 Acquire_Load(volatile const Atomic32* ptr); -#ifdef V8_HOST_ARCH_64_BIT -Atomic64 Relaxed_Load(volatile const Atomic64* ptr); -Atomic64 Acquire_Load(volatile const Atomic64* ptr); -#endif // V8_HOST_ARCH_64_BIT +inline Atomic8 Relaxed_CompareAndSwap(volatile Atomic8* ptr, Atomic8 old_value, + Atomic8 new_value) { + std::atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_relaxed, std::memory_order_relaxed); + return old_value; +} -} // namespace base -} // namespace v8 +inline Atomic16 Relaxed_CompareAndSwap(volatile Atomic16* ptr, + Atomic16 old_value, Atomic16 new_value) { + std::atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_relaxed, std::memory_order_relaxed); + return old_value; +} + +inline Atomic32 Relaxed_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, Atomic32 new_value) { + std::atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_relaxed, std::memory_order_relaxed); + return old_value; +} + +inline Atomic32 Relaxed_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + return std::atomic_exchange_explicit(helper::to_std_atomic(ptr), new_value, + std::memory_order_relaxed); +} + +inline Atomic32 SeqCst_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + return std::atomic_exchange_explicit(helper::to_std_atomic(ptr), new_value, + std::memory_order_seq_cst); +} + +inline Atomic32 Relaxed_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return increment + std::atomic_fetch_add_explicit(helper::to_std_atomic(ptr), + increment, + std::memory_order_relaxed); +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, Atomic32 new_value) { + atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_acquire, std::memory_order_acquire); + return old_value; +} + +inline Atomic8 Release_CompareAndSwap(volatile Atomic8* ptr, Atomic8 old_value, + Atomic8 new_value) { + bool result = atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_release, std::memory_order_relaxed); + USE(result); // Make gcc compiler happy. + return old_value; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, Atomic32 new_value) { + atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_release, std::memory_order_relaxed); + return old_value; +} + +inline Atomic32 AcquireRelease_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_acq_rel, std::memory_order_acquire); + return old_value; +} + +inline void Relaxed_Store(volatile Atomic8* ptr, Atomic8 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_relaxed); +} + +inline void Relaxed_Store(volatile Atomic16* ptr, Atomic16 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_relaxed); +} + +inline void Relaxed_Store(volatile Atomic32* ptr, Atomic32 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_relaxed); +} + +inline void Release_Store(volatile Atomic8* ptr, Atomic8 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_release); +} + +inline void Release_Store(volatile Atomic16* ptr, Atomic16 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_release); +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_release); +} + +inline void SeqCst_Store(volatile Atomic8* ptr, Atomic8 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_seq_cst); +} + +inline void SeqCst_Store(volatile Atomic16* ptr, Atomic16 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_seq_cst); +} + +inline void SeqCst_Store(volatile Atomic32* ptr, Atomic32 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_seq_cst); +} + +inline Atomic8 Relaxed_Load(volatile const Atomic8* ptr) { + return std::atomic_load_explicit(helper::to_std_atomic_const(ptr), + std::memory_order_relaxed); +} + +inline Atomic16 Relaxed_Load(volatile const Atomic16* ptr) { + return std::atomic_load_explicit(helper::to_std_atomic_const(ptr), + std::memory_order_relaxed); +} + +inline Atomic32 Relaxed_Load(volatile const Atomic32* ptr) { + return std::atomic_load_explicit(helper::to_std_atomic_const(ptr), + std::memory_order_relaxed); +} -#if defined(V8_OS_WIN) -#include "src/base/atomicops_internals_std.h" +inline Atomic8 Acquire_Load(volatile const Atomic8* ptr) { + return std::atomic_load_explicit(helper::to_std_atomic_const(ptr), + std::memory_order_acquire); +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + return std::atomic_load_explicit(helper::to_std_atomic_const(ptr), + std::memory_order_acquire); +} + +inline Atomic8 SeqCst_Load(volatile const Atomic8* ptr) { + return std::atomic_load_explicit(helper::to_std_atomic_const(ptr), + std::memory_order_seq_cst); +} + +inline Atomic32 SeqCst_Load(volatile const Atomic32* ptr) { + return std::atomic_load_explicit(helper::to_std_atomic_const(ptr), + std::memory_order_seq_cst); +} + +#if defined(V8_HOST_ARCH_64_BIT) + +inline Atomic64 Relaxed_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, Atomic64 new_value) { + std::atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_relaxed, std::memory_order_relaxed); + return old_value; +} + +inline Atomic64 Relaxed_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + return std::atomic_exchange_explicit(helper::to_std_atomic(ptr), new_value, + std::memory_order_relaxed); +} + +inline Atomic64 SeqCst_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + return std::atomic_exchange_explicit(helper::to_std_atomic(ptr), new_value, + std::memory_order_seq_cst); +} + +inline Atomic64 Relaxed_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return increment + std::atomic_fetch_add_explicit(helper::to_std_atomic(ptr), + increment, + std::memory_order_relaxed); +} + +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, Atomic64 new_value) { + std::atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_acquire, std::memory_order_acquire); + return old_value; +} + +inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, Atomic64 new_value) { + std::atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_release, std::memory_order_relaxed); + return old_value; +} + +inline Atomic64 AcquireRelease_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + std::atomic_compare_exchange_strong_explicit( + helper::to_std_atomic(ptr), &old_value, new_value, + std::memory_order_acq_rel, std::memory_order_acquire); + return old_value; +} + +inline void Relaxed_Store(volatile Atomic64* ptr, Atomic64 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_relaxed); +} + +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_release); +} + +inline void SeqCst_Store(volatile Atomic64* ptr, Atomic64 value) { + std::atomic_store_explicit(helper::to_std_atomic(ptr), value, + std::memory_order_seq_cst); +} + +inline Atomic64 Relaxed_Load(volatile const Atomic64* ptr) { + return std::atomic_load_explicit(helper::to_std_atomic_const(ptr), + std::memory_order_relaxed); +} + +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { + return std::atomic_load_explicit(helper::to_std_atomic_const(ptr), + std::memory_order_acquire); +} + +inline Atomic64 SeqCst_Load(volatile const Atomic64* ptr) { + return std::atomic_load_explicit(helper::to_std_atomic_const(ptr), + std::memory_order_seq_cst); +} + +#endif // defined(V8_HOST_ARCH_64_BIT) + +inline void Relaxed_Memcpy(volatile Atomic8* dst, volatile const Atomic8* src, + size_t bytes) { + constexpr size_t kAtomicWordSize = sizeof(AtomicWord); + while (bytes > 0 && + !IsAligned(reinterpret_cast(dst), kAtomicWordSize)) { + Relaxed_Store(dst++, Relaxed_Load(src++)); + --bytes; + } + if (IsAligned(reinterpret_cast(src), kAtomicWordSize) && + IsAligned(reinterpret_cast(dst), kAtomicWordSize)) { + while (bytes >= kAtomicWordSize) { + Relaxed_Store( + reinterpret_cast(dst), + Relaxed_Load(reinterpret_cast(src))); + dst += kAtomicWordSize; + src += kAtomicWordSize; + bytes -= kAtomicWordSize; + } + } + while (bytes > 0) { + Relaxed_Store(dst++, Relaxed_Load(src++)); + --bytes; + } +} + +inline void Relaxed_Memmove(volatile Atomic8* dst, volatile const Atomic8* src, + size_t bytes) { + // Use Relaxed_Memcpy if copying forwards is safe. This is the case if there + // is no overlap, or {dst} lies before {src}. + // This single check checks for both: + if (reinterpret_cast(dst) - reinterpret_cast(src) >= + bytes) { + Relaxed_Memcpy(dst, src, bytes); + return; + } + + // Otherwise copy backwards. + dst += bytes; + src += bytes; + constexpr size_t kAtomicWordSize = sizeof(AtomicWord); + while (bytes > 0 && + !IsAligned(reinterpret_cast(dst), kAtomicWordSize)) { + Relaxed_Store(--dst, Relaxed_Load(--src)); + --bytes; + } + if (IsAligned(reinterpret_cast(src), kAtomicWordSize) && + IsAligned(reinterpret_cast(dst), kAtomicWordSize)) { + while (bytes >= kAtomicWordSize) { + dst -= kAtomicWordSize; + src -= kAtomicWordSize; + bytes -= kAtomicWordSize; + Relaxed_Store( + reinterpret_cast(dst), + Relaxed_Load(reinterpret_cast(src))); + } + } + while (bytes > 0) { + Relaxed_Store(--dst, Relaxed_Load(--src)); + --bytes; + } +} + +namespace helper { +inline int MemcmpNotEqualFundamental(Atomic8 u1, Atomic8 u2) { + DCHECK_NE(u1, u2); + return u1 < u2 ? -1 : 1; +} +inline int MemcmpNotEqualFundamental(AtomicWord u1, AtomicWord u2) { + DCHECK_NE(u1, u2); +#if defined(V8_TARGET_BIG_ENDIAN) + return u1 < u2 ? -1 : 1; #else -// TODO(ulan): Switch to std version after performance regression with Wheezy -// sysroot is no longer relevant. Debian Wheezy LTS ends on 31st of May 2018. -#include "src/base/atomicops_internals_portable.h" + for (size_t i = 0; i < sizeof(AtomicWord); ++i) { + uint8_t byte1 = u1 & 0xFF; + uint8_t byte2 = u2 & 0xFF; + if (byte1 != byte2) return byte1 < byte2 ? -1 : 1; + u1 >>= 8; + u2 >>= 8; + } + UNREACHABLE(); #endif +} +} // namespace helper -// On some platforms we need additional declarations to make -// AtomicWord compatible with our other Atomic* types. -#if defined(V8_OS_MACOSX) || defined(V8_OS_OPENBSD) || defined(V8_OS_AIX) -#include "src/base/atomicops_internals_atomicword_compat.h" -#endif +inline int Relaxed_Memcmp(volatile const Atomic8* s1, + volatile const Atomic8* s2, size_t len) { + constexpr size_t kAtomicWordSize = sizeof(AtomicWord); + while (len > 0 && + !(IsAligned(reinterpret_cast(s1), kAtomicWordSize) && + IsAligned(reinterpret_cast(s2), kAtomicWordSize))) { + Atomic8 u1 = Relaxed_Load(s1++); + Atomic8 u2 = Relaxed_Load(s2++); + if (u1 != u2) return helper::MemcmpNotEqualFundamental(u1, u2); + --len; + } + + if (IsAligned(reinterpret_cast(s1), kAtomicWordSize) && + IsAligned(reinterpret_cast(s2), kAtomicWordSize)) { + while (len >= kAtomicWordSize) { + AtomicWord u1 = + Relaxed_Load(reinterpret_cast(s1)); + AtomicWord u2 = + Relaxed_Load(reinterpret_cast(s2)); + if (u1 != u2) return helper::MemcmpNotEqualFundamental(u1, u2); + s1 += kAtomicWordSize; + s2 += kAtomicWordSize; + len -= kAtomicWordSize; + } + } + + while (len > 0) { + Atomic8 u1 = Relaxed_Load(s1++); + Atomic8 u2 = Relaxed_Load(s2++); + if (u1 != u2) return helper::MemcmpNotEqualFundamental(u1, u2); + --len; + } + + return 0; +} + +} // namespace base +} // namespace v8 #endif // V8_BASE_ATOMICOPS_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomicops_internals_portable.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomicops_internals_portable.h deleted file mode 100644 index 1f89f0a6b..000000000 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/atomicops_internals_portable.h +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is an internal atomic implementation, use atomicops.h instead. -// -// This implementation uses C++11 atomics' member functions. The code base is -// currently written assuming atomicity revolves around accesses instead of -// C++11's memory locations. The burden is on the programmer to ensure that all -// memory locations accessed atomically are never accessed non-atomically (tsan -// should help with this). -// -// Of note in this implementation: -// * All NoBarrier variants are implemented as relaxed. -// * All Barrier variants are implemented as sequentially-consistent. -// * Compare exchange's failure ordering is always the same as the success one -// (except for release, which fails as relaxed): using a weaker ordering is -// only valid under certain uses of compare exchange. -// * Acquire store doesn't exist in the C11 memory model, it is instead -// implemented as a relaxed store followed by a sequentially consistent -// fence. -// * Release load doesn't exist in the C11 memory model, it is instead -// implemented as sequentially consistent fence followed by a relaxed load. -// * Atomic increment is expected to return the post-incremented value, whereas -// C11 fetch add returns the previous value. The implementation therefore -// needs to increment twice (which the compiler should be able to detect and -// optimize). - -#ifndef V8_BASE_ATOMICOPS_INTERNALS_PORTABLE_H_ -#define V8_BASE_ATOMICOPS_INTERNALS_PORTABLE_H_ - -#include - -#include "src/base/build_config.h" -#include "src/base/macros.h" - -namespace v8 { -namespace base { - -// This implementation is transitional and maintains the original API for -// atomicops.h. - -inline void SeqCst_MemoryFence() { -#if defined(__GLIBCXX__) - // Work around libstdc++ bug 51038 where atomic_thread_fence was declared but - // not defined, leading to the linker complaining about undefined references. - __atomic_thread_fence(std::memory_order_seq_cst); -#else - std::atomic_thread_fence(std::memory_order_seq_cst); -#endif -} - -inline Atomic16 Relaxed_CompareAndSwap(volatile Atomic16* ptr, - Atomic16 old_value, Atomic16 new_value) { - __atomic_compare_exchange_n(ptr, &old_value, new_value, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); - return old_value; -} - -inline Atomic32 Relaxed_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, Atomic32 new_value) { - __atomic_compare_exchange_n(ptr, &old_value, new_value, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); - return old_value; -} - -inline Atomic32 Relaxed_AtomicExchange(volatile Atomic32* ptr, - Atomic32 new_value) { - return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED); -} - -inline Atomic32 Relaxed_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - return increment + __atomic_fetch_add(ptr, increment, __ATOMIC_RELAXED); -} - -inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, Atomic32 new_value) { - __atomic_compare_exchange_n(ptr, &old_value, new_value, false, - __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); - return old_value; -} - -inline Atomic8 Release_CompareAndSwap(volatile Atomic8* ptr, Atomic8 old_value, - Atomic8 new_value) { - bool result = __atomic_compare_exchange_n(ptr, &old_value, new_value, false, - __ATOMIC_RELEASE, __ATOMIC_RELAXED); - USE(result); // Make gcc compiler happy. - return old_value; -} - -inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, Atomic32 new_value) { - __atomic_compare_exchange_n(ptr, &old_value, new_value, false, - __ATOMIC_RELEASE, __ATOMIC_RELAXED); - return old_value; -} - -inline Atomic32 AcquireRelease_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - __atomic_compare_exchange_n(ptr, &old_value, new_value, false, - __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE); - return old_value; -} - -inline void Relaxed_Store(volatile Atomic8* ptr, Atomic8 value) { - __atomic_store_n(ptr, value, __ATOMIC_RELAXED); -} - -inline void Relaxed_Store(volatile Atomic16* ptr, Atomic16 value) { - __atomic_store_n(ptr, value, __ATOMIC_RELAXED); -} - -inline void Relaxed_Store(volatile Atomic32* ptr, Atomic32 value) { - __atomic_store_n(ptr, value, __ATOMIC_RELAXED); -} - -inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { - __atomic_store_n(ptr, value, __ATOMIC_RELEASE); -} - -inline Atomic8 Relaxed_Load(volatile const Atomic8* ptr) { - return __atomic_load_n(ptr, __ATOMIC_RELAXED); -} - -inline Atomic16 Relaxed_Load(volatile const Atomic16* ptr) { - return __atomic_load_n(ptr, __ATOMIC_RELAXED); -} - -inline Atomic32 Relaxed_Load(volatile const Atomic32* ptr) { - return __atomic_load_n(ptr, __ATOMIC_RELAXED); -} - -inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { - return __atomic_load_n(ptr, __ATOMIC_ACQUIRE); -} - -#if defined(V8_HOST_ARCH_64_BIT) - -inline Atomic64 Relaxed_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, Atomic64 new_value) { - __atomic_compare_exchange_n(ptr, &old_value, new_value, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); - return old_value; -} - -inline Atomic64 Relaxed_AtomicExchange(volatile Atomic64* ptr, - Atomic64 new_value) { - return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED); -} - -inline Atomic64 Relaxed_AtomicIncrement(volatile Atomic64* ptr, - Atomic64 increment) { - return increment + __atomic_fetch_add(ptr, increment, __ATOMIC_RELAXED); -} - -inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, Atomic64 new_value) { - __atomic_compare_exchange_n(ptr, &old_value, new_value, false, - __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); - return old_value; -} - -inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, Atomic64 new_value) { - __atomic_compare_exchange_n(ptr, &old_value, new_value, false, - __ATOMIC_RELEASE, __ATOMIC_RELAXED); - return old_value; -} - -inline Atomic64 AcquireRelease_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, - Atomic64 new_value) { - __atomic_compare_exchange_n(ptr, &old_value, new_value, false, - __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE); - return old_value; -} - -inline void Relaxed_Store(volatile Atomic64* ptr, Atomic64 value) { - __atomic_store_n(ptr, value, __ATOMIC_RELAXED); -} - -inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { - __atomic_store_n(ptr, value, __ATOMIC_RELEASE); -} - -inline Atomic64 Relaxed_Load(volatile const Atomic64* ptr) { - return __atomic_load_n(ptr, __ATOMIC_RELAXED); -} - -inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { - return __atomic_load_n(ptr, __ATOMIC_ACQUIRE); -} - -#endif // defined(V8_HOST_ARCH_64_BIT) -} // namespace base -} // namespace v8 - -#endif // V8_BASE_ATOMICOPS_INTERNALS_PORTABLE_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/bit-field.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/bit-field.h new file mode 100644 index 000000000..63142a20f --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/bit-field.h @@ -0,0 +1,157 @@ +// Copyright 2019 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_BIT_FIELD_H_ +#define V8_BASE_BIT_FIELD_H_ + +#include + +#include "src/base/macros.h" + +namespace v8 { +namespace base { + +// ---------------------------------------------------------------------------- +// BitField is a help template for encoding and decode bitfield with +// unsigned content. +// Instantiate them via 'using', which is cheaper than deriving a new class: +// using MyBitField = base::BitField; +// The BitField class is final to enforce this style over derivation. + +template +class BitField final { + public: + STATIC_ASSERT(std::is_unsigned::value); + STATIC_ASSERT(shift < 8 * sizeof(U)); // Otherwise shifts by {shift} are UB. + STATIC_ASSERT(size < 8 * sizeof(U)); // Otherwise shifts by {size} are UB. + STATIC_ASSERT(shift + size <= 8 * sizeof(U)); + STATIC_ASSERT(size > 0); + + using FieldType = T; + + // A type U mask of bit field. To use all bits of a type U of x bits + // in a bitfield without compiler warnings we have to compute 2^x + // without using a shift count of x in the computation. + static constexpr int kShift = shift; + static constexpr int kSize = size; + static constexpr U kMask = ((U{1} << kShift) << kSize) - (U{1} << kShift); + static constexpr int kLastUsedBit = kShift + kSize - 1; + static constexpr U kNumValues = U{1} << kSize; + + // Value for the field with all bits set. + static constexpr T kMax = static_cast(kNumValues - 1); + + template + using Next = BitField; + + // Tells whether the provided value fits into the bit field. + static constexpr bool is_valid(T value) { + return (static_cast(value) & ~static_cast(kMax)) == 0; + } + + // Returns a type U with the bit field value encoded. + static constexpr U encode(T value) { + DCHECK(is_valid(value)); + return static_cast(value) << kShift; + } + + // Returns a type U with the bit field value updated. + static constexpr U update(U previous, T value) { + return (previous & ~kMask) | encode(value); + } + + // Extracts the bit field from the value. + static constexpr T decode(U value) { + return static_cast((value & kMask) >> kShift); + } +}; + +template +using BitField8 = BitField; + +template +using BitField16 = BitField; + +template +using BitField64 = BitField; + +// Helper macros for defining a contiguous sequence of bit fields. Example: +// (backslashes at the ends of respective lines of this multi-line macro +// definition are omitted here to please the compiler) +// +// #define MAP_BIT_FIELD1(V, _) +// V(IsAbcBit, bool, 1, _) +// V(IsBcdBit, bool, 1, _) +// V(CdeBits, int, 5, _) +// V(DefBits, MutableMode, 1, _) +// +// DEFINE_BIT_FIELDS(MAP_BIT_FIELD1) +// or +// DEFINE_BIT_FIELDS_64(MAP_BIT_FIELD1) +// +#define DEFINE_BIT_FIELD_RANGE_TYPE(Name, Type, Size, _) \ + k##Name##Start, k##Name##End = k##Name##Start + Size - 1, + +#define DEFINE_BIT_RANGES(LIST_MACRO) \ + struct LIST_MACRO##_Ranges { \ + enum { LIST_MACRO(DEFINE_BIT_FIELD_RANGE_TYPE, _) kBitsCount }; \ + }; + +#define DEFINE_BIT_FIELD_TYPE(Name, Type, Size, RangesName) \ + using Name = base::BitField; + +#define DEFINE_BIT_FIELD_64_TYPE(Name, Type, Size, RangesName) \ + using Name = base::BitField64; + +#define DEFINE_BIT_FIELDS(LIST_MACRO) \ + DEFINE_BIT_RANGES(LIST_MACRO) \ + LIST_MACRO(DEFINE_BIT_FIELD_TYPE, LIST_MACRO##_Ranges) + +#define DEFINE_BIT_FIELDS_64(LIST_MACRO) \ + DEFINE_BIT_RANGES(LIST_MACRO) \ + LIST_MACRO(DEFINE_BIT_FIELD_64_TYPE, LIST_MACRO##_Ranges) + +// ---------------------------------------------------------------------------- +// BitSetComputer is a help template for encoding and decoding information for +// a variable number of items in an array. +// +// To encode boolean data in a smi array you would use: +// using BoolComputer = BitSetComputer; +// +template +class BitSetComputer { + public: + static const int kItemsPerWord = kBitsPerWord / kBitsPerItem; + static const int kMask = (1 << kBitsPerItem) - 1; + + // The number of array elements required to embed T information for each item. + static int word_count(int items) { + if (items == 0) return 0; + return (items - 1) / kItemsPerWord + 1; + } + + // The array index to look at for item. + static int index(int base_index, int item) { + return base_index + item / kItemsPerWord; + } + + // Extract T data for a given item from data. + static T decode(U data, int item) { + return static_cast((data >> shift(item)) & kMask); + } + + // Return the encoding for a store of value for item in previous. + static U encode(U previous, int item, T value) { + int shift_value = shift(item); + int set_bits = (static_cast(value) << shift_value); + return (previous & ~(kMask << shift_value)) | set_bits; + } + + static int shift(int item) { return (item % kItemsPerWord) * kBitsPerItem; } +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_BIT_FIELD_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/bits-iterator.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/bits-iterator.h new file mode 100644 index 000000000..6ce656e6d --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/bits-iterator.h @@ -0,0 +1,58 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_BITS_ITERATOR_H_ +#define V8_BASE_BITS_ITERATOR_H_ + +#include + +#include "src/base/bits.h" +#include "src/base/iterator.h" + +namespace v8 { +namespace base { +namespace bits { + +template +class BitsIterator : public iterator { + STATIC_ASSERT(std::is_integral::value); + + public: + explicit BitsIterator(T bits) : bits_(bits) {} + + int operator*() const { + return kMSBFirst ? 8 * sizeof(T) - 1 - CountLeadingZeros(bits_) + : CountTrailingZeros(bits_); + } + + BitsIterator& operator++() { + bits_ &= ~(T{1} << **this); + return *this; + } + + bool operator==(BitsIterator other) { return bits_ == other.bits_; } + bool operator!=(BitsIterator other) { return bits_ != other.bits_; } + + private: + T bits_; +}; + +// Returns an iterable over the bits in {bits}, from LSB to MSB. +template +auto IterateBits(T bits) { + return make_iterator_range(BitsIterator{bits}, BitsIterator{0}); +} + +// Returns an iterable over the bits in {bits}, from MSB to LSB. +template +auto IterateBitsBackwards(T bits) { + return make_iterator_range(BitsIterator{bits}, + BitsIterator{0}); +} + +} // namespace bits +} // namespace base +} // namespace v8 + +#endif // V8_BASE_BITS_ITERATOR_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/bits.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/bits.h index b74b98e10..9fe237fb3 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/bits.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/bits.h @@ -32,22 +32,27 @@ constexpr inline return sizeof(T) == 8 ? __builtin_popcountll(static_cast(value)) : __builtin_popcount(static_cast(value)); #else + // Fall back to divide-and-conquer popcount (see "Hacker's Delight" by Henry + // S. Warren, Jr.), chapter 5-1. constexpr uint64_t mask[] = {0x5555555555555555, 0x3333333333333333, 0x0f0f0f0f0f0f0f0f}; - // Start with 1 bit wide buckets of [0,1]. + // Start with 64 buckets of 1 bits, holding values from [0,1]. value = ((value >> 1) & mask[0]) + (value & mask[0]); - // Having 2 bit wide buckets of [0,2] now. + // Having 32 buckets of 2 bits, holding values from [0,2] now. value = ((value >> 2) & mask[1]) + (value & mask[1]); - // Having 4 bit wide buckets of [0,4] now. - value = (value >> 4) + value; - // Having 4 bit wide buckets of [0,8] now. - if (sizeof(T) > 1) - value = ((value >> (sizeof(T) > 1 ? 8 : 0)) & mask[2]) + (value & mask[2]); - // Having 8 bit wide buckets of [0,16] now. + // Having 16 buckets of 4 bits, holding values from [0,4] now. + value = ((value >> 4) & mask[2]) + (value & mask[2]); + // Having 8 buckets of 8 bits, holding values from [0,8] now. + // From this point on, the buckets are bigger than the number of bits + // required to hold the values, and the buckets are bigger the maximum + // result, so there's no need to mask value anymore, since there's no + // more risk of overflow between buckets. + if (sizeof(T) > 1) value = (value >> (sizeof(T) > 1 ? 8 : 0)) + value; + // Having 4 buckets of 16 bits, holding values from [0,16] now. if (sizeof(T) > 2) value = (value >> (sizeof(T) > 2 ? 16 : 0)) + value; - // Having 8 bit wide buckets of [0,32] now. + // Having 2 buckets of 32 bits, holding values from [0,32] now. if (sizeof(T) > 4) value = (value >> (sizeof(T) > 4 ? 32 : 0)) + value; - // Having 8 bit wide buckets of [0,64] now. + // Having 1 buckets of 64 bits, holding values from [0,64] now. return static_cast(value & 0xff); #endif } @@ -102,6 +107,8 @@ inline constexpr unsigned CountLeadingZeros64(uint64_t value) { // CountTrailingZeros(value) returns the number of zero bits preceding the // least significant 1 bit in |value| if |value| is non-zero, otherwise it // returns {sizeof(T) * 8}. +// See CountTrailingZerosNonZero for an optimized version for the case that +// |value| is guaranteed to be non-zero. template inline constexpr typename std::enable_if::value && sizeof(T) <= 8, @@ -128,6 +135,24 @@ inline constexpr unsigned CountTrailingZeros64(uint64_t value) { return CountTrailingZeros(value); } +// CountTrailingZerosNonZero(value) returns the number of zero bits preceding +// the least significant 1 bit in |value| if |value| is non-zero, otherwise the +// behavior is undefined. +// See CountTrailingZeros for an alternative version that allows |value| == 0. +template +inline constexpr + typename std::enable_if::value && sizeof(T) <= 8, + unsigned>::type + CountTrailingZerosNonZero(T value) { + DCHECK_NE(0, value); +#if V8_HAS_BUILTIN_CTZ + return bits == 64 ? __builtin_ctzll(static_cast(value)) + : __builtin_ctz(static_cast(value)); +#else + return CountTrailingZeros(value); +#endif +} + // Returns true iff |value| is a power of 2. template ::value || @@ -140,9 +165,7 @@ constexpr inline bool IsPowerOfTwo(T value) { template ::value>::type> inline constexpr int WhichPowerOfTwo(T value) { -#if V8_HAS_CXX14_CONSTEXPR DCHECK(IsPowerOfTwo(value)); -#endif #if V8_HAS_BUILTIN_CTZ STATIC_ASSERT(sizeof(T) <= 8); return sizeof(T) == 8 ? __builtin_ctzll(static_cast(value)) @@ -171,7 +194,9 @@ inline size_t RoundUpToPowerOfTwo(size_t value) { if (sizeof(size_t) == sizeof(uint64_t)) { return RoundUpToPowerOfTwo64(value); } else { - return RoundUpToPowerOfTwo32(value); + // Without windows.h included this line triggers a truncation warning on + // 64-bit builds. Presumably windows.h disables the relevant warning. + return RoundUpToPowerOfTwo32(static_cast(value)); } } @@ -304,6 +329,16 @@ inline uint32_t UnsignedMod32(uint32_t lhs, uint32_t rhs) { return rhs ? lhs % rhs : 0u; } +// Wraparound integer arithmetic without undefined behavior. + +inline int32_t WraparoundAdd32(int32_t lhs, int32_t rhs) { + return static_cast(static_cast(lhs) + + static_cast(rhs)); +} + +inline int32_t WraparoundNeg32(int32_t x) { + return static_cast(-static_cast(x)); +} // SignedSaturatedAdd64(lhs, rhs) adds |lhs| and |rhs|, // checks and returns the result. diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/bounded-page-allocator.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/bounded-page-allocator.h new file mode 100644 index 000000000..ade9aa2d3 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/bounded-page-allocator.h @@ -0,0 +1,100 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_BOUNDED_PAGE_ALLOCATOR_H_ +#define V8_BASE_BOUNDED_PAGE_ALLOCATOR_H_ + +#include "include/v8-platform.h" +#include "src/base/platform/mutex.h" +#include "src/base/region-allocator.h" + +namespace v8 { +namespace base { + +// Defines the page initialization mode of a BoundedPageAllocator. +enum class PageInitializationMode { + // The contents of allocated pages must be zero initialized. This causes any + // committed pages to be decommitted during FreePages and ReleasePages. + kAllocatedPagesMustBeZeroInitialized, + // Allocated pages do not have to be be zero initialized and can contain old + // data. This is slightly faster as comitted pages are not decommitted + // during FreePages and ReleasePages, but only made inaccessible. + kAllocatedPagesCanBeUninitialized, +}; + +// This is a v8::PageAllocator implementation that allocates pages within the +// pre-reserved region of virtual space. This class requires the virtual space +// to be kept reserved during the lifetime of this object. +// The main application of bounded page allocator are +// - V8 heap pointer compression which requires the whole V8 heap to be +// allocated within a contiguous range of virtual address space, +// - executable page allocation, which allows to use PC-relative 32-bit code +// displacement on certain 64-bit platforms. +// Bounded page allocator uses other page allocator instance for doing actual +// page allocations. +// The implementation is thread-safe. +class V8_BASE_EXPORT BoundedPageAllocator : public v8::PageAllocator { + public: + using Address = uintptr_t; + + BoundedPageAllocator(v8::PageAllocator* page_allocator, Address start, + size_t size, size_t allocate_page_size, + PageInitializationMode page_initialization_mode); + BoundedPageAllocator(const BoundedPageAllocator&) = delete; + BoundedPageAllocator& operator=(const BoundedPageAllocator&) = delete; + ~BoundedPageAllocator() override = default; + + // These functions are not inlined to avoid https://crbug.com/v8/8275. + Address begin() const; + size_t size() const; + + // Returns true if given address is in the range controlled by the bounded + // page allocator instance. + bool contains(Address address) const { + return region_allocator_.contains(address); + } + + size_t AllocatePageSize() override { return allocate_page_size_; } + + size_t CommitPageSize() override { return commit_page_size_; } + + void SetRandomMmapSeed(int64_t seed) override { + page_allocator_->SetRandomMmapSeed(seed); + } + + void* GetRandomMmapAddr() override { + return page_allocator_->GetRandomMmapAddr(); + } + + void* AllocatePages(void* hint, size_t size, size_t alignment, + Permission access) override; + + bool ReserveForSharedMemoryMapping(void* address, size_t size) override; + + // Allocates pages at given address, returns true on success. + bool AllocatePagesAt(Address address, size_t size, Permission access); + + bool FreePages(void* address, size_t size) override; + + bool ReleasePages(void* address, size_t size, size_t new_size) override; + + bool SetPermissions(void* address, size_t size, Permission access) override; + + bool DiscardSystemPages(void* address, size_t size) override; + + bool DecommitPages(void* address, size_t size) override; + + private: + v8::base::Mutex mutex_; + const size_t allocate_page_size_; + const size_t commit_page_size_; + v8::PageAllocator* const page_allocator_; + v8::base::RegionAllocator region_allocator_; + const PageInitializationMode page_initialization_mode_; +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_BOUNDED_PAGE_ALLOCATOR_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/bounds.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/bounds.h new file mode 100644 index 000000000..0fe141b30 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/bounds.h @@ -0,0 +1,54 @@ +// Copyright 2019 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_BOUNDS_H_ +#define V8_BASE_BOUNDS_H_ + +#include "include/v8config.h" +#include "src/base/macros.h" + +namespace v8 { +namespace base { + +// Checks if value is in range [lower_limit, higher_limit] using a single +// branch. +template +inline constexpr bool IsInRange(T value, U lower_limit, U higher_limit) { + DCHECK_LE(lower_limit, higher_limit); + STATIC_ASSERT(sizeof(U) <= sizeof(T)); + using unsigned_T = typename std::make_unsigned::type; + // Use static_cast to support enum classes. + return static_cast(static_cast(value) - + static_cast(lower_limit)) <= + static_cast(static_cast(higher_limit) - + static_cast(lower_limit)); +} + +// Checks if [index, index+length) is in range [0, max). Note that this check +// works even if {index+length} would wrap around. +template ::value>::type> +inline constexpr bool IsInBounds(T index, T length, T max) { + return length <= max && index <= (max - length); +} + +// Checks if [index, index+length) is in range [0, max). If not, {length} is +// clamped to its valid range. Note that this check works even if +// {index+length} would wrap around. +template +inline bool ClampToBounds(T index, T* length, T max) { + if (index > max) { + *length = 0; + return false; + } + T avail = max - index; + bool oob = *length > avail; + if (oob) *length = avail; + return !oob; +} + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_BOUNDS_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/build_config.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/build_config.h index 8d142c456..3befde51e 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/build_config.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/build_config.h @@ -33,6 +33,9 @@ #elif defined(__MIPSEB__) || defined(__MIPSEL__) #define V8_HOST_ARCH_MIPS 1 #define V8_HOST_ARCH_32_BIT 1 +#elif defined(__loongarch64) +#define V8_HOST_ARCH_LOONG64 1 +#define V8_HOST_ARCH_64_BIT 1 #elif defined(__PPC64__) || defined(_ARCH_PPC64) #define V8_HOST_ARCH_PPC64 1 #define V8_HOST_ARCH_64_BIT 1 @@ -46,38 +49,44 @@ #else #define V8_HOST_ARCH_32_BIT 1 #endif +#elif defined(__riscv) || defined(__riscv__) +#if __riscv_xlen == 64 +#define V8_HOST_ARCH_RISCV64 1 +#define V8_HOST_ARCH_64_BIT 1 +#else +#error "Cannot detect Riscv's bitwidth" +#endif #else #error "Host architecture was not detected as supported by v8" #endif -#if defined(__ARM_ARCH_7A__) || \ - defined(__ARM_ARCH_7R__) || \ +#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \ defined(__ARM_ARCH_7__) -# define CAN_USE_ARMV7_INSTRUCTIONS 1 +#define CAN_USE_ARMV7_INSTRUCTIONS 1 #ifdef __ARM_ARCH_EXT_IDIV__ #define CAN_USE_SUDIV 1 #endif -# ifndef CAN_USE_VFP3_INSTRUCTIONS +#ifndef CAN_USE_VFP3_INSTRUCTIONS #define CAN_USE_VFP3_INSTRUCTIONS 1 -# endif +#endif #endif #if defined(__ARM_ARCH_8A__) #define CAN_USE_ARMV7_INSTRUCTIONS 1 #define CAN_USE_SUDIV 1 -# define CAN_USE_ARMV8_INSTRUCTIONS 1 +#define CAN_USE_ARMV8_INSTRUCTIONS 1 #ifndef CAN_USE_VFP3_INSTRUCTIONS #define CAN_USE_VFP3_INSTRUCTIONS 1 #endif #endif - // Target architecture detection. This may be set externally. If not, detect // in the same way as the host architecture, that is, target the native // environment as presented by the compiler. #if !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM && \ !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_MIPS && !V8_TARGET_ARCH_MIPS64 && \ - !V8_TARGET_ARCH_PPC && !V8_TARGET_ARCH_PPC64 && !V8_TARGET_ARCH_S390 + !V8_TARGET_ARCH_PPC && !V8_TARGET_ARCH_PPC64 && !V8_TARGET_ARCH_S390 && \ + !V8_TARGET_ARCH_RISCV64 && !V8_TARGET_ARCH_LOONG64 #if defined(_M_X64) || defined(__x86_64__) #define V8_TARGET_ARCH_X64 1 #elif defined(_M_IX86) || defined(__i386__) @@ -94,6 +103,10 @@ #define V8_TARGET_ARCH_PPC64 1 #elif defined(_ARCH_PPC) #define V8_TARGET_ARCH_PPC 1 +#elif defined(__riscv) || defined(__riscv__) +#if __riscv_xlen == 64 +#define V8_TARGET_ARCH_RISCV64 1 +#endif #else #error Target architecture was not detected as supported by v8 #endif @@ -118,6 +131,8 @@ #define V8_TARGET_ARCH_32_BIT 1 #elif V8_TARGET_ARCH_MIPS64 #define V8_TARGET_ARCH_64_BIT 1 +#elif V8_TARGET_ARCH_LOONG64 +#define V8_TARGET_ARCH_64_BIT 1 #elif V8_TARGET_ARCH_PPC #define V8_TARGET_ARCH_32_BIT 1 #elif V8_TARGET_ARCH_PPC64 @@ -128,6 +143,8 @@ #else #define V8_TARGET_ARCH_32_BIT 1 #endif +#elif V8_TARGET_ARCH_RISCV64 +#define V8_TARGET_ARCH_64_BIT 1 #else #error Unknown target architecture pointer size #endif @@ -137,8 +154,8 @@ #error Target architecture ia32 is only supported on ia32 host #endif #if (V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_64_BIT && \ - !(V8_HOST_ARCH_X64 && V8_HOST_ARCH_64_BIT)) -#error Target architecture x64 is only supported on x64 host + !((V8_HOST_ARCH_X64 || V8_HOST_ARCH_ARM64) && V8_HOST_ARCH_64_BIT)) +#error Target architecture x64 is only supported on x64 and arm64 host #endif #if (V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT && \ !(V8_HOST_ARCH_X64 && V8_HOST_ARCH_32_BIT)) @@ -156,6 +173,12 @@ #if (V8_TARGET_ARCH_MIPS64 && !(V8_HOST_ARCH_X64 || V8_HOST_ARCH_MIPS64)) #error Target architecture mips64 is only supported on mips64 and x64 host #endif +#if (V8_TARGET_ARCH_RISCV64 && !(V8_HOST_ARCH_X64 || V8_HOST_ARCH_RISCV64)) +#error Target architecture riscv64 is only supported on riscv64 and x64 host +#endif +#if (V8_TARGET_ARCH_LOONG64 && !(V8_HOST_ARCH_X64 || V8_HOST_ARCH_LOONG64)) +#error Target architecture loong64 is only supported on loong64 and x64 host +#endif // Determine architecture endianness. #if V8_TARGET_ARCH_IA32 @@ -166,6 +189,8 @@ #define V8_TARGET_LITTLE_ENDIAN 1 #elif V8_TARGET_ARCH_ARM64 #define V8_TARGET_LITTLE_ENDIAN 1 +#elif V8_TARGET_ARCH_LOONG64 +#define V8_TARGET_LITTLE_ENDIAN 1 #elif V8_TARGET_ARCH_MIPS #if defined(__MIPSEB__) #define V8_TARGET_BIG_ENDIAN 1 @@ -190,21 +215,43 @@ #else #define V8_TARGET_BIG_ENDIAN 1 #endif +#elif V8_TARGET_ARCH_RISCV64 +#define V8_TARGET_LITTLE_ENDIAN 1 #else #error Unknown target architecture endianness #endif +// pthread_jit_write_protect is only available on arm64 Mac. +#if defined(V8_OS_MACOS) && defined(V8_HOST_ARCH_ARM64) +#define V8_HAS_PTHREAD_JIT_WRITE_PROTECT 1 +#else +#define V8_HAS_PTHREAD_JIT_WRITE_PROTECT 0 +#endif + #if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X64) #define V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK true #else #define V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK false #endif +constexpr int kReturnAddressStackSlotCount = + V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK ? 1 : 0; // Number of bits to represent the page size for paged spaces. -#if defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_PPC64) -// PPC has large (64KB) physical pages. +#if (defined(V8_HOST_ARCH_PPC) || defined(V8_HOST_ARCH_PPC64)) && !defined(_AIX) +// Native PPC linux has large (64KB) physical pages. +// Simulator (and Aix) need to use the same value as x64. const int kPageSizeBits = 19; +#elif defined(ENABLE_HUGEPAGE) +// When enabling huge pages, adjust V8 page size to take up exactly one huge +// page. This avoids huge-page-internal fragmentation for unused address ranges. +const int kHugePageBits = 21; +const int kHugePageSize = (1U) << kHugePageBits; +const int kPageSizeBits = kHugePageBits; #else +// Arm64 supports up to 64k OS pages on Linux, however 4k pages are more common +// so we keep the V8 page size at 256k. Nonetheless, we need to make sure we +// don't decrease it further in the future due to reserving 3 OS pages for every +// executable V8 page. const int kPageSizeBits = 18; #endif diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/compiler-specific.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/compiler-specific.h index 5d68f7e11..0c37e56af 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/compiler-specific.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/compiler-specific.h @@ -7,13 +7,15 @@ #include "include/v8config.h" -// Annotate a using ALLOW_UNUSED_TYPE = or function indicating it's ok if it's -// not used. Use like: -// using Bar = Foo; +// Annotation to silence compiler warnings about unused +// types/functions/variables. Use like: +// +// using V8_ALLOW_UNUSED Bar = Foo; +// V8_ALLOW_UNUSED void foo() {} #if V8_HAS_ATTRIBUTE_UNUSED -#define ALLOW_UNUSED_TYPE __attribute__((unused)) +#define V8_ALLOW_UNUSED __attribute__((unused)) #else -#define ALLOW_UNUSED_TYPE +#define V8_ALLOW_UNUSED #endif // Tell the compiler a function is using a printf-style format string. @@ -98,11 +100,39 @@ // there. #if ((!defined(V8_CC_GNU) && !defined(V8_CC_MSVC) && \ !defined(V8_TARGET_ARCH_MIPS) && !defined(V8_TARGET_ARCH_MIPS64) && \ - !defined(V8_TARGET_ARCH_PPC) && !defined(V8_TARGET_ARCH_PPC64)) || \ + !defined(V8_TARGET_ARCH_PPC) && !defined(V8_TARGET_ARCH_PPC64) && \ + !defined(V8_TARGET_ARCH_RISCV64)) || \ (defined(__clang__) && __cplusplus > 201300L)) #define V8_NOEXCEPT noexcept #else #define V8_NOEXCEPT #endif +// Specify memory alignment for structs, classes, etc. +// Use like: +// class ALIGNAS(16) MyClass { ... } +// ALIGNAS(16) int array[4]; +// +// In most places you can use the C++11 keyword "alignas", which is preferred. +// +// But compilers have trouble mixing __attribute__((...)) syntax with +// alignas(...) syntax. +// +// Doesn't work in clang or gcc: +// struct alignas(16) __attribute__((packed)) S { char c; }; +// Works in clang but not gcc: +// struct __attribute__((packed)) alignas(16) S2 { char c; }; +// Works in clang and gcc: +// struct alignas(16) S3 { char c; } __attribute__((packed)); +// +// There are also some attributes that must be specified *before* a class +// definition: visibility (used for exporting functions/classes) is one of +// these attributes. This means that it is not possible to use alignas() with a +// class that is marked as exported. +#if defined(V8_CC_MSVC) +#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment)) +#else +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#endif + #endif // V8_BASE_COMPILER_SPECIFIC_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/cpu.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/cpu.h new file mode 100644 index 000000000..3050f2c46 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/cpu.h @@ -0,0 +1,189 @@ +// Copyright 2006-2013 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This module contains the architecture-specific code. This make the rest of +// the code less dependent on differences between different processor +// architecture. +// The classes have the same definition for all architectures. The +// implementation for a particular architecture is put in cpu_.cc. +// The build system then uses the implementation for the target architecture. +// + +#ifndef V8_BASE_CPU_H_ +#define V8_BASE_CPU_H_ + +#include "src/base/base-export.h" +#include "src/base/macros.h" + +namespace v8 { +namespace base { + +// ---------------------------------------------------------------------------- +// CPU +// +// Query information about the processor. +// +// This class also has static methods for the architecture specific functions. +// Add methods here to cope with differences between the supported +// architectures. For each architecture the file cpu_.cc contains the +// implementation of these static functions. + +class V8_BASE_EXPORT CPU final { + public: + CPU(); + + // x86 CPUID information + const char* vendor() const { return vendor_; } + int stepping() const { return stepping_; } + int model() const { return model_; } + int ext_model() const { return ext_model_; } + int family() const { return family_; } + int ext_family() const { return ext_family_; } + int type() const { return type_; } + + // arm implementer/part information + int implementer() const { return implementer_; } + static const int kArm = 0x41; + static const int kNvidia = 0x4e; + static const int kQualcomm = 0x51; + int architecture() const { return architecture_; } + int variant() const { return variant_; } + static const int kNvidiaDenver = 0x0; + int part() const { return part_; } + + // ARM-specific part codes + static const int kArmCortexA5 = 0xc05; + static const int kArmCortexA7 = 0xc07; + static const int kArmCortexA8 = 0xc08; + static const int kArmCortexA9 = 0xc09; + static const int kArmCortexA12 = 0xc0c; + static const int kArmCortexA15 = 0xc0f; + + // Denver-specific part code + static const int kNvidiaDenverV10 = 0x002; + + // PPC-specific part codes + enum { + kPPCPower5, + kPPCPower6, + kPPCPower7, + kPPCPower8, + kPPCPower9, + kPPCPower10, + kPPCG4, + kPPCG5, + kPPCPA6T + }; + + // General features + bool has_fpu() const { return has_fpu_; } + int icache_line_size() const { return icache_line_size_; } + int dcache_line_size() const { return dcache_line_size_; } + static const int kUnknownCacheLineSize = 0; + + // x86 features + bool has_cmov() const { return has_cmov_; } + bool has_sahf() const { return has_sahf_; } + bool has_mmx() const { return has_mmx_; } + bool has_sse() const { return has_sse_; } + bool has_sse2() const { return has_sse2_; } + bool has_sse3() const { return has_sse3_; } + bool has_ssse3() const { return has_ssse3_; } + bool has_sse41() const { return has_sse41_; } + bool has_sse42() const { return has_sse42_; } + bool has_osxsave() const { return has_osxsave_; } + bool has_avx() const { return has_avx_; } + bool has_avx2() const { return has_avx2_; } + bool has_fma3() const { return has_fma3_; } + bool has_bmi1() const { return has_bmi1_; } + bool has_bmi2() const { return has_bmi2_; } + bool has_lzcnt() const { return has_lzcnt_; } + bool has_popcnt() const { return has_popcnt_; } + bool is_atom() const { return is_atom_; } + bool has_cetss() const { return has_cetss_; } + bool has_non_stop_time_stamp_counter() const { + return has_non_stop_time_stamp_counter_; + } + bool is_running_in_vm() const { return is_running_in_vm_; } + bool exposes_num_virtual_address_bits() const { + return num_virtual_address_bits_ != kUnknownNumVirtualAddressBits; + } + int num_virtual_address_bits() const { + DCHECK(exposes_num_virtual_address_bits()); + return num_virtual_address_bits_; + } + static const int kUnknownNumVirtualAddressBits = 0; + + // arm features + bool has_idiva() const { return has_idiva_; } + bool has_neon() const { return has_neon_; } + bool has_thumb2() const { return has_thumb2_; } + bool has_vfp() const { return has_vfp_; } + bool has_vfp3() const { return has_vfp3_; } + bool has_vfp3_d32() const { return has_vfp3_d32_; } + bool has_jscvt() const { return has_jscvt_; } + + // mips features + bool is_fp64_mode() const { return is_fp64_mode_; } + bool has_msa() const { return has_msa_; } + + // riscv features + bool has_rvv() const { return has_rvv_; } + + private: +#if defined(V8_OS_STARBOARD) + bool StarboardDetectCPU(); +#endif + char vendor_[13]; + int stepping_; + int model_; + int ext_model_; + int family_; + int ext_family_; + int type_; + int implementer_; + int architecture_; + int variant_; + int part_; + int icache_line_size_; + int dcache_line_size_; + int num_virtual_address_bits_; + bool has_fpu_; + bool has_cmov_; + bool has_sahf_; + bool has_mmx_; + bool has_sse_; + bool has_sse2_; + bool has_sse3_; + bool has_ssse3_; + bool has_sse41_; + bool has_sse42_; + bool is_atom_; + bool has_cetss_; + bool has_osxsave_; + bool has_avx_; + bool has_avx2_; + bool has_fma3_; + bool has_bmi1_; + bool has_bmi2_; + bool has_lzcnt_; + bool has_popcnt_; + bool has_idiva_; + bool has_neon_; + bool has_thumb2_; + bool has_vfp_; + bool has_vfp3_; + bool has_vfp3_d32_; + bool has_jscvt_; + bool is_fp64_mode_; + bool has_non_stop_time_stamp_counter_; + bool is_running_in_vm_; + bool has_msa_; + bool has_rvv_; +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_CPU_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/division-by-constant.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/division-by-constant.h new file mode 100644 index 000000000..744283981 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/division-by-constant.h @@ -0,0 +1,71 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_DIVISION_BY_CONSTANT_H_ +#define V8_BASE_DIVISION_BY_CONSTANT_H_ + +#include + +#include "src/base/base-export.h" +#include "src/base/export-template.h" + +namespace v8 { +namespace base { + +// ---------------------------------------------------------------------------- + +// The magic numbers for division via multiplication, see Warren's "Hacker's +// Delight", chapter 10. The template parameter must be one of the unsigned +// integral types. +template +struct EXPORT_TEMPLATE_DECLARE(V8_BASE_EXPORT) MagicNumbersForDivision { + MagicNumbersForDivision(T m, unsigned s, bool a) + : multiplier(m), shift(s), add(a) {} + bool operator==(const MagicNumbersForDivision& rhs) const { + return multiplier == rhs.multiplier && shift == rhs.shift && add == rhs.add; + } + + T multiplier; + unsigned shift; + bool add; +}; + + +// Calculate the multiplier and shift for signed division via multiplication. +// The divisor must not be -1, 0 or 1 when interpreted as a signed value. +template +EXPORT_TEMPLATE_DECLARE(V8_BASE_EXPORT) +MagicNumbersForDivision SignedDivisionByConstant(T d); + +// Calculate the multiplier and shift for unsigned division via multiplication, +// see Warren's "Hacker's Delight", chapter 10. The divisor must not be 0 and +// leading_zeros can be used to speed up the calculation if the given number of +// upper bits of the dividend value are known to be zero. +template +EXPORT_TEMPLATE_DECLARE(V8_BASE_EXPORT) +MagicNumbersForDivision UnsignedDivisionByConstant( + T d, unsigned leading_zeros = 0); + +// Explicit instantiation declarations. +extern template struct EXPORT_TEMPLATE_DECLARE(V8_BASE_EXPORT) + MagicNumbersForDivision; +extern template struct EXPORT_TEMPLATE_DECLARE(V8_BASE_EXPORT) + MagicNumbersForDivision; + +extern template EXPORT_TEMPLATE_DECLARE(V8_BASE_EXPORT) + MagicNumbersForDivision SignedDivisionByConstant(uint32_t d); +extern template EXPORT_TEMPLATE_DECLARE(V8_BASE_EXPORT) + MagicNumbersForDivision SignedDivisionByConstant(uint64_t d); + +extern template EXPORT_TEMPLATE_DECLARE(V8_BASE_EXPORT) + MagicNumbersForDivision UnsignedDivisionByConstant( + uint32_t d, unsigned leading_zeros); +extern template EXPORT_TEMPLATE_DECLARE(V8_BASE_EXPORT) + MagicNumbersForDivision UnsignedDivisionByConstant( + uint64_t d, unsigned leading_zeros); + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_DIVISION_BY_CONSTANT_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/emulated-virtual-address-subspace.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/emulated-virtual-address-subspace.h new file mode 100644 index 000000000..c50783555 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/emulated-virtual-address-subspace.h @@ -0,0 +1,131 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_EMULATED_VIRTUAL_ADDRESS_SUBSPACE_H_ +#define V8_BASE_EMULATED_VIRTUAL_ADDRESS_SUBSPACE_H_ + +#include "include/v8-platform.h" +#include "src/base/base-export.h" +#include "src/base/compiler-specific.h" +#include "src/base/platform/mutex.h" +#include "src/base/region-allocator.h" +#include "src/base/virtual-address-space.h" + +namespace v8 { +namespace base { + +/** + * Emulates a virtual address subspace. + * + * This class is (optionally) backed by a page allocation and emulates a virtual + * address space that is potentially larger than that mapping. It generally + * first attempts to satisfy page allocation requests from its backing mapping, + * but will also attempt to obtain new page mappings inside the unmapped space + * through page allocation hints if necessary. + * + * Caveat: an emulated subspace violates the invariant that page allocations in + * an address space will never end up inside a child space and so does not + * provide the same security gurarantees. + */ +class V8_BASE_EXPORT EmulatedVirtualAddressSubspace final + : public NON_EXPORTED_BASE(::v8::VirtualAddressSpace) { + public: + // Construct an emulated virtual address subspace of the specified total size, + // potentially backed by a page allocation from the parent space. The newly + // created instance takes ownership of the page allocation (if any) and frees + // it during destruction. + EmulatedVirtualAddressSubspace(v8::VirtualAddressSpace* parent_space, + Address base, size_t mapped_size, + size_t total_size); + + ~EmulatedVirtualAddressSubspace() override; + + void SetRandomSeed(int64_t seed) override; + + Address RandomPageAddress() override; + + Address AllocatePages(Address hint, size_t size, size_t alignment, + PagePermissions permissions) override; + + void FreePages(Address address, size_t size) override; + + Address AllocateSharedPages(Address hint, size_t size, + PagePermissions permissions, + PlatformSharedMemoryHandle handle, + uint64_t offset) override; + + void FreeSharedPages(Address address, size_t size) override; + + bool SetPagePermissions(Address address, size_t size, + PagePermissions permissions) override; + + bool AllocateGuardRegion(Address address, size_t size) override; + + void FreeGuardRegion(Address address, size_t size) override; + + bool CanAllocateSubspaces() override; + + std::unique_ptr AllocateSubspace( + Address hint, size_t size, size_t alignment, + PagePermissions max_page_permissions) override; + + bool DiscardSystemPages(Address address, size_t size) override; + + bool DecommitPages(Address address, size_t size) override; + + private: + size_t mapped_size() const { return mapped_size_; } + size_t unmapped_size() const { return size() - mapped_size_; } + + Address mapped_base() const { return base(); } + Address unmapped_base() const { return base() + mapped_size_; } + + bool Contains(Address outer_start, size_t outer_size, Address inner_start, + size_t inner_size) const { + return (inner_start >= outer_start) && + ((inner_start + inner_size) <= (outer_start + outer_size)); + } + + bool Contains(Address addr, size_t length) const { + return Contains(base(), size(), addr, length); + } + + bool MappedRegionContains(Address addr, size_t length) const { + return Contains(mapped_base(), mapped_size(), addr, length); + } + + bool UnmappedRegionContains(Address addr, size_t length) const { + return Contains(unmapped_base(), unmapped_size(), addr, length); + } + + // Helper function to define a limit for the size of allocations in the + // unmapped region. This limit makes it possible to estimate the expected + // runtime of some loops in the Allocate methods. + bool IsUsableSizeForUnmappedRegion(size_t size) const { + return size <= (unmapped_size() / 2); + } + + // Size of the mapped region located at the beginning of this address space. + const size_t mapped_size_; + + // Pointer to the parent space from which the backing pages were allocated. + // Must be kept alive by the owner of this instance. + v8::VirtualAddressSpace* parent_space_; + + // Mutex guarding the non-threadsafe RegionAllocator and + // RandomNumberGenerator. + Mutex mutex_; + + // RegionAllocator to manage the page allocation and divide it into further + // regions as necessary. + RegionAllocator region_allocator_; + + // Random number generator for generating random addresses. + RandomNumberGenerator rng_; +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_EMULATED_VIRTUAL_ADDRESS_SUBSPACE_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/enum-set.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/enum-set.h new file mode 100644 index 000000000..ce49b3996 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/enum-set.h @@ -0,0 +1,92 @@ +// Copyright 2019 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_ENUM_SET_H_ +#define V8_BASE_ENUM_SET_H_ + +#include + +#include "src/base/logging.h" + +namespace v8 { +namespace base { + +// A poor man's version of STL's bitset: A bit set of enums E (without explicit +// values), fitting into an integral type T. +template +class EnumSet { + static_assert(std::is_enum::value, "EnumSet can only be used with enums"); + + public: + constexpr EnumSet() = default; + + explicit constexpr EnumSet(std::initializer_list init) { + T bits = 0; + for (E e : init) bits |= Mask(e); + bits_ = bits; + } + + constexpr bool empty() const { return bits_ == 0; } + constexpr bool contains(E element) const { + return (bits_ & Mask(element)) != 0; + } + constexpr bool contains_any(EnumSet set) const { + return (bits_ & set.bits_) != 0; + } + void Add(E element) { bits_ |= Mask(element); } + void Add(EnumSet set) { bits_ |= set.bits_; } + void Remove(E element) { bits_ &= ~Mask(element); } + void Remove(EnumSet set) { bits_ &= ~set.bits_; } + void RemoveAll() { bits_ = 0; } + void Intersect(EnumSet set) { bits_ &= set.bits_; } + constexpr T ToIntegral() const { return bits_; } + + constexpr bool operator==(EnumSet set) const { return bits_ == set.bits_; } + constexpr bool operator!=(EnumSet set) const { return bits_ != set.bits_; } + + constexpr EnumSet operator|(EnumSet set) const { + return EnumSet(bits_ | set.bits_); + } + constexpr EnumSet operator&(EnumSet set) const { + return EnumSet(bits_ & set.bits_); + } + constexpr EnumSet operator-(EnumSet set) const { + return EnumSet(bits_ & ~set.bits_); + } + + EnumSet& operator|=(EnumSet set) { return *this = *this | set; } + EnumSet& operator&=(EnumSet set) { return *this = *this & set; } + EnumSet& operator-=(EnumSet set) { return *this = *this - set; } + + constexpr EnumSet operator|(E element) const { + return EnumSet(bits_ | Mask(element)); + } + constexpr EnumSet operator&(E element) const { + return EnumSet(bits_ & Mask(element)); + } + constexpr EnumSet operator-(E element) const { + return EnumSet(bits_ & ~Mask(element)); + } + + EnumSet& operator|=(E element) { return *this = *this | element; } + EnumSet& operator&=(E element) { return *this = *this & element; } + EnumSet& operator-=(E element) { return *this = *this - element; } + + static constexpr EnumSet FromIntegral(T bits) { return EnumSet{bits}; } + + private: + explicit constexpr EnumSet(T bits) : bits_(bits) {} + + static constexpr T Mask(E element) { + DCHECK_GT(sizeof(T) * 8, static_cast(element)); + return T{1} << static_cast::type>(element); + } + + T bits_ = 0; +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_ENUM_SET_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/file-utils.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/file-utils.h new file mode 100644 index 000000000..84b57fb40 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/file-utils.h @@ -0,0 +1,23 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_FILE_UTILS_H_ +#define V8_BASE_FILE_UTILS_H_ + +#include + +#include "src/base/base-export.h" + +namespace v8 { +namespace base { + +// Helper functions to manipulate file paths. + +V8_BASE_EXPORT +std::unique_ptr RelativePath(const char* exec_path, const char* name); + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_FILE_UTILS_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/flags.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/flags.h index c2b795226..2a36ca77e 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/flags.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/flags.h @@ -81,7 +81,7 @@ class Flags final { constexpr operator mask_type() const { return mask_; } constexpr bool operator!() const { return !mask_; } - Flags without(flag_type flag) { return *this & (~Flags(flag)); } + Flags without(flag_type flag) const { return *this & (~Flags(flag)); } friend size_t hash_value(const Flags& flags) { return flags.mask_; } @@ -89,50 +89,40 @@ class Flags final { mask_type mask_; }; -#define DEFINE_OPERATORS_FOR_FLAGS(Type) \ - inline Type operator&( \ - Type::flag_type lhs, \ - Type::flag_type rhs)ALLOW_UNUSED_TYPE V8_WARN_UNUSED_RESULT; \ - inline Type operator&(Type::flag_type lhs, Type::flag_type rhs) { \ - return Type(lhs) & rhs; \ - } \ - inline Type operator&( \ - Type::flag_type lhs, \ - const Type& rhs)ALLOW_UNUSED_TYPE V8_WARN_UNUSED_RESULT; \ - inline Type operator&(Type::flag_type lhs, const Type& rhs) { \ - return rhs & lhs; \ - } \ - inline void operator&(Type::flag_type lhs, \ - Type::mask_type rhs)ALLOW_UNUSED_TYPE; \ - inline void operator&(Type::flag_type lhs, Type::mask_type rhs) {} \ - inline Type operator|(Type::flag_type lhs, Type::flag_type rhs) \ - ALLOW_UNUSED_TYPE V8_WARN_UNUSED_RESULT; \ - inline Type operator|(Type::flag_type lhs, Type::flag_type rhs) { \ - return Type(lhs) | rhs; \ - } \ - inline Type operator|(Type::flag_type lhs, const Type& rhs) \ - ALLOW_UNUSED_TYPE V8_WARN_UNUSED_RESULT; \ - inline Type operator|(Type::flag_type lhs, const Type& rhs) { \ - return rhs | lhs; \ - } \ - inline void operator|(Type::flag_type lhs, Type::mask_type rhs) \ - ALLOW_UNUSED_TYPE; \ - inline void operator|(Type::flag_type lhs, Type::mask_type rhs) {} \ - inline Type operator^(Type::flag_type lhs, Type::flag_type rhs) \ - ALLOW_UNUSED_TYPE V8_WARN_UNUSED_RESULT; \ - inline Type operator^(Type::flag_type lhs, Type::flag_type rhs) { \ - return Type(lhs) ^ rhs; \ - } \ - inline Type operator^(Type::flag_type lhs, const Type& rhs) \ - ALLOW_UNUSED_TYPE V8_WARN_UNUSED_RESULT; \ - inline Type operator^(Type::flag_type lhs, const Type& rhs) { \ - return rhs ^ lhs; \ - } \ - inline void operator^(Type::flag_type lhs, Type::mask_type rhs) \ - ALLOW_UNUSED_TYPE; \ - inline void operator^(Type::flag_type lhs, Type::mask_type rhs) {} \ - inline Type operator~(Type::flag_type val)ALLOW_UNUSED_TYPE; \ - inline Type operator~(Type::flag_type val) { return ~Type(val); } +#define DEFINE_OPERATORS_FOR_FLAGS(Type) \ + V8_ALLOW_UNUSED V8_WARN_UNUSED_RESULT inline constexpr Type operator&( \ + Type::flag_type lhs, Type::flag_type rhs) { \ + return Type(lhs) & rhs; \ + } \ + V8_ALLOW_UNUSED V8_WARN_UNUSED_RESULT inline constexpr Type operator&( \ + Type::flag_type lhs, const Type& rhs) { \ + return rhs & lhs; \ + } \ + V8_ALLOW_UNUSED inline void operator&(Type::flag_type lhs, \ + Type::mask_type rhs) {} \ + V8_ALLOW_UNUSED V8_WARN_UNUSED_RESULT inline constexpr Type operator|( \ + Type::flag_type lhs, Type::flag_type rhs) { \ + return Type(lhs) | rhs; \ + } \ + V8_ALLOW_UNUSED V8_WARN_UNUSED_RESULT inline constexpr Type operator|( \ + Type::flag_type lhs, const Type& rhs) { \ + return rhs | lhs; \ + } \ + V8_ALLOW_UNUSED inline void operator|(Type::flag_type lhs, \ + Type::mask_type rhs) {} \ + V8_ALLOW_UNUSED V8_WARN_UNUSED_RESULT inline constexpr Type operator^( \ + Type::flag_type lhs, Type::flag_type rhs) { \ + return Type(lhs) ^ rhs; \ + } \ + V8_ALLOW_UNUSED V8_WARN_UNUSED_RESULT inline constexpr Type operator^( \ + Type::flag_type lhs, const Type& rhs) { \ + return rhs ^ lhs; \ + } \ + V8_ALLOW_UNUSED inline void operator^(Type::flag_type lhs, \ + Type::mask_type rhs) {} \ + V8_ALLOW_UNUSED inline constexpr Type operator~(Type::flag_type val) { \ + return ~Type(val); \ + } } // namespace base } // namespace v8 diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/free_deleter.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/free_deleter.h new file mode 100644 index 000000000..4f4efcda1 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/free_deleter.h @@ -0,0 +1,32 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Slightly adapted for inclusion in V8. +// Copyright 2016 the V8 project authors. All rights reserved. + +#ifndef V8_BASE_FREE_DELETER_H_ +#define V8_BASE_FREE_DELETER_H_ + +#include + +#include + +#include "src/base/platform/wrappers.h" + +namespace v8 { +namespace base { + +// Function object which invokes 'free' on its parameter, which must be +// a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr: +// +// std::unique_ptr foo_ptr( +// static_cast(malloc(sizeof(int)))); +struct FreeDeleter { + inline void operator()(void* ptr) const { base::Free(ptr); } +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_FREE_DELETER_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/functional.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/functional.h new file mode 100644 index 000000000..7bf6b4bac --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/functional.h @@ -0,0 +1,226 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_FUNCTIONAL_H_ +#define V8_BASE_FUNCTIONAL_H_ + +#include +#include + +#include +#include +#include +#include + +#include "src/base/base-export.h" +#include "src/base/macros.h" + +namespace v8 { +namespace base { + +// base::hash is an implementation of the hash function object specified by +// C++11. It was designed to be compatible with std::hash (in C++11) and +// boost:hash (which in turn is based on the hash function object specified by +// the Draft Technical Report on C++ Library Extensions (TR1)). +// +// base::hash is implemented by calling the hash_value function. The namespace +// isn't specified so that it can detect overloads via argument dependent +// lookup. So if there is a free function hash_value in the same namespace as a +// custom type, it will get called. +// +// If users are asked to implement a hash function for their own types with no +// guidance, they generally write bad hash functions. Instead, we provide a +// simple function base::hash_combine to pass hash-relevant member variables +// into, in order to define a decent hash function. base::hash_combine is +// declared as: +// +// template +// size_t hash_combine(const T& v, const Ts& ...vs); +// +// Consider the following example: +// +// namespace v8 { +// namespace bar { +// struct Point { int x; int y; }; +// size_t hash_value(Point const& p) { +// return base::hash_combine(p.x, p.y); +// } +// } +// +// namespace foo { +// void DoSomeWork(bar::Point const& p) { +// base::hash h; +// ... +// size_t hash_code = h(p); // calls bar::hash_value(Point const&) +// ... +// } +// } +// } +// +// Based on the "Hashing User-Defined Types in C++1y" proposal from Jeffrey +// Yasskin and Chandler Carruth, see +// http://www.open-std.org/Jtc1/sc22/wg21/docs/papers/2012/n3333.html. + +template +struct hash; + + +V8_INLINE size_t hash_combine() { return 0u; } +V8_INLINE size_t hash_combine(size_t seed) { return seed; } +V8_BASE_EXPORT size_t hash_combine(size_t seed, size_t value); +template +V8_INLINE size_t hash_combine(T const& v, Ts const&... vs) { + return hash_combine(hash_combine(vs...), hash()(v)); +} + + +template +V8_INLINE size_t hash_range(Iterator first, Iterator last) { + size_t seed = 0; + for (; first != last; ++first) { + seed = hash_combine(seed, *first); + } + return seed; +} + + +#define V8_BASE_HASH_VALUE_TRIVIAL(type) \ + V8_INLINE size_t hash_value(type v) { return static_cast(v); } +V8_BASE_HASH_VALUE_TRIVIAL(bool) +V8_BASE_HASH_VALUE_TRIVIAL(unsigned char) +V8_BASE_HASH_VALUE_TRIVIAL(unsigned short) // NOLINT(runtime/int) +#undef V8_BASE_HASH_VALUE_TRIVIAL + +V8_BASE_EXPORT size_t hash_value(unsigned int); +V8_BASE_EXPORT size_t hash_value(unsigned long); // NOLINT(runtime/int) +V8_BASE_EXPORT size_t hash_value(unsigned long long); // NOLINT(runtime/int) + +#define V8_BASE_HASH_VALUE_SIGNED(type) \ + V8_INLINE size_t hash_value(signed type v) { \ + return hash_value(bit_cast(v)); \ + } +V8_BASE_HASH_VALUE_SIGNED(char) +V8_BASE_HASH_VALUE_SIGNED(short) // NOLINT(runtime/int) +V8_BASE_HASH_VALUE_SIGNED(int) // NOLINT(runtime/int) +V8_BASE_HASH_VALUE_SIGNED(long) // NOLINT(runtime/int) +V8_BASE_HASH_VALUE_SIGNED(long long) // NOLINT(runtime/int) +#undef V8_BASE_HASH_VALUE_SIGNED + +V8_INLINE size_t hash_value(float v) { + // 0 and -0 both hash to zero. + return v != 0.0f ? hash_value(bit_cast(v)) : 0; +} + +V8_INLINE size_t hash_value(double v) { + // 0 and -0 both hash to zero. + return v != 0.0 ? hash_value(bit_cast(v)) : 0; +} + +template +V8_INLINE size_t hash_value(const T (&v)[N]) { + return hash_range(v, v + N); +} + +template +V8_INLINE size_t hash_value(T (&v)[N]) { + return hash_range(v, v + N); +} + +template +V8_INLINE size_t hash_value(T* const& v) { + return hash_value(bit_cast(v)); +} + +template +V8_INLINE size_t hash_value(std::pair const& v) { + return hash_combine(v.first, v.second); +} + +template +struct hash { + V8_INLINE size_t operator()(T const& v) const { return hash_value(v); } +}; + +#define V8_BASE_HASH_SPECIALIZE(type) \ + template <> \ + struct hash { \ + V8_INLINE size_t operator()(type const v) const { \ + return ::v8::base::hash_value(v); \ + } \ + }; +V8_BASE_HASH_SPECIALIZE(bool) +V8_BASE_HASH_SPECIALIZE(signed char) +V8_BASE_HASH_SPECIALIZE(unsigned char) +V8_BASE_HASH_SPECIALIZE(short) // NOLINT(runtime/int) +V8_BASE_HASH_SPECIALIZE(unsigned short) // NOLINT(runtime/int) +V8_BASE_HASH_SPECIALIZE(int) +V8_BASE_HASH_SPECIALIZE(unsigned int) +V8_BASE_HASH_SPECIALIZE(long) // NOLINT(runtime/int) +V8_BASE_HASH_SPECIALIZE(unsigned long) // NOLINT(runtime/int) +V8_BASE_HASH_SPECIALIZE(long long) // NOLINT(runtime/int) +V8_BASE_HASH_SPECIALIZE(unsigned long long) // NOLINT(runtime/int) +V8_BASE_HASH_SPECIALIZE(float) +V8_BASE_HASH_SPECIALIZE(double) +#undef V8_BASE_HASH_SPECIALIZE + +template +struct hash { + V8_INLINE size_t operator()(T* const v) const { + return ::v8::base::hash_value(v); + } +}; + +// base::bit_equal_to is a function object class for bitwise equality +// comparison, similar to std::equal_to, except that the comparison is performed +// on the bit representation of the operands. +// +// base::bit_hash is a function object class for bitwise hashing, similar to +// base::hash. It can be used together with base::bit_equal_to to implement a +// hash data structure based on the bitwise representation of types. + +template +struct bit_equal_to {}; + +template +struct bit_hash {}; + +#define V8_BASE_BIT_SPECIALIZE_TRIVIAL(type) \ + template <> \ + struct bit_equal_to : public std::equal_to {}; \ + template <> \ + struct bit_hash : public hash {}; +V8_BASE_BIT_SPECIALIZE_TRIVIAL(signed char) +V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned char) +V8_BASE_BIT_SPECIALIZE_TRIVIAL(short) // NOLINT(runtime/int) +V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned short) // NOLINT(runtime/int) +V8_BASE_BIT_SPECIALIZE_TRIVIAL(int) +V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned int) +V8_BASE_BIT_SPECIALIZE_TRIVIAL(long) // NOLINT(runtime/int) +V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned long) // NOLINT(runtime/int) +V8_BASE_BIT_SPECIALIZE_TRIVIAL(long long) // NOLINT(runtime/int) +V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned long long) // NOLINT(runtime/int) +#undef V8_BASE_BIT_SPECIALIZE_TRIVIAL + +#define V8_BASE_BIT_SPECIALIZE_BIT_CAST(type, btype) \ + template <> \ + struct bit_equal_to { \ + V8_INLINE bool operator()(type lhs, type rhs) const { \ + return bit_cast(lhs) == bit_cast(rhs); \ + } \ + }; \ + template <> \ + struct bit_hash { \ + V8_INLINE size_t operator()(type v) const { \ + hash h; \ + return h(bit_cast(v)); \ + } \ + }; +V8_BASE_BIT_SPECIALIZE_BIT_CAST(float, uint32_t) +V8_BASE_BIT_SPECIALIZE_BIT_CAST(double, uint64_t) +#undef V8_BASE_BIT_SPECIALIZE_BIT_CAST + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_FUNCTIONAL_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/hashmap-entry.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/hashmap-entry.h index 629e73408..2f984f3c2 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/hashmap-entry.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/hashmap-entry.h @@ -6,15 +6,25 @@ #define V8_BASE_HASHMAP_ENTRY_H_ #include +#include + +#include "src/base/memory.h" namespace v8 { namespace base { +// Marker type for hashmaps without a value (i.e. hashsets). These won't +// allocate space for the value in the entry. +struct NoHashMapValue {}; + // HashMap entries are (key, value, hash) triplets, with a boolean indicating if // they are an empty entry. Some clients may not need to use the value slot -// (e.g. implementers of sets, where the key is the value). +// (e.g. implementers of sets, where the key is the value), in which case they +// should use NoHashMapValue. template struct TemplateHashMapEntry { + STATIC_ASSERT((!std::is_same::value)); + Key key; Value value; uint32_t hash; // The full hash value for key @@ -33,6 +43,8 @@ struct TemplateHashMapEntry { // Specialization for pointer-valued keys template struct TemplateHashMapEntry { + STATIC_ASSERT((!std::is_same::value)); + Key* key; Value value; uint32_t hash; // The full hash value for key @@ -45,8 +57,42 @@ struct TemplateHashMapEntry { void clear() { key = nullptr; } }; -// TODO(leszeks): There could be a specialisation for void values (e.g. for -// sets), which omits the value field +// Specialization for no value. +template +struct TemplateHashMapEntry { + union { + Key key; + NoHashMapValue value; // Value in union with key to not take up space. + }; + uint32_t hash; // The full hash value for key + + TemplateHashMapEntry(Key key, NoHashMapValue value, uint32_t hash) + : key(key), hash(hash), exists_(true) {} + + bool exists() const { return exists_; } + + void clear() { exists_ = false; } + + private: + bool exists_; +}; + +// Specialization for pointer-valued keys and no value. +template +struct TemplateHashMapEntry { + union { + Key* key; + NoHashMapValue value; // Value in union with key to not take up space. + }; + uint32_t hash; // The full hash value for key + + TemplateHashMapEntry(Key* key, NoHashMapValue value, uint32_t hash) + : key(key), hash(hash) {} + + bool exists() const { return key != nullptr; } + + void clear() { key = nullptr; } +}; } // namespace base } // namespace v8 diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/hashmap.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/hashmap.h index 4ad946d0d..576ffb068 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/hashmap.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/hashmap.h @@ -14,14 +14,21 @@ #include "src/base/bits.h" #include "src/base/hashmap-entry.h" #include "src/base/logging.h" +#include "src/base/platform/wrappers.h" namespace v8 { namespace base { class DefaultAllocationPolicy { public: - V8_INLINE void* New(size_t size) { return malloc(size); } - V8_INLINE static void Delete(void* p) { free(p); } + template + V8_INLINE T* NewArray(size_t length) { + return static_cast(base::Malloc(length * sizeof(T))); + } + template + V8_INLINE void DeleteArray(T* p, size_t length) { + base::Free(p); + } }; template @@ -36,17 +43,24 @@ class TemplateHashMapImpl { // initial_capacity is the size of the initial hash map; // it must be a power of 2 (and thus must not be 0). - TemplateHashMapImpl(uint32_t capacity = kDefaultHashMapCapacity, - MatchFun match = MatchFun(), - AllocationPolicy allocator = AllocationPolicy()); + explicit TemplateHashMapImpl(uint32_t capacity = kDefaultHashMapCapacity, + MatchFun match = MatchFun(), + AllocationPolicy allocator = AllocationPolicy()); + + TemplateHashMapImpl(const TemplateHashMapImpl&) = delete; + TemplateHashMapImpl& operator=(const TemplateHashMapImpl&) = delete; // Clones the given hashmap and creates a copy with the same entries. - TemplateHashMapImpl(const TemplateHashMapImpl* original, - AllocationPolicy allocator = AllocationPolicy()); + explicit TemplateHashMapImpl(const TemplateHashMapImpl* original, + AllocationPolicy allocator = AllocationPolicy()); + + TemplateHashMapImpl(TemplateHashMapImpl&& other) V8_NOEXCEPT = default; ~TemplateHashMapImpl(); + TemplateHashMapImpl& operator=(TemplateHashMapImpl&& other) + V8_NOEXCEPT = default; + // If an entry with matching key is found, returns that entry. // Otherwise, nullptr is returned. Entry* Lookup(const Key& key, uint32_t hash) const; @@ -54,18 +68,29 @@ class TemplateHashMapImpl { // If an entry with matching key is found, returns that entry. // If no matching entry is found, a new entry is inserted with // corresponding key, key hash, and default initialized value. - Entry* LookupOrInsert(const Key& key, uint32_t hash, - AllocationPolicy allocator = AllocationPolicy()); + Entry* LookupOrInsert(const Key& key, uint32_t hash); // If an entry with matching key is found, returns that entry. // If no matching entry is found, a new entry is inserted with // corresponding key, key hash, and value created by func. template - Entry* LookupOrInsert(const Key& key, uint32_t hash, const Func& value_func, - AllocationPolicy allocator = AllocationPolicy()); + Entry* LookupOrInsert(const Key& key, uint32_t hash, const Func& value_func); + + // Heterogeneous version of LookupOrInsert, which allows a + // different lookup key type than the hashmap's key type. + // The requirement is that MatchFun has an overload: + // + // operator()(const LookupKey& lookup_key, const Key& entry_key) + // + // If an entry with matching key is found, returns that entry. + // If no matching entry is found, a new entry is inserted with + // a key created by key_func, key hash, and value created by + // value_func. + template + Entry* LookupOrInsert(const LookupKey& lookup_key, uint32_t hash, + const KeyFunc& key_func, const ValueFunc& value_func); - Entry* InsertNew(const Key& key, uint32_t hash, - AllocationPolicy allocator = AllocationPolicy()); + Entry* InsertNew(const Key& key, uint32_t hash); // Removes the entry with matching key. // It returns the value of the deleted entry @@ -77,19 +102,18 @@ class TemplateHashMapImpl { // Empties the map and makes it unusable for allocation. void Invalidate() { - AllocationPolicy::Delete(map_); - map_ = nullptr; - occupancy_ = 0; - capacity_ = 0; + DCHECK_NOT_NULL(impl_.map_); + impl_.allocator().DeleteArray(impl_.map_, capacity()); + impl_ = Impl(impl_.match(), AllocationPolicy()); } // The number of (non-empty) entries in the table. - uint32_t occupancy() const { return occupancy_; } + uint32_t occupancy() const { return impl_.occupancy_; } // The capacity of the table. The implementation // makes sure that occupancy is at most 80% of // the table capacity. - uint32_t capacity() const { return capacity_; } + uint32_t capacity() const { return impl_.capacity_; } // Iteration // @@ -102,58 +126,86 @@ class TemplateHashMapImpl { Entry* Start() const; Entry* Next(Entry* entry) const; - void Reset(AllocationPolicy allocator) { - Initialize(capacity_, allocator); - occupancy_ = 0; - } + AllocationPolicy allocator() const { return impl_.allocator(); } protected: - void Initialize(uint32_t capacity, AllocationPolicy allocator); + void Initialize(uint32_t capacity); private: - Entry* map_; - uint32_t capacity_; - uint32_t occupancy_; - // TODO(leszeks): This takes up space even if it has no state, maybe replace - // with something that does the empty base optimisation e.g. std::tuple - MatchFun match_; - - Entry* map_end() const { return map_ + capacity_; } - Entry* Probe(const Key& key, uint32_t hash) const; + Entry* map_end() const { return impl_.map_ + impl_.capacity_; } + template + Entry* Probe(const LookupKey& key, uint32_t hash) const; Entry* FillEmptyEntry(Entry* entry, const Key& key, const Value& value, - uint32_t hash, - AllocationPolicy allocator = AllocationPolicy()); - void Resize(AllocationPolicy allocator); + uint32_t hash); + void Resize(); + + // To support matcher and allocator that may not be possible to + // default-construct, we have to store their instances. Using this to store + // all internal state of the hash map and using private inheritance to store + // matcher and allocator lets us take advantage of an empty base class + // optimization to avoid extra space in the common case when MatchFun and + // AllocationPolicy have no state. + // TODO(ishell): Once we reach C++20, consider removing the Impl struct and + // adding match and allocator as [[no_unique_address]] fields. + struct Impl : private MatchFun, private AllocationPolicy { + Impl(MatchFun match, AllocationPolicy allocator) + : MatchFun(std::move(match)), AllocationPolicy(std::move(allocator)) {} + + Impl() = default; + Impl(const Impl&) V8_NOEXCEPT = default; + Impl(Impl&& other) V8_NOEXCEPT { *this = std::move(other); } + + Impl& operator=(const Impl& other) V8_NOEXCEPT = default; + Impl& operator=(Impl&& other) V8_NOEXCEPT { + MatchFun::operator=(std::move(other)); + AllocationPolicy::operator=(std::move(other)); + map_ = other.map_; + capacity_ = other.capacity_; + occupancy_ = other.occupancy_; + + other.map_ = nullptr; + other.capacity_ = 0; + other.occupancy_ = 0; + return *this; + } + + const MatchFun& match() const { return *this; } + MatchFun& match() { return *this; } - DISALLOW_COPY_AND_ASSIGN(TemplateHashMapImpl); + const AllocationPolicy& allocator() const { return *this; } + AllocationPolicy& allocator() { return *this; } + + Entry* map_ = nullptr; + uint32_t capacity_ = 0; + uint32_t occupancy_ = 0; + } impl_; }; template TemplateHashMapImpl:: TemplateHashMapImpl(uint32_t initial_capacity, MatchFun match, AllocationPolicy allocator) - : match_(match) { - Initialize(initial_capacity, allocator); + : impl_(std::move(match), std::move(allocator)) { + Initialize(initial_capacity); } template TemplateHashMapImpl:: - TemplateHashMapImpl(const TemplateHashMapImpl* original, + TemplateHashMapImpl(const TemplateHashMapImpl* original, AllocationPolicy allocator) - : capacity_(original->capacity_), - occupancy_(original->occupancy_), - match_(original->match_) { - map_ = reinterpret_cast(allocator.New(capacity_ * sizeof(Entry))); - memcpy(map_, original->map_, capacity_ * sizeof(Entry)); + : impl_(original->impl_.match(), std::move(allocator)) { + impl_.capacity_ = original->capacity(); + impl_.occupancy_ = original->occupancy(); + impl_.map_ = impl_.allocator().template NewArray(capacity()); + memcpy(impl_.map_, original->impl_.map_, capacity() * sizeof(Entry)); } template TemplateHashMapImpl::~TemplateHashMapImpl() { - AllocationPolicy::Delete(map_); + if (impl_.map_) impl_.allocator().DeleteArray(impl_.map_, capacity()); } template typename TemplateHashMapImpl::Entry* TemplateHashMapImpl::LookupOrInsert( - const Key& key, uint32_t hash, AllocationPolicy allocator) { - return LookupOrInsert(key, hash, []() { return Value(); }, allocator); + const Key& key, uint32_t hash) { + return LookupOrInsert(key, hash, []() { return Value(); }); } template typename TemplateHashMapImpl::Entry* TemplateHashMapImpl::LookupOrInsert( - const Key& key, uint32_t hash, const Func& value_func, - AllocationPolicy allocator) { + const Key& key, uint32_t hash, const Func& value_func) { + return LookupOrInsert( + key, hash, [&key]() { return key; }, value_func); +} + +template +template +typename TemplateHashMapImpl::Entry* +TemplateHashMapImpl::LookupOrInsert( + const LookupKey& lookup_key, uint32_t hash, const KeyFunc& key_func, + const ValueFunc& value_func) { // Find a matching entry. - Entry* entry = Probe(key, hash); + Entry* entry = Probe(lookup_key, hash); if (entry->exists()) { return entry; } - return FillEmptyEntry(entry, key, value_func(), hash, allocator); + return FillEmptyEntry(entry, key_func(), value_func(), hash); } template typename TemplateHashMapImpl::Entry* TemplateHashMapImpl::InsertNew( - const Key& key, uint32_t hash, AllocationPolicy allocator) { + const Key& key, uint32_t hash) { Entry* entry = Probe(key, hash); - return FillEmptyEntry(entry, key, Value(), hash, allocator); + return FillEmptyEntry(entry, key, Value(), hash); } template ::Remove( // This guarantees loop termination as there is at least one empty entry so // eventually the removed entry will have an empty entry after it. - DCHECK(occupancy_ < capacity_); + DCHECK(occupancy() < capacity()); // p is the candidate entry to clear. q is used to scan forwards. Entry* q = p; // Start at the entry to remove. @@ -232,7 +294,7 @@ Value TemplateHashMapImpl::Remove( // Move q to the next entry. q = q + 1; if (q == map_end()) { - q = map_; + q = impl_.map_; } // All entries between p and q have their initial position between p and q @@ -243,7 +305,7 @@ Value TemplateHashMapImpl::Remove( } // Find the initial position for the entry at position q. - Entry* r = map_ + (q->hash & (capacity_ - 1)); + Entry* r = impl_.map_ + (q->hash & (capacity() - 1)); // If the entry at position q has its initial position outside the range // between p and q it can be moved forward to position p and will still be @@ -256,7 +318,7 @@ Value TemplateHashMapImpl::Remove( // Clear the entry which is allowed to en emptied. p->clear(); - occupancy_--; + impl_.occupancy_--; return value; } @@ -264,17 +326,17 @@ template void TemplateHashMapImpl::Clear() { // Mark all entries as empty. - for (size_t i = 0; i < capacity_; ++i) { - map_[i].clear(); + for (size_t i = 0; i < capacity(); ++i) { + impl_.map_[i].clear(); } - occupancy_ = 0; + impl_.occupancy_ = 0; } template typename TemplateHashMapImpl::Entry* TemplateHashMapImpl::Start() const { - return Next(map_ - 1); + return Next(impl_.map_ - 1); } template ::Entry* TemplateHashMapImpl::Next( Entry* entry) const { const Entry* end = map_end(); - DCHECK(map_ - 1 <= entry && entry < end); + DCHECK(impl_.map_ - 1 <= entry && entry < end); for (entry++; entry < end; entry++) { if (entry->exists()) { return entry; @@ -294,35 +356,37 @@ TemplateHashMapImpl::Next( template +template typename TemplateHashMapImpl::Entry* TemplateHashMapImpl::Probe( - const Key& key, uint32_t hash) const { - DCHECK(base::bits::IsPowerOfTwo(capacity_)); - size_t i = hash & (capacity_ - 1); - DCHECK(i < capacity_); - - DCHECK(occupancy_ < capacity_); // Guarantees loop termination. - while (map_[i].exists() && !match_(hash, map_[i].hash, key, map_[i].key)) { - i = (i + 1) & (capacity_ - 1); + const LookupKey& key, uint32_t hash) const { + DCHECK(base::bits::IsPowerOfTwo(capacity())); + size_t i = hash & (capacity() - 1); + DCHECK(i < capacity()); + + DCHECK(occupancy() < capacity()); // Guarantees loop termination. + Entry* map = impl_.map_; + while (map[i].exists() && + !impl_.match()(hash, map[i].hash, key, map[i].key)) { + i = (i + 1) & (capacity() - 1); } - return &map_[i]; + return &map[i]; } template typename TemplateHashMapImpl::Entry* TemplateHashMapImpl::FillEmptyEntry( - Entry* entry, const Key& key, const Value& value, uint32_t hash, - AllocationPolicy allocator) { + Entry* entry, const Key& key, const Value& value, uint32_t hash) { DCHECK(!entry->exists()); new (entry) Entry(key, value, hash); - occupancy_++; + impl_.occupancy_++; // Grow the map if we reached >= 80% occupancy. - if (occupancy_ + occupancy_ / 4 >= capacity_) { - Resize(allocator); + if (occupancy() + occupancy() / 4 >= capacity()) { + Resize(); entry = Probe(key, hash); } @@ -332,39 +396,39 @@ TemplateHashMapImpl::FillEmptyEntry( template void TemplateHashMapImpl::Initialize( - uint32_t capacity, AllocationPolicy allocator) { + uint32_t capacity) { DCHECK(base::bits::IsPowerOfTwo(capacity)); - map_ = reinterpret_cast(allocator.New(capacity * sizeof(Entry))); - if (map_ == nullptr) { + impl_.map_ = impl_.allocator().template NewArray(capacity); + if (impl_.map_ == nullptr) { FATAL("Out of memory: HashMap::Initialize"); return; } - capacity_ = capacity; + impl_.capacity_ = capacity; Clear(); } template -void TemplateHashMapImpl::Resize( - AllocationPolicy allocator) { - Entry* map = map_; - uint32_t n = occupancy_; +void TemplateHashMapImpl::Resize() { + Entry* old_map = impl_.map_; + uint32_t old_capacity = capacity(); + uint32_t n = occupancy(); // Allocate larger map. - Initialize(capacity_ * 2, allocator); + Initialize(capacity() * 2); // Rehash all current entries. - for (Entry* entry = map; n > 0; entry++) { + for (Entry* entry = old_map; n > 0; entry++) { if (entry->exists()) { Entry* new_entry = Probe(entry->key, entry->hash); - new_entry = FillEmptyEntry(new_entry, entry->key, entry->value, - entry->hash, allocator); + new_entry = + FillEmptyEntry(new_entry, entry->key, entry->value, entry->hash); n--; } } // Delete old map. - AllocationPolicy::Delete(map); + impl_.allocator().DeleteArray(old_map, old_capacity); } // Match function which compares hashes before executing a (potentially @@ -396,19 +460,21 @@ class CustomMatcherTemplateHashMapImpl public: using MatchFun = bool (*)(void*, void*); - CustomMatcherTemplateHashMapImpl( + explicit CustomMatcherTemplateHashMapImpl( MatchFun match, uint32_t capacity = Base::kDefaultHashMapCapacity, AllocationPolicy allocator = AllocationPolicy()) : Base(capacity, HashEqualityThenKeyMatcher(match), allocator) {} - CustomMatcherTemplateHashMapImpl( - const CustomMatcherTemplateHashMapImpl* original, + explicit CustomMatcherTemplateHashMapImpl( + const CustomMatcherTemplateHashMapImpl* original, AllocationPolicy allocator = AllocationPolicy()) : Base(original, allocator) {} - private: - DISALLOW_COPY_AND_ASSIGN(CustomMatcherTemplateHashMapImpl); + CustomMatcherTemplateHashMapImpl(const CustomMatcherTemplateHashMapImpl&) = + delete; + CustomMatcherTemplateHashMapImpl& operator=( + const CustomMatcherTemplateHashMapImpl&) = delete; }; using CustomMatcherHashMap = @@ -432,9 +498,23 @@ class PointerTemplateHashMapImpl AllocationPolicy>; public: - PointerTemplateHashMapImpl(uint32_t capacity = Base::kDefaultHashMapCapacity, - AllocationPolicy allocator = AllocationPolicy()) + explicit PointerTemplateHashMapImpl( + uint32_t capacity = Base::kDefaultHashMapCapacity, + AllocationPolicy allocator = AllocationPolicy()) : Base(capacity, KeyEqualityMatcher(), allocator) {} + + PointerTemplateHashMapImpl(const PointerTemplateHashMapImpl& other, + AllocationPolicy allocator = AllocationPolicy()) + : Base(&other, allocator) {} + + PointerTemplateHashMapImpl(PointerTemplateHashMapImpl&& other) V8_NOEXCEPT + : Base(std::move(other)) {} + + PointerTemplateHashMapImpl& operator=(PointerTemplateHashMapImpl&& other) + V8_NOEXCEPT { + static_cast(*this) = std::move(other); + return *this; + } }; using HashMap = PointerTemplateHashMapImpl; @@ -450,8 +530,8 @@ class TemplateHashMap AllocationPolicy>; public: - STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT - STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT + STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); + STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); struct value_type { Key* first; Value* second; @@ -477,17 +557,16 @@ class TemplateHashMap friend class TemplateHashMap; }; - TemplateHashMap(MatchFun match, - AllocationPolicy allocator = AllocationPolicy()) + explicit TemplateHashMap(MatchFun match, + AllocationPolicy allocator = AllocationPolicy()) : Base(Base::kDefaultHashMapCapacity, HashEqualityThenKeyMatcher(match), allocator) {} Iterator begin() const { return Iterator(this, this->Start()); } Iterator end() const { return Iterator(this, nullptr); } - Iterator find(Key* key, bool insert = false, - AllocationPolicy allocator = AllocationPolicy()) { + Iterator find(Key* key, bool insert = false) { if (insert) { - return Iterator(this, this->LookupOrInsert(key, key->Hash(), allocator)); + return Iterator(this, this->LookupOrInsert(key, key->Hash())); } return Iterator(this, this->Lookup(key, key->Hash())); } diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/ieee754.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/ieee754.h new file mode 100644 index 000000000..f2b3a3eb5 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/ieee754.h @@ -0,0 +1,90 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_IEEE754_H_ +#define V8_BASE_IEEE754_H_ + +#include "src/base/base-export.h" + +namespace v8 { +namespace base { +namespace ieee754 { + +// Returns the arc cosine of |x|; that is the value whose cosine is |x|. +V8_BASE_EXPORT double acos(double x); + +// Returns the inverse hyperbolic cosine of |x|; that is the value whose +// hyperbolic cosine is |x|. +V8_BASE_EXPORT double acosh(double x); + +// Returns the arc sine of |x|; that is the value whose sine is |x|. +V8_BASE_EXPORT double asin(double x); + +// Returns the inverse hyperbolic sine of |x|; that is the value whose +// hyperbolic sine is |x|. +V8_BASE_EXPORT double asinh(double x); + +// Returns the principal value of the arc tangent of |x|; that is the value +// whose tangent is |x|. +V8_BASE_EXPORT double atan(double x); + +// Returns the principal value of the arc tangent of |y/x|, using the signs of +// the two arguments to determine the quadrant of the result. +V8_BASE_EXPORT double atan2(double y, double x); + +// Returns the cosine of |x|, where |x| is given in radians. +V8_BASE_EXPORT double cos(double x); + +// Returns the base-e exponential of |x|. +V8_BASE_EXPORT double exp(double x); + +V8_BASE_EXPORT double atanh(double x); + +// Returns the natural logarithm of |x|. +V8_BASE_EXPORT double log(double x); + +// Returns a value equivalent to |log(1+x)|, but computed in a way that is +// accurate even if the value of |x| is near zero. +V8_BASE_EXPORT double log1p(double x); + +// Returns the base 2 logarithm of |x|. +V8_BASE_EXPORT double log2(double x); + +// Returns the base 10 logarithm of |x|. +V8_BASE_EXPORT double log10(double x); + +// Returns the cube root of |x|. +V8_BASE_EXPORT double cbrt(double x); + +// Returns exp(x)-1, the exponential of |x| minus 1. +V8_BASE_EXPORT double expm1(double x); + +// Returns |x| to the power of |y|. +// The result of base ** exponent when base is 1 or -1 and exponent is +// +Infinity or -Infinity differs from IEEE 754-2008. The first edition +// of ECMAScript specified a result of NaN for this operation, whereas +// later versions of IEEE 754-2008 specified 1. The historical ECMAScript +// behaviour is preserved for compatibility reasons. +V8_BASE_EXPORT double pow(double x, double y); + +// Returns the sine of |x|, where |x| is given in radians. +V8_BASE_EXPORT double sin(double x); + +// Returns the tangent of |x|, where |x| is given in radians. +V8_BASE_EXPORT double tan(double x); + +// Returns the hyperbolic cosine of |x|, where |x| is given radians. +V8_BASE_EXPORT double cosh(double x); + +// Returns the hyperbolic sine of |x|, where |x| is given radians. +V8_BASE_EXPORT double sinh(double x); + +// Returns the hyperbolic tangent of |x|, where |x| is given radians. +V8_BASE_EXPORT double tanh(double x); + +} // namespace ieee754 +} // namespace base +} // namespace v8 + +#endif // V8_BASE_IEEE754_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/immediate-crash.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/immediate-crash.h new file mode 100644 index 000000000..770cb273f --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/immediate-crash.h @@ -0,0 +1,162 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_IMMEDIATE_CRASH_H_ +#define V8_BASE_IMMEDIATE_CRASH_H_ + +#include "include/v8config.h" +#include "src/base/build_config.h" + +// Crashes in the fastest possible way with no attempt at logging. +// There are several constraints; see http://crbug.com/664209 for more context. +// +// - TRAP_SEQUENCE_() must be fatal. It should not be possible to ignore the +// resulting exception or simply hit 'continue' to skip over it in a debugger. +// - Different instances of TRAP_SEQUENCE_() must not be folded together, to +// ensure crash reports are debuggable. Unlike __builtin_trap(), asm volatile +// blocks will not be folded together. +// Note: TRAP_SEQUENCE_() previously required an instruction with a unique +// nonce since unlike clang, GCC folds together identical asm volatile +// blocks. +// - TRAP_SEQUENCE_() must produce a signal that is distinct from an invalid +// memory access. +// - TRAP_SEQUENCE_() must be treated as a set of noreturn instructions. +// __builtin_unreachable() is used to provide that hint here. clang also uses +// this as a heuristic to pack the instructions in the function epilogue to +// improve code density. +// +// Additional properties that are nice to have: +// - TRAP_SEQUENCE_() should be as compact as possible. +// - The first instruction of TRAP_SEQUENCE_() should not change, to avoid +// shifting crash reporting clusters. As a consequence of this, explicit +// assembly is preferred over intrinsics. +// Note: this last bullet point may no longer be true, and may be removed in +// the future. + +// Note: TRAP_SEQUENCE Is currently split into two macro helpers due to the fact +// that clang emits an actual instruction for __builtin_unreachable() on certain +// platforms (see https://crbug.com/958675). In addition, the int3/bkpt/brk will +// be removed in followups, so splitting it up like this now makes it easy to +// land the followups. + +#if V8_CC_GNU + +#if V8_HOST_ARCH_X64 || V8_HOST_ARCH_IA32 + +// TODO(https://crbug.com/958675): In theory, it should be possible to use just +// int3. However, there are a number of crashes with SIGILL as the exception +// code, so it seems likely that there's a signal handler that allows execution +// to continue after SIGTRAP. +#define TRAP_SEQUENCE1_() asm volatile("int3") + +#if V8_OS_DARWIN +// Intentionally empty: __builtin_unreachable() is always part of the sequence +// (see IMMEDIATE_CRASH below) and already emits a ud2 on Mac. +#define TRAP_SEQUENCE2_() asm volatile("") +#else +#define TRAP_SEQUENCE2_() asm volatile("ud2") +#endif // V8_OS_DARWIN + +#elif V8_HOST_ARCH_ARM + +// bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running +// as a 32 bit userspace app on arm64. There doesn't seem to be any way to +// cause a SIGTRAP from userspace without using a syscall (which would be a +// problem for sandboxing). +// TODO(https://crbug.com/958675): Remove bkpt from this sequence. +#define TRAP_SEQUENCE1_() asm volatile("bkpt #0") +#define TRAP_SEQUENCE2_() asm volatile("udf #0") + +#elif V8_HOST_ARCH_ARM64 + +// This will always generate a SIGTRAP on arm64. +// TODO(https://crbug.com/958675): Remove brk from this sequence. +#define TRAP_SEQUENCE1_() asm volatile("brk #0") +#define TRAP_SEQUENCE2_() asm volatile("hlt #0") + +#else + +// Crash report accuracy will not be guaranteed on other architectures, but at +// least this will crash as expected. +#define TRAP_SEQUENCE1_() __builtin_trap() +#define TRAP_SEQUENCE2_() asm volatile("") + +#endif // V8_HOST_ARCH_* + +#elif V8_CC_MSVC + +#if !defined(__clang__) + +// MSVC x64 doesn't support inline asm, so use the MSVC intrinsic. +#define TRAP_SEQUENCE1_() __debugbreak() +#define TRAP_SEQUENCE2_() + +#elif V8_HOST_ARCH_ARM64 + +// Windows ARM64 uses "BRK #F000" as its breakpoint instruction, and +// __debugbreak() generates that in both VC++ and clang. +#define TRAP_SEQUENCE1_() __debugbreak() +// Intentionally empty: __builtin_unreachable() is always part of the sequence +// (see IMMEDIATE_CRASH below) and already emits a ud2 on Win64, +// https://crbug.com/958373 +#define TRAP_SEQUENCE2_() __asm volatile("") + +#else + +#define TRAP_SEQUENCE1_() asm volatile("int3") +#define TRAP_SEQUENCE2_() asm volatile("ud2") + +#endif // __clang__ + +#else + +#error No supported trap sequence! + +#endif // V8_CC_GNU + +#define TRAP_SEQUENCE_() \ + do { \ + TRAP_SEQUENCE1_(); \ + TRAP_SEQUENCE2_(); \ + } while (false) + +// CHECK() and the trap sequence can be invoked from a constexpr function. +// This could make compilation fail on GCC, as it forbids directly using inline +// asm inside a constexpr function. However, it allows calling a lambda +// expression including the same asm. +// The side effect is that the top of the stacktrace will not point to the +// calling function, but to this anonymous lambda. This is still useful as the +// full name of the lambda will typically include the name of the function that +// calls CHECK() and the debugger will still break at the right line of code. +#if !V8_CC_GNU + +#define WRAPPED_TRAP_SEQUENCE_() TRAP_SEQUENCE_() + +#else + +#define WRAPPED_TRAP_SEQUENCE_() \ + do { \ + [] { TRAP_SEQUENCE_(); }(); \ + } while (false) + +#endif // !V8_CC_GCC + +#if defined(__clang__) || V8_CC_GCC + +// __builtin_unreachable() hints to the compiler that this is noreturn and can +// be packed in the function epilogue. +#define IMMEDIATE_CRASH() \ + ({ \ + WRAPPED_TRAP_SEQUENCE_(); \ + __builtin_unreachable(); \ + }) + +#else + +// This is supporting build with MSVC where there is no __builtin_unreachable(). +#define IMMEDIATE_CRASH() WRAPPED_TRAP_SEQUENCE_() + +#endif // defined(__clang__) || defined(COMPILER_GCC) + +#endif // V8_BASE_IMMEDIATE_CRASH_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/iterator.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/iterator.h new file mode 100644 index 000000000..0bec87252 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/iterator.h @@ -0,0 +1,82 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_ITERATOR_H_ +#define V8_BASE_ITERATOR_H_ + +#include + +namespace v8 { +namespace base { + +template +struct iterator { + using iterator_category = Category; + using value_type = Type; + using difference_type = Diff; + using pointer = Pointer; + using reference = Reference; +}; + +// The intention of the base::iterator_range class is to encapsulate two +// iterators so that the range defined by the iterators can be used like +// a regular STL container (actually only a subset of the full container +// functionality is available usually). +template +class iterator_range { + public: + using iterator = ForwardIterator; + using const_iterator = ForwardIterator; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::reference; + using value_type = typename std::iterator_traits::value_type; + using difference_type = + typename std::iterator_traits::difference_type; + + iterator_range() : begin_(), end_() {} + iterator_range(ForwardIterator begin, ForwardIterator end) + : begin_(begin), end_(end) {} + + iterator begin() { return begin_; } + iterator end() { return end_; } + const_iterator begin() const { return begin_; } + const_iterator end() const { return end_; } + const_iterator cbegin() const { return begin_; } + const_iterator cend() const { return end_; } + + bool empty() const { return cbegin() == cend(); } + + // Random Access iterators only. + reference operator[](difference_type n) { return begin()[n]; } + difference_type size() const { return cend() - cbegin(); } + + private: + const_iterator const begin_; + const_iterator const end_; +}; + +template +auto make_iterator_range(ForwardIterator begin, ForwardIterator end) { + return iterator_range{begin, end}; +} + +// {Reversed} returns a container adapter usable in a range-based "for" +// statement for iterating a reversible container in reverse order. +// +// Example: +// +// std::vector v = ...; +// for (int i : base::Reversed(v)) { +// // iterates through v from back to front +// } +template +auto Reversed(T& t) { // NOLINT(runtime/references): match {rbegin} and {rend} + return make_iterator_range(std::rbegin(t), std::rend(t)); +} + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_ITERATOR_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/lazy-instance.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/lazy-instance.h index 3ea5fc957..75e5b0600 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/lazy-instance.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/lazy-instance.h @@ -235,12 +235,13 @@ class LeakyObject { new (&storage_) T(std::forward(args)...); } + LeakyObject(const LeakyObject&) = delete; + LeakyObject& operator=(const LeakyObject&) = delete; + T* get() { return reinterpret_cast(&storage_); } private: typename std::aligned_storage::type storage_; - - DISALLOW_COPY_AND_ASSIGN(LeakyObject); }; // Define a function which returns a pointer to a lazily initialized and never diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/logging.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/logging.h index 790018c98..08db24a94 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/logging.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/logging.h @@ -12,6 +12,7 @@ #include "src/base/base-export.h" #include "src/base/build_config.h" #include "src/base/compiler-specific.h" +#include "src/base/immediate-crash.h" #include "src/base/template-utils.h" V8_BASE_EXPORT V8_NOINLINE void V8_Dcheck(const char* file, int line, @@ -24,28 +25,25 @@ V8_BASE_EXPORT V8_NOINLINE void V8_Dcheck(const char* file, int line, void V8_Fatal(const char* file, int line, const char* format, ...); #define FATAL(...) V8_Fatal(__FILE__, __LINE__, __VA_ARGS__) -#elif !defined(OFFICIAL_BUILD) +#else +[[noreturn]] PRINTF_FORMAT(1, 2) V8_BASE_EXPORT V8_NOINLINE + void V8_Fatal(const char* format, ...); +#if !defined(OFFICIAL_BUILD) // In non-official release, include full error message, but drop file & line // numbers. It saves binary size to drop the |file| & |line| as opposed to just // passing in "", 0 for them. -[[noreturn]] PRINTF_FORMAT(1, 2) V8_BASE_EXPORT V8_NOINLINE - void V8_Fatal(const char* format, ...); #define FATAL(...) V8_Fatal(__VA_ARGS__) #else -// In official builds, include only messages that contain parameters because -// single-message errors can always be derived from stack traces. -[[noreturn]] V8_BASE_EXPORT V8_NOINLINE void V8_FatalNoContext(); -[[noreturn]] PRINTF_FORMAT(1, 2) V8_BASE_EXPORT V8_NOINLINE - void V8_Fatal(const char* format, ...); -// FATAL(msg) -> V8_FatalNoContext() -// FATAL(msg, ...) -> V8_Fatal() +// FATAL(msg) -> IMMEDIATE_CRASH() +// FATAL(msg, ...) -> V8_Fatal(msg, ...) #define FATAL_HELPER(_7, _6, _5, _4, _3, _2, _1, _0, ...) _0 -#define FATAL_DISCARD_ARG(arg) V8_FatalNoContext() +#define FATAL_DISCARD_ARG(arg) IMMEDIATE_CRASH() #define FATAL(...) \ FATAL_HELPER(__VA_ARGS__, V8_Fatal, V8_Fatal, V8_Fatal, V8_Fatal, V8_Fatal, \ - V8_Fatal, V8_Fatal, FATAL_DISCARD_ARG) \ + V8_Fatal, FATAL_DISCARD_ARG) \ (__VA_ARGS__) -#endif +#endif // !defined(OFFICIAL_BUILD) +#endif // DEBUG #define UNIMPLEMENTED() FATAL("unimplemented code") #define UNREACHABLE() FATAL("unreachable code") @@ -53,6 +51,8 @@ V8_BASE_EXPORT V8_NOINLINE void V8_Dcheck(const char* file, int line, namespace v8 { namespace base { +class CheckMessageStream : public std::ostringstream {}; + // Overwrite the default function that prints a stack trace. V8_BASE_EXPORT void SetPrintStackTrace(void (*print_stack_trace_)()); @@ -134,16 +134,37 @@ V8_BASE_EXPORT void SetDcheckFunction(void (*dcheck_Function)(const char*, int, #endif +namespace detail { +template +std::string PrintToString(Ts&&... ts) { + CheckMessageStream oss; + int unused_results[]{((oss << std::forward(ts)), 0)...}; + (void)unused_results; // Avoid "unused variable" warning. + return oss.str(); +} + +template +auto GetUnderlyingEnumTypeForPrinting(T val) { + using underlying_t = typename std::underlying_type::type; + // For single-byte enums, return a 16-bit integer to avoid printing the value + // as a character. + using int_t = typename std::conditional_t< + sizeof(underlying_t) != 1, underlying_t, + std::conditional_t::value, int16_t, + uint16_t> >; + return static_cast(static_cast(val)); +} +} // namespace detail + // Define PrintCheckOperand for each T which defines operator<< for ostream. template typename std::enable_if< !std::is_function::type>::value && - has_output_operator::value, + !std::is_enum::value && + has_output_operator::value, std::string>::type PrintCheckOperand(T val) { - std::ostringstream oss; - oss << std::forward(val); - return oss.str(); + return detail::PrintToString(std::forward(val)); } // Provide an overload for functions and function pointers. Function pointers @@ -159,23 +180,39 @@ PrintCheckOperand(T val) { return PrintCheckOperand(reinterpret_cast(val)); } -// Define PrintCheckOperand for enums which have no operator<<. +// Define PrintCheckOperand for enums with an output operator. template -typename std::enable_if< - std::is_enum::value && !has_output_operator::value, std::string>::type +typename std::enable_if::value && + has_output_operator::value, + std::string>::type PrintCheckOperand(T val) { - using underlying_t = typename std::underlying_type::type; - // 8-bit types are not printed as number, so extend them to 16 bit. - using int_t = typename std::conditional< - std::is_same::value, uint16_t, - typename std::conditional::value, - int16_t, underlying_t>::type>::type; - return PrintCheckOperand(static_cast(static_cast(val))); + std::string val_str = detail::PrintToString(val); + std::string int_str = + detail::PrintToString(detail::GetUnderlyingEnumTypeForPrinting(val)); + // Printing the original enum might have printed a single non-printable + // character. Ignore it in that case. Also ignore if it printed the same as + // the integral representation. + // TODO(clemensb): Can we somehow statically find out if the output operator + // is the default one, printing the integral value? + if ((val_str.length() == 1 && !std::isprint(val_str[0])) || + val_str == int_str) { + return int_str; + } + return detail::PrintToString(val_str, " (", int_str, ")"); +} + +// Define PrintCheckOperand for enums without an output operator. +template +typename std::enable_if::value && + !has_output_operator::value, + std::string>::type +PrintCheckOperand(T val) { + return detail::PrintToString(detail::GetUnderlyingEnumTypeForPrinting(val)); } // Define default PrintCheckOperand for non-printable types. template -typename std::enable_if::value && +typename std::enable_if::value && !std::is_enum::value, std::string>::type PrintCheckOperand(T val) { @@ -204,7 +241,7 @@ template V8_NOINLINE std::string* MakeCheckOpString(Lhs lhs, Rhs rhs, char const* msg) { std::string lhs_str = PrintCheckOperand(lhs); std::string rhs_str = PrintCheckOperand(rhs); - std::ostringstream ss; + CheckMessageStream ss; ss << msg; constexpr size_t kMaxInlineLength = 50; if (lhs_str.size() <= kMaxInlineLength && diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/macros.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/macros.h index e22dd0089..61644ffe0 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/macros.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/macros.h @@ -10,6 +10,7 @@ #include "src/base/compiler-specific.h" #include "src/base/logging.h" +#include "src/base/platform/wrappers.h" // No-op macro which is used to work around MSVC's funky VA_ARGS support. #define EXPAND(x) x @@ -17,6 +18,11 @@ // This macro does nothing. That's all. #define NOTHING(...) +#define CONCAT_(a, b) a##b +#define CONCAT(a, b) CONCAT_(a, b) +// Creates an unique identifier. Useful for scopes to avoid shadowing names. +#define UNIQUE_IDENTIFIER(base) CONCAT(base, __COUNTER__) + // TODO(all) Replace all uses of this macro with C++'s offsetof. To do that, we // have to make sure that only standard-layout types and simple field // designators are used. @@ -109,21 +115,17 @@ V8_INLINE Dest bit_cast(Source const& source) { } // Explicitly declare the assignment operator as deleted. +// Note: This macro is deprecated and will be removed soon. Please explicitly +// delete the assignment operator instead. #define DISALLOW_ASSIGN(TypeName) TypeName& operator=(const TypeName&) = delete -// Explicitly declare the copy constructor and assignment operator as deleted. -// This also deletes the implicit move constructor and implicit move assignment -// operator, but still allows to manually define them. -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ - DISALLOW_ASSIGN(TypeName) - // Explicitly declare all implicit constructors as deleted, namely the // default constructor, copy constructor and operator= functions. // This is especially useful for classes containing only static methods. #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ TypeName() = delete; \ - DISALLOW_COPY_AND_ASSIGN(TypeName) + TypeName(const TypeName&) = delete; \ + DISALLOW_ASSIGN(TypeName) // Disallow copying a type, but provide default construction, move construction // and move assignment. Especially useful for move-only structs. @@ -136,7 +138,8 @@ V8_INLINE Dest bit_cast(Source const& source) { #define MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(TypeName) \ TypeName(TypeName&&) V8_NOEXCEPT = default; \ TypeName& operator=(TypeName&&) V8_NOEXCEPT = default; \ - DISALLOW_COPY_AND_ASSIGN(TypeName) + TypeName(const TypeName&) = delete; \ + DISALLOW_ASSIGN(TypeName) // A macro to disallow the dynamic allocation. // This should be used in the private: declarations for a class @@ -157,13 +160,6 @@ V8_INLINE Dest bit_cast(Source const& source) { #endif #endif -// Define DISABLE_ASAN macro. -#ifdef V8_USE_ADDRESS_SANITIZER -#define DISABLE_ASAN __attribute__((no_sanitize_address)) -#else -#define DISABLE_ASAN -#endif - // Define V8_USE_MEMORY_SANITIZER macro. #if defined(__has_feature) #if __has_feature(memory_sanitizer) @@ -171,27 +167,25 @@ V8_INLINE Dest bit_cast(Source const& source) { #endif #endif -// Helper macro to define no_sanitize attributes only with clang. -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -#define CLANG_NO_SANITIZE(what) __attribute__((no_sanitize(what))) -#endif +// Define V8_USE_UNDEFINED_BEHAVIOR_SANITIZER macro. +#if defined(__has_feature) +#if __has_feature(undefined_behavior_sanitizer) +#define V8_USE_UNDEFINED_BEHAVIOR_SANITIZER 1 #endif -#if !defined(CLANG_NO_SANITIZE) -#define CLANG_NO_SANITIZE(what) #endif // DISABLE_CFI_PERF -- Disable Control Flow Integrity checks for Perf reasons. -#define DISABLE_CFI_PERF CLANG_NO_SANITIZE("cfi") +#define DISABLE_CFI_PERF V8_CLANG_NO_SANITIZE("cfi") // DISABLE_CFI_ICALL -- Disable Control Flow Integrity indirect call checks, // useful because calls into JITed code can not be CFI verified. -#define DISABLE_CFI_ICALL CLANG_NO_SANITIZE("cfi-icall") - -#if V8_CC_GNU -#define V8_IMMEDIATE_CRASH() __builtin_trap() +#ifdef V8_OS_WIN +// On Windows, also needs __declspec(guard(nocf)) for CFG. +#define DISABLE_CFI_ICALL \ + V8_CLANG_NO_SANITIZE("cfi-icall") \ + __declspec(guard(nocf)) #else -#define V8_IMMEDIATE_CRASH() ((void(*)())0)() +#define DISABLE_CFI_ICALL V8_CLANG_NO_SANITIZE("cfi-icall") #endif // A convenience wrapper around static_assert without a string message argument. @@ -257,12 +251,6 @@ struct Use { (void)unused_tmp_array_for_use_macro; \ } while (false) -// Evaluate the instantiations of an expression with parameter packs. -// Since USE has left-to-right evaluation order of it's arguments, -// the parameter pack is iterated from left to right and side effects -// have defined behavior. -#define ITERATE_PACK(...) USE(0, ((__VA_ARGS__), 0)...) - } // namespace base } // namespace v8 @@ -319,7 +307,7 @@ V8_INLINE A implicit_cast(A x) { #endif // Fix for Mac OS X defining uintptr_t as "unsigned long": -#if V8_OS_MACOSX +#if V8_OS_DARWIN #undef V8PRIxPTR #define V8PRIxPTR "lx" #undef V8PRIdPTR @@ -328,10 +316,10 @@ V8_INLINE A implicit_cast(A x) { #define V8PRIuPTR "lxu" #endif -// The following macro works on both 32 and 64-bit platforms. -// Usage: instead of writing 0x1234567890123456 -// write V8_2PART_UINT64_C(0x12345678,90123456); -#define V8_2PART_UINT64_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) +// Make a uint64 from two uint32_t halves. +inline uint64_t make_uint64(uint32_t high, uint32_t low) { + return (uint64_t{high} << 32) + low; +} // Return the largest multiple of m which is <= x. template @@ -339,14 +327,14 @@ inline T RoundDown(T x, intptr_t m) { STATIC_ASSERT(std::is_integral::value); // m must be a power of two. DCHECK(m != 0 && ((m & (m - 1)) == 0)); - return x & -m; + return x & static_cast(-m); } template constexpr inline T RoundDown(T x) { STATIC_ASSERT(std::is_integral::value); // m must be a power of two. STATIC_ASSERT(m != 0 && ((m & (m - 1)) == 0)); - return x & -m; + return x & static_cast(-m); } // Return the smallest multiple of m which is >= x. @@ -422,4 +410,27 @@ bool is_inbounds(float_t v) { #endif // V8_OS_WIN +// Defines IF_WASM, to be used in macro lists for elements that should only be +// there if WebAssembly is enabled. +#if V8_ENABLE_WEBASSEMBLY +// EXPAND is needed to work around MSVC's broken __VA_ARGS__ expansion. +#define IF_WASM(V, ...) EXPAND(V(__VA_ARGS__)) +#else +#define IF_WASM(V, ...) +#endif // V8_ENABLE_WEBASSEMBLY + +// Defines IF_TSAN, to be used in macro lists for elements that should only be +// there if TSAN is enabled. +#ifdef V8_IS_TSAN +// EXPAND is needed to work around MSVC's broken __VA_ARGS__ expansion. +#define IF_TSAN(V, ...) EXPAND(V(__VA_ARGS__)) +#else +#define IF_TSAN(V, ...) +#endif // V8_ENABLE_WEBASSEMBLY + +#ifdef GOOGLE3 +// Disable FRIEND_TEST macro in Google3. +#define FRIEND_TEST(test_case_name, test_name) +#endif + #endif // V8_BASE_MACROS_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/memory.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/memory.h index 087f67291..db6a9ea1d 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/memory.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/memory.h @@ -6,6 +6,7 @@ #define V8_BASE_MEMORY_H_ #include "src/base/macros.h" +#include "src/base/platform/wrappers.h" namespace v8 { namespace base { @@ -76,6 +77,9 @@ static inline V ReadLittleEndianValue(V* p) { template static inline void WriteLittleEndianValue(V* p, V value) { + static_assert( + !std::is_array::value, + "Passing an array decays to pointer, causing unexpected results."); WriteLittleEndianValue(reinterpret_cast
(p), value); } diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/once.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/once.h index dd8b6be62..98d88c127 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/once.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/once.h @@ -53,10 +53,12 @@ #define V8_BASE_ONCE_H_ #include + #include #include #include "src/base/base-export.h" +#include "src/base/template-utils.h" namespace v8 { namespace base { @@ -76,9 +78,9 @@ enum : uint8_t { using PointerArgFunction = void (*)(void* arg); -template -struct OneArgFunction { - using type = void (*)(T); +template +struct FunctionWithArgs { + using type = void (*)(Args...); }; V8_BASE_EXPORT void CallOnceImpl(OnceType* once, @@ -90,11 +92,13 @@ inline void CallOnce(OnceType* once, std::function init_func) { } } -template +template ...>>> inline void CallOnce(OnceType* once, - typename OneArgFunction::type init_func, Arg* arg) { + typename FunctionWithArgs::type init_func, + Args... args) { if (once->load(std::memory_order_acquire) != ONCE_STATE_DONE) { - CallOnceImpl(once, [=]() { init_func(arg); }); + CallOnceImpl(once, [=]() { init_func(args...); }); } } diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/optional.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/optional.h index 6610c7ffc..31fe9a972 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/optional.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/optional.h @@ -35,7 +35,7 @@ constexpr in_place_t in_place = {}; // http://en.cppreference.com/w/cpp/utility/optional/nullopt constexpr nullopt_t nullopt(0); -// Forward declaration, which is refered by following helpers. +// Forward declaration, which is referred by following helpers. template class Optional; @@ -557,32 +557,32 @@ class OPTIONAL_DECLSPEC_EMPTY_BASES Optional return *this; } - const T* operator->() const { + constexpr const T* operator->() const { DCHECK(storage_.is_populated_); return &storage_.value_; } - T* operator->() { + constexpr T* operator->() { DCHECK(storage_.is_populated_); return &storage_.value_; } - const T& operator*() const & { + constexpr const T& operator*() const& { DCHECK(storage_.is_populated_); return storage_.value_; } - T& operator*() & { + constexpr T& operator*() & { DCHECK(storage_.is_populated_); return storage_.value_; } - const T&& operator*() const && { + constexpr const T&& operator*() const&& { DCHECK(storage_.is_populated_); return std::move(storage_.value_); } - T&& operator*() && { + constexpr T&& operator*() && { DCHECK(storage_.is_populated_); return std::move(storage_.value_); } diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/overflowing-math.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/overflowing-math.h new file mode 100644 index 000000000..7ca58aefe --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/overflowing-math.h @@ -0,0 +1,89 @@ +// Copyright 2019 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_OVERFLOWING_MATH_H_ +#define V8_BASE_OVERFLOWING_MATH_H_ + +#include + +#include +#include + +#include "src/base/macros.h" + +namespace v8 { +namespace base { + +// Helpers for performing overflowing arithmetic operations without relying +// on C++ undefined behavior. +#define ASSERT_SIGNED_INTEGER_TYPE(Type) \ + static_assert(std::is_integral::value && std::is_signed::value, \ + "use this for signed integer types"); +#define OP_WITH_WRAPAROUND(Name, OP) \ + template \ + inline signed_type Name##WithWraparound(signed_type a, signed_type b) { \ + ASSERT_SIGNED_INTEGER_TYPE(signed_type); \ + using unsigned_type = typename std::make_unsigned::type; \ + unsigned_type a_unsigned = static_cast(a); \ + unsigned_type b_unsigned = static_cast(b); \ + unsigned_type result = a_unsigned OP b_unsigned; \ + return static_cast(result); \ + } + +OP_WITH_WRAPAROUND(Add, +) +OP_WITH_WRAPAROUND(Sub, -) +OP_WITH_WRAPAROUND(Mul, *) + +// 16-bit integers are special due to C++'s implicit conversion rules. +// See https://bugs.llvm.org/show_bug.cgi?id=25580. +template <> +inline int16_t MulWithWraparound(int16_t a, int16_t b) { + uint32_t a_unsigned = static_cast(a); + uint32_t b_unsigned = static_cast(b); + uint32_t result = a_unsigned * b_unsigned; + return static_cast(static_cast(result)); +} + +#undef OP_WITH_WRAPAROUND + +template +inline signed_type NegateWithWraparound(signed_type a) { + ASSERT_SIGNED_INTEGER_TYPE(signed_type); + if (a == std::numeric_limits::min()) return a; + return -a; +} + +template +inline signed_type ShlWithWraparound(signed_type a, signed_type b) { + ASSERT_SIGNED_INTEGER_TYPE(signed_type); + using unsigned_type = typename std::make_unsigned::type; + const unsigned_type kMask = (sizeof(a) * 8) - 1; + return static_cast(static_cast(a) << (b & kMask)); +} + +#undef ASSERT_SIGNED_INTEGER_TYPE + +// Returns the quotient x/y, avoiding C++ undefined behavior if y == 0. +template +inline T Divide(T x, T y) { + if (y != 0) return x / y; + if (x == 0 || x != x) return std::numeric_limits::quiet_NaN(); + if ((x >= 0) == (std::signbit(y) == 0)) { + return std::numeric_limits::infinity(); + } + return -std::numeric_limits::infinity(); +} + +inline float Recip(float a) { return Divide(1.0f, a); } + +inline float RecipSqrt(float a) { + if (a != 0) return 1.0f / std::sqrt(a); + if (std::signbit(a) == 0) return std::numeric_limits::infinity(); + return -std::numeric_limits::infinity(); +} + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_OVERFLOWING_MATH_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/page-allocator.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/page-allocator.h new file mode 100644 index 000000000..7374c6783 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/page-allocator.h @@ -0,0 +1,63 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_PAGE_ALLOCATOR_H_ +#define V8_BASE_PAGE_ALLOCATOR_H_ + +#include + +#include "include/v8-platform.h" +#include "src/base/base-export.h" +#include "src/base/compiler-specific.h" + +namespace v8 { +namespace base { + +class SharedMemory; + +class V8_BASE_EXPORT PageAllocator + : public NON_EXPORTED_BASE(::v8::PageAllocator) { + public: + PageAllocator(); + ~PageAllocator() override = default; + + size_t AllocatePageSize() override { return allocate_page_size_; } + + size_t CommitPageSize() override { return commit_page_size_; } + + void SetRandomMmapSeed(int64_t seed) override; + + void* GetRandomMmapAddr() override; + + void* AllocatePages(void* hint, size_t size, size_t alignment, + PageAllocator::Permission access) override; + + bool CanAllocateSharedPages() override; + + std::unique_ptr AllocateSharedPages( + size_t size, const void* original_address) override; + + bool FreePages(void* address, size_t size) override; + + bool ReleasePages(void* address, size_t size, size_t new_size) override; + + bool SetPermissions(void* address, size_t size, + PageAllocator::Permission access) override; + + bool DiscardSystemPages(void* address, size_t size) override; + + bool DecommitPages(void* address, size_t size) override; + + private: + friend class v8::base::SharedMemory; + + void* RemapShared(void* old_address, void* new_address, size_t size); + + const size_t allocate_page_size_; + const size_t commit_page_size_; +}; + +} // namespace base +} // namespace v8 +#endif // V8_BASE_PAGE_ALLOCATOR_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/condition-variable.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/condition-variable.h new file mode 100644 index 000000000..3ca6ba8d1 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/condition-variable.h @@ -0,0 +1,108 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_PLATFORM_CONDITION_VARIABLE_H_ +#define V8_BASE_PLATFORM_CONDITION_VARIABLE_H_ + +#include "src/base/base-export.h" +#include "src/base/lazy-instance.h" +#include "src/base/platform/mutex.h" + +#if V8_OS_STARBOARD +#include "starboard/common/condition_variable.h" +#endif + +namespace v8 { +namespace base { + +// Forward declarations. +class ConditionVariableEvent; +class TimeDelta; + +// ----------------------------------------------------------------------------- +// ConditionVariable +// +// This class is a synchronization primitive that can be used to block a thread, +// or multiple threads at the same time, until: +// - a notification is received from another thread, +// - a timeout expires, or +// - a spurious wakeup occurs +// Any thread that intends to wait on a ConditionVariable has to acquire a lock +// on a Mutex first. The |Wait()| and |WaitFor()| operations atomically release +// the mutex and suspend the execution of the calling thread. When the condition +// variable is notified, the thread is awakened, and the mutex is reacquired. + +class V8_BASE_EXPORT ConditionVariable final { + public: + ConditionVariable(); + ConditionVariable(const ConditionVariable&) = delete; + ConditionVariable& operator=(const ConditionVariable&) = delete; + ~ConditionVariable(); + + // If any threads are waiting on this condition variable, calling + // |NotifyOne()| unblocks one of the waiting threads. + void NotifyOne(); + + // Unblocks all threads currently waiting for this condition variable. + void NotifyAll(); + + // |Wait()| causes the calling thread to block until the condition variable is + // notified or a spurious wakeup occurs. Atomically releases the mutex, blocks + // the current executing thread, and adds it to the list of threads waiting on + // this condition variable. The thread will be unblocked when |NotifyAll()| or + // |NotifyOne()| is executed. It may also be unblocked spuriously. When + // unblocked, regardless of the reason, the lock on the mutex is reacquired + // and |Wait()| exits. + void Wait(Mutex* mutex); + + // Atomically releases the mutex, blocks the current executing thread, and + // adds it to the list of threads waiting on this condition variable. The + // thread will be unblocked when |NotifyAll()| or |NotifyOne()| is executed, + // or when the relative timeout |rel_time| expires. It may also be unblocked + // spuriously. When unblocked, regardless of the reason, the lock on the mutex + // is reacquired and |WaitFor()| exits. Returns true if the condition variable + // was notified prior to the timeout. + bool WaitFor(Mutex* mutex, const TimeDelta& rel_time) V8_WARN_UNUSED_RESULT; + + // The implementation-defined native handle type. +#if V8_OS_POSIX + using NativeHandle = pthread_cond_t; +#elif V8_OS_WIN + using NativeHandle = V8_CONDITION_VARIABLE; +#elif V8_OS_STARBOARD + using NativeHandle = SbConditionVariable; +#endif + + NativeHandle& native_handle() { + return native_handle_; + } + const NativeHandle& native_handle() const { + return native_handle_; + } + + private: + NativeHandle native_handle_; +}; + +// POD ConditionVariable initialized lazily (i.e. the first time Pointer() is +// called). +// Usage: +// static LazyConditionVariable my_condvar = +// LAZY_CONDITION_VARIABLE_INITIALIZER; +// +// void my_function() { +// MutexGuard lock_guard(&my_mutex); +// my_condvar.Pointer()->Wait(&my_mutex); +// } +using LazyConditionVariable = + LazyStaticInstance, + ThreadSafeInitOnceTrait>::type; + +#define LAZY_CONDITION_VARIABLE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_PLATFORM_CONDITION_VARIABLE_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/elapsed-timer.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/elapsed-timer.h new file mode 100644 index 000000000..c5ac56043 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/elapsed-timer.h @@ -0,0 +1,159 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_PLATFORM_ELAPSED_TIMER_H_ +#define V8_BASE_PLATFORM_ELAPSED_TIMER_H_ + +#include "src/base/logging.h" +#include "src/base/platform/time.h" + +namespace v8 { +namespace base { + +class ElapsedTimer final { + public: + ElapsedTimer() : start_ticks_() {} + + // Starts this timer. Once started a timer can be checked with + // |Elapsed()| or |HasExpired()|, and may be restarted using |Restart()|. + // This method must not be called on an already started timer. + void Start() { Start(Now()); } + + void Start(TimeTicks now) { + DCHECK(!now.IsNull()); + DCHECK(!IsStarted()); + set_start_ticks(now); +#ifdef DEBUG + started_ = true; +#endif + DCHECK(IsStarted()); + } + + // Stops this timer. Must not be called on a timer that was not + // started before. + void Stop() { + DCHECK(IsStarted()); + set_start_ticks(TimeTicks()); +#ifdef DEBUG + started_ = false; +#endif + DCHECK(!IsStarted()); + } + + // Returns |true| if this timer was started previously. + bool IsStarted() const { + DCHECK(!paused_); + DCHECK_NE(started_, start_ticks_.IsNull()); + return !start_ticks_.IsNull(); + } + +#if DEBUG + bool IsPaused() const { return paused_; } +#endif + + // Restarts the timer and returns the time elapsed since the previous start. + // This method is equivalent to obtaining the elapsed time with |Elapsed()| + // and then starting the timer again, but does so in one single operation, + // avoiding the need to obtain the clock value twice. It may only be called + // on a previously started timer. + TimeDelta Restart() { return Restart(Now()); } + + TimeDelta Restart(TimeTicks now) { + DCHECK(!now.IsNull()); + DCHECK(IsStarted()); + TimeDelta elapsed = now - start_ticks_; + DCHECK_GE(elapsed.InMicroseconds(), 0); + set_start_ticks(now); + DCHECK(IsStarted()); + return elapsed; + } + + void Pause() { Pause(Now()); } + + void Pause(TimeTicks now) { + TimeDelta elapsed = Elapsed(now); + DCHECK(IsStarted()); +#ifdef DEBUG + paused_ = true; +#endif + set_paused_elapsed(elapsed); + } + + void Resume() { Resume(Now()); } + + void Resume(TimeTicks now) { + DCHECK(!now.IsNull()); + DCHECK(started_); + DCHECK(paused_); + TimeDelta elapsed = paused_elapsed(); +#ifdef DEBUG + paused_ = false; +#endif + set_start_ticks(now - elapsed); + DCHECK(IsStarted()); + } + + // Returns the time elapsed since the previous start. This method may only + // be called on a previously started timer. + TimeDelta Elapsed() const { return Elapsed(Now()); } + + TimeDelta Elapsed(TimeTicks now) const { + DCHECK(!now.IsNull()); + DCHECK(IsStarted()); + TimeDelta elapsed = now - start_ticks(); + DCHECK_GE(elapsed.InMicroseconds(), 0); + return elapsed; + } + + // Returns |true| if the specified |time_delta| has elapsed since the + // previous start, or |false| if not. This method may only be called on + // a previously started timer. + bool HasExpired(TimeDelta time_delta) const { + DCHECK(IsStarted()); + return Elapsed() >= time_delta; + } + + private: + static V8_INLINE TimeTicks Now() { + TimeTicks now = TimeTicks::Now(); + DCHECK(!now.IsNull()); + return now; + } + + TimeDelta paused_elapsed() { + // Only used started_ since paused_elapsed_ can be 0. + DCHECK(paused_); + DCHECK(started_); + return paused_elapsed_; + } + + void set_paused_elapsed(TimeDelta delta) { + DCHECK(paused_); + DCHECK(started_); + paused_elapsed_ = delta; + } + + TimeTicks start_ticks() const { + DCHECK(!paused_); + return start_ticks_; + } + void set_start_ticks(TimeTicks start_ticks) { + DCHECK(!paused_); + start_ticks_ = start_ticks; + } + + union { + TimeTicks start_ticks_; + TimeDelta paused_elapsed_; + }; +#ifdef DEBUG + bool started_ = false; + bool paused_ = false; +#endif +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_PLATFORM_ELAPSED_TIMER_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/mutex.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/mutex.h index 5b3b31ec1..ce13d8d76 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/mutex.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/mutex.h @@ -7,13 +7,20 @@ #include "src/base/base-export.h" #include "src/base/lazy-instance.h" +#include "src/base/optional.h" #if V8_OS_WIN #include "src/base/win32-headers.h" #endif #include "src/base/logging.h" #if V8_OS_POSIX -#include // NOLINT +#include +#endif + +#if V8_OS_STARBOARD +#include "starboard/common/mutex.h" +#include "starboard/common/recursive_mutex.h" +#include "starboard/common/rwlock.h" #endif namespace v8 { @@ -37,6 +44,8 @@ namespace base { class V8_BASE_EXPORT Mutex final { public: Mutex(); + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; ~Mutex(); // Locks the given mutex. If the mutex is currently unlocked, it becomes @@ -57,7 +66,9 @@ class V8_BASE_EXPORT Mutex final { #if V8_OS_POSIX using NativeHandle = pthread_mutex_t; #elif V8_OS_WIN - using NativeHandle = SRWLOCK; + using NativeHandle = V8_SRWLOCK; +#elif V8_OS_STARBOARD + using NativeHandle = SbMutex; #endif NativeHandle& native_handle() { @@ -67,7 +78,8 @@ class V8_BASE_EXPORT Mutex final { return native_handle_; } - V8_INLINE void AssertHeld() { DCHECK_EQ(1, level_); } + V8_INLINE void AssertHeld() const { DCHECK_EQ(1, level_); } + V8_INLINE void AssertUnheld() const { DCHECK_EQ(0, level_); } private: NativeHandle native_handle_; @@ -90,8 +102,6 @@ class V8_BASE_EXPORT Mutex final { } friend class ConditionVariable; - - DISALLOW_COPY_AND_ASSIGN(Mutex); }; // POD Mutex initialized lazily (i.e. the first time Pointer() is called). @@ -131,6 +141,8 @@ using LazyMutex = LazyStaticInstance, class V8_BASE_EXPORT RecursiveMutex final { public: RecursiveMutex(); + RecursiveMutex(const RecursiveMutex&) = delete; + RecursiveMutex& operator=(const RecursiveMutex&) = delete; ~RecursiveMutex(); // Locks the mutex. If another thread has already locked the mutex, a call to @@ -152,20 +164,22 @@ class V8_BASE_EXPORT RecursiveMutex final { // successfully locked. bool TryLock() V8_WARN_UNUSED_RESULT; + V8_INLINE void AssertHeld() const { DCHECK_LT(0, level_); } + private: // The implementation-defined native handle type. #if V8_OS_POSIX using NativeHandle = pthread_mutex_t; #elif V8_OS_WIN - using NativeHandle = CRITICAL_SECTION; + using NativeHandle = V8_CRITICAL_SECTION; +#elif V8_OS_STARBOARD + using NativeHandle = starboard::RecursiveMutex; #endif NativeHandle native_handle_; #ifdef DEBUG int level_; #endif - - DISALLOW_COPY_AND_ASSIGN(RecursiveMutex); }; @@ -202,55 +216,69 @@ using LazyRecursiveMutex = class V8_BASE_EXPORT SharedMutex final { public: SharedMutex(); + SharedMutex(const SharedMutex&) = delete; + SharedMutex& operator=(const SharedMutex&) = delete; ~SharedMutex(); // Acquires shared ownership of the {SharedMutex}. If another thread is // holding the mutex in exclusive ownership, a call to {LockShared()} will // block execution until shared ownership can be acquired. // If {LockShared()} is called by a thread that already owns the mutex in any - // mode (exclusive or shared), the behavior is undefined. + // mode (exclusive or shared), the behavior is undefined and outright fails + // with dchecks on. void LockShared(); // Locks the SharedMutex. If another thread has already locked the mutex, a // call to {LockExclusive()} will block execution until the lock is acquired. // If {LockExclusive()} is called by a thread that already owns the mutex in - // any mode (shared or exclusive), the behavior is undefined. + // any mode (shared or exclusive), the behavior is undefined and outright + // fails with dchecks on. void LockExclusive(); // Releases the {SharedMutex} from shared ownership by the calling thread. // The mutex must be locked by the current thread of execution in shared mode, - // otherwise, the behavior is undefined. + // otherwise, the behavior is undefined and outright fails with dchecks on. void UnlockShared(); // Unlocks the {SharedMutex}. It must be locked by the current thread of - // execution, otherwise, the behavior is undefined. + // execution, otherwise, the behavior is undefined and outright fails with + // dchecks on. void UnlockExclusive(); // Tries to lock the {SharedMutex} in shared mode. Returns immediately. On // successful lock acquisition returns true, otherwise returns false. // This function is allowed to fail spuriously and return false even if the // mutex is not currenly exclusively locked by any other thread. + // If it is called by a thread that already owns the mutex in any mode + // (shared or exclusive), the behavior is undefined, and outright fails with + // dchecks on. bool TryLockShared() V8_WARN_UNUSED_RESULT; // Tries to lock the {SharedMutex}. Returns immediately. On successful lock // acquisition returns true, otherwise returns false. // This function is allowed to fail spuriously and return false even if the // mutex is not currently locked by any other thread. - // If try_lock is called by a thread that already owns the mutex in any mode - // (shared or exclusive), the behavior is undefined. + // If it is called by a thread that already owns the mutex in any mode + // (shared or exclusive), the behavior is undefined, and outright fails with + // dchecks on. bool TryLockExclusive() V8_WARN_UNUSED_RESULT; private: // The implementation-defined native handle type. -#if V8_OS_POSIX +#if V8_OS_DARWIN + // pthread_rwlock_t is broken on MacOS when signals are being sent to the + // process (see https://crbug.com/v8/11399). Until Apple fixes that in the OS, + // we have to fall back to a non-shared mutex. + using NativeHandle = pthread_mutex_t; +#elif V8_OS_POSIX using NativeHandle = pthread_rwlock_t; #elif V8_OS_WIN - using NativeHandle = SRWLOCK; + using NativeHandle = V8_SRWLOCK; +#elif V8_OS_STARBOARD + using NativeHandle = starboard::RWLock; #endif NativeHandle native_handle_; - - DISALLOW_COPY_AND_ASSIGN(SharedMutex); }; // ----------------------------------------------------------------------------- @@ -268,11 +296,13 @@ class V8_BASE_EXPORT SharedMutex final { enum class NullBehavior { kRequireNotNull, kIgnoreIfNull }; template -class LockGuard final { +class V8_NODISCARD LockGuard final { public: explicit LockGuard(Mutex* mutex) : mutex_(mutex) { if (has_mutex()) mutex_->Lock(); } + LockGuard(const LockGuard&) = delete; + LockGuard& operator=(const LockGuard&) = delete; ~LockGuard() { if (has_mutex()) mutex_->Unlock(); } @@ -285,8 +315,6 @@ class LockGuard final { mutex_ != nullptr); return Behavior == NullBehavior::kRequireNotNull || mutex_ != nullptr; } - - DISALLOW_COPY_AND_ASSIGN(LockGuard); }; using MutexGuard = LockGuard; @@ -296,7 +324,7 @@ enum MutexSharedType : bool { kShared = true, kExclusive = false }; template -class SharedMutexGuard final { +class V8_NODISCARD SharedMutexGuard final { public: explicit SharedMutexGuard(SharedMutex* mutex) : mutex_(mutex) { if (!has_mutex()) return; @@ -306,6 +334,8 @@ class SharedMutexGuard final { mutex_->LockExclusive(); } } + SharedMutexGuard(const SharedMutexGuard&) = delete; + SharedMutexGuard& operator=(const SharedMutexGuard&) = delete; ~SharedMutexGuard() { if (!has_mutex()) return; if (kIsShared) { @@ -323,8 +353,20 @@ class SharedMutexGuard final { mutex_ != nullptr); return Behavior == NullBehavior::kRequireNotNull || mutex_ != nullptr; } +}; + +template +class V8_NODISCARD SharedMutexGuardIf final { + public: + SharedMutexGuardIf(SharedMutex* mutex, bool enable_mutex) { + if (enable_mutex) mutex_.emplace(mutex); + } + SharedMutexGuardIf(const SharedMutexGuardIf&) = delete; + SharedMutexGuardIf& operator=(const SharedMutexGuardIf&) = delete; - DISALLOW_COPY_AND_ASSIGN(SharedMutexGuard); + private: + base::Optional> mutex_; }; } // namespace base diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform-linux.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform-linux.h new file mode 100644 index 000000000..1bc5af18c --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform-linux.h @@ -0,0 +1,37 @@ +// Copyright 2022 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_PLATFORM_PLATFORM_LINUX_H_ +#define V8_BASE_PLATFORM_PLATFORM_LINUX_H_ + +#include + +#include +#include + +#include "src/base/base-export.h" +#include "src/base/optional.h" + +namespace v8 { +namespace base { + +// Represents a memory region, as parsed from /proc/PID/maps. +// Visible for testing. +struct V8_BASE_EXPORT MemoryRegion { + uintptr_t start; + uintptr_t end; + char permissions[5]; + off_t offset; + dev_t dev; + ino_t inode; + std::string pathname; + + // |line| must not contains the tail '\n'. + static base::Optional FromMapsLine(const char* line); +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_PLATFORM_PLATFORM_LINUX_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform-posix-time.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform-posix-time.h new file mode 100644 index 000000000..7814296b8 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform-posix-time.h @@ -0,0 +1,24 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_PLATFORM_PLATFORM_POSIX_TIME_H_ +#define V8_BASE_PLATFORM_PLATFORM_POSIX_TIME_H_ + +#include "src/base/platform/platform-posix.h" + +namespace v8 { +namespace base { + +class PosixDefaultTimezoneCache : public PosixTimezoneCache { + public: + const char* LocalTimezone(double time_ms) override; + double LocalTimeOffset(double time_ms, bool is_utc) override; + + ~PosixDefaultTimezoneCache() override = default; +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_PLATFORM_PLATFORM_POSIX_TIME_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform-posix.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform-posix.h new file mode 100644 index 000000000..13f40053d --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform-posix.h @@ -0,0 +1,34 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_PLATFORM_PLATFORM_POSIX_H_ +#define V8_BASE_PLATFORM_PLATFORM_POSIX_H_ + +#include "include/v8config.h" +#include "src/base/platform/platform.h" +#include "src/base/timezone-cache.h" + +namespace v8 { +namespace base { + +void PosixInitializeCommon(bool hard_abort, const char* const gc_fake_mmap); + +class PosixTimezoneCache : public TimezoneCache { + public: + double DaylightSavingsOffset(double time_ms) override; + void Clear(TimeZoneDetection) override {} + ~PosixTimezoneCache() override = default; + + protected: + static const int msPerSecond = 1000; +}; + +#if !V8_OS_FUCHSIA +int GetProtectionFromMemoryPermission(OS::MemoryPermission access); +#endif + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_PLATFORM_PLATFORM_POSIX_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform.h index af55036a0..f67d5c079 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/platform.h @@ -22,23 +22,42 @@ #define V8_BASE_PLATFORM_PLATFORM_H_ #include +#include #include #include +#include "include/v8-platform.h" #include "src/base/base-export.h" #include "src/base/build_config.h" #include "src/base/compiler-specific.h" +#include "src/base/optional.h" #include "src/base/platform/mutex.h" #include "src/base/platform/semaphore.h" +#include "testing/gtest/include/gtest/gtest_prod.h" // nogncheck #if V8_OS_QNX #include "src/base/qnx-math.h" #endif +#if V8_OS_FUCHSIA +#include +#endif // V8_OS_FUCHSIA + #ifdef V8_USE_ADDRESS_SANITIZER #include #endif // V8_USE_ADDRESS_SANITIZER +#ifndef V8_NO_FAST_TLS +#if V8_CC_MSVC && V8_HOST_ARCH_IA32 +// __readfsdword is supposed to be declared in intrin.h but it is missing from +// some versions of that file. See https://bugs.llvm.org/show_bug.cgi?id=51188 +// And, intrin.h is a very expensive header that we want to avoid here, and +// the cheaper intrin0.h is not available for all build configurations. That is +// why we declare this intrinsic. +extern "C" unsigned long __readfsdword(unsigned long); // NOLINT(runtime/int) +#endif // V8_CC_MSVC && V8_HOST_ARCH_IA32 +#endif // V8_NO_FAST_TLS + namespace v8 { namespace base { @@ -67,13 +86,16 @@ inline intptr_t InternalGetExistingThreadLocal(intptr_t index) { __readfsdword(kTibInlineTlsOffset + kSystemPointerSize * index)); } intptr_t extra = static_cast(__readfsdword(kTibExtraTlsOffset)); - DCHECK_NE(extra, 0); + if (!extra) return 0; return *reinterpret_cast(extra + kSystemPointerSize * (index - kMaxInlineSlots)); } #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64) +// tvOS simulator does not use intptr_t as TLS key. +#if !defined(V8_OS_STARBOARD) || !defined(TARGET_OS_SIMULATOR) + #define V8_FAST_TLS_SUPPORTED 1 extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset; @@ -94,12 +116,17 @@ inline intptr_t InternalGetExistingThreadLocal(intptr_t index) { return result; } +#endif // !defined(V8_OS_STARBOARD) || !defined(TARGET_OS_SIMULATOR) + #endif #endif // V8_NO_FAST_TLS +class AddressSpaceReservation; class PageAllocator; class TimezoneCache; +class VirtualAddressSpace; +class VirtualAddressSubspace; // ---------------------------------------------------------------------------- // OS @@ -115,6 +142,17 @@ class V8_BASE_EXPORT OS { // - gc_fake_mmap: Name of the file for fake gc mmap used in ll_prof. static void Initialize(bool hard_abort, const char* const gc_fake_mmap); +#if V8_OS_WIN + // On Windows, ensure the newer memory API is loaded if available. This + // includes function like VirtualAlloc2 and MapViewOfFile3. + // TODO(chromium:1218005) this should probably happen as part of Initialize, + // but that is currently invoked too late, after the sandbox is initialized. + // However, eventually the sandbox initialization will probably happen as + // part of V8::Initialize, at which point this function can probably be + // merged into OS::Initialize. + static void EnsureWin32MemoryAPILoaded(); +#endif + // Returns the accumulated user time for thread. This routine // can be used for profiling. The implementation should // strive for high-precision timer resolution, preferable @@ -160,16 +198,23 @@ class V8_BASE_EXPORT OS { static PRINTF_FORMAT(1, 0) void VPrintError(const char* format, va_list args); // Memory permissions. These should be kept in sync with the ones in - // v8::PageAllocator. + // v8::PageAllocator and v8::PagePermissions. enum class MemoryPermission { kNoAccess, kRead, kReadWrite, - // TODO(hpayer): Remove this flag. Memory should never be rwx. kReadWriteExecute, - kReadExecute + kReadExecute, + // TODO(jkummerow): Remove this when Wasm has a platform-independent + // w^x implementation. + kNoAccessWillJitLater }; + // Helpers to create shared memory objects. Currently only used for testing. + static PlatformSharedMemoryHandle CreateSharedMemoryHandleForTesting( + size_t size); + static void DestroySharedMemoryHandle(PlatformSharedMemoryHandle handle); + static bool HasLazyCommits(); // Sleep for a specified time interval. @@ -254,13 +299,55 @@ class V8_BASE_EXPORT OS { static void AdjustSchedulingParams(); - static void ExitProcess(int exit_code); + using Address = uintptr_t; + + struct MemoryRange { + uintptr_t start = 0; + uintptr_t end = 0; + }; + + // Find gaps between existing virtual memory ranges that have enough space + // to place a region with minimum_size within (boundary_start, boundary_end) + static std::vector GetFreeMemoryRangesWithin( + Address boundary_start, Address boundary_end, size_t minimum_size, + size_t alignment); + + [[noreturn]] static void ExitProcess(int exit_code); + + // Whether the platform supports mapping a given address in another location + // in the address space. + V8_WARN_UNUSED_RESULT static constexpr bool IsRemapPageSupported() { +#if defined(V8_OS_MACOS) || defined(V8_OS_LINUX) + return true; +#else + return false; +#endif + } + + // Remaps already-mapped memory at |new_address| with |access| permissions. + // + // Both the source and target addresses must be page-aligned, and |size| must + // be a multiple of the system page size. If there is already memory mapped + // at the target address, it is replaced by the new mapping. + // + // In addition, this is only meant to remap memory which is file-backed, and + // mapped from a file which is still accessible. + // + // Must not be called if |IsRemapPagesSupported()| return false. + // Returns true for success. + V8_WARN_UNUSED_RESULT static bool RemapPages(const void* address, size_t size, + void* new_address, + MemoryPermission access); private: // These classes use the private memory management API below. + friend class AddressSpaceReservation; friend class MemoryMappedFile; friend class PosixMemoryMappedFile; friend class v8::base::PageAllocator; + friend class v8::base::VirtualAddressSpace; + friend class v8::base::VirtualAddressSubspace; + FRIEND_TEST(OS, RemapPages); static size_t AllocatePageSize(); @@ -274,9 +361,22 @@ class V8_BASE_EXPORT OS { size_t alignment, MemoryPermission access); - V8_WARN_UNUSED_RESULT static bool Free(void* address, const size_t size); + V8_WARN_UNUSED_RESULT static void* AllocateShared(size_t size, + MemoryPermission access); + + V8_WARN_UNUSED_RESULT static void* RemapShared(void* old_address, + void* new_address, + size_t size); + + static void Free(void* address, size_t size); + + V8_WARN_UNUSED_RESULT static void* AllocateShared( + void* address, size_t size, OS::MemoryPermission access, + PlatformSharedMemoryHandle handle, uint64_t offset); + + static void FreeShared(void* address, size_t size); - V8_WARN_UNUSED_RESULT static bool Release(void* address, size_t size); + static void Release(void* address, size_t size); V8_WARN_UNUSED_RESULT static bool SetPermissions(void* address, size_t size, MemoryPermission access); @@ -284,6 +384,16 @@ class V8_BASE_EXPORT OS { V8_WARN_UNUSED_RESULT static bool DiscardSystemPages(void* address, size_t size); + V8_WARN_UNUSED_RESULT static bool DecommitPages(void* address, size_t size); + + V8_WARN_UNUSED_RESULT static bool CanReserveAddressSpace(); + + V8_WARN_UNUSED_RESULT static Optional + CreateAddressSpaceReservation(void* hint, size_t size, size_t alignment, + MemoryPermission max_permission); + + static void FreeAddressSpaceReservation(AddressSpaceReservation reservation); + static const int msPerSecond = 1000; #if V8_OS_POSIX @@ -305,6 +415,84 @@ inline void EnsureConsoleOutput() { #endif // (defined(_WIN32) || defined(_WIN64)) } +// ---------------------------------------------------------------------------- +// AddressSpaceReservation +// +// This class provides the same memory management functions as OS but operates +// inside a previously reserved contiguous region of virtual address space. +// +// Reserved address space in which no pages have been allocated is guaranteed +// to be inaccessible and cause a fault on access. As such, creating guard +// regions requires no further action. +class V8_BASE_EXPORT AddressSpaceReservation { + public: + using Address = uintptr_t; + + void* base() const { return base_; } + size_t size() const { return size_; } + + bool Contains(void* region_addr, size_t region_size) const { + Address base = reinterpret_cast
(base_); + Address region_base = reinterpret_cast
(region_addr); + return (region_base >= base) && + ((region_base + region_size) <= (base + size_)); + } + + V8_WARN_UNUSED_RESULT bool Allocate(void* address, size_t size, + OS::MemoryPermission access); + + V8_WARN_UNUSED_RESULT bool Free(void* address, size_t size); + + V8_WARN_UNUSED_RESULT bool AllocateShared(void* address, size_t size, + OS::MemoryPermission access, + PlatformSharedMemoryHandle handle, + uint64_t offset); + + V8_WARN_UNUSED_RESULT bool FreeShared(void* address, size_t size); + + V8_WARN_UNUSED_RESULT bool SetPermissions(void* address, size_t size, + OS::MemoryPermission access); + + V8_WARN_UNUSED_RESULT bool DiscardSystemPages(void* address, size_t size); + + V8_WARN_UNUSED_RESULT bool DecommitPages(void* address, size_t size); + + V8_WARN_UNUSED_RESULT Optional CreateSubReservation( + void* address, size_t size, OS::MemoryPermission max_permission); + + V8_WARN_UNUSED_RESULT static bool FreeSubReservation( + AddressSpaceReservation reservation); + +#if V8_OS_WIN + // On Windows, the placeholder mappings backing address space reservations + // need to be split and merged as page allocations can only replace an entire + // placeholder mapping, not parts of it. This must be done by the users of + // this API as it requires a RegionAllocator (or equivalent) to keep track of + // sub-regions and decide when to split and when to coalesce multiple free + // regions into a single one. + V8_WARN_UNUSED_RESULT bool SplitPlaceholder(void* address, size_t size); + V8_WARN_UNUSED_RESULT bool MergePlaceholders(void* address, size_t size); +#endif // V8_OS_WIN + + private: + friend class OS; + +#if V8_OS_FUCHSIA + AddressSpaceReservation(void* base, size_t size, zx_handle_t vmar) + : base_(base), size_(size), vmar_(vmar) {} +#else + AddressSpaceReservation(void* base, size_t size) : base_(base), size_(size) {} +#endif // V8_OS_FUCHSIA + + void* base_ = nullptr; + size_t size_ = 0; + +#if V8_OS_FUCHSIA + // On Fuchsia, address space reservations are backed by VMARs. + zx_handle_t vmar_ = ZX_HANDLE_INVALID; +#endif // V8_OS_FUCHSIA +}; + // ---------------------------------------------------------------------------- // Thread // @@ -316,7 +504,11 @@ inline void EnsureConsoleOutput() { class V8_BASE_EXPORT Thread { public: // Opaque data type for thread-local storage keys. +#if V8_OS_STARBOARD + using LocalStorageKey = SbThreadLocalKey; +#else using LocalStorageKey = int32_t; +#endif class Options { public: @@ -334,6 +526,8 @@ class V8_BASE_EXPORT Thread { // Create new thread. explicit Thread(const Options& options); + Thread(const Thread&) = delete; + Thread& operator=(const Thread&) = delete; virtual ~Thread(); // Start new thread by calling the Run() method on the new thread. @@ -363,13 +557,7 @@ class V8_BASE_EXPORT Thread { static LocalStorageKey CreateThreadLocalKey(); static void DeleteThreadLocalKey(LocalStorageKey key); static void* GetThreadLocal(LocalStorageKey key); - static int GetThreadLocalInt(LocalStorageKey key) { - return static_cast(reinterpret_cast(GetThreadLocal(key))); - } static void SetThreadLocal(LocalStorageKey key, void* value); - static void SetThreadLocalInt(LocalStorageKey key, int value) { - SetThreadLocal(key, reinterpret_cast(static_cast(value))); - } static bool HasThreadLocal(LocalStorageKey key) { return GetThreadLocal(key) != nullptr; } @@ -407,37 +595,48 @@ class V8_BASE_EXPORT Thread { char name_[kMaxThreadNameLength]; int stack_size_; Semaphore* start_semaphore_; - - DISALLOW_COPY_AND_ASSIGN(Thread); }; // TODO(v8:10354): Make use of the stack utilities here in V8. class V8_BASE_EXPORT Stack { public: + // Convenience wrapper to use stack slots as unsigned values or void* + // pointers. + struct StackSlot { + // NOLINTNEXTLINE + StackSlot(void* value) : value(reinterpret_cast(value)) {} + StackSlot(uintptr_t value) : value(value) {} // NOLINT + + // NOLINTNEXTLINE + operator void*() const { return reinterpret_cast(value); } + operator uintptr_t() const { return value; } // NOLINT + + uintptr_t value; + }; + // Gets the start of the stack of the current thread. - static void* GetStackStart(); + static StackSlot GetStackStart(); // Returns the current stack top. Works correctly with ASAN and SafeStack. // GetCurrentStackPosition() should not be inlined, because it works on stack // frames if it were inlined into a function with a huge stack frame it would // return an address significantly above the actual current stack position. - static V8_NOINLINE void* GetCurrentStackPosition(); + static V8_NOINLINE StackSlot GetCurrentStackPosition(); - // Translates an ASAN-based slot to a real stack slot if necessary. - static void* GetStackSlot(void* slot) { + // Returns the real stack frame if slot is part of a fake frame, and slot + // otherwise. + static StackSlot GetRealStackAddressForSlot(StackSlot slot) { #ifdef V8_USE_ADDRESS_SANITIZER - void* fake_stack = __asan_get_current_fake_stack(); - if (fake_stack) { - void* fake_frame_start; - void* real_frame = __asan_addr_is_in_fake_stack( - fake_stack, slot, &fake_frame_start, nullptr); - if (real_frame) { - return reinterpret_cast( - reinterpret_cast(real_frame) + - (reinterpret_cast(slot) - - reinterpret_cast(fake_frame_start))); - } - } + // ASAN fetches the real stack deeper in the __asan_addr_is_in_fake_stack() + // call (precisely, deeper in __asan_stack_malloc_()), which results in a + // real frame that could be outside of stack bounds. Adjust for this + // impreciseness here. + constexpr size_t kAsanRealFrameOffsetBytes = 32; + void* real_frame = __asan_addr_is_in_fake_stack( + __asan_get_current_fake_stack(), slot, nullptr, nullptr); + return real_frame + ? (static_cast(real_frame) + kAsanRealFrameOffsetBytes) + : slot; #endif // V8_USE_ADDRESS_SANITIZER return slot; } diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/semaphore.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/semaphore.h index c4937acad..2d5b50bca 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/semaphore.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/semaphore.h @@ -11,10 +11,14 @@ #include "src/base/win32-headers.h" #endif -#if V8_OS_MACOSX -#include // NOLINT +#if V8_OS_DARWIN +#include #elif V8_OS_POSIX -#include // NOLINT +#include +#endif + +#if V8_OS_STARBOARD +#include "starboard/common/semaphore.h" #endif namespace v8 { @@ -35,6 +39,8 @@ class TimeDelta; class V8_BASE_EXPORT Semaphore final { public: explicit Semaphore(int count); + Semaphore(const Semaphore&) = delete; + Semaphore& operator=(const Semaphore&) = delete; ~Semaphore(); // Increments the semaphore counter. @@ -49,12 +55,14 @@ class V8_BASE_EXPORT Semaphore final { // the semaphore counter is decremented and true is returned. bool WaitFor(const TimeDelta& rel_time) V8_WARN_UNUSED_RESULT; -#if V8_OS_MACOSX +#if V8_OS_DARWIN using NativeHandle = dispatch_semaphore_t; #elif V8_OS_POSIX using NativeHandle = sem_t; #elif V8_OS_WIN using NativeHandle = HANDLE; +#elif V8_OS_STARBOARD + using NativeHandle = starboard::Semaphore; #endif NativeHandle& native_handle() { @@ -66,8 +74,6 @@ class V8_BASE_EXPORT Semaphore final { private: NativeHandle native_handle_; - - DISALLOW_COPY_AND_ASSIGN(Semaphore); }; diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/time.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/time.h index 5f69129ec..d4be4109f 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/time.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/time.h @@ -14,6 +14,7 @@ #include "src/base/base-export.h" #include "src/base/bits.h" #include "src/base/macros.h" +#include "src/base/safe_conversions.h" #if V8_OS_WIN #include "src/base/win32-headers.h" #endif @@ -36,7 +37,7 @@ class TimeTicks; namespace time_internal { template class TimeBase; -} +} // namespace time_internal class TimeConstants { public: @@ -90,6 +91,14 @@ class V8_BASE_EXPORT TimeDelta final { return TimeDelta(nanoseconds / TimeConstants::kNanosecondsPerMicrosecond); } + static TimeDelta FromSecondsD(double seconds) { + return FromDouble(seconds * TimeConstants::kMicrosecondsPerSecond); + } + static TimeDelta FromMillisecondsD(double milliseconds) { + return FromDouble(milliseconds * + TimeConstants::kMicrosecondsPerMillisecond); + } + // Returns the maximum time delta, which should be greater than any reasonable // time delta we might compare it to. Adding or subtracting the maximum time // delta to a time or another time delta has an undefined result. @@ -201,6 +210,9 @@ class V8_BASE_EXPORT TimeDelta final { } private: + // TODO(v8:10620): constexpr requires constexpr saturated_cast. + static inline TimeDelta FromDouble(double value); + template friend class time_internal::TimeBase; // Constructs a delta given the duration in microseconds. This is private // to avoid confusion by callers with an integer constructor. Use @@ -211,6 +223,11 @@ class V8_BASE_EXPORT TimeDelta final { int64_t delta_; }; +// static +TimeDelta TimeDelta::FromDouble(double value) { + return TimeDelta(saturated_cast(value)); +} + // static constexpr TimeDelta TimeDelta::Max() { return TimeDelta(std::numeric_limits::max()); @@ -416,11 +433,6 @@ class V8_BASE_EXPORT TimeTicks final // This method never returns a null TimeTicks. static TimeTicks Now(); - // This is equivalent to Now() but DCHECKs that IsHighResolution(). Useful for - // test frameworks that rely on high resolution clocks (in practice all - // platforms but low-end Windows devices have high resolution clocks). - static TimeTicks HighResolutionNow(); - // Returns true if the high-resolution clock is working on this system. static bool IsHighResolution(); diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/wrappers.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/wrappers.h new file mode 100644 index 000000000..5de31b416 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/wrappers.h @@ -0,0 +1,70 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_PLATFORM_WRAPPERS_H_ +#define V8_BASE_PLATFORM_WRAPPERS_H_ + +#include +#include +#include +#include + +#include "src/base/base-export.h" + +#if defined(V8_OS_STARBOARD) +#include "starboard/memory.h" +#include "starboard/string.h" +#endif + +namespace v8 { +namespace base { + +#if !defined(V8_OS_STARBOARD) + +// Common libstd implementations. +// inline implementations are preferred here due to performance concerns. +inline void* Malloc(size_t size) { return malloc(size); } + +inline void* Realloc(void* memory, size_t size) { + return realloc(memory, size); +} + +inline void Free(void* memory) { return free(memory); } + +inline void* Calloc(size_t count, size_t size) { return calloc(count, size); } + +inline char* Strdup(const char* source) { return strdup(source); } + +inline FILE* Fopen(const char* filename, const char* mode) { + return fopen(filename, mode); +} + +inline int Fclose(FILE* stream) { return fclose(stream); } + +#else // V8_OS_STARBOARD + +inline void* Malloc(size_t size) { return SbMemoryAllocate(size); } + +inline void* Realloc(void* memory, size_t size) { + return SbMemoryReallocate(memory, size); +} + +inline void Free(void* memory) { return SbMemoryDeallocate(memory); } + +inline void* Calloc(size_t count, size_t size) { + return SbMemoryCalloc(count, size); +} + +inline char* Strdup(const char* source) { return SbStringDuplicate(source); } + +inline FILE* Fopen(const char* filename, const char* mode) { return NULL; } + +inline int Fclose(FILE* stream) { return -1; } + +#endif // V8_OS_STARBOARD + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_PLATFORM_WRAPPERS_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/yield-processor.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/yield-processor.h new file mode 100644 index 000000000..a2f4b2d41 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/platform/yield-processor.h @@ -0,0 +1,55 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_PLATFORM_YIELD_PROCESSOR_H_ +#define V8_BASE_PLATFORM_YIELD_PROCESSOR_H_ + +// The YIELD_PROCESSOR macro wraps an architecture specific-instruction that +// informs the processor we're in a busy wait, so it can handle the branch more +// intelligently and e.g. reduce power to our core or give more resources to the +// other hyper-thread on this core. See the following for context: +// https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops + +#if defined(V8_CC_MSVC) +// MSVC does not support inline assembly via __asm__ and provides compiler +// intrinsics instead. Check if there is a usable intrinsic. +// +// intrin.h is an expensive header, so only include it if we're on a host +// architecture that has a usable intrinsic. +#if defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64) +#include +#define YIELD_PROCESSOR _mm_pause() +#elif defined(V8_HOST_ARCH_ARM64) || \ + (defined(V8_HOST_ARCH_ARM) && __ARM_ARCH >= 6) +#include +#define YIELD_PROCESSOR __yield() +#endif // V8_HOST_ARCH + +#else // !V8_CC_MSVC + +#if defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64) +#define YIELD_PROCESSOR __asm__ __volatile__("pause") +#elif defined(V8_HOST_ARCH_ARM64) || \ + (defined(V8_HOST_ARCH_ARM) && __ARM_ARCH >= 6) +#define YIELD_PROCESSOR __asm__ __volatile__("yield") +#elif defined(V8_HOST_ARCH_MIPS) +// The MIPS32 docs state that the PAUSE instruction is a no-op on older +// architectures (first added in MIPS32r2). To avoid assembler errors when +// targeting pre-r2, we must encode the instruction manually. +#define YIELD_PROCESSOR __asm__ __volatile__(".word 0x00000140") +#elif defined(V8_HOST_ARCH_MIPS64EL) && __mips_isa_rev >= 2 +// Don't bother doing using .word here since r2 is the lowest supported mips64 +// that Chromium supports. +#define YIELD_PROCESSOR __asm__ __volatile__("pause") +#elif defined(V8_HOST_ARCH_PPC64) +#define YIELD_PROCESSOR __asm__ __volatile__("or 31,31,31") +#endif // V8_HOST_ARCH + +#endif // V8_CC_MSVC + +#ifndef YIELD_PROCESSOR +#define YIELD_PROCESSOR ((void)0) +#endif + +#endif // V8_BASE_PLATFORM_YIELD_PROCESSOR_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/pointer-with-payload.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/pointer-with-payload.h new file mode 100644 index 000000000..94801a9af --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/pointer-with-payload.h @@ -0,0 +1,118 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_POINTER_WITH_PAYLOAD_H_ +#define V8_BASE_POINTER_WITH_PAYLOAD_H_ + +#include +#include + +#include "src/base/logging.h" + +namespace v8 { +namespace base { + +template +struct PointerWithPayloadTraits { + static constexpr int kAvailableBits = + alignof(PointerType) >= 8 ? 3 : alignof(PointerType) >= 4 ? 2 : 1; +}; + +// Assume void* has the same payloads as void**, under the assumption that it's +// used for classes that contain at least one pointer. +template <> +struct PointerWithPayloadTraits : public PointerWithPayloadTraits { +}; + +// PointerWithPayload combines a PointerType* an a small PayloadType into +// one. The bits of the storage type get packed into the lower bits of the +// pointer that are free due to alignment. The user needs to specify how many +// bits are needed to store the PayloadType, allowing Types that by default are +// larger to be stored. +// +// Example: +// PointerWithPayload data_and_flag; +// +// Here we store a bool that needs 1 bit of storage state into the lower bits +// of int *, which points to some int data; +template +class PointerWithPayload { + public: + PointerWithPayload() = default; + + explicit PointerWithPayload(PointerType* pointer) + : pointer_with_payload_(reinterpret_cast(pointer)) { + DCHECK_EQ(GetPointer(), pointer); + DCHECK_EQ(GetPayload(), static_cast(0)); + } + + explicit PointerWithPayload(PayloadType payload) + : pointer_with_payload_(static_cast(payload)) { + DCHECK_EQ(GetPointer(), nullptr); + DCHECK_EQ(GetPayload(), payload); + } + + PointerWithPayload(PointerType* pointer, PayloadType payload) { + Update(pointer, payload); + } + + V8_INLINE PointerType* GetPointer() const { + return reinterpret_cast(pointer_with_payload_ & kPointerMask); + } + + // An optimized version of GetPointer for when we know the payload value. + V8_INLINE PointerType* GetPointerWithKnownPayload(PayloadType payload) const { + DCHECK_EQ(GetPayload(), payload); + return reinterpret_cast(pointer_with_payload_ - + static_cast(payload)); + } + + V8_INLINE PointerType* operator->() const { return GetPointer(); } + + V8_INLINE void Update(PointerType* new_pointer, PayloadType new_payload) { + pointer_with_payload_ = reinterpret_cast(new_pointer) | + static_cast(new_payload); + DCHECK_EQ(GetPayload(), new_payload); + DCHECK_EQ(GetPointer(), new_pointer); + } + + V8_INLINE void SetPointer(PointerType* newptr) { + DCHECK_EQ(reinterpret_cast(newptr) & kPayloadMask, 0); + pointer_with_payload_ = reinterpret_cast(newptr) | + (pointer_with_payload_ & kPayloadMask); + DCHECK_EQ(GetPointer(), newptr); + } + + V8_INLINE PayloadType GetPayload() const { + return static_cast(pointer_with_payload_ & kPayloadMask); + } + + V8_INLINE void SetPayload(PayloadType new_payload) { + uintptr_t new_payload_ptr = static_cast(new_payload); + DCHECK_EQ(new_payload_ptr & kPayloadMask, new_payload_ptr); + pointer_with_payload_ = + (pointer_with_payload_ & kPointerMask) | new_payload_ptr; + DCHECK_EQ(GetPayload(), new_payload); + } + + private: + static constexpr int kAvailableBits = PointerWithPayloadTraits< + typename std::remove_const::type>::kAvailableBits; + static_assert( + kAvailableBits >= NumPayloadBits, + "Ptr does not have sufficient alignment for the selected amount of " + "storage bits. Override PointerWithPayloadTraits to guarantee available " + "bits manually."); + + static constexpr uintptr_t kPayloadMask = + (uintptr_t{1} << NumPayloadBits) - 1; + static constexpr uintptr_t kPointerMask = ~kPayloadMask; + + uintptr_t pointer_with_payload_ = 0; +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_POINTER_WITH_PAYLOAD_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/qnx-math.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/qnx-math.h new file mode 100644 index 000000000..1503c164f --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/qnx-math.h @@ -0,0 +1,19 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_QNX_MATH_H_ +#define V8_BASE_QNX_MATH_H_ + +#include + +#undef fpclassify +#undef isfinite +#undef isinf +#undef isnan +#undef isnormal +#undef signbit + +using std::lrint; + +#endif // V8_BASE_QNX_MATH_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/region-allocator.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/region-allocator.h new file mode 100644 index 000000000..13df2aa7e --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/region-allocator.h @@ -0,0 +1,223 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_REGION_ALLOCATOR_H_ +#define V8_BASE_REGION_ALLOCATOR_H_ + +#include + +#include "src/base/address-region.h" +#include "src/base/utils/random-number-generator.h" +#include "testing/gtest/include/gtest/gtest_prod.h" // nogncheck + +namespace v8 { +namespace base { + +// Helper class for managing used/free regions within [address, address+size) +// region. Minimum allocation unit is |page_size|. Requested allocation size +// is rounded up to |page_size|. +// The region allocation algorithm implements best-fit with coalescing strategy: +// it tries to find a smallest suitable free region upon allocation and tries +// to merge region with its neighbors upon freeing. +// +// This class does not perform any actual region reservation. +// Not thread-safe. +class V8_BASE_EXPORT RegionAllocator final { + public: + using Address = uintptr_t; + + using SplitMergeCallback = std::function; + + static constexpr Address kAllocationFailure = static_cast
(-1); + + enum class RegionState { + // The region can be allocated from. + kFree, + // The region has been carved out of the wider area and is not allocatable. + kExcluded, + // The region has been allocated and is managed by a RegionAllocator. + kAllocated, + }; + + RegionAllocator(Address address, size_t size, size_t page_size); + RegionAllocator(const RegionAllocator&) = delete; + RegionAllocator& operator=(const RegionAllocator&) = delete; + ~RegionAllocator(); + + // Split and merge callbacks. + // + // These callbacks can be installed to perform additional logic when regions + // are split or merged. For example, when managing Windows placeholder + // regions, a region must be split into sub-regions (using + // VirtualFree(MEM_PRESERVE_PLACEHOLDER)) before a part of it can be replaced + // with an actual memory mapping. Similarly, multiple sub-regions must be + // merged (using VirtualFree(MEM_COALESCE_PLACEHOLDERS)) when coalescing them + // into a larger, free region again. + // + // The on_split callback is called to signal that an existing region is split + // so that [start, start+size) becomes a new region. + void set_on_split_callback(SplitMergeCallback callback) { + on_split_ = callback; + } + // The on_merge callback is called to signal that all regions in the range + // [start, start+size) are merged into a single one. + void set_on_merge_callback(SplitMergeCallback callback) { + on_merge_ = callback; + } + + // Allocates region of |size| (must be |page_size|-aligned). Returns + // the address of the region on success or kAllocationFailure. + Address AllocateRegion(size_t size); + // Same as above but tries to randomize the region displacement. + Address AllocateRegion(RandomNumberGenerator* rng, size_t size); + + // Allocates region of |size| at |requested_address| if it's free. Both the + // address and the size must be |page_size|-aligned. On success returns + // true. + // This kind of allocation is supposed to be used during setup phase to mark + // certain regions as used or for randomizing regions displacement. + // By default regions are marked as used, but can also be allocated as + // RegionState::kExcluded to prevent the RegionAllocator from using that + // memory range, which is useful when reserving any area to remap shared + // memory into. + bool AllocateRegionAt(Address requested_address, size_t size, + RegionState region_state = RegionState::kAllocated); + + // Allocates a region of |size| aligned to |alignment|. The size and alignment + // must be a multiple of |page_size|. Returns the address of the region on + // success or kAllocationFailure. + Address AllocateAlignedRegion(size_t size, size_t alignment); + + // Attempts to allocate a region of the given size and alignment at the + // specified address but fall back to allocating the region elsewhere if + // necessary. + Address AllocateRegion(Address hint, size_t size, size_t alignment); + + // Frees region at given |address|, returns the size of the region. + // There must be a used region starting at given address otherwise nothing + // will be freed and 0 will be returned. + size_t FreeRegion(Address address) { return TrimRegion(address, 0); } + + // Decreases size of the previously allocated region at |address|, returns + // freed size. |new_size| must be |page_size|-aligned and + // less than or equal to current region's size. Setting new size to zero + // frees the region. + size_t TrimRegion(Address address, size_t new_size); + + // If there is a used region starting at given address returns its size + // otherwise 0. + size_t CheckRegion(Address address); + + // Returns true if there are no pages allocated in given region. + bool IsFree(Address address, size_t size); + + Address begin() const { return whole_region_.begin(); } + Address end() const { return whole_region_.end(); } + size_t size() const { return whole_region_.size(); } + + bool contains(Address address) const { + return whole_region_.contains(address); + } + + bool contains(Address address, size_t size) const { + return whole_region_.contains(address, size); + } + + // Total size of not yet aquired regions. + size_t free_size() const { return free_size_; } + + // The alignment of the allocated region's addresses and granularity of + // the allocated region's sizes. + size_t page_size() const { return page_size_; } + + void Print(std::ostream& os) const; + + private: + class Region : public AddressRegion { + public: + Region(Address address, size_t size, RegionState state) + : AddressRegion(address, size), state_(state) {} + + bool is_free() const { return state_ == RegionState::kFree; } + bool is_allocated() const { return state_ == RegionState::kAllocated; } + bool is_excluded() const { return state_ == RegionState::kExcluded; } + + RegionState state() { return state_; } + void set_state(RegionState state) { state_ = state; } + + void Print(std::ostream& os) const; + + private: + RegionState state_; + }; + + // The whole region. + const Region whole_region_; + + // Number of |page_size_| in the whole region. + const size_t region_size_in_pages_; + + // If the free size is less than this value - stop trying to randomize the + // allocation addresses. + const size_t max_load_for_randomization_; + + // Size of all free regions. + size_t free_size_; + + // Minimum region size. Must be a pow of 2. + const size_t page_size_; + + struct AddressEndOrder { + bool operator()(const Region* a, const Region* b) const { + return a->end() < b->end(); + } + }; + // All regions ordered by addresses. + using AllRegionsSet = std::set; + AllRegionsSet all_regions_; + + struct SizeAddressOrder { + bool operator()(const Region* a, const Region* b) const { + if (a->size() != b->size()) return a->size() < b->size(); + return a->begin() < b->begin(); + } + }; + // Free regions ordered by sizes and addresses. + std::set free_regions_; + + // Callbacks called when regions are split or merged. + SplitMergeCallback on_split_; + SplitMergeCallback on_merge_; + + // Returns region containing given address or nullptr. + AllRegionsSet::iterator FindRegion(Address address); + + // Adds given region to the set of free regions. + void FreeListAddRegion(Region* region); + + // Finds best-fit free region for given size. + Region* FreeListFindRegion(size_t size); + + // Removes given region from the set of free regions. + void FreeListRemoveRegion(Region* region); + + // Splits given |region| into two: one of |new_size| size and a new one + // having the rest. The new region is returned. + Region* Split(Region* region, size_t new_size); + + // For two coalescing regions merges |next| to |prev| and deletes |next|. + void Merge(AllRegionsSet::iterator prev_iter, + AllRegionsSet::iterator next_iter); + + FRIEND_TEST(RegionAllocatorTest, AllocateExcluded); + FRIEND_TEST(RegionAllocatorTest, AllocateRegionRandom); + FRIEND_TEST(RegionAllocatorTest, Contains); + FRIEND_TEST(RegionAllocatorTest, FindRegion); + FRIEND_TEST(RegionAllocatorTest, Fragmentation); +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_REGION_ALLOCATOR_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/ring-buffer.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/ring-buffer.h new file mode 100644 index 000000000..835798708 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/ring-buffer.h @@ -0,0 +1,57 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_RING_BUFFER_H_ +#define V8_BASE_RING_BUFFER_H_ + +#include "src/base/macros.h" + +namespace v8 { +namespace base { + +template +class RingBuffer { + public: + RingBuffer() { Reset(); } + RingBuffer(const RingBuffer&) = delete; + RingBuffer& operator=(const RingBuffer&) = delete; + + static const int kSize = 10; + + void Push(const T& value) { + if (count_ == kSize) { + elements_[start_++] = value; + if (start_ == kSize) start_ = 0; + } else { + DCHECK_EQ(start_, 0); + elements_[count_++] = value; + } + } + + int Count() const { return count_; } + + template + T Sum(Callback callback, const T& initial) const { + int j = start_ + count_ - 1; + if (j >= kSize) j -= kSize; + T result = initial; + for (int i = 0; i < count_; i++) { + result = callback(result, elements_[j]); + if (--j == -1) j += kSize; + } + return result; + } + + void Reset() { start_ = count_ = 0; } + + private: + T elements_[kSize]; + int start_; + int count_; +}; + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_RING_BUFFER_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions.h index f63f1ad99..38aa7b9aa 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions.h @@ -4,59 +4,383 @@ // Slightly adapted for inclusion in V8. // Copyright 2014 the V8 project authors. All rights reserved. +// List of adaptations: +// - include guard names +// - wrap in v8 namespace +// - formatting (git cl format) +// - include paths #ifndef V8_BASE_SAFE_CONVERSIONS_H_ #define V8_BASE_SAFE_CONVERSIONS_H_ +#include + +#include #include +#include #include "src/base/safe_conversions_impl.h" +#if defined(__ARMEL__) && !defined(__native_client__) +#include "src/base/safe_conversions_arm_impl.h" +#define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS (1) +#else +#define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS (0) +#endif + +#if !BASE_NUMERICS_DISABLE_OSTREAM_OPERATORS +#include +#endif + namespace v8 { namespace base { +namespace internal { + +#if !BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS +template +struct SaturateFastAsmOp { + static constexpr bool is_supported = false; + static constexpr Dst Do(Src) { + // Force a compile failure if instantiated. + return CheckOnFailure::template HandleFailure(); + } +}; +#endif // BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS +#undef BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS + +// The following special case a few specific integer conversions where we can +// eke out better performance than range checking. +template +struct IsValueInRangeFastOp { + static constexpr bool is_supported = false; + static constexpr bool Do(Src value) { + // Force a compile failure if instantiated. + return CheckOnFailure::template HandleFailure(); + } +}; + +// Signed to signed range comparison. +template +struct IsValueInRangeFastOp< + Dst, Src, + typename std::enable_if< + std::is_integral::value && std::is_integral::value && + std::is_signed::value && std::is_signed::value && + !IsTypeInRangeForNumericType::value>::type> { + static constexpr bool is_supported = true; + + static constexpr bool Do(Src value) { + // Just downcast to the smaller type, sign extend it back to the original + // type, and then see if it matches the original value. + return value == static_cast(value); + } +}; + +// Signed to unsigned range comparison. +template +struct IsValueInRangeFastOp< + Dst, Src, + typename std::enable_if< + std::is_integral::value && std::is_integral::value && + !std::is_signed::value && std::is_signed::value && + !IsTypeInRangeForNumericType::value>::type> { + static constexpr bool is_supported = true; + + static constexpr bool Do(Src value) { + // We cast a signed as unsigned to overflow negative values to the top, + // then compare against whichever maximum is smaller, as our upper bound. + return as_unsigned(value) <= as_unsigned(CommonMax()); + } +}; // Convenience function that returns true if the supplied value is in range // for the destination type. template -inline bool IsValueInRangeForNumericType(Src value) { - return internal::DstRangeRelationToSrcRange(value) == - internal::RANGE_VALID; +constexpr bool IsValueInRangeForNumericType(Src value) { + using SrcType = typename internal::UnderlyingType::type; + return internal::IsValueInRangeFastOp::is_supported + ? internal::IsValueInRangeFastOp::Do( + static_cast(value)) + : internal::DstRangeRelationToSrcRange( + static_cast(value)) + .IsValid(); } // checked_cast<> is analogous to static_cast<> for numeric types, // except that it CHECKs that the specified numeric conversion will not // overflow or underflow. NaN source will always trigger a CHECK. -template -inline Dst checked_cast(Src value) { - CHECK(IsValueInRangeForNumericType(value)); - return static_cast(value); +template +constexpr Dst checked_cast(Src value) { + // This throws a compile-time error on evaluating the constexpr if it can be + // determined at compile-time as failing, otherwise it will CHECK at runtime. + using SrcType = typename internal::UnderlyingType::type; + return BASE_NUMERICS_LIKELY((IsValueInRangeForNumericType(value))) + ? static_cast(static_cast(value)) + : CheckHandler::template HandleFailure(); } +// Default boundaries for integral/float: max/infinity, lowest/-infinity, 0/NaN. +// You may provide your own limits (e.g. to saturated_cast) so long as you +// implement all of the static constexpr member functions in the class below. +template +struct SaturationDefaultLimits : public std::numeric_limits { + static constexpr T NaN() { + return std::numeric_limits::has_quiet_NaN + ? std::numeric_limits::quiet_NaN() + : T(); + } + using std::numeric_limits::max; + static constexpr T Overflow() { + return std::numeric_limits::has_infinity + ? std::numeric_limits::infinity() + : std::numeric_limits::max(); + } + using std::numeric_limits::lowest; + static constexpr T Underflow() { + return std::numeric_limits::has_infinity + ? std::numeric_limits::infinity() * -1 + : std::numeric_limits::lowest(); + } +}; + +template class S, typename Src> +constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) { + // For some reason clang generates much better code when the branch is + // structured exactly this way, rather than a sequence of checks. + return !constraint.IsOverflowFlagSet() + ? (!constraint.IsUnderflowFlagSet() ? static_cast(value) + : S::Underflow()) + // Skip this check for integral Src, which cannot be NaN. + : (std::is_integral::value || !constraint.IsUnderflowFlagSet() + ? S::Overflow() + : S::NaN()); +} + +// We can reduce the number of conditions and get slightly better performance +// for normal signed and unsigned integer ranges. And in the specific case of +// Arm, we can use the optimized saturation instructions. +template +struct SaturateFastOp { + static constexpr bool is_supported = false; + static constexpr Dst Do(Src value) { + // Force a compile failure if instantiated. + return CheckOnFailure::template HandleFailure(); + } +}; + +template +struct SaturateFastOp< + Dst, Src, + typename std::enable_if::value && + std::is_integral::value && + SaturateFastAsmOp::is_supported>::type> { + static constexpr bool is_supported = true; + static constexpr Dst Do(Src value) { + return SaturateFastAsmOp::Do(value); + } +}; + +template +struct SaturateFastOp< + Dst, Src, + typename std::enable_if::value && + std::is_integral::value && + !SaturateFastAsmOp::is_supported>::type> { + static constexpr bool is_supported = true; + static constexpr Dst Do(Src value) { + // The exact order of the following is structured to hit the correct + // optimization heuristics across compilers. Do not change without + // checking the emitted code. + const Dst saturated = CommonMaxOrMin( + IsMaxInRangeForNumericType() || + (!IsMinInRangeForNumericType() && IsValueNegative(value))); + return BASE_NUMERICS_LIKELY(IsValueInRangeForNumericType(value)) + ? static_cast(value) + : saturated; + } +}; + // saturated_cast<> is analogous to static_cast<> for numeric types, except -// that the specified numeric conversion will saturate rather than overflow or -// underflow. NaN assignment to an integral will trigger a CHECK condition. +// that the specified numeric conversion will saturate by default rather than +// overflow or underflow, and NaN assignment to an integral will return 0. +// All boundary condition behaviors can be overriden with a custom handler. +template class SaturationHandler = SaturationDefaultLimits, + typename Src> +constexpr Dst saturated_cast(Src value) { + using SrcType = typename UnderlyingType::type; + return !IsCompileTimeConstant(value) && + SaturateFastOp::is_supported && + std::is_same, + SaturationDefaultLimits>::value + ? SaturateFastOp::Do(static_cast(value)) + : saturated_cast_impl( + static_cast(value), + DstRangeRelationToSrcRange( + static_cast(value))); +} + +// strict_cast<> is analogous to static_cast<> for numeric types, except that +// it will cause a compile failure if the destination type is not large enough +// to contain any value in the source type. It performs no runtime checking. template -inline Dst saturated_cast(Src value) { - // Optimization for floating point values, which already saturate. - if (std::numeric_limits::is_iec559) - return static_cast(value); +constexpr Dst strict_cast(Src value) { + using SrcType = typename UnderlyingType::type; + static_assert(UnderlyingType::is_numeric, "Argument must be numeric."); + static_assert(std::is_arithmetic::value, "Result must be numeric."); + + // If you got here from a compiler error, it's because you tried to assign + // from a source type to a destination type that has insufficient range. + // The solution may be to change the destination type you're assigning to, + // and use one large enough to represent the source. + // Alternatively, you may be better served with the checked_cast<> or + // saturated_cast<> template functions for your particular use case. + static_assert(StaticDstRangeRelationToSrcRange::value == + NUMERIC_RANGE_CONTAINED, + "The source type is out of range for the destination type. " + "Please see strict_cast<> comments for more information."); + + return static_cast(static_cast(value)); +} + +// Some wrappers to statically check that a type is in range. +template +struct IsNumericRangeContained { + static constexpr bool value = false; +}; + +template +struct IsNumericRangeContained< + Dst, Src, + typename std::enable_if::value && + ArithmeticOrUnderlyingEnum::value>::type> { + static constexpr bool value = + StaticDstRangeRelationToSrcRange::value == + NUMERIC_RANGE_CONTAINED; +}; + +// StrictNumeric implements compile time range checking between numeric types by +// wrapping assignment operations in a strict_cast. This class is intended to be +// used for function arguments and return types, to ensure the destination type +// can always contain the source type. This is essentially the same as enforcing +// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied +// incrementally at API boundaries, making it easier to convert code so that it +// compiles cleanly with truncation warnings enabled. +// This template should introduce no runtime overhead, but it also provides no +// runtime checking of any of the associated mathematical operations. Use +// CheckedNumeric for runtime range checks of the actual value being assigned. +template +class StrictNumeric { + public: + using type = T; - switch (internal::DstRangeRelationToSrcRange(value)) { - case internal::RANGE_VALID: - return static_cast(value); + constexpr StrictNumeric() : value_(0) {} - case internal::RANGE_UNDERFLOW: - return std::numeric_limits::min(); + // Copy constructor. + template + constexpr StrictNumeric(const StrictNumeric& rhs) + : value_(strict_cast(rhs.value_)) {} - case internal::RANGE_OVERFLOW: - return std::numeric_limits::max(); + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to StrictNumerics to make them easier to use. + template + constexpr StrictNumeric(Src value) // NOLINT(runtime/explicit) + : value_(strict_cast(value)) {} - // Should fail only on attempting to assign NaN to a saturated integer. - case internal::RANGE_INVALID: - UNREACHABLE(); + // If you got here from a compiler error, it's because you tried to assign + // from a source type to a destination type that has insufficient range. + // The solution may be to change the destination type you're assigning to, + // and use one large enough to represent the source. + // If you're assigning from a CheckedNumeric<> class, you may be able to use + // the AssignIfValid() member function, specify a narrower destination type to + // the member value functions (e.g. val.template ValueOrDie()), use one + // of the value helper functions (e.g. ValueOrDieForType(val)). + // If you've encountered an _ambiguous overload_ you can use a static_cast<> + // to explicitly cast the result to the destination type. + // If none of that works, you may be better served with the checked_cast<> or + // saturated_cast<> template functions for your particular use case. + template ::value>::type* = nullptr> + constexpr operator Dst() const { + return static_cast::type>(value_); } - UNREACHABLE(); + private: + const T value_; +}; + +// Convience wrapper returns a StrictNumeric from the provided arithmetic type. +template +constexpr StrictNumeric::type> MakeStrictNum( + const T value) { + return value; +} + +#if !BASE_NUMERICS_DISABLE_OSTREAM_OPERATORS +// Overload the ostream output operator to make logging work nicely. +template +std::ostream& operator<<(std::ostream& os, const StrictNumeric& value) { + os << static_cast(value); + return os; +} +#endif + +#define BASE_NUMERIC_COMPARISON_OPERATORS(CLASS, NAME, OP) \ + template ::value>::type* = nullptr> \ + constexpr bool operator OP(const L lhs, const R rhs) { \ + return SafeCompare::type, \ + typename UnderlyingType::type>(lhs, rhs); \ + } + +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLess, <) +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLessOrEqual, <=) +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreater, >) +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreaterOrEqual, >=) +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsEqual, ==) +BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsNotEqual, !=) + +} // namespace internal + +using internal::as_signed; +using internal::as_unsigned; +using internal::checked_cast; +using internal::IsTypeInRangeForNumericType; +using internal::IsValueInRangeForNumericType; +using internal::IsValueNegative; +using internal::MakeStrictNum; +using internal::SafeUnsignedAbs; +using internal::saturated_cast; +using internal::strict_cast; +using internal::StrictNumeric; + +// Explicitly make a shorter size_t alias for convenience. +using SizeT = StrictNumeric; + +// floating -> integral conversions that saturate and thus can actually return +// an integral type. In most cases, these should be preferred over the std:: +// versions. +template ::value && + std::is_floating_point::value>> +Dst ClampFloor(Src value) { + return saturated_cast(std::floor(value)); +} +template ::value && + std::is_floating_point::value>> +Dst ClampCeil(Src value) { + return saturated_cast(std::ceil(value)); +} +template ::value && + std::is_floating_point::value>> +Dst ClampRound(Src value) { + const Src rounded = + (value >= 0.0f) ? std::floor(value + 0.5f) : std::ceil(value - 0.5f); + return saturated_cast(rounded); } } // namespace base diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions_arm_impl.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions_arm_impl.h new file mode 100644 index 000000000..0e08a1440 --- /dev/null +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions_arm_impl.h @@ -0,0 +1,60 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Slightly adapted for inclusion in V8. +// Copyright 2014 the V8 project authors. All rights reserved. +// List of adaptations: +// - include guard names +// - wrap in v8 namespace +// - include paths + +#ifndef V8_BASE_SAFE_CONVERSIONS_ARM_IMPL_H_ +#define V8_BASE_SAFE_CONVERSIONS_ARM_IMPL_H_ + +#include +#include +#include + +#include "src/base/safe_conversions_impl.h" + +namespace v8 { +namespace base { +namespace internal { + +// Fast saturation to a destination type. +template +struct SaturateFastAsmOp { + static constexpr bool is_supported = + std::is_signed::value && std::is_integral::value && + std::is_integral::value && + IntegerBitsPlusSign::value <= IntegerBitsPlusSign::value && + IntegerBitsPlusSign::value <= IntegerBitsPlusSign::value && + !IsTypeInRangeForNumericType::value; + + __attribute__((always_inline)) static Dst Do(Src value) { + int32_t src = value; + typename std::conditional::value, int32_t, + uint32_t>::type result; + if (std::is_signed::value) { + asm("ssat %[dst], %[shift], %[src]" + : [dst] "=r"(result) + : [src] "r"(src), [shift] "n"(IntegerBitsPlusSign::value <= 32 + ? IntegerBitsPlusSign::value + : 32)); + } else { + asm("usat %[dst], %[shift], %[src]" + : [dst] "=r"(result) + : [src] "r"(src), [shift] "n"(IntegerBitsPlusSign::value < 32 + ? IntegerBitsPlusSign::value + : 31)); + } + return static_cast(result); + } +}; + +} // namespace internal +} // namespace base +} // namespace v8 + +#endif // V8_BASE_SAFE_CONVERSIONS_ARM_IMPL_H_ diff --git a/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions_impl.h b/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions_impl.h index 90c8e1935..89a41740b 100644 --- a/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions_impl.h +++ b/test-app/runtime/src/main/cpp/v8_inspector/src/base/safe_conversions_impl.h @@ -4,28 +4,131 @@ // Slightly adapted for inclusion in V8. // Copyright 2014 the V8 project authors. All rights reserved. +// List of adaptations: +// - include guard names +// - wrap in v8 namespace +// - formatting (git cl format) #ifndef V8_BASE_SAFE_CONVERSIONS_IMPL_H_ #define V8_BASE_SAFE_CONVERSIONS_IMPL_H_ +#include +#include + #include +#include -#include "src/base/logging.h" -#include "src/base/macros.h" +#if defined(__GNUC__) || defined(__clang__) +#define BASE_NUMERICS_LIKELY(x) __builtin_expect(!!(x), 1) +#define BASE_NUMERICS_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define BASE_NUMERICS_LIKELY(x) (x) +#define BASE_NUMERICS_UNLIKELY(x) (x) +#endif namespace v8 { namespace base { namespace internal { // The std library doesn't provide a binary max_exponent for integers, however -// we can compute one by adding one to the number of non-sign bits. This allows -// for accurate range comparisons between floating point and integer types. +// we can compute an analog using std::numeric_limits<>::digits. template struct MaxExponent { - static const int value = std::numeric_limits::is_iec559 + static const int value = std::is_floating_point::value ? std::numeric_limits::max_exponent - : (sizeof(NumericType) * 8 + 1 - - std::numeric_limits::is_signed); + : std::numeric_limits::digits + 1; +}; + +// The number of bits (including the sign) in an integer. Eliminates sizeof +// hacks. +template +struct IntegerBitsPlusSign { + static const int value = std::numeric_limits::digits + + std::is_signed::value; +}; + +// Helper templates for integer manipulations. + +template +struct PositionOfSignBit { + static const size_t value = IntegerBitsPlusSign::value - 1; +}; + +// Determines if a numeric value is negative without throwing compiler +// warnings on: unsigned(value) < 0. +template ::value>::type* = nullptr> +constexpr bool IsValueNegative(T value) { + static_assert(std::is_arithmetic::value, "Argument must be numeric."); + return value < 0; +} + +template ::value>::type* = nullptr> +constexpr bool IsValueNegative(T) { + static_assert(std::is_arithmetic::value, "Argument must be numeric."); + return false; +} + +// This performs a fast negation, returning a signed value. It works on unsigned +// arguments, but probably doesn't do what you want for any unsigned value +// larger than max / 2 + 1 (i.e. signed min cast to unsigned). +template +constexpr typename std::make_signed::type ConditionalNegate( + T x, bool is_negative) { + static_assert(std::is_integral::value, "Type must be integral"); + using SignedT = typename std::make_signed::type; + using UnsignedT = typename std::make_unsigned::type; + return static_cast( + (static_cast(x) ^ -SignedT(is_negative)) + is_negative); +} + +// This performs a safe, absolute value via unsigned overflow. +template +constexpr typename std::make_unsigned::type SafeUnsignedAbs(T value) { + static_assert(std::is_integral::value, "Type must be integral"); + using UnsignedT = typename std::make_unsigned::type; + return IsValueNegative(value) + ? static_cast(0u - static_cast(value)) + : static_cast(value); +} + +// This allows us to switch paths on known compile-time constants. +#if defined(__clang__) || defined(__GNUC__) +constexpr bool CanDetectCompileTimeConstant() { return true; } +template +constexpr bool IsCompileTimeConstant(const T v) { + return __builtin_constant_p(v); +} +#else +constexpr bool CanDetectCompileTimeConstant() { return false; } +template +constexpr bool IsCompileTimeConstant(const T) { + return false; +} +#endif +template +constexpr bool MustTreatAsConstexpr(const T v) { + // Either we can't detect a compile-time constant, and must always use the + // constexpr path, or we know we have a compile-time constant. + return !CanDetectCompileTimeConstant() || IsCompileTimeConstant(v); +} + +// Forces a crash, like a CHECK(false). Used for numeric boundary errors. +// Also used in a constexpr template to trigger a compilation failure on +// an error condition. +struct CheckOnFailure { + template + static T HandleFailure() { +#if defined(_MSC_VER) + __debugbreak(); +#elif defined(__GNUC__) || defined(__clang__) + __builtin_trap(); +#else + ((void)(*(volatile char*)0 = 0)); +#endif + return T(); + } }; enum IntegerRepresentation { @@ -35,7 +138,7 @@ enum IntegerRepresentation { // A range for a given nunmeric Src type is contained for a given numeric Dst // type if both numeric_limits::max() <= numeric_limits::max() and -// numeric_limits::min() >= numeric_limits::min() are true. +// numeric_limits::lowest() >= numeric_limits::lowest() are true. // We implement this as template specializations rather than simple static // comparisons to ensure type correctness in our comparisons. enum NumericRangeRepresentation { @@ -46,16 +149,13 @@ enum NumericRangeRepresentation { // Helper templates to statically determine if our destination type can contain // maximum and minimum values represented by the source type. -template < - typename Dst, - typename Src, - IntegerRepresentation DstSign = std::numeric_limits::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED, - IntegerRepresentation SrcSign = - std::numeric_limits::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED > +template ::value + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::is_signed::value + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED> struct StaticDstRangeRelationToSrcRange; // Same sign: Dst is guaranteed to contain Src only if its range is equal or @@ -90,127 +190,630 @@ struct StaticDstRangeRelationToSrcRange= RANGE_VALID && - integer_range_constraint <= RANGE_INVALID); - return static_cast(integer_range_constraint); -} +// The following helper template addresses a corner case in range checks for +// conversion from a floating-point type to an integral type of smaller range +// but larger precision (e.g. float -> unsigned). The problem is as follows: +// 1. Integral maximum is always one less than a power of two, so it must be +// truncated to fit the mantissa of the floating point. The direction of +// rounding is implementation defined, but by default it's always IEEE +// floats, which round to nearest and thus result in a value of larger +// magnitude than the integral value. +// Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX +// // is 4294967295u. +// 2. If the floating point value is equal to the promoted integral maximum +// value, a range check will erroneously pass. +// Example: (4294967296f <= 4294967295u) // This is true due to a precision +// // loss in rounding up to float. +// 3. When the floating point value is then converted to an integral, the +// resulting value is out of range for the target integral type and +// thus is implementation defined. +// Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. +// To fix this bug we manually truncate the maximum value when the destination +// type is an integral of larger precision than the source floating-point type, +// such that the resulting maximum is represented exactly as a floating point. +template class Bounds> +struct NarrowingRange { + using SrcLimits = std::numeric_limits; + using DstLimits = typename std::numeric_limits; -// This function creates a RangeConstraint from an upper and lower bound -// check by taking advantage of the fact that only NaN can be out of range in -// both directions at once. -inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound, - bool is_in_lower_bound) { - return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) | - (is_in_lower_bound ? 0 : RANGE_UNDERFLOW)); -} + // Computes the mask required to make an accurate comparison between types. + static const int kShift = + (MaxExponent::value > MaxExponent::value && + SrcLimits::digits < DstLimits::digits) + ? (DstLimits::digits - SrcLimits::digits) + : 0; + template ::value>::type* = nullptr> -template < - typename Dst, - typename Src, - IntegerRepresentation DstSign = std::numeric_limits::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED, - IntegerRepresentation SrcSign = std::numeric_limits::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED, - NumericRangeRepresentation DstRange = - StaticDstRangeRelationToSrcRange::value > + // Masks out the integer bits that are beyond the precision of the + // intermediate type used for comparison. + static constexpr T Adjust(T value) { + static_assert(std::is_same::value, ""); + static_assert(kShift < DstLimits::digits, ""); + return static_cast( + ConditionalNegate(SafeUnsignedAbs(value) & ~((T(1) << kShift) - T(1)), + IsValueNegative(value))); + } + + template ::value>::type* = nullptr> + static constexpr T Adjust(T value) { + static_assert(std::is_same::value, ""); + static_assert(kShift == 0, ""); + return value; + } + + static constexpr Dst max() { return Adjust(Bounds::max()); } + static constexpr Dst lowest() { return Adjust(Bounds::lowest()); } +}; + +template class Bounds, + IntegerRepresentation DstSign = std::is_signed::value + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::is_signed::value + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + NumericRangeRepresentation DstRange = + StaticDstRangeRelationToSrcRange::value> struct DstRangeRelationToSrcRangeImpl; // The following templates are for ranges that must be verified at runtime. We // split it into checks based on signedness to avoid confusing casts and // compiler warnings on signed an unsigned comparisons. -// Dst range is statically determined to contain Src: Nothing to check. -template -struct DstRangeRelationToSrcRangeImpl class Bounds, + IntegerRepresentation DstSign, IntegerRepresentation SrcSign> +struct DstRangeRelationToSrcRangeImpl { - static RangeConstraint Check(Src value) { return RANGE_VALID; } + static constexpr RangeCheck Check(Src value) { + using SrcLimits = std::numeric_limits; + using DstLimits = NarrowingRange; + return RangeCheck( + static_cast(SrcLimits::lowest()) >= DstLimits::lowest() || + static_cast(value) >= DstLimits::lowest(), + static_cast(SrcLimits::max()) <= DstLimits::max() || + static_cast(value) <= DstLimits::max()); + } }; // Signed to signed narrowing: Both the upper and lower boundaries may be -// exceeded. -template -struct DstRangeRelationToSrcRangeImpl { - static RangeConstraint Check(Src value) { - return std::numeric_limits::is_iec559 - ? GetRangeConstraint(value <= std::numeric_limits::max(), - value >= -std::numeric_limits::max()) - : GetRangeConstraint(value <= std::numeric_limits::max(), - value >= std::numeric_limits::min()); +// exceeded for standard limits. +template class Bounds> +struct DstRangeRelationToSrcRangeImpl< + Dst, Src, Bounds, INTEGER_REPRESENTATION_SIGNED, + INTEGER_REPRESENTATION_SIGNED, NUMERIC_RANGE_NOT_CONTAINED> { + static constexpr RangeCheck Check(Src value) { + using DstLimits = NarrowingRange; + return RangeCheck(value >= DstLimits::lowest(), value <= DstLimits::max()); } }; -// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded. -template -struct DstRangeRelationToSrcRangeImpl { - static RangeConstraint Check(Src value) { - return GetRangeConstraint(value <= std::numeric_limits::max(), true); +// Unsigned to unsigned narrowing: Only the upper bound can be exceeded for +// standard limits. +template class Bounds> +struct DstRangeRelationToSrcRangeImpl< + Dst, Src, Bounds, INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_UNSIGNED, NUMERIC_RANGE_NOT_CONTAINED> { + static constexpr RangeCheck Check(Src value) { + using DstLimits = NarrowingRange; + return RangeCheck( + DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest(), + value <= DstLimits::max()); } }; -// Unsigned to signed: The upper boundary may be exceeded. -template -struct DstRangeRelationToSrcRangeImpl { - static RangeConstraint Check(Src value) { - return sizeof(Dst) > sizeof(Src) - ? RANGE_VALID - : GetRangeConstraint( - value <= static_cast(std::numeric_limits::max()), - true); +// Unsigned to signed: Only the upper bound can be exceeded for standard limits. +template class Bounds> +struct DstRangeRelationToSrcRangeImpl< + Dst, Src, Bounds, INTEGER_REPRESENTATION_SIGNED, + INTEGER_REPRESENTATION_UNSIGNED, NUMERIC_RANGE_NOT_CONTAINED> { + static constexpr RangeCheck Check(Src value) { + using DstLimits = NarrowingRange; + using Promotion = decltype(Src() + Dst()); + return RangeCheck(DstLimits::lowest() <= Dst(0) || + static_cast(value) >= + static_cast(DstLimits::lowest()), + static_cast(value) <= + static_cast(DstLimits::max())); } }; // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, -// and any negative value exceeds the lower boundary. +// and any negative value exceeds the lower boundary for standard limits. +template class Bounds> +struct DstRangeRelationToSrcRangeImpl< + Dst, Src, Bounds, INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED, NUMERIC_RANGE_NOT_CONTAINED> { + static constexpr RangeCheck Check(Src value) { + using SrcLimits = std::numeric_limits; + using DstLimits = NarrowingRange; + using Promotion = decltype(Src() + Dst()); + bool ge_zero = false; + // Converting floating-point to integer will discard fractional part, so + // values in (-1.0, -0.0) will truncate to 0 and fit in Dst. + if (std::is_floating_point::value) { + ge_zero = value > Src(-1); + } else { + ge_zero = value >= Src(0); + } + return RangeCheck( + ge_zero && (DstLimits::lowest() == 0 || + static_cast(value) >= DstLimits::lowest()), + static_cast(SrcLimits::max()) <= + static_cast(DstLimits::max()) || + static_cast(value) <= + static_cast(DstLimits::max())); + } +}; + +// Simple wrapper for statically checking if a type's range is contained. template -struct DstRangeRelationToSrcRangeImpl { - static RangeConstraint Check(Src value) { - return (MaxExponent::value >= MaxExponent::value) - ? GetRangeConstraint(true, value >= static_cast(0)) - : GetRangeConstraint( - value <= static_cast(std::numeric_limits::max()), - value >= static_cast(0)); +struct IsTypeInRangeForNumericType { + static const bool value = StaticDstRangeRelationToSrcRange::value == + NUMERIC_RANGE_CONTAINED; +}; + +template class Bounds = std::numeric_limits, + typename Src> +constexpr RangeCheck DstRangeRelationToSrcRange(Src value) { + static_assert(std::is_arithmetic::value, "Argument must be numeric."); + static_assert(std::is_arithmetic::value, "Result must be numeric."); + static_assert(Bounds::lowest() < Bounds::max(), ""); + return DstRangeRelationToSrcRangeImpl::Check(value); +} + +// Integer promotion templates used by the portable checked integer arithmetic. +template +struct IntegerForDigitsAndSign; + +#define INTEGER_FOR_DIGITS_AND_SIGN(I) \ + template <> \ + struct IntegerForDigitsAndSign::value, \ + std::is_signed::value> { \ + using type = I; \ + } + +INTEGER_FOR_DIGITS_AND_SIGN(int8_t); +INTEGER_FOR_DIGITS_AND_SIGN(uint8_t); +INTEGER_FOR_DIGITS_AND_SIGN(int16_t); +INTEGER_FOR_DIGITS_AND_SIGN(uint16_t); +INTEGER_FOR_DIGITS_AND_SIGN(int32_t); +INTEGER_FOR_DIGITS_AND_SIGN(uint32_t); +INTEGER_FOR_DIGITS_AND_SIGN(int64_t); +INTEGER_FOR_DIGITS_AND_SIGN(uint64_t); +#undef INTEGER_FOR_DIGITS_AND_SIGN + +// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to +// support 128-bit math, then the ArithmeticPromotion template below will need +// to be updated (or more likely replaced with a decltype expression). +static_assert(IntegerBitsPlusSign::value == 64, + "Max integer size not supported for this toolchain."); + +template ::value> +struct TwiceWiderInteger { + using type = + typename IntegerForDigitsAndSign::value * 2, + IsSigned>::type; +}; + +enum ArithmeticPromotionCategory { + LEFT_PROMOTION, // Use the type of the left-hand argument. + RIGHT_PROMOTION // Use the type of the right-hand argument. +}; + +// Determines the type that can represent the largest positive value. +template ::value > MaxExponent::value) + ? LEFT_PROMOTION + : RIGHT_PROMOTION> +struct MaxExponentPromotion; + +template +struct MaxExponentPromotion { + using type = Lhs; +}; + +template +struct MaxExponentPromotion { + using type = Rhs; +}; + +// Determines the type that can represent the lowest arithmetic value. +template ::value + ? (std::is_signed::value + ? (MaxExponent::value > MaxExponent::value + ? LEFT_PROMOTION + : RIGHT_PROMOTION) + : LEFT_PROMOTION) + : (std::is_signed::value + ? RIGHT_PROMOTION + : (MaxExponent::value < MaxExponent::value + ? LEFT_PROMOTION + : RIGHT_PROMOTION))> +struct LowestValuePromotion; + +template +struct LowestValuePromotion { + using type = Lhs; +}; + +template +struct LowestValuePromotion { + using type = Rhs; +}; + +// Determines the type that is best able to represent an arithmetic result. +template < + typename Lhs, typename Rhs = Lhs, + bool is_intmax_type = + std::is_integral::type>::value&& + IntegerBitsPlusSign::type>:: + value == IntegerBitsPlusSign::value, + bool is_max_exponent = + StaticDstRangeRelationToSrcRange< + typename MaxExponentPromotion::type, Lhs>::value == + NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange< + typename MaxExponentPromotion::type, Rhs>::value == + NUMERIC_RANGE_CONTAINED> +struct BigEnoughPromotion; + +// The side with the max exponent is big enough. +template +struct BigEnoughPromotion { + using type = typename MaxExponentPromotion::type; + static const bool is_contained = true; +}; + +// We can use a twice wider type to fit. +template +struct BigEnoughPromotion { + using type = + typename TwiceWiderInteger::type, + std::is_signed::value || + std::is_signed::value>::type; + static const bool is_contained = true; +}; + +// No type is large enough. +template +struct BigEnoughPromotion { + using type = typename MaxExponentPromotion::type; + static const bool is_contained = false; +}; + +// We can statically check if operations on the provided types can wrap, so we +// can skip the checked operations if they're not needed. So, for an integer we +// care if the destination type preserves the sign and is twice the width of +// the source. +template +struct IsIntegerArithmeticSafe { + static const bool value = + !std::is_floating_point::value && + !std::is_floating_point::value && + !std::is_floating_point::value && + std::is_signed::value >= std::is_signed::value && + IntegerBitsPlusSign::value >= (2 * IntegerBitsPlusSign::value) && + std::is_signed::value >= std::is_signed::value && + IntegerBitsPlusSign::value >= (2 * IntegerBitsPlusSign::value); +}; + +// Promotes to a type that can represent any possible result of a binary +// arithmetic operation with the source types. +template ::value || + std::is_signed::value, + intmax_t, uintmax_t>::type, + typename MaxExponentPromotion::type>::value> +struct FastIntegerArithmeticPromotion; + +template +struct FastIntegerArithmeticPromotion { + using type = + typename TwiceWiderInteger::type, + std::is_signed::value || + std::is_signed::value>::type; + static_assert(IsIntegerArithmeticSafe::value, ""); + static const bool is_contained = true; +}; + +template +struct FastIntegerArithmeticPromotion { + using type = typename BigEnoughPromotion::type; + static const bool is_contained = false; +}; + +// Extracts the underlying type from an enum. +template ::value> +struct ArithmeticOrUnderlyingEnum; + +template +struct ArithmeticOrUnderlyingEnum { + using type = typename std::underlying_type::type; + static const bool value = std::is_arithmetic::value; +}; + +template +struct ArithmeticOrUnderlyingEnum { + using type = T; + static const bool value = std::is_arithmetic::value; +}; + +// The following are helper templates used in the CheckedNumeric class. +template +class CheckedNumeric; + +template +class ClampedNumeric; + +template +class StrictNumeric; + +// Used to treat CheckedNumeric and arithmetic underlying types the same. +template +struct UnderlyingType { + using type = typename ArithmeticOrUnderlyingEnum::type; + static const bool is_numeric = std::is_arithmetic::value; + static const bool is_checked = false; + static const bool is_clamped = false; + static const bool is_strict = false; +}; + +template +struct UnderlyingType> { + using type = T; + static const bool is_numeric = true; + static const bool is_checked = true; + static const bool is_clamped = false; + static const bool is_strict = false; +}; + +template +struct UnderlyingType> { + using type = T; + static const bool is_numeric = true; + static const bool is_checked = false; + static const bool is_clamped = true; + static const bool is_strict = false; +}; + +template +struct UnderlyingType> { + using type = T; + static const bool is_numeric = true; + static const bool is_checked = false; + static const bool is_clamped = false; + static const bool is_strict = true; +}; + +template +struct IsCheckedOp { + static const bool value = + UnderlyingType::is_numeric && UnderlyingType::is_numeric && + (UnderlyingType::is_checked || UnderlyingType::is_checked); +}; + +template +struct IsClampedOp { + static const bool value = + UnderlyingType::is_numeric && UnderlyingType::is_numeric && + (UnderlyingType::is_clamped || UnderlyingType::is_clamped) && + !(UnderlyingType::is_checked || UnderlyingType::is_checked); +}; + +template +struct IsStrictOp { + static const bool value = + UnderlyingType::is_numeric && UnderlyingType::is_numeric && + (UnderlyingType::is_strict || UnderlyingType::is_strict) && + !(UnderlyingType::is_checked || UnderlyingType::is_checked) && + !(UnderlyingType::is_clamped || UnderlyingType::is_clamped); +}; + +// as_signed<> returns the supplied integral value (or integral castable +// Numeric template) cast as a signed integral of equivalent precision. +// I.e. it's mostly an alias for: static_cast::type>(t) +template +constexpr typename std::make_signed< + typename base::internal::UnderlyingType::type>::type +as_signed(const Src value) { + static_assert(std::is_integral::value, + "Argument must be a signed or unsigned integer type."); + return static_cast(value); +} + +// as_unsigned<> returns the supplied integral value (or integral castable +// Numeric template) cast as an unsigned integral of equivalent precision. +// I.e. it's mostly an alias for: static_cast::type>(t) +template +constexpr typename std::make_unsigned< + typename base::internal::UnderlyingType::type>::type +as_unsigned(const Src value) { + static_assert(std::is_integral::value, + "Argument must be a signed or unsigned integer type."); + return static_cast(value); +} + +template +constexpr bool IsLessImpl(const L lhs, const R rhs, const RangeCheck l_range, + const RangeCheck r_range) { + return l_range.IsUnderflow() || r_range.IsOverflow() || + (l_range == r_range && static_cast(lhs) < + static_cast(rhs)); +} + +template +struct IsLess { + static_assert(std::is_arithmetic::value && std::is_arithmetic::value, + "Types must be numeric."); + static constexpr bool Test(const L lhs, const R rhs) { + return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange(lhs), + DstRangeRelationToSrcRange(rhs)); + } +}; + +template +constexpr bool IsLessOrEqualImpl(const L lhs, const R rhs, + const RangeCheck l_range, + const RangeCheck r_range) { + return l_range.IsUnderflow() || r_range.IsOverflow() || + (l_range == r_range && static_cast(lhs) <= + static_cast(rhs)); +} + +template +struct IsLessOrEqual { + static_assert(std::is_arithmetic::value && std::is_arithmetic::value, + "Types must be numeric."); + static constexpr bool Test(const L lhs, const R rhs) { + return IsLessOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange(lhs), + DstRangeRelationToSrcRange(rhs)); + } +}; + +template +constexpr bool IsGreaterImpl(const L lhs, const R rhs, const RangeCheck l_range, + const RangeCheck r_range) { + return l_range.IsOverflow() || r_range.IsUnderflow() || + (l_range == r_range && static_cast(lhs) > + static_cast(rhs)); +} + +template +struct IsGreater { + static_assert(std::is_arithmetic::value && std::is_arithmetic::value, + "Types must be numeric."); + static constexpr bool Test(const L lhs, const R rhs) { + return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange(lhs), + DstRangeRelationToSrcRange(rhs)); } }; +template +constexpr bool IsGreaterOrEqualImpl(const L lhs, const R rhs, + const RangeCheck l_range, + const RangeCheck r_range) { + return l_range.IsOverflow() || r_range.IsUnderflow() || + (l_range == r_range && static_cast(lhs) >= + static_cast(rhs)); +} + +template +struct IsGreaterOrEqual { + static_assert(std::is_arithmetic::value && std::is_arithmetic::value, + "Types must be numeric."); + static constexpr bool Test(const L lhs, const R rhs) { + return IsGreaterOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange(lhs), + DstRangeRelationToSrcRange(rhs)); + } +}; + +template +struct IsEqual { + static_assert(std::is_arithmetic::value && std::is_arithmetic::value, + "Types must be numeric."); + static constexpr bool Test(const L lhs, const R rhs) { + return DstRangeRelationToSrcRange(lhs) == + DstRangeRelationToSrcRange(rhs) && + static_cast(lhs) == + static_cast(rhs); + } +}; + +template +struct IsNotEqual { + static_assert(std::is_arithmetic::value && std::is_arithmetic::value, + "Types must be numeric."); + static constexpr bool Test(const L lhs, const R rhs) { + return DstRangeRelationToSrcRange(lhs) != + DstRangeRelationToSrcRange(rhs) || + static_cast(lhs) != + static_cast(rhs); + } +}; + +// These perform the actual math operations on the CheckedNumerics. +// Binary arithmetic operations. +template